From 1f3e0606ee42f5cec594b2c34b17d2aafcb47faf Mon Sep 17 00:00:00 2001 From: fudongbai <296179868@qq.com> Date: Mon, 17 May 2021 19:32:39 +0800 Subject: [PATCH 001/117] use more aggressive write cache policy --- consensus/parlia/parlia.go | 2 +- consensus/parlia/snapshot.go | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 438042aff2..a8976fd4ad 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -868,7 +868,7 @@ func (p *Parlia) EnoughDistance(chain consensus.ChainReader, header *types.Heade if err != nil { return true } - return snap.enoughDistance(p.val) + return snap.enoughDistance(p.val, header) } // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty diff --git a/consensus/parlia/snapshot.go b/consensus/parlia/snapshot.go index 05aa8de64f..dc83d92c8d 100644 --- a/consensus/parlia/snapshot.go +++ b/consensus/parlia/snapshot.go @@ -244,17 +244,23 @@ func (s *Snapshot) inturn(validator common.Address) bool { return validators[offset] == validator } -func (s *Snapshot) enoughDistance(validator common.Address) bool { +func (s *Snapshot) enoughDistance(validator common.Address, header *types.Header) bool { idx := s.indexOfVal(validator) if idx < 0 { return true } validatorNum := int64(len(s.validators())) + if validatorNum == 1 { + return true + } + if validator == header.Coinbase { + return false + } offset := (int64(s.Number) + 1) % int64(validatorNum) if int64(idx) >= offset { - return int64(idx)-offset >= validatorNum/2 + return int64(idx)-offset >= validatorNum-2 } else { - return validatorNum+int64(idx)-offset >= validatorNum/2 + return validatorNum+int64(idx)-offset >= validatorNum-2 } } From 571a3170923bccf899d3ac9fb9f74d3605b5b8b8 Mon Sep 17 00:00:00 2001 From: fudongbai <296179868@qq.com> Date: Wed, 19 May 2021 11:46:46 +0800 Subject: [PATCH 002/117] fix ungraceful shutdown issue --- eth/backend.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth/backend.go b/eth/backend.go index 224253d4e1..2247b94b5d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -574,6 +574,9 @@ func (s *Ethereum) Stop() error { close(s.closeBloomHandler) s.txPool.Stop() s.miner.Stop() + s.miner.Close() + // TODO this is a hotfix for https://github.com/ethereum/go-ethereum/issues/22892, need a better solution + time.Sleep(5 * time.Second) s.blockchain.Stop() s.engine.Close() rawdb.PopUncleanShutdownMarker(s.chainDb) From 72dfda0e8861d05f790c9df198fd990a722e807d Mon Sep 17 00:00:00 2001 From: fudongbai <296179868@qq.com> Date: Thu, 10 Jun 2021 10:19:17 +0800 Subject: [PATCH 003/117] update discord link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5968a22a2..ad197ee28b 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ from anyone on the internet, and are grateful for even the smallest of fixes! If you'd like to contribute to bsc, please fork, fix, commit and send a pull request for the maintainers to review and merge into the main code base. If you wish to submit -more complex changes though, please check up with the core devs first on [our discord channel](https://discord.com/invite/T3Ka4V4N) +more complex changes though, please check up with the core devs first on [our discord channel](https://discord.gg/5Z3C3SdxDw) to ensure those changes are in line with the general philosophy of the project and/or get some early feedback which can make both your efforts much lighter as well as our review and merge procedures quick and simple. From 1bde62fe87b61007230474d7831188e85594067d Mon Sep 17 00:00:00 2001 From: fudongbai <296179868@qq.com> Date: Thu, 10 Jun 2021 14:00:06 +0800 Subject: [PATCH 004/117] update discord link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad197ee28b..b74ec4d0a5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Binance Smart Chain starts its development based on go-ethereum fork. So you may [![API Reference]( https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 )](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc) -[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/T3Ka4V4N) +[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/5Z3C3SdxDw) But from that baseline of EVM compatible, Binance Smart Chain introduces a system of 21 validators with Proof of Staked Authority (PoSA) consensus that can support short block time and lower fees. The most bonded validator candidates of staking will become validators and produce blocks. The double-sign detection and other slashing logic guarantee security, stability, and chain finality. From 7c2cca285b081730753166f2af67cbc0f1a84bf5 Mon Sep 17 00:00:00 2001 From: j75689 Date: Mon, 26 Jul 2021 12:51:46 +0800 Subject: [PATCH 005/117] release v1.1.0 --- CHANGELOG.md | 5 +++++ params/version.go | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df8ff340de..0263d13b8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog ## v1.1.0 +*[\#282](https://github.com/binance-chain/bsc/pull/282) update discord link +*[\#280](https://github.com/binance-chain/bsc/pull/280) update discord link +*[\#227](https://github.com/binance-chain/bsc/pull/227) use more aggressive write cache policy + +## v1.1.0-beta *[\#152](https://github.com/binance-chain/bsc/pull/152) upgrade to go-ethereum 1.10.3 ## v1.0.7-hf.2 diff --git a/params/version.go b/params/version.go index 87dea87679..653e7cf3d6 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 = 1 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release - VersionMeta = "beta" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 1 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release + VersionMeta = "" // Version metadata to append to the version string ) // Version holds the textual version string. From f124267144b3a4af8f3b158b0091efbcdb0ff334 Mon Sep 17 00:00:00 2001 From: "John.h" <708967537@qq.com> Date: Thu, 29 Jul 2021 17:08:41 +0800 Subject: [PATCH 006/117] eth/tracers: improve tracing performance (#23016) (#326) * eth/tracers: improve tracing performance (#23016) Improves the performance of debug.traceTransaction * Update the import order Co-authored-by: Martin Holst Swende Co-authored-by: John.H --- core/vm/gen_structlog.go | 20 +++------- core/vm/logger.go | 33 ++++++++++------ core/vm/logger_json.go | 8 +--- eth/tracers/tracers_test.go | 78 +++++++++++++++++++++++++++++++++++++ internal/ethapi/api.go | 2 +- 5 files changed, 107 insertions(+), 34 deletions(-) diff --git a/core/vm/gen_structlog.go b/core/vm/gen_structlog.go index ac04afe8b7..4e6e4fb4f4 100644 --- a/core/vm/gen_structlog.go +++ b/core/vm/gen_structlog.go @@ -4,7 +4,8 @@ package vm import ( "encoding/json" - "math/big" + + "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -22,8 +23,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) { GasCost math.HexOrDecimal64 `json:"gasCost"` Memory hexutil.Bytes `json:"memory"` MemorySize int `json:"memSize"` - Stack []*math.HexOrDecimal256 `json:"stack"` - ReturnStack []math.HexOrDecimal64 `json:"returnStack"` + Stack []uint256.Int `json:"stack"` ReturnData hexutil.Bytes `json:"returnData"` Storage map[common.Hash]common.Hash `json:"-"` Depth int `json:"depth"` @@ -39,12 +39,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) { enc.GasCost = math.HexOrDecimal64(s.GasCost) enc.Memory = s.Memory enc.MemorySize = s.MemorySize - if s.Stack != nil { - enc.Stack = make([]*math.HexOrDecimal256, len(s.Stack)) - for k, v := range s.Stack { - enc.Stack[k] = (*math.HexOrDecimal256)(v) - } - } + enc.Stack = s.Stack enc.ReturnData = s.ReturnData enc.Storage = s.Storage enc.Depth = s.Depth @@ -64,7 +59,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error { GasCost *math.HexOrDecimal64 `json:"gasCost"` Memory *hexutil.Bytes `json:"memory"` MemorySize *int `json:"memSize"` - Stack []*math.HexOrDecimal256 `json:"stack"` + Stack []uint256.Int `json:"stack"` ReturnData *hexutil.Bytes `json:"returnData"` Storage map[common.Hash]common.Hash `json:"-"` Depth *int `json:"depth"` @@ -94,10 +89,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error { s.MemorySize = *dec.MemorySize } if dec.Stack != nil { - s.Stack = make([]*big.Int, len(dec.Stack)) - for k, v := range dec.Stack { - s.Stack[k] = (*big.Int)(v) - } + s.Stack = dec.Stack } if dec.ReturnData != nil { s.ReturnData = *dec.ReturnData diff --git a/core/vm/logger.go b/core/vm/logger.go index 9ccaafc772..be24f315c2 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -24,6 +24,8 @@ import ( "strings" "time" + "github.com/holiman/uint256" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" @@ -66,7 +68,7 @@ type StructLog struct { GasCost uint64 `json:"gasCost"` Memory []byte `json:"memory"` MemorySize int `json:"memSize"` - Stack []*big.Int `json:"stack"` + Stack []uint256.Int `json:"stack"` ReturnData []byte `json:"returnData"` Storage map[common.Hash]common.Hash `json:"-"` Depth int `json:"depth"` @@ -76,7 +78,6 @@ type StructLog struct { // overrides for gencodec type structLogMarshaling struct { - Stack []*math.HexOrDecimal256 Gas math.HexOrDecimal64 GasCost math.HexOrDecimal64 Memory hexutil.Bytes @@ -135,6 +136,14 @@ func NewStructLogger(cfg *LogConfig) *StructLogger { return logger } +// Reset clears the data held by the logger. +func (l *StructLogger) Reset() { + l.storage = make(map[common.Address]Storage) + l.output = make([]byte, 0) + l.logs = l.logs[:0] + l.err = nil +} + // CaptureStart implements the Tracer interface to initialize the tracing operation. func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { } @@ -157,16 +166,16 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui copy(mem, memory.Data()) } // Copy a snapshot of the current stack state to a new buffer - var stck []*big.Int + var stck []uint256.Int if !l.cfg.DisableStack { - stck = make([]*big.Int, len(stack.Data())) + stck = make([]uint256.Int, len(stack.Data())) for i, item := range stack.Data() { - stck[i] = new(big.Int).Set(item.ToBig()) + stck[i] = item } } // Copy a snapshot of the current storage to a new container var storage Storage - if !l.cfg.DisableStorage { + if !l.cfg.DisableStorage && (op == SLOAD || op == SSTORE) { // initialise new changed values storage container for this contract // if not present. if l.storage[contract.Address()] == nil { @@ -179,16 +188,16 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui value = env.StateDB.GetState(contract.Address(), address) ) l.storage[contract.Address()][address] = value - } - // capture SSTORE opcodes and record the written entry in the local storage. - if op == SSTORE && stack.len() >= 2 { + storage = l.storage[contract.Address()].Copy() + } else if op == SSTORE && stack.len() >= 2 { + // capture SSTORE opcodes and record the written entry in the local storage. var ( value = common.Hash(stack.data[stack.len()-2].Bytes32()) address = common.Hash(stack.data[stack.len()-1].Bytes32()) ) l.storage[contract.Address()][address] = value + storage = l.storage[contract.Address()].Copy() } - storage = l.storage[contract.Address()].Copy() } var rdata []byte if !l.cfg.DisableReturnData { @@ -238,7 +247,7 @@ func WriteTrace(writer io.Writer, logs []StructLog) { if len(log.Stack) > 0 { fmt.Fprintln(writer, "Stack:") for i := len(log.Stack) - 1; i >= 0; i-- { - fmt.Fprintf(writer, "%08d %x\n", len(log.Stack)-i-1, math.PaddedBigBytes(log.Stack[i], 32)) + fmt.Fprintf(writer, "%08d %s\n", len(log.Stack)-i-1, log.Stack[i].Hex()) } } if len(log.Memory) > 0 { @@ -314,7 +323,7 @@ func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64 // format stack var a []string for _, elem := range stack.data { - a = append(a, fmt.Sprintf("%v", elem.String())) + a = append(a, elem.Hex()) } b := fmt.Sprintf("[%v]", strings.Join(a, ",")) fmt.Fprintf(t.out, "%10v |", b) diff --git a/core/vm/logger_json.go b/core/vm/logger_json.go index e54be08596..0975452b60 100644 --- a/core/vm/logger_json.go +++ b/core/vm/logger_json.go @@ -57,7 +57,6 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint Gas: gas, GasCost: cost, MemorySize: memory.Len(), - Storage: nil, Depth: depth, RefundCounter: env.StateDB.GetRefund(), Err: err, @@ -66,12 +65,7 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint log.Memory = memory.Data() } if !l.cfg.DisableStack { - //TODO(@holiman) improve this - logstack := make([]*big.Int, len(stack.Data())) - for i, item := range stack.Data() { - logstack[i] = item.ToBig() - } - log.Stack = logstack + log.Stack = stack.data } if !l.cfg.DisableReturnData { log.ReturnData = rData diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 9dc4c69631..cdffdc6024 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -300,3 +300,81 @@ func jsonEqual(x, y interface{}) bool { } return reflect.DeepEqual(xTrace, yTrace) } + +func BenchmarkTransactionTrace(b *testing.B) { + key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + from := crypto.PubkeyToAddress(key.PublicKey) + gas := uint64(1000000) // 1M gas + to := common.HexToAddress("0x00000000000000000000000000000000deadbeef") + signer := types.LatestSignerForChainID(big.NewInt(1337)) + tx, err := types.SignNewTx(key, signer, + &types.LegacyTx{ + Nonce: 1, + GasPrice: big.NewInt(500), + Gas: gas, + To: &to, + }) + if err != nil { + b.Fatal(err) + } + txContext := vm.TxContext{ + Origin: from, + GasPrice: tx.GasPrice(), + } + context := vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Coinbase: common.Address{}, + BlockNumber: new(big.Int).SetUint64(uint64(5)), + Time: new(big.Int).SetUint64(uint64(5)), + Difficulty: big.NewInt(0xffffffff), + GasLimit: gas, + } + alloc := core.GenesisAlloc{} + // The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns + // the address + loop := []byte{ + byte(vm.JUMPDEST), // [ count ] + byte(vm.PUSH1), 0, // jumpdestination + byte(vm.JUMP), + } + alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{ + Nonce: 1, + Code: loop, + Balance: big.NewInt(1), + } + alloc[from] = core.GenesisAccount{ + Nonce: 1, + Code: []byte{}, + Balance: big.NewInt(500000000000000), + } + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) + // Create the tracer, the EVM environment and run it + tracer := vm.NewStructLogger(&vm.LogConfig{ + Debug: false, + //DisableStorage: true, + //DisableMemory: true, + //DisableReturnData: true, + }) + evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer}) + msg, err := tx.AsMessage(signer, nil) + if err != nil { + b.Fatalf("failed to prepare transaction for tracing: %v", err) + } + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + snap := statedb.Snapshot() + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + _, err = st.TransitionDb() + if err != nil { + b.Fatal(err) + } + statedb.RevertToSnapshot(snap) + if have, want := len(tracer.StructLogs()), 244752; have != want { + b.Fatalf("trace wrong, want %d steps, have %d", want, have) + } + tracer.Reset() + } +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 56c8eb206e..212bc13b33 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1124,7 +1124,7 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes { if trace.Stack != nil { stack := make([]string, len(trace.Stack)) for i, stackValue := range trace.Stack { - stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + stack[i] = stackValue.Hex() } formatted[index].Stack = &stack } From 2ce00adb5545e792f7993862f0aeb7fb579bedd6 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Thu, 29 Jul 2021 17:16:53 +0800 Subject: [PATCH 007/117] [R4R] performance improvement in many aspects (#257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * focus on performance improvement in many aspects. 1. Do BlockBody verification concurrently; 2. Do calculation of intermediate root concurrently; 3. Preload accounts before processing blocks; 4. Make the snapshot layers configurable. 5. Reuse some object to reduce GC. add * rlp: improve decoder stream implementation (#22858) This commit makes various cleanup changes to rlp.Stream. * rlp: shrink Stream struct This removes a lot of unused padding space in Stream by reordering the fields. The size of Stream changes from 120 bytes to 88 bytes. Stream instances are internally cached and reused using sync.Pool, so this does not improve performance. * rlp: simplify list stack The list stack kept track of the size of the current list context as well as the current offset into it. The size had to be stored in the stack in order to subtract it from the remaining bytes of any enclosing list in ListEnd. It seems that this can be implemented in a simpler way: just subtract the size from the enclosing list context in List instead. * rlp: use atomic.Value for type cache (#22902) All encoding/decoding operations read the type cache to find the writer/decoder function responsible for a type. When analyzing CPU profiles of geth during sync, I found that the use of sync.RWMutex in cache lookups appears in the profiles. It seems we are running into CPU cache contention problems when package rlp is heavily used on all CPU cores during sync. This change makes it use atomic.Value + a writer lock instead of sync.RWMutex. In the common case where the typeinfo entry is present in the cache, we simply fetch the map and lookup the type. * rlp: optimize byte array handling (#22924) This change improves the performance of encoding/decoding [N]byte. name old time/op new time/op delta DecodeByteArrayStruct-8 336ns ± 0% 246ns ± 0% -26.98% (p=0.000 n=9+10) EncodeByteArrayStruct-8 225ns ± 1% 148ns ± 1% -34.12% (p=0.000 n=10+10) name old alloc/op new alloc/op delta DecodeByteArrayStruct-8 120B ± 0% 48B ± 0% -60.00% (p=0.000 n=10+10) EncodeByteArrayStruct-8 0.00B 0.00B ~ (all equal) * rlp: optimize big.Int decoding for size <= 32 bytes (#22927) This change grows the static integer buffer in Stream to 32 bytes, making it possible to decode 256bit integers without allocating a temporary buffer. In the recent commit 088da24, Stream struct size decreased from 120 bytes down to 88 bytes. This commit grows the struct to 112 bytes again, but the size change will not degrade performance because Stream instances are internally cached in sync.Pool. name old time/op new time/op delta DecodeBigInts-8 12.2µs ± 0% 8.6µs ± 4% -29.58% (p=0.000 n=9+10) name old speed new speed delta DecodeBigInts-8 230MB/s ± 0% 326MB/s ± 4% +42.04% (p=0.000 n=9+10) * eth/protocols/eth, les: avoid Raw() when decoding HashOrNumber (#22841) Getting the raw value is not necessary to decode this type, and decoding it directly from the stream is faster. * fix testcase * debug no lazy * fix can not repair * address comments Co-authored-by: Felix Lange --- build/ci.go | 5 +- cmd/devp2p/internal/ethtest/suite_test.go | 107 ------ cmd/faucet/faucet_test.go | 43 --- cmd/geth/main.go | 2 +- cmd/geth/snapshot.go | 5 +- cmd/geth/usage.go | 2 +- cmd/utils/flags.go | 32 +- common/gopool/pool.go | 48 +++ consensus/clique/clique.go | 9 +- consensus/ethash/algorithm.go | 5 +- consensus/ethash/consensus.go | 9 +- consensus/ethash/ethash.go | 5 +- consensus/ethash/sealer.go | 5 +- consensus/parlia/parlia.go | 44 ++- core/asm/lexer.go | 6 +- core/block_validator.go | 87 ++++- core/blockchain.go | 140 ++++---- core/blockchain_repair_test.go | 2 + core/blockchain_sethead_test.go | 2 + core/blockchain_snapshot_test.go | 3 + core/blockchain_test.go | 30 +- core/bloombits/matcher.go | 21 +- core/bloombits/scheduler.go | 10 +- core/genesis.go | 2 +- core/genesis_test.go | 9 - core/rawdb/chain_iterator.go | 5 +- core/state/database.go | 116 +++++- core/state/journal.go | 15 +- core/state/pruner/pruner.go | 32 +- core/state/snapshot/conversion.go | 7 +- core/state/snapshot/difflayer.go | 4 +- core/state/snapshot/snapshot.go | 26 +- core/state/state_object.go | 101 +++--- core/state/state_test.go | 6 +- core/state/statedb.go | 420 ++++++++++++++++------ core/state/trie_prefetcher.go | 37 +- core/state_processor.go | 9 +- core/tx_list.go | 35 +- core/tx_pool.go | 44 +-- core/types/block.go | 2 + core/types/transaction.go | 5 +- core/vm/evm.go | 27 +- core/vm/interpreter.go | 18 +- crypto/crypto.go | 38 +- eth/backend.go | 20 +- eth/bloombits.go | 5 +- eth/catalyst/api_test.go | 6 +- eth/downloader/api.go | 5 +- eth/downloader/peer.go | 3 +- eth/ethconfig/config.go | 7 +- eth/ethconfig/gen_config.go | 10 +- eth/fetcher/block_fetcher.go | 5 +- eth/fetcher/tx_fetcher.go | 11 +- eth/filters/api.go | 25 +- eth/protocols/eth/broadcast.go | 7 +- eth/protocols/eth/handshake.go | 9 +- eth/protocols/eth/protocol.go | 24 +- eth/protocols/snap/sync.go | 24 +- eth/sync.go | 3 +- eth/tracers/api.go | 21 +- eth/tracers/api_test.go | 1 + event/subscription.go | 9 +- go.mod | 2 + go.sum | 145 ++++++++ internal/ethapi/api.go | 9 +- les/handler_test.go | 4 +- les/peer.go | 3 +- les/protocol.go | 24 +- les/server_requests.go | 4 +- les/test_helper.go | 2 +- light/trie.go | 12 + miner/worker.go | 71 +--- miner/worker_test.go | 163 --------- node/api.go | 5 +- p2p/dial.go | 14 +- p2p/discover/lookup.go | 5 +- p2p/discover/table.go | 24 +- p2p/discover/v4_udp.go | 5 +- p2p/enode/iter.go | 6 +- p2p/enode/nodedb.go | 7 +- p2p/nat/nat.go | 6 +- p2p/nat/natpmp.go | 5 +- p2p/peer.go | 5 +- p2p/rlpx/rlpx.go | 29 +- p2p/server.go | 17 +- p2p/simulations/examples/ping-pong.go | 11 +- p2p/transport.go | 3 +- params/config.go | 55 +-- rlp/decode.go | 247 +++++++------ rlp/decode_test.go | 66 +++- rlp/encode.go | 60 +--- rlp/encode_test.go | 60 ++++ rlp/safe.go | 26 ++ rlp/typecache.go | 136 +++++-- rlp/unsafe.go | 35 ++ rpc/handler.go | 6 +- tests/state_test_util.go | 2 +- trie/committer.go | 4 +- trie/database.go | 33 +- trie/secure_trie.go | 17 +- trie/secure_trie_test.go | 6 +- trie/sync_bloom.go | 10 +- trie/trie.go | 4 + 103 files changed, 1944 insertions(+), 1179 deletions(-) delete mode 100644 cmd/devp2p/internal/ethtest/suite_test.go delete mode 100644 cmd/faucet/faucet_test.go create mode 100644 common/gopool/pool.go create mode 100644 rlp/safe.go create mode 100644 rlp/unsafe.go diff --git a/build/ci.go b/build/ci.go index d9f147ef0e..18172c327a 100644 --- a/build/ci.go +++ b/build/ci.go @@ -300,7 +300,10 @@ func doTest(cmdline []string) { gotest.Args = append(gotest.Args, "-v") } - packages := []string{"./..."} + packages := []string{"./accounts/...", "./common/...", "./consensus/...", "./console/...", "./core/...", + "./crypto/...", "./eth/...", "./ethclient/...", "./ethdb/...", "./event/...", "./graphql/...", "./les/...", + "./light/...", "./log/...", "./metrics/...", "./miner/...", "./mobile/...", "./node/...", + "./p2p/...", "./params/...", "./rlp/...", "./rpc/...", "./tests/...", "./trie/..."} if len(flag.CommandLine.Args()) > 0 { packages = flag.CommandLine.Args() } diff --git a/cmd/devp2p/internal/ethtest/suite_test.go b/cmd/devp2p/internal/ethtest/suite_test.go deleted file mode 100644 index 6e3217151a..0000000000 --- a/cmd/devp2p/internal/ethtest/suite_test.go +++ /dev/null @@ -1,107 +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 ethtest - -import ( - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/internal/utesting" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" -) - -var ( - genesisFile = "./testdata/genesis.json" - halfchainFile = "./testdata/halfchain.rlp" - fullchainFile = "./testdata/chain.rlp" -) - -func TestEthSuite(t *testing.T) { - geth, err := runGeth() - if err != nil { - t.Fatalf("could not run geth: %v", err) - } - defer geth.Close() - - suite, err := NewSuite(geth.Server().Self(), fullchainFile, genesisFile) - if err != nil { - t.Fatalf("could not create new test suite: %v", err) - } - for _, test := range suite.AllEthTests() { - 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 { - t.Fatal() - } - }) - } -} - -// runGeth creates and starts a geth node -func runGeth() (*node.Node, error) { - stack, err := node.New(&node.Config{ - P2P: p2p.Config{ - ListenAddr: "127.0.0.1:0", - NoDiscovery: true, - MaxPeers: 10, // in case a test requires multiple connections, can be changed in the future - NoDial: true, - }, - }) - if err != nil { - return nil, err - } - - err = setupGeth(stack) - if err != nil { - stack.Close() - return nil, err - } - if err = stack.Start(); err != nil { - stack.Close() - return nil, err - } - return stack, nil -} - -func setupGeth(stack *node.Node) error { - chain, err := loadChain(halfchainFile, genesisFile) - if err != nil { - return err - } - - backend, err := eth.New(stack, ðconfig.Config{ - Genesis: &chain.genesis, - NetworkId: chain.genesis.Config.ChainID.Uint64(), // 19763 - DatabaseCache: 10, - TrieCleanCache: 10, - TrieCleanCacheJournal: "", - TrieCleanCacheRejournal: 60 * time.Minute, - TrieDirtyCache: 16, - TrieTimeout: 60 * time.Minute, - SnapshotCache: 10, - }) - if err != nil { - return err - } - - _, err = backend.BlockChain().InsertChain(chain.blocks[1:]) - return err -} diff --git a/cmd/faucet/faucet_test.go b/cmd/faucet/faucet_test.go deleted file mode 100644 index 4f3e47084e..0000000000 --- a/cmd/faucet/faucet_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021 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 ( - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -func TestFacebook(t *testing.T) { - for _, tt := range []struct { - url string - want common.Address - }{ - { - "https://www.facebook.com/fooz.gazonk/posts/2837228539847129", - common.HexToAddress("0xDeadDeaDDeaDbEefbEeFbEEfBeeFBeefBeeFbEEF"), - }, - } { - _, _, gotAddress, err := authFacebook(tt.url) - if err != nil { - t.Fatal(err) - } - if gotAddress != tt.want { - t.Fatalf("address wrong, have %v want %v", gotAddress, tt.want) - } - } -} diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ed54827c97..d383d99b7e 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -105,6 +105,7 @@ var ( utils.LightNoSyncServeFlag, utils.WhitelistFlag, utils.BloomFilterSizeFlag, + utils.TriesInMemoryFlag, utils.CacheFlag, utils.CacheDatabaseFlag, utils.CacheTrieFlag, @@ -112,7 +113,6 @@ var ( utils.CacheTrieRejournalFlag, utils.CacheGCFlag, utils.CacheSnapshotFlag, - utils.CacheNoPrefetchFlag, utils.CachePreimagesFlag, utils.ListenPortFlag, utils.MaxPeersFlag, diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 1af458af20..2f615a2c18 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -63,6 +63,7 @@ var ( utils.GoerliFlag, utils.CacheTrieJournalFlag, utils.BloomFilterSizeFlag, + utils.TriesInMemoryFlag, }, Description: ` geth snapshot prune-state @@ -153,7 +154,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.GlobalUint64(utils.BloomFilterSizeFlag.Name), ctx.GlobalUint64(utils.TriesInMemoryFlag.Name)) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return err @@ -187,7 +188,7 @@ func verifyState(ctx *cli.Context) error { 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) + snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, 128, headBlock.Root(), false, false, false) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return err diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 1cc6693ec0..1450c29e84 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -56,6 +56,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.IdentityFlag, utils.LightKDFFlag, utils.WhitelistFlag, + utils.TriesInMemoryFlag, }, }, { @@ -118,7 +119,6 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.CacheTrieRejournalFlag, utils.CacheGCFlag, utils.CacheSnapshotFlag, - utils.CacheNoPrefetchFlag, utils.CachePreimagesFlag, }, }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index f02f326bcf..8197b8ceab 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -241,6 +241,11 @@ var ( Usage: "Megabytes of memory allocated to bloom-filter for pruning", Value: 2048, } + TriesInMemoryFlag = cli.Uint64Flag{ + Name: "triesInMemory", + Usage: "The layer of tries trees that keep in memory", + Value: 128, + } OverrideBerlinFlag = cli.Uint64Flag{ Name: "override.berlin", Usage: "Manually specify Berlin fork-block, overriding the bundled setting", @@ -389,7 +394,7 @@ var ( CacheDatabaseFlag = cli.IntFlag{ Name: "cache.database", Usage: "Percentage of cache memory allowance to use for database io", - Value: 50, + Value: 40, } CacheTrieFlag = cli.IntFlag{ Name: "cache.trie", @@ -413,12 +418,8 @@ var ( } 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)", + Usage: "Percentage of cache memory allowance to use for snapshot caching (default = 20%)", + Value: 20, } CachePreimagesFlag = cli.BoolFlag{ Name: "cache.preimages", @@ -1576,9 +1577,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(RangeLimitFlag.Name) { cfg.RangeLimit = ctx.GlobalBool(RangeLimitFlag.Name) } - if ctx.GlobalIsSet(CacheNoPrefetchFlag.Name) { - cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name) - } // Read the value from the flag no matter if it's set or not. cfg.Preimages = ctx.GlobalBool(CachePreimagesFlag.Name) if cfg.NoPruning && !cfg.Preimages { @@ -1905,13 +1903,13 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } cache := &core.CacheConfig{ - TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, - TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name), - TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, - TrieDirtyDisabled: ctx.GlobalString(GCModeFlag.Name) == "archive", - TrieTimeLimit: ethconfig.Defaults.TrieTimeout, - SnapshotLimit: ethconfig.Defaults.SnapshotCache, - Preimages: ctx.GlobalBool(CachePreimagesFlag.Name), + TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, + TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, + TrieDirtyDisabled: ctx.GlobalString(GCModeFlag.Name) == "archive", + TrieTimeLimit: ethconfig.Defaults.TrieTimeout, + TriesInMemory: ethconfig.Defaults.TriesInMemory, + SnapshotLimit: ethconfig.Defaults.SnapshotCache, + Preimages: ctx.GlobalBool(CachePreimagesFlag.Name), } if cache.TrieDirtyDisabled && !cache.Preimages { cache.Preimages = true diff --git a/common/gopool/pool.go b/common/gopool/pool.go new file mode 100644 index 0000000000..b4fc1c459d --- /dev/null +++ b/common/gopool/pool.go @@ -0,0 +1,48 @@ +package gopool + +import ( + "time" + + "github.com/panjf2000/ants/v2" +) + +var ( + // Init a instance pool when importing ants. + defaultPool, _ = ants.NewPool(ants.DefaultAntsPoolSize, ants.WithExpiryDuration(10*time.Second)) +) + +// Logger is used for logging formatted messages. +type Logger interface { + // Printf must have the same semantics as log.Printf. + Printf(format string, args ...interface{}) +} + +// Submit submits a task to pool. +func Submit(task func()) error { + return defaultPool.Submit(task) +} + +// Running returns the number of the currently running goroutines. +func Running() int { + return defaultPool.Running() +} + +// Cap returns the capacity of this default pool. +func Cap() int { + return defaultPool.Cap() +} + +// Free returns the available goroutines to work. +func Free() int { + return defaultPool.Free() +} + +// Release Closes the default pool. +func Release() { + defaultPool.Release() +} + +// Reboot reboots the default pool. +func Reboot() { + defaultPool.Reboot() +} diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 2355950424..dfec81f6ad 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" @@ -224,7 +225,7 @@ func (c *Clique) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*typ abort := make(chan struct{}) results := make(chan error, len(headers)) - go func() { + gopool.Submit(func() { for i, header := range headers { err := c.verifyHeader(chain, header, headers[:i]) @@ -234,7 +235,7 @@ func (c *Clique) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*typ case results <- err: } } - }() + }) return abort, results } @@ -635,7 +636,7 @@ func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, res copy(header.Extra[len(header.Extra)-extraSeal:], sighash) // Wait until sealing is terminated or delay timeout. log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay)) - go func() { + gopool.Submit(func() { select { case <-stop: return @@ -647,7 +648,7 @@ func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, res default: log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header)) } - }() + }) return nil } diff --git a/consensus/ethash/algorithm.go b/consensus/ethash/algorithm.go index 065e60b90b..f38397d5c1 100644 --- a/consensus/ethash/algorithm.go +++ b/consensus/ethash/algorithm.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/bitutil" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "golang.org/x/crypto/sha3" @@ -168,7 +169,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { done := make(chan struct{}) defer close(done) - go func() { + gopool.Submit(func() { for { select { case <-done: @@ -177,7 +178,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { logger.Info("Generating ethash verification cache", "percentage", atomic.LoadUint32(&progress)*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start))) } } - }() + }) // Create a hasher to reuse between invocations keccak512 := makeHasher(sha3.NewLegacyKeccak512()) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index f8a84c3d00..c32e0ec3cf 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -26,6 +26,7 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" @@ -133,16 +134,16 @@ func (ethash *Ethash) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ unixNow = time.Now().Unix() ) for i := 0; i < workers; i++ { - go func() { + gopool.Submit(func() { for index := range inputs { errors[index] = ethash.verifyHeaderWorker(chain, headers, seals, index, unixNow) done <- index } - }() + }) } errorsOut := make(chan error, len(headers)) - go func() { + gopool.Submit(func() { defer close(inputs) var ( in, out = 0, 0 @@ -167,7 +168,7 @@ func (ethash *Ethash) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ return } } - }() + }) return abort, errorsOut } diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index ec06d02a54..9944daa8f5 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -34,6 +34,7 @@ import ( "unsafe" "github.com/edsrzf/mmap-go" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -590,14 +591,14 @@ func (ethash *Ethash) dataset(block uint64, async bool) *dataset { // If async is specified, generate everything in a background thread if async && !current.generated() { - go func() { + gopool.Submit(func() { current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) if futureI != nil { future := futureI.(*dataset) 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) diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index 1830e672b1..d8954e0f1b 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -31,6 +31,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/types" @@ -100,7 +101,7 @@ func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block }(i, uint64(ethash.rand.Int63())) } // Wait until sealing is terminated or a nonce is found - go func() { + gopool.Submit(func() { var result *types.Block select { case <-stop: @@ -123,7 +124,7 @@ func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block } // Wait for all miners to terminate and return the block pend.Wait() - }() + }) return nil } diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index a8976fd4ad..62d109848f 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" @@ -301,7 +302,7 @@ func (p *Parlia) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*typ abort := make(chan struct{}) results := make(chan error, len(headers)) - go func() { + gopool.Submit(func() { for i, header := range headers { err := p.verifyHeader(chain, header, headers[:i]) @@ -311,7 +312,7 @@ func (p *Parlia) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*typ case results <- err: } } - }() + }) return abort, results } @@ -651,7 +652,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade number := header.Number.Uint64() snap, err := p.snapshot(chain, number-1, header.ParentHash, nil) if err != nil { - panic(err) + return err } nextForkHash := forkid.NextForkHash(p.chainConfig, p.genesisHash, number) if !snap.isMajorityFork(hex.EncodeToString(nextForkHash[:])) { @@ -705,13 +706,11 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade val := header.Coinbase err = p.distributeIncoming(val, state, header, cx, txs, receipts, systemTxs, usedGas, false) if err != nil { - panic(err) + return err } if len(*systemTxs) > 0 { return errors.New("the length of systemTxs do not match") } - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - header.UncleHash = types.CalcUncleHash(nil) return nil } @@ -737,7 +736,7 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * number := header.Number.Uint64() snap, err := p.snapshot(chain, number-1, header.ParentHash, nil) if err != nil { - panic(err) + return nil, nil, err } spoiledVal := snap.supposeValidator() signedRecently := false @@ -757,17 +756,29 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * } err := p.distributeIncoming(p.val, state, header, cx, &txs, &receipts, nil, &header.GasUsed, true) if err != nil { - panic(err) + return nil, nil, err } // should not happen. Once happen, stop the node is better than broadcast the block if header.GasLimit < header.GasUsed { - panic("Gas consumption of system txs exceed the gas limit") + return nil, nil, errors.New("gas consumption of system txs exceed the gas limit") } - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) - + var blk *types.Block + var rootHash common.Hash + wg := sync.WaitGroup{} + wg.Add(2) + go func() { + rootHash = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + wg.Done() + }() + go func() { + blk = types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) + wg.Done() + }() + wg.Wait() + blk.SetRoot(rootHash) // Assemble and return the final block for sealing - return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), receipts, nil + return blk, receipts, nil } // Authorize injects a private key into the consensus engine to mint new blocks @@ -1106,7 +1117,14 @@ func (p *Parlia) applyTransaction( } actualTx := (*receivedTxs)[0] if !bytes.Equal(p.signer.Hash(actualTx).Bytes(), expectedHash.Bytes()) { - return fmt.Errorf("expected tx hash %v, get %v", expectedHash.String(), actualTx.Hash().String()) + return fmt.Errorf("expected tx hash %v, get %v, nonce %d, to %s, value %s, gas %d, gasPrice %s, data %s", expectedHash.String(), actualTx.Hash().String(), + expectedTx.Nonce(), + expectedTx.To().String(), + expectedTx.Value().String(), + expectedTx.Gas(), + expectedTx.GasPrice().String(), + hex.EncodeToString(expectedTx.Data()), + ) } expectedTx = actualTx // move to next diff --git a/core/asm/lexer.go b/core/asm/lexer.go index 9eb8f914ac..efea204d2d 100644 --- a/core/asm/lexer.go +++ b/core/asm/lexer.go @@ -22,6 +22,8 @@ import ( "strings" "unicode" "unicode/utf8" + + "github.com/ethereum/go-ethereum/common/gopool" ) // stateFn is used through the lifetime of the @@ -103,14 +105,14 @@ func Lex(source []byte, debug bool) <-chan token { state: lexLine, debug: debug, } - go func() { + gopool.Submit(func() { l.emit(lineStart) for l.state != nil { l.state = l.state(l) } l.emit(eof) close(l.tokens) - }() + }) return ch } diff --git a/core/block_validator.go b/core/block_validator.go index 6f349b0d04..92be755199 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -64,14 +64,42 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash { return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash) } - 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) + + validateFuns := []func() error{ + func() error { + if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { + return ErrKnownBlock + } + return nil + }, + func() 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) + } + return nil + }, + func() error { + if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { + if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { + return consensus.ErrUnknownAncestor + } + return consensus.ErrPrunedAncestor + } + return nil + }, + } + validateRes := make(chan error, len(validateFuns)) + for _, f := range validateFuns { + tmpFunc := f + go func() { + validateRes <- tmpFunc() + }() } - if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { - if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { - return consensus.ErrUnknownAncestor + for i := 0; i < len(validateFuns); i++ { + r := <-validateRes + if r != nil { + return r } - return consensus.ErrPrunedAncestor } return nil } @@ -87,20 +115,43 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. - rbloom := types.CreateBloom(receipts) - if rbloom != header.Bloom { - return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) + validateFuns := []func() error{ + func() error { + rbloom := types.CreateBloom(receipts) + if rbloom != header.Bloom { + return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) + } + return nil + }, + func() error { + receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) + if receiptSha != header.ReceiptHash { + return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) + } else { + return nil + } + }, + func() error { + if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { + statedb.IterativeDump(true, true, true, json.NewEncoder(os.Stdout)) + return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) + } else { + return nil + } + }, } - // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) - receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) - if receiptSha != header.ReceiptHash { - return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) + validateRes := make(chan error, len(validateFuns)) + for _, f := range validateFuns { + tmpFunc := f + go func() { + validateRes <- tmpFunc() + }() } - // 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 { - statedb.IterativeDump(true, true, true, json.NewEncoder(os.Stdout)) - return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) + for i := 0; i < len(validateFuns); i++ { + r := <-validateRes + if r != nil { + return r + } } return nil } diff --git a/core/blockchain.go b/core/blockchain.go index f8fffc091b..3cc44fc4e5 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -76,9 +76,6 @@ var ( blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil) blockReorgInvalidatedTx = metrics.NewRegisteredMeter("chain/reorg/invalidTx", nil) - blockPrefetchExecuteTimer = metrics.NewRegisteredTimer("chain/prefetch/executes", nil) - blockPrefetchInterruptMeter = metrics.NewRegisteredMeter("chain/prefetch/interrupts", nil) - errInsertionInterrupted = errors.New("insertion is interrupted") ) @@ -90,7 +87,7 @@ const ( maxFutureBlocks = 256 maxTimeFutureBlocks = 30 badBlockLimit = 10 - TriesInMemory = 128 + maxBeyondBlocks = 2048 // BlockChainVersion ensures that an incompatible database forces a resync from scratch. // @@ -121,15 +118,15 @@ const ( // CacheConfig contains the configuration values for the trie caching/pruning // that's resident in a blockchain. type CacheConfig struct { - TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory - TrieCleanJournal string // Disk journal for saving clean cache entries. - TrieCleanRejournal time.Duration // Time interval to dump clean cache to disk periodically - TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks - TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk - TrieDirtyDisabled bool // Whether to disable trie write caching and GC altogether (archive node) - TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk - 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 + TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory + TrieCleanJournal string // Disk journal for saving clean cache entries. + TrieCleanRejournal time.Duration // Time interval to dump clean cache to disk periodically + TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk + TrieDirtyDisabled bool // Whether to disable trie write caching and GC altogether (archive node) + TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk + 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 + TriesInMemory uint64 // How many tries keeps in memory SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } @@ -141,6 +138,7 @@ var defaultCacheConfig = &CacheConfig{ TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, + TriesInMemory: 128, SnapshotWait: true, } @@ -173,6 +171,7 @@ type BlockChain struct { // * N: means N block limit [HEAD-N+1, HEAD] and delete extra indexes // * nil: disable tx reindexer/deleter, but still index new blocks txLookupLimit uint64 + triesInMemory uint64 hc *HeaderChain rmLogsFeed event.Feed @@ -202,11 +201,10 @@ type BlockChain struct { running int32 // 0 if chain is running, 1 when stopped procInterrupt int32 // interrupt signaler for block processing - engine consensus.Engine - validator Validator // Block and state validator interface - prefetcher Prefetcher - processor Processor // Block transaction processor interface - vmConfig vm.Config + engine consensus.Engine + validator Validator // Block and state validator interface + processor Processor // Block transaction processor interface + vmConfig vm.Config shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. terminateInsert func(common.Hash, uint64) bool // Testing hook used to terminate ancient receipt chain insertion. @@ -231,11 +229,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par cacheConfig: cacheConfig, db: db, triegc: prque.New(nil), - stateCache: state.NewDatabaseWithConfig(db, &trie.Config{ + stateCache: state.NewDatabaseWithConfigAndCache(db, &trie.Config{ Cache: cacheConfig.TrieCleanLimit, Journal: cacheConfig.TrieCleanJournal, Preimages: cacheConfig.Preimages, }), + triesInMemory: cacheConfig.TriesInMemory, quit: make(chan struct{}), shouldPreserve: shouldPreserve, bodyCache: bodyCache, @@ -248,7 +247,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par vmConfig: vmConfig, } bc.validator = NewBlockValidator(chainConfig, bc, engine) - bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) bc.processor = NewStateProcessor(chainConfig, bc, engine) var err error @@ -372,7 +370,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par 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) + bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, int(bc.cacheConfig.TriesInMemory), head.Root(), !bc.cacheConfig.SnapshotWait, true, recover) } // Take ownership of this particular state go bc.update() @@ -407,6 +405,10 @@ func (bc *BlockChain) CacheReceipts(hash common.Hash, receipts types.Receipts) { bc.receiptsCache.Add(hash, receipts) } +func (bc *BlockChain) CacheBlock(hash common.Hash, block *types.Block) { + bc.blockCache.Add(hash, block) +} + // empty returns an indicator whether the blockchain is empty. // Note, it's a special case that we connect a non-empty ancient // database with an empty node, so that we can plugin the ancient @@ -511,6 +513,7 @@ func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64, // chain reparation mechanism without deleting any data! if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.NumberU64() { newHeadBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) + lastBlockNum := header.Number.Uint64() if newHeadBlock == nil { log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash()) newHeadBlock = bc.genesisBlock @@ -519,12 +522,17 @@ func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64, // keeping rewinding until we exceed the optional threshold // root hash beyondRoot := (root == common.Hash{}) // Flag whether we're beyond the requested root (no root, always true) - + enoughBeyondCount := false + beyondCount := 0 for { + beyondCount++ // If a root threshold was requested but not yet crossed, check if root != (common.Hash{}) && !beyondRoot && newHeadBlock.Root() == root { beyondRoot, rootNumber = true, newHeadBlock.NumberU64() } + + enoughBeyondCount = beyondCount > maxBeyondBlocks + if _, err := state.New(newHeadBlock.Root(), bc.stateCache, bc.snaps); err != nil { log.Trace("Block state missing, rewinding further", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash()) if pivot == nil || newHeadBlock.NumberU64() > *pivot { @@ -540,7 +548,20 @@ func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64, newHeadBlock = bc.genesisBlock } } - if beyondRoot || newHeadBlock.NumberU64() == 0 { + if beyondRoot || (enoughBeyondCount && root != common.Hash{}) || newHeadBlock.NumberU64() == 0 { + if enoughBeyondCount && (root != common.Hash{}) && rootNumber == 0 { + for { + lastBlockNum++ + block := bc.GetBlockByNumber(lastBlockNum) + if block == nil { + break + } + if block.Root() == root { + rootNumber = block.NumberU64() + break + } + } + } log.Debug("Rewound to block with state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash()) break } @@ -1019,7 +1040,7 @@ func (bc *BlockChain) Stop() { if !bc.cacheConfig.TrieDirtyDisabled { triedb := bc.stateCache.TrieDB() - for _, offset := range []uint64{0, 1, TriesInMemory - 1} { + for _, offset := range []uint64{0, 1, bc.triesInMemory - 1} { if number := bc.CurrentBlock().NumberU64(); number > offset { recent := bc.GetBlockByNumber(number - offset) @@ -1036,7 +1057,7 @@ func (bc *BlockChain) Stop() { } } for !bc.triegc.Empty() { - triedb.Dereference(bc.triegc.PopItem().(common.Hash)) + go triedb.Dereference(bc.triegc.PopItem().(common.Hash)) } if size, _ := triedb.Size(); size != 0 { log.Error("Dangling trie nodes after full cleanup") @@ -1468,14 +1489,19 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. // // Note all the components of block(td, hash->number map, header, body, receipts) // should be written atomically. BlockBatch is used for containing all components. - blockBatch := bc.db.NewBatch() - rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) - rawdb.WriteBlock(blockBatch, block) - rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) - rawdb.WritePreimages(blockBatch, state.Preimages()) - if err := blockBatch.Write(); err != nil { - log.Crit("Failed to write block into disk", "err", err) - } + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + blockBatch := bc.db.NewBatch() + rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) + rawdb.WriteBlock(blockBatch, block) + rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) + rawdb.WritePreimages(blockBatch, state.Preimages()) + if err := blockBatch.Write(); err != nil { + log.Crit("Failed to write block into disk", "err", err) + } + wg.Done() + }() // Commit all cached state changes into underlying memory database. root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) if err != nil { @@ -1493,7 +1519,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. 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 current := block.NumberU64(); current > bc.triesInMemory { // If we exceeded our memory allowance, flush matured singleton nodes to disk var ( nodes, imgs = triedb.Size() @@ -1503,7 +1529,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. triedb.Cap(limit - ethdb.IdealBatchSize) } // Find the next state trie we need to commit - chosen := current - TriesInMemory + chosen := current - bc.triesInMemory // If we exceeded out time allowance, flush an entire trie to disk if bc.gcproc > bc.cacheConfig.TrieTimeLimit { @@ -1522,8 +1548,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } 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) + if chosen < lastWrite+bc.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)/float64(bc.triesInMemory)) } // Flush an entire trie and restart the counters triedb.Commit(header.Root, true, nil) @@ -1539,10 +1565,11 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.triegc.Push(root, number) break } - triedb.Dereference(root.(common.Hash)) + go triedb.Dereference(root.(common.Hash)) } } } + wg.Wait() // If the total difficulty is higher than our known, add it to the canonical chain // Second clause in the if statement reduces the vulnerability to selfish mining. // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf @@ -1681,7 +1708,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er return 0, nil } // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) - senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) + signer := types.MakeSigner(bc.chainConfig, chain[0].Number()) + go senderCacher.recoverFromBlocks(signer, chain) var ( stats = insertStats{startTime: mclock.Now()} @@ -1853,33 +1881,17 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") activeState = statedb + statedb.TryPreload(block, signer) - // 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 - if !bc.cacheConfig.TrieCleanNoPrefetch { - 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) { - bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) - - blockPrefetchExecuteTimer.Update(time.Since(start)) - if atomic.LoadUint32(interrupt) == 1 { - blockPrefetchInterruptMeter.Mark(1) - } - }(time.Now(), followup, throwaway, &followupInterrupt) - } - } - // Process block using the parent state as reference point + //Process block using the parent state as reference point substart := 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 } bc.CacheReceipts(block.Hash(), receipts) + bc.CacheBlock(block.Hash(), block) // 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 @@ -1887,17 +1899,16 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er 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) + blockExecutionTimer.Update(time.Since(substart)) // Validate the state using the default validator substart = time.Now() if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) - atomic.StoreUint32(&followupInterrupt, 1) + log.Error("validate state failed", "error", err) return it.index, err } proctime := time.Since(start) @@ -1906,12 +1917,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er 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)) + blockValidationTimer.Update(time.Since(substart)) // Write the block to the chain and get the status. substart = time.Now() status, err := bc.writeBlockWithState(block, receipts, logs, statedb, false) - atomic.StoreUint32(&followupInterrupt, 1) if err != nil { return it.index, err } @@ -1920,7 +1930,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them - blockWriteTimer.Update(time.Since(substart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits) + blockWriteTimer.Update(time.Since(substart)) blockInsertTimer.UpdateSince(start) switch status { @@ -2488,6 +2498,8 @@ func (bc *BlockChain) GetTransactionLookup(hash common.Hash) *rawdb.LegacyTxLook return lookup } +func (bc *BlockChain) TriesInMemory() uint64 { return bc.triesInMemory } + // Config retrieves the chain's fork configuration. func (bc *BlockChain) Config() *params.ChainConfig { return bc.chainConfig } diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 8bb39d2607..5ddb6d2e07 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1783,6 +1783,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { config.SnapshotLimit = 256 config.SnapshotWait = true } + config.TriesInMemory = 128 chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) @@ -1812,6 +1813,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { } } } + if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil { t.Fatalf("Failed to import canonical chain tail: %v", err) } diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index e99b09cf8c..6caec36eab 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1982,6 +1982,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { config.SnapshotLimit = 256 config.SnapshotWait = true } + config.TriesInMemory = 128 chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) @@ -2021,6 +2022,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { for _, block := range canonblocks { chain.stateCache.TrieDB().Dereference(block.Root()) } + chain.stateCache.Purge() // Force run a freeze cycle type freezer interface { Freeze(threshold uint64) error diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 75c09b421d..b61eb741f0 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -298,6 +298,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, + TriesInMemory: 128, SnapshotLimit: 0, } newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) @@ -418,6 +419,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, + TriesInMemory: 128, } newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) if err != nil { @@ -434,6 +436,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, SnapshotWait: false, // Don't wait rebuild + TriesInMemory: 128, } newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) if err != nil { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 5004abd1c7..9395a379f5 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -44,6 +44,8 @@ import ( var ( canonicalSeed = 1 forkSeed = 2 + + TestTriesInMemory = 128 ) // newCanonical creates a chain database, and injects a deterministic canonical @@ -1481,7 +1483,7 @@ func TestTrieForkGC(t *testing.T) { db := rawdb.NewMemoryDatabase() genesis := new(Genesis).MustCommit(db) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TestTriesInMemory, 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)) @@ -1510,7 +1512,7 @@ func TestTrieForkGC(t *testing.T) { } } // Dereference all the recent tries and ensure no past trie is left in - for i := 0; i < TriesInMemory; i++ { + for i := 0; i < TestTriesInMemory; i++ { chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) } @@ -1529,8 +1531,8 @@ func TestLargeReorgTrieGC(t *testing.T) { genesis := new(Genesis).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}) }) + original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TestTriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TestTriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one diskdb := rawdb.NewMemoryDatabase() @@ -1565,7 +1567,7 @@ func TestLargeReorgTrieGC(t *testing.T) { if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { t.Fatalf("failed to finalize competitor chain: %v", err) } - for i, block := range competitor[:len(competitor)-TriesInMemory] { + for i, block := range competitor[:len(competitor)-TestTriesInMemory] { if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { t.Fatalf("competitor %d: competing chain state missing", i) } @@ -1702,7 +1704,7 @@ func TestLowDiffLongChain(t *testing.T) { // 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) { + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*TestTriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) }) @@ -1720,7 +1722,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(params.TestChainConfig, parent, engine, db, 8*TestTriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) @@ -1755,7 +1757,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon genesis := new(Genesis).MustCommit(db) // Generate and import the canonical chain - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TestTriesInMemory, nil) diskdb := rawdb.NewMemoryDatabase() new(Genesis).MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) @@ -1766,9 +1768,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - lastPrunedIndex := len(blocks) - TriesInMemory - 1 + lastPrunedIndex := len(blocks) - TestTriesInMemory - 1 lastPrunedBlock := blocks[lastPrunedIndex] - firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] + firstNonPrunedBlock := blocks[len(blocks)-TestTriesInMemory] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { @@ -1785,7 +1787,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate fork chain, make it longer than canon parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock parent := blocks[parentIndex] - fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 2*TestTriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) // Prepend the parent(s) @@ -2406,7 +2408,7 @@ func TestSideImportPrunedBlocks(t *testing.T) { genesis := new(Genesis).MustCommit(db) // Generate and import the canonical chain - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TestTriesInMemory, nil) diskdb := rawdb.NewMemoryDatabase() new(Genesis).MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) @@ -2417,14 +2419,14 @@ func TestSideImportPrunedBlocks(t *testing.T) { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - lastPrunedIndex := len(blocks) - TriesInMemory - 1 + lastPrunedIndex := len(blocks) - TestTriesInMemory - 1 lastPrunedBlock := blocks[lastPrunedIndex] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64()) } - firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] + firstNonPrunedBlock := blocks[len(blocks)-TestTriesInMemory] // Verify firstNonPrunedBlock is not pruned if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go index 927232be01..4e9df8a368 100644 --- a/core/bloombits/matcher.go +++ b/core/bloombits/matcher.go @@ -27,6 +27,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/bitutil" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/crypto" ) @@ -164,7 +165,7 @@ func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uin // Read the output from the result sink and deliver to the user session.pend.Add(1) - go func() { + gopool.Submit(func() { defer session.pend.Done() defer close(results) @@ -210,7 +211,7 @@ func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uin } } } - }() + }) return session, nil } @@ -226,7 +227,7 @@ func (m *Matcher) run(begin, end uint64, buffer int, session *MatcherSession) ch source := make(chan *partialMatches, buffer) session.pend.Add(1) - go func() { + gopool.Submit(func() { defer session.pend.Done() defer close(source) @@ -237,7 +238,7 @@ func (m *Matcher) run(begin, end uint64, buffer int, session *MatcherSession) ch case source <- &partialMatches{i, bytes.Repeat([]byte{0xff}, int(m.sectionSize/8))}: } } - }() + }) // Assemble the daisy-chained filtering pipeline next := source dist := make(chan *request, buffer) @@ -247,7 +248,9 @@ func (m *Matcher) run(begin, end uint64, buffer int, session *MatcherSession) ch } // Start the request distribution session.pend.Add(1) - go m.distributor(dist, session) + gopool.Submit(func() { + m.distributor(dist, session) + }) return next } @@ -273,7 +276,7 @@ func (m *Matcher) subMatch(source chan *partialMatches, dist chan *request, bloo results := make(chan *partialMatches, cap(source)) session.pend.Add(2) - go func() { + gopool.Submit(func() { // Tear down the goroutine and terminate all source channels defer session.pend.Done() defer close(process) @@ -314,9 +317,9 @@ func (m *Matcher) subMatch(source chan *partialMatches, dist chan *request, bloo } } } - }() + }) - go func() { + gopool.Submit(func() { // Tear down the goroutine and terminate the final sink channel defer session.pend.Done() defer close(results) @@ -372,7 +375,7 @@ func (m *Matcher) subMatch(source chan *partialMatches, dist chan *request, bloo } } } - }() + }) return results } diff --git a/core/bloombits/scheduler.go b/core/bloombits/scheduler.go index 6449c7465a..5fa6248110 100644 --- a/core/bloombits/scheduler.go +++ b/core/bloombits/scheduler.go @@ -18,6 +18,8 @@ package bloombits import ( "sync" + + "github.com/ethereum/go-ethereum/common/gopool" ) // request represents a bloom retrieval task to prioritize and pull from the local @@ -63,8 +65,12 @@ func (s *scheduler) run(sections chan uint64, dist chan *request, done chan []by // Start the pipeline schedulers to forward between user -> distributor -> user wg.Add(2) - go s.scheduleRequests(sections, dist, pend, quit, wg) - go s.scheduleDeliveries(pend, done, quit, wg) + gopool.Submit(func() { + s.scheduleRequests(sections, dist, pend, quit, wg) + }) + gopool.Submit(func() { + s.scheduleDeliveries(pend, done, quit, wg) + }) } // reset cleans up any leftovers from previous runs. This is required before a diff --git a/core/genesis.go b/core/genesis.go index 75052a19b5..9303522947 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -180,7 +180,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.NewDatabaseWithConfigAndCache(db, nil), nil); err != nil { if genesis == nil { genesis = DefaultGenesisBlock() } diff --git a/core/genesis_test.go b/core/genesis_test.go index 44c1ef253a..e8efdbffb9 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -76,15 +76,6 @@ func TestSetupGenesis(t *testing.T) { wantHash: params.MainnetGenesisHash, wantConfig: params.MainnetChainConfig, }, - { - name: "mainnet block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - DefaultGenesisBlock().MustCommit(db) - return SetupGenesisBlock(db, nil) - }, - wantHash: params.MainnetGenesisHash, - wantConfig: params.MainnetChainConfig, - }, { name: "custom block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index ad222005be..4dca06765e 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -22,6 +22,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -159,7 +160,9 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool } go lookup() // start the sequential db accessor for i := 0; i < int(threads); i++ { - go process() + gopool.Submit(func() { + process() + }) } return hashesCh } diff --git a/core/state/database.go b/core/state/database.go index 1a06e33409..ce37e73837 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -19,6 +19,7 @@ package state import ( "errors" "fmt" + "time" "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" @@ -32,8 +33,18 @@ const ( // Number of codehash->size associations to keep. codeSizeCacheSize = 100000 + // Number of state trie in cache + accountTrieCacheSize = 32 + + // Number of storage Trie in cache + storageTrieCacheSize = 2000 + // Cache size granted for caching clean code. codeCacheSize = 64 * 1024 * 1024 + + purgeInterval = 600 + + maxAccountTrieSize = 1024 * 1024 ) // Database wraps access to tries and contract code. @@ -55,6 +66,15 @@ type Database interface { // TrieDB retrieves the low level trie database used for data storage. TrieDB() *trie.Database + + // Cache the account trie tree + CacheAccount(root common.Hash, t Trie) + + // Cache the storage trie tree + CacheStorage(addrHash common.Hash, root common.Hash, t Trie) + + // Purge cache + Purge() } // Trie is a Ethereum Merkle Patricia trie. @@ -121,14 +141,56 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { } } +func NewDatabaseWithConfigAndCache(db ethdb.Database, config *trie.Config) Database { + csc, _ := lru.New(codeSizeCacheSize) + atc, _ := lru.New(accountTrieCacheSize) + stc, _ := lru.New(storageTrieCacheSize) + + database := &cachingDB{ + db: trie.NewDatabaseWithConfig(db, config), + codeSizeCache: csc, + codeCache: fastcache.New(codeCacheSize), + accountTrieCache: atc, + storageTrieCache: stc, + } + go database.purgeLoop() + return database +} + type cachingDB struct { - db *trie.Database - codeSizeCache *lru.Cache - codeCache *fastcache.Cache + db *trie.Database + codeSizeCache *lru.Cache + codeCache *fastcache.Cache + accountTrieCache *lru.Cache + storageTrieCache *lru.Cache +} + +type triePair struct { + root common.Hash + trie Trie +} + +func (db *cachingDB) purgeLoop() { + for { + time.Sleep(purgeInterval * time.Second) + _, accounts, ok := db.accountTrieCache.GetOldest() + if !ok { + continue + } + tr := accounts.(*trie.SecureTrie).GetRawTrie() + if tr.Size() > maxAccountTrieSize { + db.Purge() + } + } } // OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { + if db.accountTrieCache != nil { + if tr, exist := db.accountTrieCache.Get(root); exist { + return tr.(Trie).(*trie.SecureTrie).Copy(), nil + } + } tr, err := trie.NewSecure(root, db.db) if err != nil { return nil, err @@ -138,6 +200,17 @@ 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) { + if db.storageTrieCache != nil { + if tries, exist := db.storageTrieCache.Get(addrHash); exist { + triesPairs := tries.([3]*triePair) + for _, triePair := range triesPairs { + if triePair != nil && triePair.root == root { + return triePair.trie.(*trie.SecureTrie).Copy(), nil + } + } + } + } + tr, err := trie.NewSecure(root, db.db) if err != nil { return nil, err @@ -145,6 +218,43 @@ func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { return tr, nil } +func (db *cachingDB) CacheAccount(root common.Hash, t Trie) { + if db.accountTrieCache == nil { + return + } + tr := t.(*trie.SecureTrie) + db.accountTrieCache.Add(root, tr.ResetCopy()) +} + +func (db *cachingDB) CacheStorage(addrHash common.Hash, root common.Hash, t Trie) { + if db.storageTrieCache == nil { + return + } + tr := t.(*trie.SecureTrie) + if tries, exist := db.storageTrieCache.Get(addrHash); exist { + triesArray := tries.([3]*triePair) + newTriesArray := [3]*triePair{ + {root: root, trie: tr.ResetCopy()}, + triesArray[0], + triesArray[1], + } + db.storageTrieCache.Add(addrHash, newTriesArray) + } else { + triesArray := [3]*triePair{{root: root, trie: tr.ResetCopy()}, nil, nil} + db.storageTrieCache.Add(addrHash, triesArray) + } + return +} + +func (db *cachingDB) Purge() { + if db.storageTrieCache != nil { + db.storageTrieCache.Purge() + } + if db.accountTrieCache != nil { + db.accountTrieCache.Purge() + } +} + // CopyTrie returns an independent copy of the given trie. func (db *cachingDB) CopyTrie(t Trie) Trie { switch t := t.(type) { diff --git a/core/state/journal.go b/core/state/journal.go index 2070f30875..366e0c9c26 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -43,7 +43,8 @@ type journal struct { // newJournal create a new initialized journal. func newJournal() *journal { return &journal{ - dirties: make(map[common.Address]int), + dirties: make(map[common.Address]int, defaultNumOfSlots), + entries: make([]journalEntry, 0, defaultNumOfSlots), } } @@ -90,7 +91,7 @@ type ( account *common.Address } resetObjectChange struct { - prev *stateObject + prev *StateObject prevdestruct bool } suicideChange struct { @@ -150,7 +151,7 @@ func (ch createObjectChange) dirtied() *common.Address { } func (ch resetObjectChange) revert(s *StateDB) { - s.setStateObject(ch.prev) + s.SetStateObject(ch.prev) if !ch.prevdestruct && s.snap != nil { delete(s.snapDestructs, ch.prev.addrHash) } @@ -253,7 +254,9 @@ func (ch accessListAddAccountChange) revert(s *StateDB) { (addr) at this point, since no storage adds can remain when come upon a single (addr) change. */ - s.accessList.DeleteAddress(*ch.address) + if s.accessList != nil { + s.accessList.DeleteAddress(*ch.address) + } } func (ch accessListAddAccountChange) dirtied() *common.Address { @@ -261,7 +264,9 @@ func (ch accessListAddAccountChange) dirtied() *common.Address { } func (ch accessListAddSlotChange) revert(s *StateDB) { - s.accessList.DeleteSlot(*ch.address, *ch.slot) + if s.accessList != nil { + s.accessList.DeleteSlot(*ch.address, *ch.slot) + } } func (ch accessListAddSlotChange) dirtied() *common.Address { diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 9e3c531707..bb599fcd87 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -82,15 +82,16 @@ type Pruner struct { trieCachePath string headHeader *types.Header snaptree *snapshot.Tree + triesInMemory uint64 } // NewPruner creates the pruner instance. -func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize uint64) (*Pruner, error) { +func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize, triesInMemory uint64) (*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) + snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, int(triesInMemory), headBlock.Root(), false, false, false) if err != nil { return nil, err // The relevant snapshot(s) might not exist } @@ -108,6 +109,7 @@ func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize uint6 stateBloom: stateBloom, datadir: datadir, trieCachePath: trieCachePath, + triesInMemory: triesInMemory, headHeader: headBlock.Header(), snaptree: snaptree, }, nil @@ -244,23 +246,23 @@ func (p *Pruner) Prune(root common.Hash) error { return err } if stateBloomRoot != (common.Hash{}) { - return RecoverPruning(p.datadir, p.db, p.trieCachePath) + return RecoverPruning(p.datadir, p.db, p.trieCachePath, p.triesInMemory) } - // If the target state root is not specified, use the HEAD-127 as the + // If the target state root is not specified, use the HEAD-(n-1) as the // target. The reason for picking it is: // - in most of the normal cases, the related state is available // - the probability of this layer being reorg is very low var layers []snapshot.Snapshot if root == (common.Hash{}) { // 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) - if len(layers) != 128 { - // Reject if the accumulated diff layers are less than 128. It + // In theory there are n difflayers + 1 disk layer present, + // so n diff layers are expected to be returned. + layers = p.snaptree.Snapshots(p.headHeader.Root, int(p.triesInMemory), true) + if len(layers) != int(p.triesInMemory) { + // Reject if the accumulated diff layers are less than n. It // means in most of normal cases, there is no associated state // with bottom-most diff layer. - return fmt.Errorf("snapshot not old enough yet: need %d more blocks", 128-len(layers)) + return fmt.Errorf("snapshot not old enough yet: need %d more blocks", int(p.triesInMemory)-len(layers)) } // Use the bottom-most diff layer as the target root = layers[len(layers)-1].Root() @@ -272,8 +274,8 @@ func (p *Pruner) Prune(root common.Hash) error { // 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 - // difflayer won't be created. So HEAD-127 may not paired with - // head-127 layer. Instead the paired layer is higher than the + // difflayer won't be created. So HEAD-(n-1) may not paired with + // head-(n-1) layer. Instead the paired layer is higher than the // bottom-most diff layer. Try to find the bottom-most snapshot // layer with state available. // @@ -352,7 +354,7 @@ func (p *Pruner) Prune(root common.Hash) error { // pruning can be resumed. What's more if the bloom filter is constructed, the // pruning **has to be resumed**. Otherwise a lot of dangling nodes may be left // in the disk. -func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) error { +func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string, triesInMemory uint64) error { stateBloomPath, stateBloomRoot, err := findBloomFilter(datadir) if err != nil { return err @@ -372,7 +374,7 @@ 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) + snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, int(triesInMemory), headBlock.Root(), false, false, true) if err != nil { return err // The relevant snapshot(s) might not exist } @@ -392,7 +394,7 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err // otherwise the dangling state will be left. var ( found bool - layers = snaptree.Snapshots(headBlock.Root(), 128, true) + layers = snaptree.Snapshots(headBlock.Root(), int(triesInMemory), true) middleRoots = make(map[common.Hash]struct{}) ) for _, layer := range layers { diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index f70cbf1e68..250692422d 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -26,6 +26,8 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/gopool" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" @@ -315,7 +317,8 @@ func generateTrieRoot(db ethdb.KeyValueWriter, it Iterator, account common.Hash, if err != nil { return stop(err) } - go func(hash common.Hash) { + hash := it.Hash() + gopool.Submit(func() { subroot, err := leafCallback(db, hash, common.BytesToHash(account.CodeHash), stats) if err != nil { results <- err @@ -326,7 +329,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, it Iterator, account common.Hash, return } results <- nil - }(it.Hash()) + }) fullData, err = rlp.EncodeToBytes(account) if err != nil { return stop(err) diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index ee88938b77..c0f0dab568 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -394,7 +394,7 @@ func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([ if storage, ok := dl.storageData[accountHash]; ok { if data, ok := storage[storageHash]; ok { snapshotDirtyStorageHitMeter.Mark(1) - snapshotDirtyStorageHitDepthHist.Update(int64(depth)) + //snapshotDirtyStorageHitDepthHist.Update(int64(depth)) if n := len(data); n > 0 { snapshotDirtyStorageReadMeter.Mark(int64(n)) } else { @@ -407,7 +407,7 @@ func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([ // If the account is known locally, but deleted, return an empty slot if _, ok := dl.destructSet[accountHash]; ok { snapshotDirtyStorageHitMeter.Mark(1) - snapshotDirtyStorageHitDepthHist.Update(int64(depth)) + //snapshotDirtyStorageHitDepthHist.Update(int64(depth)) snapshotDirtyStorageInexMeter.Mark(1) snapshotBloomStorageTrueHitMeter.Mark(1) return nil, nil diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 3ed534461b..1b0d883439 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -158,11 +158,12 @@ 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 { - 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 + 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 + capLimit int } // New attempts to load an already existing snapshot from a persistent key-value @@ -174,13 +175,14 @@ type Tree struct { // store, on a background thread. If the memory layers from the journal is not // continuous with disk layer or the journal is missing, all diffs will be discarded // iff it's in "recovery" mode, otherwise rebuild is mandatory. -func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, root common.Hash, async bool, rebuild bool, recovery bool) (*Tree, error) { +func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache, cap int, root common.Hash, async bool, rebuild bool, recovery bool) (*Tree, error) { // Create a new, empty snapshot tree snap := &Tree{ - diskdb: diskdb, - triedb: triedb, - cache: cache, - layers: make(map[common.Hash]snapshot), + diskdb: diskdb, + triedb: triedb, + cache: cache, + capLimit: cap, + layers: make(map[common.Hash]snapshot), } if !async { defer snap.waitBuild() @@ -348,6 +350,10 @@ func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs m return nil } +func (t *Tree) CapLimit() int { + return t.capLimit +} + // Cap traverses downwards the snapshot tree from a head block hash until the // number of allowed layers are crossed. All layers beyond the permitted number // are flattened downwards. diff --git a/core/state/state_object.go b/core/state/state_object.go index f93f47d5f5..623d07ac13 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -56,13 +56,13 @@ func (s Storage) Copy() Storage { return cpy } -// stateObject represents an Ethereum account which is being modified. +// StateObject represents an Ethereum account which is being modified. // // 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. -type stateObject struct { +type StateObject struct { address common.Address addrHash common.Hash // hash of ethereum address of the account data Account @@ -90,10 +90,13 @@ type stateObject struct { dirtyCode bool // true if the code was updated suicided bool deleted bool + + //encode + encodeData []byte } // empty returns whether the account is considered empty. -func (s *stateObject) empty() bool { +func (s *StateObject) empty() bool { return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash) } @@ -107,7 +110,7 @@ type Account struct { } // newObject creates a state object. -func newObject(db *StateDB, address common.Address, data Account) *stateObject { +func newObject(db *StateDB, address common.Address, data Account) *StateObject { if data.Balance == nil { data.Balance = new(big.Int) } @@ -117,7 +120,7 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject { if data.Root == (common.Hash{}) { data.Root = emptyRoot } - return &stateObject{ + return &StateObject{ db: db, address: address, addrHash: crypto.Keccak256Hash(address[:]), @@ -129,22 +132,22 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject { } // EncodeRLP implements rlp.Encoder. -func (s *stateObject) EncodeRLP(w io.Writer) error { +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) { +func (s *StateObject) setError(err error) { if s.dbErr == nil { s.dbErr = err } } -func (s *stateObject) markSuicided() { +func (s *StateObject) markSuicided() { s.suicided = true } -func (s *stateObject) touch() { +func (s *StateObject) touch() { s.db.journal.append(touchChange{ account: &s.address, }) @@ -155,7 +158,7 @@ func (s *stateObject) touch() { } } -func (s *stateObject) getTrie(db Database) Trie { +func (s *StateObject) getTrie(db Database) Trie { if s.trie == nil { // Try fetching from prefetcher first // We don't prefetch empty tries @@ -177,7 +180,7 @@ func (s *stateObject) getTrie(db Database) Trie { } // GetState retrieves a value from the account storage trie. -func (s *stateObject) GetState(db Database, key common.Hash) common.Hash { +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] @@ -192,7 +195,7 @@ 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 { +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] @@ -265,7 +268,7 @@ 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) { +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 @@ -291,7 +294,7 @@ func (s *stateObject) SetState(db Database, key, value common.Hash) { // 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) { +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) @@ -303,13 +306,13 @@ func (s *stateObject) SetStorage(storage map[common.Hash]common.Hash) { // debugging and the `fake` storage won't be committed to database. } -func (s *stateObject) setState(key, value common.Hash) { +func (s *StateObject) setState(key, value common.Hash) { s.dirtyStorage[key] = value } // finalise moves all dirty storage slots into the pending area to be hashed or // committed later. It is invoked at the end of every transaction. -func (s *stateObject) finalise(prefetch bool) { +func (s *StateObject) finalise(prefetch bool) { slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage)) for key, value := range s.dirtyStorage { s.pendingStorage[key] = value @@ -318,7 +321,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.data.Root, slotsToPrefetch, s.addrHash) } if len(s.dirtyStorage) > 0 { s.dirtyStorage = make(Storage) @@ -327,7 +330,7 @@ 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 { +func (s *StateObject) updateTrie(db Database) Trie { // Make sure all dirty slots are finalized into the pending storage area s.finalise(false) // Don't prefetch any more, pull directly if need be if len(s.pendingStorage) == 0 { @@ -335,7 +338,11 @@ func (s *stateObject) updateTrie(db Database) Trie { } // 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()) + defer func(start time.Time) { + s.db.MetricsMux.Lock() + s.db.StorageUpdates += time.Since(start) + s.db.MetricsMux.Unlock() + }(time.Now()) } // The snapshot storage map for the object var storage map[common.Hash][]byte @@ -361,6 +368,7 @@ func (s *stateObject) updateTrie(db Database) Trie { } // If state snapshotting is active, cache the data til commit if s.db.snap != nil { + s.db.snapMux.Lock() if storage == nil { // Retrieve the old storage map, if available, create a new one otherwise if storage = s.db.snapStorage[s.addrHash]; storage == nil { @@ -369,6 +377,7 @@ func (s *stateObject) updateTrie(db Database) Trie { } } storage[crypto.HashData(hasher, key[:])] = v // v will be nil if value is 0x00 + s.db.snapMux.Unlock() } usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure } @@ -382,23 +391,30 @@ func (s *stateObject) updateTrie(db Database) Trie { } // UpdateRoot sets the trie root to the current root hash of -func (s *stateObject) updateRoot(db Database) { +func (s *StateObject) updateRoot(db Database) { // If nothing changed, don't bother with hashing anything if s.updateTrie(db) == 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()) + defer func(start time.Time) { + s.db.MetricsMux.Lock() + s.db.StorageHashes += time.Since(start) + s.db.MetricsMux.Unlock() + }(time.Now()) } 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) error { +func (s *StateObject) CommitTrie(db Database) error { // If nothing changed, don't bother with hashing anything if s.updateTrie(db) == nil { + if s.trie != nil && s.data.Root != emptyRoot { + db.CacheStorage(s.addrHash, s.data.Root, s.trie) + } return nil } if s.dbErr != nil { @@ -412,12 +428,15 @@ func (s *stateObject) CommitTrie(db Database) error { if err == nil { s.data.Root = root } + if s.data.Root != emptyRoot { + db.CacheStorage(s.addrHash, s.data.Root, s.trie) + } return err } // AddBalance adds amount to s's balance. // It is used to add funds to the destination account of a transfer. -func (s *stateObject) AddBalance(amount *big.Int) { +func (s *StateObject) AddBalance(amount *big.Int) { // EIP161: We must check emptiness for the objects such that the account // clearing (0,0,0 objects) can take effect. if amount.Sign() == 0 { @@ -431,14 +450,14 @@ func (s *stateObject) AddBalance(amount *big.Int) { // SubBalance removes amount from s's balance. // It is used to remove funds from the origin account of a transfer. -func (s *stateObject) SubBalance(amount *big.Int) { +func (s *StateObject) SubBalance(amount *big.Int) { if amount.Sign() == 0 { return } s.SetBalance(new(big.Int).Sub(s.Balance(), amount)) } -func (s *stateObject) SetBalance(amount *big.Int) { +func (s *StateObject) SetBalance(amount *big.Int) { s.db.journal.append(balanceChange{ account: &s.address, prev: new(big.Int).Set(s.data.Balance), @@ -446,14 +465,14 @@ func (s *stateObject) SetBalance(amount *big.Int) { s.setBalance(amount) } -func (s *stateObject) setBalance(amount *big.Int) { +func (s *StateObject) setBalance(amount *big.Int) { s.data.Balance = amount } // Return the gas back to the origin. Used by the Virtual machine or Closures -func (s *stateObject) ReturnGas(gas *big.Int) {} +func (s *StateObject) ReturnGas(gas *big.Int) {} -func (s *stateObject) deepCopy(db *StateDB) *stateObject { +func (s *StateObject) deepCopy(db *StateDB) *StateObject { stateObject := newObject(db, s.address, s.data) if s.trie != nil { stateObject.trie = db.db.CopyTrie(s.trie) @@ -473,12 +492,12 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject { // // Returns the address of the contract/account -func (s *stateObject) Address() common.Address { +func (s *StateObject) Address() common.Address { return s.address } // Code returns the contract code associated with this object, if any. -func (s *stateObject) Code(db Database) []byte { +func (s *StateObject) Code(db Database) []byte { if s.code != nil { return s.code } @@ -496,7 +515,7 @@ func (s *stateObject) Code(db Database) []byte { // CodeSize returns the size of the contract code associated with this object, // or zero if none. This method is an almost mirror of Code, but uses a cache // inside the database to avoid loading codes seen recently. -func (s *stateObject) CodeSize(db Database) int { +func (s *StateObject) CodeSize(db Database) int { if s.code != nil { return len(s.code) } @@ -510,7 +529,7 @@ func (s *stateObject) CodeSize(db Database) int { return size } -func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { +func (s *StateObject) SetCode(codeHash common.Hash, code []byte) { prevcode := s.Code(s.db.db) s.db.journal.append(codeChange{ account: &s.address, @@ -520,13 +539,13 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { s.setCode(codeHash, code) } -func (s *stateObject) setCode(codeHash common.Hash, code []byte) { +func (s *StateObject) setCode(codeHash common.Hash, code []byte) { s.code = code s.data.CodeHash = codeHash[:] s.dirtyCode = true } -func (s *stateObject) SetNonce(nonce uint64) { +func (s *StateObject) SetNonce(nonce uint64) { s.db.journal.append(nonceChange{ account: &s.address, prev: s.data.Nonce, @@ -534,25 +553,25 @@ func (s *stateObject) SetNonce(nonce uint64) { s.setNonce(nonce) } -func (s *stateObject) setNonce(nonce uint64) { +func (s *StateObject) setNonce(nonce uint64) { s.data.Nonce = nonce } -func (s *stateObject) CodeHash() []byte { +func (s *StateObject) CodeHash() []byte { return s.data.CodeHash } -func (s *stateObject) Balance() *big.Int { +func (s *StateObject) Balance() *big.Int { return s.data.Balance } -func (s *stateObject) Nonce() uint64 { +func (s *StateObject) Nonce() uint64 { return s.data.Nonce } -// Never called, but must be present to allow stateObject to be used +// 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") +func (s *StateObject) Value() *big.Int { + panic("Value on StateObject should never be called") } diff --git a/core/state/state_test.go b/core/state/state_test.go index 9566531466..9f003fefb5 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -165,7 +165,7 @@ func TestSnapshot2(t *testing.T) { so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) so0.suicided = false so0.deleted = false - state.setStateObject(so0) + state.SetStateObject(so0) root, _ := state.Commit(false) state, _ = New(root, state.db, state.snaps) @@ -177,7 +177,7 @@ func TestSnapshot2(t *testing.T) { so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) so1.suicided = true so1.deleted = true - state.setStateObject(so1) + state.SetStateObject(so1) so1 = state.getStateObject(stateobjaddr1) if so1 != nil { @@ -201,7 +201,7 @@ func TestSnapshot2(t *testing.T) { } } -func compareStateObjects(so0, so1 *stateObject, t *testing.T) { +func compareStateObjects(so0, so1 *StateObject, t *testing.T) { if so0.Address() != so1.Address() { t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 90f4709bfc..7940613cd6 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -21,7 +21,9 @@ import ( "errors" "fmt" "math/big" + "runtime" "sort" + "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -29,12 +31,18 @@ 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/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) +const ( + preLoadLimit = 64 + defaultNumOfSlots = 100 +) + type revision struct { id int journalIndex int @@ -43,6 +51,8 @@ type revision struct { var ( // emptyRoot is the known root hash of an empty trie. emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + + emptyAddr = crypto.Keccak256Hash(common.Address{}.Bytes()) ) type proofList [][]byte @@ -68,6 +78,7 @@ type StateDB struct { trie Trie hasher crypto.KeccakState + snapMux sync.Mutex snaps *snapshot.Tree snap snapshot.Snapshot snapDestructs map[common.Hash]struct{} @@ -75,7 +86,7 @@ type StateDB struct { 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 + 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 @@ -106,6 +117,7 @@ type StateDB struct { nextRevisionId int // Measurements gathered during execution for debugging purposes + MetricsMux sync.Mutex AccountReads time.Duration AccountHashes time.Duration AccountUpdates time.Duration @@ -121,24 +133,27 @@ type StateDB struct { // New creates a new state from a given trie. func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { - tr, err := db.OpenTrie(root) - if err != nil { - return nil, err - } + return newStateDB(root, db, snaps) +} + +func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { 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), + stateObjects: make(map[common.Address]*StateObject, defaultNumOfSlots), + stateObjectsPending: make(map[common.Address]struct{}, defaultNumOfSlots), + stateObjectsDirty: make(map[common.Address]struct{}, defaultNumOfSlots), + logs: make(map[common.Hash][]*types.Log, defaultNumOfSlots), preimages: make(map[common.Hash][]byte), journal: newJournal(), - accessList: newAccessList(), hasher: crypto.NewKeccakState(), } + tr, err := db.OpenTrie(root) + if err != nil { + return nil, err + } + sdb.trie = tr if sdb.snaps != nil { if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil { sdb.snapDestructs = make(map[common.Hash]struct{}) @@ -461,33 +476,28 @@ func (s *StateDB) Suicide(addr common.Address) bool { // // updateStateObject writes the given object to the trie. -func (s *StateDB) updateStateObject(obj *stateObject) { +func (s *StateDB) updateStateObject(obj *StateObject) { // Track the amount of time wasted on updating the account from the trie if metrics.EnabledExpensive { defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) } // Encode the account and update the account trie addr := obj.Address() - - data, err := rlp.EncodeToBytes(obj) - if err != nil { - panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err)) + data := obj.encodeData + var err error + if data == nil { + data, err = rlp.EncodeToBytes(obj) + if err != nil { + panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err)) + } } if err = s.trie.TryUpdate(addr[:], data); err != nil { s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) } - - // If state snapshotting is active, cache the data til commit. Note, this - // update mechanism is not symmetric to the deletion, because whereas it is - // enough to track account updates at commit time, deletions need tracking - // at transaction boundary level to ensure we capture state clearing. - if s.snap != nil { - s.snapAccounts[obj.addrHash] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash) - } } // deleteStateObject removes the given object from the state trie. -func (s *StateDB) deleteStateObject(obj *stateObject) { +func (s *StateDB) deleteStateObject(obj *StateObject) { // Track the amount of time wasted on deleting the account from the trie if metrics.EnabledExpensive { defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) @@ -502,18 +512,92 @@ func (s *StateDB) deleteStateObject(obj *stateObject) { // getStateObject retrieves a state object given by the address, returning nil if // the object is not found or was deleted in this execution context. If you need // to differentiate between non-existent/just-deleted, use getDeletedStateObject. -func (s *StateDB) getStateObject(addr common.Address) *stateObject { +func (s *StateDB) getStateObject(addr common.Address) *StateObject { if obj := s.getDeletedStateObject(addr); obj != nil && !obj.deleted { return obj } return nil } +func (s *StateDB) TryPreload(block *types.Block, signer types.Signer) { + accounts := make(map[common.Address]bool, block.Transactions().Len()) + accountsSlice := make([]common.Address, 0, block.Transactions().Len()) + for _, tx := range block.Transactions() { + from, err := types.Sender(signer, tx) + if err != nil { + break + } + accounts[from] = true + if tx.To() != nil { + accounts[*tx.To()] = true + } + } + for account, _ := range accounts { + accountsSlice = append(accountsSlice, account) + } + if len(accountsSlice) >= preLoadLimit && len(accountsSlice) > runtime.NumCPU() { + objsChan := make(chan []*StateObject, runtime.NumCPU()) + for i := 0; i < runtime.NumCPU(); i++ { + start := i * len(accountsSlice) / runtime.NumCPU() + end := (i + 1) * len(accountsSlice) / runtime.NumCPU() + if i+1 == runtime.NumCPU() { + end = len(accountsSlice) + } + go func(start, end int) { + objs := s.preloadStateObject(accountsSlice[start:end]) + objsChan <- objs + }(start, end) + } + for i := 0; i < runtime.NumCPU(); i++ { + objs := <-objsChan + if objs != nil { + for _, obj := range objs { + s.SetStateObject(obj) + } + } + } + } +} + +func (s *StateDB) preloadStateObject(address []common.Address) []*StateObject { + // Prefer live objects if any is available + if s.snap == nil { + return nil + } + hasher := crypto.NewKeccakState() + objs := make([]*StateObject, 0, len(address)) + for _, addr := range address { + // If no live objects are available, attempt to use snapshots + if acc, err := s.snap.Account(crypto.HashData(hasher, addr.Bytes())); err == nil { + if acc == nil { + continue + } + data := &Account{ + Nonce: acc.Nonce, + Balance: acc.Balance, + CodeHash: acc.CodeHash, + Root: common.BytesToHash(acc.Root), + } + if len(data.CodeHash) == 0 { + data.CodeHash = emptyCodeHash + } + if data.Root == (common.Hash{}) { + data.Root = emptyRoot + } + // Insert into the live set + obj := newObject(s, addr, *data) + objs = append(objs, obj) + } + // Do not enable this feature when snapshot is not enabled. + } + return objs +} + // getDeletedStateObject is similar to getStateObject, but instead of returning // nil for a deleted state object, it returns the actual object with the deleted // flag set. This is needed by the state journal to revert to the correct s- // destructed object instead of wiping all knowledge about the state object. -func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { +func (s *StateDB) getDeletedStateObject(addr common.Address) *StateObject { // Prefer live objects if any is available if obj := s.stateObjects[addr]; obj != nil { return obj @@ -548,6 +632,14 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { } // If snapshot unavailable or reading from it failed, load from the database if s.snap == nil || err != nil { + if s.trie == nil { + tr, err := s.db.OpenTrie(s.originalRoot) + if err != nil { + s.setError(fmt.Errorf("failed to open trie tree")) + return nil + } + s.trie = tr + } if metrics.EnabledExpensive { defer func(start time.Time) { s.AccountReads += time.Since(start) }(time.Now()) } @@ -567,16 +659,16 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { } // Insert into the live set obj := newObject(s, addr, *data) - s.setStateObject(obj) + s.SetStateObject(obj) return obj } -func (s *StateDB) setStateObject(object *stateObject) { +func (s *StateDB) SetStateObject(object *StateObject) { s.stateObjects[object.Address()] = object } // GetOrNewStateObject retrieves a state object or create a new state object if nil. -func (s *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { +func (s *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { stateObject := s.getStateObject(addr) if stateObject == nil { stateObject, _ = s.createObject(addr) @@ -586,7 +678,7 @@ func (s *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { // createObject creates a new state object. If there is an existing account with // the given address, it is overwritten and returned as the second return value. -func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { +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 @@ -603,7 +695,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) } else { s.journal.append(resetObjectChange{prev: prev, prevdestruct: prevdestruct}) } - s.setStateObject(newobj) + s.SetStateObject(newobj) if prev != nil && !prev.deleted { return newobj, prev } @@ -663,7 +755,7 @@ func (s *StateDB) Copy() *StateDB { state := &StateDB{ db: s.db, trie: s.db.CopyTrie(s.trie), - stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)), + 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, @@ -720,7 +812,9 @@ func (s *StateDB) Copy() *StateDB { // _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 - state.accessList = s.accessList.Copy() + if s.accessList != nil { + state.accessList = s.accessList.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 @@ -816,16 +910,19 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { } else { obj.finalise(true) // Prefetch slots in the background } - s.stateObjectsPending[addr] = struct{}{} - s.stateObjectsDirty[addr] = struct{}{} - - // At this point, also ship the address off to the precacher. The precacher - // will start loading tries, and when the change is eventually committed, - // the commit-phase will be a lot faster - addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure + if _, exist := s.stateObjectsPending[addr]; !exist { + s.stateObjectsPending[addr] = struct{}{} + } + if _, exist := s.stateObjectsDirty[addr]; !exist { + s.stateObjectsDirty[addr] = struct{}{} + // At this point, also ship the address off to the precacher. The precacher + // will start loading tries, and when the change is eventually committed, + // the commit-phase will be a lot faster + 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(s.originalRoot, addressesToPrefetch, emptyAddr) } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() @@ -852,6 +949,23 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.prefetcher = nil }() } + + tasks := make(chan func()) + finishCh := make(chan struct{}) + defer close(finishCh) + wg := sync.WaitGroup{} + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + for { + select { + case task := <-tasks: + task() + case <-finishCh: + return + } + } + }() + } // 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 @@ -859,9 +973,29 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // to pull useful data from disk. for addr := range s.stateObjectsPending { if obj := s.stateObjects[addr]; !obj.deleted { - obj.updateRoot(s.db) + wg.Add(1) + tasks <- func() { + obj.updateRoot(s.db) + + // If state snapshotting is active, cache the data til commit. Note, this + // update mechanism is not symmetric to the deletion, because whereas it is + // enough to track account updates at commit time, deletions need tracking + // at transaction boundary level to ensure we capture state clearing. + if s.snap != nil && !obj.deleted { + s.snapMux.Lock() + s.snapAccounts[obj.addrHash] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash) + s.snapMux.Unlock() + } + data, err := rlp.EncodeToBytes(obj) + if err != nil { + panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err)) + } + obj.encodeData = data + wg.Done() + } } } + wg.Wait() // Now we're about to start to write changes to the trie. The trie is so far // _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. @@ -870,6 +1004,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.trie = trie } } + if s.trie == nil { + tr, err := s.db.OpenTrie(s.originalRoot) + if err != nil { + panic(fmt.Sprintf("Failed to open trie tree")) + } + s.trie = tr + } usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) for addr := range s.stateObjectsPending { if obj := s.stateObjects[addr]; obj.deleted { @@ -889,7 +1030,8 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if metrics.EnabledExpensive { defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) } - return s.trie.Hash() + root := s.trie.Hash() + return root } // Prepare sets the current transaction hash and index and block hash which is @@ -898,7 +1040,7 @@ func (s *StateDB) Prepare(thash, bhash common.Hash, ti int) { s.thash = thash s.bhash = bhash s.txIndex = ti - s.accessList = newAccessList() + s.accessList = nil } func (s *StateDB) clearJournalAndRefund() { @@ -915,72 +1057,130 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) } // Finalize any pending changes and merge everything into the tries - s.IntermediateRoot(deleteEmptyObjects) + root := s.IntermediateRoot(deleteEmptyObjects) + + commitFuncs := []func() error{ + func() error { + // Commit objects to the trie, measuring the elapsed time + tasks := make(chan func(batch ethdb.KeyValueWriter)) + taskResults := make(chan error, len(s.stateObjectsDirty)) + tasksNum := 0 + finishCh := make(chan struct{}) + defer close(finishCh) + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + codeWriter := s.db.TrieDB().DiskDB().NewBatch() + for { + select { + case task := <-tasks: + task(codeWriter) + case <-finishCh: + if codeWriter.ValueSize() > 0 { + if err := codeWriter.Write(); err != nil { + log.Crit("Failed to commit dirty codes", "error", err) + } + } + return + } + } + }() + } - // Commit objects to the trie, measuring the elapsed time - codeWriter := s.db.TrieDB().DiskDB().NewBatch() - for addr := range s.stateObjectsDirty { - if obj := s.stateObjects[addr]; !obj.deleted { - // Write any contract code associated with the state object - if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) - obj.dirtyCode = false + for addr := range s.stateObjectsDirty { + if obj := s.stateObjects[addr]; !obj.deleted { + // Write any contract code associated with the state object + tasks <- func(codeWriter ethdb.KeyValueWriter) { + if obj.code != nil && obj.dirtyCode { + rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) + obj.dirtyCode = false + } + // Write any storage changes in the state object to its storage trie + if err := obj.CommitTrie(s.db); err != nil { + taskResults <- err + } + taskResults <- nil + } + tasksNum++ + } } - // Write any storage changes in the state object to its storage trie - if err := obj.CommitTrie(s.db); err != nil { - return common.Hash{}, err + + for i := 0; i < tasksNum; i++ { + err := <-taskResults + if err != nil { + return err + } } - } - } - if len(s.stateObjectsDirty) > 0 { - s.stateObjectsDirty = make(map[common.Address]struct{}) - } - if codeWriter.ValueSize() > 0 { - if err := codeWriter.Write(); err != nil { - log.Crit("Failed to commit dirty codes", "error", err) - } - } - // Write the account trie changes, measuing the amount of wasted time - var start time.Time - 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 Account - root, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash) error { - if err := rlp.DecodeBytes(leaf, &account); err != nil { - return nil - } - if account.Root != emptyRoot { - s.db.TrieDB().Reference(account.Root, parent) - } - return nil - }) - if metrics.EnabledExpensive { - s.AccountCommits += time.Since(start) - } - // 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()) - } - // 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 { - log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) + + if len(s.stateObjectsDirty) > 0 { + s.stateObjectsDirty = make(map[common.Address]struct{}, len(s.stateObjectsDirty)/2) + } + // Write the account trie changes, measuing the amount of wasted time + var start time.Time + 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 Account + root, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash) error { + if err := rlp.DecodeBytes(leaf, &account); err != nil { + return nil + } + if account.Root != emptyRoot { + s.db.TrieDB().Reference(account.Root, parent) + } + return nil + }) + if err != nil { + return err + } + if metrics.EnabledExpensive { + s.AccountCommits += time.Since(start) } - // Keep 128 diff layers in the memory, persistent layer is 129th. - // - head layer is paired with HEAD state - // - head-1 layer is paired with HEAD-1 state - // - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state - if err := s.snaps.Cap(root, 128); err != nil { - log.Warn("Failed to cap snapshot tree", "root", root, "layers", 128, "err", err) + if root != emptyRoot { + s.db.CacheAccount(root, s.trie) } + return nil + }, + func() error { + // 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()) + } + // 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 { + log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) + } + // Keep n diff layers in the memory + // - head layer is paired with HEAD state + // - head-1 layer is paired with HEAD-1 state + // - head-(n-1) layer(bottom-most diff layer) is paired with HEAD-(n-1)state + if err := s.snaps.Cap(root, s.snaps.CapLimit()); err != nil { + log.Warn("Failed to cap snapshot tree", "root", root, "layers", s.snaps.CapLimit(), "err", err) + } + } + s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil + } + return nil + }, + } + commitRes := make(chan error, len(commitFuncs)) + for _, f := range commitFuncs { + tmpFunc := f + go func() { + commitRes <- tmpFunc() + }() + } + for i := 0; i < len(commitFuncs); i++ { + r := <-commitRes + if r != nil { + return common.Hash{}, r } - s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil } - return root, err + + return root, nil } // PrepareAccessList handles the preparatory steps for executing a state transition with @@ -1011,6 +1211,9 @@ func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, // AddAddressToAccessList adds the given address to the access list func (s *StateDB) AddAddressToAccessList(addr common.Address) { + if s.accessList == nil { + s.accessList = newAccessList() + } if s.accessList.AddAddress(addr) { s.journal.append(accessListAddAccountChange{&addr}) } @@ -1018,6 +1221,9 @@ func (s *StateDB) AddAddressToAccessList(addr common.Address) { // AddSlotToAccessList adds the given (address, slot)-tuple to the access list func (s *StateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) { + if s.accessList == nil { + s.accessList = newAccessList() + } addrMod, slotMod := s.accessList.AddSlot(addr, slot) if addrMod { // In practice, this should not happen, since there is no way to enter the @@ -1036,10 +1242,16 @@ func (s *StateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) { // AddressInAccessList returns true if the given address is in the access list. func (s *StateDB) AddressInAccessList(addr common.Address) bool { + if s.accessList == nil { + return false + } return s.accessList.ContainsAddress(addr) } // SlotInAccessList returns true if the given (address, slot)-tuple is in the access list. func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) { + if s.accessList == nil { + return false, false + } return s.accessList.Contains(addr, slot) } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index ac5e95c5c2..c8667deae3 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -20,6 +20,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" ) @@ -139,7 +140,7 @@ func (p *triePrefetcher) copy() *triePrefetcher { } // prefetch schedules a batch of trie items to prefetch. -func (p *triePrefetcher) prefetch(root common.Hash, keys [][]byte) { +func (p *triePrefetcher) prefetch(root common.Hash, keys [][]byte, accountHash common.Hash) { // If the prefetcher is an inactive one, bail out if p.fetches != nil { return @@ -147,7 +148,7 @@ func (p *triePrefetcher) prefetch(root common.Hash, keys [][]byte) { // Active fetcher, schedule the retrievals fetcher := p.fetchers[root] if fetcher == nil { - fetcher = newSubfetcher(p.db, root) + fetcher = newSubfetcher(p.db, root, accountHash) p.fetchers[root] = fetcher } fetcher.schedule(keys) @@ -211,21 +212,26 @@ type subfetcher struct { seen map[string]struct{} // Tracks the entries already loaded dups int // Number of duplicate preload tasks used [][]byte // Tracks the entries used in the end + + accountHash common.Hash } // 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, root common.Hash, accountHash 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, + 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{}), + accountHash: accountHash, } - go sf.loop() + gopool.Submit(func() { + sf.loop() + }) return sf } @@ -279,7 +285,14 @@ 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) + var trie Trie + var err error + if sf.accountHash == emptyAddr { + trie, err = sf.db.OpenTrie(sf.root) + } else { + // address is useless + trie, err = sf.db.OpenStorageTrie(sf.accountHash, sf.root) + } if err != nil { log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) return diff --git a/core/state_processor.go b/core/state_processor.go index 84372082d2..858796b67a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -79,6 +79,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg commonTxs := make([]*types.Transaction, 0, len(block.Transactions())) // usually do have two tx, one for validator set contract, another for system reward contract. systemTxs := make([]*types.Transaction, 0, 2) + signer := types.MakeSigner(p.config, header.Number) for i, tx := range block.Transactions() { if isPoSA { if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { @@ -89,7 +90,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } } - msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number)) + msg, err := tx.AsMessage(signer) if err != nil { return nil, nil, 0, err } @@ -102,6 +103,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg commonTxs = append(commonTxs, tx) receipts = append(receipts, receipt) } + // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) err := p.engine.Finalize(p.bc, header, statedb, &commonTxs, block.Uncles(), &receipts, &systemTxs, usedGas) if err != nil { @@ -171,5 +173,10 @@ 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) + defer func() { + ite := vmenv.Interpreter() + vm.EVMInterpreterPool.Put(ite) + vm.EvmPool.Put(vmenv) + }() return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv) } diff --git a/core/tx_list.go b/core/tx_list.go index 894640d570..ec122a7384 100644 --- a/core/tx_list.go +++ b/core/tx_list.go @@ -21,11 +21,18 @@ import ( "math" "math/big" "sort" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) +var txSortedMapPool = sync.Pool{ + New: func() interface{} { + return make(types.Transactions, 0, 10) + }, +} + // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for // retrieving sorted transactions from the possibly gapped future queue. type nonceHeap []uint64 @@ -74,6 +81,9 @@ func (m *txSortedMap) Put(tx *types.Transaction) { if m.items[nonce] == nil { heap.Push(m.index, nonce) } + if m.cache != nil { + txSortedMapPool.Put(m.cache) + } m.items[nonce], m.cache = tx, nil } @@ -132,7 +142,10 @@ func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transac } } if len(removed) > 0 { - m.cache = nil + if m.cache != nil { + txSortedMapPool.Put(m.cache) + m.cache = nil + } } return removed } @@ -178,7 +191,10 @@ func (m *txSortedMap) Remove(nonce uint64) bool { } } delete(m.items, nonce) - m.cache = nil + if m.cache != nil { + txSortedMapPool.Put(m.cache) + m.cache = nil + } return true } @@ -202,7 +218,10 @@ func (m *txSortedMap) Ready(start uint64) types.Transactions { delete(m.items, next) heap.Pop(m.index) } - m.cache = nil + if m.cache != nil { + txSortedMapPool.Put(m.cache) + m.cache = nil + } return ready } @@ -215,7 +234,13 @@ func (m *txSortedMap) Len() int { func (m *txSortedMap) 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)) + cache := txSortedMapPool.Get() + if cache != nil { + m.cache = cache.(types.Transactions) + m.cache = m.cache[:0] + } else { + m.cache = make(types.Transactions, 0, len(m.items)) + } for _, tx := range m.items { m.cache = append(m.cache, tx) } @@ -384,7 +409,7 @@ func (l *txList) Ready(start uint64) types.Transactions { // Len returns the length of the transaction list. func (l *txList) Len() int { - return l.txs.Len() + return len(l.txs.items) } // Empty returns whether the list of transactions is empty or not. diff --git a/core/tx_pool.go b/core/tx_pool.go index 5db1d3df32..d0304857c3 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -456,11 +456,11 @@ func (pool *TxPool) Stats() (int, int) { func (pool *TxPool) stats() (int, int) { pending := 0 for _, list := range pool.pending { - pending += list.Len() + pending += len(list.txs.items) } queued := 0 for _, list := range pool.queue { - queued += list.Len() + queued += len(list.txs.items) } return pending, queued } @@ -580,7 +580,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e // If the transaction is already known, discard it hash := tx.Hash() if pool.all.Get(hash) != nil { - log.Trace("Discarding already known transaction", "hash", hash) + //log.Trace("Discarding already known transaction", "hash", hash) knownTxMeter.Mark(1) return false, ErrAlreadyKnown } @@ -590,7 +590,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e // If the transaction fails basic validation, discard it if err := pool.validateTx(tx, isLocal); err != nil { - log.Trace("Discarding invalid transaction", "hash", hash, "err", err) + //log.Trace("Discarding invalid transaction", "hash", hash, "err", err) invalidTxMeter.Mark(1) return false, err } @@ -598,7 +598,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e if uint64(pool.all.Count()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue { // If the new transaction is underpriced, don't accept it if !isLocal && pool.priced.Underpriced(tx) { - log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) + //log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) underpricedTxMeter.Mark(1) return false, ErrUnderpriced } @@ -609,13 +609,13 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e // Special case, we still can't make the room for the new remote one. if !isLocal && !success { - log.Trace("Discarding overflown transaction", "hash", hash) + //log.Trace("Discarding overflown transaction", "hash", hash) overflowedTxMeter.Mark(1) return false, ErrTxPoolOverflow } // Kick out the underpriced remote transactions. for _, tx := range drop { - log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) + //log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) underpricedTxMeter.Mark(1) pool.removeTx(tx.Hash(), false) } @@ -639,7 +639,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e pool.priced.Put(tx, isLocal) pool.journalTx(from, tx) pool.queueTxEvent(tx) - log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) + //log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) // Successful promotion, bump the heartbeat pool.beats[from] = time.Now() @@ -652,7 +652,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e } // Mark local addresses and journal local transactions if local && !pool.locals.contains(from) { - log.Info("Setting new local account", "address", from) + //log.Info("Setting new local account", "address", from) pool.locals.add(from) pool.priced.Removed(pool.all.RemoteToLocals(pool.locals)) // Migrate the remotes if it's marked as local first time. } @@ -661,7 +661,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e } pool.journalTx(from, tx) - log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) + //log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) return replaced, nil } @@ -1070,7 +1070,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt // Nonces were reset, discard any events that became stale for addr := range events { events[addr].Forward(pool.pendingNonces.get(addr)) - if events[addr].Len() == 0 { + if len(events[addr].items) == 0 { delete(events, addr) } } @@ -1279,7 +1279,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans func (pool *TxPool) truncatePending() { pending := uint64(0) for _, list := range pool.pending { - pending += uint64(list.Len()) + pending += uint64(len(list.txs.items)) } if pending <= pool.config.GlobalSlots { return @@ -1290,8 +1290,8 @@ func (pool *TxPool) truncatePending() { spammers := prque.New(nil) for addr, list := range pool.pending { // Only evict transactions from high rollers - if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { - spammers.Push(addr, int64(list.Len())) + if !pool.locals.contains(addr) && uint64(len(list.txs.items)) > pool.config.AccountSlots { + spammers.Push(addr, int64(len(list.txs.items))) } } // Gradually drop transactions from offenders @@ -1304,14 +1304,14 @@ func (pool *TxPool) truncatePending() { // 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 := len(pool.pending[offender.(common.Address)].txs.items) // Iteratively reduce all offenders until below limit or threshold reached - for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { + for pending > pool.config.GlobalSlots && len(pool.pending[offenders[len(offenders)-2]].txs.items) > threshold { for i := 0; i < len(offenders)-1; i++ { list := pool.pending[offenders[i]] - caps := list.Cap(list.Len() - 1) + caps := list.Cap(len(list.txs.items) - 1) for _, tx := range caps { // Drop the transaction from the global pools too hash := tx.Hash() @@ -1334,11 +1334,11 @@ func (pool *TxPool) truncatePending() { // If still above threshold, reduce to limit or min allowance if pending > pool.config.GlobalSlots && len(offenders) > 0 { - for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots { + for pending > pool.config.GlobalSlots && uint64(len(pool.pending[offenders[len(offenders)-1]].txs.items)) > pool.config.AccountSlots { for _, addr := range offenders { list := pool.pending[addr] - caps := list.Cap(list.Len() - 1) + caps := list.Cap(len(list.txs.items) - 1) for _, tx := range caps { // Drop the transaction from the global pools too hash := tx.Hash() @@ -1364,7 +1364,7 @@ func (pool *TxPool) truncatePending() { func (pool *TxPool) truncateQueue() { queued := uint64(0) for _, list := range pool.queue { - queued += uint64(list.Len()) + queued += uint64(len(list.txs.items)) } if queued <= pool.config.GlobalQueue { return @@ -1387,7 +1387,7 @@ func (pool *TxPool) truncateQueue() { addresses = addresses[:len(addresses)-1] // Drop all transactions if they are less than the overflow - if size := uint64(list.Len()); size <= drop { + if size := uint64(len(list.txs.items)); size <= drop { for _, tx := range list.Flatten() { pool.removeTx(tx.Hash(), true) } @@ -1442,7 +1442,7 @@ func (pool *TxPool) demoteUnexecutables() { localGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) } // If there's a gap in front, alert (should never happen) and postpone all transactions - if list.Len() > 0 && list.txs.Get(nonce) == nil { + if len(list.txs.items) > 0 && list.txs.Get(nonce) == nil { gapped := list.Cap(0) for _, tx := range gapped { hash := tx.Hash() diff --git a/core/types/block.go b/core/types/block.go index a3318f8779..b33493ef7d 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -306,6 +306,8 @@ func (b *Block) Size() common.StorageSize { return common.StorageSize(c) } +func (b *Block) SetRoot(root common.Hash) { b.header.Root = root } + // SanityCheck can be used to prevent that unbounded fields are // stuffed with junk data to add processing overhead func (b *Block) SanityCheck() error { diff --git a/core/types/transaction.go b/core/types/transaction.go index a35e07a5a3..1bb43d805f 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -260,6 +260,9 @@ func (tx *Transaction) Gas() uint64 { return tx.inner.gas() } // GasPrice returns the gas price of the transaction. func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.inner.gasPrice()) } +// The return value of ImmutableGasPrice can not been modified. +func (tx *Transaction) ImmutableGasPrice() *big.Int { return tx.inner.gasPrice() } + // Value returns the ether amount of the transaction. func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) } @@ -394,7 +397,7 @@ func (s TxByPriceAndTime) Len() int { return len(s) } func (s TxByPriceAndTime) Less(i, j int) bool { // If the prices are equal, use the time the transaction was first seen for // deterministic sorting - cmp := s[i].GasPrice().Cmp(s[j].GasPrice()) + cmp := s[i].ImmutableGasPrice().Cmp(s[j].ImmutableGasPrice()) if cmp == 0 { return s[i].time.Before(s[j].time) } diff --git a/core/vm/evm.go b/core/vm/evm.go index bd54e855c6..26a5fa7c45 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -19,6 +19,7 @@ package vm import ( "errors" "math/big" + "sync" "sync/atomic" "time" @@ -32,6 +33,12 @@ import ( // deployed contract addresses (relevant after the account abstraction). var emptyCodeHash = crypto.Keccak256Hash(nil) +var EvmPool = sync.Pool{ + New: func() interface{} { + return &EVM{} + }, +} + type ( // CanTransferFunc is the signature of a transfer guard function CanTransferFunc func(StateDB, common.Address, *big.Int) bool @@ -144,15 +151,17 @@ type EVM struct { // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { - evm := &EVM{ - Context: blockCtx, - TxContext: txCtx, - StateDB: statedb, - vmConfig: vmConfig, - chainConfig: chainConfig, - chainRules: chainConfig.Rules(blockCtx.BlockNumber), - interpreters: make([]Interpreter, 0, 1), - } + evm := EvmPool.Get().(*EVM) + evm.Context = blockCtx + evm.TxContext = txCtx + evm.StateDB = statedb + evm.vmConfig = vmConfig + evm.chainConfig = chainConfig + evm.chainRules = chainConfig.Rules(blockCtx.BlockNumber) + evm.interpreters = make([]Interpreter, 0, 1) + evm.abort = 0 + evm.callGasTemp = 0 + evm.depth = 0 if chainConfig.IsEWASM(blockCtx.BlockNumber) { // to be implemented by EVM-C and Wagon PRs. diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 08da68ea2a..c004672cae 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -18,6 +18,7 @@ package vm import ( "hash" + "sync" "sync/atomic" "github.com/ethereum/go-ethereum/common" @@ -25,6 +26,12 @@ import ( "github.com/ethereum/go-ethereum/log" ) +var EVMInterpreterPool = sync.Pool{ + New: func() interface{} { + return &EVMInterpreter{} + }, +} + // Config are the configuration options for the Interpreter type Config struct { Debug bool // Enables debugging @@ -124,11 +131,12 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { } cfg.JumpTable = jt } - - return &EVMInterpreter{ - evm: evm, - cfg: cfg, - } + evmInterpreter := EVMInterpreterPool.Get().(*EVMInterpreter) + evmInterpreter.evm = evm + evmInterpreter.cfg = cfg + evmInterpreter.readOnly = false + evmInterpreter.returnData = nil + return evmInterpreter } // Run loops and evaluates the contract's code with the given input data and returns diff --git a/crypto/crypto.go b/crypto/crypto.go index 40969a2895..88c44d0e22 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -29,6 +29,9 @@ import ( "io/ioutil" "math/big" "os" + "sync" + + "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -48,10 +51,17 @@ const DigestLength = 32 var ( secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) + + keccakState256Cache = fastcache.New(100 * 1024 * 1024) ) var errInvalidPubkey = errors.New("invalid secp256k1 public key") +var keccakState256Pool = sync.Pool{ + New: func() interface{} { + return sha3.NewLegacyKeccak256().(KeccakState) + }} + // 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. @@ -67,31 +77,55 @@ func NewKeccakState() KeccakState { // HashData hashes the provided data using the KeccakState and returns a 32 byte hash func HashData(kh KeccakState, data []byte) (h common.Hash) { + if hash, ok := keccakState256Cache.HasGet(nil, data); ok { + return common.BytesToHash(hash) + } kh.Reset() kh.Write(data) kh.Read(h[:]) + keccakState256Cache.Set(data, h.Bytes()) return h } // Keccak256 calculates and returns the Keccak256 hash of the input data. func Keccak256(data ...[]byte) []byte { + if len(data) == 1 { + if hash, ok := keccakState256Cache.HasGet(nil, data[0]); ok { + return hash + } + } b := make([]byte, 32) - d := NewKeccakState() + d := keccakState256Pool.Get().(KeccakState) + defer keccakState256Pool.Put(d) + d.Reset() for _, b := range data { d.Write(b) } d.Read(b) + if len(data) == 1 { + keccakState256Cache.Set(data[0], b) + } return b } // Keccak256Hash calculates and returns the Keccak256 hash of the input data, // converting it to an internal Hash data structure. func Keccak256Hash(data ...[]byte) (h common.Hash) { - d := NewKeccakState() + if len(data) == 1 { + if hash, ok := keccakState256Cache.HasGet(nil, data[0]); ok { + return common.BytesToHash(hash) + } + } + d := keccakState256Pool.Get().(KeccakState) + defer keccakState256Pool.Put(d) + d.Reset() for _, b := range data { d.Write(b) } d.Read(h[:]) + if len(data) == 1 { + keccakState256Cache.Set(data[0], h.Bytes()) + } return h } diff --git a/eth/backend.go b/eth/backend.go index 2247b94b5d..b52591fd71 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -138,7 +138,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } log.Info("Initialised chain configuration", "config", chainConfig) - if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil { + if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal), config.TriesInMemory); err != nil { log.Error("Failed to recover state", "error", err) } eth := &Ethereum{ @@ -186,15 +186,15 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { EVMInterpreter: config.EVMInterpreter, } cacheConfig = &core.CacheConfig{ - TrieCleanLimit: config.TrieCleanCache, - TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal), - TrieCleanRejournal: config.TrieCleanCacheRejournal, - TrieCleanNoPrefetch: config.NoPrefetch, - TrieDirtyLimit: config.TrieDirtyCache, - TrieDirtyDisabled: config.NoPruning, - TrieTimeLimit: config.TrieTimeout, - SnapshotLimit: config.SnapshotCache, - Preimages: config.Preimages, + TrieCleanLimit: config.TrieCleanCache, + TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal), + TrieCleanRejournal: config.TrieCleanCacheRejournal, + TrieDirtyLimit: config.TrieDirtyCache, + TrieDirtyDisabled: config.NoPruning, + TrieTimeLimit: config.TrieTimeout, + SnapshotLimit: config.SnapshotCache, + TriesInMemory: config.TriesInMemory, + Preimages: config.Preimages, } ) eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) diff --git a/eth/bloombits.go b/eth/bloombits.go index 0cb7050d23..314317ae4f 100644 --- a/eth/bloombits.go +++ b/eth/bloombits.go @@ -20,6 +20,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/bitutil" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/core/rawdb" ) @@ -45,7 +46,7 @@ const ( // retrievals from possibly a range of filters and serving the data to satisfy. func (eth *Ethereum) startBloomHandlers(sectionSize uint64) { for i := 0; i < bloomServiceThreads; i++ { - go func() { + gopool.Submit(func() { for { select { case <-eth.closeBloomHandler: @@ -69,6 +70,6 @@ func (eth *Ethereum) startBloomHandlers(sectionSize uint64) { request <- task } } - }() + }) } } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index b8a6e43fcd..001b27147f 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -79,7 +79,11 @@ func generateTestChainWithFork(n int, fork int) (*core.Genesis, []*types.Block, MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), CatalystBlock: big.NewInt(0), - Ethash: new(params.EthashConfig), + RamanujanBlock: big.NewInt(0), + NielsBlock: big.NewInt(0), + MirrorSyncBlock: big.NewInt(0), + + Ethash: new(params.EthashConfig), } genesis := &core.Genesis{ Config: config, diff --git a/eth/downloader/api.go b/eth/downloader/api.go index 2024d23dea..0fea49f7bc 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -21,6 +21,7 @@ import ( "sync" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/rpc" ) @@ -98,7 +99,7 @@ func (api *PublicDownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, rpcSub := notifier.CreateSubscription() - go func() { + gopool.Submit(func() { statuses := make(chan interface{}) sub := api.SubscribeSyncStatus(statuses) @@ -114,7 +115,7 @@ func (api *PublicDownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, return } } - }() + }) return rpcSub, nil } diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go index b3b6cc95a0..4d76988f71 100644 --- a/eth/downloader/peer.go +++ b/eth/downloader/peer.go @@ -150,8 +150,8 @@ func (p *peerConnection) FetchHeaders(from uint64, count int) error { p.headerStarted = time.Now() // Issue the header retrieval request (absolute upwards without gaps) - go p.peer.RequestHeadersByNumber(from, count, 0, false) + go p.peer.RequestHeadersByNumber(from, count, 0, false) return nil } @@ -202,7 +202,6 @@ func (p *peerConnection) FetchNodeData(hashes []common.Hash) error { return errAlreadyFetching } p.stateStarted = time.Now() - go p.peer.RequestNodeData(hashes) return nil diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 1c4b796e9f..40dece429a 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -18,8 +18,6 @@ package ethconfig import ( - "github.com/ethereum/go-ethereum/consensus/parlia" - "github.com/ethereum/go-ethereum/internal/ethapi" "math/big" "os" "os/user" @@ -31,10 +29,12 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/consensus/parlia" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/node" @@ -78,6 +78,7 @@ var Defaults = Config{ TrieCleanCacheRejournal: 60 * time.Minute, TrieDirtyCache: 256, TrieTimeout: 60 * time.Minute, + TriesInMemory: 128, SnapshotCache: 102, Miner: miner.Config{ GasFloor: 8000000, @@ -131,7 +132,6 @@ type Config struct { SnapDiscoveryURLs []string NoPruning bool // Whether to disable pruning and flush everything to disk - NoPrefetch bool // Whether to disable prefetching and only load state on demand DirectBroadcast bool RangeLimit bool @@ -166,6 +166,7 @@ type Config struct { TrieDirtyCache int TrieTimeout time.Duration SnapshotCache int + TriesInMemory uint64 Preimages bool // Mining options diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index ca93b2ad00..fa31b78335 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -45,6 +45,7 @@ func (c Config) MarshalTOML() (interface{}, error) { TrieCleanCacheRejournal time.Duration `toml:",omitempty"` TrieDirtyCache int TrieTimeout time.Duration + TriesInMemory uint64 `toml:",omitempty"` SnapshotCache int Preimages bool Miner miner.Config @@ -67,7 +68,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.EthDiscoveryURLs = c.EthDiscoveryURLs enc.SnapDiscoveryURLs = c.SnapDiscoveryURLs enc.NoPruning = c.NoPruning - enc.NoPrefetch = c.NoPrefetch enc.TxLookupLimit = c.TxLookupLimit enc.Whitelist = c.Whitelist enc.LightServ = c.LightServ @@ -89,6 +89,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.TrieCleanCacheRejournal = c.TrieCleanCacheRejournal enc.TrieDirtyCache = c.TrieDirtyCache enc.TrieTimeout = c.TrieTimeout + enc.TriesInMemory = c.TriesInMemory enc.SnapshotCache = c.SnapshotCache enc.Preimages = c.Preimages enc.Miner = c.Miner @@ -137,6 +138,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` TrieDirtyCache *int TrieTimeout *time.Duration + TriesInMemory *uint64 `toml:",omitempty"` SnapshotCache *int Preimages *bool Miner *miner.Config @@ -174,9 +176,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.NoPruning != nil { c.NoPruning = *dec.NoPruning } - if dec.NoPrefetch != nil { - c.NoPrefetch = *dec.NoPrefetch - } if dec.TxLookupLimit != nil { c.TxLookupLimit = *dec.TxLookupLimit } @@ -240,6 +239,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.TrieTimeout != nil { c.TrieTimeout = *dec.TrieTimeout } + if dec.TriesInMemory != nil { + c.TriesInMemory = *dec.TriesInMemory + } if dec.SnapshotCache != nil { c.SnapshotCache = *dec.SnapshotCache } diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index fc75dd4310..05e5833ce2 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/types" @@ -460,7 +461,7 @@ func (f *BlockFetcher) loop() { // Create a closure of the fetch and schedule in on a new thread fetchHeader, hashes := f.fetching[hashes[0]].fetchHeader, hashes - go func() { + gopool.Submit(func() { if f.fetchingHook != nil { f.fetchingHook(hashes) } @@ -468,7 +469,7 @@ func (f *BlockFetcher) loop() { headerFetchMeter.Mark(1) fetchHeader(hash) // Suboptimal, but protocol doesn't allow batch header retrievals } - }() + }) } // Schedule the next fetch if blocks are still pending f.rescheduleFetch(fetchTimer) diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 3ba7753916..d0c1348014 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -25,6 +25,7 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -794,15 +795,15 @@ func (f *TxFetcher) scheduleFetches(timer *mclock.Timer, timeout chan struct{}, if len(hashes) > 0 { f.requests[peer] = &txRequest{hashes: hashes, time: f.clock.Now()} txRequestOutMeter.Mark(int64(len(hashes))) - - go func(peer string, hashes []common.Hash) { + p := peer + gopool.Submit(func() { // Try to fetch the transactions, but in case of a request // failure (e.g. peer disconnected), reschedule the hashes. - if err := f.fetchTxs(peer, hashes); err != nil { + if err := f.fetchTxs(p, hashes); err != nil { txRequestFailMeter.Mark(int64(len(hashes))) - f.Drop(peer) + f.Drop(p) } - }(peer, hashes) + }) } }) // If a new request was fired, schedule a timeout timer diff --git a/eth/filters/api.go b/eth/filters/api.go index 00e28d8955..91477a9170 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -121,7 +122,7 @@ func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID { api.filters[pendingTxSub.ID] = f api.filtersMu.Unlock() - go func() { + gopool.Submit(func() { for { select { case ph := <-pendingTxs: @@ -133,7 +134,7 @@ func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID { return } } - }() + }) return pendingTxSub.ID } @@ -148,7 +149,7 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su rpcSub := notifier.CreateSubscription() - go func() { + gopool.Submit(func() { txHashes := make(chan []common.Hash, 128) pendingTxSub := api.events.SubscribePendingTxs(txHashes) @@ -168,7 +169,7 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su return } } - }() + }) return rpcSub, nil } @@ -187,7 +188,7 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID { api.filters[headerSub.ID] = &filter{typ: BlocksSubscription, deadline: time.NewTimer(api.timeout), hashes: make([]common.Hash, 0), s: headerSub} api.filtersMu.Unlock() - go func() { + gopool.Submit(func() { for { select { case h := <-headers: @@ -203,7 +204,7 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID { return } } - }() + }) return headerSub.ID } @@ -217,7 +218,7 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er rpcSub := notifier.CreateSubscription() - go func() { + gopool.Submit(func() { headers := make(chan *types.Header) headersSub := api.events.SubscribeNewHeads(headers) @@ -233,7 +234,7 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er return } } - }() + }) return rpcSub, nil } @@ -255,7 +256,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc return nil, err } - go func() { + gopool.Submit(func() { for { select { @@ -271,7 +272,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc return } } - }() + }) return rpcSub, nil } @@ -304,7 +305,7 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { api.filters[logsSub.ID] = &filter{typ: LogsSubscription, crit: crit, deadline: time.NewTimer(api.timeout), logs: make([]*types.Log, 0), s: logsSub} api.filtersMu.Unlock() - go func() { + gopool.Submit(func() { for { select { case l := <-logs: @@ -320,7 +321,7 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { return } } - }() + }) return logsSub.ID, nil } diff --git a/eth/protocols/eth/broadcast.go b/eth/protocols/eth/broadcast.go index 328396d510..e0ee2a1cfa 100644 --- a/eth/protocols/eth/broadcast.go +++ b/eth/protocols/eth/broadcast.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/core/types" ) @@ -158,14 +159,14 @@ func (p *Peer) announceTransactions() { // If there's anything available to transfer, fire up an async writer if len(pending) > 0 { done = make(chan struct{}) - go func() { + gopool.Submit(func() { if err := p.sendPooledTransactionHashes(pending); err != nil { fail <- err return } close(done) - p.Log().Trace("Sent transaction announcements", "count", len(pending)) - }() + //p.Log().Trace("Sent transaction announcements", "count", len(pending)) + }) } } // Transfer goroutine may or may not have been started, listen for events diff --git a/eth/protocols/eth/handshake.go b/eth/protocols/eth/handshake.go index 57a4e0bc34..b634f18e00 100644 --- a/eth/protocols/eth/handshake.go +++ b/eth/protocols/eth/handshake.go @@ -22,6 +22,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/p2p" ) @@ -40,7 +41,7 @@ func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis var status StatusPacket // safe to read after two values have been received from errc - go func() { + gopool.Submit(func() { errc <- p2p.Send(p.rw, StatusMsg, &StatusPacket{ ProtocolVersion: uint32(p.version), NetworkID: network, @@ -49,10 +50,10 @@ func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis Genesis: genesis, ForkID: forkID, }) - }() - go func() { + }) + gopool.Submit(func() { errc <- p.readStatus(network, &status, genesis, forkFilter) - }() + }) timeout := time.NewTimer(handshakeTimeout) defer timeout.Stop() for i := 0; i < 2; i++ { diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index 62c018ef8e..de1b0ed1ee 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -155,19 +155,19 @@ func (hn *HashOrNumber) EncodeRLP(w io.Writer) error { // DecodeRLP is a specialized decoder for HashOrNumber to decode the contents // into either a block hash or a block number. func (hn *HashOrNumber) DecodeRLP(s *rlp.Stream) error { - _, size, _ := s.Kind() - origin, err := s.Raw() - if err == nil { - switch { - case size == 32: - err = rlp.DecodeBytes(origin, &hn.Hash) - case size <= 8: - err = rlp.DecodeBytes(origin, &hn.Number) - default: - err = fmt.Errorf("invalid input size %d for origin", size) - } + _, size, err := s.Kind() + switch { + case err != nil: + return err + case size == 32: + hn.Number = 0 + return s.Decode(&hn.Hash) + case size <= 8: + hn.Hash = common.Hash{} + return s.Decode(&hn.Number) + default: + return fmt.Errorf("invalid input size %d for origin", size) } - return err } // BlockHeadersPacket represents a block header response. diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index e283473207..f37bf14df7 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -28,6 +28,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" @@ -911,7 +912,8 @@ func (s *Syncer) assignAccountTasks(success chan *accountResponse, fail chan *ac delete(s.accountIdlers, idle) s.pend.Add(1) - go func(root common.Hash) { + root := s.root + gopool.Submit(func() { defer s.pend.Done() // Attempt to send the remote request and revert if it fails @@ -919,7 +921,7 @@ func (s *Syncer) assignAccountTasks(success chan *accountResponse, fail chan *ac peer.Log().Debug("Failed to request account range", "err", err) s.scheduleRevertAccountRequest(req) } - }(s.root) + }) // Inject the request into the task to block further assignments task.req = req @@ -1002,7 +1004,7 @@ func (s *Syncer) assignBytecodeTasks(success chan *bytecodeResponse, fail chan * delete(s.bytecodeIdlers, idle) s.pend.Add(1) - go func() { + gopool.Submit(func() { defer s.pend.Done() // Attempt to send the remote request and revert if it fails @@ -1010,7 +1012,7 @@ func (s *Syncer) assignBytecodeTasks(success chan *bytecodeResponse, fail chan * log.Debug("Failed to request bytecodes", "err", err) s.scheduleRevertBytecodeRequest(req) } - }() + }) } } @@ -1130,7 +1132,8 @@ func (s *Syncer) assignStorageTasks(success chan *storageResponse, fail chan *st delete(s.storageIdlers, idle) s.pend.Add(1) - go func(root common.Hash) { + root := s.root + gopool.Submit(func() { defer s.pend.Done() // Attempt to send the remote request and revert if it fails @@ -1142,7 +1145,7 @@ func (s *Syncer) assignStorageTasks(success chan *storageResponse, fail chan *st log.Debug("Failed to request storage", "err", err) s.scheduleRevertStorageRequest(req) } - }(s.root) + }) // Inject the request into the subtask to block further assignments if subtask != nil { @@ -1249,7 +1252,8 @@ func (s *Syncer) assignTrienodeHealTasks(success chan *trienodeHealResponse, fai delete(s.trienodeHealIdlers, idle) s.pend.Add(1) - go func(root common.Hash) { + root := s.root + gopool.Submit(func() { defer s.pend.Done() // Attempt to send the remote request and revert if it fails @@ -1257,7 +1261,7 @@ func (s *Syncer) assignTrienodeHealTasks(success chan *trienodeHealResponse, fai log.Debug("Failed to request trienode healers", "err", err) s.scheduleRevertTrienodeHealRequest(req) } - }(s.root) + }) } } @@ -1351,7 +1355,7 @@ func (s *Syncer) assignBytecodeHealTasks(success chan *bytecodeHealResponse, fai delete(s.bytecodeHealIdlers, idle) s.pend.Add(1) - go func() { + gopool.Submit(func() { defer s.pend.Done() // Attempt to send the remote request and revert if it fails @@ -1359,7 +1363,7 @@ func (s *Syncer) assignBytecodeHealTasks(success chan *bytecodeHealResponse, fai log.Debug("Failed to request bytecode healers", "err", err) s.scheduleRevertBytecodeHealRequest(req) } - }() + }) } } diff --git a/eth/sync.go b/eth/sync.go index 4520ec6879..2256c7cb99 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" @@ -114,7 +115,7 @@ func (h *handler) txsyncLoop64() { // Send the pack in the background. s.p.Log().Trace("Sending batch of transactions", "count", len(pack.txs), "bytes", size) sending = true - go func() { done <- pack.p.SendTransactions(pack.txs) }() + gopool.Submit(func() { done <- pack.p.SendTransactions(pack.txs) }) } // pick chooses the next pending sync. pick := func() *txsync { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 40def8d288..eee27e9a0c 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -30,6 +30,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" @@ -263,7 +264,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config ) for th := 0; th < threads; th++ { pend.Add(1) - go func() { + gopool.Submit(func() { defer pend.Done() // Fetch and execute the next block trace tasks @@ -295,12 +296,12 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config return } } - }() + }) } // Start a goroutine to feed all the blocks into the tracers begin := time.Now() - go func() { + gopool.Submit(func() { var ( logged time.Time number uint64 @@ -375,10 +376,10 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config } traced += uint64(len(txs)) } - }() + }) // Keep reading the trace results and stream the to the user - go func() { + gopool.Submit(func() { var ( done = make(map[uint64]*blockTraceResult) next = start.NumberU64() + 1 @@ -405,7 +406,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config next++ } } - }() + }) return sub, nil } @@ -520,7 +521,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac blockHash := block.Hash() for th := 0; th < threads; th++ { pend.Add(1) - go func() { + gopool.Submit(func() { defer pend.Done() // Fetch and execute the next transaction trace tasks for task := range jobs { @@ -537,7 +538,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac } results[task.index] = &txTraceResult{Result: res} } - }() + }) } // Feed the transactions into the tracers and return var failed error @@ -814,12 +815,12 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac } // Handle timeouts and RPC cancellations deadlineCtx, cancel := context.WithTimeout(ctx, timeout) - go func() { + gopool.Submit(func() { <-deadlineCtx.Done() if deadlineCtx.Err() == context.DeadlineExceeded { tracer.(*Tracer).Stop(errors.New("execution timeout")) } - }() + }) defer cancel() case config == nil: diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 4c0240cd2c..598c84c3b1 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -79,6 +79,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, + TriesInMemory: 128, TrieDirtyDisabled: true, // Archive mode } chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil) diff --git a/event/subscription.go b/event/subscription.go index 6c62874719..080985d1d4 100644 --- a/event/subscription.go +++ b/event/subscription.go @@ -21,6 +21,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/mclock" ) @@ -48,7 +49,7 @@ type Subscription interface { // error, it is sent on the subscription's error channel. func NewSubscription(producer func(<-chan struct{}) error) Subscription { s := &funcSub{unsub: make(chan struct{}), err: make(chan error, 1)} - go func() { + gopool.Submit(func() { defer close(s.err) err := producer(s.unsub) s.mu.Lock() @@ -59,7 +60,7 @@ func NewSubscription(producer func(<-chan struct{}) error) Subscription { } s.unsubscribed = true } - }() + }) return s } @@ -171,11 +172,11 @@ func (s *resubscribeSub) subscribe() Subscription { for { s.lastTry = mclock.Now() ctx, cancel := context.WithCancel(context.Background()) - go func() { + gopool.Submit(func() { rsub, err := s.fn(ctx, s.lastSubErr) sub = rsub subscribed <- err - }() + }) select { case err := <-subscribed: cancel() diff --git a/go.mod b/go.mod index 524078e203..fc5ec88fec 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,8 @@ require ( github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 + github.com/panjf2000/ants/v2 v2.4.5 + github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 github.com/prometheus/tsdb v0.7.1 github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 // indirect diff --git a/go.sum b/go.sum index c22848f2f8..5fbb839b90 100644 --- a/go.sum +++ b/go.sum @@ -8,16 +8,24 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK 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 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM= 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 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigtable v1.2.0 h1:F4cCmA4nuV84V5zYQ3MKY+M1Cw1avHDuf3S/LcZPA9c= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/datastore v1.0.0 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM= 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 h1:9/vpR43S4aJaROxqQHQ3nH9lfyKKV0dC3vOmnw8ebQQ= 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 h1:RPUcBvDeYgQFMfQu1eBMq6piD1SXmLH+vK3qjewZPus= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +collectd.org v0.3.0 h1:iNBHGw1VvPJxH2B6RiFWFZ+vsjo1lCdRszBeOuwGi00= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY= @@ -42,8 +50,11 @@ github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VY github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= 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 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 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= @@ -51,13 +62,19 @@ github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQu github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af h1:wVe6/Ea46ZMeNkQjjBW6xcqyQA/j5e0D6GytH95g0gQ= 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 h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= 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 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= 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 h1:nxAtV4VajJDhKysp2kdcJZsq8Ss1xSA0vZTkVHHJd0E= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/aws/aws-sdk-go-v2 v1.4.0 h1:Ryh4fNebT9SwLyCKPSk83dyEZj+KB6KzDyb1gXii7EI= github.com/aws/aws-sdk-go-v2 v1.4.0/go.mod h1:tI4KhsR5VkzlUa2DZAdwx7wCAYGwkZZ1H31PYrBFx1w= @@ -80,19 +97,29 @@ github.com/aws/smithy-go v1.4.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAm github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/c-bata/go-prompt v0.2.2 h1:uyKRz6Z6DUyj49QVijyM339UJV9yhbr70gESwbNU3e0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= +github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= 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= @@ -100,16 +127,23 @@ 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= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= 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 h1:+R8G1+Ftumd0DaveLgMIjrFPcAS4G8MsVXWXiyZL5BY= 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/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/dave/jennifer v1.2.0 h1:S15ZkFMRoJ36mGAQgWL1tnr0NQJh9rZ8qatseX/VbBc= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -119,7 +153,9 @@ github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 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 h1:akOQj8IVgoeFfBTzGOEQakCYshWD6RNo1M5pivFXt70= 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 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= @@ -127,10 +163,13 @@ github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmak github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 h1:Y9vTBSsV4hSwPSj4bacAU/eSnV3dAxVpepaghAdhGoQ= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0= 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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w= 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 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= @@ -138,6 +177,7 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 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 h1:WXb3TSNmHp2vHoCroCIB1foO/yQ36swABL8aOVeDpgg= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= @@ -146,9 +186,13 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 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/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04MMPyLHj/QwZuMJ5+7tJcBr1AQjpiAK/rZWRrQT7o= 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 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= 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 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE= 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= @@ -159,21 +203,27 @@ 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-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 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/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= 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 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 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 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA= 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 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= 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= @@ -191,7 +241,9 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/flatbuffers v1.11.0 h1:O7CEyB8Cb3/DmtxODGtLHcEvpr81Jm5qLg/hsHnxA2A= 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= @@ -202,15 +254,20 @@ 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/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 h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= 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 h1:DLpL8pWq0v4JYoRpEhDfsJhhJyGKCcQM2WPW2TJs31c= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= github.com/google/uuid v1.1.5/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 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -224,55 +281,85 @@ 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.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw= github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88 h1:bcAj8KroPf552TScjFPIakjH2/tdIrIH8F+cc4v4SRo= github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150 h1:vlNjIqmUZ9CMAWsbURYl3a6wZbw7q5RHVvlXTNS/Bs8= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/flux v0.65.1 h1:77BcVUCzvN5HMm8+j9PRBQ4iZcu98Dl4Y9rf+J5vhnc= 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/influxql v1.1.1-0.20200828144457-65d3ef77d385 h1:ED4e5Cc3z5vSN2Tz2GkOHN7vs4Sxe2yds6CXvDnvZFE= 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 h1:/o3vQtpWJhvnIbXley4/jwzzqNeigJK9z+LZcJZ9zfM= github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= +github.com/influxdata/promql/v2 v2.12.0 h1:kXn3p0D7zPw16rOtfDR+wo6aaiH8tSMfhPwONTxrlEc= github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= +github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6 h1:UzJnB7VRL4PSkUJHwsyzseGOmrO/r4yA+AuxGJxiZmA= 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 h1:MHTrDWmQpHq/hkq+7cw9oYAt2PqUw52TZazRA0N7PGE= 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 h1:+TUUmaFa4YD1Q+7bH9o5NCHQGPMqZCYJiNW6lIIS9z4= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/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/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 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 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jsternberg/zap-logfmt v1.0.0 h1:0Dz2s/eturmdUS34GM82JwNEdQ9hPoJgqptcEKcbpzY= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5 h1:PJr+ZMXIecYc1Ey2zucXdR73SMBtgjPgwa31099IMv0= 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 h1:2jNeR4YUziVtswNP9sEFAI913cVrzH85T+8Q6LpYbT0= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.4.0 h1:8nsMz3tWa9SWWPL60G1V6CUsf4lLjWLTNEtibhe8gh8= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5 h1:2U0HzY8BJ8hVwDKIzp7y4voR9CX/nvcfymLmg2UiOio= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= +github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada h1:3L+neHp83cTjegPdCiOxVOJtRIy7/8RldvMTsyPYH10= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 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/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.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -280,6 +367,7 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 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 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -295,13 +383,19 @@ github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXT 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 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104 h1:d8RFOZ2IiFtFWBcKEHAFYJcPTf0wY5q0exFNJZVWa1U= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY= 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 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc= 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= @@ -309,6 +403,7 @@ github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcou 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/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= 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= @@ -325,16 +420,24 @@ github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt 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/panjf2000/ants/v2 v2.4.5 h1:kcGvjXB7ea0MrzzszpnlVFthhYKoFxLi75nRbsq01HY= +github.com/panjf2000/ants/v2 v2.4.5/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/paulbellamy/ratecounter v0.2.0 h1:2L/RhJq+HA8gBQImDXtLPrDXK5qAj6ozWVK/zFXVJGs= github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= 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 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 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 h1:tFwafIEMf0B7NlcxV/zJ6leBIa81D3hgGSgsE5hCkOQ= 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= @@ -356,29 +459,43 @@ github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52 h1:RnWNS9Hlm8BIkjr6wx8li5abe0fr73jljLycdfemTp0= 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 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= 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= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/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 h1:HtCSf6B4gN/87yc5qTl7WsxPKQIIGXLPPM1bMCPOsoY= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= 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 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= 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= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -394,6 +511,7 @@ github.com/tendermint/iavl v0.12.0 h1:xcaFAr+ycqCj7WN1RzL2EfcBioRDOHcU1oWcg83K02 github.com/tendermint/iavl v0.12.0/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM= github.com/tendermint/tendermint v0.31.11 h1:TIs//4WfEAG4TOZc2eUfJPI3T8KrywXQCCPnGAaM1Wo= github.com/tendermint/tendermint v0.31.11/go.mod h1:ymcPyWblXCplCPQjbOYbrF1fWnpslATMVqiGgWbZrlc= +github.com/tinylib/msgp v1.0.2 h1:DfdQrzQa7Yh2es9SuLkixqxuXS2SxsdYn0KbdrOGWD8= 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= @@ -401,17 +519,25 @@ 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/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/willf/bitset v1.1.3 h1:ekJIKh6+YbUIVt9DfNbkR5d6aFcFTLDRyJNAACURBg8= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6 h1:YdYsPAZ2pC6Tow/nPZOPQ96O3hm/ToAkGsPLzedXERk= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= 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 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -432,9 +558,11 @@ golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxT 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 h1:zQpM52jfKHG6II1ISZY1ZcpygvuSFZpLwfluuF89XOg= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 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 h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= 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= @@ -443,13 +571,16 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl 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 h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= 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= 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 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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= @@ -477,6 +608,7 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG 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 h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= 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= @@ -555,6 +687,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/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.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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= @@ -563,9 +696,12 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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 h1:DJy6UzXbahnGUf1ujUNkh/NEtK14qMo2nvlBPs4U5yw= 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 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b h1:Qh4dB5D/WpoUUp3lSod7qgoyEHbDGPUWjIbnqdqqe1k= 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= @@ -573,11 +709,13 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn 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 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA= 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 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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= @@ -608,11 +746,14 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE 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= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 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= @@ -626,6 +767,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.7/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 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -638,6 +780,9 @@ 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 h1:qTakTkI6ni6LFD5sBwwsdSO+AQqbSIxOauHTTQKZ/7o= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 212bc13b33..15e7a8c8f1 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -25,19 +25,20 @@ import ( "strings" "time" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/davecgh/go-spew/spew" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "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/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -896,10 +897,10 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo } // Wait for the context to be done and cancel the evm. Even if the // EVM has finished, cancelling may be done (repeatedly) - go func() { + gopool.Submit(func() { <-ctx.Done() evm.Cancel() - }() + }) // Execute the message. gp := new(core.GasPool).AddGas(math.MaxUint64) diff --git a/les/handler_test.go b/les/handler_test.go index d1dbee6bdf..c4f54cb941 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -316,7 +316,7 @@ func TestGetStaleCodeLes4(t *testing.T) { testGetStaleCode(t, 4) } func testGetStaleCode(t *testing.T, protocol int) { netconfig := testnetConfig{ - blocks: core.TriesInMemory + 4, + blocks: 128 + 4, protocol: protocol, nopruning: true, } @@ -430,7 +430,7 @@ func TestGetStaleProofLes4(t *testing.T) { testGetStaleProof(t, 4) } func testGetStaleProof(t *testing.T, protocol int) { netconfig := testnetConfig{ - blocks: core.TriesInMemory + 4, + blocks: 128 + 4, protocol: protocol, nopruning: true, } diff --git a/les/peer.go b/les/peer.go index 25a3bb1556..5cdd557a90 100644 --- a/les/peer.go +++ b/les/peer.go @@ -29,7 +29,6 @@ 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/forkid" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/les/flowcontrol" @@ -1055,7 +1054,7 @@ func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, ge // If local ethereum node is running in archive mode, advertise ourselves we have // all version state data. Otherwise only recent state is available. - stateRecent := uint64(core.TriesInMemory - blockSafetyMargin) + stateRecent := uint64(server.handler.blockchain.TriesInMemory() - blockSafetyMargin) if server.archiveMode { stateRecent = 0 } diff --git a/les/protocol.go b/les/protocol.go index 07a4452f40..06db9024eb 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -307,19 +307,19 @@ func (hn *hashOrNumber) EncodeRLP(w io.Writer) error { // DecodeRLP is a specialized decoder for hashOrNumber to decode the contents // into either a block hash or a block number. func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error { - _, size, _ := s.Kind() - origin, err := s.Raw() - if err == nil { - switch { - case size == 32: - err = rlp.DecodeBytes(origin, &hn.Hash) - case size <= 8: - err = rlp.DecodeBytes(origin, &hn.Number) - default: - err = fmt.Errorf("invalid input size %d for origin", size) - } + _, size, err := s.Kind() + switch { + case err != nil: + return err + case size == 32: + hn.Number = 0 + return s.Decode(&hn.Hash) + case size <= 8: + hn.Hash = common.Hash{} + return s.Decode(&hn.Number) + default: + return fmt.Errorf("invalid input size %d for origin", size) } - return err } // CodeData is the network response packet for a node data retrieval. diff --git a/les/server_requests.go b/les/server_requests.go index bab5f733d5..7564420ce6 100644 --- a/les/server_requests.go +++ b/les/server_requests.go @@ -297,7 +297,7 @@ func handleGetCode(msg Decoder) (serveRequestFn, uint64, uint64, error) { // Refuse to search stale state data in the database since looking for // a non-exist key is kind of expensive. local := bc.CurrentHeader().Number.Uint64() - if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { + if !backend.ArchiveMode() && header.Number.Uint64()+bc.TriesInMemory() <= local { p.Log().Debug("Reject stale code request", "number", header.Number.Uint64(), "head", local) p.bumpInvalid() continue @@ -396,7 +396,7 @@ func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { // Refuse to search stale state data in the database since looking for // a non-exist key is kind of expensive. local := bc.CurrentHeader().Number.Uint64() - if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { + if !backend.ArchiveMode() && header.Number.Uint64()+bc.TriesInMemory() <= local { p.Log().Debug("Reject stale trie request", "number", header.Number.Uint64(), "head", local) p.bumpInvalid() continue diff --git a/les/test_helper.go b/les/test_helper.go index fc85ed957f..70d0c294a8 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -373,7 +373,7 @@ func (p *testPeer) handshakeWithClient(t *testing.T, td *big.Int, head common.Ha sendList = sendList.add("serveHeaders", nil) sendList = sendList.add("serveChainSince", uint64(0)) sendList = sendList.add("serveStateSince", uint64(0)) - sendList = sendList.add("serveRecentState", uint64(core.TriesInMemory-4)) + sendList = sendList.add("serveRecentState", uint64(128-4)) sendList = sendList.add("txRelay", nil) sendList = sendList.add("flowControl/BL", testBufLimit) sendList = sendList.add("flowControl/MRR", testBufRecharge) diff --git a/light/trie.go b/light/trie.go index 0516b94486..e189634e1c 100644 --- a/light/trie.go +++ b/light/trie.go @@ -95,6 +95,18 @@ func (db *odrDatabase) TrieDB() *trie.Database { return nil } +func (db *odrDatabase) CacheAccount(_ common.Hash, _ state.Trie) { + return +} + +func (db *odrDatabase) CacheStorage(_ common.Hash, _ common.Hash, _ state.Trie) { + return +} + +func (db *odrDatabase) Purge() { + return +} + type odrTrie struct { db *odrDatabase id *TrieID diff --git a/miner/worker.go b/miner/worker.go index 950efc7e63..b93b8752af 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -474,22 +474,7 @@ func (w *worker) mainLoop() { start := time.Now() if err := w.commitUncle(w.current, ev.Block.Header()); err == nil { var uncles []*types.Header - w.current.uncles.Each(func(item interface{}) bool { - hash, ok := item.(common.Hash) - if !ok { - return false - } - uncle, exist := w.localUncles[hash] - if !exist { - uncle, exist = w.remoteUncles[hash] - } - if !exist { - return false - } - uncles = append(uncles, uncle.Header()) - return false - }) - w.commit(uncles, nil, true, start) + w.commit(uncles, nil, false, start) } } @@ -676,14 +661,6 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { uncles: mapset.NewSet(), header: header, } - // when 08 is processed ancestors contain 07 (quick block) - for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) { - for _, uncle := range ancestor.Uncles() { - env.family.Add(uncle.Hash()) - } - env.family.Add(ancestor.Hash()) - env.ancestors.Add(ancestor.Hash()) - } // Keep track of transactions which return errors so they can be removed env.tcount = 0 @@ -825,12 +802,11 @@ LOOP: // during transaction acceptance is the transaction pool. // // We use the eip155 signer regardless of the current hf. - from, _ := types.Sender(w.current.signer, tx) + //from, _ := types.Sender(w.current.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(w.current.header.Number) { - log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.chainConfig.EIP155Block) - + //log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.chainConfig.EIP155Block) txs.Pop() continue } @@ -841,17 +817,17 @@ LOOP: 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) + //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()) + //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()) + //log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) txs.Pop() case errors.Is(err, nil): @@ -862,13 +838,13 @@ LOOP: case errors.Is(err, core.ErrTxTypeNotSupported): // Pop the unsupported transaction without shifting in the next from the account - log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type()) + //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). - log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) + //log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) txs.Shift() } } @@ -953,30 +929,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) } systemcontracts.UpgradeBuildInSystemContract(w.chainConfig, header.Number, env.state) // Accumulate the uncles for the current block - uncles := make([]*types.Header, 0, 2) - commitUncles := func(blocks map[common.Hash]*types.Block) { - // Clean up stale uncle blocks first - for hash, uncle := range blocks { - if uncle.NumberU64()+staleThreshold <= header.Number.Uint64() { - delete(blocks, hash) - } - } - for hash, uncle := range blocks { - if len(uncles) == 2 { - break - } - if err := w.commitUncle(env, uncle.Header()); err != nil { - log.Trace("Possible uncle rejected", "hash", hash, "reason", err) - } else { - log.Debug("Committing new uncle to block", "hash", hash) - uncles = append(uncles, uncle.Header()) - } - } - } - // Prefer to locally generated uncle - commitUncles(w.localUncles) - commitUncles(w.remoteUncles) - + uncles := make([]*types.Header, 0) // 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 { @@ -1014,13 +967,13 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) commitTxsTimer.UpdateSince(start) log.Info("Gas pool", "height", header.Number.String(), "pool", w.current.gasPool.String()) } - w.commit(uncles, w.fullTaskHook, true, tstart) + w.commit(uncles, w.fullTaskHook, false, tstart) } // commit runs any post-transaction state modifications, assembles the final block // and commits new work if consensus engine is running. func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { - s := w.current.state.Copy() + s := w.current.state block, receipts, err := w.engine.FinalizeAndAssemble(w.chain, types.CopyHeader(w.current.header), s, w.current.txs, uncles, w.current.receipts) if err != nil { return err @@ -1034,7 +987,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st w.unconfirmed.Shift(block.NumberU64() - 1) log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), "uncles", len(uncles), "txs", w.current.tcount, - "gas", block.GasUsed(), "fees", totalFees(block, receipts), + "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(start))) case <-w.exitCh: diff --git a/miner/worker_test.go b/miner/worker_test.go index 0fe62316e1..4015e7294f 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -260,169 +260,6 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) { } } -func TestEmptyWorkEthash(t *testing.T) { - testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) -} -func TestEmptyWorkClique(t *testing.T) { - testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) -} - -func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { - defer engine.Close() - - w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) - defer w.close() - - var ( - taskIndex int - taskCh = make(chan struct{}, 2) - ) - checkEqual := func(t *testing.T, task *task, index int) { - // The first empty work without any txs included - receiptLen, balance := 0, big.NewInt(0) - if index == 1 { - // The second full work with 1 tx included - receiptLen, balance = 1, big.NewInt(1000) - } - if len(task.receipts) != receiptLen { - t.Fatalf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) - } - if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { - t.Fatalf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) - } - } - w.newTaskHook = func(task *task) { - if task.block.NumberU64() == 1 { - checkEqual(t, task, taskIndex) - taskIndex += 1 - taskCh <- struct{}{} - } - } - w.skipSealHook = func(task *task) bool { return true } - w.fullTaskHook = func() { - time.Sleep(100 * time.Millisecond) - } - w.start() // Start mining! - for i := 0; i < 2; i += 1 { - select { - case <-taskCh: - case <-time.NewTimer(3 * time.Second).C: - t.Error("new task timeout") - } - } -} - -func TestStreamUncleBlock(t *testing.T) { - ethash := ethash.NewFaker() - defer ethash.Close() - - w, b := newTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1) - defer w.close() - - var taskCh = make(chan struct{}) - - taskIndex := 0 - w.newTaskHook = func(task *task) { - if task.block.NumberU64() == 2 { - // The first task is an empty task, the second - // one has 1 pending tx, the third one has 1 tx - // and 1 uncle. - if taskIndex == 2 { - have := task.block.Header().UncleHash - want := types.CalcUncleHash([]*types.Header{b.uncleBlock.Header()}) - if have != want { - t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex()) - } - } - taskCh <- struct{}{} - taskIndex += 1 - } - } - w.skipSealHook = func(task *task) bool { - return true - } - w.fullTaskHook = func() { - time.Sleep(100 * time.Millisecond) - } - w.start() - - for i := 0; i < 2; i += 1 { - select { - case <-taskCh: - case <-time.NewTimer(time.Second).C: - t.Error("new task timeout") - } - } - - w.postSideBlock(core.ChainSideEvent{Block: b.uncleBlock}) - - select { - case <-taskCh: - case <-time.NewTimer(time.Second).C: - t.Error("new task timeout") - } -} - -func TestRegenerateMiningBlockEthash(t *testing.T) { - testRegenerateMiningBlock(t, ethashChainConfig, ethash.NewFaker()) -} - -func TestRegenerateMiningBlockClique(t *testing.T) { - testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) -} - -func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { - defer engine.Close() - - w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) - defer w.close() - - var taskCh = make(chan struct{}) - - taskIndex := 0 - w.newTaskHook = func(task *task) { - if task.block.NumberU64() == 1 { - // The first task is an empty task, the second - // one has 1 pending tx, the third one has 2 txs - if taskIndex == 2 { - receiptLen, balance := 2, big.NewInt(2000) - if len(task.receipts) != receiptLen { - t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) - } - if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { - t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) - } - } - taskCh <- struct{}{} - taskIndex += 1 - } - } - w.skipSealHook = func(task *task) bool { - return true - } - w.fullTaskHook = func() { - time.Sleep(100 * time.Millisecond) - } - - w.start() - // Ignore the first two works - for i := 0; i < 2; i += 1 { - select { - case <-taskCh: - case <-time.NewTimer(time.Second).C: - t.Error("new task timeout") - } - } - b.txPool.AddLocals(newTxs) - time.Sleep(time.Second) - - select { - case <-taskCh: - case <-time.NewTimer(time.Second).C: - t.Error("new task timeout") - } -} - func TestAdjustIntervalEthash(t *testing.T) { testAdjustInterval(t, ethashChainConfig, ethash.NewFaker()) } diff --git a/node/api.go b/node/api.go index be20b89d95..023d5d27b3 100644 --- a/node/api.go +++ b/node/api.go @@ -21,6 +21,7 @@ import ( "fmt" "strings" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/debug" @@ -141,7 +142,7 @@ func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, } rpcSub := notifier.CreateSubscription() - go func() { + gopool.Submit(func() { events := make(chan *p2p.PeerEvent) sub := server.SubscribeEvents(events) defer sub.Unsubscribe() @@ -158,7 +159,7 @@ func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, return } } - }() + }) return rpcSub, nil } diff --git a/p2p/dial.go b/p2p/dial.go index d36d665501..f7f48916ea 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -27,6 +27,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" @@ -177,8 +178,13 @@ func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupF d.lastStatsLog = d.clock.Now() d.ctx, d.cancel = context.WithCancel(context.Background()) d.wg.Add(2) - go d.readNodes(it) - go d.loop(it) + gopool.Submit(func() { + d.readNodes(it) + }) + gopool.Submit( + func() { + d.loop(it) + }) return d } @@ -455,10 +461,10 @@ func (d *dialScheduler) startDial(task *dialTask) { hkey := string(task.dest.ID().Bytes()) d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration)) d.dialing[task.dest.ID()] = task - go func() { + gopool.Submit(func() { task.run(d) d.doneCh <- task - }() + }) } // A dialTask generated for each node that is dialed. diff --git a/p2p/discover/lookup.go b/p2p/discover/lookup.go index 9ab4a71ce7..f6f125d944 100644 --- a/p2p/discover/lookup.go +++ b/p2p/discover/lookup.go @@ -20,6 +20,7 @@ import ( "context" "time" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/p2p/enode" ) @@ -122,7 +123,9 @@ func (it *lookup) startQueries() bool { if !it.asked[n.ID()] { it.asked[n.ID()] = true it.queries++ - go it.query(n, it.replyCh) + gopool.Submit(func() { + it.query(n, it.replyCh) + }) } } // The lookup ends when no more nodes can be asked. diff --git a/p2p/discover/table.go b/p2p/discover/table.go index d08f8a6c69..bf136cf48f 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -33,6 +33,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/netutil" @@ -229,8 +230,9 @@ func (tab *Table) loop() { defer copyNodes.Stop() // Start initial refresh. - go tab.doRefresh(refreshDone) - + gopool.Submit(func() { + tab.doRefresh(refreshDone) + }) loop: for { select { @@ -238,13 +240,18 @@ loop: tab.seedRand() if refreshDone == nil { refreshDone = make(chan struct{}) - go tab.doRefresh(refreshDone) + gopool.Submit(func() { + tab.doRefresh(refreshDone) + }) } case req := <-tab.refreshReq: waiting = append(waiting, req) if refreshDone == nil { refreshDone = make(chan struct{}) - go tab.doRefresh(refreshDone) + gopool.Submit( + func() { + tab.doRefresh(refreshDone) + }) } case <-refreshDone: for _, ch := range waiting { @@ -253,12 +260,17 @@ loop: waiting, refreshDone = nil, nil case <-revalidate.C: revalidateDone = make(chan struct{}) - go tab.doRevalidate(revalidateDone) + gopool.Submit(func() { + tab.doRevalidate(revalidateDone) + }) case <-revalidateDone: revalidate.Reset(tab.nextRevalidateTime()) revalidateDone = nil case <-copyNodes.C: - go tab.copyLiveNodes() + gopool.Submit(func() { + tab.copyLiveNodes() + }) + case <-tab.closeReq: break loop } diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index ad23eee6b4..88580d7cee 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -29,6 +29,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/discover/v4wire" @@ -490,7 +491,9 @@ func (t *UDPv4) loop() { if contTimeouts > ntpFailureThreshold { if time.Since(ntpWarnTime) >= ntpWarningCooldown { ntpWarnTime = time.Now() - go checkClockDrift() + gopool.Submit(func() { + checkClockDrift() + }) } contTimeouts = 0 } diff --git a/p2p/enode/iter.go b/p2p/enode/iter.go index 664964f534..b14ce4656f 100644 --- a/p2p/enode/iter.go +++ b/p2p/enode/iter.go @@ -19,6 +19,8 @@ package enode import ( "sync" "time" + + "github.com/ethereum/go-ethereum/common/gopool" ) // Iterator represents a sequence of nodes. The Next method moves to the next node in the @@ -177,7 +179,9 @@ func (m *FairMix) AddSource(it Iterator) { m.wg.Add(1) source := &mixSource{it, make(chan *Node), m.timeout} m.sources = append(m.sources, source) - go m.runSource(m.closed, source) + gopool.Submit(func() { + m.runSource(m.closed, source) + }) } // Close shuts down the mixer and all current sources. diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index d62f383f0b..18570c3659 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -26,6 +26,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/rlp" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/errors" @@ -303,7 +304,11 @@ func deleteRange(db *leveldb.DB, prefix []byte) { // convergence, it's simpler to "ensure" the correct state when an appropriate // condition occurs (i.e. a successful bonding), and discard further events. func (db *DB) ensureExpirer() { - db.runner.Do(func() { go db.expirer() }) + db.runner.Do(func() { + gopool.Submit(func() { + db.expirer() + }) + }) } // expirer should be started in a go routine, and is responsible for looping ad diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index 9d5519b9c4..8458452ded 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -25,6 +25,8 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/gopool" + "github.com/ethereum/go-ethereum/log" natpmp "github.com/jackpal/go-nat-pmp" ) @@ -145,8 +147,8 @@ func Any() Interface { // Internet-class address. Return ExtIP in this case. return startautodisc("UPnP or NAT-PMP", func() Interface { found := make(chan Interface, 2) - go func() { found <- discoverUPnP() }() - go func() { found <- discoverPMP() }() + gopool.Submit(func() { found <- discoverUPnP() }) + gopool.Submit(func() { found <- discoverPMP() }) for i := 0; i < cap(found); i++ { if c := <-found; c != nil { return c diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index 7f85543f8e..ac9aa1ec83 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/common/gopool" natpmp "github.com/jackpal/go-nat-pmp" ) @@ -68,14 +69,14 @@ func discoverPMP() Interface { found := make(chan *pmp, len(gws)) for i := range gws { gw := gws[i] - go func() { + gopool.Submit(func() { c := natpmp.NewClient(gw) if _, err := c.GetExternalAddress(); err != nil { found <- nil } else { found <- &pmp{gw, c} } - }() + }) } // return the one that responds first. // discovery needs to be quick, so we stop caring about diff --git a/p2p/peer.go b/p2p/peer.go index 8ebc858392..e057e689f6 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -25,6 +25,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -308,7 +309,9 @@ func (p *Peer) handle(msg Msg) error { switch { case msg.Code == pingMsg: msg.Discard() - go SendItems(p.rw, pongMsg) + gopool.Submit(func() { + SendItems(p.rw, pongMsg) + }) case msg.Code == discMsg: var reason [1]DiscReason // This is the last message. We don't need to discard or diff --git a/p2p/rlpx/rlpx.go b/p2p/rlpx/rlpx.go index 2021bf08be..ab79c26a28 100644 --- a/p2p/rlpx/rlpx.go +++ b/p2p/rlpx/rlpx.go @@ -34,13 +34,22 @@ import ( "net" "time" + "github.com/VictoriaMetrics/fastcache" + "github.com/golang/snappy" + "github.com/oxtoacart/bpool" + "golang.org/x/crypto/sha3" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/rlp" - "github.com/golang/snappy" - "golang.org/x/crypto/sha3" ) +var snappyCache *fastcache.Cache + +func init() { + snappyCache = fastcache.New(50 * 1024 * 1024) +} + // Conn is an RLPx network connection. It wraps a low-level network connection. The // underlying connection should not be used for other activity when it is wrapped by Conn. // @@ -179,7 +188,14 @@ func (c *Conn) Write(code uint64, data []byte) (uint32, error) { return 0, errPlainMessageTooLarge } if c.snappy { - data = snappy.Encode(nil, data) + if encodedResult, ok := snappyCache.HasGet(nil, data); ok { + data = encodedResult + } else { + encodedData := snappy.Encode(nil, data) + snappyCache.Set(data, encodedData) + + data = encodedData + } } wireSize := uint32(len(data)) @@ -239,15 +255,20 @@ func putInt24(v uint32, b []byte) { b[2] = byte(v) } +const BpoolMaxSize = 4 + +var bytepool = bpool.NewBytePool(BpoolMaxSize, aes.BlockSize) + // updateMAC reseeds the given hash with encrypted seed. // it returns the first 16 bytes of the hash sum after seeding. func updateMAC(mac hash.Hash, block cipher.Block, seed []byte) []byte { - aesbuf := make([]byte, aes.BlockSize) + aesbuf := bytepool.Get() block.Encrypt(aesbuf, mac.Sum(nil)) for i := range aesbuf { aesbuf[i] ^= seed[i] } mac.Write(aesbuf) + bytepool.Put(aesbuf) return mac.Sum(nil)[:16] } diff --git a/p2p/server.go b/p2p/server.go index f70ebf7216..dbaee12ea1 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -30,6 +30,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" @@ -562,10 +563,10 @@ func (srv *Server) setupDiscovery() error { if srv.NAT != nil { if !realaddr.IP.IsLoopback() { srv.loopWG.Add(1) - go func() { + gopool.Submit(func() { nat.Map(srv.NAT, srv.quit, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") srv.loopWG.Done() - }() + }) } } srv.localnode.SetFallbackUDP(realaddr.Port) @@ -669,10 +670,10 @@ func (srv *Server) setupListening() error { srv.localnode.Set(enr.TCP(tcp.Port)) if !tcp.IP.IsLoopback() && srv.NAT != nil { srv.loopWG.Add(1) - go func() { + gopool.Submit(func() { nat.Map(srv.NAT, srv.quit, "tcp", tcp.Port, tcp.Port, "ethereum p2p") srv.loopWG.Done() - }() + }) } } @@ -890,10 +891,10 @@ func (srv *Server) listenLoop() { fd = newMeteredConn(fd, true, addr) srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr()) } - go func() { + gopool.Submit(func() { srv.SetupConn(fd, inboundConn, nil) slots <- struct{}{} - }() + }) } } @@ -1019,7 +1020,9 @@ func (srv *Server) launchPeer(c *conn) *Peer { // to the peer. p.events = &srv.peerFeed } - go srv.runPeer(p) + gopool.Submit(func() { + srv.runPeer(p) + }) return p } diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go index 0cddd9b505..3780b8635a 100644 --- a/p2p/simulations/examples/ping-pong.go +++ b/p2p/simulations/examples/ping-pong.go @@ -25,6 +25,7 @@ import ( "sync/atomic" "time" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" @@ -140,7 +141,7 @@ func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { log := p.log.New("peer.id", peer.ID()) errC := make(chan error) - go func() { + gopool.Submit(func() { for range time.Tick(10 * time.Second) { log.Info("sending ping") if err := p2p.Send(rw, pingMsgCode, "PING"); err != nil { @@ -148,8 +149,8 @@ func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { return } } - }() - go func() { + }) + gopool.Submit(func() { for { msg, err := rw.ReadMsg() if err != nil { @@ -165,9 +166,9 @@ func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { atomic.AddInt64(&p.received, 1) if msg.Code == pingMsgCode { log.Info("sending pong") - go p2p.Send(rw, pongMsgCode, "PONG") + gopool.Submit(func() { p2p.Send(rw, pongMsgCode, "PONG") }) } } - }() + }) return <-errC } diff --git a/p2p/transport.go b/p2p/transport.go index 3f1cd7d64f..502983a11b 100644 --- a/p2p/transport.go +++ b/p2p/transport.go @@ -26,6 +26,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/bitutil" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p/rlpx" "github.com/ethereum/go-ethereum/rlp" @@ -132,7 +133,7 @@ func (t *rlpxTransport) doProtoHandshake(our *protoHandshake) (their *protoHands // disconnects us early with a valid reason, we should return it // as the error so it can be tracked elsewhere. werr := make(chan error, 1) - go func() { werr <- Send(t, handshakeMsg, our) }() + gopool.Submit(func() { werr <- Send(t, handshakeMsg, our) }) if their, err = readProtocolHandshake(t); err != nil { <-werr // make sure the write terminates too return nil, err diff --git a/params/config.go b/params/config.go index 1a43d835e4..81ff4da9c3 100644 --- a/params/config.go +++ b/params/config.go @@ -72,6 +72,9 @@ var ( PetersburgBlock: big.NewInt(7_280_000), IstanbulBlock: big.NewInt(9_069_000), MuirGlacierBlock: big.NewInt(9_200_000), + RamanujanBlock: big.NewInt(0), + NielsBlock: big.NewInt(0), + MirrorSyncBlock: big.NewInt(0), BerlinBlock: big.NewInt(12_244_000), Ethash: new(EthashConfig), } @@ -112,6 +115,9 @@ var ( PetersburgBlock: big.NewInt(4_939_394), IstanbulBlock: big.NewInt(6_485_846), MuirGlacierBlock: big.NewInt(7_117_117), + RamanujanBlock: big.NewInt(0), + NielsBlock: big.NewInt(0), + MirrorSyncBlock: big.NewInt(0), BerlinBlock: big.NewInt(9_812_189), Ethash: new(EthashConfig), } @@ -152,6 +158,9 @@ var ( PetersburgBlock: big.NewInt(4_321_234), IstanbulBlock: big.NewInt(5_435_345), MuirGlacierBlock: nil, + RamanujanBlock: big.NewInt(0), + NielsBlock: big.NewInt(0), + MirrorSyncBlock: big.NewInt(0), BerlinBlock: big.NewInt(8_290_928), Clique: &CliqueConfig{ Period: 15, @@ -191,6 +200,9 @@ var ( ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), + RamanujanBlock: big.NewInt(0), + NielsBlock: big.NewInt(0), + MirrorSyncBlock: big.NewInt(0), IstanbulBlock: big.NewInt(1_561_651), MuirGlacierBlock: nil, BerlinBlock: big.NewInt(4_460_644), @@ -293,6 +305,9 @@ var ( ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + RamanujanBlock: big.NewInt(0), + NielsBlock: big.NewInt(0), + MirrorSyncBlock: big.NewInt(0), MuirGlacierBlock: nil, BerlinBlock: nil, // Don't enable Berlin directly, we're YOLOing it YoloV3Block: big.NewInt(0), @@ -307,16 +322,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), nil, nil, nil,nil, nil, nil, new(EthashConfig), nil, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, 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), nil, nil, nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil} + 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, &CliqueConfig{Period: 0, Epoch: 30000}, 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), nil, nil, nil, nil,nil, nil, new(EthashConfig), nil, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, nil} TestRules = TestChainConfig.Rules(new(big.Int)) ) @@ -389,21 +404,20 @@ type ChainConfig struct { EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block - ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) - ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) - PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) - IstanbulBlock *big.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) - MuirGlacierBlock *big.Int `json:"muirGlacierBlock,omitempty"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated) - BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin) + ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) + ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) + PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) + IstanbulBlock *big.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) + MuirGlacierBlock *big.Int `json:"muirGlacierBlock,omitempty"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated) + BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin) - YoloV3Block *big.Int `json:"yoloV3Block,omitempty"` // YOLO v3: Gas repricings TODO @holiman add EIP references - EWASMBlock *big.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated) RamanujanBlock *big.Int `json:"ramanujanBlock,omitempty" toml:",omitempty"` // ramanujanBlock switch block (nil = no fork, 0 = already activated) + YoloV3Block *big.Int `json:"yoloV3Block,omitempty"` // YOLO v3: Gas repricings TODO @holiman add EIP references + EWASMBlock *big.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated) RamanujanBlock *big.Int `json:"ramanujanBlock,omitempty" toml:",omitempty"` // ramanujanBlock switch block (nil = no fork, 0 = already activated) CatalystBlock *big.Int `json:"catalystBlock,omitempty"` // Catalyst switch block (nil = no fork, 0 = already on catalyst) - RamanujanBlock *big.Int `json:"ramanujanBlock,omitempty" toml:",omitempty"` // ramanujanBlock switch block (nil = no fork, 0 = already activated) - NielsBlock *big.Int `json:"nielsBlock,omitempty" toml:",omitempty"` // nielsBlock switch block (nil = no fork, 0 = already activated) - MirrorSyncBlock *big.Int `json:"mirrorSyncBlock,omitempty" toml:",omitempty"` // mirrorSyncBlock switch block (nil = no fork, 0 = already activated) - + RamanujanBlock *big.Int `json:"ramanujanBlock,omitempty" toml:",omitempty"` // ramanujanBlock switch block (nil = no fork, 0 = already activated) + NielsBlock *big.Int `json:"nielsBlock,omitempty" toml:",omitempty"` // nielsBlock switch block (nil = no fork, 0 = already activated) + MirrorSyncBlock *big.Int `json:"mirrorSyncBlock,omitempty" toml:",omitempty"` // mirrorSyncBlock switch block (nil = no fork, 0 = already activated) // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty" toml:",omitempty"` @@ -601,17 +615,6 @@ func (c *ChainConfig) CheckConfigForkOrder() error { } var lastFork fork for _, cur := range []fork{ - {name: "homesteadBlock", block: c.HomesteadBlock}, - {name: "daoForkBlock", block: c.DAOForkBlock, optional: true}, - {name: "eip150Block", block: c.EIP150Block}, - {name: "eip155Block", block: c.EIP155Block}, - {name: "eip158Block", block: c.EIP158Block}, - {name: "byzantiumBlock", block: c.ByzantiumBlock}, - {name: "constantinopleBlock", block: c.ConstantinopleBlock}, - {name: "petersburgBlock", block: c.PetersburgBlock}, - {name: "istanbulBlock", block: c.IstanbulBlock}, - {name: "muirGlacierBlock", block: c.MuirGlacierBlock, optional: true}, - {name: "ramanujanBlock", block: c.RamanujanBlock}, {name: "mirrorSyncBlock", block: c.MirrorSyncBlock}, {name: "berlinBlock", block: c.BerlinBlock}, } { diff --git a/rlp/decode.go b/rlp/decode.go index 79b7ef0626..a7054edc44 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -220,20 +220,51 @@ func decodeBigIntNoPtr(s *Stream, val reflect.Value) error { } func decodeBigInt(s *Stream, val reflect.Value) error { - b, err := s.Bytes() - if err != nil { + var buffer []byte + kind, size, err := s.Kind() + switch { + case err != nil: return wrapStreamError(err, val.Type()) + case kind == List: + return wrapStreamError(ErrExpectedString, val.Type()) + 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)): + // For integers smaller than s.uintbuf, allocating a buffer + // can be avoided. + buffer = s.uintbuf[:size] + if err := s.readFull(buffer); err != nil { + return wrapStreamError(err, val.Type()) + } + // Reject inputs where single byte encoding should have been used. + if size == 1 && buffer[0] < 128 { + return wrapStreamError(ErrCanonSize, val.Type()) + } + default: + // For large integers, a temporary buffer is needed. + buffer = make([]byte, size) + if err := s.readFull(buffer); err != nil { + return wrapStreamError(err, val.Type()) + } } + + // Reject leading zero bytes. + if len(buffer) > 0 && buffer[0] == 0 { + return wrapStreamError(ErrCanonInt, val.Type()) + } + + // Set the integer bytes. i := val.Interface().(*big.Int) if i == nil { i = new(big.Int) val.Set(reflect.ValueOf(i)) } - // Reject leading zero bytes - if len(b) > 0 && b[0] == 0 { - return wrapStreamError(ErrCanonInt, val.Type()) - } - i.SetBytes(b) + i.SetBytes(buffer) return nil } @@ -245,7 +276,7 @@ func makeListDecoder(typ reflect.Type, tag tags) (decoder, error) { } return decodeByteSlice, nil } - etypeinfo := cachedTypeInfo1(etype, tags{}) + etypeinfo := theTC.infoWhileGenerating(etype, tags{}) if etypeinfo.decoderErr != nil { return nil, etypeinfo.decoderErr } @@ -348,25 +379,23 @@ func decodeByteArray(s *Stream, val reflect.Value) error { if err != nil { return err } - vlen := val.Len() + slice := byteArrayBytes(val) switch kind { case Byte: - if vlen == 0 { + if len(slice) == 0 { return &decodeError{msg: "input string too long", typ: val.Type()} - } - if vlen > 1 { + } else if len(slice) > 1 { return &decodeError{msg: "input string too short", typ: val.Type()} } - bv, _ := s.Uint() - val.Index(0).SetUint(bv) + slice[0] = s.byteval + s.kind = -1 case String: - if uint64(vlen) < size { + if uint64(len(slice)) < size { return &decodeError{msg: "input string too long", typ: val.Type()} } - if uint64(vlen) > size { + if uint64(len(slice)) > size { return &decodeError{msg: "input string too short", typ: val.Type()} } - slice := val.Slice(0, vlen).Interface().([]byte) if err := s.readFull(slice); err != nil { return err } @@ -410,7 +439,7 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) { // makePtrDecoder creates a decoder that decodes into the pointer's element type. func makePtrDecoder(typ reflect.Type, tag tags) (decoder, error) { etype := typ.Elem() - etypeinfo := cachedTypeInfo1(etype, tags{}) + etypeinfo := theTC.infoWhileGenerating(etype, tags{}) switch { case etypeinfo.decoderErr != nil: return nil, etypeinfo.decoderErr @@ -504,7 +533,7 @@ func decodeDecoder(s *Stream, val reflect.Value) error { } // Kind represents the kind of value contained in an RLP stream. -type Kind int +type Kind int8 const ( Byte Kind = iota @@ -547,22 +576,16 @@ type ByteReader interface { type Stream struct { r ByteReader - // number of bytes remaining to be read from r. - remaining uint64 - limited bool - - // auxiliary buffer for integer decoding - uintbuf []byte - - kind Kind // kind of value ahead - size uint64 // size of value ahead - byteval byte // value of single byte in type tag - kinderr error // error from last readKind - stack []listpos + remaining uint64 // number of bytes remaining to be read from r + size uint64 // size of value ahead + kinderr error // error from last readKind + stack []uint64 // list sizes + uintbuf [32]byte // auxiliary buffer for integer decoding + kind Kind // kind of value ahead + byteval byte // value of single byte in type tag + limited bool // true if input limit is in effect } -type listpos struct{ pos, size uint64 } - // NewStream creates a new decoding stream reading from r. // // If r implements the ByteReader interface, Stream will @@ -632,8 +655,8 @@ func (s *Stream) Raw() ([]byte, error) { s.kind = -1 // rearm Kind return []byte{s.byteval}, nil } - // the original header has already been read and is no longer - // available. read content and put a new header in front of it. + // The original header has already been read and is no longer + // available. Read content and put a new header in front of it. start := headsize(size) buf := make([]byte, uint64(start)+size) if err := s.readFull(buf[start:]); err != nil { @@ -716,7 +739,14 @@ func (s *Stream) List() (size uint64, err error) { if kind != List { return 0, ErrExpectedList } - s.stack = append(s.stack, listpos{0, size}) + + // Remove size of inner list from outer list before pushing the new size + // onto the stack. This ensures that the remaining outer list size will + // be correct after the matching call to ListEnd. + if inList, limit := s.listLimit(); inList { + s.stack[len(s.stack)-1] = limit - size + } + s.stack = append(s.stack, size) s.kind = -1 s.size = 0 return size, nil @@ -725,17 +755,13 @@ func (s *Stream) List() (size uint64, err error) { // ListEnd returns to the enclosing list. // The input reader must be positioned at the end of a list. func (s *Stream) ListEnd() error { - if len(s.stack) == 0 { + // Ensure that no more data is remaining in the current list. + if inList, listLimit := s.listLimit(); !inList { return errNotInList - } - tos := s.stack[len(s.stack)-1] - if tos.pos != tos.size { + } else if listLimit > 0 { return errNotAtEOL } s.stack = s.stack[:len(s.stack)-1] // pop - if len(s.stack) > 0 { - s.stack[len(s.stack)-1].pos += tos.size - } s.kind = -1 s.size = 0 return nil @@ -763,7 +789,7 @@ func (s *Stream) Decode(val interface{}) error { err = decoder(s, rval.Elem()) if decErr, ok := err.(*decodeError); ok && len(decErr.ctx) > 0 { - // add decode target type to error so context has more meaning + // Add decode target type to error so context has more meaning. decErr.ctx = append(decErr.ctx, fmt.Sprint("(", rtyp.Elem(), ")")) } return err @@ -786,6 +812,9 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) { case *bytes.Reader: s.remaining = uint64(br.Len()) s.limited = true + case *bytes.Buffer: + s.remaining = uint64(br.Len()) + s.limited = true case *strings.Reader: s.remaining = uint64(br.Len()) s.limited = true @@ -804,10 +833,8 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) { s.size = 0 s.kind = -1 s.kinderr = nil - if s.uintbuf == nil { - s.uintbuf = make([]byte, 8) - } s.byteval = 0 + s.uintbuf = [32]byte{} } // Kind returns the kind and size of the next value in the @@ -822,35 +849,29 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) { // the value. Subsequent calls to Kind (until the value is decoded) // will not advance the input reader and return cached information. func (s *Stream) Kind() (kind Kind, size uint64, err error) { - var tos *listpos - if len(s.stack) > 0 { - tos = &s.stack[len(s.stack)-1] - } - if s.kind < 0 { - s.kinderr = nil - // Don't read further if we're at the end of the - // innermost list. - if tos != nil && tos.pos == tos.size { - return 0, 0, EOL - } - s.kind, s.size, s.kinderr = s.readKind() - if s.kinderr == nil { - if tos == nil { - // At toplevel, check that the value is smaller - // than the remaining input length. - if s.limited && s.size > s.remaining { - s.kinderr = ErrValueTooLarge - } - } else { - // Inside a list, check that the value doesn't overflow the list. - if s.size > tos.size-tos.pos { - s.kinderr = ErrElemTooLarge - } - } + if s.kind >= 0 { + return s.kind, s.size, s.kinderr + } + + // Check for end of list. This needs to be done here because readKind + // checks against the list size, and would return the wrong error. + inList, listLimit := s.listLimit() + if inList && listLimit == 0 { + return 0, 0, EOL + } + // Read the actual size tag. + s.kind, s.size, s.kinderr = s.readKind() + if s.kinderr == nil { + // Check the data size of the value ahead against input limits. This + // is done here because many decoders require allocating an input + // buffer matching the value size. Checking it here protects those + // decoders from inputs declaring very large value size. + if inList && s.size > listLimit { + s.kinderr = ErrElemTooLarge + } else if s.limited && s.size > s.remaining { + s.kinderr = ErrValueTooLarge } } - // Note: this might return a sticky error generated - // by an earlier call to readKind. return s.kind, s.size, s.kinderr } @@ -877,37 +898,35 @@ func (s *Stream) readKind() (kind Kind, size uint64, err error) { s.byteval = b return Byte, 0, nil case b < 0xB8: - // Otherwise, if a string is 0-55 bytes long, - // the RLP encoding consists of a single byte with value 0x80 plus the - // length of the string followed by the string. The range of the first - // byte is thus [0x80, 0xB7]. + // Otherwise, if a string is 0-55 bytes long, the RLP encoding consists + // of a single byte with value 0x80 plus the length of the string + // followed by the string. The range of the first byte is thus [0x80, 0xB7]. return String, uint64(b - 0x80), nil case b < 0xC0: - // If a string is more than 55 bytes long, the - // RLP encoding consists of a single byte with value 0xB7 plus the length - // of the length of the string in binary form, followed by the length of - // the string, followed by the string. For example, a length-1024 string - // would be encoded as 0xB90400 followed by the string. The range of - // the first byte is thus [0xB8, 0xBF]. + // If a string is more than 55 bytes long, the RLP encoding consists of a + // single byte with value 0xB7 plus the length of the length of the + // string in binary form, followed by the length of the string, followed + // by the string. For example, a length-1024 string would be encoded as + // 0xB90400 followed by the string. The range of the first byte is thus + // [0xB8, 0xBF]. size, err = s.readUint(b - 0xB7) if err == nil && size < 56 { err = ErrCanonSize } return String, size, err case b < 0xF8: - // If the total payload of a list - // (i.e. the combined length of all its items) is 0-55 bytes long, the - // RLP encoding consists of a single byte with value 0xC0 plus the length - // of the list followed by the concatenation of the RLP encodings of the - // items. The range of the first byte is thus [0xC0, 0xF7]. + // If the total payload of a list (i.e. the combined length of all its + // items) is 0-55 bytes long, the RLP encoding consists of a single byte + // with value 0xC0 plus the length of the list followed by the + // concatenation of the RLP encodings of the items. The range of the + // first byte is thus [0xC0, 0xF7]. return List, uint64(b - 0xC0), nil default: - // If the total payload of a list is more than 55 bytes long, - // the RLP encoding consists of a single byte with value 0xF7 - // plus the length of the length of the payload in binary - // form, followed by the length of the payload, followed by - // the concatenation of the RLP encodings of the items. The - // range of the first byte is thus [0xF8, 0xFF]. + // If the total payload of a list is more than 55 bytes long, the RLP + // encoding consists of a single byte with value 0xF7 plus the length of + // the length of the payload in binary form, followed by the length of + // the payload, followed by the concatenation of the RLP encodings of + // the items. The range of the first byte is thus [0xF8, 0xFF]. size, err = s.readUint(b - 0xF7) if err == nil && size < 56 { err = ErrCanonSize @@ -925,23 +944,24 @@ func (s *Stream) readUint(size byte) (uint64, error) { b, err := s.readByte() return uint64(b), err default: - start := int(8 - size) - for i := 0; i < start; i++ { - s.uintbuf[i] = 0 + buffer := s.uintbuf[:8] + for i := range buffer { + buffer[i] = 0 } - if err := s.readFull(s.uintbuf[start:]); err != nil { + start := int(8 - size) + if err := s.readFull(buffer[start:]); err != nil { return 0, err } - if s.uintbuf[start] == 0 { - // Note: readUint is also used to decode integer - // values. The error needs to be adjusted to become - // ErrCanonInt in this case. + if buffer[start] == 0 { + // Note: readUint is also used to decode integer values. + // The error needs to be adjusted to become ErrCanonInt in this case. return 0, ErrCanonSize } - return binary.BigEndian.Uint64(s.uintbuf), nil + return binary.BigEndian.Uint64(buffer[:]), nil } } +// readFull reads into buf from the underlying stream. func (s *Stream) readFull(buf []byte) (err error) { if err := s.willRead(uint64(len(buf))); err != nil { return err @@ -963,6 +983,7 @@ func (s *Stream) readFull(buf []byte) (err error) { return err } +// readByte reads a single byte from the underlying stream. func (s *Stream) readByte() (byte, error) { if err := s.willRead(1); err != nil { return 0, err @@ -974,16 +995,16 @@ func (s *Stream) readByte() (byte, error) { return b, err } +// willRead is called before any read from the underlying stream. It checks +// n against size limits, and updates the limits if n doesn't overflow them. func (s *Stream) willRead(n uint64) error { s.kind = -1 // rearm Kind - if len(s.stack) > 0 { - // check list overflow - tos := s.stack[len(s.stack)-1] - if n > tos.size-tos.pos { + if inList, limit := s.listLimit(); inList { + if n > limit { return ErrElemTooLarge } - s.stack[len(s.stack)-1].pos += n + s.stack[len(s.stack)-1] = limit - n } if s.limited { if n > s.remaining { @@ -993,3 +1014,11 @@ func (s *Stream) willRead(n uint64) error { } return nil } + +// listLimit returns the amount of data remaining in the innermost list. +func (s *Stream) listLimit() (inList bool, limit uint64) { + if len(s.stack) == 0 { + return false, 0 + } + return true, s.stack[len(s.stack)-1] +} diff --git a/rlp/decode_test.go b/rlp/decode_test.go index d94c3969b2..f8af3897c0 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -26,6 +26,8 @@ import ( "reflect" "strings" "testing" + + "github.com/ethereum/go-ethereum/common/math" ) func TestStreamKind(t *testing.T) { @@ -327,6 +329,11 @@ type recstruct struct { Child *recstruct `rlp:"nil"` } +type bigIntStruct struct { + I *big.Int + B string +} + type invalidNilTag struct { X []byte `rlp:"nil"` } @@ -370,10 +377,11 @@ type intField struct { } var ( - veryBigInt = big.NewInt(0).Add( + veryBigInt = new(big.Int).Add( big.NewInt(0).Lsh(big.NewInt(0xFFFFFFFFFFFFFF), 16), big.NewInt(0xFFFF), ) + veryVeryBigInt = new(big.Int).Exp(veryBigInt, big.NewInt(8), nil) ) type hasIgnoredField struct { @@ -450,12 +458,15 @@ var decodeTests = []decodeTest{ {input: "C0", ptr: new(string), error: "rlp: expected input string or byte for string"}, // big ints + {input: "80", ptr: new(*big.Int), value: big.NewInt(0)}, {input: "01", ptr: new(*big.Int), value: big.NewInt(1)}, {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 {input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte 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"}, + {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"}, // structs { @@ -468,6 +479,13 @@ var decodeTests = []decodeTest{ ptr: new(recstruct), value: recstruct{1, &recstruct{2, &recstruct{3, nil}}}, }, + { + // This checks that empty big.Int works correctly in struct context. It's easy to + // miss the update of s.kind for this case, so it needs its own test. + input: "C58083343434", + ptr: new(bigIntStruct), + value: bigIntStruct{new(big.Int), "444"}, + }, // struct errors { @@ -898,7 +916,7 @@ func ExampleStream() { // [102 111 111 98 97 114] } -func BenchmarkDecode(b *testing.B) { +func BenchmarkDecodeUints(b *testing.B) { enc := encodeTestSlice(90000) b.SetBytes(int64(len(enc))) b.ReportAllocs() @@ -913,7 +931,7 @@ func BenchmarkDecode(b *testing.B) { } } -func BenchmarkDecodeIntSliceReuse(b *testing.B) { +func BenchmarkDecodeUintsReused(b *testing.B) { enc := encodeTestSlice(100000) b.SetBytes(int64(len(enc))) b.ReportAllocs() @@ -928,6 +946,44 @@ func BenchmarkDecodeIntSliceReuse(b *testing.B) { } } +func BenchmarkDecodeByteArrayStruct(b *testing.B) { + enc, err := EncodeToBytes(&byteArrayStruct{}) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(enc))) + b.ReportAllocs() + b.ResetTimer() + + var out byteArrayStruct + for i := 0; i < b.N; i++ { + if err := DecodeBytes(enc, &out); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkDecodeBigInts(b *testing.B) { + ints := make([]*big.Int, 200) + for i := range ints { + ints[i] = 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 []*big.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/encode.go b/rlp/encode.go index 77b591045d..9fc270ef6d 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -124,19 +124,15 @@ func puthead(buf []byte, smalltag, largetag byte, size uint64) int { } type encbuf struct { - str []byte // string data, contains everything except list headers - lheads []listhead // all list headers - lhsize int // sum of sizes of all encoded list headers - sizebuf [9]byte // auxiliary buffer for uint encoding - bufvalue reflect.Value // used in writeByteArrayCopy + str []byte // string data, contains everything except list headers + lheads []listhead // all list headers + lhsize int // sum of sizes of all encoded list headers + sizebuf [9]byte // auxiliary buffer for uint encoding } // encbufs are pooled. var encbufPool = sync.Pool{ - New: func() interface{} { - var bytes []byte - return &encbuf{bufvalue: reflect.ValueOf(&bytes).Elem()} - }, + New: func() interface{} { return new(encbuf) }, } func (w *encbuf) reset() { @@ -429,21 +425,14 @@ func writeBytes(val reflect.Value, w *encbuf) error { return nil } -var byteType = reflect.TypeOf(byte(0)) - func makeByteArrayWriter(typ reflect.Type) writer { - length := typ.Len() - if length == 0 { + switch typ.Len() { + case 0: return writeLengthZeroByteArray - } else if length == 1 { + case 1: return writeLengthOneByteArray - } - if typ.Elem() != byteType { - return writeNamedByteArray - } - return func(val reflect.Value, w *encbuf) error { - writeByteArrayCopy(length, val, w) - return nil + default: + return writeByteArray } } @@ -462,29 +451,18 @@ func writeLengthOneByteArray(val reflect.Value, w *encbuf) error { return nil } -// writeByteArrayCopy encodes byte arrays using reflect.Copy. This is -// the fast path for [N]byte where N > 1. -func writeByteArrayCopy(length int, val reflect.Value, w *encbuf) { - w.encodeStringHeader(length) - offset := len(w.str) - w.str = append(w.str, make([]byte, length)...) - w.bufvalue.SetBytes(w.str[offset:]) - reflect.Copy(w.bufvalue, val) -} - -// writeNamedByteArray encodes byte arrays with named element type. -// This exists because reflect.Copy can't be used with such types. -func writeNamedByteArray(val reflect.Value, w *encbuf) error { +func writeByteArray(val reflect.Value, w *encbuf) error { if !val.CanAddr() { - // Slice requires the value to be addressable. - // Make it addressable by copying. + // Getting the byte slice of val requires it to be addressable. Make it + // addressable by copying. copy := reflect.New(val.Type()).Elem() copy.Set(val) val = copy } - size := val.Len() - slice := val.Slice(0, size).Bytes() - w.encodeString(slice) + + slice := byteArrayBytes(val) + w.encodeStringHeader(len(slice)) + w.str = append(w.str, slice...) return nil } @@ -517,7 +495,7 @@ func writeInterface(val reflect.Value, w *encbuf) error { } func makeSliceWriter(typ reflect.Type, ts tags) (writer, error) { - etypeinfo := cachedTypeInfo1(typ.Elem(), tags{}) + etypeinfo := theTC.infoWhileGenerating(typ.Elem(), tags{}) if etypeinfo.writerErr != nil { return nil, etypeinfo.writerErr } @@ -560,7 +538,7 @@ func makeStructWriter(typ reflect.Type) (writer, error) { } func makePtrWriter(typ reflect.Type, ts tags) (writer, error) { - etypeinfo := cachedTypeInfo1(typ.Elem(), tags{}) + etypeinfo := theTC.infoWhileGenerating(typ.Elem(), tags{}) if etypeinfo.writerErr != nil { return nil, etypeinfo.writerErr } diff --git a/rlp/encode_test.go b/rlp/encode_test.go index 418ee10a35..523ea97cf2 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -23,6 +23,7 @@ import ( "io" "io/ioutil" "math/big" + "runtime" "sync" "testing" @@ -130,6 +131,14 @@ var encTests = []encTest{ val: big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")), output: "A1010000000000000000000000000000000000000000000000000000000000000000", }, + { + val: veryBigInt, + output: "89FFFFFFFFFFFFFFFFFF", + }, + { + val: veryVeryBigInt, + output: "B848FFFFFFFFFFFFFFFFF800000000000000001BFFFFFFFFFFFFFFFFC8000000000000000045FFFFFFFFFFFFFFFFC800000000000000001BFFFFFFFFFFFFFFFFF8000000000000000001", + }, // non-pointer big.Int {val: *big.NewInt(0), output: "80"}, @@ -462,3 +471,54 @@ func BenchmarkEncodeBigInts(b *testing.B) { } } } + +func BenchmarkEncodeConcurrentInterface(b *testing.B) { + type struct1 struct { + A string + B *big.Int + C [20]byte + } + value := []interface{}{ + uint(999), + &struct1{A: "hello", B: big.NewInt(0xFFFFFFFF)}, + [10]byte{1, 2, 3, 4, 5, 6}, + []string{"yeah", "yeah", "yeah"}, + } + + var wg sync.WaitGroup + for cpu := 0; cpu < runtime.NumCPU(); cpu++ { + wg.Add(1) + go func() { + defer wg.Done() + + var buffer bytes.Buffer + for i := 0; i < b.N; i++ { + buffer.Reset() + err := Encode(&buffer, value) + if err != nil { + panic(err) + } + } + }() + } + wg.Wait() +} + +type byteArrayStruct struct { + A [20]byte + B [32]byte + C [32]byte +} + +func BenchmarkEncodeByteArrayStruct(b *testing.B) { + var out bytes.Buffer + var value byteArrayStruct + + b.ReportAllocs() + for i := 0; i < b.N; i++ { + out.Reset() + if err := Encode(&out, &value); err != nil { + b.Fatal(err) + } + } +} diff --git a/rlp/safe.go b/rlp/safe.go new file mode 100644 index 0000000000..c881650a0d --- /dev/null +++ b/rlp/safe.go @@ -0,0 +1,26 @@ +// 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 . + +// +build nacl js !cgo + +package rlp + +import "reflect" + +// byteArrayBytes returns a slice of the byte array v. +func byteArrayBytes(v reflect.Value) []byte { + return v.Slice(0, v.Len()).Bytes() +} diff --git a/rlp/typecache.go b/rlp/typecache.go index 6026e1a649..62553d3b55 100644 --- a/rlp/typecache.go +++ b/rlp/typecache.go @@ -21,13 +21,10 @@ import ( "reflect" "strings" "sync" + "sync/atomic" ) -var ( - typeCacheMutex sync.RWMutex - typeCache = make(map[typekey]*typeinfo) -) - +// typeinfo is an entry in the type cache. type typeinfo struct { decoder decoder decoderErr error // error from makeDecoder @@ -38,15 +35,16 @@ type typeinfo struct { // tags represents struct tags. type tags struct { // rlp:"nil" controls whether empty input results in a nil pointer. - nilOK bool - - // This controls whether nil pointers are encoded/decoded as empty strings - // or empty lists. + // nilKind is the kind of empty value allowed for the field. nilKind Kind + nilOK bool + + // rlp:"optional" allows for a field to be missing in the input list. + // If this is set, all subsequent fields must also be optional. + optional bool - // rlp:"tail" controls whether this field swallows additional list - // elements. It can only be set for the last field, which must be - // of slice type. + // rlp:"tail" controls whether this field swallows additional list elements. It can + // only be set for the last field, which must be of slice type. tail bool // rlp:"-" ignores fields. @@ -64,68 +62,126 @@ type decoder func(*Stream, reflect.Value) error type writer func(reflect.Value, *encbuf) error +var theTC = newTypeCache() + +type typeCache struct { + cur atomic.Value + + // This lock synchronizes writers. + mu sync.Mutex + next map[typekey]*typeinfo +} + +func newTypeCache() *typeCache { + c := new(typeCache) + c.cur.Store(make(map[typekey]*typeinfo)) + return c +} + func cachedDecoder(typ reflect.Type) (decoder, error) { - info := cachedTypeInfo(typ, tags{}) + info := theTC.info(typ) return info.decoder, info.decoderErr } func cachedWriter(typ reflect.Type) (writer, error) { - info := cachedTypeInfo(typ, tags{}) + info := theTC.info(typ) return info.writer, info.writerErr } -func cachedTypeInfo(typ reflect.Type, tags tags) *typeinfo { - typeCacheMutex.RLock() - info := typeCache[typekey{typ, tags}] - typeCacheMutex.RUnlock() - if info != nil { +func (c *typeCache) info(typ reflect.Type) *typeinfo { + key := typekey{Type: typ} + if info := c.cur.Load().(map[typekey]*typeinfo)[key]; info != nil { return info } - // not in the cache, need to generate info for this type. - typeCacheMutex.Lock() - defer typeCacheMutex.Unlock() - return cachedTypeInfo1(typ, tags) + + // Not in the cache, need to generate info for this type. + return c.generate(typ, tags{}) } -func cachedTypeInfo1(typ reflect.Type, tags tags) *typeinfo { +func (c *typeCache) generate(typ reflect.Type, tags tags) *typeinfo { + c.mu.Lock() + defer c.mu.Unlock() + + cur := c.cur.Load().(map[typekey]*typeinfo) + if info := cur[typekey{typ, tags}]; info != nil { + return info + } + + // Copy cur to next. + c.next = make(map[typekey]*typeinfo, len(cur)+1) + for k, v := range cur { + c.next[k] = v + } + + // Generate. + info := c.infoWhileGenerating(typ, tags) + + // next -> cur + c.cur.Store(c.next) + c.next = nil + return info +} + +func (c *typeCache) infoWhileGenerating(typ reflect.Type, tags tags) *typeinfo { key := typekey{typ, tags} - info := typeCache[key] - if info != nil { - // another goroutine got the write lock first + if info := c.next[key]; info != nil { return info } - // put a dummy value into the cache before generating. - // if the generator tries to lookup itself, it will get + // Put a dummy value into the cache before generating. + // If the generator tries to lookup itself, it will get // the dummy value and won't call itself recursively. - info = new(typeinfo) - typeCache[key] = info + info := new(typeinfo) + c.next[key] = info info.generate(typ, tags) return info } type field struct { - index int - info *typeinfo + index int + info *typeinfo + optional bool } +// structFields resolves the typeinfo of all public fields in a struct type. func structFields(typ reflect.Type) (fields []field, err error) { - lastPublic := lastPublicField(typ) + var ( + lastPublic = lastPublicField(typ) + anyOptional = false + ) for i := 0; i < typ.NumField(); i++ { if f := typ.Field(i); f.PkgPath == "" { // exported tags, err := parseStructTag(typ, i, lastPublic) if err != nil { return nil, err } + + // Skip rlp:"-" fields. if tags.ignored { continue } - info := cachedTypeInfo1(f.Type, tags) - fields = append(fields, field{i, info}) + // If any field has the "optional" tag, subsequent fields must also have it. + if tags.optional || tags.tail { + anyOptional = true + } else if anyOptional { + return nil, fmt.Errorf(`rlp: struct field %v.%s needs "optional" tag`, typ, f.Name) + } + info := theTC.infoWhileGenerating(f.Type, tags) + fields = append(fields, field{i, info, tags.optional}) } } return fields, nil } +// anyOptionalFields returns the index of the first field with "optional" tag. +func firstOptionalField(fields []field) int { + for i, f := range fields { + if f.optional { + return i + } + } + return len(fields) +} + type structFieldError struct { typ reflect.Type field int @@ -166,11 +222,19 @@ func parseStructTag(typ reflect.Type, fi, lastPublic int) (tags, error) { case "nilList": ts.nilKind = List } + case "optional": + ts.optional = true + if ts.tail { + return ts, structTagError{typ, f.Name, t, `also has "tail" tag`} + } case "tail": ts.tail = true if fi != lastPublic { return ts, structTagError{typ, f.Name, t, "must be on last field"} } + if ts.optional { + return ts, structTagError{typ, f.Name, t, `also has "optional" tag`} + } if f.Type.Kind() != reflect.Slice { return ts, structTagError{typ, f.Name, t, "field type is not slice"} } diff --git a/rlp/unsafe.go b/rlp/unsafe.go new file mode 100644 index 0000000000..94ed5405a8 --- /dev/null +++ b/rlp/unsafe.go @@ -0,0 +1,35 @@ +// 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 . + +// +build !nacl,!js,cgo + +package rlp + +import ( + "reflect" + "unsafe" +) + +// byteArrayBytes returns a slice of the byte array v. +func byteArrayBytes(v reflect.Value) []byte { + len := v.Len() + var s []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s)) + hdr.Data = v.UnsafeAddr() + hdr.Cap = len + hdr.Len = len + return s +} diff --git a/rpc/handler.go b/rpc/handler.go index 2ca6480ec2..b1fd20c86b 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -25,6 +25,8 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/gopool" + "github.com/ethereum/go-ethereum/log" ) @@ -219,12 +221,12 @@ func (h *handler) cancelServerSubscriptions(err error) { // startCallProc runs fn in a new goroutine and starts tracking it in the h.calls wait group. func (h *handler) startCallProc(fn func(*callProc)) { h.callWG.Add(1) - go func() { + gopool.Submit(func() { ctx, cancel := context.WithCancel(h.rootCtx) defer h.callWG.Done() defer cancel() fn(&callProc{ctx: ctx}) - }() + }) } // handleImmediate executes non-call messages. It returns false if the message is a diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 46834de6da..19c79b6eed 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -230,7 +230,7 @@ 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) + snaps, _ = snapshot.New(db, sdb.TrieDB(), 1, 128, root, false, true, false) } statedb, _ = state.New(root, sdb, snaps) return snaps, statedb diff --git a/trie/committer.go b/trie/committer.go index ce4065f5fd..250b36e37f 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -44,7 +44,6 @@ type leaf struct { // 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. type committer struct { - tmp sliceBuffer sha crypto.KeccakState onleaf LeafCallback @@ -55,7 +54,6 @@ type committer struct { var committerPool = sync.Pool{ New: func() interface{} { return &committer{ - tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode. sha: sha3.NewLegacyKeccak256().(crypto.KeccakState), } }, @@ -95,6 +93,7 @@ func (c *committer) commit(n node, db *Database) (node, error) { switch cn := n.(type) { case *shortNode: // Commit child + cn.flags.dirty = false collapsed := cn.copy() // If the child is fullnode, recursively commit. @@ -114,6 +113,7 @@ func (c *committer) commit(n node, db *Database) (node, error) { } return collapsed, nil case *fullNode: + cn.flags.dirty = false hashedKids, err := c.commitChildren(cn, db) if err != nil { return nil, err diff --git a/trie/database.go b/trie/database.go index b18665770e..76f8b26ccd 100644 --- a/trie/database.go +++ b/trie/database.go @@ -88,6 +88,11 @@ type Database struct { childrenSize common.StorageSize // Storage size of the external children tracking preimagesSize common.StorageSize // Storage size of the preimages cache + //metrics with light lock + sizeLock sync.RWMutex + roughPreimagesSize common.StorageSize + roughDirtiesSize common.StorageSize + lock sync.RWMutex } @@ -483,9 +488,15 @@ func (db *Database) Nodes() []common.Hash { // are referenced together by database itself. func (db *Database) Reference(child common.Hash, parent common.Hash) { db.lock.Lock() - defer db.lock.Unlock() - db.reference(child, parent) + var roughDirtiesSize = common.StorageSize((len(db.dirties)-1)*cachedNodeSize) + db.dirtiesSize + db.childrenSize - common.StorageSize(len(db.dirties[common.Hash{}].children)*(common.HashLength+2)) + var roughPreimagesSize = db.preimagesSize + db.lock.Unlock() + + db.sizeLock.Lock() + db.roughDirtiesSize = roughDirtiesSize + db.roughPreimagesSize = roughPreimagesSize + db.sizeLock.Unlock() } // reference is the private locked version of Reference. @@ -703,12 +714,6 @@ 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) - if batch.ValueSize() > ethdb.IdealBatchSize { - if err := batch.Write(); err != nil { - return err - } - batch.Reset() - } // 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 { @@ -843,15 +848,9 @@ func (c *cleaner) Delete(key []byte) error { // 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) { - db.lock.RLock() - defer db.lock.RUnlock() - - // db.dirtiesSize only contains the useful data in the cache, but when reporting - // the total memory consumption, the maintenance metadata is also needed to be - // 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 + db.sizeLock.RLock() + defer db.sizeLock.RUnlock() + return db.roughDirtiesSize, db.roughPreimagesSize } // saveCache saves clean state cache to given directory path diff --git a/trie/secure_trie.go b/trie/secure_trie.go index e38471c1b7..c85d0831a7 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -35,7 +35,6 @@ import ( // SecureTrie is not safe for concurrent use. type SecureTrie struct { trie Trie - hashKeyBuf [common.HashLength]byte secKeyCache map[string][]byte secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch } @@ -172,6 +171,17 @@ func (t *SecureTrie) Copy() *SecureTrie { return &cpy } +func (t *SecureTrie) ResetCopy() *SecureTrie { + cpy := *t + cpy.secKeyCacheOwner = nil + cpy.secKeyCache = nil + return &cpy +} + +func (t *SecureTrie) GetRawTrie() Trie { + return t.trie +} + // 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 { @@ -182,12 +192,13 @@ func (t *SecureTrie) NodeIterator(start []byte) NodeIterator { // 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 { + hash := make([]byte, common.HashLength) h := newHasher(false) h.sha.Reset() h.sha.Write(key) - h.sha.Read(t.hashKeyBuf[:]) + h.sha.Read(hash) returnHasherToPool(h) - return t.hashKeyBuf[:] + return hash } // getSecKeyCache returns the current secure key cache, creating a new one if diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index fb6c38ee22..7bbdf29ef0 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb/memorydb" ) @@ -119,7 +120,8 @@ func TestSecureTrieConcurrency(t *testing.T) { pend := new(sync.WaitGroup) pend.Add(threads) for i := 0; i < threads; i++ { - go func(index int) { + index := i + gopool.Submit(func() { defer pend.Done() for j := byte(0); j < 255; j++ { @@ -137,7 +139,7 @@ func TestSecureTrieConcurrency(t *testing.T) { } } tries[index].Commit(nil) - }(i) + }) } // Wait for all threads to finish pend.Wait() diff --git a/trie/sync_bloom.go b/trie/sync_bloom.go index 1afcce21da..855c7cf5eb 100644 --- a/trie/sync_bloom.go +++ b/trie/sync_bloom.go @@ -24,6 +24,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" @@ -67,14 +68,15 @@ func NewSyncBloom(memory uint64, database ethdb.Iteratee) *SyncBloom { bloom: bloom, } b.pend.Add(2) - go func() { + gopool.Submit(func() { defer b.pend.Done() b.init(database) - }() - go func() { + }) + + gopool.Submit(func() { defer b.pend.Done() b.meter() - }() + }) return b } diff --git a/trie/trie.go b/trie/trie.go index 7ed235fa8a..44de1374a4 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -570,3 +570,7 @@ func (t *Trie) Reset() { t.root = nil t.unhashed = 0 } + +func (t *Trie) Size() int { + return estimateSize(t.root) +} From 7e8d9fb51d3a3d006c6599c6b2b295ab59e4bf9f Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Thu, 29 Jul 2021 17:17:11 +0800 Subject: [PATCH 008/117] fix: block fetcher efficiency (#333) --- eth/fetcher/block_fetcher.go | 44 +++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index 05e5833ce2..4819e9eab5 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -33,10 +33,12 @@ import ( ) const ( - lightTimeout = time.Millisecond // Time allowance before an announced header is explicitly requested - arriveTimeout = 500 * time.Millisecond // Time allowance before an announced block/transaction is explicitly requested - gatherSlack = 100 * time.Millisecond // Interval used to collate almost-expired announces with fetches - fetchTimeout = 5 * time.Second // Maximum allotted time to return an explicitly requested block/transaction + lightTimeout = time.Millisecond // Time allowance before an announced header is explicitly requested + arriveTimeout = 500 * time.Millisecond // Time allowance before an announced block/transaction is explicitly requested + gatherSlack = 100 * time.Millisecond // Interval used to collate almost-expired announces with fetches + fetchTimeout = 5 * time.Second // Maximum allotted time to return an explicitly requested block/transaction + reQueueBlockTimeout = 500 * time.Millisecond // Time allowance before blocks are requeued for import + ) const ( @@ -167,6 +169,8 @@ type BlockFetcher struct { done chan common.Hash quit chan struct{} + requeue chan *blockOrHeaderInject + // Announce states announces map[string]int // Per peer blockAnnounce counts to prevent memory exhaustion announced map[common.Hash][]*blockAnnounce // Announced blocks, scheduled for fetching @@ -207,6 +211,7 @@ func NewBlockFetcher(light bool, getHeader HeaderRetrievalFn, getBlock blockRetr bodyFilter: make(chan chan *bodyFilterTask), done: make(chan common.Hash), quit: make(chan struct{}), + requeue: make(chan *blockOrHeaderInject), announces: make(map[string]int), announced: make(map[common.Hash][]*blockAnnounce), fetching: make(map[common.Hash]*blockAnnounce), @@ -371,9 +376,9 @@ func (f *BlockFetcher) loop() { continue } if f.light { - f.importHeaders(op.origin, op.header) + f.importHeaders(op) } else { - f.importBlocks(op.origin, op.block) + f.importBlocks(op) } } // Wait for an outside event to occur @@ -416,6 +421,21 @@ func (f *BlockFetcher) loop() { f.rescheduleFetch(fetchTimer) } + case op := <-f.requeue: + // Re-queue blocks that have not been written due to fork block competition + number := int64(0) + hash := "" + if op.header != nil { + number = op.header.Number.Int64() + hash = op.header.Hash().String() + } else if op.block != nil { + number = op.block.Number().Int64() + hash = op.block.Hash().String() + } + + log.Info("Re-queue blocks", "number", number, "hash", hash) + f.enqueue(op.origin, op.header, op.block) + case op := <-f.inject: // A direct block insertion was requested, try and fill any pending gaps blockBroadcastInMeter.Mark(1) @@ -751,7 +771,9 @@ func (f *BlockFetcher) enqueue(peer string, header *types.Header, block *types.B // importHeaders spawns a new goroutine to run a header insertion into the chain. // If the header's number is at the same height as the current import phase, it // updates the phase states accordingly. -func (f *BlockFetcher) importHeaders(peer string, header *types.Header) { +func (f *BlockFetcher) importHeaders(op *blockOrHeaderInject) { + peer := op.origin + header := op.header hash := header.Hash() log.Debug("Importing propagated header", "peer", peer, "number", header.Number, "hash", hash) @@ -761,6 +783,8 @@ func (f *BlockFetcher) importHeaders(peer string, header *types.Header) { parent := f.getHeader(header.ParentHash) if parent == nil { log.Debug("Unknown parent of propagated header", "peer", peer, "number", header.Number, "hash", hash, "parent", header.ParentHash) + time.Sleep(reQueueBlockTimeout) + f.requeue <- op return } // Validate the header and if something went wrong, drop the peer @@ -784,7 +808,9 @@ func (f *BlockFetcher) importHeaders(peer string, header *types.Header) { // importBlocks spawns a new goroutine to run a block insertion into the chain. If the // block's number is at the same height as the current import phase, it updates // the phase states accordingly. -func (f *BlockFetcher) importBlocks(peer string, block *types.Block) { +func (f *BlockFetcher) importBlocks(op *blockOrHeaderInject) { + peer := op.origin + block := op.block hash := block.Hash() // Run the import on a new thread @@ -796,6 +822,8 @@ func (f *BlockFetcher) importBlocks(peer string, block *types.Block) { parent := f.getBlock(block.ParentHash()) if parent == nil { log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash()) + time.Sleep(reQueueBlockTimeout) + f.requeue <- op return } // Quickly validate the header and propagate the block if it passes From 69ce7f1e5ee20f04e6571243bcffc1d68a8eda2d Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Thu, 29 Jul 2021 18:53:24 +0800 Subject: [PATCH 009/117] prepare release 1.1.1-beta (#334) --- CHANGELOG.md | 5 +++++ params/version.go | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0263d13b8c..a0c9a2ac52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # Changelog +## v1.1.1-beta +*[\#333](https://github.com/binance-chain/bsc/pull/333) improve block fetcher efficiency +*[\#326](https://github.com/binance-chain/bsc/pull/326) eth/tracers: improve tracing performance +*[\#257](https://github.com/binance-chain/bsc/pull/257) performance improvement in many aspects + ## v1.1.0 *[\#282](https://github.com/binance-chain/bsc/pull/282) update discord link diff --git a/params/version.go b/params/version.go index 653e7cf3d6..92536b8bd7 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 = 1 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release - VersionMeta = "" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 1 // Minor version component of the current release + VersionPatch = 1 // Patch version component of the current release + VersionMeta = "beta" // Version metadata to append to the version string ) // Version holds the textual version string. From 3bd4e2995412a326bba13bba4c0d1b0a50403382 Mon Sep 17 00:00:00 2001 From: barryz Date: Mon, 9 Aug 2021 13:48:43 +0800 Subject: [PATCH 010/117] fix: TriesInmemory specified but not work (#350) * fix: TriesInmemory specified but not work * change warning log when TriesInMemory isn't default --- cmd/utils/flags.go | 6 ++++++ core/blockchain.go | 3 +++ 2 files changed, 9 insertions(+) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 8197b8ceab..b4d93fc1f1 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1598,6 +1598,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 } + if ctx.GlobalIsSet(TriesInMemoryFlag.Name) { + cfg.TriesInMemory = ctx.GlobalUint64(TriesInMemoryFlag.Name) + } if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) { cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100 } @@ -1924,6 +1927,9 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 } + if ctx.GlobalIsSet(TriesInMemoryFlag.Name) { + cache.TriesInMemory = ctx.GlobalUint64(TriesInMemoryFlag.Name) + } vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} // TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only. diff --git a/core/blockchain.go b/core/blockchain.go index 3cc44fc4e5..7a1bd5088b 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -217,6 +217,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par if cacheConfig == nil { cacheConfig = defaultCacheConfig } + if cacheConfig.TriesInMemory != 128 { + log.Warn("TriesInMemory isn't the default value(128), you need specify exact same TriesInMemory when prune data", "triesInMemory", cacheConfig.TriesInMemory) + } bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) receiptsCache, _ := lru.New(receiptsCacheLimit) From 955c78bde05c756fe30a9e6ecf8bed5091d9f62e Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Tue, 10 Aug 2021 10:33:00 +0800 Subject: [PATCH 011/117] [R4R] the miner module should propose block on a proper fork (#355) * change Canon chain condition * resolve comment --- consensus/consensus.go | 1 + consensus/parlia/parlia.go | 28 ++++++++++++++++++++++++++++ core/blockchain.go | 4 +++- miner/worker.go | 11 +++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/consensus/consensus.go b/consensus/consensus.go index 69a5f2f2ef..fc161390f9 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -140,4 +140,5 @@ type PoSA interface { IsSystemTransaction(tx *types.Transaction, header *types.Header) (bool, error) IsSystemContract(to *common.Address) bool EnoughDistance(chain ChainReader, header *types.Header) bool + IsLocalBlock(header *types.Header) bool } diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 62d109848f..14304fe2bc 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -882,6 +882,34 @@ func (p *Parlia) EnoughDistance(chain consensus.ChainReader, header *types.Heade return snap.enoughDistance(p.val, header) } +func (p *Parlia) IsLocalBlock(header *types.Header) bool { + return p.val == header.Coinbase +} + +func (p *Parlia) SignRecently(chain consensus.ChainReader, parent *types.Header) (bool, error) { + snap, err := p.snapshot(chain, parent.Number.Uint64(), parent.ParentHash, nil) + if err != nil { + return true, err + } + + // Bail out if we're unauthorized to sign a block + if _, authorized := snap.Validators[p.val]; !authorized { + return true, errUnauthorizedValidator + } + + // If we're amongst the recent signers, wait for the next block + number := parent.Number.Uint64() + 1 + for seen, recent := range snap.Recents { + if recent == p.val { + // Signer is among recents, only wait if the current block doesn't shift it out + if limit := uint64(len(snap.Validators)/2 + 1); number < limit || seen > number-limit { + return true, nil + } + } + } + return false, nil +} + // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty // that a new block should have based on the previous blocks in the chain and the // current signer. diff --git a/core/blockchain.go b/core/blockchain.go index 7a1bd5088b..be0b0f04ae 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1581,7 +1581,9 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. if !reorg && externTd.Cmp(localTd) == 0 { // Split same-difficulty blocks by number, then preferentially select // the block generated by the local miner as the canonical block. - if block.NumberU64() < currentBlock.NumberU64() { + if block.NumberU64() < currentBlock.NumberU64() || block.Time() < currentBlock.Time() { + reorg = true + } else if p, ok := bc.engine.(consensus.PoSA); ok && p.IsLocalBlock(currentBlock.Header()) { reorg = true } else if block.NumberU64() == currentBlock.NumberU64() { var currentPreserve, blockPreserve bool diff --git a/miner/worker.go b/miner/worker.go index b93b8752af..984af7baaf 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -389,6 +389,17 @@ func (w *worker) newWorkLoop(recommit time.Duration) { } clearPending(head.Block.NumberU64()) timestamp = time.Now().Unix() + if p, ok := w.engine.(*parlia.Parlia); ok { + signedRecent, err := p.SignRecently(w.chain, head.Block.Header()) + if err != nil { + log.Info("Not allowed to propose block", "err", err) + continue + } + if signedRecent { + log.Info("Signed recently, must wait") + continue + } + } commit(true, commitInterruptNewHead) case <-timer.C: From 6fcce0dce95fa917c7fb3887abfbf1945d1526aa Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Tue, 10 Aug 2021 12:03:15 +0800 Subject: [PATCH 012/117] fix pending block null issue (#358) --- miner/miner.go | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index 8c9d249f6c..efae1abd70 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -184,19 +184,21 @@ func (miner *Miner) SetRecommitInterval(interval time.Duration) { // Pending returns the currently pending block and associated state. func (miner *Miner) Pending() (*types.Block, *state.StateDB) { if miner.worker.isRunning() { - return miner.worker.pending() - } else { - // fallback to latest block - block := miner.worker.chain.CurrentBlock() - if block == nil { - return nil, nil + pendingBlock, pendingState := miner.worker.pending() + if pendingState != nil && pendingBlock != nil { + return pendingBlock, pendingState } - stateDb, err := miner.worker.chain.StateAt(block.Root()) - if err != nil { - return nil, nil - } - return block, stateDb } + // fallback to latest block + block := miner.worker.chain.CurrentBlock() + if block == nil { + return nil, nil + } + stateDb, err := miner.worker.chain.StateAt(block.Root()) + if err != nil { + return nil, nil + } + return block, stateDb } // PendingBlock returns the currently pending block. @@ -206,11 +208,13 @@ func (miner *Miner) Pending() (*types.Block, *state.StateDB) { // change between multiple method calls func (miner *Miner) PendingBlock() *types.Block { if miner.worker.isRunning() { - return miner.worker.pendingBlock() - } else { - // fallback to latest block - return miner.worker.chain.CurrentBlock() + pendingBlock := miner.worker.pendingBlock() + if pendingBlock != nil { + return pendingBlock + } } + // fallback to latest block + return miner.worker.chain.CurrentBlock() } func (miner *Miner) SetEtherbase(addr common.Address) { From 29707b92520fa63fae374481af790648cd119f3b Mon Sep 17 00:00:00 2001 From: fudongbai <296179868@qq.com> Date: Tue, 10 Aug 2021 15:19:32 +0800 Subject: [PATCH 013/117] fix syc failed on windows when prune --- core/state/pruner/bloom.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/pruner/bloom.go b/core/state/pruner/bloom.go index 4aeeb176e8..1f7a68d690 100644 --- a/core/state/pruner/bloom.go +++ b/core/state/pruner/bloom.go @@ -90,7 +90,7 @@ func (bloom *stateBloom) Commit(filename, tempname string) error { return err } // Ensure the file is synced to disk - f, err := os.Open(tempname) + f, err := os.OpenFile(tempname, os.O_RDWR, 0644) if err != nil { return err } From 504424dc7c17414b1a1473901a033ef5d1656320 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Fri, 13 Aug 2021 10:18:17 +0800 Subject: [PATCH 014/117] fix doube close channel of subfetcher (#366) --- core/state/trie_prefetcher.go | 38 ++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index c8667deae3..116302001d 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -25,6 +25,8 @@ import ( "github.com/ethereum/go-ethereum/metrics" ) +const abortChanSize = 64 + var ( // triePrefetchMetricsPrefix is the prefix under which to publis the metrics. triePrefetchMetricsPrefix = "trie/prefetch/" @@ -41,6 +43,9 @@ type triePrefetcher struct { fetches map[common.Hash]Trie // Partially or fully fetcher tries fetchers map[common.Hash]*subfetcher // Subfetchers for each trie + abortChan chan *subfetcher + closeChan chan struct{} + deliveryMissMeter metrics.Meter accountLoadMeter metrics.Meter accountDupMeter metrics.Meter @@ -56,9 +61,11 @@ type triePrefetcher struct { 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 + db: db, + root: root, + fetchers: make(map[common.Hash]*subfetcher), // Active prefetchers use the fetchers map + abortChan: make(chan *subfetcher, abortChanSize), + closeChan: make(chan struct{}), deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil), accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil), @@ -70,14 +77,34 @@ func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePre storageSkipMeter: metrics.GetOrRegisterMeter(prefix+"/storage/skip", nil), storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil), } + go p.abortLoop() return p } +func (p *triePrefetcher) abortLoop() { + for { + select { + case fetcher := <-p.abortChan: + fetcher.abort() + case <-p.closeChan: + // drain fetcher channel + for { + select { + case fetcher := <-p.abortChan: + fetcher.abort() + default: + return + } + } + } + } +} + // close iterates over all the subfetchers, aborts any that were left spinning // and reports the stats to the metrics subsystem. func (p *triePrefetcher) close() { for _, fetcher := range p.fetchers { - fetcher.abort() // safe to do multiple times + p.abortChan <- fetcher // safe to do multiple times if metrics.Enabled { if fetcher.root == p.root { @@ -101,6 +128,7 @@ func (p *triePrefetcher) close() { } } } + close(p.closeChan) // Clear out all fetchers (will crash on a second call, deliberate) p.fetchers = nil } @@ -174,7 +202,7 @@ func (p *triePrefetcher) trie(root common.Hash) Trie { } // Interrupt the prefetcher if it's by any chance still running and return // a copy of any pre-loaded trie. - fetcher.abort() // safe to do multiple times + p.abortChan <- fetcher // safe to do multiple times trie := fetcher.peek() if trie == nil { From a3320d6f6ef43a6a3d8658f5a3f05a58a29e467d Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Fri, 13 Aug 2021 10:20:35 +0800 Subject: [PATCH 015/117] prepare release v1.1.1 (#362) --- CHANGELOG.md | 9 +++++++++ params/version.go | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0c9a2ac52..3a634813be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ # Changelog +## v1.1.1 +https://github.com/binance-chain/bsc/pull/350 +*[\#350](https://github.com/binance-chain/bsc/pull/350) flag: fix TriesInmemory specified but not work +*[\#355](https://github.com/binance-chain/bsc/pull/355) miner should propose block on a proper fork +*[\#358](https://github.com/binance-chain/bsc/pull/358) miner: fix null pending block +*[\#360](https://github.com/binance-chain/bsc/pull/360) pruner: fix state bloom sync permission in Windows +*[\#366](https://github.com/binance-chain/bsc/pull/366) fix double close channel of subfetcher git reba + + ## v1.1.1-beta *[\#333](https://github.com/binance-chain/bsc/pull/333) improve block fetcher efficiency *[\#326](https://github.com/binance-chain/bsc/pull/326) eth/tracers: improve tracing performance diff --git a/params/version.go b/params/version.go index 92536b8bd7..0dd14e8854 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 = 1 // Minor version component of the current release - VersionPatch = 1 // Patch version component of the current release - VersionMeta = "beta" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 1 // Minor version component of the current release + VersionPatch = 1 // Patch version component of the current release + VersionMeta = "" // Version metadata to append to the version string ) // Version holds the textual version string. From 03f7b318d9e19d0477bf3ffe6d6f85a681048dae Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Fri, 13 Aug 2021 10:37:58 +0800 Subject: [PATCH 016/117] format changelog (#367) --- CHANGELOG.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a634813be..9ed0d51579 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,26 +1,29 @@ # Changelog + ## v1.1.1 -https://github.com/binance-chain/bsc/pull/350 -*[\#350](https://github.com/binance-chain/bsc/pull/350) flag: fix TriesInmemory specified but not work -*[\#355](https://github.com/binance-chain/bsc/pull/355) miner should propose block on a proper fork -*[\#358](https://github.com/binance-chain/bsc/pull/358) miner: fix null pending block -*[\#360](https://github.com/binance-chain/bsc/pull/360) pruner: fix state bloom sync permission in Windows -*[\#366](https://github.com/binance-chain/bsc/pull/366) fix double close channel of subfetcher git reba +IMPROVEMENT +* [\#355](https://github.com/binance-chain/bsc/pull/355) miner should propose block on a proper fork + +BUGFIX +* [\#350](https://github.com/binance-chain/bsc/pull/350) flag: fix TriesInmemory specified but not work +* [\#358](https://github.com/binance-chain/bsc/pull/358) miner: fix null pending block +* [\#360](https://github.com/binance-chain/bsc/pull/360) pruner: fix state bloom sync permission in Windows +* [\#366](https://github.com/binance-chain/bsc/pull/366) fix double close channel of subfetcher ## v1.1.1-beta -*[\#333](https://github.com/binance-chain/bsc/pull/333) improve block fetcher efficiency -*[\#326](https://github.com/binance-chain/bsc/pull/326) eth/tracers: improve tracing performance -*[\#257](https://github.com/binance-chain/bsc/pull/257) performance improvement in many aspects +* [\#333](https://github.com/binance-chain/bsc/pull/333) improve block fetcher efficiency +* [\#326](https://github.com/binance-chain/bsc/pull/326) eth/tracers: improve tracing performance +* [\#257](https://github.com/binance-chain/bsc/pull/257) performance improvement in many aspects ## v1.1.0 -*[\#282](https://github.com/binance-chain/bsc/pull/282) update discord link -*[\#280](https://github.com/binance-chain/bsc/pull/280) update discord link -*[\#227](https://github.com/binance-chain/bsc/pull/227) use more aggressive write cache policy +* [\#282](https://github.com/binance-chain/bsc/pull/282) update discord link +* [\#280](https://github.com/binance-chain/bsc/pull/280) update discord link +* [\#227](https://github.com/binance-chain/bsc/pull/227) use more aggressive write cache policy ## v1.1.0-beta -*[\#152](https://github.com/binance-chain/bsc/pull/152) upgrade to go-ethereum 1.10.3 +* [\#152](https://github.com/binance-chain/bsc/pull/152) upgrade to go-ethereum 1.10.3 ## v1.0.7-hf.2 BUGFIX From 804c853537d70a7b37de891b34ea0b310146868e Mon Sep 17 00:00:00 2001 From: Alexandr <30272185+alexqrid@users.noreply.github.com> Date: Sun, 22 Aug 2021 13:55:04 +0300 Subject: [PATCH 017/117] fix: tracing system transactions failed due to wrong state (#374) * fixed wrong state creation which resulted in fail of tracing transaction * sorted package imports * added the check to `standardTraceBlockToFile` that resolves the #314 Co-authored-by: alexqrid <> --- eth/state_accessor.go | 10 ++++++++++ eth/tracers/api.go | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 84cfaf4d73..aaabd1d152 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -19,9 +19,11 @@ package eth import ( "errors" "fmt" + "math/big" "time" "github.com/ethereum/go-ethereum/common" + "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/types" @@ -170,6 +172,14 @@ 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{}) + if posa, ok := eth.Engine().(consensus.PoSA); ok && msg.From() == context.Coinbase && + posa.IsSystemContract(msg.To()) && msg.GasPrice().Cmp(big.NewInt(0)) == 0 { + balance := statedb.GetBalance(consensus.SystemAddress) + if balance.Cmp(common.Big0) > 0 { + statedb.SetBalance(consensus.SystemAddress, big.NewInt(0)) + statedb.AddBalance(context.Coinbase, balance) + } + } statedb.Prepare(tx.Hash(), block.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) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index eee27e9a0c..5f20858b2e 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -673,6 +673,15 @@ 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) + if posa, ok := api.backend.Engine().(consensus.PoSA); ok { + if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem { + balance := statedb.GetBalance(consensus.SystemAddress) + if balance.Cmp(common.Big0) > 0 { + statedb.SetBalance(consensus.SystemAddress, big.NewInt(0)) + statedb.AddBalance(vmctx.Coinbase, balance) + } + } + } statedb.Prepare(tx.Hash(), block.Hash(), i) _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) if writer != nil { From 57632c94e813ec8a2583dfec0b802cc2a352fa21 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 24 Aug 2021 09:00:10 +0200 Subject: [PATCH 018/117] core/vm: faster code analysis (#23381) * core/vm: more detailed benchmark for jumpdest analysis * core/vm: make jd analysis benchmark alloc free * core/vm: improve jumpdest analysis * core/vm: improve worst-case * core/vm: further improvements in analysis * core/vm: improve jumpdest analysis >PUSH15 * core/vm: make jd analysis ref by value * core/vm: fix misspell * core/vm: improve set8 and set16 a bit * core/vm: reduce amount of code * core/vm: optimize byte copying --- core/vm/analysis.go | 94 +++++++++++++++++++++++++++++++++------- core/vm/analysis_test.go | 24 +++++++++- core/vm/instructions.go | 4 ++ 3 files changed, 104 insertions(+), 18 deletions(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 0ccf47b979..449cded2a8 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -16,17 +16,49 @@ package vm +const ( + set2BitsMask = uint16(0b1100_0000_0000_0000) + set3BitsMask = uint16(0b1110_0000_0000_0000) + set4BitsMask = uint16(0b1111_0000_0000_0000) + set5BitsMask = uint16(0b1111_1000_0000_0000) + set6BitsMask = uint16(0b1111_1100_0000_0000) + set7BitsMask = uint16(0b1111_1110_0000_0000) +) + // bitvec is a bit vector which maps bytes in a program. // An unset bit means the byte is an opcode, a set bit means // it's data (i.e. argument of PUSHxx). type bitvec []byte -func (bits *bitvec) set(pos uint64) { - (*bits)[pos/8] |= 0x80 >> (pos % 8) +var lookup = [8]byte{ + 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1, +} + +func (bits bitvec) set1(pos uint64) { + bits[pos/8] |= lookup[pos%8] +} + +func (bits bitvec) setN(flag uint16, pos uint64) { + a := flag >> (pos % 8) + bits[pos/8] |= byte(a >> 8) + if b := byte(a); b != 0 { + // If the bit-setting affects the neighbouring byte, we can assign - no need to OR it, + // since it's the first write to that byte + bits[pos/8+1] = b + } +} + +func (bits bitvec) set8(pos uint64) { + a := byte(0xFF >> (pos % 8)) + bits[pos/8] |= a + bits[pos/8+1] = ^a } -func (bits *bitvec) set8(pos uint64) { - (*bits)[pos/8] |= 0xFF >> (pos % 8) - (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) + +func (bits bitvec) set16(pos uint64) { + a := byte(0xFF >> (pos % 8)) + bits[pos/8] |= a + bits[pos/8+1] = 0xFF + bits[pos/8+2] = ^a } // codeSegment checks if the position is in a code segment. @@ -40,22 +72,52 @@ func codeBitmap(code []byte) bitvec { // ends with a PUSH32, the algorithm will push zeroes onto the // bitvector outside the bounds of the actual code. bits := make(bitvec, len(code)/8+1+4) + return codeBitmapInternal(code, bits) +} + +// codeBitmapInternal is the internal implementation of codeBitmap. +// It exists for the purpose of being able to run benchmark tests +// without dynamic allocations affecting the results. +func codeBitmapInternal(code, bits bitvec) bitvec { for pc := uint64(0); pc < uint64(len(code)); { op := OpCode(code[pc]) - - if op >= PUSH1 && op <= PUSH32 { - numbits := op - PUSH1 + 1 - pc++ + pc++ + if op < PUSH1 || op > PUSH32 { + continue + } + numbits := op - PUSH1 + 1 + if numbits >= 8 { + for ; numbits >= 16; numbits -= 16 { + bits.set16(pc) + pc += 16 + } for ; numbits >= 8; numbits -= 8 { - bits.set8(pc) // 8 + bits.set8(pc) pc += 8 } - for ; numbits > 0; numbits-- { - bits.set(pc) - pc++ - } - } else { - pc++ + } + switch numbits { + case 1: + bits.set1(pc) + pc += 1 + case 2: + bits.setN(set2BitsMask, pc) + pc += 2 + case 3: + bits.setN(set3BitsMask, pc) + pc += 3 + case 4: + bits.setN(set4BitsMask, pc) + pc += 4 + case 5: + bits.setN(set5BitsMask, pc) + pc += 5 + case 6: + bits.setN(set6BitsMask, pc) + pc += 6 + case 7: + bits.setN(set7BitsMask, pc) + pc += 7 } } return bits diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index fd2d744d87..585bb3097f 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -47,10 +47,10 @@ func TestJumpDestAnalysis(t *testing.T) { {[]byte{byte(PUSH32)}, 0xFF, 1}, {[]byte{byte(PUSH32)}, 0xFF, 2}, } - for _, test := range tests { + for i, test := range tests { ret := codeBitmap(test.code) if ret[test.which] != test.exp { - t.Fatalf("expected %x, got %02x", test.exp, ret[test.which]) + t.Fatalf("test %d: expected %x, got %02x", i, test.exp, ret[test.which]) } } } @@ -73,3 +73,23 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) { } bench.StopTimer() } + +func BenchmarkJumpdestOpAnalysis(bench *testing.B) { + var op OpCode + bencher := func(b *testing.B) { + code := make([]byte, 32*b.N) + for i := range code { + code[i] = byte(op) + } + bits := make(bitvec, len(code)/8+1+4) + b.ResetTimer() + codeBitmapInternal(code, bits) + } + for op = PUSH1; op <= PUSH32; op++ { + bench.Run(op.String(), bencher) + } + op = JUMPDEST + bench.Run(op.String(), bencher) + op = STOP + bench.Run(op.String(), bencher) +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 3277674ee8..f0eac1cc34 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -669,6 +669,7 @@ 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 @@ -703,6 +704,7 @@ 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 @@ -730,6 +732,7 @@ 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 @@ -757,6 +760,7 @@ 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 c4f931212903b3ee8495c36ac374340aec4ac269 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Wed, 25 Aug 2021 10:13:43 +0800 Subject: [PATCH 019/117] prepare for release 1.1.2 (#381) --- CHANGELOG.md | 4 ++++ params/version.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ed0d51579..e2eb20ff22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +## v1.1.2 +Security +* [\#379](https://github.com/binance-chain/bsc/pull/379) A pre-announced hotfix release to patch a vulnerability in the EVM (CVE-2021-39137). + ## v1.1.1 IMPROVEMENT diff --git a/params/version.go b/params/version.go index 0dd14e8854..c3d0ab20ee 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 1 // Patch version component of the current release + VersionPatch = 2 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From 55775d9aee1fa75a910545dd8ef2f1579c9e1471 Mon Sep 17 00:00:00 2001 From: j75689 Date: Tue, 31 Aug 2021 00:05:03 +0800 Subject: [PATCH 020/117] ci pipeline for release page --- .github/generate_change_log.sh | 41 ++++++++ .github/release.env | 2 + .github/workflows/release.yml | 176 +++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100755 .github/generate_change_log.sh create mode 100644 .github/release.env create mode 100644 .github/workflows/release.yml diff --git a/.github/generate_change_log.sh b/.github/generate_change_log.sh new file mode 100755 index 0000000000..09332b7911 --- /dev/null +++ b/.github/generate_change_log.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +checksum() { + echo $(sha256sum $@ | awk '{print $1}') +} +change_log_file="./CHANGELOG.md" +version="## $@" +version_prefix="## v" +start=0 +CHANGE_LOG="" +while read line; do + if [[ $line == *"$version"* ]]; then + start=1 + continue + fi + if [[ $line == *"$version_prefix"* ]] && [ $start == 1 ]; then + break; + fi + if [ $start == 1 ] && [[ $line != "" ]]; then + CHANGE_LOG+="$line\n" + fi +done < ${change_log_file} +MAINNET_ZIP_SUM="$(checksum ./mainnet.zip)" +TESTNET_ZIP_SUM="$(checksum ./testnet.zip)" +LINUX_BIN_SUM="$(checksum ./linux/geth)" +MAC_BIN_SUM="$(checksum ./macos/geth)" +WINDOWS_BIN_SUM="$(checksum ./windows/geth.exe)" +OUTPUT=$(cat <<-END +## Changelog\n +${CHANGE_LOG}\n +## Assets\n +| Assets | Sha256 Checksum |\n +| :-----------: |------------|\n +| mainnet.zip | ${MAINNET_ZIP_SUM} |\n +| testnet.zip | ${TESTNET_ZIP_SUM} |\n +| geth_linux | ${LINUX_BIN_SUM} |\n +| geth_mac | ${MAC_BIN_SUM} |\n +| geth_windows | ${WINDOWS_BIN_SUM} |\n +END +) + +echo -e ${OUTPUT} diff --git a/.github/release.env b/.github/release.env new file mode 100644 index 0000000000..c65f709a26 --- /dev/null +++ b/.github/release.env @@ -0,0 +1,2 @@ +MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.2/mainnet.zip" +TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.2/testnet.zip" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..66e73dbc5b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,176 @@ +name: Release + +on: + push: + # Publish `v1.2.3` tags as releases. + tags: + - v* + +jobs: + build: + name: Build Release + strategy: + matrix: + go-version: [1.16.x] + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - name: Checkout Code + uses: actions/checkout@v2 + + # ============================== + # Linux/Macos/Windows Build + # ============================== + + - name: Build Binary for ${{matrix.os}} + run: make geth + + # ============================== + # Upload artifacts + # ============================== + + - name: Upload Linux Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-latest' + with: + name: linux + path: ./build/bin/geth + + - name: Upload MacOS Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'macos-latest' + with: + name: macos + path: ./build/bin/geth + + - name: Upload Windows Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'windows-latest' + with: + name: windows + path: ./build/bin/geth.exe + + release: + name: Release + needs: build + runs-on: ubuntu-latest + steps: + - name: Set Env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + + - name: Checkout Code + uses: actions/checkout@v2 + + # ============================== + # Download artifacts + # ============================== + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: linux + path: ./linux + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: macos + path: ./macos + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: windows + path: ./windows + + - name: Download Config File + run: | + . ./.github/release.env + echo "mainnet.zip url: $MAINNET_FILE_URL" + echo "testnet.zip url: $TESTNET_FILE_URL" + curl -L $MAINNET_FILE_URL -o ./mainnet.zip + curl -L $TESTNET_FILE_URL -o ./testnet.zip + + # ============================== + # Create release + # ============================== + - name: Generate Change Log + id: changelog + run: | + chmod 755 ./.github/generate_change_log.sh + CHANGELOG=$(./.github/generate_change_log.sh ${{ env.RELEASE_VERSION}}) + + echo "CHANGELOG<> $GITHUB_ENV + echo "$CHANGELOG" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Create Release + id: create_release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + body: | + ${{ env.CHANGELOG }} + draft: false + prerelease: false + + # Check downloaded files + - run: ls + + - name: Upload Release Asset - Linux + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./linux/geth + asset_name: geth_linux + asset_content_type: application/octet-stream + + - name: Upload Release Asset - MacOS + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./macos/geth + asset_name: geth_mac + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Windows + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./windows/geth.exe + asset_name: geth_windows.exe + asset_content_type: application/octet-stream + + - name: Upload Release Asset - MAINNET.ZIP + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./mainnet.zip + asset_name: mainnet.zip + asset_content_type: application/zip + + - name: Upload Release Asset - TESTNET.ZIP + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./testnet.zip + asset_name: testnet.zip + asset_content_type: application/zip From 6e960cc85018cdc3721b666c5e714fc740920e4d Mon Sep 17 00:00:00 2001 From: j75689 Date: Tue, 31 Aug 2021 16:59:46 +0800 Subject: [PATCH 021/117] Revert "fix potential deadlock of pub/sub module" This reverts commit 3d3f9694a426eafc32640a643b5399a58209da1c. --- eth/filters/api.go | 9 ++++++--- eth/filters/filter_system.go | 11 ----------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index 91477a9170..ef360dd70f 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -117,16 +117,19 @@ func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID { pendingTxs = make(chan []common.Hash) pendingTxSub = api.events.SubscribePendingTxs(pendingTxs) ) - f := &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(api.timeout), hashes: make([]common.Hash, 0), s: pendingTxSub} api.filtersMu.Lock() - api.filters[pendingTxSub.ID] = f + api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(api.timeout), hashes: make([]common.Hash, 0), s: pendingTxSub} api.filtersMu.Unlock() gopool.Submit(func() { for { select { case ph := <-pendingTxs: - f.hashes = append(f.hashes, ph...) + api.filtersMu.Lock() + if f, found := api.filters[pendingTxSub.ID]; found { + f.hashes = append(f.hashes, ph...) + } + api.filtersMu.Unlock() case <-pendingTxSub.Err(): api.filtersMu.Lock() delete(api.filters, pendingTxSub.ID) diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 4be7ceb449..12f037d0f9 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -174,17 +174,6 @@ func (sub *Subscription) Unsubscribe() { // this ensures that the manager won't use the event channel which // will probably be closed by the client asap after this method returns. <-sub.Err() - - drainLoop: - for { - select { - case <-sub.f.logs: - case <-sub.f.hashes: - case <-sub.f.headers: - default: - break drainLoop - } - } }) } From 1540ad932d556211a0321b8120255d8758f47d17 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Mon, 6 Sep 2021 10:37:16 +0800 Subject: [PATCH 022/117] fix nil point in downloader (#409) --- eth/downloader/downloader.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 6f59b29a5e..3dee90c424 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -985,6 +985,10 @@ func (d *Downloader) findAncestorBinarySearch(p *peerConnection, mode SyncMode, break } header := d.lightchain.GetHeaderByHash(h) // Independent of sync mode, header surely exists + if header == nil { + p.log.Error("header not found", "number", header.Number, "hash", header.Hash(), "request", check) + return 0, fmt.Errorf("%w: header no found (%d)", errBadPeer, header.Number) + } if header.Number.Uint64() != check { p.log.Warn("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check) return 0, fmt.Errorf("%w: non-requested header (%d)", errBadPeer, header.Number) From bca96785476e66816bca30eb8050cd3e527efeba Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Mon, 6 Sep 2021 12:22:21 +0900 Subject: [PATCH 023/117] core/state/snapshot: fix typo (#408) strorage -> storage --- core/state/snapshot/iterator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/snapshot/iterator.go b/core/state/snapshot/iterator.go index 1d9340bbad..c1a196c7ff 100644 --- a/core/state/snapshot/iterator.go +++ b/core/state/snapshot/iterator.go @@ -385,7 +385,7 @@ func (it *diskStorageIterator) Hash() common.Hash { return common.BytesToHash(it.it.Key()) // The prefix will be truncated } -// Slot returns the raw strorage slot content the iterator is currently at. +// Slot returns the raw storage slot content the iterator is currently at. func (it *diskStorageIterator) Slot() []byte { return it.it.Value() } From 88ba737a46163330cfce1fa0072227ffc6450b13 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Thu, 23 Sep 2021 16:05:09 +0800 Subject: [PATCH 024/117] add block proccess backoff time when validator is not in turn --- consensus/consensus.go | 3 +++ consensus/parlia/parlia.go | 22 ++++++++++++++++++++++ core/blockchain.go | 28 +++++++++++++++++++++++++--- core/chain_makers.go | 1 + core/headerchain.go | 7 ++++++- light/lightchain.go | 7 ++++++- 6 files changed, 63 insertions(+), 5 deletions(-) diff --git a/consensus/consensus.go b/consensus/consensus.go index fc161390f9..a9e79359f9 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -49,6 +49,9 @@ type ChainHeaderReader interface { // GetHeaderByHash retrieves a block header from the database by its hash. GetHeaderByHash(hash common.Hash) *types.Header + + // GetHighestVerifiedHeader retrieves the highest header verified. + GetHighestVerifiedHeader() *types.Header } // ChainReader defines a small collection of methods needed to access the local diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 14304fe2bc..004f872716 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -56,6 +56,7 @@ const ( validatorBytesLength = common.AddressLength wiggleTime = uint64(1) // second, Random delay (per signer) to allow concurrent signers initialBackOffTime = uint64(1) // second + processBackOffTime = uint64(1) // second systemRewardPercent = 4 // it means 1/2^4 = 1/16 percentage of gas fee incoming will be distributed to system @@ -863,6 +864,14 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res return case <-time.After(delay): } + if p.shouldWaitForCurrentBlockProcess(chain, header, snap) { + log.Info("not in turn and received current block, wait for current block process") + select { + case <-stop: + return + case <-time.After(time.Duration(processBackOffTime) * time.Second): + } + } select { case results <- block.WithSeal(header): @@ -874,6 +883,19 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res return nil } +func (p *Parlia) shouldWaitForCurrentBlockProcess(chain consensus.ChainHeaderReader, header *types.Header, snap *Snapshot) bool { + highestVerifiedHeader := chain.GetHighestVerifiedHeader() + if highestVerifiedHeader == nil || highestVerifiedHeader.Number == nil { + return false + } + + if !snap.inturn(p.val) && header.Number.Cmp(highestVerifiedHeader.Number) == 0 { + return true + } + + return false +} + func (p *Parlia) EnoughDistance(chain consensus.ChainReader, header *types.Header) bool { snap, err := p.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil) if err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index be0b0f04ae..d4ebbbfcbc 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -28,6 +28,8 @@ import ( "sync/atomic" "time" + lru "github.com/hashicorp/golang-lru" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" @@ -44,7 +46,6 @@ import ( "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 ( @@ -185,8 +186,9 @@ type BlockChain struct { chainmu sync.RWMutex // blockchain insertion lock - 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!) + 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!) + highestVerifiedHeader atomic.Value stateCache state.Database // State database to reuse between imports (contains state cache) bodyCache *lru.Cache // Cache for the most recent block bodies @@ -266,6 +268,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par bc.currentBlock.Store(nilBlock) bc.currentFastBlock.Store(nilBlock) + var nilHeader *types.Header + bc.highestVerifiedHeader.Store(nilHeader) + // Initialize the chain with ancient data if it isn't empty. var txIndexBlock uint64 @@ -1883,6 +1888,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er if err != nil { return it.index, err } + bc.updateHighestVerifiedHeader(block.Header()) + // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") activeState = statedb @@ -1989,6 +1996,21 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er return it.index, err } +func (bc *BlockChain) updateHighestVerifiedHeader(header *types.Header) { + if header == nil || header.Number == nil { + return + } + currentHeader := bc.highestVerifiedHeader.Load().(*types.Header) + if currentHeader == nil || currentHeader.Number == nil || currentHeader.Number.Cmp(header.Number) < 0 { + bc.highestVerifiedHeader.Store(types.CopyHeader(header)) + return + } +} + +func (bc *BlockChain) GetHighestVerifiedHeader() *types.Header { + return bc.highestVerifiedHeader.Load().(*types.Header) +} + // insertSideChain is called when an import batch hits upon a pruned ancestor // error, which happens when a sidechain with a sufficiently old fork-block is // found. diff --git a/core/chain_makers.go b/core/chain_makers.go index 6cb74d51be..7f62e41ad8 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -303,3 +303,4 @@ func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header { return nil } func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil } func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil } +func (cr *fakeChainReader) GetHighestVerifiedHeader() *types.Header { return nil } diff --git a/core/headerchain.go b/core/headerchain.go index 1dbf958786..fe4770a469 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -26,6 +26,8 @@ import ( "sync/atomic" "time" + lru "github.com/hashicorp/golang-lru" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/rawdb" @@ -33,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - lru "github.com/hashicorp/golang-lru" ) const ( @@ -413,6 +414,10 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co return chain } +func (hc *HeaderChain) GetHighestVerifiedHeader() *types.Header { + return nil +} + // GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or // a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the // number of blocks to be individually checked before we reach the canonical chain. diff --git a/light/lightchain.go b/light/lightchain.go index ca6fbfac49..99644355ac 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -26,6 +26,8 @@ import ( "sync/atomic" "time" + lru "github.com/hashicorp/golang-lru" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" @@ -37,7 +39,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 ( @@ -148,6 +149,10 @@ func (lc *LightChain) HeaderChain() *core.HeaderChain { return lc.hc } +func (lc *LightChain) GetHighestVerifiedHeader() *types.Header { + return nil +} + // loadLastState loads the last known chain state from the database. This method // assumes that the chain manager mutex is held. func (lc *LightChain) loadLastState() error { From e0e58b23451eee6b0c8c29d6353ee641c2858e0c Mon Sep 17 00:00:00 2001 From: yutianwu Date: Thu, 23 Sep 2021 19:12:34 +0800 Subject: [PATCH 025/117] update comment --- consensus/parlia/parlia.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 004f872716..267be62889 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -865,7 +865,7 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res case <-time.After(delay): } if p.shouldWaitForCurrentBlockProcess(chain, header, snap) { - log.Info("not in turn and received current block, wait for current block process") + log.Info("Waiting for received in turn block to process") select { case <-stop: return From 4a84cfdf625976856138cd0635d2c223ab785a11 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Fri, 24 Sep 2021 14:29:16 +0800 Subject: [PATCH 026/117] add more log --- consensus/parlia/parlia.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 267be62889..789ca84ce6 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -868,8 +868,10 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res log.Info("Waiting for received in turn block to process") select { case <-stop: + log.Info("Received block process finished, abort block seal") return case <-time.After(time.Duration(processBackOffTime) * time.Second): + log.Info("Process backoff time exhausted, start to seal block") } } From 065e69e3205e3d66f4888221324b303564dde6b5 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Sun, 26 Sep 2021 18:23:45 +0800 Subject: [PATCH 027/117] fix comments --- consensus/parlia/parlia.go | 9 ++++++--- core/blockchain.go | 10 +++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 789ca84ce6..3f76082010 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -886,15 +886,18 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res } func (p *Parlia) shouldWaitForCurrentBlockProcess(chain consensus.ChainHeaderReader, header *types.Header, snap *Snapshot) bool { + if snap.inturn(p.val) { + return false + } + highestVerifiedHeader := chain.GetHighestVerifiedHeader() - if highestVerifiedHeader == nil || highestVerifiedHeader.Number == nil { + if highestVerifiedHeader == nil { return false } - if !snap.inturn(p.val) && header.Number.Cmp(highestVerifiedHeader.Number) == 0 { + if header.ParentHash == highestVerifiedHeader.ParentHash && header.Difficulty.Cmp(highestVerifiedHeader.Difficulty) < 0 { return true } - return false } diff --git a/core/blockchain.go b/core/blockchain.go index d4ebbbfcbc..a09cc5ff62 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2001,7 +2001,15 @@ func (bc *BlockChain) updateHighestVerifiedHeader(header *types.Header) { return } currentHeader := bc.highestVerifiedHeader.Load().(*types.Header) - if currentHeader == nil || currentHeader.Number == nil || currentHeader.Number.Cmp(header.Number) < 0 { + if currentHeader == nil { + bc.highestVerifiedHeader.Store(types.CopyHeader(header)) + return + } + + newTD := big.NewInt(0).Add(bc.GetTdByHash(header.ParentHash), header.Difficulty) + oldTD := big.NewInt(0).Add(bc.GetTdByHash(currentHeader.ParentHash), currentHeader.Difficulty) + + if newTD.Cmp(oldTD) > 0 { bc.highestVerifiedHeader.Store(types.CopyHeader(header)) return } From 77f19d435dd6bef1ef7575428d3bac9625fa8e6e Mon Sep 17 00:00:00 2001 From: yutianwu Date: Sun, 26 Sep 2021 19:09:31 +0800 Subject: [PATCH 028/117] wait if td is the same --- consensus/parlia/parlia.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 3f76082010..68ade2e6ff 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -895,7 +895,7 @@ func (p *Parlia) shouldWaitForCurrentBlockProcess(chain consensus.ChainHeaderRea return false } - if header.ParentHash == highestVerifiedHeader.ParentHash && header.Difficulty.Cmp(highestVerifiedHeader.Difficulty) < 0 { + if header.ParentHash == highestVerifiedHeader.ParentHash && header.Difficulty.Cmp(highestVerifiedHeader.Difficulty) <= 0 { return true } return false From 7f9cdc4ae5832d58e833b34cc7d43c35c77fb962 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Mon, 27 Sep 2021 10:50:13 +0800 Subject: [PATCH 029/117] minor update --- consensus/parlia/parlia.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 68ade2e6ff..7cb352d1f2 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -886,7 +886,7 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res } func (p *Parlia) shouldWaitForCurrentBlockProcess(chain consensus.ChainHeaderReader, header *types.Header, snap *Snapshot) bool { - if snap.inturn(p.val) { + if header.Difficulty.Cmp(diffInTurn) == 0 { return false } @@ -895,7 +895,7 @@ func (p *Parlia) shouldWaitForCurrentBlockProcess(chain consensus.ChainHeaderRea return false } - if header.ParentHash == highestVerifiedHeader.ParentHash && header.Difficulty.Cmp(highestVerifiedHeader.Difficulty) <= 0 { + if header.ParentHash == highestVerifiedHeader.ParentHash { return true } return false From 1ded097733aa44537f2a18dd48c56451366b8e1b Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Tue, 28 Sep 2021 16:03:38 +0800 Subject: [PATCH 030/117] [R4R]implement diff sync (#376) * implement block process part of light sync * add difflayer protocol * handle difflayer and refine light processor * add testcase for diff protocol * make it faster * allow validator to light sync * change into diff sync * ligth sync: download difflayer (#2) * ligth sync: download difflayer Signed-off-by: kyrie-yl * download diff layer: fix according to the comments Signed-off-by: kyrie-yl * download diff layer: update Signed-off-by: kyrie-yl * download diff layer: fix accroding comments Signed-off-by: kyrie-yl Co-authored-by: kyrie-yl * update light sync to diff sync * raise the max diff limit * add switcher of snap protocol * fix test case * make commit concurrently * remove peer for diff cache when peer closed * consensus tuning * add test code * remove extra message * fix testcase and lint make diff block configable wait code write fix testcase resolve comments resolve comment * resolve comments * resolve comments * resolve comment * fix mistake Co-authored-by: kyrie-yl <83150977+kyrie-yl@users.noreply.github.com> Co-authored-by: kyrie-yl --- cmd/evm/internal/t8ntool/execution.go | 4 +- cmd/faucet/faucet.go | 2 +- cmd/geth/main.go | 4 + cmd/geth/usage.go | 1 + cmd/utils/flags.go | 41 ++- common/gopool/pool.go | 14 +- consensus/consensus.go | 1 + consensus/parlia/parlia.go | 16 + consensus/parlia/ramanujanfork.go | 2 +- consensus/parlia/snapshot.go | 2 +- core/block_validator.go | 3 - core/blockchain.go | 465 ++++++++++++++++++++++++-- core/blockchain_diff_test.go | 263 +++++++++++++++ core/blockchain_test.go | 6 +- core/chain_makers.go | 2 +- core/rawdb/accessors_chain.go | 38 +++ core/rawdb/database.go | 26 ++ core/rawdb/freezer_table_test.go | 60 +--- core/rawdb/schema.go | 8 + core/rawdb/table.go | 8 + core/state/database.go | 1 - core/state/journal.go | 2 +- core/state/snapshot/disklayer_test.go | 8 +- core/state/snapshot/iterator_test.go | 86 ++--- core/state/snapshot/snapshot.go | 33 +- core/state/snapshot/snapshot_test.go | 24 +- core/state/state_object.go | 13 +- core/state/state_test.go | 2 +- core/state/statedb.go | 309 +++++++++++++++-- core/state/statedb_test.go | 14 +- core/state/sync_test.go | 2 +- core/state_prefetcher.go | 9 - core/state_processor.go | 329 +++++++++++++++++- core/types.go | 2 +- core/types/block.go | 89 ++++- core/vm/contracts_lightclient_test.go | 2 +- core/vm/lightclient/types.go | 2 +- eth/backend.go | 18 +- eth/downloader/downloader.go | 56 +++- eth/downloader/downloader_test.go | 4 +- eth/ethconfig/config.go | 12 +- eth/ethconfig/gen_config.go | 18 + eth/fetcher/block_fetcher.go | 13 +- eth/fetcher/block_fetcher_test.go | 36 +- eth/handler.go | 41 ++- eth/handler_diff.go | 87 +++++ eth/handler_diff_test.go | 203 +++++++++++ eth/handler_eth.go | 13 +- eth/peer.go | 22 ++ eth/peerset.go | 87 ++++- eth/protocols/diff/discovery.go | 32 ++ eth/protocols/diff/handler.go | 180 ++++++++++ eth/protocols/diff/handler_test.go | 192 +++++++++++ eth/protocols/diff/handshake.go | 82 +++++ eth/protocols/diff/peer.go | 107 ++++++ eth/protocols/diff/peer_test.go | 61 ++++ eth/protocols/diff/protocol.go | 122 +++++++ eth/protocols/diff/protocol_test.go | 131 ++++++++ eth/protocols/diff/tracker.go | 161 +++++++++ eth/state_accessor.go | 4 +- eth/tracers/tracers_test.go | 2 +- ethclient/ethclient_test.go | 70 +--- ethdb/database.go | 6 + les/fetcher.go | 4 +- les/peer.go | 2 +- light/trie.go | 12 +- miner/worker.go | 19 -- node/config.go | 3 + node/node.go | 41 +++ rlp/typecache.go | 10 - tests/state_test_util.go | 2 +- 71 files changed, 3352 insertions(+), 394 deletions(-) create mode 100644 core/blockchain_diff_test.go create mode 100644 eth/handler_diff.go create mode 100644 eth/handler_diff_test.go create mode 100644 eth/protocols/diff/discovery.go create mode 100644 eth/protocols/diff/handler.go create mode 100644 eth/protocols/diff/handler_test.go create mode 100644 eth/protocols/diff/handshake.go create mode 100644 eth/protocols/diff/peer.go create mode 100644 eth/protocols/diff/peer_test.go create mode 100644 eth/protocols/diff/protocol.go create mode 100644 eth/protocols/diff/protocol_test.go create mode 100644 eth/protocols/diff/tracker.go diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index c3f1b16efc..0471037ed8 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -223,7 +223,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, statedb.AddBalance(pre.Env.Coinbase, minerReward) } // Commit block - root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) + root, _, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) if err != nil { fmt.Fprintf(os.Stderr, "Could not commit state: %v", err) return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) @@ -252,7 +252,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB } } // Commit and re-open to start with a clean state. - root, _ := statedb.Commit(false) + root, _, _ := statedb.Commit(false) statedb, _ = state.New(root, sdb, nil) return statedb } diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 5aab7598a1..500a1e920f 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -139,7 +139,7 @@ func main() { log.Crit("Length of bep2eContracts, bep2eSymbols, bep2eAmounts mismatch") } - bep2eInfos := make(map[string]bep2eInfo, 0) + bep2eInfos := make(map[string]bep2eInfo, len(symbols)) for idx, s := range symbols { n, ok := big.NewInt(0).SetString(bep2eNumAmounts[idx], 10) if !ok { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d383d99b7e..8be8d20bf4 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -65,6 +65,8 @@ var ( utils.ExternalSignerFlag, utils.NoUSBFlag, utils.DirectBroadcastFlag, + utils.DisableSnapProtocolFlag, + utils.DiffSyncFlag, utils.RangeLimitFlag, utils.USBFlag, utils.SmartCardDaemonPathFlag, @@ -114,6 +116,8 @@ var ( utils.CacheGCFlag, utils.CacheSnapshotFlag, utils.CachePreimagesFlag, + utils.PersistDiffFlag, + utils.DiffBlockFlag, utils.ListenPortFlag, utils.MaxPeersFlag, utils.MaxPendingPeersFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 1450c29e84..2a208c827b 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -40,6 +40,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.KeyStoreDirFlag, utils.NoUSBFlag, utils.DirectBroadcastFlag, + utils.DisableSnapProtocolFlag, utils.RangeLimitFlag, utils.SmartCardDaemonPathFlag, utils.NetworkIdFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b4d93fc1f1..c4dbd84911 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -117,6 +117,15 @@ var ( Name: "directbroadcast", Usage: "Enable directly broadcast mined block to all peers", } + DisableSnapProtocolFlag = cli.BoolFlag{ + Name: "disablesnapprotocol", + Usage: "Disable snap protocol", + } + DiffSyncFlag = cli.BoolFlag{ + Name: "diffsync", + Usage: "Enable diffy sync, Please note that enable diffsync will improve the syncing speed, " + + "but will degrade the security to light client level", + } RangeLimitFlag = cli.BoolFlag{ Name: "rangelimit", Usage: "Enable 5000 blocks limit for range query", @@ -125,6 +134,10 @@ var ( Name: "datadir.ancient", Usage: "Data directory for ancient chain segments (default = inside chaindata)", } + DiffFlag = DirectoryFlag{ + Name: "datadir.diff", + Usage: "Data directory for difflayer 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)", @@ -425,6 +438,15 @@ var ( Name: "cache.preimages", Usage: "Enable recording the SHA3/keccak preimages of trie keys", } + PersistDiffFlag = cli.BoolFlag{ + Name: "persistdiff", + Usage: "Enable persistence of the diff layer", + } + DiffBlockFlag = cli.Uint64Flag{ + Name: "diffblock", + Usage: "The number of blocks should be persisted in db (default = 864000 )", + Value: uint64(864000), + } // Miner settings MiningEnabledFlag = cli.BoolFlag{ Name: "mine", @@ -1271,6 +1293,9 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { if ctx.GlobalIsSet(DirectBroadcastFlag.Name) { cfg.DirectBroadcast = ctx.GlobalBool(DirectBroadcastFlag.Name) } + if ctx.GlobalIsSet(DisableSnapProtocolFlag.Name) { + cfg.DisableSnapProtocol = ctx.GlobalBool(DisableSnapProtocolFlag.Name) + } if ctx.GlobalIsSet(RangeLimitFlag.Name) { cfg.RangeLimit = ctx.GlobalBool(RangeLimitFlag.Name) } @@ -1564,7 +1589,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(AncientFlag.Name) { cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name) } - + if ctx.GlobalIsSet(DiffFlag.Name) { + cfg.DatabaseDiff = ctx.GlobalString(DiffFlag.Name) + } + if ctx.GlobalIsSet(PersistDiffFlag.Name) { + cfg.PersistDiff = ctx.GlobalBool(PersistDiffFlag.Name) + } + if ctx.GlobalIsSet(DiffBlockFlag.Name) { + cfg.DiffBlock = ctx.GlobalUint64(DiffBlockFlag.Name) + } if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } @@ -1574,6 +1607,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(DirectBroadcastFlag.Name) { cfg.DirectBroadcast = ctx.GlobalBool(DirectBroadcastFlag.Name) } + if ctx.GlobalIsSet(DisableSnapProtocolFlag.Name) { + cfg.DisableSnapProtocol = ctx.GlobalBool(DisableSnapProtocolFlag.Name) + } + if ctx.GlobalIsSet(DiffSyncFlag.Name) { + cfg.DiffSync = ctx.GlobalBool(DiffSyncFlag.Name) + } if ctx.GlobalIsSet(RangeLimitFlag.Name) { cfg.RangeLimit = ctx.GlobalBool(RangeLimitFlag.Name) } diff --git a/common/gopool/pool.go b/common/gopool/pool.go index b4fc1c459d..bfcc618e46 100644 --- a/common/gopool/pool.go +++ b/common/gopool/pool.go @@ -1,6 +1,7 @@ package gopool import ( + "runtime" "time" "github.com/panjf2000/ants/v2" @@ -8,7 +9,8 @@ import ( var ( // Init a instance pool when importing ants. - defaultPool, _ = ants.NewPool(ants.DefaultAntsPoolSize, ants.WithExpiryDuration(10*time.Second)) + defaultPool, _ = ants.NewPool(ants.DefaultAntsPoolSize, ants.WithExpiryDuration(10*time.Second)) + minNumberPerTask = 5 ) // Logger is used for logging formatted messages. @@ -46,3 +48,13 @@ func Release() { func Reboot() { defaultPool.Reboot() } + +func Threads(tasks int) int { + threads := tasks / minNumberPerTask + if threads > runtime.NumCPU() { + threads = runtime.NumCPU() + } else if threads == 0 { + threads = 1 + } + return threads +} diff --git a/consensus/consensus.go b/consensus/consensus.go index fc161390f9..04a9924383 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -141,4 +141,5 @@ type PoSA interface { IsSystemContract(to *common.Address) bool EnoughDistance(chain ChainReader, header *types.Header) bool IsLocalBlock(header *types.Header) bool + AllowLightProcess(chain ChainReader, currentHeader *types.Header) bool } diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 14304fe2bc..729c6f3730 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -799,6 +799,11 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header) *time. return nil } delay := p.delayForRamanujanFork(snap, header) + // The blocking time should be no more than half of period + half := time.Duration(p.config.Period) * time.Second / 2 + if delay > half { + delay = half + } return &delay } @@ -882,6 +887,17 @@ func (p *Parlia) EnoughDistance(chain consensus.ChainReader, header *types.Heade return snap.enoughDistance(p.val, header) } +func (p *Parlia) AllowLightProcess(chain consensus.ChainReader, currentHeader *types.Header) bool { + snap, err := p.snapshot(chain, currentHeader.Number.Uint64()-1, currentHeader.ParentHash, nil) + if err != nil { + return true + } + + idx := snap.indexOfVal(p.val) + // validator is not allowed to diff sync + return idx < 0 +} + func (p *Parlia) IsLocalBlock(header *types.Header) bool { return p.val == header.Coinbase } diff --git a/consensus/parlia/ramanujanfork.go b/consensus/parlia/ramanujanfork.go index 903c678f42..9b702ca6c5 100644 --- a/consensus/parlia/ramanujanfork.go +++ b/consensus/parlia/ramanujanfork.go @@ -21,7 +21,7 @@ func (p *Parlia) delayForRamanujanFork(snap *Snapshot, header *types.Header) tim if header.Difficulty.Cmp(diffNoTurn) == 0 { // It's not our turn explicitly to sign, delay it a bit wiggle := time.Duration(len(snap.Validators)/2+1) * wiggleTimeBeforeFork - delay += time.Duration(fixedBackOffTimeBeforeFork) + time.Duration(rand.Int63n(int64(wiggle))) + delay += fixedBackOffTimeBeforeFork + time.Duration(rand.Int63n(int64(wiggle))) } return delay } diff --git a/consensus/parlia/snapshot.go b/consensus/parlia/snapshot.go index dc83d92c8d..95aaf861de 100644 --- a/consensus/parlia/snapshot.go +++ b/consensus/parlia/snapshot.go @@ -256,7 +256,7 @@ func (s *Snapshot) enoughDistance(validator common.Address, header *types.Header if validator == header.Coinbase { return false } - offset := (int64(s.Number) + 1) % int64(validatorNum) + offset := (int64(s.Number) + 1) % validatorNum if int64(idx) >= offset { return int64(idx)-offset >= validatorNum-2 } else { diff --git a/core/block_validator.go b/core/block_validator.go index 92be755199..7ef440b4b7 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -17,9 +17,7 @@ package core import ( - "encoding/json" "fmt" - "os" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" @@ -133,7 +131,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD }, func() error { if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { - statedb.IterativeDump(true, true, true, json.NewEncoder(os.Stdout)) return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) } else { return nil diff --git a/core/blockchain.go b/core/blockchain.go index be0b0f04ae..3cfa21654f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -80,14 +80,22 @@ var ( ) const ( - bodyCacheLimit = 256 - blockCacheLimit = 256 - receiptsCacheLimit = 10000 - txLookupCacheLimit = 1024 - maxFutureBlocks = 256 - maxTimeFutureBlocks = 30 - badBlockLimit = 10 - maxBeyondBlocks = 2048 + bodyCacheLimit = 256 + blockCacheLimit = 256 + diffLayerCacheLimit = 1024 + diffLayerRLPCacheLimit = 256 + receiptsCacheLimit = 10000 + txLookupCacheLimit = 1024 + maxFutureBlocks = 256 + maxTimeFutureBlocks = 30 + maxBeyondBlocks = 2048 + + diffLayerFreezerRecheckInterval = 3 * time.Second + diffLayerPruneRecheckInterval = 1 * time.Second // The interval to prune unverified diff layers + maxDiffQueueDist = 2048 // Maximum allowed distance from the chain head to queue diffLayers + maxDiffLimit = 2048 // Maximum number of unique diff layers a peer may have responded + maxDiffForkDist = 11 // Maximum allowed backward distance from the chain head + maxDiffLimitForBroadcast = 128 // Maximum number of unique diff layers a peer may have broadcasted // BlockChainVersion ensures that an incompatible database forces a resync from scratch. // @@ -131,6 +139,11 @@ type CacheConfig struct { SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } +// To avoid cycle import +type PeerIDer interface { + ID() string +} + // defaultCacheConfig are the default caching values if none are specified by the // user (also used during testing). var defaultCacheConfig = &CacheConfig{ @@ -142,6 +155,8 @@ var defaultCacheConfig = &CacheConfig{ SnapshotWait: true, } +type BlockChainOption func(*BlockChain) *BlockChain + // BlockChain represents the canonical chain given a database with a genesis // block. The Blockchain manages chain imports, reverts, chain reorganisations. // @@ -196,6 +211,21 @@ type BlockChain struct { txLookupCache *lru.Cache // Cache for the most recent transaction lookup data. futureBlocks *lru.Cache // future blocks are blocks added for later processing + // trusted diff layers + diffLayerCache *lru.Cache // Cache for the diffLayers + diffLayerRLPCache *lru.Cache // Cache for the rlp encoded diffLayers + diffQueue *prque.Prque // A Priority queue to store recent diff layer + diffQueueBuffer chan *types.DiffLayer + diffLayerFreezerBlockLimit uint64 + + // untrusted diff layers + diffMux sync.RWMutex + blockHashToDiffLayers map[common.Hash]map[common.Hash]*types.DiffLayer // map[blockHash] map[DiffHash]Diff + diffHashToBlockHash map[common.Hash]common.Hash // map[diffHash]blockHash + diffHashToPeers map[common.Hash]map[string]struct{} // map[diffHash]map[pid] + diffNumToBlockHashes map[uint64]map[common.Hash]struct{} // map[number]map[blockHash] + diffPeersToDiffHashes map[string]map[common.Hash]struct{} // map[pid]map[diffHash] + quit chan struct{} // blockchain quit channel wg sync.WaitGroup // chain processing wait group for shutting down running int32 // 0 if chain is running, 1 when stopped @@ -213,12 +243,15 @@ 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(block *types.Block) bool, txLookupLimit *uint64) (*BlockChain, error) { +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, + vmConfig vm.Config, shouldPreserve func(block *types.Block) bool, txLookupLimit *uint64, + options ...BlockChainOption) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = defaultCacheConfig } if cacheConfig.TriesInMemory != 128 { - log.Warn("TriesInMemory isn't the default value(128), you need specify exact same TriesInMemory when prune data", "triesInMemory", cacheConfig.TriesInMemory) + log.Warn("TriesInMemory isn't the default value(128), you need specify exact same TriesInMemory when prune data", + "triesInMemory", cacheConfig.TriesInMemory) } bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) @@ -226,6 +259,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par blockCache, _ := lru.New(blockCacheLimit) txLookupCache, _ := lru.New(txLookupCacheLimit) futureBlocks, _ := lru.New(maxFutureBlocks) + diffLayerCache, _ := lru.New(diffLayerCacheLimit) + diffLayerRLPCache, _ := lru.New(diffLayerRLPCacheLimit) bc := &BlockChain{ chainConfig: chainConfig, @@ -237,17 +272,26 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par Journal: cacheConfig.TrieCleanJournal, Preimages: cacheConfig.Preimages, }), - triesInMemory: cacheConfig.TriesInMemory, - quit: make(chan struct{}), - shouldPreserve: shouldPreserve, - bodyCache: bodyCache, - bodyRLPCache: bodyRLPCache, - receiptsCache: receiptsCache, - blockCache: blockCache, - txLookupCache: txLookupCache, - futureBlocks: futureBlocks, - engine: engine, - vmConfig: vmConfig, + triesInMemory: cacheConfig.TriesInMemory, + quit: make(chan struct{}), + shouldPreserve: shouldPreserve, + bodyCache: bodyCache, + bodyRLPCache: bodyRLPCache, + receiptsCache: receiptsCache, + blockCache: blockCache, + diffLayerCache: diffLayerCache, + diffLayerRLPCache: diffLayerRLPCache, + txLookupCache: txLookupCache, + futureBlocks: futureBlocks, + engine: engine, + vmConfig: vmConfig, + diffQueue: prque.New(nil), + diffQueueBuffer: make(chan *types.DiffLayer), + blockHashToDiffLayers: make(map[common.Hash]map[common.Hash]*types.DiffLayer), + diffHashToBlockHash: make(map[common.Hash]common.Hash), + diffHashToPeers: make(map[common.Hash]map[string]struct{}), + diffNumToBlockHashes: make(map[uint64]map[common.Hash]struct{}), + diffPeersToDiffHashes: make(map[string]map[common.Hash]struct{}), } bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.processor = NewStateProcessor(chainConfig, bc, engine) @@ -375,6 +419,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par } bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, int(bc.cacheConfig.TriesInMemory), head.Root(), !bc.cacheConfig.SnapshotWait, true, recover) } + // do options before start any routine + for _, option := range options { + bc = option(bc) + } // Take ownership of this particular state go bc.update() if txLookupLimit != nil { @@ -396,6 +444,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit) }() } + // Need persist and prune diff layer + if bc.db.DiffStore() != nil { + go bc.trustedDiffLayerLoop() + } + go bc.untrustedDiffLayerPruneLoop() + return bc, nil } @@ -404,11 +458,19 @@ func (bc *BlockChain) GetVMConfig() *vm.Config { return &bc.vmConfig } -func (bc *BlockChain) CacheReceipts(hash common.Hash, receipts types.Receipts) { +func (bc *BlockChain) cacheReceipts(hash common.Hash, receipts types.Receipts) { bc.receiptsCache.Add(hash, receipts) } -func (bc *BlockChain) CacheBlock(hash common.Hash, block *types.Block) { +func (bc *BlockChain) cacheDiffLayer(diffLayer *types.DiffLayer) { + bc.diffLayerCache.Add(diffLayer.BlockHash, diffLayer) + if bc.db.DiffStore() != nil { + // push to priority queue before persisting + bc.diffQueueBuffer <- diffLayer + } +} + +func (bc *BlockChain) cacheBlock(hash common.Hash, block *types.Block) { bc.blockCache.Add(hash, block) } @@ -873,6 +935,45 @@ func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue { return body } +// GetDiffLayerRLP retrieves a diff layer in RLP encoding from the cache or database by blockHash +func (bc *BlockChain) GetDiffLayerRLP(blockHash common.Hash) rlp.RawValue { + // Short circuit if the diffLayer's already in the cache, retrieve otherwise + if cached, ok := bc.diffLayerRLPCache.Get(blockHash); ok { + return cached.(rlp.RawValue) + } + if cached, ok := bc.diffLayerCache.Get(blockHash); ok { + diff := cached.(*types.DiffLayer) + bz, err := rlp.EncodeToBytes(diff) + if err != nil { + return nil + } + bc.diffLayerRLPCache.Add(blockHash, rlp.RawValue(bz)) + return bz + } + + // fallback to untrusted sources. + diff := bc.GetUnTrustedDiffLayer(blockHash, "") + if diff != nil { + bz, err := rlp.EncodeToBytes(diff) + if err != nil { + return nil + } + // No need to cache untrusted data + return bz + } + + // fallback to disk + diffStore := bc.db.DiffStore() + if diffStore == nil { + return nil + } + rawData := rawdb.ReadDiffLayerRLP(diffStore, blockHash) + if len(rawData) != 0 { + bc.diffLayerRLPCache.Add(blockHash, rawData) + } + return rawData +} + // HasBlock checks if a block is fully present in the database or not. func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool { if bc.blockCache.Contains(hash) { @@ -1506,10 +1607,19 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. wg.Done() }() // Commit all cached state changes into underlying memory database. - root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) + root, diffLayer, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) if err != nil { return NonStatTy, err } + + // Ensure no empty block body + if diffLayer != nil && block.Header().TxHash != types.EmptyRootHash { + // Filling necessary field + diffLayer.Receipts = receipts + diffLayer.BlockHash = block.Hash() + diffLayer.Number = block.NumberU64() + bc.cacheDiffLayer(diffLayer) + } triedb := bc.stateCache.TrieDB() // If we're running an archive node, always flush @@ -1885,18 +1995,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er } // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") - activeState = statedb - statedb.TryPreload(block, signer) //Process block using the parent state as reference point substart := time.Now() - receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) + statedb, receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) + activeState = statedb if err != nil { bc.reportBlock(block, receipts, err) return it.index, err } - bc.CacheReceipts(block.Hash(), receipts) - bc.CacheBlock(block.Hash(), block) // 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 @@ -1904,18 +2011,20 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er 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 - trieproc := statedb.SnapshotAccountReads + statedb.AccountReads + statedb.AccountUpdates - trieproc += statedb.SnapshotStorageReads + statedb.StorageReads + statedb.StorageUpdates blockExecutionTimer.Update(time.Since(substart)) // Validate the state using the default validator substart = time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { - bc.reportBlock(block, receipts, err) - log.Error("validate state failed", "error", err) - return it.index, err + if !statedb.IsLightProcessed() { + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { + log.Error("validate state failed", "error", err) + bc.reportBlock(block, receipts, err) + return it.index, err + } } + bc.cacheReceipts(block.Hash(), receipts) + bc.cacheBlock(block.Hash(), block) proctime := time.Since(start) // Update the metrics touched during block validation @@ -2292,6 +2401,279 @@ func (bc *BlockChain) update() { } } +func (bc *BlockChain) trustedDiffLayerLoop() { + recheck := time.Tick(diffLayerFreezerRecheckInterval) + bc.wg.Add(1) + defer bc.wg.Done() + for { + select { + case diff := <-bc.diffQueueBuffer: + bc.diffQueue.Push(diff, -(int64(diff.Number))) + case <-bc.quit: + // Persist all diffLayers when shutdown, it will introduce redundant storage, but it is acceptable. + // If the client been ungracefully shutdown, it will missing all cached diff layers, it is acceptable as well. + var batch ethdb.Batch + for !bc.diffQueue.Empty() { + diff, _ := bc.diffQueue.Pop() + diffLayer := diff.(*types.DiffLayer) + if batch == nil { + batch = bc.db.DiffStore().NewBatch() + } + rawdb.WriteDiffLayer(batch, diffLayer.BlockHash, diffLayer) + if batch.ValueSize() > ethdb.IdealBatchSize { + if err := batch.Write(); err != nil { + log.Error("Failed to write diff layer", "err", err) + return + } + batch.Reset() + } + } + if batch != nil { + // flush data + if err := batch.Write(); err != nil { + log.Error("Failed to write diff layer", "err", err) + return + } + batch.Reset() + } + return + case <-recheck: + currentHeight := bc.CurrentBlock().NumberU64() + var batch ethdb.Batch + for !bc.diffQueue.Empty() { + diff, prio := bc.diffQueue.Pop() + diffLayer := diff.(*types.DiffLayer) + + // if the block old enough + if int64(currentHeight)+prio >= int64(bc.triesInMemory) { + canonicalHash := bc.GetCanonicalHash(uint64(-prio)) + // on the canonical chain + if canonicalHash == diffLayer.BlockHash { + if batch == nil { + batch = bc.db.DiffStore().NewBatch() + } + rawdb.WriteDiffLayer(batch, diffLayer.BlockHash, diffLayer) + staleHash := bc.GetCanonicalHash(uint64(-prio) - bc.diffLayerFreezerBlockLimit) + rawdb.DeleteDiffLayer(batch, staleHash) + } + } else { + bc.diffQueue.Push(diffLayer, prio) + break + } + if batch != nil && batch.ValueSize() > ethdb.IdealBatchSize { + if err := batch.Write(); err != nil { + panic(fmt.Sprintf("Failed to write diff layer, error %v", err)) + } + batch.Reset() + } + } + if batch != nil { + if err := batch.Write(); err != nil { + panic(fmt.Sprintf("Failed to write diff layer, error %v", err)) + } + batch.Reset() + } + } + } +} + +func (bc *BlockChain) GetUnTrustedDiffLayer(blockHash common.Hash, pid string) *types.DiffLayer { + bc.diffMux.RLock() + defer bc.diffMux.RUnlock() + if diffs, exist := bc.blockHashToDiffLayers[blockHash]; exist && len(diffs) != 0 { + if len(diffs) == 1 { + // return the only one diff layer + for _, diff := range diffs { + return diff + } + } + // pick the one from exact same peer if we know where the block comes from + if pid != "" { + if diffHashes, exist := bc.diffPeersToDiffHashes[pid]; exist { + for diff := range diffs { + if _, overlap := diffHashes[diff]; overlap { + return bc.blockHashToDiffLayers[blockHash][diff] + } + } + } + } + // Do not find overlap, do random pick + for _, diff := range diffs { + return diff + } + } + return nil +} + +func (bc *BlockChain) removeDiffLayers(diffHash common.Hash) { + bc.diffMux.Lock() + defer bc.diffMux.Unlock() + + // Untrusted peers + pids := bc.diffHashToPeers[diffHash] + invalidDiffHashes := make(map[common.Hash]struct{}) + for pid := range pids { + invaliDiffHashesPeer := bc.diffPeersToDiffHashes[pid] + for invaliDiffHash := range invaliDiffHashesPeer { + invalidDiffHashes[invaliDiffHash] = struct{}{} + } + delete(bc.diffPeersToDiffHashes, pid) + } + for invalidDiffHash := range invalidDiffHashes { + delete(bc.diffHashToPeers, invalidDiffHash) + affectedBlockHash := bc.diffHashToBlockHash[invalidDiffHash] + if diffs, exist := bc.blockHashToDiffLayers[affectedBlockHash]; exist { + delete(diffs, invalidDiffHash) + if len(diffs) == 0 { + delete(bc.blockHashToDiffLayers, affectedBlockHash) + } + } + delete(bc.diffHashToBlockHash, invalidDiffHash) + } +} + +func (bc *BlockChain) RemoveDiffPeer(pid string) { + bc.diffMux.Lock() + defer bc.diffMux.Unlock() + if invaliDiffHashes := bc.diffPeersToDiffHashes[pid]; invaliDiffHashes != nil { + for invalidDiffHash := range invaliDiffHashes { + lastDiffHash := false + if peers, ok := bc.diffHashToPeers[invalidDiffHash]; ok { + delete(peers, pid) + if len(peers) == 0 { + lastDiffHash = true + delete(bc.diffHashToPeers, invalidDiffHash) + } + } + if lastDiffHash { + affectedBlockHash := bc.diffHashToBlockHash[invalidDiffHash] + if diffs, exist := bc.blockHashToDiffLayers[affectedBlockHash]; exist { + delete(diffs, invalidDiffHash) + if len(diffs) == 0 { + delete(bc.blockHashToDiffLayers, affectedBlockHash) + } + } + delete(bc.diffHashToBlockHash, invalidDiffHash) + } + } + delete(bc.diffPeersToDiffHashes, pid) + } +} + +func (bc *BlockChain) untrustedDiffLayerPruneLoop() { + recheck := time.NewTicker(diffLayerPruneRecheckInterval) + bc.wg.Add(1) + defer func() { + bc.wg.Done() + recheck.Stop() + }() + for { + select { + case <-bc.quit: + return + case <-recheck.C: + bc.pruneDiffLayer() + } + } +} + +func (bc *BlockChain) pruneDiffLayer() { + currentHeight := bc.CurrentBlock().NumberU64() + bc.diffMux.Lock() + defer bc.diffMux.Unlock() + sortNumbers := make([]uint64, 0, len(bc.diffNumToBlockHashes)) + for number := range bc.diffNumToBlockHashes { + sortNumbers = append(sortNumbers, number) + } + sort.Slice(sortNumbers, func(i, j int) bool { + return sortNumbers[i] <= sortNumbers[j] + }) + staleBlockHashes := make(map[common.Hash]struct{}) + for _, number := range sortNumbers { + if number >= currentHeight-maxDiffForkDist { + break + } + affectedHashes := bc.diffNumToBlockHashes[number] + if affectedHashes != nil { + for affectedHash := range affectedHashes { + staleBlockHashes[affectedHash] = struct{}{} + } + delete(bc.diffNumToBlockHashes, number) + } + } + staleDiffHashes := make(map[common.Hash]struct{}) + for blockHash := range staleBlockHashes { + if diffHashes, exist := bc.blockHashToDiffLayers[blockHash]; exist { + for diffHash := range diffHashes { + staleDiffHashes[diffHash] = struct{}{} + delete(bc.diffHashToBlockHash, diffHash) + delete(bc.diffHashToPeers, diffHash) + } + } + delete(bc.blockHashToDiffLayers, blockHash) + } + for diffHash := range staleDiffHashes { + for p, diffHashes := range bc.diffPeersToDiffHashes { + delete(diffHashes, diffHash) + if len(diffHashes) == 0 { + delete(bc.diffPeersToDiffHashes, p) + } + } + } +} + +// Process received diff layers +func (bc *BlockChain) HandleDiffLayer(diffLayer *types.DiffLayer, pid string, fulfilled bool) error { + // Basic check + currentHeight := bc.CurrentBlock().NumberU64() + if diffLayer.Number > currentHeight && diffLayer.Number-currentHeight > maxDiffQueueDist { + log.Error("diff layers too new from current", "pid", pid) + return nil + } + if diffLayer.Number < currentHeight && currentHeight-diffLayer.Number > maxDiffForkDist { + log.Error("diff layers too old from current", "pid", pid) + return nil + } + + bc.diffMux.Lock() + defer bc.diffMux.Unlock() + + if !fulfilled && len(bc.diffPeersToDiffHashes[pid]) > maxDiffLimitForBroadcast { + log.Error("too many accumulated diffLayers", "pid", pid) + return nil + } + + if len(bc.diffPeersToDiffHashes[pid]) > maxDiffLimit { + log.Error("too many accumulated diffLayers", "pid", pid) + return nil + } + if _, exist := bc.diffPeersToDiffHashes[pid]; exist { + if _, alreadyHas := bc.diffPeersToDiffHashes[pid][diffLayer.DiffHash]; alreadyHas { + return nil + } + } else { + bc.diffPeersToDiffHashes[pid] = make(map[common.Hash]struct{}) + } + bc.diffPeersToDiffHashes[pid][diffLayer.DiffHash] = struct{}{} + if _, exist := bc.diffNumToBlockHashes[diffLayer.Number]; !exist { + bc.diffNumToBlockHashes[diffLayer.Number] = make(map[common.Hash]struct{}) + } + bc.diffNumToBlockHashes[diffLayer.Number][diffLayer.BlockHash] = struct{}{} + + if _, exist := bc.diffHashToPeers[diffLayer.DiffHash]; !exist { + bc.diffHashToPeers[diffLayer.DiffHash] = make(map[string]struct{}) + } + bc.diffHashToPeers[diffLayer.DiffHash][pid] = struct{}{} + + if _, exist := bc.blockHashToDiffLayers[diffLayer.BlockHash]; !exist { + bc.blockHashToDiffLayers[diffLayer.BlockHash] = make(map[common.Hash]*types.DiffLayer) + } + bc.blockHashToDiffLayers[diffLayer.BlockHash][diffLayer.DiffHash] = diffLayer + bc.diffHashToBlockHash[diffLayer.DiffHash] = diffLayer.BlockHash + + return nil +} + // maintainTxIndex is responsible for the construction and deletion of the // transaction index. // @@ -2541,3 +2923,16 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription { return bc.scope.Track(bc.blockProcFeed.Subscribe(ch)) } + +// Options +func EnableLightProcessor(bc *BlockChain) *BlockChain { + bc.processor = NewLightStateProcessor(bc.Config(), bc, bc.engine) + return bc +} + +func EnablePersistDiff(limit uint64) BlockChainOption { + return func(chain *BlockChain) *BlockChain { + chain.diffLayerFreezerBlockLimit = limit + return chain + } +} diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go new file mode 100644 index 0000000000..717b4039ed --- /dev/null +++ b/core/blockchain_diff_test.go @@ -0,0 +1,263 @@ +// 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 . + +// Tests that abnormal program termination (i.e.crash) and restart doesn't leave +// the database in some strange state with gaps in the chain, nor with block data +// dangling in the future. + +package core + +import ( + "math/big" + "testing" + "time" + + "golang.org/x/crypto/sha3" + + "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/state/snapshot" + "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/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" +) + +var ( + // testKey is a private key to use for funding a tester account. + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + // testAddr is the Ethereum address of the tester account. + testAddr = crypto.PubkeyToAddress(testKey.PublicKey) +) + +// 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. +type testBackend struct { + db ethdb.Database + chain *BlockChain +} + +// newTestBackend creates an empty chain and wraps it into a mock backend. +func newTestBackend(blocks int, light bool) *testBackend { + return newTestBackendWithGenerator(blocks, light) +} + +// newTestBackend creates a chain with a number of explicitly defined blocks and +// wraps it into a mock backend. +func newTestBackendWithGenerator(blocks int, lightProcess bool) *testBackend { + signer := types.HomesteadSigner{} + // Create a database pre-initialize with a genesis block + db := rawdb.NewMemoryDatabase() + db.SetDiffStore(memorydb.New()) + (&Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db) + + chain, _ := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, EnablePersistDiff(860000)) + generator := func(i int, block *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.SetCoinbase(testAddr) + + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), common.Address{0x01}, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain, tx) + } + bs, _ := GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator) + if _, err := chain.InsertChain(bs); err != nil { + panic(err) + } + if lightProcess { + EnableLightProcessor(chain) + } + + return &testBackend{ + db: db, + chain: chain, + } +} + +// close tears down the transaction pool and chain behind the mock backend. +func (b *testBackend) close() { + b.chain.Stop() +} + +func (b *testBackend) Chain() *BlockChain { return b.chain } + +func rawDataToDiffLayer(data rlp.RawValue) (*types.DiffLayer, error) { + var diff types.DiffLayer + hasher := sha3.NewLegacyKeccak256() + err := rlp.DecodeBytes(data, &diff) + if err != nil { + return nil, err + } + hasher.Write(data) + var diffHash common.Hash + hasher.Sum(diffHash[:0]) + diff.DiffHash = diffHash + hasher.Reset() + return &diff, nil +} + +func TestProcessDiffLayer(t *testing.T) { + t.Parallel() + + blockNum := 128 + fullBackend := newTestBackend(blockNum, false) + falseDiff := 5 + defer fullBackend.close() + + lightBackend := newTestBackend(0, true) + defer lightBackend.close() + for i := 1; i <= blockNum-falseDiff; i++ { + block := fullBackend.chain.GetBlockByNumber(uint64(i)) + if block == nil { + t.Fatal("block should not be nil") + } + blockHash := block.Hash() + rawDiff := fullBackend.chain.GetDiffLayerRLP(blockHash) + diff, err := rawDataToDiffLayer(rawDiff) + if err != nil { + t.Errorf("failed to decode rawdata %v", err) + } + lightBackend.Chain().HandleDiffLayer(diff, "testpid", true) + _, err = lightBackend.chain.insertChain([]*types.Block{block}, true) + if err != nil { + t.Errorf("failed to insert block %v", err) + } + } + currentBlock := lightBackend.chain.CurrentBlock() + nextBlock := fullBackend.chain.GetBlockByNumber(currentBlock.NumberU64() + 1) + rawDiff := fullBackend.chain.GetDiffLayerRLP(nextBlock.Hash()) + diff, _ := rawDataToDiffLayer(rawDiff) + latestAccount, _ := snapshot.FullAccount(diff.Accounts[0].Blob) + latestAccount.Balance = big.NewInt(0) + bz, _ := rlp.EncodeToBytes(&latestAccount) + diff.Accounts[0].Blob = bz + + lightBackend.Chain().HandleDiffLayer(diff, "testpid", true) + + _, err := lightBackend.chain.insertChain([]*types.Block{nextBlock}, true) + if err != nil { + t.Errorf("failed to process block %v", err) + } + + // the diff cache should be cleared + if len(lightBackend.chain.diffPeersToDiffHashes) != 0 { + t.Errorf("the size of diffPeersToDiffHashes should be 0, but get %d", len(lightBackend.chain.diffPeersToDiffHashes)) + } + if len(lightBackend.chain.diffHashToPeers) != 0 { + t.Errorf("the size of diffHashToPeers should be 0, but get %d", len(lightBackend.chain.diffHashToPeers)) + } + if len(lightBackend.chain.diffHashToBlockHash) != 0 { + t.Errorf("the size of diffHashToBlockHash should be 0, but get %d", len(lightBackend.chain.diffHashToBlockHash)) + } + if len(lightBackend.chain.blockHashToDiffLayers) != 0 { + t.Errorf("the size of blockHashToDiffLayers should be 0, but get %d", len(lightBackend.chain.blockHashToDiffLayers)) + } +} + +func TestFreezeDiffLayer(t *testing.T) { + t.Parallel() + + blockNum := 1024 + fullBackend := newTestBackend(blockNum, true) + defer fullBackend.close() + if fullBackend.chain.diffQueue.Size() != blockNum { + t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum, fullBackend.chain.diffQueue.Size()) + } + time.Sleep(diffLayerFreezerRecheckInterval + 1*time.Second) + if fullBackend.chain.diffQueue.Size() != int(fullBackend.chain.triesInMemory) { + t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum, fullBackend.chain.diffQueue.Size()) + } + + block := fullBackend.chain.GetBlockByNumber(uint64(blockNum / 2)) + diffStore := fullBackend.chain.db.DiffStore() + rawData := rawdb.ReadDiffLayerRLP(diffStore, block.Hash()) + if len(rawData) == 0 { + t.Error("do not find diff layer in db") + } +} + +func TestPruneDiffLayer(t *testing.T) { + t.Parallel() + + blockNum := 1024 + fullBackend := newTestBackend(blockNum, true) + defer fullBackend.close() + + anotherFullBackend := newTestBackend(2*blockNum, true) + defer anotherFullBackend.close() + + for num := uint64(1); num < uint64(blockNum); num++ { + header := fullBackend.chain.GetHeaderByNumber(num) + rawDiff := fullBackend.chain.GetDiffLayerRLP(header.Hash()) + diff, _ := rawDataToDiffLayer(rawDiff) + fullBackend.Chain().HandleDiffLayer(diff, "testpid1", true) + fullBackend.Chain().HandleDiffLayer(diff, "testpid2", true) + + } + fullBackend.chain.pruneDiffLayer() + if len(fullBackend.chain.diffNumToBlockHashes) != maxDiffForkDist { + t.Error("unexpected size of diffNumToBlockHashes") + } + if len(fullBackend.chain.diffPeersToDiffHashes) != 2 { + t.Error("unexpected size of diffPeersToDiffHashes") + } + if len(fullBackend.chain.blockHashToDiffLayers) != maxDiffForkDist { + t.Error("unexpected size of diffNumToBlockHashes") + } + if len(fullBackend.chain.diffHashToBlockHash) != maxDiffForkDist { + t.Error("unexpected size of diffHashToBlockHash") + } + if len(fullBackend.chain.diffHashToPeers) != maxDiffForkDist { + t.Error("unexpected size of diffHashToPeers") + } + + blocks := make([]*types.Block, 0, blockNum) + for i := blockNum + 1; i <= 2*blockNum; i++ { + b := anotherFullBackend.chain.GetBlockByNumber(uint64(i)) + blocks = append(blocks, b) + } + fullBackend.chain.insertChain(blocks, true) + fullBackend.chain.pruneDiffLayer() + if len(fullBackend.chain.diffNumToBlockHashes) != 0 { + t.Error("unexpected size of diffNumToBlockHashes") + } + if len(fullBackend.chain.diffPeersToDiffHashes) != 0 { + t.Error("unexpected size of diffPeersToDiffHashes") + } + if len(fullBackend.chain.blockHashToDiffLayers) != 0 { + t.Error("unexpected size of diffNumToBlockHashes") + } + if len(fullBackend.chain.diffHashToBlockHash) != 0 { + t.Error("unexpected size of diffHashToBlockHash") + } + if len(fullBackend.chain.diffHashToPeers) != 0 { + t.Error("unexpected size of diffHashToPeers") + } + +} diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 9395a379f5..4314bd45a9 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -151,7 +151,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } - receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{}) + statedb, receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{}) if err != nil { blockchain.reportBlock(block, receipts, err) return err @@ -1769,7 +1769,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon } lastPrunedIndex := len(blocks) - TestTriesInMemory - 1 - lastPrunedBlock := blocks[lastPrunedIndex] + lastPrunedBlock := blocks[lastPrunedIndex-1] firstNonPrunedBlock := blocks[len(blocks)-TestTriesInMemory] // Verify pruning of lastPrunedBlock @@ -2420,7 +2420,7 @@ func TestSideImportPrunedBlocks(t *testing.T) { } lastPrunedIndex := len(blocks) - TestTriesInMemory - 1 - lastPrunedBlock := blocks[lastPrunedIndex] + lastPrunedBlock := blocks[lastPrunedIndex-1] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { diff --git a/core/chain_makers.go b/core/chain_makers.go index 6cb74d51be..9ded01a433 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -223,7 +223,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse block, _, _ := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) // Write state changes to db - root, err := statedb.Commit(config.IsEIP158(b.header.Number)) + root, _, err := statedb.Commit(config.IsEIP158(b.header.Number)) if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 76132bf37e..6489a600fb 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -447,6 +447,44 @@ func WriteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64, body *t WriteBodyRLP(db, hash, number, data) } +func WriteDiffLayer(db ethdb.KeyValueWriter, hash common.Hash, layer *types.DiffLayer) { + data, err := rlp.EncodeToBytes(layer) + if err != nil { + log.Crit("Failed to RLP encode diff layer", "err", err) + } + WriteDiffLayerRLP(db, hash, data) +} + +func WriteDiffLayerRLP(db ethdb.KeyValueWriter, blockHash common.Hash, rlp rlp.RawValue) { + if err := db.Put(diffLayerKey(blockHash), rlp); err != nil { + log.Crit("Failed to store diff layer", "err", err) + } +} + +func ReadDiffLayer(db ethdb.KeyValueReader, blockHash common.Hash) *types.DiffLayer { + data := ReadDiffLayerRLP(db, blockHash) + if len(data) == 0 { + return nil + } + diff := new(types.DiffLayer) + if err := rlp.Decode(bytes.NewReader(data), diff); err != nil { + log.Error("Invalid diff layer RLP", "hash", blockHash, "err", err) + return nil + } + return diff +} + +func ReadDiffLayerRLP(db ethdb.KeyValueReader, blockHash common.Hash) rlp.RawValue { + data, _ := db.Get(diffLayerKey(blockHash)) + return data +} + +func DeleteDiffLayer(db ethdb.KeyValueWriter, blockHash common.Hash) { + if err := db.Delete(diffLayerKey(blockHash)); err != nil { + log.Crit("Failed to delete diffLayer", "err", err) + } +} + // DeleteBody removes all block body data associated with a hash. func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { if err := db.Delete(blockBodyKey(number, hash)); err != nil { diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 725972f9ba..82d5df06ce 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -36,6 +36,7 @@ import ( type freezerdb struct { ethdb.KeyValueStore ethdb.AncientStore + diffStore ethdb.KeyValueStore } // Close implements io.Closer, closing both the fast key-value store as well as @@ -48,12 +49,28 @@ func (frdb *freezerdb) Close() error { if err := frdb.KeyValueStore.Close(); err != nil { errs = append(errs, err) } + if frdb.diffStore != nil { + if err := frdb.diffStore.Close(); err != nil { + errs = append(errs, err) + } + } if len(errs) != 0 { return fmt.Errorf("%v", errs) } return nil } +func (frdb *freezerdb) DiffStore() ethdb.KeyValueStore { + return frdb.diffStore +} + +func (frdb *freezerdb) SetDiffStore(diff ethdb.KeyValueStore) { + if frdb.diffStore != nil { + frdb.diffStore.Close() + } + frdb.diffStore = diff +} + // Freeze is a helper method used for external testing to trigger and block until // a freeze cycle completes, without having to sleep for a minute to trigger the // automatic background run. @@ -77,6 +94,7 @@ func (frdb *freezerdb) Freeze(threshold uint64) error { // nofreezedb is a database wrapper that disables freezer data retrievals. type nofreezedb struct { ethdb.KeyValueStore + diffStore ethdb.KeyValueStore } // HasAncient returns an error as we don't have a backing chain freezer. @@ -114,6 +132,14 @@ func (db *nofreezedb) Sync() error { return errNotSupported } +func (db *nofreezedb) DiffStore() ethdb.KeyValueStore { + return db.diffStore +} + +func (db *nofreezedb) SetDiffStore(diff ethdb.KeyValueStore) { + db.diffStore = diff +} + // NewDatabase creates a high level database on top of a given key-value data // store without a freezer moving immutable chain segments into cold storage. func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { diff --git a/core/rawdb/freezer_table_test.go b/core/rawdb/freezer_table_test.go index 0df28f236d..8e52b20088 100644 --- a/core/rawdb/freezer_table_test.go +++ b/core/rawdb/freezer_table_test.go @@ -18,13 +18,10 @@ package rawdb import ( "bytes" - "encoding/binary" "fmt" - "io/ioutil" "math/rand" "os" "path/filepath" - "sync" "testing" "time" @@ -528,7 +525,6 @@ func TestOffset(t *testing.T) { f.Append(4, getChunk(20, 0xbb)) f.Append(5, getChunk(20, 0xaa)) - f.DumpIndex(0, 100) f.Close() } // Now crop it. @@ -575,7 +571,6 @@ func TestOffset(t *testing.T) { if err != nil { t.Fatal(err) } - f.DumpIndex(0, 100) // It should allow writing item 6 f.Append(numDeleted+2, getChunk(20, 0x99)) @@ -640,55 +635,6 @@ func TestOffset(t *testing.T) { // 1. have data files d0, d1, d2, d3 // 2. remove d2,d3 // -// However, all 'normal' failure modes arising due to failing to sync() or save a file -// should be handled already, and the case described above can only (?) happen if an -// external process/user deletes files from the filesystem. - -// TestAppendTruncateParallel is a test to check if the Append/truncate operations are -// racy. -// -// The reason why it's not a regular fuzzer, within tests/fuzzers, is that it is dependent -// on timing rather than 'clever' input -- there's no determinism. -func TestAppendTruncateParallel(t *testing.T) { - dir, err := ioutil.TempDir("", "freezer") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - f, err := newCustomTable(dir, "tmp", metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, 8, true) - if err != nil { - t.Fatal(err) - } - - fill := func(mark uint64) []byte { - data := make([]byte, 8) - binary.LittleEndian.PutUint64(data, mark) - return data - } - - for i := 0; i < 5000; i++ { - f.truncate(0) - data0 := fill(0) - f.Append(0, data0) - data1 := fill(1) - - var wg sync.WaitGroup - wg.Add(2) - go func() { - f.truncate(0) - wg.Done() - }() - go func() { - f.Append(1, data1) - wg.Done() - }() - wg.Wait() - - if have, err := f.Retrieve(0); err == nil { - if !bytes.Equal(have, data0) { - t.Fatalf("have %x want %x", have, data0) - } - } - } -} +// However, all 'normal' failure modes arising due to failing to sync() or save a file should be +// handled already, and the case described above can only (?) happen if an external process/user +// deletes files from the filesystem. diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 2505ce90b9..b4fb99e451 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -90,6 +90,9 @@ var ( SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value CodePrefix = []byte("c") // CodePrefix + code hash -> account code + // difflayer database + diffLayerPrefix = []byte("d") // diffLayerPrefix + hash -> diffLayer + preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage configPrefix = []byte("ethereum-config-") // config prefix for the db @@ -177,6 +180,11 @@ func blockReceiptsKey(number uint64, hash common.Hash) []byte { return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...) } +// diffLayerKey = diffLayerKeyPrefix + hash +func diffLayerKey(hash common.Hash) []byte { + return append(append(diffLayerPrefix, hash.Bytes()...)) +} + // txLookupKey = txLookupPrefix + hash func txLookupKey(hash common.Hash) []byte { return append(txLookupPrefix, hash.Bytes()...) diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 323ef6293c..a27f5f8ed7 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -159,6 +159,14 @@ func (t *table) NewBatch() ethdb.Batch { return &tableBatch{t.db.NewBatch(), t.prefix} } +func (t *table) DiffStore() ethdb.KeyValueStore { + return nil +} + +func (t *table) SetDiffStore(diff ethdb.KeyValueStore) { + panic("not implement") +} + // tableBatch is a wrapper around a database batch that prefixes each key access // with a pre-configured string. type tableBatch struct { diff --git a/core/state/database.go b/core/state/database.go index ce37e73837..0bcde2d5a9 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -243,7 +243,6 @@ func (db *cachingDB) CacheStorage(addrHash common.Hash, root common.Hash, t Trie triesArray := [3]*triePair{{root: root, trie: tr.ResetCopy()}, nil, nil} db.storageTrieCache.Add(addrHash, triesArray) } - return } func (db *cachingDB) Purge() { diff --git a/core/state/journal.go b/core/state/journal.go index 366e0c9c26..d86823c2ca 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -153,7 +153,7 @@ 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) + delete(s.snapDestructs, ch.prev.address) } } diff --git a/core/state/snapshot/disklayer_test.go b/core/state/snapshot/disklayer_test.go index ccde2fc094..362edba90d 100644 --- a/core/state/snapshot/disklayer_test.go +++ b/core/state/snapshot/disklayer_test.go @@ -121,7 +121,7 @@ func TestDiskMerge(t *testing.T) { base.Storage(conNukeCache, conNukeCacheSlot) // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{ + if err := snaps.update(diffRoot, baseRoot, map[common.Hash]struct{}{ accDelNoCache: {}, accDelCache: {}, conNukeNoCache: {}, @@ -344,7 +344,7 @@ func TestDiskPartialMerge(t *testing.T) { assertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:]) // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{ + if err := snaps.update(diffRoot, baseRoot, map[common.Hash]struct{}{ accDelNoCache: {}, accDelCache: {}, conNukeNoCache: {}, @@ -466,7 +466,7 @@ func TestDiskGeneratorPersistence(t *testing.T) { }, } // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffRoot, baseRoot, nil, map[common.Hash][]byte{ + if err := snaps.update(diffRoot, baseRoot, nil, map[common.Hash][]byte{ accTwo: accTwo[:], }, nil); err != nil { t.Fatalf("failed to update snapshot tree: %v", err) @@ -484,7 +484,7 @@ func TestDiskGeneratorPersistence(t *testing.T) { } // Test scenario 2, the disk layer is fully generated // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffTwoRoot, diffRoot, nil, map[common.Hash][]byte{ + if err := snaps.update(diffTwoRoot, diffRoot, nil, map[common.Hash][]byte{ accThree: accThree.Bytes(), }, map[common.Hash]map[common.Hash][]byte{ accThree: {accThreeSlot: accThreeSlot.Bytes()}, diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index 2c7e876e08..2a27b01577 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -221,13 +221,13 @@ func TestAccountIteratorTraversal(t *testing.T) { }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Verify the single and multi-layer iterators @@ -268,13 +268,13 @@ func TestStorageIteratorTraversal(t *testing.T) { }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil)) // Verify the single and multi-layer iterators @@ -353,14 +353,14 @@ func TestAccountIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, a, nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, b, nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, c, nil) - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, d, nil) - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, e, nil) - snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, f, nil) - snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, g, nil) - snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, h, nil) + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, a, nil) + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, b, nil) + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, c, nil) + snaps.update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, d, nil) + snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, e, nil) + snaps.update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, f, nil) + snaps.update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, g, nil) + snaps.update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, h, nil) it, _ := snaps.AccountIterator(common.HexToHash("0x09"), common.Hash{}) head := snaps.Snapshot(common.HexToHash("0x09")) @@ -452,14 +452,14 @@ func TestStorageIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), wrapStorage(a)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), wrapStorage(b)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), wrapStorage(c)) - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), wrapStorage(d)) - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, randomAccountSet("0xaa"), wrapStorage(e)) - snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, randomAccountSet("0xaa"), wrapStorage(e)) - snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, randomAccountSet("0xaa"), wrapStorage(g)) - snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, randomAccountSet("0xaa"), wrapStorage(h)) + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), wrapStorage(a)) + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), wrapStorage(b)) + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), wrapStorage(c)) + snaps.update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), wrapStorage(d)) + snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, randomAccountSet("0xaa"), wrapStorage(e)) + snaps.update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, randomAccountSet("0xaa"), wrapStorage(e)) + snaps.update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, randomAccountSet("0xaa"), wrapStorage(g)) + snaps.update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, randomAccountSet("0xaa"), wrapStorage(h)) it, _ := snaps.StorageIterator(common.HexToHash("0x09"), common.HexToHash("0xaa"), common.Hash{}) head := snaps.Snapshot(common.HexToHash("0x09")) @@ -522,7 +522,7 @@ func TestAccountIteratorLargeTraversal(t *testing.T) { }, } for i := 1; i < 128; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) + snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) } // Iterate the entire stack and ensure everything is hit only once head := snaps.Snapshot(common.HexToHash("0x80")) @@ -566,13 +566,13 @@ func TestAccountIteratorFlattening(t *testing.T) { }, } // Create a stack of diffs on top - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Create an iterator and flatten the data from underneath it @@ -597,13 +597,13 @@ func TestAccountIteratorSeek(t *testing.T) { base.root: base, }, } - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Account set is now @@ -661,13 +661,13 @@ func TestStorageIteratorSeek(t *testing.T) { }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil)) // Account set is now @@ -724,17 +724,17 @@ func TestAccountIteratorDeletions(t *testing.T) { }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0x11", "0x22", "0x33"), nil) deleted := common.HexToHash("0x22") destructed := map[common.Hash]struct{}{ deleted: {}, } - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), destructed, randomAccountSet("0x11", "0x33"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0x33", "0x44", "0x55"), nil) // The output should be 11,33,44,55 @@ -770,10 +770,10 @@ func TestStorageIteratorDeletions(t *testing.T) { }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}})) // The output should be 02,04,05,06 @@ -790,14 +790,14 @@ func TestStorageIteratorDeletions(t *testing.T) { destructed := map[common.Hash]struct{}{ common.HexToHash("0xaa"): {}, } - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), destructed, nil, nil) + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), destructed, nil, nil) it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 0, it, verifyStorage) it.Release() // Re-insert the slots of the same account - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, + snaps.update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil)) // The output should be 07,08,09 @@ -806,7 +806,7 @@ func TestStorageIteratorDeletions(t *testing.T) { it.Release() // Destruct the whole storage but re-create the account in the same layer - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil)) + snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil)) it, _ = snaps.StorageIterator(common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12 it.Release() @@ -848,7 +848,7 @@ func BenchmarkAccountIteratorTraversal(b *testing.B) { }, } for i := 1; i <= 100; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) + snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. @@ -943,9 +943,9 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) { base.root: base, }, } - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil) + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil) for i := 2; i <= 100; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil) + snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 1b0d883439..46d1b06def 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -26,6 +26,7 @@ import ( "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/log" "github.com/ethereum/go-ethereum/metrics" @@ -59,7 +60,6 @@ var ( snapshotDirtyStorageWriteMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/write", nil) snapshotDirtyAccountHitDepthHist = metrics.NewRegisteredHistogram("state/snapshot/dirty/account/hit/depth", nil, metrics.NewExpDecaySample(1028, 0.015)) - snapshotDirtyStorageHitDepthHist = metrics.NewRegisteredHistogram("state/snapshot/dirty/storage/hit/depth", nil, metrics.NewExpDecaySample(1028, 0.015)) snapshotFlushAccountItemMeter = metrics.NewRegisteredMeter("state/snapshot/flush/account/item", nil) snapshotFlushAccountSizeMeter = metrics.NewRegisteredMeter("state/snapshot/flush/account/size", nil) @@ -322,9 +322,14 @@ func (t *Tree) Snapshots(root common.Hash, limits int, nodisk bool) []Snapshot { return ret } +func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Address]struct{}, accounts map[common.Address][]byte, storage map[common.Address]map[string][]byte) error { + hashDestructs, hashAccounts, hashStorage := transformSnapData(destructs, accounts, storage) + return t.update(blockRoot, parentRoot, hashDestructs, hashAccounts, hashStorage) +} + // Update adds a new snapshot into the tree, if that can be linked to an existing // old parent. It is disallowed to insert a disk layer (the origin of all). -func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { +func (t *Tree) update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { // Reject noop updates to avoid self-loops in the snapshot tree. This is a // special case that can only happen for Clique networks where empty blocks // don't modify the state (0 block subsidy). @@ -836,3 +841,27 @@ func (t *Tree) DiskRoot() common.Hash { return t.diskRoot() } + +// TODO we can further improve it when the set is very large +func transformSnapData(destructs map[common.Address]struct{}, accounts map[common.Address][]byte, + storage map[common.Address]map[string][]byte) (map[common.Hash]struct{}, map[common.Hash][]byte, + map[common.Hash]map[common.Hash][]byte) { + hasher := crypto.NewKeccakState() + hashDestructs := make(map[common.Hash]struct{}, len(destructs)) + hashAccounts := make(map[common.Hash][]byte, len(accounts)) + hashStorages := make(map[common.Hash]map[common.Hash][]byte, len(storage)) + for addr := range destructs { + hashDestructs[crypto.Keccak256Hash(addr[:])] = struct{}{} + } + for addr, account := range accounts { + hashAccounts[crypto.Keccak256Hash(addr[:])] = account + } + for addr, accountStore := range storage { + hashStorage := make(map[common.Hash][]byte, len(accountStore)) + for k, v := range accountStore { + hashStorage[crypto.HashData(hasher, []byte(k))] = v + } + hashStorages[crypto.Keccak256Hash(addr[:])] = hashStorage + } + return hashDestructs, hashAccounts, hashStorages +} diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index 4b787cfe2e..f8ced63665 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -105,7 +105,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 2 { @@ -149,10 +149,10 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 3 { @@ -197,13 +197,13 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 4 { @@ -257,12 +257,12 @@ func TestPostCapBasicDataAccess(t *testing.T) { }, } // The lowest difflayer - snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil) - snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil) - snaps.Update(common.HexToHash("0xb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil) + snaps.update(common.HexToHash("0xa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil) + snaps.update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil) + snaps.update(common.HexToHash("0xb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil) - snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil) - snaps.Update(common.HexToHash("0xb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil) + 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 := func(layer *diffLayer, key string) error { @@ -357,7 +357,7 @@ func TestSnaphots(t *testing.T) { ) for i := 0; i < 129; i++ { head = makeRoot(uint64(i + 2)) - snaps.Update(head, last, nil, setAccount(fmt.Sprintf("%d", i+2)), nil) + snaps.update(head, last, nil, setAccount(fmt.Sprintf("%d", i+2)), nil) last = head snaps.Cap(head, 128) // 130 layers (128 diffs + 1 accumulator + 1 disk) } diff --git a/core/state/state_object.go b/core/state/state_object.go index 623d07ac13..298f4305ba 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -234,7 +234,7 @@ func (s *StateObject) GetCommittedState(db Database, key common.Hash) common.Has // 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 { + if _, destructed := s.db.snapDestructs[s.address]; destructed { return common.Hash{} } enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) @@ -345,10 +345,9 @@ func (s *StateObject) updateTrie(db Database) Trie { }(time.Now()) } // The snapshot storage map for the object - var storage map[common.Hash][]byte + var storage map[string][]byte // 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 { @@ -371,12 +370,12 @@ func (s *StateObject) updateTrie(db Database) Trie { s.db.snapMux.Lock() if storage == nil { // Retrieve the old storage map, if available, create a new one otherwise - if storage = s.db.snapStorage[s.addrHash]; storage == nil { - storage = make(map[common.Hash][]byte) - s.db.snapStorage[s.addrHash] = storage + if storage = s.db.snapStorage[s.address]; storage == nil { + storage = make(map[string][]byte) + s.db.snapStorage[s.address] = storage } } - storage[crypto.HashData(hasher, key[:])] = v // v will be nil if value is 0x00 + storage[string(key[:])] = v // v will be nil if value is 0x00 s.db.snapMux.Unlock() } usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure diff --git a/core/state/state_test.go b/core/state/state_test.go index 9f003fefb5..77847772c6 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -167,7 +167,7 @@ func TestSnapshot2(t *testing.T) { so0.deleted = false state.SetStateObject(so0) - root, _ := state.Commit(false) + root, _, _ := state.Commit(false) state, _ = New(root, state.db, state.snaps) // and one with deleted == true diff --git a/core/state/statedb.go b/core/state/statedb.go index 7940613cd6..c68e09490c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -27,6 +27,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" @@ -39,7 +40,7 @@ import ( ) const ( - preLoadLimit = 64 + preLoadLimit = 128 defaultNumOfSlots = 100 ) @@ -72,18 +73,22 @@ 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 + originalRoot common.Hash // The pre-state root, before any changes were made + trie Trie + hasher crypto.KeccakState + diffLayer *types.DiffLayer + diffTries map[common.Address]Trie + diffCode map[common.Hash][]byte + lightProcessed bool snapMux sync.Mutex snaps *snapshot.Tree snap snapshot.Snapshot - snapDestructs map[common.Hash]struct{} - snapAccounts map[common.Hash][]byte - snapStorage map[common.Hash]map[common.Hash][]byte + snapDestructs map[common.Address]struct{} + snapAccounts map[common.Address][]byte + snapStorage map[common.Address]map[string][]byte // This map holds 'live' objects, which will get modified while processing a state transition. stateObjects map[common.Address]*StateObject @@ -156,9 +161,9 @@ func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, sdb.trie = tr 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) + sdb.snapDestructs = make(map[common.Address]struct{}) + sdb.snapAccounts = make(map[common.Address][]byte) + sdb.snapStorage = make(map[common.Address]map[string][]byte) } } return sdb, nil @@ -186,6 +191,15 @@ func (s *StateDB) StopPrefetcher() { } } +// Mark that the block is processed by diff layer +func (s *StateDB) MarkLightProcessed() { + s.lightProcessed = true +} + +func (s *StateDB) IsLightProcessed() bool { + return s.lightProcessed +} + // setError remembers the first non-nil error it is called with. func (s *StateDB) setError(err error) { if s.dbErr == nil { @@ -197,6 +211,19 @@ func (s *StateDB) Error() error { return s.dbErr } +func (s *StateDB) Trie() Trie { + return s.trie +} + +func (s *StateDB) SetDiff(diffLayer *types.DiffLayer, diffTries map[common.Address]Trie, diffCode map[common.Hash][]byte) { + s.diffLayer, s.diffTries, s.diffCode = diffLayer, diffTries, diffCode +} + +func (s *StateDB) SetSnapData(snapDestructs map[common.Address]struct{}, snapAccounts map[common.Address][]byte, + snapStorage map[common.Address]map[string][]byte) { + s.snapDestructs, s.snapAccounts, s.snapStorage = snapDestructs, snapAccounts, snapStorage +} + func (s *StateDB) AddLog(log *types.Log) { s.journal.append(addLogChange{txhash: s.thash}) @@ -532,7 +559,7 @@ func (s *StateDB) TryPreload(block *types.Block, signer types.Signer) { accounts[*tx.To()] = true } } - for account, _ := range accounts { + for account := range accounts { accountsSlice = append(accountsSlice, account) } if len(accountsSlice) >= preLoadLimit && len(accountsSlice) > runtime.NumCPU() { @@ -550,10 +577,8 @@ func (s *StateDB) TryPreload(block *types.Block, signer types.Signer) { } for i := 0; i < runtime.NumCPU(); i++ { objs := <-objsChan - if objs != nil { - for _, obj := range objs { - s.SetStateObject(obj) - } + for _, obj := range objs { + s.SetStateObject(obj) } } } @@ -683,9 +708,9 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *StateObject) var prevdestruct bool if s.snap != nil && prev != nil { - _, prevdestruct = s.snapDestructs[prev.addrHash] + _, prevdestruct = s.snapDestructs[prev.address] if !prevdestruct { - s.snapDestructs[prev.addrHash] = struct{}{} + s.snapDestructs[prev.address] = struct{}{} } } newobj = newObject(s, addr, Account{}) @@ -830,17 +855,17 @@ func (s *StateDB) Copy() *StateDB { state.snaps = s.snaps state.snap = s.snap // deep copy needed - state.snapDestructs = make(map[common.Hash]struct{}) + state.snapDestructs = make(map[common.Address]struct{}) for k, v := range s.snapDestructs { state.snapDestructs[k] = v } - state.snapAccounts = make(map[common.Hash][]byte) + state.snapAccounts = make(map[common.Address][]byte) for k, v := range s.snapAccounts { state.snapAccounts[k] = v } - state.snapStorage = make(map[common.Hash]map[common.Hash][]byte) + state.snapStorage = make(map[common.Address]map[string][]byte) for k, v := range s.snapStorage { - temp := make(map[common.Hash][]byte) + temp := make(map[string][]byte) for kk, vv := range v { temp[kk] = vv } @@ -903,9 +928,9 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // transactions within the same block might self destruct and then // ressurrect 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) + s.snapDestructs[obj.address] = struct{}{} // We need to maintain account deletions explicitly (will remain set indefinitely) + delete(s.snapAccounts, obj.address) // Clear out any previously updated account data (may be recreated via a ressurrect) + delete(s.snapStorage, obj.address) // Clear out any previously updated storage data (may be recreated via a ressurrect) } } else { obj.finalise(true) // Prefetch slots in the background @@ -932,6 +957,9 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // It is called in between transactions to get the root hash that // goes into transaction receipts. func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { + if s.lightProcessed { + return s.trie.Hash() + } // Finalise all the dirty storage states and write them into the tries s.Finalise(deleteEmptyObjects) @@ -983,7 +1011,8 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // at transaction boundary level to ensure we capture state clearing. if s.snap != nil && !obj.deleted { s.snapMux.Lock() - s.snapAccounts[obj.addrHash] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash) + // It is possible to add unnecessary change, but it is fine. + s.snapAccounts[obj.address] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash) s.snapMux.Unlock() } data, err := rlp.EncodeToBytes(obj) @@ -1007,7 +1036,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if s.trie == nil { tr, err := s.db.OpenTrie(s.originalRoot) if err != nil { - panic(fmt.Sprintf("Failed to open trie tree")) + panic("Failed to open trie tree") } s.trie = tr } @@ -1051,14 +1080,143 @@ func (s *StateDB) clearJournalAndRefund() { s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entires } +func (s *StateDB) LightCommit(root common.Hash) (common.Hash, *types.DiffLayer, error) { + codeWriter := s.db.TrieDB().DiskDB().NewBatch() + + commitFuncs := []func() error{ + func() error { + for codeHash, code := range s.diffCode { + rawdb.WriteCode(codeWriter, codeHash, code) + if codeWriter.ValueSize() >= ethdb.IdealBatchSize { + if err := codeWriter.Write(); err != nil { + return err + } + codeWriter.Reset() + } + } + if codeWriter.ValueSize() > 0 { + if err := codeWriter.Write(); err != nil { + return err + } + } + return nil + }, + func() error { + tasks := make(chan func()) + taskResults := make(chan error, len(s.diffTries)) + tasksNum := 0 + finishCh := make(chan struct{}) + defer close(finishCh) + threads := gopool.Threads(len(s.diffTries)) + + for i := 0; i < threads; i++ { + go func() { + for { + select { + case task := <-tasks: + task() + case <-finishCh: + return + } + } + }() + } + + for account, diff := range s.diffTries { + tmpAccount := account + tmpDiff := diff + tasks <- func() { + root, err := tmpDiff.Commit(nil) + if err != nil { + taskResults <- err + return + } + s.db.CacheStorage(crypto.Keccak256Hash(tmpAccount[:]), root, tmpDiff) + taskResults <- nil + } + tasksNum++ + } + + for i := 0; i < tasksNum; i++ { + err := <-taskResults + if err != nil { + return err + } + } + + // commit account trie + var account Account + root, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash) error { + if err := rlp.DecodeBytes(leaf, &account); err != nil { + return nil + } + if account.Root != emptyRoot { + s.db.TrieDB().Reference(account.Root, parent) + } + return nil + }) + if err != nil { + return err + } + if root != emptyRoot { + s.db.CacheAccount(root, s.trie) + } + return nil + }, + func() error { + if s.snap != nil { + if metrics.EnabledExpensive { + defer func(start time.Time) { s.SnapshotCommits += time.Since(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 { + log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) + } + // Keep n diff layers in the memory + // - head layer is paired with HEAD state + // - head-1 layer is paired with HEAD-1 state + // - head-(n-1) layer(bottom-most diff layer) is paired with HEAD-(n-1)state + if err := s.snaps.Cap(root, s.snaps.CapLimit()); err != nil { + log.Warn("Failed to cap snapshot tree", "root", root, "layers", s.snaps.CapLimit(), "err", err) + } + } + } + return nil + }, + } + commitRes := make(chan error, len(commitFuncs)) + for _, f := range commitFuncs { + tmpFunc := f + go func() { + commitRes <- tmpFunc() + }() + } + for i := 0; i < len(commitFuncs); i++ { + r := <-commitRes + if r != nil { + return common.Hash{}, nil, r + } + } + s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil + s.diffTries, s.diffCode = nil, nil + return root, s.diffLayer, nil +} + // Commit writes the state to the underlying in-memory trie database. -func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { +func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer, error) { if s.dbErr != nil { - return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) + return common.Hash{}, nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) } // Finalize any pending changes and merge everything into the tries root := s.IntermediateRoot(deleteEmptyObjects) - + if s.lightProcessed { + return s.LightCommit(root) + } + var diffLayer *types.DiffLayer + if s.snap != nil { + diffLayer = &types.DiffLayer{} + } commitFuncs := []func() error{ func() error { // Commit objects to the trie, measuring the elapsed time @@ -1066,9 +1224,13 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { taskResults := make(chan error, len(s.stateObjectsDirty)) tasksNum := 0 finishCh := make(chan struct{}) - defer close(finishCh) - for i := 0; i < runtime.NumCPU(); i++ { + + threads := gopool.Threads(len(s.stateObjectsDirty)) + wg := sync.WaitGroup{} + for i := 0; i < threads; i++ { + wg.Add(1) go func() { + defer wg.Done() codeWriter := s.db.TrieDB().DiskDB().NewBatch() for { select { @@ -1086,6 +1248,19 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { }() } + if s.snap != nil { + for addr := range s.stateObjectsDirty { + if obj := s.stateObjects[addr]; !obj.deleted { + if obj.code != nil && obj.dirtyCode { + diffLayer.Codes = append(diffLayer.Codes, types.DiffCode{ + Hash: common.BytesToHash(obj.CodeHash()), + Code: obj.code, + }) + } + } + } + } + for addr := range s.stateObjectsDirty { if obj := s.stateObjects[addr]; !obj.deleted { // Write any contract code associated with the state object @@ -1107,9 +1282,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { for i := 0; i < tasksNum; i++ { err := <-taskResults if err != nil { + close(finishCh) return err } } + close(finishCh) if len(s.stateObjectsDirty) > 0 { s.stateObjectsDirty = make(map[common.Address]struct{}, len(s.stateObjectsDirty)/2) @@ -1140,6 +1317,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if root != emptyRoot { s.db.CacheAccount(root, s.trie) } + wg.Wait() return nil }, func() error { @@ -1161,7 +1339,12 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { log.Warn("Failed to cap snapshot tree", "root", root, "layers", s.snaps.CapLimit(), "err", err) } } - s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil + } + return nil + }, + func() error { + if s.snap != nil { + diffLayer.Destructs, diffLayer.Accounts, diffLayer.Storages = s.SnapToDiffLayer() } return nil }, @@ -1176,11 +1359,65 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { for i := 0; i < len(commitFuncs); i++ { r := <-commitRes if r != nil { - return common.Hash{}, r + return common.Hash{}, nil, r } } + s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil + return root, diffLayer, nil +} - return root, nil +func (s *StateDB) DiffLayerToSnap(diffLayer *types.DiffLayer) (map[common.Address]struct{}, map[common.Address][]byte, map[common.Address]map[string][]byte, error) { + snapDestructs := make(map[common.Address]struct{}) + snapAccounts := make(map[common.Address][]byte) + snapStorage := make(map[common.Address]map[string][]byte) + + for _, des := range diffLayer.Destructs { + snapDestructs[des] = struct{}{} + } + for _, account := range diffLayer.Accounts { + snapAccounts[account.Account] = account.Blob + } + for _, storage := range diffLayer.Storages { + // should never happen + if len(storage.Keys) != len(storage.Vals) { + return nil, nil, nil, errors.New("invalid diffLayer: length of keys and values mismatch") + } + snapStorage[storage.Account] = make(map[string][]byte, len(storage.Keys)) + n := len(storage.Keys) + for i := 0; i < n; i++ { + snapStorage[storage.Account][storage.Keys[i]] = storage.Vals[i] + } + } + return snapDestructs, snapAccounts, snapStorage, nil +} + +func (s *StateDB) SnapToDiffLayer() ([]common.Address, []types.DiffAccount, []types.DiffStorage) { + destructs := make([]common.Address, 0, len(s.snapDestructs)) + for account := range s.snapDestructs { + destructs = append(destructs, account) + } + accounts := make([]types.DiffAccount, 0, len(s.snapAccounts)) + for accountHash, account := range s.snapAccounts { + accounts = append(accounts, types.DiffAccount{ + Account: accountHash, + Blob: account, + }) + } + storages := make([]types.DiffStorage, 0, len(s.snapStorage)) + for accountHash, storage := range s.snapStorage { + keys := make([]string, 0, len(storage)) + values := make([][]byte, 0, len(storage)) + for k, v := range storage { + keys = append(keys, k) + values = append(values, v) + } + storages = append(storages, types.DiffStorage{ + Account: accountHash, + Keys: keys, + Vals: values, + }) + } + return destructs, accounts, storages } // PrepareAccessList handles the preparatory steps for executing a state transition with diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 9524e3730d..2c0b9296ff 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -102,7 +102,7 @@ func TestIntermediateLeaks(t *testing.T) { } // Commit and cross check the databases. - transRoot, err := transState.Commit(false) + transRoot, _, err := transState.Commit(false) if err != nil { t.Fatalf("failed to commit transition state: %v", err) } @@ -110,7 +110,7 @@ func TestIntermediateLeaks(t *testing.T) { t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) } - finalRoot, err := finalState.Commit(false) + finalRoot, _, err := finalState.Commit(false) if err != nil { t.Fatalf("failed to commit final state: %v", err) } @@ -473,7 +473,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { func TestTouchDelete(t *testing.T) { s := newStateTest() s.state.GetOrNewStateObject(common.Address{}) - root, _ := s.state.Commit(false) + root, _, _ := s.state.Commit(false) s.state, _ = New(root, s.state.db, s.state.snaps) snapshot := s.state.Snapshot() @@ -675,7 +675,7 @@ func TestDeleteCreateRevert(t *testing.T) { addr := common.BytesToAddress([]byte("so")) state.SetBalance(addr, big.NewInt(1)) - root, _ := state.Commit(false) + root, _, _ := state.Commit(false) state, _ = New(root, state.db, state.snaps) // Simulate self-destructing in one transaction, then create-reverting in another @@ -687,7 +687,7 @@ func TestDeleteCreateRevert(t *testing.T) { state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state - root, _ = state.Commit(true) + root, _, _ = state.Commit(true) state, _ = New(root, state.db, state.snaps) if state.getStateObject(addr) != nil { @@ -712,7 +712,7 @@ func TestMissingTrieNodes(t *testing.T) { a2 := common.BytesToAddress([]byte("another")) state.SetBalance(a2, big.NewInt(100)) state.SetCode(a2, []byte{1, 2, 4}) - root, _ = state.Commit(false) + root, _, _ = state.Commit(false) t.Logf("root: %x", root) // force-flush state.Database().TrieDB().Cap(0) @@ -736,7 +736,7 @@ func TestMissingTrieNodes(t *testing.T) { } // Modify the state state.SetBalance(addr, big.NewInt(2)) - root, err := state.Commit(false) + root, _, err := state.Commit(false) if err == nil { t.Fatalf("expected error, got root :%x", root) } diff --git a/core/state/sync_test.go b/core/state/sync_test.go index a13fcf56a3..24cae59004 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -69,7 +69,7 @@ func makeTestState() (Database, common.Hash, []*testAccount) { state.updateStateObject(obj) accounts = append(accounts, acc) } - root, _ := state.Commit(false) + root, _, _ := state.Commit(false) // Return the generated state return db, root, accounts diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 05394321f7..dacd8df404 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -35,15 +35,6 @@ type statePrefetcher struct { engine consensus.Engine // Consensus engine used for block rewards } -// newStatePrefetcher initialises a new statePrefetcher. -func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *statePrefetcher { - return &statePrefetcher{ - config: config, - bc: bc, - engine: engine, - } -} - // 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. diff --git a/core/state_processor.go b/core/state_processor.go index 858796b67a..973fd27b54 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,17 +17,36 @@ package core import ( + "bytes" + "errors" "fmt" + "math/big" + "math/rand" + "sync" + "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/gopool" "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/state/snapshot" "github.com/ethereum/go-ethereum/core/systemcontracts" "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/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" +) + +const ( + fullProcessCheck = 21 // On diff sync mode, will do full process every fullProcessCheck randomly + minNumberOfAccountPerTask = 5 + recentTime = 2048 * 3 + recentDiffLayerTimeout = 20 + farDiffLayerTimeout = 2 ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -49,6 +68,301 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen } } +type LightStateProcessor struct { + randomGenerator *rand.Rand + StateProcessor +} + +func NewLightStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *LightStateProcessor { + randomGenerator := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) + return &LightStateProcessor{ + randomGenerator: randomGenerator, + StateProcessor: *NewStateProcessor(config, bc, engine), + } +} + +func (p *LightStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) { + allowLightProcess := true + if posa, ok := p.engine.(consensus.PoSA); ok { + allowLightProcess = posa.AllowLightProcess(p.bc, block.Header()) + } + // random fallback to full process + if check := p.randomGenerator.Int63n(fullProcessCheck); allowLightProcess && check != 0 && len(block.Transactions()) != 0 { + var pid string + if peer, ok := block.ReceivedFrom.(PeerIDer); ok { + pid = peer.ID() + } + var diffLayer *types.DiffLayer + var diffLayerTimeout = recentDiffLayerTimeout + if time.Now().Unix()-int64(block.Time()) > recentTime { + diffLayerTimeout = farDiffLayerTimeout + } + for tried := 0; tried < diffLayerTimeout; tried++ { + // wait a bit for the diff layer + diffLayer = p.bc.GetUnTrustedDiffLayer(block.Hash(), pid) + if diffLayer != nil { + break + } + time.Sleep(time.Millisecond) + } + if diffLayer != nil { + if err := diffLayer.Receipts.DeriveFields(p.bc.chainConfig, block.Hash(), block.NumberU64(), block.Transactions()); err != nil { + log.Error("Failed to derive block receipts fields", "hash", block.Hash(), "number", block.NumberU64(), "err", err) + // fallback to full process + return p.StateProcessor.Process(block, statedb, cfg) + } + + receipts, logs, gasUsed, err := p.LightProcess(diffLayer, block, statedb) + if err == nil { + log.Info("do light process success at block", "num", block.NumberU64()) + return statedb, receipts, logs, gasUsed, nil + } + log.Error("do light process err at block", "num", block.NumberU64(), "err", err) + p.bc.removeDiffLayers(diffLayer.DiffHash) + // prepare new statedb + statedb.StopPrefetcher() + parent := p.bc.GetHeader(block.ParentHash(), block.NumberU64()-1) + statedb, err = state.New(parent.Root, p.bc.stateCache, p.bc.snaps) + if err != nil { + return statedb, nil, nil, 0, err + } + // Enable prefetching to pull in trie node paths while processing transactions + statedb.StartPrefetcher("chain") + } + } + // fallback to full process + return p.StateProcessor.Process(block, statedb, cfg) +} + +func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *types.Block, statedb *state.StateDB) (types.Receipts, []*types.Log, uint64, error) { + statedb.MarkLightProcessed() + fullDiffCode := make(map[common.Hash][]byte, len(diffLayer.Codes)) + diffTries := make(map[common.Address]state.Trie) + diffCode := make(map[common.Hash][]byte) + + snapDestructs, snapAccounts, snapStorage, err := statedb.DiffLayerToSnap(diffLayer) + if err != nil { + return nil, nil, 0, err + } + + for _, c := range diffLayer.Codes { + fullDiffCode[c.Hash] = c.Code + } + + for des := range snapDestructs { + statedb.Trie().TryDelete(des[:]) + } + threads := gopool.Threads(len(snapAccounts)) + + iteAccounts := make([]common.Address, 0, len(snapAccounts)) + for diffAccount := range snapAccounts { + iteAccounts = append(iteAccounts, diffAccount) + } + + errChan := make(chan error, threads) + exitChan := make(chan struct{}) + var snapMux sync.RWMutex + var stateMux, diffMux sync.Mutex + for i := 0; i < threads; i++ { + start := i * len(iteAccounts) / threads + end := (i + 1) * len(iteAccounts) / threads + if i+1 == threads { + end = len(iteAccounts) + } + go func(start, end int) { + for index := start; index < end; index++ { + select { + // fast fail + case <-exitChan: + return + default: + } + diffAccount := iteAccounts[index] + snapMux.RLock() + blob := snapAccounts[diffAccount] + snapMux.RUnlock() + addrHash := crypto.Keccak256Hash(diffAccount[:]) + latestAccount, err := snapshot.FullAccount(blob) + if err != nil { + errChan <- err + return + } + + // fetch previous state + var previousAccount state.Account + stateMux.Lock() + enc, err := statedb.Trie().TryGet(diffAccount[:]) + stateMux.Unlock() + if err != nil { + errChan <- err + return + } + if len(enc) != 0 { + if err := rlp.DecodeBytes(enc, &previousAccount); err != nil { + errChan <- err + return + } + } + if latestAccount.Balance == nil { + latestAccount.Balance = new(big.Int) + } + if previousAccount.Balance == nil { + previousAccount.Balance = new(big.Int) + } + if previousAccount.Root == (common.Hash{}) { + previousAccount.Root = types.EmptyRootHash + } + if len(previousAccount.CodeHash) == 0 { + previousAccount.CodeHash = types.EmptyCodeHash + } + + // skip no change account + if previousAccount.Nonce == latestAccount.Nonce && + bytes.Equal(previousAccount.CodeHash, latestAccount.CodeHash) && + previousAccount.Balance.Cmp(latestAccount.Balance) == 0 && + previousAccount.Root == common.BytesToHash(latestAccount.Root) { + // It is normal to receive redundant message since the collected message is redundant. + log.Debug("receive redundant account change in diff layer", "account", diffAccount, "num", block.NumberU64()) + snapMux.Lock() + delete(snapAccounts, diffAccount) + delete(snapStorage, diffAccount) + snapMux.Unlock() + continue + } + + // update code + codeHash := common.BytesToHash(latestAccount.CodeHash) + if !bytes.Equal(latestAccount.CodeHash, previousAccount.CodeHash) && + !bytes.Equal(latestAccount.CodeHash, types.EmptyCodeHash) { + if code, exist := fullDiffCode[codeHash]; exist { + if crypto.Keccak256Hash(code) != codeHash { + errChan <- fmt.Errorf("code and code hash mismatch, account %s", diffAccount.String()) + return + } + diffMux.Lock() + diffCode[codeHash] = code + diffMux.Unlock() + } else { + rawCode := rawdb.ReadCode(p.bc.db, codeHash) + if len(rawCode) == 0 { + errChan <- fmt.Errorf("missing code, account %s", diffAccount.String()) + return + } + } + } + + //update storage + latestRoot := common.BytesToHash(latestAccount.Root) + if latestRoot != previousAccount.Root && latestRoot != types.EmptyRootHash { + accountTrie, err := statedb.Database().OpenStorageTrie(addrHash, previousAccount.Root) + if err != nil { + errChan <- err + return + } + snapMux.RLock() + storageChange, exist := snapStorage[diffAccount] + snapMux.RUnlock() + + if !exist { + errChan <- errors.New("missing storage change in difflayer") + return + } + for k, v := range storageChange { + if len(v) != 0 { + accountTrie.TryUpdate([]byte(k), v) + } else { + accountTrie.TryDelete([]byte(k)) + } + } + + // check storage root + accountRootHash := accountTrie.Hash() + if latestRoot != accountRootHash { + errChan <- errors.New("account storage root mismatch") + return + } + diffMux.Lock() + diffTries[diffAccount] = accountTrie + diffMux.Unlock() + } else { + snapMux.Lock() + delete(snapStorage, diffAccount) + snapMux.Unlock() + } + + // can't trust the blob, need encode by our-self. + latestStateAccount := state.Account{ + Nonce: latestAccount.Nonce, + Balance: latestAccount.Balance, + Root: common.BytesToHash(latestAccount.Root), + CodeHash: latestAccount.CodeHash, + } + bz, err := rlp.EncodeToBytes(&latestStateAccount) + if err != nil { + errChan <- err + return + } + stateMux.Lock() + err = statedb.Trie().TryUpdate(diffAccount[:], bz) + stateMux.Unlock() + if err != nil { + errChan <- err + return + } + } + errChan <- nil + }(start, end) + } + + for i := 0; i < threads; i++ { + err := <-errChan + if err != nil { + close(exitChan) + return nil, nil, 0, err + } + } + + var allLogs []*types.Log + var gasUsed uint64 + for _, receipt := range diffLayer.Receipts { + allLogs = append(allLogs, receipt.Logs...) + gasUsed += receipt.GasUsed + } + + // Do validate in advance so that we can fall back to full process + if err := p.bc.validator.ValidateState(block, statedb, diffLayer.Receipts, gasUsed); err != nil { + log.Error("validate state failed during diff sync", "error", err) + return nil, nil, 0, err + } + + // remove redundant storage change + for account := range snapStorage { + if _, exist := snapAccounts[account]; !exist { + log.Warn("receive redundant storage change in diff layer") + delete(snapStorage, account) + } + } + + // remove redundant code + if len(fullDiffCode) != len(diffLayer.Codes) { + diffLayer.Codes = make([]types.DiffCode, 0, len(diffCode)) + for hash, code := range diffCode { + diffLayer.Codes = append(diffLayer.Codes, types.DiffCode{ + Hash: hash, + Code: code, + }) + } + } + + statedb.SetSnapData(snapDestructs, snapAccounts, snapStorage) + if len(snapAccounts) != len(diffLayer.Accounts) || len(snapStorage) != len(diffLayer.Storages) { + diffLayer.Destructs, diffLayer.Accounts, diffLayer.Storages = statedb.SnapToDiffLayer() + } + statedb.SetDiff(diffLayer, diffTries, diffCode) + + return diffLayer.Receipts, allLogs, gasUsed, nil +} + // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. @@ -56,13 +370,15 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) { var ( usedGas = new(uint64) header = block.Header() allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) ) + signer := types.MakeSigner(p.bc.chainConfig, block.Number()) + statedb.TryPreload(block, signer) var receipts = make([]*types.Receipt, 0) // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { @@ -79,11 +395,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg commonTxs := make([]*types.Transaction, 0, len(block.Transactions())) // usually do have two tx, one for validator set contract, another for system reward contract. systemTxs := make([]*types.Transaction, 0, 2) - signer := types.MakeSigner(p.config, header.Number) for i, tx := range block.Transactions() { if isPoSA { if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { - return nil, nil, 0, err + return statedb, nil, nil, 0, err } else if isSystemTx { systemTxs = append(systemTxs, tx) continue @@ -92,12 +407,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg msg, err := tx.AsMessage(signer) if err != nil { - return nil, nil, 0, err + return statedb, nil, nil, 0, err } statedb.Prepare(tx.Hash(), block.Hash(), i) receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv) if err != nil { - return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return statedb, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } commonTxs = append(commonTxs, tx) @@ -107,13 +422,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) err := p.engine.Finalize(p.bc, header, statedb, &commonTxs, block.Uncles(), &receipts, &systemTxs, usedGas) if err != nil { - return receipts, allLogs, *usedGas, err + return statedb, receipts, allLogs, *usedGas, err } for _, receipt := range receipts { allLogs = append(allLogs, receipt.Logs...) } - return receipts, allLogs, *usedGas, nil + return statedb, receipts, allLogs, *usedGas, nil } func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { diff --git a/core/types.go b/core/types.go index 4c5b74a498..49bd58e086 100644 --- a/core/types.go +++ b/core/types.go @@ -47,5 +47,5 @@ type Processor interface { // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) } diff --git a/core/types/block.go b/core/types/block.go index b33493ef7d..a577e60516 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -19,6 +19,7 @@ package types import ( "encoding/binary" + "errors" "fmt" "io" "math/big" @@ -28,11 +29,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" ) var ( - EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + EmptyCodeHash = crypto.Keccak256(nil) + EmptyUncleHash = rlpHash([]*Header(nil)) ) @@ -366,3 +370,86 @@ func (b *Block) Hash() common.Hash { } type Blocks []*Block + +type DiffLayer struct { + BlockHash common.Hash + Number uint64 + Receipts Receipts // Receipts are duplicated stored to simplify the logic + Codes []DiffCode + Destructs []common.Address + Accounts []DiffAccount + Storages []DiffStorage + + DiffHash common.Hash +} + +type extDiffLayer struct { + BlockHash common.Hash + Number uint64 + Receipts []*ReceiptForStorage // Receipts are duplicated stored to simplify the logic + Codes []DiffCode + Destructs []common.Address + Accounts []DiffAccount + Storages []DiffStorage +} + +// DecodeRLP decodes the Ethereum +func (d *DiffLayer) DecodeRLP(s *rlp.Stream) error { + var ed extDiffLayer + if err := s.Decode(&ed); err != nil { + return err + } + d.BlockHash, d.Number, d.Codes, d.Destructs, d.Accounts, d.Storages = + ed.BlockHash, ed.Number, ed.Codes, ed.Destructs, ed.Accounts, ed.Storages + + d.Receipts = make([]*Receipt, len(ed.Receipts)) + for i, storageReceipt := range ed.Receipts { + d.Receipts[i] = (*Receipt)(storageReceipt) + } + return nil +} + +// EncodeRLP serializes b into the Ethereum RLP block format. +func (d *DiffLayer) EncodeRLP(w io.Writer) error { + storageReceipts := make([]*ReceiptForStorage, len(d.Receipts)) + for i, receipt := range d.Receipts { + storageReceipts[i] = (*ReceiptForStorage)(receipt) + } + return rlp.Encode(w, extDiffLayer{ + BlockHash: d.BlockHash, + Number: d.Number, + Receipts: storageReceipts, + Codes: d.Codes, + Destructs: d.Destructs, + Accounts: d.Accounts, + Storages: d.Storages, + }) +} + +func (d *DiffLayer) Validate() error { + if d.BlockHash == (common.Hash{}) { + return errors.New("blockHash can't be empty") + } + for _, storage := range d.Storages { + if len(storage.Keys) != len(storage.Vals) { + return errors.New("the length of keys and values mismatch in storage") + } + } + return nil +} + +type DiffCode struct { + Hash common.Hash + Code []byte +} + +type DiffAccount struct { + Account common.Address + Blob []byte +} + +type DiffStorage struct { + Account common.Address + Keys []string + Vals [][]byte +} diff --git a/core/vm/contracts_lightclient_test.go b/core/vm/contracts_lightclient_test.go index cf17c03559..e1634be809 100644 --- a/core/vm/contracts_lightclient_test.go +++ b/core/vm/contracts_lightclient_test.go @@ -10,7 +10,7 @@ import ( ) const ( - testHeight uint64 = 66848226 + testHeight uint64 = 66848226 ) func TestTmHeaderValidateAndMerkleProofValidate(t *testing.T) { diff --git a/core/vm/lightclient/types.go b/core/vm/lightclient/types.go index 406d428e74..6006fe04d4 100644 --- a/core/vm/lightclient/types.go +++ b/core/vm/lightclient/types.go @@ -103,7 +103,7 @@ func (cs ConsensusState) EncodeConsensusState() ([]byte, error) { copy(encodingBytes[pos:pos+chainIDLength], cs.ChainID) pos += chainIDLength - binary.BigEndian.PutUint64(encodingBytes[pos:pos+heightLength], uint64(cs.Height)) + binary.BigEndian.PutUint64(encodingBytes[pos:pos+heightLength], cs.Height) pos += heightLength copy(encodingBytes[pos:pos+appHashLength], cs.AppHash) diff --git a/eth/backend.go b/eth/backend.go index b52591fd71..bdae4b4235 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -42,6 +42,7 @@ import ( "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/diff" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/ethdb" @@ -128,7 +129,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { ethashConfig.NotifyFull = config.Miner.NotifyFull // Assemble the Ethereum object - chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false) + chainDb, err := stack.OpenAndMergeDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles, + config.DatabaseFreezer, config.DatabaseDiff, "eth/db/chaindata/", false, config.PersistDiff) if err != nil { return nil, err } @@ -197,7 +199,14 @@ 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) + bcOps := make([]core.BlockChainOption, 0) + if config.DiffSync { + bcOps = append(bcOps, core.EnableLightProcessor) + } + if config.PersistDiff { + bcOps = append(bcOps, core.EnablePersistDiff(config.DiffBlock)) + } + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit, bcOps...) if err != nil { return nil, err } @@ -232,6 +241,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Checkpoint: checkpoint, Whitelist: config.Whitelist, DirectBroadcast: config.DirectBroadcast, + DiffSync: config.DiffSync, }); err != nil { return nil, err } @@ -534,9 +544,11 @@ func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } // network protocols to start. func (s *Ethereum) Protocols() []p2p.Protocol { protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) - if s.config.SnapshotCache > 0 { + if !s.config.DisableSnapProtocol && s.config.SnapshotCache > 0 { protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) } + // diff protocol can still open without snap protocol + protos = append(protos, diff.MakeProtocols((*diffHandler)(s.handler), s.snapDialCandidates)...) return protos } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 3dee90c424..55be200d59 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -161,10 +161,10 @@ type Downloader struct { quitLock sync.Mutex // Lock to prevent double closes // Testing hooks - syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run - 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) + syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run + bodyFetchHook func([]*types.Header, ...interface{}) // Method to call upon starting a block body fetch + receiptFetchHook func([]*types.Header, ...interface{}) // Method to call upon starting a receipt fetch + chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations) } // LightChain encapsulates functions required to synchronise a light chain. @@ -220,8 +220,45 @@ type BlockChain interface { Snapshots() *snapshot.Tree } +type DownloadOption func(downloader *Downloader) *Downloader + +type IDiffPeer interface { + RequestDiffLayers([]common.Hash) error +} + +type IPeerSet interface { + GetDiffPeer(string) IDiffPeer +} + +func EnableDiffFetchOp(peers IPeerSet) DownloadOption { + return func(dl *Downloader) *Downloader { + var hook = func(headers []*types.Header, args ...interface{}) { + if len(args) < 2 { + return + } + peerID, ok := args[1].(string) + if !ok { + return + } + mode, ok := args[0].(SyncMode) + if !ok { + return + } + if ep := peers.GetDiffPeer(peerID); mode == FullSync && ep != nil { + hashes := make([]common.Hash, 0, len(headers)) + for _, header := range headers { + hashes = append(hashes, header.Hash()) + } + ep.RequestDiffLayers(hashes) + } + } + dl.bodyFetchHook = hook + return dl + } +} + // New creates a new downloader to fetch hashes and blocks from remote peers. -func New(checkpoint uint64, stateDb ethdb.Database, stateBloom *trie.SyncBloom, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn) *Downloader { +func New(checkpoint uint64, stateDb ethdb.Database, stateBloom *trie.SyncBloom, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, options ...DownloadOption) *Downloader { if lightchain == nil { lightchain = chain } @@ -252,6 +289,11 @@ func New(checkpoint uint64, stateDb ethdb.Database, stateBloom *trie.SyncBloom, }, trackStateReq: make(chan *stateReq), } + for _, option := range options { + if dl != nil { + dl = option(dl) + } + } go dl.qosTuner() go dl.stateFetcher() return dl @@ -1363,7 +1405,7 @@ func (d *Downloader) fetchReceipts(from uint64) error { // - 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, + fetchHook func([]*types.Header, ...interface{}), 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 @@ -1512,7 +1554,7 @@ func (d *Downloader) fetchParts(deliveryCh chan dataPack, deliver func(dataPack) } // Fetch the chunk and make sure any errors return the hashes to the queue if fetchHook != nil { - fetchHook(request.Headers) + fetchHook(request.Headers, d.getMode(), peer.id) } if err := fetch(peer, request); err != nil { // Although we could try and make an attempt to fix this, this error really diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 794160993b..66f6872025 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -921,10 +921,10 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { // Instrument the downloader to signal body requests bodiesHave, receiptsHave := int32(0), int32(0) - tester.downloader.bodyFetchHook = func(headers []*types.Header) { + tester.downloader.bodyFetchHook = func(headers []*types.Header, _ ...interface{}) { atomic.AddInt32(&bodiesHave, int32(len(headers))) } - tester.downloader.receiptFetchHook = func(headers []*types.Header) { + tester.downloader.receiptFetchHook = func(headers []*types.Header, _ ...interface{}) { atomic.AddInt32(&receiptsHave, int32(len(headers))) } // Synchronise with the peer and make sure all blocks were retrieved diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 40dece429a..bf143ba02c 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -80,6 +80,7 @@ var Defaults = Config{ TrieTimeout: 60 * time.Minute, TriesInMemory: 128, SnapshotCache: 102, + DiffBlock: uint64(864000), Miner: miner.Config{ GasFloor: 8000000, GasCeil: 8000000, @@ -131,9 +132,11 @@ type Config struct { EthDiscoveryURLs []string SnapDiscoveryURLs []string - NoPruning bool // Whether to disable pruning and flush everything to disk - DirectBroadcast bool - RangeLimit bool + NoPruning bool // Whether to disable pruning and flush everything to disk + DirectBroadcast bool + DisableSnapProtocol bool //Whether disable snap protocol + DiffSync bool // Whether support diff sync + RangeLimit bool TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. @@ -159,6 +162,9 @@ type Config struct { DatabaseHandles int `toml:"-"` DatabaseCache int DatabaseFreezer string + DatabaseDiff string + PersistDiff bool + DiffBlock uint64 TrieCleanCache int TrieCleanCacheJournal string `toml:",omitempty"` // Disk journal directory for trie cache to survive node restarts diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index fa31b78335..258ade2293 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -40,6 +40,7 @@ func (c Config) MarshalTOML() (interface{}, error) { DatabaseHandles int `toml:"-"` DatabaseCache int DatabaseFreezer string + DatabaseDiff string TrieCleanCache int TrieCleanCacheJournal string `toml:",omitempty"` TrieCleanCacheRejournal time.Duration `toml:",omitempty"` @@ -48,6 +49,8 @@ func (c Config) MarshalTOML() (interface{}, error) { TriesInMemory uint64 `toml:",omitempty"` SnapshotCache int Preimages bool + PersistDiff bool + DiffBlock uint64 `toml:",omitempty"` Miner miner.Config Ethash ethash.Config TxPool core.TxPoolConfig @@ -84,6 +87,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.DatabaseHandles = c.DatabaseHandles enc.DatabaseCache = c.DatabaseCache enc.DatabaseFreezer = c.DatabaseFreezer + enc.DatabaseDiff = c.DatabaseDiff enc.TrieCleanCache = c.TrieCleanCache enc.TrieCleanCacheJournal = c.TrieCleanCacheJournal enc.TrieCleanCacheRejournal = c.TrieCleanCacheRejournal @@ -92,6 +96,8 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.TriesInMemory = c.TriesInMemory enc.SnapshotCache = c.SnapshotCache enc.Preimages = c.Preimages + enc.PersistDiff = c.PersistDiff + enc.DiffBlock = c.DiffBlock enc.Miner = c.Miner enc.Ethash = c.Ethash enc.TxPool = c.TxPool @@ -133,6 +139,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { DatabaseHandles *int `toml:"-"` DatabaseCache *int DatabaseFreezer *string + DatabaseDiff *string + PersistDiff *bool + DiffBlock *uint64 `toml:",omitempty"` TrieCleanCache *int TrieCleanCacheJournal *string `toml:",omitempty"` TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` @@ -224,6 +233,15 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.DatabaseFreezer != nil { c.DatabaseFreezer = *dec.DatabaseFreezer } + if dec.DatabaseDiff != nil { + c.DatabaseDiff = *dec.DatabaseDiff + } + if dec.PersistDiff != nil { + c.PersistDiff = *dec.PersistDiff + } + if dec.DiffBlock != nil { + c.DiffBlock = *dec.DiffBlock + } if dec.TrieCleanCache != nil { c.TrieCleanCache = *dec.TrieCleanCache } diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index 4819e9eab5..4007fee650 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -82,6 +82,9 @@ type headerRequesterFn func(common.Hash) error // bodyRequesterFn is a callback type for sending a body retrieval request. type bodyRequesterFn func([]common.Hash) error +// DiffRequesterFn is a callback type for sending a diff layer retrieval request. +type DiffRequesterFn func([]common.Hash) error + // headerVerifierFn is a callback type to verify a block's header for fast propagation. type headerVerifierFn func(header *types.Header) error @@ -112,6 +115,8 @@ type blockAnnounce struct { fetchHeader headerRequesterFn // Fetcher function to retrieve the header of an announced block fetchBodies bodyRequesterFn // Fetcher function to retrieve the body of an announced block + fetchDiffs DiffRequesterFn // Fetcher function to retrieve the diff layer of an announced block + } // headerFilterTask represents a batch of headers needing fetcher filtering. @@ -246,7 +251,7 @@ func (f *BlockFetcher) Stop() { // Notify announces the fetcher of the potential availability of a new block in // the network. func (f *BlockFetcher) Notify(peer string, hash common.Hash, number uint64, time time.Time, - headerFetcher headerRequesterFn, bodyFetcher bodyRequesterFn) error { + headerFetcher headerRequesterFn, bodyFetcher bodyRequesterFn, diffFetcher DiffRequesterFn) error { block := &blockAnnounce{ hash: hash, number: number, @@ -254,6 +259,7 @@ func (f *BlockFetcher) Notify(peer string, hash common.Hash, number uint64, time origin: peer, fetchHeader: headerFetcher, fetchBodies: bodyFetcher, + fetchDiffs: diffFetcher, } select { case f.notify <- block: @@ -481,10 +487,15 @@ func (f *BlockFetcher) loop() { // Create a closure of the fetch and schedule in on a new thread fetchHeader, hashes := f.fetching[hashes[0]].fetchHeader, hashes + fetchDiff := f.fetching[hashes[0]].fetchDiffs + gopool.Submit(func() { if f.fetchingHook != nil { f.fetchingHook(hashes) } + if fetchDiff != nil { + fetchDiff(hashes) + } for _, hash := range hashes { headerFetchMeter.Mark(1) fetchHeader(hash) // Suboptimal, but protocol doesn't allow batch header retrievals diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index a6eef71da0..9a40d4cb3e 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -343,7 +343,7 @@ func testSequentialAnnouncements(t *testing.T, light bool) { } } for i := len(hashes) - 2; i >= 0; i-- { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) verifyImportEvent(t, imported, true) } verifyImportDone(t, imported) @@ -392,9 +392,9 @@ func testConcurrentAnnouncements(t *testing.T, light bool) { } } for i := len(hashes) - 2; i >= 0; i-- { - tester.fetcher.Notify("first", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), firstHeaderWrapper, firstBodyFetcher) - tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout+time.Millisecond), secondHeaderWrapper, secondBodyFetcher) - tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout-time.Millisecond), secondHeaderWrapper, secondBodyFetcher) + tester.fetcher.Notify("first", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), firstHeaderWrapper, firstBodyFetcher, nil) + tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout+time.Millisecond), secondHeaderWrapper, secondBodyFetcher, nil) + tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout-time.Millisecond), secondHeaderWrapper, secondBodyFetcher, nil) verifyImportEvent(t, imported, true) } verifyImportDone(t, imported) @@ -441,7 +441,7 @@ func testOverlappingAnnouncements(t *testing.T, light bool) { } for i := len(hashes) - 2; i >= 0; i-- { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) select { case <-imported: case <-time.After(time.Second): @@ -488,7 +488,7 @@ func testPendingDeduplication(t *testing.T, light bool) { } // Announce the same block many times until it's fetched (wait for any pending ops) for checkNonExist() { - tester.fetcher.Notify("repeater", hashes[0], 1, time.Now().Add(-arriveTimeout), headerWrapper, bodyFetcher) + tester.fetcher.Notify("repeater", hashes[0], 1, time.Now().Add(-arriveTimeout), headerWrapper, bodyFetcher, nil) time.Sleep(time.Millisecond) } time.Sleep(delay) @@ -532,12 +532,12 @@ func testRandomArrivalImport(t *testing.T, light bool) { } for i := len(hashes) - 1; i >= 0; i-- { if i != skip { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) time.Sleep(time.Millisecond) } } // Finally announce the skipped entry and check full import - tester.fetcher.Notify("valid", hashes[skip], uint64(len(hashes)-skip-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("valid", hashes[skip], uint64(len(hashes)-skip-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) verifyImportCount(t, imported, len(hashes)-1) verifyChainHeight(t, tester, uint64(len(hashes)-1)) } @@ -560,7 +560,7 @@ func TestQueueGapFill(t *testing.T) { for i := len(hashes) - 1; i >= 0; i-- { if i != skip { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) time.Sleep(time.Millisecond) } } @@ -593,7 +593,7 @@ func TestImportDeduplication(t *testing.T) { tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block } // Announce the duplicating block, wait for retrieval, and also propagate directly - tester.fetcher.Notify("valid", hashes[0], 1, time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("valid", hashes[0], 1, time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) <-fetching tester.fetcher.Enqueue("valid", blocks[hashes[0]]) @@ -669,14 +669,14 @@ func testDistantAnnouncementDiscarding(t *testing.T, light bool) { tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- struct{}{} } // Ensure that a block with a lower number than the threshold is discarded - tester.fetcher.Notify("lower", hashes[low], blocks[hashes[low]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("lower", hashes[low], blocks[hashes[low]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) select { case <-time.After(50 * time.Millisecond): case <-fetching: t.Fatalf("fetcher requested stale header") } // Ensure that a block with a higher number than the threshold is discarded - tester.fetcher.Notify("higher", hashes[high], blocks[hashes[high]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("higher", hashes[high], blocks[hashes[high]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) select { case <-time.After(50 * time.Millisecond): case <-fetching: @@ -712,7 +712,7 @@ func testInvalidNumberAnnouncement(t *testing.T, light bool) { } } // Announce a block with a bad number, check for immediate drop - tester.fetcher.Notify("bad", hashes[0], 2, time.Now().Add(-arriveTimeout), badHeaderFetcher, badBodyFetcher) + tester.fetcher.Notify("bad", hashes[0], 2, time.Now().Add(-arriveTimeout), badHeaderFetcher, badBodyFetcher, nil) verifyImportEvent(t, imported, false) tester.lock.RLock() @@ -726,7 +726,7 @@ func testInvalidNumberAnnouncement(t *testing.T, light bool) { goodHeaderFetcher := tester.makeHeaderFetcher("good", blocks, -gatherSlack) goodBodyFetcher := tester.makeBodyFetcher("good", blocks, 0) // Make sure a good announcement passes without a drop - tester.fetcher.Notify("good", hashes[0], 1, time.Now().Add(-arriveTimeout), goodHeaderFetcher, goodBodyFetcher) + tester.fetcher.Notify("good", hashes[0], 1, time.Now().Add(-arriveTimeout), goodHeaderFetcher, goodBodyFetcher, nil) verifyImportEvent(t, imported, true) tester.lock.RLock() @@ -765,7 +765,7 @@ func TestEmptyBlockShortCircuit(t *testing.T) { } // Iteratively announce blocks until all are imported for i := len(hashes) - 2; i >= 0; i-- { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher) + tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher, nil) // All announces should fetch the header verifyFetchingEvent(t, fetching, true) @@ -808,9 +808,9 @@ func TestHashMemoryExhaustionAttack(t *testing.T) { // Feed the tester a huge hashset from the attacker, and a limited from the valid peer for i := 0; i < len(attack); i++ { if i < maxQueueDist { - tester.fetcher.Notify("valid", hashes[len(hashes)-2-i], uint64(i+1), time.Now(), validHeaderFetcher, validBodyFetcher) + tester.fetcher.Notify("valid", hashes[len(hashes)-2-i], uint64(i+1), time.Now(), validHeaderFetcher, validBodyFetcher, nil) } - tester.fetcher.Notify("attacker", attack[i], 1 /* don't distance drop */, time.Now(), attackerHeaderFetcher, attackerBodyFetcher) + tester.fetcher.Notify("attacker", attack[i], 1 /* don't distance drop */, time.Now(), attackerHeaderFetcher, attackerBodyFetcher, nil) } if count := atomic.LoadInt32(&announces); count != hashLimit+maxQueueDist { t.Fatalf("queued announce count mismatch: have %d, want %d", count, hashLimit+maxQueueDist) @@ -820,7 +820,7 @@ func TestHashMemoryExhaustionAttack(t *testing.T) { // Feed the remaining valid hashes to ensure DOS protection state remains clean for i := len(hashes) - maxQueueDist - 2; i >= 0; i-- { - tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), validHeaderFetcher, validBodyFetcher) + tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), validHeaderFetcher, validBodyFetcher, nil) verifyImportEvent(t, imported, true) } verifyImportDone(t, imported) diff --git a/eth/handler.go b/eth/handler.go index f42109753d..41b459d2d5 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/fetcher" + "github.com/ethereum/go-ethereum/eth/protocols/diff" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/ethdb" @@ -37,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) @@ -81,6 +83,7 @@ type handlerConfig struct { TxPool txPool // Transaction pool to propagate from Network uint64 // Network identifier to adfvertise Sync downloader.SyncMode // Whether to fast or full sync + DiffSync bool // Whether to diff sync BloomCache uint64 // Megabytes to alloc for fast sync bloom EventMux *event.TypeMux // Legacy event mux, deprecate for `feed` Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges @@ -96,6 +99,7 @@ type handler struct { snapSync uint32 // Flag whether fast sync should operate on top of the snap protocol acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing) directBroadcast bool + diffSync bool // Flag whether diff sync should operate on top of the diff protocol checkpointNumber uint64 // Block number for the sync progress validator to cross reference checkpointHash common.Hash // Block hash for the sync progress validator to cross reference @@ -143,6 +147,7 @@ func newHandler(config *handlerConfig) (*handler, error) { peers: newPeerSet(), whitelist: config.Whitelist, directBroadcast: config.DirectBroadcast, + diffSync: config.DiffSync, txsyncCh: make(chan *txsync), quitSync: make(chan struct{}), } @@ -187,7 +192,11 @@ func newHandler(config *handlerConfig) (*handler, error) { if atomic.LoadUint32(&h.fastSync) == 1 && atomic.LoadUint32(&h.snapSync) == 0 { h.stateBloom = trie.NewSyncBloom(config.BloomCache, config.Database) } - h.downloader = downloader.New(h.checkpointNumber, config.Database, h.stateBloom, h.eventMux, h.chain, nil, h.removePeer) + var downloadOptions []downloader.DownloadOption + if h.diffSync { + downloadOptions = append(downloadOptions, downloader.EnableDiffFetchOp(h.peers)) + } + h.downloader = downloader.New(h.checkpointNumber, config.Database, h.stateBloom, h.eventMux, h.chain, nil, h.removePeer, downloadOptions...) // Construct the fetcher (short sync) validator := func(header *types.Header) error { @@ -246,6 +255,11 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Error("Snapshot extension barrier failed", "err", err) return err } + diff, err := h.peers.waitDiffExtension(peer) + if err != nil { + peer.Log().Error("Diff extension barrier failed", "err", err) + return err + } // TODO(karalabe): Not sure why this is needed if !h.chainSync.handlePeerEvent(peer) { return p2p.DiscQuitting @@ -286,7 +300,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Debug("Ethereum peer connected", "name", peer.Name()) // Register the peer locally - if err := h.peers.registerPeer(peer, snap); err != nil { + if err := h.peers.registerPeer(peer, snap, diff); err != nil { peer.Log().Error("Ethereum peer registration failed", "err", err) return err } @@ -357,6 +371,21 @@ func (h *handler) runSnapExtension(peer *snap.Peer, handler snap.Handler) error return handler(peer) } +// runDiffExtension registers a `diff` peer into the joint eth/diff peerset and +// starts handling inbound messages. As `diff` is only a satellite protocol to +// `eth`, all subsystem registrations and lifecycle management will be done by +// the main `eth` handler to prevent strange races. +func (h *handler) runDiffExtension(peer *diff.Peer, handler diff.Handler) error { + h.peerWG.Add(1) + defer h.peerWG.Done() + + if err := h.peers.registerDiffExtension(peer); err != nil { + peer.Log().Error("Diff extension registration failed", "err", err) + return err + } + return handler(peer) +} + // removePeer unregisters a peer from the downloader and fetchers, removes it from // the set of tracked peers and closes the network connection to it. func (h *handler) removePeer(id string) { @@ -449,13 +478,19 @@ func (h *handler) BroadcastBlock(block *types.Block, propagate bool) { // Send the block to a subset of our peers var transfer []*ethPeer if h.directBroadcast { - transfer = peers[:int(len(peers))] + transfer = peers[:] } else { transfer = peers[:int(math.Sqrt(float64(len(peers))))] } + diff := h.chain.GetDiffLayerRLP(block.Hash()) for _, peer := range transfer { + if len(diff) != 0 && peer.diffExt != nil { + // difflayer should send before block + peer.diffExt.SendDiffLayers([]rlp.RawValue{diff}) + } peer.AsyncSendNewBlock(block, td) } + log.Trace("Propagated block", "hash", hash, "recipients", len(transfer), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) return } diff --git a/eth/handler_diff.go b/eth/handler_diff.go new file mode 100644 index 0000000000..c996105f0f --- /dev/null +++ b/eth/handler_diff.go @@ -0,0 +1,87 @@ +// 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 ( + "fmt" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/eth/protocols/diff" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +// diffHandler implements the diff.Backend interface to handle the various network +// packets that are sent as replies or broadcasts. +type diffHandler handler + +func (h *diffHandler) Chain() *core.BlockChain { return h.chain } + +// RunPeer is invoked when a peer joins on the `diff` protocol. +func (h *diffHandler) RunPeer(peer *diff.Peer, hand diff.Handler) error { + if err := peer.Handshake(h.diffSync); err != nil { + return err + } + defer h.chain.RemoveDiffPeer(peer.ID()) + return (*handler)(h).runDiffExtension(peer, hand) +} + +// PeerInfo retrieves all known `diff` information about a peer. +func (h *diffHandler) PeerInfo(id enode.ID) interface{} { + if p := h.peers.peer(id.String()); p != nil && p.diffExt != nil { + return p.diffExt.info() + } + return nil +} + +// Handle is invoked from a peer's message handler when it receives a new remote +// message that the handler couldn't consume and serve itself. +func (h *diffHandler) Handle(peer *diff.Peer, packet diff.Packet) error { + // DeliverSnapPacket is invoked from a peer's message handler when it transmits a + // data packet for the local node to consume. + switch packet := packet.(type) { + case *diff.DiffLayersPacket: + return h.handleDiffLayerPackage(packet, peer.ID(), false) + + case *diff.FullDiffLayersPacket: + return h.handleDiffLayerPackage(&packet.DiffLayersPacket, peer.ID(), true) + + default: + return fmt.Errorf("unexpected diff packet type: %T", packet) + } +} + +func (h *diffHandler) handleDiffLayerPackage(packet *diff.DiffLayersPacket, pid string, fulfilled bool) error { + diffs, err := packet.Unpack() + + if err != nil { + return err + } + for _, d := range diffs { + if d != nil { + if err := d.Validate(); err != nil { + return err + } + } + } + for _, diff := range diffs { + err := h.chain.HandleDiffLayer(diff, pid, fulfilled) + if err != nil { + return err + } + } + return nil +} diff --git a/eth/handler_diff_test.go b/eth/handler_diff_test.go new file mode 100644 index 0000000000..f6b967631a --- /dev/null +++ b/eth/handler_diff_test.go @@ -0,0 +1,203 @@ +// 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 eth + +import ( + "crypto/rand" + "math/big" + "testing" + "time" + + "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/core/vm" + "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/eth/protocols/diff" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" +) + +// 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. +type testBackend struct { + db ethdb.Database + chain *core.BlockChain + txpool *core.TxPool + + handler *handler +} + +// newTestBackend creates an empty chain and wraps it into a mock backend. +func newTestBackend(blocks int) *testBackend { + return newTestBackendWithGenerator(blocks) +} + +// newTestBackend creates a chain with a number of explicitly defined blocks and +// wraps it into a mock backend. +func newTestBackendWithGenerator(blocks int) *testBackend { + signer := types.HomesteadSigner{} + // Create a database pre-initialize with a genesis block + db := rawdb.NewMemoryDatabase() + (&core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db) + + chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + generator := 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.SetCoinbase(testAddr) + + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), common.Address{0x01}, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain, tx) + } + bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator) + if _, err := chain.InsertChain(bs); err != nil { + panic(err) + } + txpool := newTestTxPool() + + handler, _ := newHandler(&handlerConfig{ + Database: db, + Chain: chain, + TxPool: txpool, + Network: 1, + Sync: downloader.FullSync, + BloomCache: 1, + }) + handler.Start(100) + + txconfig := core.DefaultTxPoolConfig + txconfig.Journal = "" // Don't litter the disk with test journals + + return &testBackend{ + db: db, + chain: chain, + txpool: core.NewTxPool(txconfig, params.TestChainConfig, chain), + handler: handler, + } +} + +// close tears down the transaction pool and chain behind the mock backend. +func (b *testBackend) close() { + b.txpool.Stop() + b.chain.Stop() + b.handler.Stop() +} + +func (b *testBackend) Chain() *core.BlockChain { return b.chain } + +func (b *testBackend) RunPeer(peer *diff.Peer, handler diff.Handler) error { + // Normally the backend would do peer mainentance and handshakes. All that + // is omitted and we will just give control back to the handler. + return handler(peer) +} +func (b *testBackend) PeerInfo(enode.ID) interface{} { panic("not implemented") } + +func (b *testBackend) Handle(*diff.Peer, diff.Packet) error { + panic("data processing tests should be done in the handler package") +} + +type testPeer struct { + *diff.Peer + + net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging + app *p2p.MsgPipeRW // Application layer reader/writer to simulate the local side +} + +// newTestPeer creates a new peer registered at the given data backend. +func newTestPeer(name string, version uint, backend *testBackend) (*testPeer, <-chan error) { + // Create a message pipe to communicate through + app, net := p2p.MsgPipe() + + // Start the peer on a new thread + var id enode.ID + rand.Read(id[:]) + + peer := diff.NewPeer(version, p2p.NewPeer(id, name, nil), net) + errc := make(chan error, 1) + go func() { + errc <- backend.RunPeer(peer, func(peer *diff.Peer) error { + + return diff.Handle((*diffHandler)(backend.handler), peer) + }) + }() + return &testPeer{app: app, net: net, Peer: peer}, errc +} + +// close terminates the local side of the peer, notifying the remote protocol +// manager of termination. +func (p *testPeer) close() { + p.Peer.Close() + p.app.Close() +} + +func TestHandleDiffLayer(t *testing.T) { + t.Parallel() + + blockNum := 1024 + waitInterval := 100 * time.Millisecond + backend := newTestBackend(blockNum) + defer backend.close() + + peer, _ := newTestPeer("peer", diff.Diff1, backend) + defer peer.close() + + tests := []struct { + DiffLayer *types.DiffLayer + Valid bool + }{ + {DiffLayer: &types.DiffLayer{ + BlockHash: common.Hash{0x1}, + Number: 1025, + }, Valid: true}, + {DiffLayer: &types.DiffLayer{ + BlockHash: common.Hash{0x2}, + Number: 3073, + }, Valid: false}, + {DiffLayer: &types.DiffLayer{ + BlockHash: common.Hash{0x3}, + Number: 500, + }, Valid: false}, + } + + for _, tt := range tests { + bz, _ := rlp.EncodeToBytes(tt.DiffLayer) + + p2p.Send(peer.app, diff.DiffLayerMsg, diff.DiffLayersPacket{rlp.RawValue(bz)}) + } + time.Sleep(waitInterval) + for idx, tt := range tests { + diff := backend.chain.GetUnTrustedDiffLayer(tt.DiffLayer.BlockHash, "") + if (tt.Valid && diff == nil) || (!tt.Valid && diff != nil) { + t.Errorf("test: %d, diff layer handle failed", idx) + } + } +} diff --git a/eth/handler_eth.go b/eth/handler_eth.go index 3ff9f2245b..d2cf83fbfe 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -26,6 +26,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/eth/fetcher" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" @@ -98,7 +99,6 @@ func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error { case *eth.PooledTransactionsPacket: return h.txFetcher.Enqueue(peer.ID(), *packet, true) - default: return fmt.Errorf("unexpected eth packet type: %T", packet) } @@ -191,8 +191,17 @@ func (h *ethHandler) handleBlockAnnounces(peer *eth.Peer, hashes []common.Hash, unknownNumbers = append(unknownNumbers, numbers[i]) } } + // self support diff sync + var diffFetcher fetcher.DiffRequesterFn + if h.diffSync { + // the peer support diff protocol + if ep := h.peers.peer(peer.ID()); ep != nil && ep.diffExt != nil { + diffFetcher = ep.diffExt.RequestDiffLayers + } + } + for i := 0; i < len(unknownHashes); i++ { - h.blockFetcher.Notify(peer.ID(), unknownHashes[i], unknownNumbers[i], time.Now(), peer.RequestOneHeader, peer.RequestBodies) + h.blockFetcher.Notify(peer.ID(), unknownHashes[i], unknownNumbers[i], time.Now(), peer.RequestOneHeader, peer.RequestBodies, diffFetcher) } return nil } diff --git a/eth/peer.go b/eth/peer.go index 1cea9c640e..2fb6fabf26 100644 --- a/eth/peer.go +++ b/eth/peer.go @@ -21,6 +21,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/eth/protocols/diff" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" ) @@ -37,6 +38,7 @@ type ethPeerInfo struct { type ethPeer struct { *eth.Peer snapExt *snapPeer // Satellite `snap` connection + diffExt *diffPeer syncDrop *time.Timer // Connection dropper if `eth` sync progress isn't validated in time snapWait chan struct{} // Notification channel for snap connections @@ -60,11 +62,31 @@ type snapPeerInfo struct { Version uint `json:"version"` // Snapshot protocol version negotiated } +// diffPeerInfo represents a short summary of the `diff` sub-protocol metadata known +// about a connected peer. +type diffPeerInfo struct { + Version uint `json:"version"` // diff protocol version negotiated + DiffSync bool `json:"diff_sync"` +} + // snapPeer is a wrapper around snap.Peer to maintain a few extra metadata. type snapPeer struct { *snap.Peer } +// diffPeer is a wrapper around diff.Peer to maintain a few extra metadata. +type diffPeer struct { + *diff.Peer +} + +// info gathers and returns some `diff` protocol metadata known about a peer. +func (p *diffPeer) info() *diffPeerInfo { + return &diffPeerInfo{ + Version: p.Version(), + DiffSync: p.DiffSync(), + } +} + // info gathers and returns some `snap` protocol metadata known about a peer. func (p *snapPeer) info() *snapPeerInfo { return &snapPeerInfo{ diff --git a/eth/peerset.go b/eth/peerset.go index 1e864a8e46..f0955f34c6 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -22,6 +22,8 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/eth/protocols/diff" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/p2p" @@ -43,6 +45,10 @@ var ( // errSnapWithoutEth is returned if a peer attempts to connect only on the // snap protocol without advertizing the eth main protocol. errSnapWithoutEth = errors.New("peer connected on snap without compatible eth support") + + // errDiffWithoutEth is returned if a peer attempts to connect only on the + // diff protocol without advertizing the eth main protocol. + errDiffWithoutEth = errors.New("peer connected on diff without compatible eth support") ) // peerSet represents the collection of active peers currently participating in @@ -54,6 +60,9 @@ type peerSet struct { snapWait map[string]chan *snap.Peer // Peers connected on `eth` waiting for their snap extension snapPend map[string]*snap.Peer // Peers connected on the `snap` protocol, but not yet on `eth` + diffWait map[string]chan *diff.Peer // Peers connected on `eth` waiting for their diff extension + diffPend map[string]*diff.Peer // Peers connected on the `diff` protocol, but not yet on `eth` + lock sync.RWMutex closed bool } @@ -64,6 +73,8 @@ func newPeerSet() *peerSet { peers: make(map[string]*ethPeer), snapWait: make(map[string]chan *snap.Peer), snapPend: make(map[string]*snap.Peer), + diffWait: make(map[string]chan *diff.Peer), + diffPend: make(map[string]*diff.Peer), } } @@ -97,6 +108,36 @@ func (ps *peerSet) registerSnapExtension(peer *snap.Peer) error { return nil } +// registerDiffExtension unblocks an already connected `eth` peer waiting for its +// `diff` extension, or if no such peer exists, tracks the extension for the time +// being until the `eth` main protocol starts looking for it. +func (ps *peerSet) registerDiffExtension(peer *diff.Peer) error { + // Reject the peer if it advertises `diff` without `eth` as `diff` is only a + // satellite protocol meaningful with the chain selection of `eth` + if !peer.RunningCap(eth.ProtocolName, eth.ProtocolVersions) { + return errDiffWithoutEth + } + // Ensure nobody can double connect + ps.lock.Lock() + defer ps.lock.Unlock() + + id := peer.ID() + if _, ok := ps.peers[id]; ok { + return errPeerAlreadyRegistered // avoid connections with the same id as existing ones + } + if _, ok := ps.diffPend[id]; ok { + return errPeerAlreadyRegistered // avoid connections with the same id as pending ones + } + // Inject the peer into an `eth` counterpart is available, otherwise save for later + if wait, ok := ps.diffWait[id]; ok { + delete(ps.diffWait, id) + wait <- peer + return nil + } + ps.diffPend[id] = peer + return nil +} + // waitExtensions blocks until all satellite protocols are connected and tracked // by the peerset. func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { @@ -131,9 +172,50 @@ func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { return <-wait, nil } +// waitDiffExtension blocks until all satellite protocols are connected and tracked +// by the peerset. +func (ps *peerSet) waitDiffExtension(peer *eth.Peer) (*diff.Peer, error) { + // If the peer does not support a compatible `diff`, don't wait + if !peer.RunningCap(diff.ProtocolName, diff.ProtocolVersions) { + return nil, nil + } + // Ensure nobody can double connect + ps.lock.Lock() + + id := peer.ID() + if _, ok := ps.peers[id]; ok { + ps.lock.Unlock() + return nil, errPeerAlreadyRegistered // avoid connections with the same id as existing ones + } + if _, ok := ps.diffWait[id]; ok { + ps.lock.Unlock() + return nil, errPeerAlreadyRegistered // avoid connections with the same id as pending ones + } + // If `diff` already connected, retrieve the peer from the pending set + if diff, ok := ps.diffPend[id]; ok { + delete(ps.diffPend, id) + + ps.lock.Unlock() + return diff, nil + } + // Otherwise wait for `diff` to connect concurrently + wait := make(chan *diff.Peer) + ps.diffWait[id] = wait + ps.lock.Unlock() + + return <-wait, nil +} + +func (ps *peerSet) GetDiffPeer(pid string) downloader.IDiffPeer { + if p := ps.peer(pid); p != nil && p.diffExt != nil { + return p.diffExt + } + return nil +} + // registerPeer injects a new `eth` peer into the working set, or returns an error // if the peer is already known. -func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer) error { +func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer, diffExt *diff.Peer) error { // Start tracking the new peer ps.lock.Lock() defer ps.lock.Unlock() @@ -152,6 +234,9 @@ func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer) error { eth.snapExt = &snapPeer{ext} ps.snapPeers++ } + if diffExt != nil { + eth.diffExt = &diffPeer{diffExt} + } ps.peers[id] = eth return nil } diff --git a/eth/protocols/diff/discovery.go b/eth/protocols/diff/discovery.go new file mode 100644 index 0000000000..6a6ff066db --- /dev/null +++ b/eth/protocols/diff/discovery.go @@ -0,0 +1,32 @@ +// 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 diff + +import ( + "github.com/ethereum/go-ethereum/rlp" +) + +// enrEntry is the ENR entry which advertises `diff` protocol on the discovery. +type enrEntry struct { + // Ignore additional fields (for forward compatibility). + Rest []rlp.RawValue `rlp:"tail"` +} + +// ENRKey implements enr.Entry. +func (e enrEntry) ENRKey() string { + return "diff" +} diff --git a/eth/protocols/diff/handler.go b/eth/protocols/diff/handler.go new file mode 100644 index 0000000000..8678ff7f65 --- /dev/null +++ b/eth/protocols/diff/handler.go @@ -0,0 +1,180 @@ +package diff + +import ( + "fmt" + "time" + + "github.com/ethereum/go-ethereum/core" + "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" +) + +const ( + // softResponseLimit is the target maximum size of replies to data retrievals. + softResponseLimit = 2 * 1024 * 1024 + + // maxDiffLayerServe is the maximum number of diff layers to serve. + maxDiffLayerServe = 1024 +) + +var requestTracker = NewTracker(time.Minute) + +// Handler is a callback to invoke from an outside runner after the boilerplate +// exchanges have passed. +type Handler func(peer *Peer) error + +type Backend interface { + // Chain retrieves the blockchain object to serve data. + Chain() *core.BlockChain + + // RunPeer is invoked when a peer joins on the `eth` protocol. The handler + // should do any peer maintenance work, handshakes and validations. If all + // is passed, control should be given back to the `handler` to process the + // inbound messages going forward. + RunPeer(peer *Peer, handler Handler) error + + PeerInfo(id enode.ID) interface{} + + Handle(peer *Peer, packet Packet) error +} + +// MakeProtocols constructs the P2P protocol definitions for `diff`. +func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { + // Filter the discovery iterator for nodes advertising diff support. + dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool { + var diff enrEntry + return n.Load(&diff) == nil + }) + + protocols := make([]p2p.Protocol, len(ProtocolVersions)) + for i, version := range ProtocolVersions { + version := version // Closure + + protocols[i] = p2p.Protocol{ + Name: ProtocolName, + Version: version, + Length: protocolLengths[version], + Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + return backend.RunPeer(NewPeer(version, p, rw), func(peer *Peer) error { + defer peer.Close() + return Handle(backend, peer) + }) + }, + NodeInfo: func() interface{} { + return nodeInfo(backend.Chain()) + }, + PeerInfo: func(id enode.ID) interface{} { + return backend.PeerInfo(id) + }, + Attributes: []enr.Entry{&enrEntry{}}, + DialCandidates: dnsdisc, + } + } + return protocols +} + +// Handle is the callback invoked to manage the life cycle of a `diff` peer. +// When this function terminates, the peer is disconnected. +func Handle(backend Backend, peer *Peer) error { + for { + if err := handleMessage(backend, peer); err != nil { + peer.Log().Debug("Message handling failed in `diff`", "err", err) + return err + } + } +} + +// handleMessage is invoked whenever an inbound message is received from a +// remote peer on the `diff` protocol. The remote connection is torn down upon +// returning any error. +func handleMessage(backend Backend, peer *Peer) error { + // Read the next message from the remote peer, and ensure it's fully consumed + msg, err := peer.rw.ReadMsg() + if err != nil { + return err + } + if msg.Size > maxMessageSize { + return fmt.Errorf("%w: %v > %v", errMsgTooLarge, msg.Size, maxMessageSize) + } + defer msg.Discard() + start := time.Now() + // Track the emount 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) { + sampler := func() metrics.Sample { + return metrics.ResettingSample( + metrics.NewExpDecaySample(1028, 0.015), + ) + } + metrics.GetOrRegisterHistogramLazy(h, nil, sampler).Update(time.Since(start).Microseconds()) + }(start) + } + // Handle the message depending on its contents + switch { + case msg.Code == GetDiffLayerMsg: + res := new(GetDiffLayersPacket) + if err := msg.Decode(res); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + diffs := answerDiffLayersQuery(backend, res) + + p2p.Send(peer.rw, FullDiffLayerMsg, &FullDiffLayersPacket{ + RequestId: res.RequestId, + DiffLayersPacket: diffs, + }) + return nil + + case msg.Code == DiffLayerMsg: + // A batch of trie nodes arrived to one of our previous requests + res := new(DiffLayersPacket) + if err := msg.Decode(res); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + return backend.Handle(peer, res) + case msg.Code == FullDiffLayerMsg: + // A batch of trie nodes arrived to one of our previous requests + res := new(FullDiffLayersPacket) + if err := msg.Decode(res); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + if fulfilled := requestTracker.Fulfil(peer.id, peer.version, FullDiffLayerMsg, res.RequestId); fulfilled { + return backend.Handle(peer, res) + } + return fmt.Errorf("%w: %v", errUnexpectedMsg, msg.Code) + default: + return fmt.Errorf("%w: %v", errInvalidMsgCode, msg.Code) + } +} + +func answerDiffLayersQuery(backend Backend, query *GetDiffLayersPacket) []rlp.RawValue { + // Gather blocks until the fetch or network limits is reached + var ( + bytes int + diffLayers []rlp.RawValue + ) + // Need avoid transfer huge package + for lookups, hash := range query.BlockHashes { + if bytes >= softResponseLimit || len(diffLayers) >= maxDiffLayerServe || + lookups >= 2*maxDiffLayerServe { + break + } + if data := backend.Chain().GetDiffLayerRLP(hash); len(data) != 0 { + diffLayers = append(diffLayers, data) + bytes += len(data) + } + } + return diffLayers +} + +// NodeInfo represents a short summary of the `diff` sub-protocol metadata +// known about the host peer. +type NodeInfo struct{} + +// nodeInfo retrieves some `diff` protocol metadata about the running host node. +func nodeInfo(_ *core.BlockChain) *NodeInfo { + return &NodeInfo{} +} diff --git a/eth/protocols/diff/handler_test.go b/eth/protocols/diff/handler_test.go new file mode 100644 index 0000000000..fcdca07b9f --- /dev/null +++ b/eth/protocols/diff/handler_test.go @@ -0,0 +1,192 @@ +// 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 diff + +import ( + "math/big" + "math/rand" + "testing" + + "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/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" +) + +var ( + // testKey is a private key to use for funding a tester account. + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + + // testAddr is the Ethereum address of the tester account. + testAddr = crypto.PubkeyToAddress(testKey.PublicKey) +) + +// 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. +type testBackend struct { + db ethdb.Database + chain *core.BlockChain + txpool *core.TxPool +} + +// newTestBackend creates an empty chain and wraps it into a mock backend. +func newTestBackend(blocks int) *testBackend { + return newTestBackendWithGenerator(blocks) +} + +// newTestBackend creates a chain with a number of explicitly defined blocks and +// wraps it into a mock backend. +func newTestBackendWithGenerator(blocks int) *testBackend { + signer := types.HomesteadSigner{} + // Create a database pre-initialize with a genesis block + db := rawdb.NewMemoryDatabase() + (&core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db) + + chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + generator := 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.SetCoinbase(testAddr) + + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), common.Address{0x01}, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain, tx) + } + bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator) + if _, err := chain.InsertChain(bs); err != nil { + panic(err) + } + txconfig := core.DefaultTxPoolConfig + txconfig.Journal = "" // Don't litter the disk with test journals + + return &testBackend{ + db: db, + chain: chain, + txpool: core.NewTxPool(txconfig, params.TestChainConfig, chain), + } +} + +// close tears down the transaction pool and chain behind the mock backend. +func (b *testBackend) close() { + b.txpool.Stop() + b.chain.Stop() +} + +func (b *testBackend) Chain() *core.BlockChain { return b.chain } + +func (b *testBackend) RunPeer(peer *Peer, handler Handler) error { + // Normally the backend would do peer mainentance and handshakes. All that + // is omitted and we will just give control back to the handler. + return handler(peer) +} +func (b *testBackend) PeerInfo(enode.ID) interface{} { panic("not implemented") } + +func (b *testBackend) Handle(*Peer, Packet) error { + panic("data processing tests should be done in the handler package") +} + +func TestGetDiffLayers(t *testing.T) { testGetDiffLayers(t, Diff1) } + +func testGetDiffLayers(t *testing.T, protocol uint) { + t.Parallel() + + blockNum := 2048 + backend := newTestBackend(blockNum) + defer backend.close() + + peer, _ := newTestPeer("peer", protocol, backend) + defer peer.close() + + foundDiffBlockHashes := make([]common.Hash, 0) + foundDiffPackets := make([]FullDiffLayersPacket, 0) + foundDiffRlps := make([]rlp.RawValue, 0) + missDiffBlockHashes := make([]common.Hash, 0) + missDiffPackets := make([]FullDiffLayersPacket, 0) + + for i := 0; i < 100; i++ { + number := uint64(rand.Int63n(1024)) + if number == 0 { + continue + } + foundHash := backend.chain.GetCanonicalHash(number + 1024) + missHash := backend.chain.GetCanonicalHash(number) + foundRlp := backend.chain.GetDiffLayerRLP(foundHash) + + if len(foundHash) == 0 { + t.Fatalf("Faild to fond rlp encoded diff layer %v", foundHash) + } + foundDiffPackets = append(foundDiffPackets, FullDiffLayersPacket{ + RequestId: uint64(i), + DiffLayersPacket: []rlp.RawValue{foundRlp}, + }) + foundDiffRlps = append(foundDiffRlps, foundRlp) + + missDiffPackets = append(missDiffPackets, FullDiffLayersPacket{ + RequestId: uint64(i), + DiffLayersPacket: []rlp.RawValue{}, + }) + + missDiffBlockHashes = append(missDiffBlockHashes, missHash) + foundDiffBlockHashes = append(foundDiffBlockHashes, foundHash) + } + + for idx, blockHash := range foundDiffBlockHashes { + p2p.Send(peer.app, GetDiffLayerMsg, GetDiffLayersPacket{RequestId: uint64(idx), BlockHashes: []common.Hash{blockHash}}) + if err := p2p.ExpectMsg(peer.app, FullDiffLayerMsg, foundDiffPackets[idx]); err != nil { + t.Errorf("test %d: diff layer mismatch: %v", idx, err) + } + } + + for idx, blockHash := range missDiffBlockHashes { + p2p.Send(peer.app, GetDiffLayerMsg, GetDiffLayersPacket{RequestId: uint64(idx), BlockHashes: []common.Hash{blockHash}}) + if err := p2p.ExpectMsg(peer.app, FullDiffLayerMsg, missDiffPackets[idx]); err != nil { + t.Errorf("test %d: diff layer mismatch: %v", idx, err) + } + } + + p2p.Send(peer.app, GetDiffLayerMsg, GetDiffLayersPacket{RequestId: 111, BlockHashes: foundDiffBlockHashes}) + if err := p2p.ExpectMsg(peer.app, FullDiffLayerMsg, FullDiffLayersPacket{ + 111, + foundDiffRlps, + }); err != nil { + t.Errorf("test: diff layer mismatch: %v", err) + } + + p2p.Send(peer.app, GetDiffLayerMsg, GetDiffLayersPacket{RequestId: 111, BlockHashes: missDiffBlockHashes}) + if err := p2p.ExpectMsg(peer.app, FullDiffLayerMsg, FullDiffLayersPacket{ + 111, + nil, + }); err != nil { + t.Errorf("test: diff layer mismatch: %v", err) + } +} diff --git a/eth/protocols/diff/handshake.go b/eth/protocols/diff/handshake.go new file mode 100644 index 0000000000..4198ea88a1 --- /dev/null +++ b/eth/protocols/diff/handshake.go @@ -0,0 +1,82 @@ +// 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 diff + +import ( + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common/gopool" + "github.com/ethereum/go-ethereum/p2p" +) + +const ( + // handshakeTimeout is the maximum allowed time for the `diff` handshake to + // complete before dropping the connection.= as malicious. + handshakeTimeout = 5 * time.Second +) + +// Handshake executes the diff protocol handshake, +func (p *Peer) Handshake(diffSync bool) error { + // Send out own handshake in a new thread + errc := make(chan error, 2) + + var cap DiffCapPacket // safe to read after two values have been received from errc + + gopool.Submit(func() { + errc <- p2p.Send(p.rw, DiffCapMsg, &DiffCapPacket{ + DiffSync: diffSync, + Extra: defaultExtra, + }) + }) + gopool.Submit(func() { + errc <- p.readCap(&cap) + }) + timeout := time.NewTimer(handshakeTimeout) + defer timeout.Stop() + for i := 0; i < 2; i++ { + select { + case err := <-errc: + if err != nil { + return err + } + case <-timeout.C: + return p2p.DiscReadTimeout + } + } + p.diffSync = cap.DiffSync + return nil +} + +// readStatus reads the remote handshake message. +func (p *Peer) readCap(cap *DiffCapPacket) error { + msg, err := p.rw.ReadMsg() + if err != nil { + return err + } + if msg.Code != DiffCapMsg { + return fmt.Errorf("%w: first msg has code %x (!= %x)", errNoCapMsg, msg.Code, DiffCapMsg) + } + if msg.Size > maxMessageSize { + return fmt.Errorf("%w: %v > %v", errMsgTooLarge, msg.Size, maxMessageSize) + } + // Decode the handshake and make sure everything matches + if err := msg.Decode(cap); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + return nil +} diff --git a/eth/protocols/diff/peer.go b/eth/protocols/diff/peer.go new file mode 100644 index 0000000000..f110cab69e --- /dev/null +++ b/eth/protocols/diff/peer.go @@ -0,0 +1,107 @@ +package diff + +import ( + "math/rand" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/rlp" +) + +const maxQueuedDiffLayers = 12 + +// Peer is a collection of relevant information we have about a `diff` peer. +type Peer struct { + id string // Unique ID for the peer, cached + diffSync bool // whether the peer can diff sync + queuedDiffLayers chan []rlp.RawValue // Queue of diff layers to broadcast to the peer + + *p2p.Peer // The embedded P2P package peer + rw p2p.MsgReadWriter // Input/output streams for diff + version uint // Protocol version negotiated + logger log.Logger // Contextual logger with the peer id injected + term chan struct{} // Termination channel to stop the broadcasters +} + +// NewPeer create a wrapper for a network connection and negotiated protocol +// version. +func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) *Peer { + id := p.ID().String() + peer := &Peer{ + id: id, + Peer: p, + rw: rw, + diffSync: false, + version: version, + logger: log.New("peer", id[:8]), + queuedDiffLayers: make(chan []rlp.RawValue, maxQueuedDiffLayers), + term: make(chan struct{}), + } + go peer.broadcastDiffLayers() + return peer +} + +func (p *Peer) broadcastDiffLayers() { + for { + select { + case prop := <-p.queuedDiffLayers: + if err := p.SendDiffLayers(prop); err != nil { + p.Log().Error("Failed to propagated diff layer", "err", err) + return + } + case <-p.term: + return + } + } +} + +// ID retrieves the peer's unique identifier. +func (p *Peer) ID() string { + return p.id +} + +// Version retrieves the peer's negoatiated `diff` protocol version. +func (p *Peer) Version() uint { + return p.version +} + +func (p *Peer) DiffSync() bool { + return p.diffSync +} + +// Log overrides the P2P logget with the higher level one containing only the id. +func (p *Peer) Log() log.Logger { + return p.logger +} + +// Close signals the broadcast goroutine to terminate. Only ever call this if +// you created the peer yourself via NewPeer. Otherwise let whoever created it +// clean it up! +func (p *Peer) Close() { + close(p.term) +} + +// RequestDiffLayers fetches a batch of diff layers corresponding to the hashes +// specified. +func (p *Peer) RequestDiffLayers(hashes []common.Hash) error { + id := rand.Uint64() + + requestTracker.Track(p.id, p.version, GetDiffLayerMsg, FullDiffLayerMsg, id) + return p2p.Send(p.rw, GetDiffLayerMsg, GetDiffLayersPacket{ + RequestId: id, + BlockHashes: hashes, + }) +} + +func (p *Peer) SendDiffLayers(diffs []rlp.RawValue) error { + return p2p.Send(p.rw, DiffLayerMsg, diffs) +} + +func (p *Peer) AsyncSendDiffLayer(diffLayers []rlp.RawValue) { + select { + case p.queuedDiffLayers <- diffLayers: + default: + p.Log().Debug("Dropping diff layers propagation") + } +} diff --git a/eth/protocols/diff/peer_test.go b/eth/protocols/diff/peer_test.go new file mode 100644 index 0000000000..015b86f134 --- /dev/null +++ b/eth/protocols/diff/peer_test.go @@ -0,0 +1,61 @@ +// 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 . + +// This file contains some shares testing functionality, common to multiple +// different files and modules being tested. + +package diff + +import ( + "crypto/rand" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +// testPeer is a simulated peer to allow testing direct network calls. +type testPeer struct { + *Peer + + net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging + app *p2p.MsgPipeRW // Application layer reader/writer to simulate the local side +} + +// newTestPeer creates a new peer registered at the given data backend. +func newTestPeer(name string, version uint, backend Backend) (*testPeer, <-chan error) { + // Create a message pipe to communicate through + app, net := p2p.MsgPipe() + + // Start the peer on a new thread + var id enode.ID + rand.Read(id[:]) + + peer := NewPeer(version, p2p.NewPeer(id, name, nil), net) + errc := make(chan error, 1) + go func() { + errc <- backend.RunPeer(peer, func(peer *Peer) error { + return Handle(backend, peer) + }) + }() + return &testPeer{app: app, net: net, Peer: peer}, errc +} + +// close terminates the local side of the peer, notifying the remote protocol +// manager of termination. +func (p *testPeer) close() { + p.Peer.Close() + p.app.Close() +} diff --git a/eth/protocols/diff/protocol.go b/eth/protocols/diff/protocol.go new file mode 100644 index 0000000000..4467d0b327 --- /dev/null +++ b/eth/protocols/diff/protocol.go @@ -0,0 +1,122 @@ +// 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 diff + +import ( + "errors" + "fmt" + + "golang.org/x/crypto/sha3" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +// Constants to match up protocol versions and messages +const ( + Diff1 = 1 +) + +// ProtocolName is the official short name of the `diff` protocol used during +// devp2p capability negotiation. +const ProtocolName = "diff" + +// ProtocolVersions are the supported versions of the `diff` protocol (first +// is primary). +var ProtocolVersions = []uint{Diff1} + +// protocolLengths are the number of implemented message corresponding to +// different protocol versions. +var protocolLengths = map[uint]uint64{Diff1: 4} + +// maxMessageSize is the maximum cap on the size of a protocol message. +const maxMessageSize = 10 * 1024 * 1024 + +const ( + DiffCapMsg = 0x00 + GetDiffLayerMsg = 0x01 + DiffLayerMsg = 0x02 + FullDiffLayerMsg = 0x03 +) + +var defaultExtra = []byte{0x00} + +var ( + errMsgTooLarge = errors.New("message too long") + errDecode = errors.New("invalid message") + errInvalidMsgCode = errors.New("invalid message code") + errUnexpectedMsg = errors.New("unexpected message code") + errNoCapMsg = errors.New("miss cap message during handshake") +) + +// Packet represents a p2p message in the `diff` protocol. +type Packet interface { + Name() string // Name returns a string corresponding to the message type. + Kind() byte // Kind returns the message type. +} + +type GetDiffLayersPacket struct { + RequestId uint64 + BlockHashes []common.Hash +} + +func (p *DiffLayersPacket) Unpack() ([]*types.DiffLayer, error) { + diffLayers := make([]*types.DiffLayer, 0, len(*p)) + hasher := sha3.NewLegacyKeccak256() + for _, rawData := range *p { + var diff types.DiffLayer + err := rlp.DecodeBytes(rawData, &diff) + if err != nil { + return nil, fmt.Errorf("%w: diff layer %v", errDecode, err) + } + diffLayers = append(diffLayers, &diff) + _, err = hasher.Write(rawData) + if err != nil { + return nil, err + } + var diffHash common.Hash + hasher.Sum(diffHash[:0]) + hasher.Reset() + diff.DiffHash = diffHash + } + return diffLayers, nil +} + +type DiffCapPacket struct { + DiffSync bool + Extra rlp.RawValue // for extension +} + +type DiffLayersPacket []rlp.RawValue + +type FullDiffLayersPacket struct { + RequestId uint64 + DiffLayersPacket +} + +func (*GetDiffLayersPacket) Name() string { return "GetDiffLayers" } +func (*GetDiffLayersPacket) Kind() byte { return GetDiffLayerMsg } + +func (*DiffLayersPacket) Name() string { return "DiffLayers" } +func (*DiffLayersPacket) Kind() byte { return DiffLayerMsg } + +func (*FullDiffLayersPacket) Name() string { return "FullDiffLayers" } +func (*FullDiffLayersPacket) Kind() byte { return FullDiffLayerMsg } + +func (*DiffCapPacket) Name() string { return "DiffCap" } +func (*DiffCapPacket) Kind() byte { return DiffCapMsg } diff --git a/eth/protocols/diff/protocol_test.go b/eth/protocols/diff/protocol_test.go new file mode 100644 index 0000000000..eda96adf1b --- /dev/null +++ b/eth/protocols/diff/protocol_test.go @@ -0,0 +1,131 @@ +// Copyright 2014 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 diff + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +// Tests that the custom union field encoder and decoder works correctly. +func TestDiffLayersPacketDataEncodeDecode(t *testing.T) { + // Create a "random" hash for testing + var hash common.Hash + for i := range hash { + hash[i] = byte(i) + } + + testDiffLayers := []*types.DiffLayer{ + { + BlockHash: common.HexToHash("0x1e9624dcd0874958723aa3dae1fe299861e93ef32b980143d798c428bdd7a20a"), + Number: 10479133, + Receipts: []*types.Receipt{{ + GasUsed: 100, + TransactionIndex: 1, + }}, + Codes: []types.DiffCode{{ + Hash: common.HexToHash("0xaece2dbf80a726206cf4df299afa09f9d8f3dcd85ff39bb4b3f0402a3a6af2f5"), + Code: []byte{1, 2, 3, 4}, + }}, + Destructs: []common.Address{ + common.HexToAddress("0x0205bb28ece9289d3fb8eb0c9e999bbd5be2b931"), + }, + Accounts: []types.DiffAccount{{ + Account: common.HexToAddress("0x18b2a687610328590bc8f2e5fedde3b582a49cda"), + Blob: []byte{2, 3, 4, 5}, + }}, + Storages: []types.DiffStorage{{ + Account: common.HexToAddress("0x18b2a687610328590bc8f2e5fedde3b582a49cda"), + Keys: []string{"abc"}, + Vals: [][]byte{{1, 2, 3}}, + }}, + }, + } + // Assemble some table driven tests + tests := []struct { + diffLayers []*types.DiffLayer + fail bool + }{ + {fail: false, diffLayers: testDiffLayers}, + } + // Iterate over each of the tests and try to encode and then decode + for i, tt := range tests { + originPacket := make([]rlp.RawValue, 0) + for _, diff := range tt.diffLayers { + bz, err := rlp.EncodeToBytes(diff) + assert.NoError(t, err) + originPacket = append(originPacket, bz) + } + + bz, err := rlp.EncodeToBytes(DiffLayersPacket(originPacket)) + if err != nil && !tt.fail { + t.Fatalf("test %d: failed to encode packet: %v", i, err) + } else if err == nil && tt.fail { + t.Fatalf("test %d: encode should have failed", i) + } + if !tt.fail { + packet := new(DiffLayersPacket) + if err := rlp.DecodeBytes(bz, packet); err != nil { + t.Fatalf("test %d: failed to decode packet: %v", i, err) + } + diffLayers, err := packet.Unpack() + assert.NoError(t, err) + + if len(diffLayers) != len(tt.diffLayers) { + t.Fatalf("test %d: encode length mismatch: have %+v, want %+v", i, len(diffLayers), len(tt.diffLayers)) + } + expectedPacket := make([]rlp.RawValue, 0) + for _, diff := range diffLayers { + bz, err := rlp.EncodeToBytes(diff) + assert.NoError(t, err) + expectedPacket = append(expectedPacket, bz) + } + for i := 0; i < len(expectedPacket); i++ { + if !bytes.Equal(expectedPacket[i], originPacket[i]) { + t.Fatalf("test %d: data change during encode and decode", i) + } + } + } + } +} + +func TestDiffMessages(t *testing.T) { + + for i, tc := range []struct { + message interface{} + want []byte + }{ + { + DiffCapPacket{true, defaultExtra}, + common.FromHex("c20100"), + }, + { + GetDiffLayersPacket{1111, []common.Hash{common.HexToHash("0xaece2dbf80a726206cf4df299afa09f9d8f3dcd85ff39bb4b3f0402a3a6af2f5")}}, + common.FromHex("e5820457e1a0aece2dbf80a726206cf4df299afa09f9d8f3dcd85ff39bb4b3f0402a3a6af2f5"), + }, + } { + if have, _ := rlp.EncodeToBytes(tc.message); !bytes.Equal(have, tc.want) { + t.Errorf("test %d, type %T, have\n\t%x\nwant\n\t%x", i, tc.message, have, tc.want) + } + } +} diff --git a/eth/protocols/diff/tracker.go b/eth/protocols/diff/tracker.go new file mode 100644 index 0000000000..7ee49e6ce2 --- /dev/null +++ b/eth/protocols/diff/tracker.go @@ -0,0 +1,161 @@ +// 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 diff + +import ( + "container/list" + "fmt" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" +) + +const ( + // maxTrackedPackets is a huge number to act as a failsafe on the number of + // pending requests the node will track. It should never be hit unless an + // attacker figures out a way to spin requests. + maxTrackedPackets = 10000 +) + +// request tracks sent network requests which have not yet received a response. +type request struct { + peer string + version uint // Protocol version + + reqCode uint64 // Protocol message code of the request + resCode uint64 // Protocol message code of the expected response + + time time.Time // Timestamp when the request was made + expire *list.Element // Expiration marker to untrack it +} + +type Tracker struct { + timeout time.Duration // Global timeout after which to drop a tracked packet + + pending map[uint64]*request // Currently pending requests + expire *list.List // Linked list tracking the expiration order + wake *time.Timer // Timer tracking the expiration of the next item + + lock sync.Mutex // Lock protecting from concurrent updates +} + +func NewTracker(timeout time.Duration) *Tracker { + return &Tracker{ + timeout: timeout, + pending: make(map[uint64]*request), + expire: list.New(), + } +} + +// Track adds a network request to the tracker to wait for a response to arrive +// or until the request it cancelled or times out. +func (t *Tracker) Track(peer string, version uint, reqCode uint64, resCode uint64, id uint64) { + t.lock.Lock() + defer t.lock.Unlock() + + // If there's a duplicate request, we've just random-collided (or more probably, + // we have a bug), report it. We could also add a metric, but we're not really + // expecting ourselves to be buggy, so a noisy warning should be enough. + if _, ok := t.pending[id]; ok { + log.Error("Network request id collision", "version", version, "code", reqCode, "id", id) + return + } + // If we have too many pending requests, bail out instead of leaking memory + if pending := len(t.pending); pending >= maxTrackedPackets { + log.Error("Request tracker exceeded allowance", "pending", pending, "peer", peer, "version", version, "code", reqCode) + return + } + // Id doesn't exist yet, start tracking it + t.pending[id] = &request{ + peer: peer, + version: version, + reqCode: reqCode, + resCode: resCode, + time: time.Now(), + expire: t.expire.PushBack(id), + } + + // If we've just inserted the first item, start the expiration timer + if t.wake == nil { + t.wake = time.AfterFunc(t.timeout, t.clean) + } +} + +// clean is called automatically when a preset time passes without a response +// being dleivered for the first network request. +func (t *Tracker) clean() { + t.lock.Lock() + defer t.lock.Unlock() + + // Expire anything within a certain threshold (might be no items at all if + // we raced with the delivery) + for t.expire.Len() > 0 { + // Stop iterating if the next pending request is still alive + var ( + head = t.expire.Front() + id = head.Value.(uint64) + req = t.pending[id] + ) + if time.Since(req.time) < t.timeout+5*time.Millisecond { + break + } + // Nope, dead, drop it + t.expire.Remove(head) + delete(t.pending, id) + } + t.schedule() +} + +// schedule starts a timer to trigger on the expiration of the first network +// packet. +func (t *Tracker) schedule() { + if t.expire.Len() == 0 { + t.wake = nil + return + } + t.wake = time.AfterFunc(time.Until(t.pending[t.expire.Front().Value.(uint64)].time.Add(t.timeout)), t.clean) +} + +// Fulfil fills a pending request, if any is available. +func (t *Tracker) Fulfil(peer string, version uint, code uint64, id uint64) bool { + t.lock.Lock() + defer t.lock.Unlock() + + // If it's a non existing request, track as stale response + req, ok := t.pending[id] + if !ok { + return false + } + // If the response is funky, it might be some active attack + if req.peer != peer || req.version != version || req.resCode != code { + log.Warn("Network response id collision", + "have", fmt.Sprintf("%s:/%d:%d", peer, version, code), + "want", fmt.Sprintf("%s:/%d:%d", peer, req.version, req.resCode), + ) + return false + } + // Everything matches, mark the request serviced + t.expire.Remove(req.expire) + delete(t.pending, id) + if req.expire.Prev() == nil { + if t.wake.Stop() { + t.schedule() + } + } + return true +} diff --git a/eth/state_accessor.go b/eth/state_accessor.go index aaabd1d152..461dc491fb 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -114,12 +114,12 @@ func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state if current = eth.blockchain.GetBlockByNumber(next); current == nil { return nil, fmt.Errorf("block #%d not found", next) } - _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) + statedb, _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) if err != nil { return 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())) + root, _, err := statedb.Commit(eth.blockchain.Config().IsEIP158(current.Number())) if err != nil { return nil, err } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index cdffdc6024..0bc4cd81e6 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -357,7 +357,7 @@ func BenchmarkTransactionTrace(b *testing.B) { //DisableReturnData: true, }) evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer}) - msg, err := tx.AsMessage(signer, nil) + msg, err := tx.AsMessage(signer) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 9fa5bf87a4..341acf978f 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -17,7 +17,6 @@ package ethclient import ( - "bytes" "context" "errors" "fmt" @@ -262,9 +261,7 @@ func TestEthClient(t *testing.T) { "TestCallContract": { func(t *testing.T) { testCallContract(t, client) }, }, - "TestAtFunctions": { - func(t *testing.T) { testAtFunctions(t, client) }, - }, + // DO not have TestAtFunctions now, because we do not have pending block now } t.Parallel() @@ -490,69 +487,6 @@ func testCallContract(t *testing.T, client *rpc.Client) { } } -func testAtFunctions(t *testing.T, client *rpc.Client) { - ec := NewClient(client) - // send a transaction for some interesting pending status - sendTransaction(ec) - time.Sleep(100 * time.Millisecond) - // Check pending transaction count - pending, err := ec.PendingTransactionCount(context.Background()) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if pending != 1 { - t.Fatalf("unexpected pending, wanted 1 got: %v", pending) - } - // Query balance - balance, err := ec.BalanceAt(context.Background(), testAddr, nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - penBalance, err := ec.PendingBalanceAt(context.Background(), testAddr) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if balance.Cmp(penBalance) == 0 { - t.Fatalf("unexpected balance: %v %v", balance, penBalance) - } - // NonceAt - nonce, err := ec.NonceAt(context.Background(), testAddr, nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - penNonce, err := ec.PendingNonceAt(context.Background(), testAddr) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if penNonce != nonce+1 { - t.Fatalf("unexpected nonce: %v %v", nonce, penNonce) - } - // StorageAt - storage, err := ec.StorageAt(context.Background(), testAddr, common.Hash{}, nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - penStorage, err := ec.PendingStorageAt(context.Background(), testAddr, common.Hash{}) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !bytes.Equal(storage, penStorage) { - t.Fatalf("unexpected storage: %v %v", storage, penStorage) - } - // CodeAt - code, err := ec.CodeAt(context.Background(), testAddr, nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - penCode, err := ec.PendingCodeAt(context.Background(), testAddr) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !bytes.Equal(code, penCode) { - t.Fatalf("unexpected code: %v %v", code, penCode) - } -} - func sendTransaction(ec *Client) error { // Retrieve chainID chainID, err := ec.ChainID(context.Background()) @@ -560,7 +494,7 @@ func sendTransaction(ec *Client) error { return err } // Create transaction - tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil) + tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 23000, big.NewInt(100000), nil) signer := types.LatestSignerForChainID(chainID) signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) if err != nil { diff --git a/ethdb/database.go b/ethdb/database.go index 0dc14624b9..40d0e01d57 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -118,11 +118,17 @@ type AncientStore interface { io.Closer } +type DiffStore interface { + DiffStore() KeyValueStore + SetDiffStore(diff KeyValueStore) +} + // Database contains all the methods required by the high level database to not // only access the key-value data store but also the chain freezer. type Database interface { Reader Writer + DiffStore Batcher Iteratee Stater diff --git a/les/fetcher.go b/les/fetcher.go index fc4c5e386a..ed2e72a330 100644 --- a/les/fetcher.go +++ b/les/fetcher.go @@ -339,7 +339,7 @@ func (f *lightFetcher) mainloop() { log.Debug("Trigger light sync", "peer", peerid, "local", localHead.Number, "localhash", localHead.Hash(), "remote", data.Number, "remotehash", data.Hash) continue } - f.fetcher.Notify(peerid.String(), data.Hash, data.Number, time.Now(), f.requestHeaderByHash(peerid), nil) + f.fetcher.Notify(peerid.String(), data.Hash, data.Number, time.Now(), f.requestHeaderByHash(peerid), nil, nil) log.Debug("Trigger header retrieval", "peer", peerid, "number", data.Number, "hash", data.Hash) } // Keep collecting announces from trusted server even we are syncing. @@ -355,7 +355,7 @@ func (f *lightFetcher) mainloop() { continue } p := agreed[rand.Intn(len(agreed))] - f.fetcher.Notify(p.String(), data.Hash, data.Number, time.Now(), f.requestHeaderByHash(p), nil) + f.fetcher.Notify(p.String(), data.Hash, data.Number, time.Now(), f.requestHeaderByHash(p), nil, nil) log.Debug("Trigger trusted header retrieval", "number", data.Number, "hash", data.Hash) } } diff --git a/les/peer.go b/les/peer.go index 5cdd557a90..e09b3bc130 100644 --- a/les/peer.go +++ b/les/peer.go @@ -1054,7 +1054,7 @@ func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, ge // If local ethereum node is running in archive mode, advertise ourselves we have // all version state data. Otherwise only recent state is available. - stateRecent := uint64(server.handler.blockchain.TriesInMemory() - blockSafetyMargin) + stateRecent := server.handler.blockchain.TriesInMemory() - blockSafetyMargin if server.archiveMode { stateRecent = 0 } diff --git a/light/trie.go b/light/trie.go index e189634e1c..3896b73c4d 100644 --- a/light/trie.go +++ b/light/trie.go @@ -95,17 +95,11 @@ func (db *odrDatabase) TrieDB() *trie.Database { return nil } -func (db *odrDatabase) CacheAccount(_ common.Hash, _ state.Trie) { - return -} +func (db *odrDatabase) CacheAccount(_ common.Hash, _ state.Trie) {} -func (db *odrDatabase) CacheStorage(_ common.Hash, _ common.Hash, _ state.Trie) { - return -} +func (db *odrDatabase) CacheStorage(_ common.Hash, _ common.Hash, _ state.Trie) {} -func (db *odrDatabase) Purge() { - return -} +func (db *odrDatabase) Purge() {} type odrTrie struct { db *odrDatabase diff --git a/miner/worker.go b/miner/worker.go index 984af7baaf..ef7a8c5630 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1011,16 +1011,6 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st return nil } -// copyReceipts makes a deep copy of the given receipts. -func copyReceipts(receipts []*types.Receipt) []*types.Receipt { - result := make([]*types.Receipt, len(receipts)) - for i, l := range receipts { - cpy := *l - result[i] = &cpy - } - return result -} - // postSideBlock fires a side chain event, only use it for testing. func (w *worker) postSideBlock(event core.ChainSideEvent) { select { @@ -1028,12 +1018,3 @@ func (w *worker) postSideBlock(event core.ChainSideEvent) { case <-w.exitCh: } } - -// totalFees computes total consumed fees in ETH. Block transactions and receipts have to have the same order. -func totalFees(block *types.Block, receipts []*types.Receipt) *big.Float { - feesWei := new(big.Int) - for i, tx := range block.Transactions() { - feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())) - } - return new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) -} diff --git a/node/config.go b/node/config.go index 23461c1916..527cd36415 100644 --- a/node/config.go +++ b/node/config.go @@ -98,6 +98,9 @@ type Config struct { // DirectBroadcast enable directly broadcast mined block to all peers DirectBroadcast bool `toml:",omitempty"` + // DisableSnapProtocol disable the snap protocol + DisableSnapProtocol bool `toml:",omitempty"` + // RangeLimit enable 5000 blocks limit when handle range query RangeLimit bool `toml:",omitempty"` diff --git a/node/node.go b/node/node.go index f2602dee47..f1564bea23 100644 --- a/node/node.go +++ b/node/node.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/leveldb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" @@ -578,6 +579,22 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r return db, err } +func (n *Node) OpenAndMergeDatabase(name string, cache, handles int, freezer, diff, namespace string, readonly, persistDiff bool) (ethdb.Database, error) { + chainDB, err := n.OpenDatabaseWithFreezer(name, cache, handles, freezer, namespace, readonly) + if err != nil { + return nil, err + } + if persistDiff { + diffStore, err := n.OpenDiffDatabase(name, handles, diff, namespace, readonly) + if err != nil { + chainDB.Close() + return nil, err + } + chainDB.SetDiffStore(diffStore) + } + return chainDB, nil +} + // OpenDatabaseWithFreezer opens an existing database with the given name (or // creates one if no previous can be found) from within the node's data directory, // also attaching a chain freezer to it that moves ancient chain data from the @@ -611,6 +628,30 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, return db, err } +func (n *Node) OpenDiffDatabase(name string, handles int, diff, namespace string, readonly bool) (*leveldb.Database, error) { + n.lock.Lock() + defer n.lock.Unlock() + if n.state == closedState { + return nil, ErrNodeStopped + } + + var db *leveldb.Database + var err error + if n.config.DataDir == "" { + panic("datadir is missing") + } + root := n.ResolvePath(name) + switch { + case diff == "": + diff = filepath.Join(root, "diff") + case !filepath.IsAbs(diff): + diff = n.ResolvePath(diff) + } + db, err = leveldb.New(diff, 0, handles, namespace, readonly) + + return db, err +} + // ResolvePath returns the absolute path of a resource in the instance directory. func (n *Node) ResolvePath(x string) string { return n.config.ResolvePath(x) diff --git a/rlp/typecache.go b/rlp/typecache.go index 62553d3b55..c21025ad26 100644 --- a/rlp/typecache.go +++ b/rlp/typecache.go @@ -172,16 +172,6 @@ func structFields(typ reflect.Type) (fields []field, err error) { return fields, nil } -// anyOptionalFields returns the index of the first field with "optional" tag. -func firstOptionalField(fields []field) int { - for i, f := range fields { - if f.optional { - return i - } - } - return len(fields) -} - type structFieldError struct { typ reflect.Type field int diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 19c79b6eed..77d4fd08d4 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -226,7 +226,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo } } // Commit and re-open to start with a clean state. - root, _ := statedb.Commit(false) + root, _, _ := statedb.Commit(false) var snaps *snapshot.Tree if snapshotter { From b2f1d25f83f75ba39d3e310743a01dd4fbde09bf Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Fri, 8 Oct 2021 12:29:38 +0800 Subject: [PATCH 031/117] Export get diff accounts in block api (#431) * support get diff accounts Signed-off-by: Keefe-Liu * add testcase for diff accounts Signed-off-by: Keefe-Liu --- core/blockchain.go | 36 ++++++++ core/blockchain_diff_test.go | 174 +++++++++++++++++++++++++++++++---- core/types/block.go | 11 +++ eth/api_backend.go | 4 + ethclient/ethclient.go | 14 +++ ethclient/ethclient_test.go | 169 ++++++++++++++++++++++++++++++++-- internal/ethapi/api.go | 106 +++++++++++++++++++++ internal/ethapi/backend.go | 1 + les/api_backend.go | 4 + 9 files changed, 495 insertions(+), 24 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 3cfa21654f..7157d39455 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -974,6 +974,42 @@ func (bc *BlockChain) GetDiffLayerRLP(blockHash common.Hash) rlp.RawValue { return rawData } +func (bc *BlockChain) GetDiffAccounts(blockHash common.Hash) ([]common.Address, error) { + var ( + accounts []common.Address + diffLayer *types.DiffLayer + ) + + header := bc.GetHeaderByHash(blockHash) + if header == nil { + return nil, fmt.Errorf("no block found") + } + + if cached, ok := bc.diffLayerCache.Get(blockHash); ok { + diffLayer = cached.(*types.DiffLayer) + } else if diffStore := bc.db.DiffStore(); diffStore != nil { + diffLayer = rawdb.ReadDiffLayer(diffStore, blockHash) + } + + if diffLayer == nil { + if header.TxHash != types.EmptyRootHash { + return nil, fmt.Errorf("no diff layer found") + } + + return nil, nil + } + + for _, diffAccounts := range diffLayer.Accounts { + accounts = append(accounts, diffAccounts.Account) + } + + if header.TxHash != types.EmptyRootHash && len(accounts) == 0 { + return nil, fmt.Errorf("no diff account in block, maybe bad diff layer") + } + + return accounts, nil +} + // HasBlock checks if a block is fully present in the database or not. func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool { if bc.blockCache.Contains(hash) { diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index 717b4039ed..bec463136e 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -45,8 +45,79 @@ var ( testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") // testAddr is the Ethereum address of the tester account. testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + // testBlocks is the test parameters array for specific blocks. + testBlocks = []testBlockParam{ + { + // This txs params also used to default block. + blockNr: 11, + txs: []testTransactionParam{ + { + to: common.Address{0x01}, + value: big.NewInt(1), + gasPrice: big.NewInt(1), + data: nil, + }, + }, + }, + { + blockNr: 12, + txs: []testTransactionParam{ + { + to: common.Address{0x01}, + value: big.NewInt(1), + gasPrice: big.NewInt(1), + data: nil, + }, + { + to: common.Address{0x02}, + value: big.NewInt(2), + gasPrice: big.NewInt(2), + data: nil, + }, + }, + }, + { + blockNr: 13, + txs: []testTransactionParam{ + { + to: common.Address{0x01}, + value: big.NewInt(1), + gasPrice: big.NewInt(1), + data: nil, + }, + { + to: common.Address{0x02}, + value: big.NewInt(2), + gasPrice: big.NewInt(2), + data: nil, + }, + { + to: common.Address{0x03}, + value: big.NewInt(3), + gasPrice: big.NewInt(3), + data: nil, + }, + }, + }, + { + blockNr: 14, + txs: []testTransactionParam{}, + }, + } ) +type testTransactionParam struct { + to common.Address + value *big.Int + gasPrice *big.Int + data []byte +} + +type testBlockParam struct { + blockNr int + txs []testTransactionParam +} + // 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. @@ -78,13 +149,35 @@ func newTestBackendWithGenerator(blocks int, lightProcess bool) *testBackend { // lets unset (nil). Set it here to the correct value. block.SetCoinbase(testAddr) - // We want to simulate an empty middle block, having the same state as the - // first one. The last is needs a state change again to force a reorg. - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), common.Address{0x01}, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testKey) - if err != nil { - panic(err) + for idx, testBlock := range testBlocks { + // Specific block setting, the index in this generator has 1 diff from specified blockNr. + if i+1 == testBlock.blockNr { + for _, testTransaction := range testBlock.txs { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, + testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain, tx) + } + break + } + + // Default block setting. + if idx == len(testBlocks)-1 { + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + for _, testTransaction := range testBlocks[0].txs { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, + testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain, tx) + } + } } - block.AddTxWithChain(chain, tx) + } bs, _ := GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator) if _, err := chain.InsertChain(bs); err != nil { @@ -139,12 +232,17 @@ func TestProcessDiffLayer(t *testing.T) { } blockHash := block.Hash() rawDiff := fullBackend.chain.GetDiffLayerRLP(blockHash) - diff, err := rawDataToDiffLayer(rawDiff) - if err != nil { - t.Errorf("failed to decode rawdata %v", err) + if len(rawDiff) != 0 { + diff, err := rawDataToDiffLayer(rawDiff) + if err != nil { + t.Errorf("failed to decode rawdata %v", err) + } + if diff == nil { + continue + } + lightBackend.Chain().HandleDiffLayer(diff, "testpid", true) } - lightBackend.Chain().HandleDiffLayer(diff, "testpid", true) - _, err = lightBackend.chain.insertChain([]*types.Block{block}, true) + _, err := lightBackend.chain.insertChain([]*types.Block{block}, true) if err != nil { t.Errorf("failed to insert block %v", err) } @@ -186,7 +284,8 @@ func TestFreezeDiffLayer(t *testing.T) { blockNum := 1024 fullBackend := newTestBackend(blockNum, true) defer fullBackend.close() - if fullBackend.chain.diffQueue.Size() != blockNum { + // Minus one empty block. + if fullBackend.chain.diffQueue.Size() != blockNum-1 { t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum, fullBackend.chain.diffQueue.Size()) } time.Sleep(diffLayerFreezerRecheckInterval + 1*time.Second) @@ -215,10 +314,11 @@ func TestPruneDiffLayer(t *testing.T) { for num := uint64(1); num < uint64(blockNum); num++ { header := fullBackend.chain.GetHeaderByNumber(num) rawDiff := fullBackend.chain.GetDiffLayerRLP(header.Hash()) - diff, _ := rawDataToDiffLayer(rawDiff) - fullBackend.Chain().HandleDiffLayer(diff, "testpid1", true) - fullBackend.Chain().HandleDiffLayer(diff, "testpid2", true) - + if len(rawDiff) != 0 { + diff, _ := rawDataToDiffLayer(rawDiff) + fullBackend.Chain().HandleDiffLayer(diff, "testpid1", true) + fullBackend.Chain().HandleDiffLayer(diff, "testpid2", true) + } } fullBackend.chain.pruneDiffLayer() if len(fullBackend.chain.diffNumToBlockHashes) != maxDiffForkDist { @@ -261,3 +361,45 @@ func TestPruneDiffLayer(t *testing.T) { } } + +func TestGetDiffAccounts(t *testing.T) { + t.Parallel() + + blockNum := 128 + fullBackend := newTestBackend(blockNum, false) + defer fullBackend.close() + + for _, testBlock := range testBlocks { + block := fullBackend.chain.GetBlockByNumber(uint64(testBlock.blockNr)) + if block == nil { + t.Fatal("block should not be nil") + } + blockHash := block.Hash() + accounts, err := fullBackend.chain.GetDiffAccounts(blockHash) + if err != nil { + t.Errorf("get diff accounts eror for block number (%d): %v", testBlock.blockNr, err) + } + + for idx, account := range accounts { + if testAddr == account { + break + } + + if idx == len(accounts)-1 { + t.Errorf("the diff accounts does't include addr: %v", testAddr) + } + } + + for _, transaction := range testBlock.txs { + for idx, account := range accounts { + if transaction.to == account { + break + } + + if idx == len(accounts)-1 { + t.Errorf("the diff accounts does't include addr: %v", transaction.to) + } + } + } + } +} diff --git a/core/types/block.go b/core/types/block.go index a577e60516..bee5d80cdd 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -453,3 +453,14 @@ type DiffStorage struct { Keys []string Vals [][]byte } + +type DiffAccountsInTx struct { + TxHash common.Hash + Accounts map[common.Address]*big.Int +} + +type DiffAccountsInBlock struct { + Number uint64 + BlockHash common.Hash + Transactions []DiffAccountsInTx +} diff --git a/eth/api_backend.go b/eth/api_backend.go index 7ac1f82a86..5c864a236b 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -279,6 +279,10 @@ func (b *EthAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) { return b.gpo.SuggestPrice(ctx) } +func (b *EthAPIBackend) Chain() *core.BlockChain { + return b.eth.BlockChain() +} + func (b *EthAPIBackend) ChainDb() ethdb.Database { return b.eth.ChainDb() } diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 81fbe5b407..578b10f09a 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -186,6 +186,20 @@ func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H return head, err } +// GetDiffAccounts returns changed accounts in a specific block number. +func (ec *Client) GetDiffAccounts(ctx context.Context, number *big.Int) ([]common.Address, error) { + accounts := make([]common.Address, 0) + err := ec.c.CallContext(ctx, &accounts, "eth_getDiffAccounts", toBlockNumArg(number)) + return accounts, err +} + +// GetDiffAccountsWithScope returns detailed changes of some interested accounts in a specific block number. +func (ec *Client) GetDiffAccountsWithScope(ctx context.Context, number *big.Int, accounts []common.Address) (*types.DiffAccountsInBlock, error) { + var result types.DiffAccountsInBlock + err := ec.c.CallContext(ctx, &result, "eth_getDiffAccountsWithScope", toBlockNumArg(number), accounts) + return &result, err +} + type rpcTransaction struct { tx *types.Transaction txExtraInfo diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 341acf978f..d2fd056041 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -31,9 +31,11 @@ import ( "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/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -181,11 +183,82 @@ func TestToFilterArg(t *testing.T) { } var ( - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testAddr = crypto.PubkeyToAddress(testKey.PublicKey) - testBalance = big.NewInt(2e10) + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + testBalance = big.NewInt(2e10) + testBlockNum = 128 + testBlocks = []testBlockParam{ + { + // This txs params also used to default block. + blockNr: 10, + txs: []testTransactionParam{}, + }, + { + blockNr: 11, + txs: []testTransactionParam{ + { + to: common.Address{0x01}, + value: big.NewInt(1), + gasPrice: big.NewInt(1), + data: nil, + }, + }, + }, + { + blockNr: 12, + txs: []testTransactionParam{ + { + to: common.Address{0x01}, + value: big.NewInt(1), + gasPrice: big.NewInt(1), + data: nil, + }, + { + to: common.Address{0x02}, + value: big.NewInt(2), + gasPrice: big.NewInt(2), + data: nil, + }, + }, + }, + { + blockNr: 13, + txs: []testTransactionParam{ + { + to: common.Address{0x01}, + value: big.NewInt(1), + gasPrice: big.NewInt(1), + data: nil, + }, + { + to: common.Address{0x02}, + value: big.NewInt(2), + gasPrice: big.NewInt(2), + data: nil, + }, + { + to: common.Address{0x03}, + value: big.NewInt(3), + gasPrice: big.NewInt(3), + data: nil, + }, + }, + }, + } ) +type testTransactionParam struct { + to common.Address + value *big.Int + gasPrice *big.Int + data []byte +} + +type testBlockParam struct { + blockNr int + txs []testTransactionParam +} + func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { // Generate test chain. genesis, blocks := generateTestChain() @@ -197,6 +270,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { // Create Ethereum Service config := ðconfig.Config{Genesis: genesis} config.Ethash.PowMode = ethash.ModeFake + config.SnapshotCache = 256 ethservice, err := eth.New(n, config) if err != nil { t.Fatalf("can't create new ethereum service: %v", err) @@ -212,7 +286,10 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { } func generateTestChain() (*core.Genesis, []*types.Block) { + signer := types.HomesteadSigner{} + // Create a database pre-initialize with a genesis block db := rawdb.NewMemoryDatabase() + db.SetDiffStore(memorydb.New()) config := params.AllEthashProtocolChanges genesis := &core.Genesis{ Config: config, @@ -220,13 +297,45 @@ func generateTestChain() (*core.Genesis, []*types.Block) { ExtraData: []byte("test genesis"), Timestamp: 9000, } - generate := func(i int, g *core.BlockGen) { - g.OffsetTime(5) - g.SetExtra([]byte("test")) + genesis.MustCommit(db) + chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, core.EnablePersistDiff(860000)) + generate := func(i int, block *core.BlockGen) { + block.OffsetTime(5) + block.SetExtra([]byte("test")) + //block.SetCoinbase(testAddr) + + for idx, testBlock := range testBlocks { + // Specific block setting, the index in this generator has 1 diff from specified blockNr. + if i+1 == testBlock.blockNr { + for _, testTransaction := range testBlock.txs { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, + testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain, tx) + } + break + } + + // Default block setting. + if idx == len(testBlocks)-1 { + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + for _, testTransaction := range testBlocks[0].txs { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, + testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain, tx) + } + } + } } gblock := genesis.ToBlock(db) engine := ethash.NewFaker() - blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate) + blocks, _ := core.GenerateChain(config, gblock, engine, db, testBlockNum, generate) blocks = append([]*types.Block{gblock}, blocks...) return genesis, blocks } @@ -261,6 +370,9 @@ func TestEthClient(t *testing.T) { "TestCallContract": { func(t *testing.T) { testCallContract(t, client) }, }, + "TestDiffAccounts": { + func(t *testing.T) { testDiffAccounts(t, client) }, + }, // DO not have TestAtFunctions now, because we do not have pending block now } @@ -393,7 +505,7 @@ func testGetBlock(t *testing.T, client *rpc.Client) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if blockNumber != 1 { + if blockNumber != uint64(testBlockNum) { t.Fatalf("BlockNumber returned wrong number: %d", blockNumber) } // Get current block by number @@ -507,3 +619,44 @@ func sendTransaction(ec *Client) error { // Send transaction return ec.SendTransaction(context.Background(), signedTx) } + +func testDiffAccounts(t *testing.T, client *rpc.Client) { + ec := NewClient(client) + ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Millisecond) + defer cancel() + + for _, testBlock := range testBlocks { + if testBlock.blockNr == 10 { + continue + } + diffAccounts, err := ec.GetDiffAccounts(ctx, big.NewInt(int64(testBlock.blockNr))) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + accounts := make([]common.Address, 0) + for _, tx := range testBlock.txs { + // tx.to should be in the accounts list. + for idx, account := range diffAccounts { + if tx.to == account { + break + } + + if idx == len(diffAccounts)-1 { + t.Fatalf("address(%v) expected in the diff account list, but not", tx.to) + } + } + + accounts = append(accounts, tx.to) + } + + diffDetail, err := ec.GetDiffAccountsWithScope(ctx, big.NewInt(int64(testBlock.blockNr)), accounts) + if err != nil { + t.Fatalf("get diff accounts in block error: %v", err) + } + // No contract deposit tx, so expect empty transactions. + if len(diffDetail.Transactions) != 0 { + t.Fatalf("expect ignore all transactions, but some transaction has recorded") + } + } +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 15e7a8c8f1..e6064ab787 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/common/gopool" "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/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" @@ -1086,6 +1087,111 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs, bl return DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap()) } +// GetDiffAccounts returns changed accounts in a specific block number. +func (s *PublicBlockChainAPI) GetDiffAccounts(ctx context.Context, blockNr rpc.BlockNumber) ([]common.Address, error) { + if s.b.Chain() == nil { + return nil, fmt.Errorf("blockchain not support get diff accounts") + } + + header, err := s.b.HeaderByNumber(ctx, blockNr) + if err != nil { + return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) + } + + return s.b.Chain().GetDiffAccounts(header.Hash()) +} + +// GetDiffAccountsWithScope returns detailed changes of some interested accounts in a specific block number. +func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, blockNr rpc.BlockNumber, accounts []common.Address) (*types.DiffAccountsInBlock, error) { + if s.b.Chain() == nil { + return nil, fmt.Errorf("blockchain not support get diff accounts") + } + + block, err := s.b.BlockByNumber(ctx, blockNr) + if err != nil { + return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) + } + parent, err := s.b.BlockByHash(ctx, block.ParentHash()) + if err != nil { + return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr-1, err) + } + statedb, err := s.b.Chain().StateAt(parent.Root()) + if err != nil { + return nil, fmt.Errorf("state not found for block number (%d): %v", blockNr-1, err) + } + + result := &types.DiffAccountsInBlock{ + Number: uint64(blockNr), + BlockHash: block.Hash(), + Transactions: make([]types.DiffAccountsInTx, 0), + } + + accountSet := make(map[common.Address]struct{}, len(accounts)) + for _, account := range accounts { + accountSet[account] = struct{}{} + } + + // Recompute transactions. + signer := types.MakeSigner(s.b.ChainConfig(), block.Number()) + for _, tx := range block.Transactions() { + // Skip data empty tx and to is one of the interested accounts tx. + skip := false + if len(tx.Data()) == 0 { + skip = true + } else if to := tx.To(); to != nil { + if _, exists := accountSet[*to]; exists { + skip = true + } + } + + diffTx := types.DiffAccountsInTx{ + TxHash: tx.Hash(), + Accounts: make(map[common.Address]*big.Int, len(accounts)), + } + + if !skip { + // Record account balance + for _, account := range accounts { + diffTx.Accounts[account] = statedb.GetBalance(account) + } + } + + // Apply transaction + msg, _ := tx.AsMessage(signer) + txContext := core.NewEVMTxContext(msg) + context := core.NewEVMBlockContext(block.Header(), s.b.Chain(), nil) + vmenv := vm.NewEVM(context, txContext, statedb, s.b.ChainConfig(), vm.Config{}) + + if posa, ok := s.b.Engine().(consensus.PoSA); ok { + if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem { + balance := statedb.GetBalance(consensus.SystemAddress) + if balance.Cmp(common.Big0) > 0 { + statedb.SetBalance(consensus.SystemAddress, big.NewInt(0)) + statedb.AddBalance(block.Header().Coinbase, balance) + } + } + } + + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + return nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + } + statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) + + if !skip { + // Compute account balance diff. + for _, account := range accounts { + diffTx.Accounts[account] = new(big.Int).Sub(statedb.GetBalance(account), diffTx.Accounts[account]) + if diffTx.Accounts[account].Cmp(big.NewInt(0)) == 0 { + delete(diffTx.Accounts, account) + } + } + result.Transactions = append(result.Transactions, diffTx) + } + } + + return result, nil +} + // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 07e76583f3..ca5a55d5ed 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -42,6 +42,7 @@ type Backend interface { // General Ethereum API Downloader() *downloader.Downloader SuggestPrice(ctx context.Context) (*big.Int, error) + Chain() *core.BlockChain ChainDb() ethdb.Database AccountManager() *accounts.Manager ExtRPCEnabled() bool diff --git a/les/api_backend.go b/les/api_backend.go index 60c64a8bdf..c8eca2d905 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -255,6 +255,10 @@ func (b *LesApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) { return b.gpo.SuggestPrice(ctx) } +func (b *LesApiBackend) Chain() *core.BlockChain { + return nil +} + func (b *LesApiBackend) ChainDb() ethdb.Database { return b.eth.chainDb } From 0315f60924eec1256285085389aede47fd278255 Mon Sep 17 00:00:00 2001 From: Keefe-Liu Date: Fri, 8 Oct 2021 17:38:19 +0800 Subject: [PATCH 032/117] ignore empty tx in GetDiffAccountsWithScope Signed-off-by: Keefe-Liu --- internal/ethapi/api.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e6064ab787..da4cf8cad1 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1185,7 +1185,10 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc delete(diffTx.Accounts, account) } } - result.Transactions = append(result.Transactions, diffTx) + + if len(diffTx.Accounts) != 0 { + result.Transactions = append(result.Transactions, diffTx) + } } } From 03febe17c2151b9607493756524175450f4f86b6 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Mon, 11 Oct 2021 10:55:52 +0800 Subject: [PATCH 033/117] fix blockhash not correct for the logs of system tx receipt (#444) --- core/blockchain.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/blockchain.go b/core/blockchain.go index 7157d39455..491cae3043 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -459,6 +459,16 @@ func (bc *BlockChain) GetVMConfig() *vm.Config { } func (bc *BlockChain) cacheReceipts(hash common.Hash, receipts types.Receipts) { + // TODO, This is a hot fix for the block hash of logs is `0x0000000000000000000000000000000000000000000000000000000000000000` for system tx + // Please check details in https://github.com/binance-chain/bsc/issues/443 + // This is a temporary fix, the official fix should be a hard fork. + const possibleSystemReceipts = 3 // One slash tx, two reward distribute txs. + numOfReceipts := len(receipts) + for i := numOfReceipts - 1; i >= 0 && i >= numOfReceipts-possibleSystemReceipts; i-- { + for j := 0; j < len(receipts[i].Logs); j++ { + receipts[i].Logs[j].BlockHash = hash + } + } bc.receiptsCache.Add(hash, receipts) } From 5e210b311b540c3397c65efbac9b0ecd3de68fcf Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Tue, 12 Oct 2021 11:29:17 +0800 Subject: [PATCH 034/117] fix concurrent write seen of subfetcher (#446) --- core/state/trie_prefetcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 116302001d..ddecd7a202 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -105,7 +105,7 @@ func (p *triePrefetcher) abortLoop() { func (p *triePrefetcher) close() { for _, fetcher := range p.fetchers { p.abortChan <- fetcher // safe to do multiple times - + <-fetcher.term if metrics.Enabled { if fetcher.root == p.root { p.accountLoadMeter.Mark(int64(len(fetcher.seen))) From 610f6a5e633638794d1c215c74d87e2ce13e2f42 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Wed, 13 Oct 2021 11:30:19 +0800 Subject: [PATCH 035/117] [R4R] add extension in eth protocol handshake to disable tx broadcast (#412) * add extension for eth protocol handshake * fix comments --- eth/backend.go | 23 ++++++----- eth/downloader/peer.go | 8 ++-- eth/ethconfig/config.go | 5 ++- eth/ethconfig/gen_config.go | 6 +++ eth/handler.go | 55 +++++++++++++------------ eth/handler_eth_test.go | 10 ++--- eth/protocols/eth/broadcast.go | 6 +++ eth/protocols/eth/handshake.go | 62 ++++++++++++++++++++++++++++- eth/protocols/eth/handshake_test.go | 2 +- eth/protocols/eth/peer.go | 33 ++++++++++++--- eth/protocols/eth/protocol.go | 40 ++++++++++++++++++- 11 files changed, 193 insertions(+), 57 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index bdae4b4235..f6599529db 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -231,17 +231,18 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } if eth.handler, err = newHandler(&handlerConfig{ - Database: chainDb, - Chain: eth.blockchain, - TxPool: eth.txPool, - Network: config.NetworkId, - Sync: config.SyncMode, - BloomCache: uint64(cacheLimit), - EventMux: eth.eventMux, - Checkpoint: checkpoint, - Whitelist: config.Whitelist, - DirectBroadcast: config.DirectBroadcast, - DiffSync: config.DiffSync, + Database: chainDb, + Chain: eth.blockchain, + TxPool: eth.txPool, + Network: config.NetworkId, + Sync: config.SyncMode, + BloomCache: uint64(cacheLimit), + EventMux: eth.eventMux, + Checkpoint: checkpoint, + Whitelist: config.Whitelist, + DirectBroadcast: config.DirectBroadcast, + DiffSync: config.DiffSync, + DisablePeerTxBroadcast: config.DisablePeerTxBroadcast, }); err != nil { return nil, err } diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go index 4d76988f71..297ba2fa55 100644 --- a/eth/downloader/peer.go +++ b/eth/downloader/peer.go @@ -457,7 +457,7 @@ func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) { defer p.lock.RUnlock() return p.headerThroughput } - return ps.idlePeers(eth.ETH65, eth.ETH66, idle, throughput) + return ps.idlePeers(eth.ETH65, eth.ETH67, idle, throughput) } // BodyIdlePeers retrieves a flat list of all the currently body-idle peers within @@ -471,7 +471,7 @@ func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) { defer p.lock.RUnlock() return p.blockThroughput } - return ps.idlePeers(eth.ETH65, eth.ETH66, idle, throughput) + return ps.idlePeers(eth.ETH65, eth.ETH67, idle, throughput) } // ReceiptIdlePeers retrieves a flat list of all the currently receipt-idle peers @@ -485,7 +485,7 @@ func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) { defer p.lock.RUnlock() return p.receiptThroughput } - return ps.idlePeers(eth.ETH65, eth.ETH66, idle, throughput) + return ps.idlePeers(eth.ETH65, eth.ETH67, idle, throughput) } // NodeDataIdlePeers retrieves a flat list of all the currently node-data-idle @@ -499,7 +499,7 @@ func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) { defer p.lock.RUnlock() return p.stateThroughput } - return ps.idlePeers(eth.ETH65, eth.ETH66, idle, throughput) + return ps.idlePeers(eth.ETH65, eth.ETH67, idle, throughput) } // idlePeers retrieves a flat list of all currently idle peers satisfying the diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index bf143ba02c..83db7fc998 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -124,8 +124,9 @@ type Config struct { Genesis *core.Genesis `toml:",omitempty"` // Protocol options - NetworkId uint64 // Network ID to use for selecting peers to connect to - SyncMode downloader.SyncMode + NetworkId uint64 // Network ID to use for selecting peers to connect to + SyncMode downloader.SyncMode + DisablePeerTxBroadcast bool // This can be set to list of enrtree:// URLs which will be queried for // for nodes to connect to. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 258ade2293..f192a1aace 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -20,6 +20,7 @@ func (c Config) MarshalTOML() (interface{}, error) { Genesis *core.Genesis `toml:",omitempty"` NetworkId uint64 SyncMode downloader.SyncMode + DisablePeerTxBroadcast bool EthDiscoveryURLs []string SnapDiscoveryURLs []string NoPruning bool @@ -68,6 +69,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.Genesis = c.Genesis enc.NetworkId = c.NetworkId enc.SyncMode = c.SyncMode + enc.DisablePeerTxBroadcast = c.DisablePeerTxBroadcast enc.EthDiscoveryURLs = c.EthDiscoveryURLs enc.SnapDiscoveryURLs = c.SnapDiscoveryURLs enc.NoPruning = c.NoPruning @@ -119,6 +121,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { Genesis *core.Genesis `toml:",omitempty"` NetworkId *uint64 SyncMode *downloader.SyncMode + DisablePeerTxBroadcast *bool EthDiscoveryURLs []string SnapDiscoveryURLs []string NoPruning *bool @@ -176,6 +179,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.SyncMode != nil { c.SyncMode = *dec.SyncMode } + if dec.DisablePeerTxBroadcast != nil { + c.DisablePeerTxBroadcast = *dec.DisablePeerTxBroadcast + } if dec.EthDiscoveryURLs != nil { c.EthDiscoveryURLs = dec.EthDiscoveryURLs } diff --git a/eth/handler.go b/eth/handler.go index 41b459d2d5..f00f955b34 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -78,22 +78,24 @@ type txPool interface { // handlerConfig is the collection of initialization parameters to create a full // node network handler. type handlerConfig struct { - Database ethdb.Database // Database for direct sync insertions - Chain *core.BlockChain // Blockchain to serve data from - TxPool txPool // Transaction pool to propagate from - Network uint64 // Network identifier to adfvertise - Sync downloader.SyncMode // Whether to fast or full sync - DiffSync bool // Whether to diff sync - BloomCache uint64 // Megabytes to alloc for fast sync bloom - EventMux *event.TypeMux // Legacy event mux, deprecate for `feed` - Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges - Whitelist map[uint64]common.Hash // Hard coded whitelist for sync challenged - DirectBroadcast bool + Database ethdb.Database // Database for direct sync insertions + Chain *core.BlockChain // Blockchain to serve data from + TxPool txPool // Transaction pool to propagate from + Network uint64 // Network identifier to adfvertise + Sync downloader.SyncMode // Whether to fast or full sync + DiffSync bool // Whether to diff sync + BloomCache uint64 // Megabytes to alloc for fast sync bloom + EventMux *event.TypeMux // Legacy event mux, deprecate for `feed` + Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges + Whitelist map[uint64]common.Hash // Hard coded whitelist for sync challenged + DirectBroadcast bool + DisablePeerTxBroadcast bool } type handler struct { - networkID uint64 - forkFilter forkid.Filter // Fork ID filter, constant across the lifetime of the node + networkID uint64 + forkFilter forkid.Filter // Fork ID filter, constant across the lifetime of the node + disablePeerTxBroadcast bool fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks) snapSync uint32 // Flag whether fast sync should operate on top of the snap protocol @@ -138,18 +140,19 @@ func newHandler(config *handlerConfig) (*handler, error) { config.EventMux = new(event.TypeMux) // Nicety initialization for tests } h := &handler{ - networkID: config.Network, - forkFilter: forkid.NewFilter(config.Chain), - eventMux: config.EventMux, - database: config.Database, - txpool: config.TxPool, - chain: config.Chain, - peers: newPeerSet(), - whitelist: config.Whitelist, - directBroadcast: config.DirectBroadcast, - diffSync: config.DiffSync, - txsyncCh: make(chan *txsync), - quitSync: make(chan struct{}), + networkID: config.Network, + forkFilter: forkid.NewFilter(config.Chain), + disablePeerTxBroadcast: config.DisablePeerTxBroadcast, + eventMux: config.EventMux, + database: config.Database, + txpool: config.TxPool, + chain: config.Chain, + peers: newPeerSet(), + whitelist: config.Whitelist, + directBroadcast: config.DirectBroadcast, + diffSync: config.DiffSync, + txsyncCh: make(chan *txsync), + quitSync: make(chan struct{}), } if config.Sync == downloader.FullSync { // The database seems empty as the current block is the genesis. Yet the fast @@ -276,7 +279,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { td = h.chain.GetTd(hash, number) ) forkID := forkid.NewID(h.chain.Config(), h.chain.Genesis().Hash(), h.chain.CurrentHeader().Number.Uint64()) - if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil { + if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter, ð.UpgradeStatusExtension{DisablePeerTxBroadcast: h.disablePeerTxBroadcast}); err != nil { peer.Log().Debug("Ethereum handshake failed", "err", err) return err } diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 1d38e3b666..271bae07c7 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -271,7 +271,7 @@ func testRecvTransactions(t *testing.T, protocol uint) { head = handler.chain.CurrentBlock() td = handler.chain.GetTd(head.Hash(), head.NumberU64()) ) - if err := src.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { + if err := src.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain), nil); err != nil { t.Fatalf("failed to run protocol handshake") } // Send the transaction to the sink and verify that it's added to the tx pool @@ -333,7 +333,7 @@ func testSendTransactions(t *testing.T, protocol uint) { head = handler.chain.CurrentBlock() td = handler.chain.GetTd(head.Hash(), head.NumberU64()) ) - if err := sink.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { + if err := sink.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain), nil); err != nil { t.Fatalf("failed to run protocol handshake") } // After the handshake completes, the source handler should stream the sink @@ -532,7 +532,7 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo head = handler.chain.CurrentBlock() td = handler.chain.GetTd(head.Hash(), head.NumberU64()) ) - if err := remote.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { + if err := remote.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain), nil); err != nil { t.Fatalf("failed to run protocol handshake") } // Connect a new peer and check that we receive the checkpoint challenge @@ -616,7 +616,7 @@ func testBroadcastBlock(t *testing.T, peers, bcasts int) { go source.handler.runEthPeer(sourcePeer, func(peer *eth.Peer) error { return eth.Handle((*ethHandler)(source.handler), peer) }) - if err := sinkPeer.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain)); err != nil { + if err := sinkPeer.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain), nil); err != nil { t.Fatalf("failed to run protocol handshake") } go eth.Handle(sink, sinkPeer) @@ -689,7 +689,7 @@ func testBroadcastMalformedBlock(t *testing.T, protocol uint) { genesis = source.chain.Genesis() td = source.chain.GetTd(genesis.Hash(), genesis.NumberU64()) ) - if err := sink.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain)); err != nil { + if err := sink.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain), nil); err != nil { t.Fatalf("failed to run protocol handshake") } // After the handshake completes, the source handler should stream the sink diff --git a/eth/protocols/eth/broadcast.go b/eth/protocols/eth/broadcast.go index e0ee2a1cfa..132eac0102 100644 --- a/eth/protocols/eth/broadcast.go +++ b/eth/protocols/eth/broadcast.go @@ -122,6 +122,9 @@ func (p *Peer) broadcastTransactions() { case <-fail: failed = true + case <-p.txTerm: + return + case <-p.term: return } @@ -189,6 +192,9 @@ func (p *Peer) announceTransactions() { case <-fail: failed = true + case <-p.txTerm: + return + case <-p.term: return } diff --git a/eth/protocols/eth/handshake.go b/eth/protocols/eth/handshake.go index b634f18e00..d604f045f4 100644 --- a/eth/protocols/eth/handshake.go +++ b/eth/protocols/eth/handshake.go @@ -35,7 +35,7 @@ const ( // Handshake executes the eth protocol handshake, negotiating version number, // network IDs, difficulties, head and genesis blocks. -func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter) error { +func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter, extension *UpgradeStatusExtension) error { // Send out own handshake in a new thread errc := make(chan error, 2) @@ -68,6 +68,49 @@ func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis } p.td, p.head = status.TD, status.Head + if p.version >= ETH67 { + var upgradeStatus UpgradeStatusPacket // safe to read after two values have been received from errc + if extension == nil { + extension = &UpgradeStatusExtension{} + } + extensionRaw, err := extension.Encode() + if err != nil { + return err + } + + gopool.Submit(func() { + errc <- p2p.Send(p.rw, UpgradeStatusMsg, &UpgradeStatusPacket{ + Extension: extensionRaw, + }) + }) + gopool.Submit(func() { + errc <- p.readUpgradeStatus(&upgradeStatus) + }) + timeout := time.NewTimer(handshakeTimeout) + defer timeout.Stop() + for i := 0; i < 2; i++ { + select { + case err := <-errc: + if err != nil { + return err + } + case <-timeout.C: + return p2p.DiscReadTimeout + } + } + + extension, err := upgradeStatus.GetExtension() + if err != nil { + return err + } + p.statusExtension = extension + + if p.statusExtension.DisablePeerTxBroadcast { + p.Log().Debug("peer does not need broadcast txs, closing broadcast routines") + p.CloseTxBroadcast() + } + } + // TD at mainnet block #7753254 is 76 bits. If it becomes 100 million times // larger, it will still fit within 100 bits if tdlen := p.td.BitLen(); tdlen > 100 { @@ -106,3 +149,20 @@ func (p *Peer) readStatus(network uint64, status *StatusPacket, genesis common.H } return nil } + +func (p *Peer) readUpgradeStatus(status *UpgradeStatusPacket) error { + msg, err := p.rw.ReadMsg() + if err != nil { + return err + } + if msg.Code != UpgradeStatusMsg { + return fmt.Errorf("%w: upgrade status msg has code %x (!= %x)", errNoStatusMsg, msg.Code, UpgradeStatusMsg) + } + if msg.Size > maxMessageSize { + return fmt.Errorf("%w: %v > %v", errMsgTooLarge, msg.Size, maxMessageSize) + } + if err := msg.Decode(&status); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + return nil +} diff --git a/eth/protocols/eth/handshake_test.go b/eth/protocols/eth/handshake_test.go index 3bebda2dcc..8a433f3ce4 100644 --- a/eth/protocols/eth/handshake_test.go +++ b/eth/protocols/eth/handshake_test.go @@ -81,7 +81,7 @@ func testHandshake(t *testing.T, protocol uint) { // Send the junk test with one peer, check the handshake failure go p2p.Send(app, test.code, test.data) - err := peer.Handshake(1, td, head.Hash(), genesis.Hash(), forkID, forkid.NewFilter(backend.chain)) + err := peer.Handshake(1, td, head.Hash(), genesis.Hash(), forkID, forkid.NewFilter(backend.chain), nil) if err == nil { t.Errorf("test %d: protocol returned nil error, want %q", i, test.want) } else if !errors.Is(err, test.want) { diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index e619c183ba..7ab4fa1a36 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -22,6 +22,7 @@ import ( "sync" mapset "github.com/deckarep/golang-set" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/p2p" @@ -68,9 +69,10 @@ func max(a, b int) int { type Peer struct { id string // Unique ID for the peer, cached - *p2p.Peer // The embedded P2P package peer - rw p2p.MsgReadWriter // Input/output streams for snap - version uint // Protocol version negotiated + *p2p.Peer // The embedded P2P package peer + rw p2p.MsgReadWriter // Input/output streams for snap + version uint // Protocol version negotiated + statusExtension *UpgradeStatusExtension head common.Hash // Latest advertised head block hash td *big.Int // Latest advertised head block total difficulty @@ -84,8 +86,9 @@ type Peer struct { txBroadcast chan []common.Hash // Channel used to queue transaction propagation requests txAnnounce chan []common.Hash // Channel used to queue transaction announcement requests - term chan struct{} // Termination channel to stop the broadcasters - lock sync.RWMutex // Mutex protecting the internal fields + term chan struct{} // Termination channel to stop the broadcasters + txTerm chan struct{} // Termination channel to stop the tx broadcasters + lock sync.RWMutex // Mutex protecting the internal fields } // NewPeer create a wrapper for a network connection and negotiated protocol @@ -104,6 +107,7 @@ func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter, txpool TxPool) *Pe txAnnounce: make(chan []common.Hash), txpool: txpool, term: make(chan struct{}), + txTerm: make(chan struct{}), } // Start up all the broadcasters go peer.broadcastBlocks() @@ -119,6 +123,17 @@ func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter, txpool TxPool) *Pe // clean it up! func (p *Peer) Close() { close(p.term) + + p.CloseTxBroadcast() +} + +// CloseTxBroadcast signals the tx broadcast goroutine to terminate. +func (p *Peer) CloseTxBroadcast() { + select { + case <-p.txTerm: + default: + close(p.txTerm) + } } // ID retrieves the peer's unique identifier. @@ -212,6 +227,10 @@ func (p *Peer) AsyncSendTransactions(hashes []common.Hash) { for _, hash := range hashes { p.knownTxs.Add(hash) } + + case <-p.txTerm: + p.Log().Debug("Dropping transaction propagation", "count", len(hashes)) + case <-p.term: p.Log().Debug("Dropping transaction propagation", "count", len(hashes)) } @@ -247,6 +266,10 @@ func (p *Peer) AsyncSendPooledTransactionHashes(hashes []common.Hash) { for _, hash := range hashes { p.knownTxs.Add(hash) } + + case <-p.txTerm: + p.Log().Debug("Dropping transaction announcement", "count", len(hashes)) + case <-p.term: p.Log().Debug("Dropping transaction announcement", "count", len(hashes)) } diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index de1b0ed1ee..3e0e0cf6ed 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -32,6 +32,7 @@ import ( const ( ETH65 = 65 ETH66 = 66 + ETH67 = 67 ) // 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{ETH66, ETH65} +var ProtocolVersions = []uint{ETH67, ETH66, ETH65} // protocolLengths are the number of implemented message corresponding to // different protocol versions. -var protocolLengths = map[uint]uint64{ETH66: 17, ETH65: 17} +var protocolLengths = map[uint]uint64{ETH67: 18, ETH66: 17, ETH65: 17} // maxMessageSize is the maximum cap on the size of a protocol message. const maxMessageSize = 10 * 1024 * 1024 @@ -68,6 +69,9 @@ const ( NewPooledTransactionHashesMsg = 0x08 GetPooledTransactionsMsg = 0x09 PooledTransactionsMsg = 0x0a + + // Protocol messages overloaded in eth/66 + UpgradeStatusMsg = 0x0b ) var ( @@ -97,6 +101,35 @@ type StatusPacket struct { ForkID forkid.ID } +type UpgradeStatusExtension struct { + DisablePeerTxBroadcast bool +} + +func (e *UpgradeStatusExtension) Encode() (*rlp.RawValue, error) { + rawBytes, err := rlp.EncodeToBytes(e) + if err != nil { + return nil, err + } + raw := rlp.RawValue(rawBytes) + return &raw, nil +} + +type UpgradeStatusPacket struct { + Extension *rlp.RawValue `rlp:"nil"` +} + +func (p *UpgradeStatusPacket) GetExtension() (*UpgradeStatusExtension, error) { + extension := &UpgradeStatusExtension{} + if p.Extension == nil { + return extension, nil + } + err := rlp.DecodeBytes(*p.Extension, extension) + if err != nil { + return nil, err + } + return extension, nil +} + // NewBlockHashesPacket is the network packet for the block announcements. type NewBlockHashesPacket []struct { Hash common.Hash // Hash of one particular block being announced @@ -324,6 +357,9 @@ type PooledTransactionsRLPPacket66 struct { func (*StatusPacket) Name() string { return "Status" } func (*StatusPacket) Kind() byte { return StatusMsg } +func (*UpgradeStatusPacket) Name() string { return "UpgradeStatus" } +func (*UpgradeStatusPacket) Kind() byte { return UpgradeStatusMsg } + func (*NewBlockHashesPacket) Name() string { return "NewBlockHashes" } func (*NewBlockHashesPacket) Kind() byte { return NewBlockHashesMsg } From 33aa77949fc027f43e815a735b212a5dc131fdae Mon Sep 17 00:00:00 2001 From: kyrie-yl <83150977+kyrie-yl@users.noreply.github.com> Date: Fri, 15 Oct 2021 15:12:14 +0800 Subject: [PATCH 036/117] cache bitmap and change the cache type of GetCode (#449) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * change cache type of GetCode from fastcache to lrucache Signed-off-by: kyrie-yl * add cache for contract code bitmap Signed-off-by: kyrie-yl * core/vm: rework jumpdest analysis benchmarks (#23499) * core/vm: rework jumpdest analysis benchmarks For BenchmarkJumpdestOpAnalysis use fixed code size of ~1.2MB and classic benchmark loop. * core/vm: clear bitvec in jumpdest analysis benchmark Co-authored-by: Paweł Bylica --- core/state/database.go | 28 ++++++++++++++++++---------- core/vm/analysis_test.go | 18 ++++++++++++++---- core/vm/contract.go | 19 +++++++++++++++---- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 0bcde2d5a9..24a1474d57 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -21,7 +21,6 @@ import ( "fmt" "time" - "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" @@ -134,22 +133,24 @@ func NewDatabase(db ethdb.Database) Database { // large memory cache. func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { csc, _ := lru.New(codeSizeCacheSize) + cc, _ := lru.New(codeCacheSize) return &cachingDB{ db: trie.NewDatabaseWithConfig(db, config), codeSizeCache: csc, - codeCache: fastcache.New(codeCacheSize), + codeCache: cc, } } func NewDatabaseWithConfigAndCache(db ethdb.Database, config *trie.Config) Database { csc, _ := lru.New(codeSizeCacheSize) + cc, _ := lru.New(codeCacheSize) atc, _ := lru.New(accountTrieCacheSize) stc, _ := lru.New(storageTrieCacheSize) database := &cachingDB{ db: trie.NewDatabaseWithConfig(db, config), codeSizeCache: csc, - codeCache: fastcache.New(codeCacheSize), + codeCache: cc, accountTrieCache: atc, storageTrieCache: stc, } @@ -160,7 +161,7 @@ func NewDatabaseWithConfigAndCache(db ethdb.Database, config *trie.Config) Datab type cachingDB struct { db *trie.Database codeSizeCache *lru.Cache - codeCache *fastcache.Cache + codeCache *lru.Cache accountTrieCache *lru.Cache storageTrieCache *lru.Cache } @@ -266,12 +267,16 @@ 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 { - return code, nil + if cached, ok := db.codeCache.Get(codeHash.Bytes()); ok { + code := cached.([]byte) + if len(code) > 0 { + return code, nil + } } code := rawdb.ReadCode(db.db.DiskDB(), codeHash) if len(code) > 0 { - db.codeCache.Set(codeHash.Bytes(), code) + + db.codeCache.Add(codeHash.Bytes(), code) db.codeSizeCache.Add(codeHash, len(code)) return code, nil } @@ -282,12 +287,15 @@ 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 { - return code, nil + if cached, ok := db.codeCache.Get(codeHash.Bytes()); ok { + code := cached.([]byte) + if len(code) > 0 { + return code, nil + } } code := rawdb.ReadCodeWithPrefix(db.db.DiskDB(), codeHash) if len(code) > 0 { - db.codeCache.Set(codeHash.Bytes(), code) + db.codeCache.Add(codeHash.Bytes(), code) db.codeSizeCache.Add(codeHash, len(code)) return code, nil } diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index 585bb3097f..d7f21e04aa 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -55,9 +55,12 @@ func TestJumpDestAnalysis(t *testing.T) { } } +const analysisCodeSize = 1200 * 1024 + func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) { // 1.4 ms - code := make([]byte, 1200000) + code := make([]byte, analysisCodeSize) + bench.SetBytes(analysisCodeSize) bench.ResetTimer() for i := 0; i < bench.N; i++ { codeBitmap(code) @@ -66,7 +69,8 @@ func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) { } func BenchmarkJumpdestHashing_1200k(bench *testing.B) { // 4 ms - code := make([]byte, 1200000) + code := make([]byte, analysisCodeSize) + bench.SetBytes(analysisCodeSize) bench.ResetTimer() for i := 0; i < bench.N; i++ { crypto.Keccak256Hash(code) @@ -77,13 +81,19 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) { func BenchmarkJumpdestOpAnalysis(bench *testing.B) { var op OpCode bencher := func(b *testing.B) { - code := make([]byte, 32*b.N) + code := make([]byte, analysisCodeSize) + b.SetBytes(analysisCodeSize) for i := range code { code[i] = byte(op) } bits := make(bitvec, len(code)/8+1+4) b.ResetTimer() - codeBitmapInternal(code, bits) + for i := 0; i < b.N; i++ { + for j := range bits { + bits[j] = 0 + } + codeBitmapInternal(code, bits) + } } for op = PUSH1; op <= PUSH32; op++ { bench.Run(op.String(), bencher) diff --git a/core/vm/contract.go b/core/vm/contract.go index 61dbd5007a..6fac7f9858 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -19,10 +19,16 @@ package vm import ( "math/big" + lru "github.com/hashicorp/golang-lru" + "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" ) +const codeBitmapCacheSize = 2000 + +var codeBitmapCache, _ = lru.New(codeBitmapCacheSize) + // ContractRef is a reference to the contract's backing object type ContractRef interface { Address() common.Address @@ -110,10 +116,15 @@ func (c *Contract) isCode(udest uint64) bool { // Does parent context have the analysis? analysis, exist := c.jumpdests[c.CodeHash] if !exist { - // Do the analysis and save in parent context - // We do not need to store it in c.analysis - analysis = codeBitmap(c.Code) - c.jumpdests[c.CodeHash] = analysis + if cached, ok := codeBitmapCache.Get(c.CodeHash); ok { + analysis = cached.(bitvec) + } else { + // Do the analysis and save in parent context + // We do not need to store it in c.analysis + analysis = codeBitmap(c.Code) + c.jumpdests[c.CodeHash] = analysis + codeBitmapCache.Add(c.CodeHash, analysis) + } } // Also stash it in current contract for faster access c.analysis = analysis From 31463f8dd1ccc8f1db0bd104eb69e5b8d7a775a0 Mon Sep 17 00:00:00 2001 From: Steven Tran Date: Fri, 15 Oct 2021 16:30:44 +0800 Subject: [PATCH 037/117] parallel bloom calculation (#445) * parallel bloom calculation * indent * add condition if bloomJobs not nil * add handler for worker * fix format * bloomWorker should exit when all txs have been processed * rename BloomPair => BloomHash * add size to map * rename & unique variable * bloomJobs => bloomProcessors * fix * only assign bloom if empty * abstraction method for processing receipt bloom * remove duplicate receipt_processor * rename Processor * fix ReceiptProcessor * fix ReceiptBloomGenertor typo * reduce worker to 1 * remove empty wg * add defence code to check if channel is closed * remove nil * format fix * remove thread pool * use max 100 worker capacity * reduce worker size * refactor startWorker --- core/chain_makers.go | 2 +- core/receipt_processor.go | 66 +++++++++++++++++++++++++++++++++++++++ core/state_processor.go | 20 ++++++++---- core/types/bloom9.go | 2 ++ core/types/transaction.go | 4 +++ eth/catalyst/api.go | 2 +- miner/worker.go | 15 +++++++-- 7 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 core/receipt_processor.go diff --git a/core/chain_makers.go b/core/chain_makers.go index 985aa61cd6..d8e3ee012f 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -104,7 +104,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), common.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{}) + receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}, NewReceiptBloomGenerator()) if err != nil { panic(err) } diff --git a/core/receipt_processor.go b/core/receipt_processor.go new file mode 100644 index 0000000000..57fb56a6dc --- /dev/null +++ b/core/receipt_processor.go @@ -0,0 +1,66 @@ +package core + +import ( + "bytes" + "sync" + + "github.com/ethereum/go-ethereum/core/types" +) + +type ReceiptProcessor interface { + Apply(receipt *types.Receipt) +} + +var ( + _ ReceiptProcessor = (*ReceiptBloomGenerator)(nil) + _ ReceiptProcessor = (*AsyncReceiptBloomGenerator)(nil) +) + +func NewReceiptBloomGenerator() *ReceiptBloomGenerator { + return &ReceiptBloomGenerator{} +} + +type ReceiptBloomGenerator struct { +} + +func (p *ReceiptBloomGenerator) Apply(receipt *types.Receipt) { + receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) +} + +func NewAsyncReceiptBloomGenerator(txNums int) *AsyncReceiptBloomGenerator { + generator := &AsyncReceiptBloomGenerator{ + receipts: make(chan *types.Receipt, txNums), + } + generator.startWorker() + return generator +} + +type AsyncReceiptBloomGenerator struct { + receipts chan *types.Receipt + wg sync.WaitGroup + isClosed bool +} + +func (p *AsyncReceiptBloomGenerator) startWorker() { + p.wg.Add(1) + go func() { + defer p.wg.Done() + for receipt := range p.receipts { + if receipt != nil && bytes.Equal(receipt.Bloom[:], types.EmptyBloom[:]) { + receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + } + } + }() +} + +func (p *AsyncReceiptBloomGenerator) Apply(receipt *types.Receipt) { + if !p.isClosed { + p.receipts <- receipt + } +} + +func (p *AsyncReceiptBloomGenerator) Close() { + close(p.receipts) + p.isClosed = true + p.wg.Wait() +} \ No newline at end of file diff --git a/core/state_processor.go b/core/state_processor.go index 973fd27b54..14bd5d75b2 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -390,9 +390,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg blockContext := NewEVMBlockContext(header, p.bc, nil) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) + txNum := len(block.Transactions()) // Iterate over and process the individual transactions posa, isPoSA := p.engine.(consensus.PoSA) - commonTxs := make([]*types.Transaction, 0, len(block.Transactions())) + commonTxs := make([]*types.Transaction, 0, txNum) + + // initilise bloom processors + bloomProcessors := NewAsyncReceiptBloomGenerator(txNum) + // usually do have two tx, one for validator set contract, another for system reward contract. systemTxs := make([]*types.Transaction, 0, 2) for i, tx := range block.Transactions() { @@ -410,7 +415,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return statedb, nil, nil, 0, err } statedb.Prepare(tx.Hash(), block.Hash(), i) - receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv) + receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv, bloomProcessors) if err != nil { return statedb, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -418,6 +423,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg commonTxs = append(commonTxs, tx) receipts = append(receipts, receipt) } + bloomProcessors.Close() // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) err := p.engine.Finalize(p.bc, header, statedb, &commonTxs, block.Uncles(), &receipts, &systemTxs, usedGas) @@ -431,7 +437,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return statedb, receipts, allLogs, *usedGas, nil } -func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { +func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, receiptProcessors ...ReceiptProcessor) (*types.Receipt, error) { // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) @@ -469,10 +475,12 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon // Set the receipt logs and create the bloom filter. receipt.Logs = statedb.GetLogs(tx.Hash()) - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) receipt.BlockHash = statedb.BlockHash() receipt.BlockNumber = header.Number receipt.TransactionIndex = uint(statedb.TxIndex()) + for _, receiptProcessor := range receiptProcessors { + receiptProcessor.Apply(receipt) + } return receipt, err } @@ -480,7 +488,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon // and uses the input parameters for its environment. It returns the receipt // 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) { +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, receiptProcessors ...ReceiptProcessor) (*types.Receipt, error) { msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { return nil, err @@ -493,5 +501,5 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo vm.EVMInterpreterPool.Put(ite) vm.EvmPool.Put(vmenv) }() - return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv) + return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv, receiptProcessors...) } diff --git a/core/types/bloom9.go b/core/types/bloom9.go index 1793c2adc7..342a0b0ec3 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -37,6 +37,8 @@ const ( BloomBitLength = 8 * BloomByteLength ) +var EmptyBloom = Bloom{} + // Bloom represents a 2048 bit bloom filter. type Bloom [BloomByteLength]byte diff --git a/core/types/transaction.go b/core/types/transaction.go index 1bb43d805f..b127cb2af6 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -479,6 +479,10 @@ func (t *TransactionsByPriceAndNonce) Pop() { heap.Pop(&t.heads) } +func (t *TransactionsByPriceAndNonce) CurrentSize() int { + return len(t.heads) +} + // Message is a fully derived transaction and implements core.Message // // NOTE: In a future PR this will be removed. diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index ccb0e6bb45..70de993b18 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -79,7 +79,7 @@ type blockExecutionEnv struct { func (env *blockExecutionEnv) commitTransaction(tx *types.Transaction, coinbase common.Address) error { vmconfig := *env.chain.GetVMConfig() - receipt, err := core.ApplyTransaction(env.chain.Config(), env.chain, &coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vmconfig) + receipt, err := core.ApplyTransaction(env.chain.Config(), env.chain, &coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vmconfig, core.NewReceiptBloomGenerator()) if err != nil { return err } diff --git a/miner/worker.go b/miner/worker.go index ef7a8c5630..2dcb75ac10 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -736,10 +736,10 @@ func (w *worker) updateSnapshot() { w.snapshotState = w.current.state.Copy() } -func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { +func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address, receiptProcessors ...core.ReceiptProcessor) ([]*types.Log, error) { snap := w.current.state.Snapshot() - receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) + receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig(), receiptProcessors...) if err != nil { w.current.state.RevertToSnapshot(snap) return nil, err @@ -769,6 +769,14 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin log.Debug("Time left for mining work", "left", (*delay - w.config.DelayLeftOver).String(), "leftover", w.config.DelayLeftOver) defer stopTimer.Stop() } + + // initilise bloom processors + processorCapacity := 100 + if txs.CurrentSize() < processorCapacity { + processorCapacity = txs.CurrentSize() + } + bloomProcessors := core.NewAsyncReceiptBloomGenerator(processorCapacity) + LOOP: for { // In the following three cases, we will interrupt the execution of the transaction. @@ -824,7 +832,7 @@ LOOP: // Start executing the transaction w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount) - logs, err := w.commitTransaction(tx, coinbase) + logs, err := w.commitTransaction(tx, coinbase, bloomProcessors) switch { case errors.Is(err, core.ErrGasLimitReached): // Pop the current out-of-gas transaction without shifting in the next from the account @@ -859,6 +867,7 @@ LOOP: txs.Shift() } } + bloomProcessors.Close() if !w.isRunning() && len(coalescedLogs) > 0 { // We don't push the pendingLogsEvent while we are mining. The reason is that From 8f605f5904ae0aae9da0106b61dca73a650e9292 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Fri, 15 Oct 2021 17:04:30 +0800 Subject: [PATCH 038/117] fix cache key (#454) --- core/state/database.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 24a1474d57..1c18c282e7 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -267,7 +267,7 @@ 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 cached, ok := db.codeCache.Get(codeHash.Bytes()); ok { + if cached, ok := db.codeCache.Get(codeHash); ok { code := cached.([]byte) if len(code) > 0 { return code, nil @@ -276,7 +276,7 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error code := rawdb.ReadCode(db.db.DiskDB(), codeHash) if len(code) > 0 { - db.codeCache.Add(codeHash.Bytes(), code) + db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) return code, nil } @@ -289,7 +289,7 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) { if cached, ok := db.codeCache.Get(codeHash.Bytes()); ok { code := cached.([]byte) - if len(code) > 0 { + if len(code) > 0 { return code, nil } } From aecb61296d928474b94511d614f8b5a47ae907de Mon Sep 17 00:00:00 2001 From: kyrie-yl <83150977+kyrie-yl@users.noreply.github.com> Date: Fri, 15 Oct 2021 18:10:58 +0800 Subject: [PATCH 039/117] fix cache key do not have hash func (#455) Signed-off-by: kyrie-yl --- core/state/database.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 1c18c282e7..b65dfca158 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -287,7 +287,7 @@ 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 cached, ok := db.codeCache.Get(codeHash.Bytes()); ok { + if cached, ok := db.codeCache.Get(codeHash); ok { code := cached.([]byte) if len(code) > 0 { return code, nil @@ -295,7 +295,7 @@ func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]b } code := rawdb.ReadCodeWithPrefix(db.db.DiskDB(), codeHash) if len(code) > 0 { - db.codeCache.Add(codeHash.Bytes(), code) + db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) return code, nil } From f2f68dba15e72728abd71b535d1a86173686ab06 Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Mon, 18 Oct 2021 18:16:32 +0800 Subject: [PATCH 040/117] ci: unit test and truffle test (#456) * ci: add unit test fix: failed on test * ci: add truffle test * ci: update os version * ci: add cache for go build --- .github/workflows/build-test.yml | 50 ++++++ .github/workflows/integration-test.yml | 25 +++ .github/workflows/lint.yml | 48 ++++++ .github/workflows/release.yml | 26 +++- .github/workflows/unit-test.yml | 55 +++++++ .gitignore | 1 + Makefile | 14 +- build/ci.go | 4 + cmd/puppeth/testdata/stureby_aleth.json | 2 +- cmd/puppeth/testdata/stureby_parity.json | 2 +- core/blockchain.go | 12 +- core/blockchain_diff_test.go | 8 - core/receipt_processor.go | 2 +- core/state_processor.go | 9 +- docker/Dockerfile | 24 +++ docker/Dockerfile.truffle | 16 ++ docker/init_holders.template | 7 + docker/truffle-config.js | 70 +++++++++ eth/api_backend.go | 2 +- ethclient/ethclient_test.go | 21 --- go.mod | 2 +- go.sum | 147 +----------------- tests/state_test.go | 4 +- tests/truffle/.env | 5 + tests/truffle/config/config-bsc-rpc.toml | 67 ++++++++ tests/truffle/config/config-validator.toml | 49 ++++++ tests/truffle/docker-compose.yml | 62 ++++++++ ...0x59b02d4d2f94ea5c55230715a58ebb0b703bcd4b | 1 + ...0x7fd60c817837dcfefca6d0a52a44980d12f70c59 | 1 + ...0x8e1ad6fac6ea5871140594abef5b1d503385e936 | 1 + ...0xa2bc4cf857f3d7a22b29c71774b4d8f25cc7edd0 | 1 + ...0xb75573a04648535bddc52adf6fbc887149624253 | 1 + ...0xbb46abbcc95213754f549e0cfa2b13bef0abfab6 | 1 + ...0xc32ec0115bcb6693d4b4854531ca5e6a99217abf | 1 + ...0xc8d063a7e0a118432721dae5e059404b5598bd76 | 1 + tests/truffle/scripts/bootstrap.sh | 60 +++++++ tests/truffle/scripts/bsc-rpc.sh | 16 ++ tests/truffle/scripts/bsc-validator.sh | 18 +++ tests/truffle/scripts/truffle-test.sh | 5 + tests/truffle/scripts/utils.sh | 14 ++ 40 files changed, 660 insertions(+), 195 deletions(-) create mode 100644 .github/workflows/build-test.yml create mode 100644 .github/workflows/integration-test.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/unit-test.yml create mode 100644 docker/Dockerfile create mode 100644 docker/Dockerfile.truffle create mode 100644 docker/init_holders.template create mode 100644 docker/truffle-config.js create mode 100644 tests/truffle/.env create mode 100644 tests/truffle/config/config-bsc-rpc.toml create mode 100644 tests/truffle/config/config-validator.toml create mode 100644 tests/truffle/docker-compose.yml create mode 100644 tests/truffle/init-holders/0x59b02d4d2f94ea5c55230715a58ebb0b703bcd4b create mode 100644 tests/truffle/init-holders/0x7fd60c817837dcfefca6d0a52a44980d12f70c59 create mode 100644 tests/truffle/init-holders/0x8e1ad6fac6ea5871140594abef5b1d503385e936 create mode 100644 tests/truffle/init-holders/0xa2bc4cf857f3d7a22b29c71774b4d8f25cc7edd0 create mode 100644 tests/truffle/init-holders/0xb75573a04648535bddc52adf6fbc887149624253 create mode 100644 tests/truffle/init-holders/0xbb46abbcc95213754f549e0cfa2b13bef0abfab6 create mode 100644 tests/truffle/init-holders/0xc32ec0115bcb6693d4b4854531ca5e6a99217abf create mode 100644 tests/truffle/init-holders/0xc8d063a7e0a118432721dae5e059404b5598bd76 create mode 100755 tests/truffle/scripts/bootstrap.sh create mode 100755 tests/truffle/scripts/bsc-rpc.sh create mode 100755 tests/truffle/scripts/bsc-validator.sh create mode 100755 tests/truffle/scripts/truffle-test.sh create mode 100644 tests/truffle/scripts/utils.sh diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 0000000000..b0fb9833b3 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,50 @@ +name: Build Test + +on: + push: + branches: + - master + - develop + + pull_request: + branches: + - master + - develop + +jobs: + unit-test: + strategy: + matrix: + go-version: [1.16.x] + os: [ubuntu-18.04] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - name: Checkout code + uses: actions/checkout@v2 + + - uses: actions/cache@v2 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + # * Build cache (Mac) + # * Build cache (Windows) + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + %LocalAppData%\go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Test Build + run: | + make geth + + diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml new file mode 100644 index 0000000000..a4774d856f --- /dev/null +++ b/.github/workflows/integration-test.yml @@ -0,0 +1,25 @@ +name: Integration Test + +on: + push: + branches: + - master + - develop + + pull_request: + branches: + - master + - develop + +jobs: + truffle-test: + strategy: + matrix: + os: [ubuntu-18.04] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Truffle test + run: make truffle-test diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..288749ae41 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,48 @@ +name: Lint + +on: + push: + branches: + - master + - develop + + pull_request: + branches: + - master + - develop + +jobs: + unit-test: + strategy: + matrix: + go-version: [1.16.x] + os: [ubuntu-18.04] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - name: Checkout code + uses: actions/checkout@v2 + + - uses: actions/cache@v2 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + # * Build cache (Mac) + # * Build cache (Windows) + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + %LocalAppData%\go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Lint + run: | + make lint diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 66e73dbc5b..1633752c23 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: go-version: [1.16.x] - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-18.04, macos-11, windows-2019] runs-on: ${{ matrix.os }} steps: - name: Install Go @@ -23,6 +23,22 @@ jobs: - name: Checkout Code uses: actions/checkout@v2 + - uses: actions/cache@v2 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + # * Build cache (Mac) + # * Build cache (Windows) + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + %LocalAppData%\go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + # ============================== # Linux/Macos/Windows Build # ============================== @@ -36,21 +52,21 @@ jobs: - name: Upload Linux Build uses: actions/upload-artifact@v2 - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-18.04' with: name: linux path: ./build/bin/geth - name: Upload MacOS Build uses: actions/upload-artifact@v2 - if: matrix.os == 'macos-latest' + if: matrix.os == 'macos-11' with: name: macos path: ./build/bin/geth - name: Upload Windows Build uses: actions/upload-artifact@v2 - if: matrix.os == 'windows-latest' + if: matrix.os == 'windows-2019' with: name: windows path: ./build/bin/geth.exe @@ -58,7 +74,7 @@ jobs: release: name: Release needs: build - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - name: Set Env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml new file mode 100644 index 0000000000..737e4928a7 --- /dev/null +++ b/.github/workflows/unit-test.yml @@ -0,0 +1,55 @@ +name: Unit Test + +on: + push: + branches: + - master + - develop + + pull_request: + branches: + - master + - develop + +jobs: + unit-test: + strategy: + matrix: + go-version: [1.16.x] + os: [ubuntu-18.04] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - name: Checkout code + uses: actions/checkout@v2 + + - uses: actions/cache@v2 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + # * Build cache (Mac) + # * Build cache (Windows) + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + %LocalAppData%\go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Test Build + run: | + make geth + + - name: Uint Test + env: + ANDROID_HOME: "" # Skip android test + run: | + make test + diff --git a/.gitignore b/.gitignore index 1ee8b83022..3d05da8816 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ */**/*tx_database* */**/*dapps* build/_vendor/pkg +/tests/truffle/storage #* .#* diff --git a/Makefile b/Makefile index cb5a87dad0..03f92e6f43 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # with Go source code. If you know what GOPATH is then you probably # don't need to bother with make. -.PHONY: geth android ios geth-cross evm all test clean +.PHONY: geth android ios geth-cross evm all test truffle-test clean .PHONY: geth-linux geth-linux-386 geth-linux-amd64 geth-linux-mips64 geth-linux-mips64le .PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64 .PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64 @@ -33,7 +33,17 @@ ios: @echo "Import \"$(GOBIN)/Geth.framework\" to use the library." test: all - $(GORUN) build/ci.go test + $(GORUN) build/ci.go test -timeout 1h + +truffle-test: + docker build . -f ./docker/Dockerfile --target bsc-genesis -t bsc-genesis + docker build . -f ./docker/Dockerfile --target bsc -t bsc + docker build . -f ./docker/Dockerfile.truffle -t truffle-test + docker-compose -f ./tests/truffle/docker-compose.yml up genesis + docker-compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1 + sleep 30 + docker-compose -f ./tests/truffle/docker-compose.yml up --exit-code-from truffle-test truffle-test + docker-compose -f ./tests/truffle/docker-compose.yml down lint: ## Run linters. $(GORUN) build/ci.go lint diff --git a/build/ci.go b/build/ci.go index 18172c327a..df1cb50ab2 100644 --- a/build/ci.go +++ b/build/ci.go @@ -279,6 +279,7 @@ func doTest(cmdline []string) { cc = flag.String("cc", "", "Sets C compiler binary") coverage = flag.Bool("coverage", false, "Whether to record code coverage") verbose = flag.Bool("v", false, "Whether to log verbosely") + timeout = flag.String("timeout", "10m", `Timeout of runing tests`) ) flag.CommandLine.Parse(cmdline) @@ -299,6 +300,9 @@ func doTest(cmdline []string) { if *verbose { gotest.Args = append(gotest.Args, "-v") } + if *timeout != "" { + gotest.Args = append(gotest.Args, []string{"-timeout", *timeout}...) + } packages := []string{"./accounts/...", "./common/...", "./consensus/...", "./console/...", "./core/...", "./crypto/...", "./eth/...", "./ethclient/...", "./ethdb/...", "./event/...", "./graphql/...", "./les/...", diff --git a/cmd/puppeth/testdata/stureby_aleth.json b/cmd/puppeth/testdata/stureby_aleth.json index d18ba3854a..9f928f4889 100644 --- a/cmd/puppeth/testdata/stureby_aleth.json +++ b/cmd/puppeth/testdata/stureby_aleth.json @@ -14,7 +14,7 @@ "minGasLimit": "0x1388", "maxGasLimit": "0x7fffffffffffffff", "tieBreakingGas": false, - "gasLimitBoundDivisor": "0x400", + "gasLimitBoundDivisor": "0x100", "minimumDifficulty": "0x20000", "difficultyBoundDivisor": "0x800", "durationLimit": "0xd", diff --git a/cmd/puppeth/testdata/stureby_parity.json b/cmd/puppeth/testdata/stureby_parity.json index e9229f99b7..a9f27b8e41 100644 --- a/cmd/puppeth/testdata/stureby_parity.json +++ b/cmd/puppeth/testdata/stureby_parity.json @@ -25,7 +25,7 @@ "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", - "gasLimitBoundDivisor": "0x400", + "gasLimitBoundDivisor": "0x100", "networkID": "0x4cb2e", "chainID": "0x4cb2e", "maxCodeSize": "0x6000", diff --git a/core/blockchain.go b/core/blockchain.go index 2668ba601d..91371940cd 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2161,8 +2161,16 @@ func (bc *BlockChain) updateHighestVerifiedHeader(header *types.Header) { return } - newTD := big.NewInt(0).Add(bc.GetTdByHash(header.ParentHash), header.Difficulty) - oldTD := big.NewInt(0).Add(bc.GetTdByHash(currentHeader.ParentHash), currentHeader.Difficulty) + newParentTD := bc.GetTdByHash(header.ParentHash) + if newParentTD == nil { + newParentTD = big.NewInt(0) + } + oldParentTD := bc.GetTdByHash(currentHeader.ParentHash) + if oldParentTD == nil { + oldParentTD = big.NewInt(0) + } + newTD := big.NewInt(0).Add(newParentTD, header.Difficulty) + oldTD := big.NewInt(0).Add(oldParentTD, currentHeader.Difficulty) if newTD.Cmp(oldTD) > 0 { bc.highestVerifiedHeader.Store(types.CopyHeader(header)) diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index bec463136e..0b289bdc1c 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -216,8 +216,6 @@ func rawDataToDiffLayer(data rlp.RawValue) (*types.DiffLayer, error) { } func TestProcessDiffLayer(t *testing.T) { - t.Parallel() - blockNum := 128 fullBackend := newTestBackend(blockNum, false) falseDiff := 5 @@ -279,8 +277,6 @@ func TestProcessDiffLayer(t *testing.T) { } func TestFreezeDiffLayer(t *testing.T) { - t.Parallel() - blockNum := 1024 fullBackend := newTestBackend(blockNum, true) defer fullBackend.close() @@ -302,8 +298,6 @@ func TestFreezeDiffLayer(t *testing.T) { } func TestPruneDiffLayer(t *testing.T) { - t.Parallel() - blockNum := 1024 fullBackend := newTestBackend(blockNum, true) defer fullBackend.close() @@ -363,8 +357,6 @@ func TestPruneDiffLayer(t *testing.T) { } func TestGetDiffAccounts(t *testing.T) { - t.Parallel() - blockNum := 128 fullBackend := newTestBackend(blockNum, false) defer fullBackend.close() diff --git a/core/receipt_processor.go b/core/receipt_processor.go index 57fb56a6dc..3b4c2579cc 100644 --- a/core/receipt_processor.go +++ b/core/receipt_processor.go @@ -63,4 +63,4 @@ func (p *AsyncReceiptBloomGenerator) Close() { close(p.receipts) p.isClosed = true p.wg.Wait() -} \ No newline at end of file +} diff --git a/core/state_processor.go b/core/state_processor.go index 14bd5d75b2..b529082063 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -42,11 +42,10 @@ import ( ) const ( - fullProcessCheck = 21 // On diff sync mode, will do full process every fullProcessCheck randomly - minNumberOfAccountPerTask = 5 - recentTime = 2048 * 3 - recentDiffLayerTimeout = 20 - farDiffLayerTimeout = 2 + fullProcessCheck = 21 // On diff sync mode, will do full process every fullProcessCheck randomly + recentTime = 2048 * 3 + recentDiffLayerTimeout = 20 + farDiffLayerTimeout = 2 ) // StateProcessor is a basic Processor, which takes care of transitioning diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000000..a00454c1ab --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,24 @@ +FROM golang:1.16-alpine as bsc + +RUN apk add --no-cache make gcc musl-dev linux-headers git bash + +ADD . /bsc +WORKDIR /bsc +RUN make geth +RUN mv /bsc/build/bin/geth /usr/local/bin/geth + +EXPOSE 8545 8547 30303 30303/udp +ENTRYPOINT [ "/usr/local/bin/geth" ] + +FROM ethereum/solc:0.6.4-alpine as bsc-genesis + +RUN apk add --d --no-cache ca-certificates npm nodejs bash alpine-sdk + +RUN git clone https://github.com/binance-chain/bsc-genesis-contract.git /root/genesis \ + && rm /root/genesis/package-lock.json && cd /root/genesis && npm install + +COPY docker/init_holders.template /root/genesis/init_holders.template + +COPY --from=bsc /usr/local/bin/geth /usr/local/bin/geth + +ENTRYPOINT [ "/bin/bash" ] diff --git a/docker/Dockerfile.truffle b/docker/Dockerfile.truffle new file mode 100644 index 0000000000..0ec7029377 --- /dev/null +++ b/docker/Dockerfile.truffle @@ -0,0 +1,16 @@ +FROM ethereum/solc:0.6.4-alpine + +RUN apk add --d --no-cache ca-certificates npm nodejs bash alpine-sdk git + +RUN git clone https://github.com/binance-chain/canonical-upgradeable-bep20.git /usr/app/canonical-upgradeable-bep20 + +WORKDIR /usr/app/canonical-upgradeable-bep20 +COPY docker/truffle-config.js /usr/app/canonical-upgradeable-bep20 + +RUN npm install -g n +RUN n 12.18.3 && node -v + +RUN npm install -g truffle@v5.1.14 +RUN npm install + +ENTRYPOINT [ "/bin/bash" ] diff --git a/docker/init_holders.template b/docker/init_holders.template new file mode 100644 index 0000000000..4012909164 --- /dev/null +++ b/docker/init_holders.template @@ -0,0 +1,7 @@ +const web3 = require("web3") + +const addresses = "{{INIT_HOLDER_ADDRESSES}}" +const balance = web3.utils.toBN("{{INIT_HOLDER_BALANCE}}").toString("hex") +const init_holders = addresses.split(",").map(address => ({ address, balance })); + +exports = module.exports = init_holders diff --git a/docker/truffle-config.js b/docker/truffle-config.js new file mode 100644 index 0000000000..91539a9ab6 --- /dev/null +++ b/docker/truffle-config.js @@ -0,0 +1,70 @@ +/** + * Use this file to configure your truffle project. It's seeded with some + * common settings for different networks and features like migrations, + * compilation and testing. Uncomment the ones you need or modify + * them to suit your project as necessary. + * + * More information about configuration can be found at: + * + * truffleframework.com/docs/advanced/configuration + * + * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) + * to sign your transactions before they're sent to a remote public node. Infura accounts + * are available for free at: infura.io/register. + * + * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate + * public/private key pairs. If you're publishing your code to GitHub make sure you load this + * phrase from a file you've .gitignored so it doesn't accidentally become public. + * + */ + +// const HDWalletProvider = require('truffle-hdwallet-provider'); +// const infuraKey = "fj4jll3k....."; +// +// const fs = require('fs'); +// const mnemonic = fs.readFileSync(".secret").toString().trim(); + +module.exports = { + /** + * Networks define how you connect to your ethereum client and let you set the + * defaults web3 uses to send transactions. If you don't specify one truffle + * will spin up a development blockchain for you on port 9545 when you + * run `develop` or `test`. You can ask a truffle command to use a specific + * network from the command line, e.g + * + * $ truffle test --network + */ + + networks: { + // Useful for testing. The `development` name is special - truffle uses it by default + // if it's defined here and no other network is specified at the command line. + // You should run a client (like ganache-cli, geth or parity) in a separate terminal + // tab if you use this network and you must also set the `host`, `port` and `network_id` + // options below to some value. + // + development: { + host: process.env.RPC_HOST || '127.0.0.1', // Localhost (default: none) + port: process.env.RPC_PORT || 8545, // Standard Ethereum port (default: none) + network_id: process.env.BSC_CHAIN_ID, // Any network (default: none) + }, + }, + + // Set default mocha options here, use special reporters etc. + mocha: { + // timeout: 100000 + }, + + // Configure your compilers + compilers: { + solc: { + version: "0.6.4", // Fetch exact version from solc-bin (default: truffle's version) + docker: false, // Use "0.5.1" you've installed locally with docker (default: false) + settings: { // See the solidity docs for advice about optimization and evmVersion + optimizer: { + enabled: true, + runs: 200 + } + } + } + } + } diff --git a/eth/api_backend.go b/eth/api_backend.go index 5c864a236b..18514b7cc3 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -279,7 +279,7 @@ func (b *EthAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) { return b.gpo.SuggestPrice(ctx) } -func (b *EthAPIBackend) Chain() *core.BlockChain { +func (b *EthAPIBackend) Chain() *core.BlockChain { return b.eth.BlockChain() } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index d2fd056041..380481a22d 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -599,27 +599,6 @@ func testCallContract(t *testing.T, client *rpc.Client) { } } -func sendTransaction(ec *Client) error { - // Retrieve chainID - chainID, err := ec.ChainID(context.Background()) - if err != nil { - return err - } - // Create transaction - tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 23000, big.NewInt(100000), nil) - signer := types.LatestSignerForChainID(chainID) - signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) - if err != nil { - return err - } - signedTx, err := tx.WithSignature(signer, signature) - if err != nil { - return err - } - // Send transaction - return ec.SendTransaction(context.Background(), signedTx) -} - func testDiffAccounts(t *testing.T, client *rpc.Client) { ec := NewClient(client) ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Millisecond) diff --git a/go.mod b/go.mod index fc5ec88fec..4ea9fc689a 100644 --- a/go.mod +++ b/go.mod @@ -55,8 +55,8 @@ require ( github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 - github.com/panjf2000/ants/v2 v2.4.5 github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c + github.com/panjf2000/ants/v2 v2.4.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 github.com/prometheus/tsdb v0.7.1 github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 // indirect diff --git a/go.sum b/go.sum index 5fbb839b90..e94241a414 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= 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= @@ -8,24 +7,16 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK 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 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM= 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 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigtable v1.2.0 h1:F4cCmA4nuV84V5zYQ3MKY+M1Cw1avHDuf3S/LcZPA9c= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= -cloud.google.com/go/datastore v1.0.0 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM= 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 h1:9/vpR43S4aJaROxqQHQ3nH9lfyKKV0dC3vOmnw8ebQQ= 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 h1:RPUcBvDeYgQFMfQu1eBMq6piD1SXmLH+vK3qjewZPus= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -collectd.org v0.3.0 h1:iNBHGw1VvPJxH2B6RiFWFZ+vsjo1lCdRszBeOuwGi00= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY= @@ -48,13 +39,9 @@ github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1Gn github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= 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 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 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= @@ -62,19 +49,13 @@ github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQu github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af h1:wVe6/Ea46ZMeNkQjjBW6xcqyQA/j5e0D6GytH95g0gQ= 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 h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= 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 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= 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 h1:nxAtV4VajJDhKysp2kdcJZsq8Ss1xSA0vZTkVHHJd0E= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/aws/aws-sdk-go-v2 v1.4.0 h1:Ryh4fNebT9SwLyCKPSk83dyEZj+KB6KzDyb1gXii7EI= github.com/aws/aws-sdk-go-v2 v1.4.0/go.mod h1:tI4KhsR5VkzlUa2DZAdwx7wCAYGwkZZ1H31PYrBFx1w= @@ -97,29 +78,19 @@ github.com/aws/smithy-go v1.4.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAm github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/c-bata/go-prompt v0.2.2 h1:uyKRz6Z6DUyj49QVijyM339UJV9yhbr70gESwbNU3e0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= -github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= 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= @@ -127,23 +98,16 @@ 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= -github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= 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 h1:+R8G1+Ftumd0DaveLgMIjrFPcAS4G8MsVXWXiyZL5BY= 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/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/dave/jennifer v1.2.0 h1:S15ZkFMRoJ36mGAQgWL1tnr0NQJh9rZ8qatseX/VbBc= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -153,9 +117,7 @@ github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 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 h1:akOQj8IVgoeFfBTzGOEQakCYshWD6RNo1M5pivFXt70= 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 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= @@ -163,13 +125,10 @@ github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmak github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 h1:Y9vTBSsV4hSwPSj4bacAU/eSnV3dAxVpepaghAdhGoQ= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= -github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0= 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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w= 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 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= @@ -177,7 +136,6 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 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 h1:WXb3TSNmHp2vHoCroCIB1foO/yQ36swABL8aOVeDpgg= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= @@ -186,13 +144,9 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 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/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04MMPyLHj/QwZuMJ5+7tJcBr1AQjpiAK/rZWRrQT7o= 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 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= 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 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE= 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= @@ -203,27 +157,21 @@ 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-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 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/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= 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 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 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 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA= 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 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= 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= @@ -241,33 +189,25 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v1.11.0 h1:O7CEyB8Cb3/DmtxODGtLHcEvpr81Jm5qLg/hsHnxA2A= 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= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/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/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 h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= 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 h1:DLpL8pWq0v4JYoRpEhDfsJhhJyGKCcQM2WPW2TJs31c= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= github.com/google/uuid v1.1.5/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 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -281,85 +221,55 @@ 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.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw= github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88 h1:bcAj8KroPf552TScjFPIakjH2/tdIrIH8F+cc4v4SRo= github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150 h1:vlNjIqmUZ9CMAWsbURYl3a6wZbw7q5RHVvlXTNS/Bs8= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/flux v0.65.1 h1:77BcVUCzvN5HMm8+j9PRBQ4iZcu98Dl4Y9rf+J5vhnc= 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/influxql v1.1.1-0.20200828144457-65d3ef77d385 h1:ED4e5Cc3z5vSN2Tz2GkOHN7vs4Sxe2yds6CXvDnvZFE= 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 h1:/o3vQtpWJhvnIbXley4/jwzzqNeigJK9z+LZcJZ9zfM= github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= -github.com/influxdata/promql/v2 v2.12.0 h1:kXn3p0D7zPw16rOtfDR+wo6aaiH8tSMfhPwONTxrlEc= github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= -github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6 h1:UzJnB7VRL4PSkUJHwsyzseGOmrO/r4yA+AuxGJxiZmA= 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 h1:MHTrDWmQpHq/hkq+7cw9oYAt2PqUw52TZazRA0N7PGE= 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 h1:+TUUmaFa4YD1Q+7bH9o5NCHQGPMqZCYJiNW6lIIS9z4= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/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/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= -github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 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 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jsternberg/zap-logfmt v1.0.0 h1:0Dz2s/eturmdUS34GM82JwNEdQ9hPoJgqptcEKcbpzY= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5 h1:PJr+ZMXIecYc1Ey2zucXdR73SMBtgjPgwa31099IMv0= 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 h1:2jNeR4YUziVtswNP9sEFAI913cVrzH85T+8Q6LpYbT0= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.4.0 h1:8nsMz3tWa9SWWPL60G1V6CUsf4lLjWLTNEtibhe8gh8= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5 h1:2U0HzY8BJ8hVwDKIzp7y4voR9CX/nvcfymLmg2UiOio= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= -github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada h1:3L+neHp83cTjegPdCiOxVOJtRIy7/8RldvMTsyPYH10= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 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/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.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -367,7 +277,6 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 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 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -383,19 +292,13 @@ github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXT 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 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104 h1:d8RFOZ2IiFtFWBcKEHAFYJcPTf0wY5q0exFNJZVWa1U= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY= 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 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc= 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= @@ -403,7 +306,6 @@ github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcou 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/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= 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= @@ -420,24 +322,20 @@ github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt 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/panjf2000/ants/v2 v2.4.5 h1:kcGvjXB7ea0MrzzszpnlVFthhYKoFxLi75nRbsq01HY= -github.com/panjf2000/ants/v2 v2.4.5/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= -github.com/paulbellamy/ratecounter v0.2.0 h1:2L/RhJq+HA8gBQImDXtLPrDXK5qAj6ozWVK/zFXVJGs= +github.com/panjf2000/ants/v2 v2.4.5 h1:kcGvjXB7ea0MrzzszpnlVFthhYKoFxLi75nRbsq01HY= +github.com/panjf2000/ants/v2 v2.4.5/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= 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 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 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 h1:tFwafIEMf0B7NlcxV/zJ6leBIa81D3hgGSgsE5hCkOQ= 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= @@ -459,43 +357,29 @@ github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52 h1:RnWNS9Hlm8BIkjr6wx8li5abe0fr73jljLycdfemTp0= 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 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= 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= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/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 h1:HtCSf6B4gN/87yc5qTl7WsxPKQIIGXLPPM1bMCPOsoY= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= 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 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= 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= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -511,7 +395,6 @@ github.com/tendermint/iavl v0.12.0 h1:xcaFAr+ycqCj7WN1RzL2EfcBioRDOHcU1oWcg83K02 github.com/tendermint/iavl v0.12.0/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM= github.com/tendermint/tendermint v0.31.11 h1:TIs//4WfEAG4TOZc2eUfJPI3T8KrywXQCCPnGAaM1Wo= github.com/tendermint/tendermint v0.31.11/go.mod h1:ymcPyWblXCplCPQjbOYbrF1fWnpslATMVqiGgWbZrlc= -github.com/tinylib/msgp v1.0.2 h1:DfdQrzQa7Yh2es9SuLkixqxuXS2SxsdYn0KbdrOGWD8= 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= @@ -519,25 +402,17 @@ 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/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/willf/bitset v1.1.3 h1:ekJIKh6+YbUIVt9DfNbkR5d6aFcFTLDRyJNAACURBg8= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6 h1:YdYsPAZ2pC6Tow/nPZOPQ96O3hm/ToAkGsPLzedXERk= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= 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 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -558,11 +433,9 @@ golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxT 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 h1:zQpM52jfKHG6II1ISZY1ZcpygvuSFZpLwfluuF89XOg= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 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 h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= 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= @@ -571,16 +444,13 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl 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 h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= 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= 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 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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= @@ -608,7 +478,6 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG 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 h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= 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= @@ -687,7 +556,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/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.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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= @@ -696,12 +564,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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 h1:DJy6UzXbahnGUf1ujUNkh/NEtK14qMo2nvlBPs4U5yw= 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 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b h1:Qh4dB5D/WpoUUp3lSod7qgoyEHbDGPUWjIbnqdqqe1k= 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= @@ -709,13 +574,11 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn 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 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA= 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 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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= @@ -746,14 +609,11 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE 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= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 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= @@ -780,9 +640,6 @@ 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 h1:qTakTkI6ni6LFD5sBwwsdSO+AQqbSIxOauHTTQKZ/7o= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/tests/state_test.go b/tests/state_test.go index b77a898c21..c1d9f6a0dc 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -19,8 +19,8 @@ package tests import ( "bufio" "bytes" + "errors" "fmt" - "reflect" "testing" "github.com/ethereum/go-ethereum/core/vm" @@ -108,7 +108,7 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { tracer := vm.NewJSONLogger(&vm.LogConfig{DisableMemory: true}, w) config.Debug, config.Tracer = true, tracer err2 := test(config) - if !reflect.DeepEqual(err, err2) { + if !errors.Is(err, err2) { t.Errorf("different error for second run: %v", err2) } w.Flush() diff --git a/tests/truffle/.env b/tests/truffle/.env new file mode 100644 index 0000000000..d933e4cfef --- /dev/null +++ b/tests/truffle/.env @@ -0,0 +1,5 @@ +BSC_CHAIN_ID="99" +CLUSTER_CIDR=99.1.0.0/16 +BOOTSTRAP_PUB_KEY=177ae5db445a2f70db781b019aedd928f5b1528a7a43448840b022408f9a21509adcce0b37c87d59da68d47a16879cc1e95a62bbac9723f7b22f4365b2afabbe +BOOTSTRAP_TCP_PORT=30311 +VERBOSE=3 diff --git a/tests/truffle/config/config-bsc-rpc.toml b/tests/truffle/config/config-bsc-rpc.toml new file mode 100644 index 0000000000..66031308f8 --- /dev/null +++ b/tests/truffle/config/config-bsc-rpc.toml @@ -0,0 +1,67 @@ +[Eth] +NetworkId = {{NetworkId}} +LightPeers = 100 +TrieTimeout = 360000000000 +EnablePreimageRecording = false + +[Eth.Miner] +GasFloor = 30000000 +GasCeil = 40000000 +GasPrice = 5000000000 +Recommit = 10000000000 +Noverify = false + +[Eth.Ethash] +CacheDir = "" +CachesInMem = 0 +CachesOnDisk = 0 +CachesLockMmap = false +DatasetDir = "" +DatasetsInMem = 0 +DatasetsOnDisk = 0 +DatasetsLockMmap = false +PowMode = 0 + +[Eth.TxPool] +Locals = [] +NoLocals = true +Journal = "transactions.rlp" +Rejournal = 3600000000000 +PriceLimit = 5000000000 +PriceBump = 10 +AccountSlots = 128 +GlobalSlots = 10000 +AccountQueue = 64 +GlobalQueue = 5000 +Lifetime = 600000000000 + +[Eth.GPO] +Blocks = 20 +Percentile = 60 +OracleThreshold = 20 +Default = 5000000000 + +[Node] +DataDir = "node" +InsecureUnlockAllowed = true +NoUSB = true +IPCPath = "geth.ipc" +HTTPHost = "0.0.0.0" +HTTPPort = 8545 +HTTPVirtualHosts = ["*"] +HTTPModules = ["eth", "net", "web3", "txpool", "parlia"] +WSPort = 8547 +WSModules = ["net", "web3", "eth"] + +[Node.P2P] +MaxPeers = 30 +NoDiscovery = false +BootstrapNodes = [] +StaticNodes = [] +ListenAddr = ":30311" +EnableMsgEvents = false + +[Node.HTTPTimeouts] +ReadTimeout = 30000000000 +WriteTimeout = 30000000000 +IdleTimeout = 120000000000 diff --git a/tests/truffle/config/config-validator.toml b/tests/truffle/config/config-validator.toml new file mode 100644 index 0000000000..a96315a9db --- /dev/null +++ b/tests/truffle/config/config-validator.toml @@ -0,0 +1,49 @@ +[Eth] +NetworkId = {{NetworkId}} +SyncMode = "full" +NoPruning = false +NoPrefetch = false +LightPeers = 100 +DatabaseCache = 512 +DatabaseFreezer = "" +TrieCleanCache = 256 +TrieDirtyCache = 256 +TrieTimeout = 6000000000 +EnablePreimageRecording = false +EWASMInterpreter = "" +EVMInterpreter = "" + +[Eth.Ethash] +CacheDir = "" +CachesInMem = 0 +CachesOnDisk = 0 +CachesLockMmap = false +DatasetDir = "" +DatasetsInMem = 0 +DatasetsOnDisk = 0 +DatasetsLockMmap = false +PowMode = 0 + +[Eth.GPO] +Blocks = 20 +Percentile = 60 +OracleThreshold = 100 + +[Node] +DataDir = "" +InsecureUnlockAllowed = false +NoUSB = true +IPCPath = "geth.ipc" + +[Node.P2P] +MaxPeers = 50 +NoDiscovery = false +BootstrapNodes = [] +StaticNodes = [] +TrustedNodes = [] +ListenAddr = ":30311" +EnableMsgEvents = false + +[Node.HTTPTimeouts] +ReadTimeout = 30000000000 +WriteTimeout = 30000000000 diff --git a/tests/truffle/docker-compose.yml b/tests/truffle/docker-compose.yml new file mode 100644 index 0000000000..d5f007afee --- /dev/null +++ b/tests/truffle/docker-compose.yml @@ -0,0 +1,62 @@ +version: "3" + +services: + genesis: + image: bsc-genesis + env_file: .env + environment: + INIT_HOLDER_BALANCE: "500000000000000000000" + NUMS_OF_VALIDATOR: 1 + volumes: + - ./storage:/root/storage + - ./scripts:/root/scripts + - ./config:/root/config + - ./init-holders:/root/init-holders + command: /root/scripts/bootstrap.sh + + bsc-rpc: + image: bsc + healthcheck: + test: nc -z localhost 8545 + interval: 3s + timeout: 5s + retries: 15 + env_file: .env + environment: + NODE_ID: bsc-rpc + volumes: + - ./storage/bsc-rpc:/root/.ethereum + - ./scripts:/scripts + - ./config:/config + entrypoint: [ "sh", "-c", "/scripts/bsc-rpc.sh" ] + + bsc-validator1: + image: bsc + env_file: .env + environment: + NODE_ID: bsc-validator1 + BOOTSTRAP_HOST: bsc-rpc + volumes: + - ./storage/bsc-validator1:/root/.ethereum + - ./scripts:/scripts + entrypoint: [ "sh", "-c", "/scripts/bsc-validator.sh" ] + + truffle-test: + image: truffle-test + command: /scripts/truffle-test.sh + env_file: .env + environment: + RPC_HOST: bsc-rpc + RPC_PORT: 8545 + volumes: + - ./scripts:/scripts + depends_on: + bsc-rpc: + condition: service_healthy + +networks: + default: + ipam: + driver: default + config: + - subnet: 99.1.0.0/16 diff --git a/tests/truffle/init-holders/0x59b02d4d2f94ea5c55230715a58ebb0b703bcd4b b/tests/truffle/init-holders/0x59b02d4d2f94ea5c55230715a58ebb0b703bcd4b new file mode 100644 index 0000000000..f02e888f60 --- /dev/null +++ b/tests/truffle/init-holders/0x59b02d4d2f94ea5c55230715a58ebb0b703bcd4b @@ -0,0 +1 @@ +{"address":"59b02d4d2f94ea5c55230715a58ebb0b703bcd4b","crypto":{"cipher":"aes-128-ctr","ciphertext":"7d148d2d14ce811e6b6c407352b9dd9fa78012fb28cedfefd39c8c4821e6d495","cipherparams":{"iv":"4f896d1aaac704f23a5b0d982791af24"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"32ee8c617c9cf111efb1070aeaa6bdf1e23272e91826d7cf1c032a35e57647bf"},"mac":"9c46e2947e8a2184ab780dd8b99df83dc2ea7f555ba09edb39bac14e3cdd2ab1"},"id":"546d67c8-22aa-47f8-822c-d1338a56fde0","version":3} diff --git a/tests/truffle/init-holders/0x7fd60c817837dcfefca6d0a52a44980d12f70c59 b/tests/truffle/init-holders/0x7fd60c817837dcfefca6d0a52a44980d12f70c59 new file mode 100644 index 0000000000..7da28e4854 --- /dev/null +++ b/tests/truffle/init-holders/0x7fd60c817837dcfefca6d0a52a44980d12f70c59 @@ -0,0 +1 @@ +{"address":"7fd60c817837dcfefca6d0a52a44980d12f70c59","crypto":{"cipher":"aes-128-ctr","ciphertext":"de615dc06e491ffde4378effa527c307d5ad9b880e20e7246ed4c16768a99b66","cipherparams":{"iv":"daef85c2faea3d0bca64e5588bd10fb5"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"41a745c4fecdbe04139ca24cf203ff0c3c0c5890b918c8284fc32a285ec07f77"},"mac":"7ae357c9abcc3f0e41cf7f28edbc47089189699393f92dcd48420d9155063b2f"},"id":"dae91829-589f-46fd-bf83-2e05c99c2f76","version":3} diff --git a/tests/truffle/init-holders/0x8e1ad6fac6ea5871140594abef5b1d503385e936 b/tests/truffle/init-holders/0x8e1ad6fac6ea5871140594abef5b1d503385e936 new file mode 100644 index 0000000000..1e4048099c --- /dev/null +++ b/tests/truffle/init-holders/0x8e1ad6fac6ea5871140594abef5b1d503385e936 @@ -0,0 +1 @@ +{"address":"8e1ad6fac6ea5871140594abef5b1d503385e936","crypto":{"cipher":"aes-128-ctr","ciphertext":"2429bd13413d542e41033d12fa22fd7b848e6bd1fa73da42b146154b91f6bb42","cipherparams":{"iv":"ca266dd7bb8d42f440030c8c5057b720"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3db50346ccd753740c3a997f406b2fff7ed382be16b5f2473e140971db098fe8"},"mac":"d08ca68beb30fa16f42553342d1c4c65c1ce198f490089588541c976892a105b"},"id":"44bf04b2-bb8b-4083-8a15-8ef0a7ebd2e4","version":3} diff --git a/tests/truffle/init-holders/0xa2bc4cf857f3d7a22b29c71774b4d8f25cc7edd0 b/tests/truffle/init-holders/0xa2bc4cf857f3d7a22b29c71774b4d8f25cc7edd0 new file mode 100644 index 0000000000..bd293be3e0 --- /dev/null +++ b/tests/truffle/init-holders/0xa2bc4cf857f3d7a22b29c71774b4d8f25cc7edd0 @@ -0,0 +1 @@ +{"address":"a2bc4cf857f3d7a22b29c71774b4d8f25cc7edd0","crypto":{"cipher":"aes-128-ctr","ciphertext":"2f294fe93b33feb559ff39180645259d05278be73940f763dfb94dec5a9eaaf5","cipherparams":{"iv":"6c8172356cea235580d451812bfb2939"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ff0d64fcf4ee1b010c9e48addea6db74a27dd0b7f558a7ea39bd7879ccdc1d91"},"mac":"e500decff7ba7ad1acba4acabda507d147532dc59e15687c64e2e9cb286fbb1e"},"id":"54994cde-17cc-41e2-beba-8e5b67648229","version":3} diff --git a/tests/truffle/init-holders/0xb75573a04648535bddc52adf6fbc887149624253 b/tests/truffle/init-holders/0xb75573a04648535bddc52adf6fbc887149624253 new file mode 100644 index 0000000000..be31ac0c39 --- /dev/null +++ b/tests/truffle/init-holders/0xb75573a04648535bddc52adf6fbc887149624253 @@ -0,0 +1 @@ +{"address":"b75573a04648535bddc52adf6fbc887149624253","crypto":{"cipher":"aes-128-ctr","ciphertext":"968b6572ba689cc82aceacde5b075805a894f93f4d0a1a3eab2ec8426dd09864","cipherparams":{"iv":"f6dfc6e30df4de7637e5c22008ceab3b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e35e27d6040f86904eff8e1b2b93e96684dd542da51dc2f8f4700760d41861e6"},"mac":"a0dea8100a790961423d9138eddd2a95e8c291f0907673c121e9cee2ed988c1e"},"id":"ce7c3ea0-bb13-479a-be45-1b676ba4ea69","version":3} diff --git a/tests/truffle/init-holders/0xbb46abbcc95213754f549e0cfa2b13bef0abfab6 b/tests/truffle/init-holders/0xbb46abbcc95213754f549e0cfa2b13bef0abfab6 new file mode 100644 index 0000000000..a7fafc639c --- /dev/null +++ b/tests/truffle/init-holders/0xbb46abbcc95213754f549e0cfa2b13bef0abfab6 @@ -0,0 +1 @@ +{"address":"bb46abbcc95213754f549e0cfa2b13bef0abfab6","crypto":{"cipher":"aes-128-ctr","ciphertext":"b4e4bb220f060ddb88bb069bb779a86b2d4541df69dd074bbd5db20102c7bd9a","cipherparams":{"iv":"d8df230541cb6591436d13d8e921d748"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"1e250a04130e716bd14853bfb28539ceb2dd0bd199128e95e238878c5fe0f70d"},"mac":"e72ea48770406a43154a475657fb32b00de818f0f2c3722978aa1b3f4564f3b0"},"id":"a7eafd39-c349-437a-9734-bf41a88a9011","version":3} diff --git a/tests/truffle/init-holders/0xc32ec0115bcb6693d4b4854531ca5e6a99217abf b/tests/truffle/init-holders/0xc32ec0115bcb6693d4b4854531ca5e6a99217abf new file mode 100644 index 0000000000..78a7d24126 --- /dev/null +++ b/tests/truffle/init-holders/0xc32ec0115bcb6693d4b4854531ca5e6a99217abf @@ -0,0 +1 @@ +{"address":"c32ec0115bcb6693d4b4854531ca5e6a99217abf","crypto":{"cipher":"aes-128-ctr","ciphertext":"f274f8d49d2a7312be077da9fcc0d6be566952609a20720916ef8f0889b10ea9","cipherparams":{"iv":"b4e561354c859e32a05c71679c566e6d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a4dc8d1354590c5f15bf8fcdecfea60f3785b4496daab97caa48128c6d13a5c8"},"mac":"08600abf4f1d56a79bb410b500b60bf045f156eff858aab743aa1c0f5bae4fd3"},"id":"fab4ac2e-3714-498f-804a-d186e07e827c","version":3} diff --git a/tests/truffle/init-holders/0xc8d063a7e0a118432721dae5e059404b5598bd76 b/tests/truffle/init-holders/0xc8d063a7e0a118432721dae5e059404b5598bd76 new file mode 100644 index 0000000000..8968530b10 --- /dev/null +++ b/tests/truffle/init-holders/0xc8d063a7e0a118432721dae5e059404b5598bd76 @@ -0,0 +1 @@ +{"address":"c8d063a7e0a118432721dae5e059404b5598bd76","crypto":{"cipher":"aes-128-ctr","ciphertext":"9bf66fada0411b2a07fde861889f4fa5eb032e30bfbb74f4f3253d9ed9339330","cipherparams":{"iv":"b9e1045eff919d63f16e1182ee1b48ef"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"8efa2dbad843d7eeb3d26836e17b562cdb134c5ef7d875a5a34bd98d45bb28fb"},"mac":"b99064cfb5d043789a8684605ddd85efae6c87cab8a8a94924a2b49421d7f854"},"id":"eba9456c-e8eb-411f-ac75-33d0db977ffb","version":3} diff --git a/tests/truffle/scripts/bootstrap.sh b/tests/truffle/scripts/bootstrap.sh new file mode 100755 index 0000000000..0e5e00df99 --- /dev/null +++ b/tests/truffle/scripts/bootstrap.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +workspace=$(cd `dirname $0`; pwd)/.. + +function prepare() { + if ! [[ -f /usr/local/bin/geth ]];then + echo "geth do not exist!" + exit 1 + fi + rm -rf ${workspace}/storage/* + cd ${workspace}/genesis + rm -rf validators.conf +} + +function init_validator() { + node_id=$1 + mkdir -p ${workspace}/storage/${node_id} + geth --datadir ${workspace}/storage/${node_id} account new --password /dev/null > ${workspace}/storage/${node_id}Info + validatorAddr=`cat ${workspace}/storage/${node_id}Info|grep 'Public address of the key'|awk '{print $6}'` + echo "${validatorAddr},${validatorAddr},${validatorAddr},0x0000000010000000" >> ${workspace}/genesis/validators.conf + echo ${validatorAddr} > ${workspace}/storage/${node_id}/address +} + +function generate_genesis() { + INIT_HOLDER_ADDRESSES=$(ls ${workspace}/init-holders | tr '\n' ',') + INIT_HOLDER_ADDRESSES=${INIT_HOLDER_ADDRESSES/%,/} + sed "s/{{INIT_HOLDER_ADDRESSES}}/${INIT_HOLDER_ADDRESSES}/g" ${workspace}/genesis/init_holders.template | sed "s/{{INIT_HOLDER_BALANCE}}/${INIT_HOLDER_BALANCE}/g" > ${workspace}/genesis/init_holders.js + node generate-validator.js + chainIDHex=$(printf '%04x\n' ${BSC_CHAIN_ID}) + node generate-genesis.js --chainid ${BSC_CHAIN_ID} --bscChainId ${chainIDHex} +} + +function init_genesis_data() { + node_type=$1 + node_id=$2 + geth --datadir ${workspace}/storage/${node_id} init ${workspace}/genesis/genesis.json + cp ${workspace}/config/config-${node_type}.toml ${workspace}/storage/${node_id}/config.toml + sed -i -e "s/{{NetworkId}}/${BSC_CHAIN_ID}/g" ${workspace}/storage/${node_id}/config.toml + if [ "${node_id}" == "bsc-rpc" ]; then + cp ${workspace}/init-holders/* ${workspace}/storage/${node_id}/keystore + cp ${workspace}/genesis/genesis.json ${workspace}/storage/${node_id} + fi +} + +prepare + +# First, generate config for each validator +for((i=1;i<=${NUMS_OF_VALIDATOR};i++)); do + init_validator "bsc-validator${i}" +done + +# Then, use validator configs to generate genesis file +generate_genesis + +# Finally, use genesis file to init cluster data +init_genesis_data bsc-rpc bsc-rpc + +for((i=1;i<=${NUMS_OF_VALIDATOR};i++)); do + init_genesis_data validator "bsc-validator${i}" +done diff --git a/tests/truffle/scripts/bsc-rpc.sh b/tests/truffle/scripts/bsc-rpc.sh new file mode 100755 index 0000000000..33bcdc1fb2 --- /dev/null +++ b/tests/truffle/scripts/bsc-rpc.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +DATA_DIR=/root/.ethereum + +account_cnt=$(ls ${DATA_DIR}/keystore | wc -l) +i=1 +unlock_sequences="0" +while [ "$i" -lt ${account_cnt} ]; do + unlock_sequences="${unlock_sequences},${i}" + i=$(( i + 1 )) +done + +geth --config ${DATA_DIR}/config.toml --datadir ${DATA_DIR} --netrestrict ${CLUSTER_CIDR} \ + --verbosity ${VERBOSE} --nousb \ + --rpc --rpc.allow-unprotected-txs --txlookuplimit 15768000 \ + -unlock ${unlock_sequences} --password /dev/null diff --git a/tests/truffle/scripts/bsc-validator.sh b/tests/truffle/scripts/bsc-validator.sh new file mode 100755 index 0000000000..b5cb38465b --- /dev/null +++ b/tests/truffle/scripts/bsc-validator.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +source /scripts/utils.sh + +DATA_DIR=/root/.ethereum + +wait_for_host_port ${BOOTSTRAP_HOST} ${BOOTSTRAP_TCP_PORT} +BOOTSTRAP_IP=$(get_host_ip $BOOTSTRAP_HOST) +VALIDATOR_ADDR=$(cat ${DATA_DIR}/address) +HOST_IP=$(hostname -i) + +echo "validator id: ${HOST_IP}" + +geth --config ${DATA_DIR}/config.toml --datadir ${DATA_DIR} --netrestrict ${CLUSTER_CIDR} \ + --verbosity ${VERBOSE} --nousb \ + --bootnodes enode://${BOOTSTRAP_PUB_KEY}@${BOOTSTRAP_IP}:${BOOTSTRAP_TCP_PORT} \ + --mine -unlock ${VALIDATOR_ADDR} --password /dev/null \ + --light.serve 50 \ + --rpc.allow-unprotected-txs --txlookuplimit 15768000 diff --git a/tests/truffle/scripts/truffle-test.sh b/tests/truffle/scripts/truffle-test.sh new file mode 100755 index 0000000000..7b483e42ee --- /dev/null +++ b/tests/truffle/scripts/truffle-test.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +sed -i -e "s/localhost:8545/${RPC_HOST}:${RPC_PORT}/g" test/TestProxyBEP20.js + +npm run truffle:test diff --git a/tests/truffle/scripts/utils.sh b/tests/truffle/scripts/utils.sh new file mode 100644 index 0000000000..c13e54bc67 --- /dev/null +++ b/tests/truffle/scripts/utils.sh @@ -0,0 +1,14 @@ +wait_for_host_port() { + while ! nc -v -z -w 3 ${1} ${2} >/dev/null 2>&1 < /dev/null; do + echo "$(date) - waiting for ${1}:${2}..." + sleep 5 + done +} + +get_host_ip() { + local host_ip + while [ -z ${host_ip} ]; do + host_ip=$(getent hosts ${1}| awk '{ print $1 ; exit }') + done + echo $host_ip +} From eb581fd9497bdf5249e4b083f51b6d1bed8d8ae6 Mon Sep 17 00:00:00 2001 From: guagualvcha <296179868@qq.com> Date: Tue, 19 Oct 2021 10:55:19 +0800 Subject: [PATCH 041/117] prepare for release v1.1.3 --- CHANGELOG.md | 23 +++++++++++++++++++++++ params/version.go | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2eb20ff22..c0bd5774f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,27 @@ # Changelog +## v1.1.3 +Improvement +* [\#456](https://github.com/binance-chain/bsc/pull/456) git-flow support lint, unit test, and integration test +* [\#449](https://github.com/binance-chain/bsc/pull/449) cache bitmap and change the cache type of GetCode +* [\#454](https://github.com/binance-chain/bsc/pull/454) fix cache key do not have hash func +* [\#446](https://github.com/binance-chain/bsc/pull/446) parallel bloom calculation +* [\#442](https://github.com/binance-chain/bsc/pull/442) ignore empty tx in GetDiffAccountsWithScope +* [\#426](https://github.com/binance-chain/bsc/pull/426) add block proccess backoff time when validator is not in turn and received in turn block +* [\#398](https://github.com/binance-chain/bsc/pull/398) ci pipeline for release page + + +BUGFIX +* [\#446](https://github.com/binance-chain/bsc/pull/446) fix concurrent write of subfetcher +* [\#444](https://github.com/binance-chain/bsc/pull/444) fix blockhash not correct for the logs of system tx receipt +* [\#409](https://github.com/binance-chain/bsc/pull/409) fix nil point in downloader +* [\#408](https://github.com/binance-chain/bsc/pull/408) core/state/snapshot: fix typo + + +FEATURES +* [\#431](https://github.com/binance-chain/bsc/pull/431) Export get diff accounts in block api +* [\#412](https://github.com/binance-chain/bsc/pull/412) add extension in eth protocol handshake to disable tx broadcast +* [\#376](https://github.com/binance-chain/bsc/pull/376) implement diff sync + ## v1.1.2 Security * [\#379](https://github.com/binance-chain/bsc/pull/379) A pre-announced hotfix release to patch a vulnerability in the EVM (CVE-2021-39137). diff --git a/params/version.go b/params/version.go index c3d0ab20ee..fe8f2938e6 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 2 // Patch version component of the current release + VersionPatch = 3 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From dc8df5c8570976e81463a57ea59471d222f4bd41 Mon Sep 17 00:00:00 2001 From: guagualvcha <296179868@qq.com> Date: Wed, 20 Oct 2021 12:00:40 +0800 Subject: [PATCH 042/117] fix download nil issue --- 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 55be200d59..5da80c9d3a 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1028,8 +1028,8 @@ func (d *Downloader) findAncestorBinarySearch(p *peerConnection, mode SyncMode, } header := d.lightchain.GetHeaderByHash(h) // Independent of sync mode, header surely exists if header == nil { - p.log.Error("header not found", "number", header.Number, "hash", header.Hash(), "request", check) - return 0, fmt.Errorf("%w: header no found (%d)", errBadPeer, header.Number) + p.log.Error("header not found", "hash", h, "request", check) + return 0, fmt.Errorf("%w: header no found (%s)", errBadPeer, h) } if header.Number.Uint64() != check { p.log.Warn("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check) From a04ee709a55d2ee9d8173b12f7abacbc37e66601 Mon Sep 17 00:00:00 2001 From: kyrie-yl Date: Wed, 20 Oct 2021 14:34:57 +0800 Subject: [PATCH 043/117] add metrics for contract code bitmap cache Signed-off-by: kyrie-yl --- core/vm/contract.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/vm/contract.go b/core/vm/contract.go index 6fac7f9858..dfc3ecd73f 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -22,12 +22,18 @@ import ( lru "github.com/hashicorp/golang-lru" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/metrics" "github.com/holiman/uint256" ) const codeBitmapCacheSize = 2000 -var codeBitmapCache, _ = lru.New(codeBitmapCacheSize) +var ( + codeBitmapCache, _ = lru.New(codeBitmapCacheSize) + + contractCodeBitmapHitMeter = metrics.NewRegisteredMeter("vm/contract/code/bitmap/hit", nil) + contractCodeBitmapMissMeter = metrics.NewRegisteredMeter("vm/contract/code/bitmap/miss", nil) +) // ContractRef is a reference to the contract's backing object type ContractRef interface { @@ -117,12 +123,14 @@ func (c *Contract) isCode(udest uint64) bool { analysis, exist := c.jumpdests[c.CodeHash] if !exist { if cached, ok := codeBitmapCache.Get(c.CodeHash); ok { + contractCodeBitmapHitMeter.Mark(1) analysis = cached.(bitvec) } else { // Do the analysis and save in parent context // We do not need to store it in c.analysis analysis = codeBitmap(c.Code) c.jumpdests[c.CodeHash] = analysis + contractCodeBitmapMissMeter.Mark(1) codeBitmapCache.Add(c.CodeHash, analysis) } } From faa007de15523ca4f7d1d6ec08b2baf4c45f3755 Mon Sep 17 00:00:00 2001 From: j75689 Date: Wed, 20 Oct 2021 18:29:40 +0800 Subject: [PATCH 044/117] ci: fix error on install truffle --- docker/Dockerfile.truffle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docker/Dockerfile.truffle b/docker/Dockerfile.truffle index 0ec7029377..28ab9da393 100644 --- a/docker/Dockerfile.truffle +++ b/docker/Dockerfile.truffle @@ -7,10 +7,7 @@ RUN git clone https://github.com/binance-chain/canonical-upgradeable-bep20.git / WORKDIR /usr/app/canonical-upgradeable-bep20 COPY docker/truffle-config.js /usr/app/canonical-upgradeable-bep20 -RUN npm install -g n -RUN n 12.18.3 && node -v - -RUN npm install -g truffle@v5.1.14 +RUN npm install -g --unsafe-perm truffle@v5.1.14 RUN npm install ENTRYPOINT [ "/bin/bash" ] From 100db0784a6f46487136080252f9eb3896895bdd Mon Sep 17 00:00:00 2001 From: j75689 Date: Wed, 20 Oct 2021 18:30:43 +0800 Subject: [PATCH 045/117] ci: remove unnecessary job in unit test --- .github/workflows/unit-test.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 737e4928a7..e885e4acf5 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -43,10 +43,6 @@ jobs: restore-keys: | ${{ runner.os }}-go- - - name: Test Build - run: | - make geth - - name: Uint Test env: ANDROID_HOME: "" # Skip android test From 3e5a7c0abcc41b527580a3ff56d6e53a6581bd4e Mon Sep 17 00:00:00 2001 From: j75689 Date: Thu, 21 Oct 2021 12:37:44 +0800 Subject: [PATCH 046/117] fix: unit-test failed --- core/blockchain_diff_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index 0b289bdc1c..67affcff75 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -280,10 +280,14 @@ func TestFreezeDiffLayer(t *testing.T) { blockNum := 1024 fullBackend := newTestBackend(blockNum, true) defer fullBackend.close() + for len(fullBackend.chain.diffQueueBuffer) > 0 { + // Wait for the buffer to be zero. + } // Minus one empty block. if fullBackend.chain.diffQueue.Size() != blockNum-1 { - t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum, fullBackend.chain.diffQueue.Size()) + t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum-1, fullBackend.chain.diffQueue.Size()) } + time.Sleep(diffLayerFreezerRecheckInterval + 1*time.Second) if fullBackend.chain.diffQueue.Size() != int(fullBackend.chain.triesInMemory) { t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum, fullBackend.chain.diffQueue.Size()) From 87bd1b0d612163f0a31a1a7d41a3323f250a86e3 Mon Sep 17 00:00:00 2001 From: j75689 Date: Thu, 21 Oct 2021 12:40:27 +0800 Subject: [PATCH 047/117] feat: time.Tick replaced with time.Ticker --- core/blockchain.go | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 91371940cd..22fe3e5998 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2486,9 +2486,12 @@ func (bc *BlockChain) update() { } func (bc *BlockChain) trustedDiffLayerLoop() { - recheck := time.Tick(diffLayerFreezerRecheckInterval) + recheck := time.NewTicker(diffLayerFreezerRecheckInterval) bc.wg.Add(1) - defer bc.wg.Done() + defer func() { + bc.wg.Done() + recheck.Stop() + }() for { select { case diff := <-bc.diffQueueBuffer: @@ -2521,29 +2524,28 @@ func (bc *BlockChain) trustedDiffLayerLoop() { batch.Reset() } return - case <-recheck: + case <-recheck.C: currentHeight := bc.CurrentBlock().NumberU64() var batch ethdb.Batch for !bc.diffQueue.Empty() { diff, prio := bc.diffQueue.Pop() diffLayer := diff.(*types.DiffLayer) - // if the block old enough - if int64(currentHeight)+prio >= int64(bc.triesInMemory) { - canonicalHash := bc.GetCanonicalHash(uint64(-prio)) - // on the canonical chain - if canonicalHash == diffLayer.BlockHash { - if batch == nil { - batch = bc.db.DiffStore().NewBatch() - } - rawdb.WriteDiffLayer(batch, diffLayer.BlockHash, diffLayer) - staleHash := bc.GetCanonicalHash(uint64(-prio) - bc.diffLayerFreezerBlockLimit) - rawdb.DeleteDiffLayer(batch, staleHash) - } - } else { + // if the block not old enough + if int64(currentHeight)+prio < int64(bc.triesInMemory) { bc.diffQueue.Push(diffLayer, prio) break } + canonicalHash := bc.GetCanonicalHash(uint64(-prio)) + // on the canonical chain + if canonicalHash == diffLayer.BlockHash { + if batch == nil { + batch = bc.db.DiffStore().NewBatch() + } + rawdb.WriteDiffLayer(batch, diffLayer.BlockHash, diffLayer) + staleHash := bc.GetCanonicalHash(uint64(-prio) - bc.diffLayerFreezerBlockLimit) + rawdb.DeleteDiffLayer(batch, staleHash) + } if batch != nil && batch.ValueSize() > ethdb.IdealBatchSize { if err := batch.Write(); err != nil { panic(fmt.Sprintf("Failed to write diff layer, error %v", err)) From a9657cb0e67161514d64aa5f0e29b817f629afcb Mon Sep 17 00:00:00 2001 From: j75689 Date: Thu, 21 Oct 2021 15:24:30 +0800 Subject: [PATCH 048/117] debug --- .github/workflows/unit-test.yml | 1 + core/blockchain_test.go | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index e885e4acf5..8847aeba4d 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -47,5 +47,6 @@ jobs: env: ANDROID_HOME: "" # Skip android test run: | + go clean -testcache make test diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 4314bd45a9..6874534817 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1568,8 +1568,8 @@ func TestLargeReorgTrieGC(t *testing.T) { t.Fatalf("failed to finalize competitor chain: %v", err) } for i, block := range competitor[:len(competitor)-TestTriesInMemory] { - if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { - t.Fatalf("competitor %d: competing chain state missing", i) + if node, err := chain.stateCache.TrieDB().Node(block.Root()); node != nil { + t.Fatalf("competitor %d: competing chain state missing, err: %v", i, err) } } } From 797ba71c806d20fb13de4c4c8f67d2bcc3669c6b Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:55:20 +0800 Subject: [PATCH 049/117] [R4R]fix prefetcher related bugs (#491) * fix goroutine leak in prefetcher Signed-off-by: Keefe-Liu * wait all goroutine done to avoid prefetcher close panic Signed-off-by: Keefe-Liu --- core/block_validator.go | 8 +++++--- core/state/statedb.go | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index 7ef440b4b7..12fa908cd0 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -144,13 +144,15 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD validateRes <- tmpFunc() }() } + + var err error for i := 0; i < len(validateFuns); i++ { r := <-validateRes - if r != nil { - return r + if r != nil && err == nil { + err = r } } - return nil + return err } // CalcGasLimit computes the gas limit of the next block after parent. It aims diff --git a/core/state/statedb.go b/core/state/statedb.go index c68e09490c..c7a9d92ef7 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -958,6 +958,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // goes into transaction receipts. func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if s.lightProcessed { + s.StopPrefetcher() return s.trie.Hash() } // Finalise all the dirty storage states and write them into the tries From 354d0a4dab2597b90563d6b5638262f4205fac1a Mon Sep 17 00:00:00 2001 From: "John.h" <25290445+Mercybudda@users.noreply.github.com> Date: Mon, 1 Nov 2021 20:34:58 +0800 Subject: [PATCH 050/117] core/state/snapshot: fix BAD BLOCK error when snapshot is generating (#23635) (#485) * core/state/snapshot: fix BAD BLOCK error when snapshot is generating * core/state/snapshot: alternative fix for the snapshot generator * add comments and minor update Co-authored-by: Martin Holst Swende * core/state/snapshot: fix BAD BLOCK error when snapshot is generating * core/state/snapshot: alternative fix for the snapshot generator * add comments and minor update Co-authored-by: Martin Holst Swende Co-authored-by: Ziyuan Zhong Co-authored-by: Martin Holst Swende --- core/state/snapshot/generate.go | 14 +++++++++++++- eth/downloader/downloader.go | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 7e29e51b21..a9f89b20b5 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -560,6 +560,12 @@ func (dl *diskLayer) generate(stats *generatorStats) { default: } if batch.ValueSize() > ethdb.IdealBatchSize || abort != nil { + if bytes.Compare(currentLocation, dl.genMarker) < 0 { + log.Error("Snapshot generator went backwards", + "currentLocation", fmt.Sprintf("%x", currentLocation), + "genMarker", fmt.Sprintf("%x", dl.genMarker)) + } + // Flush out the batch anyway no matter it's empty or not. // It's possible that all the states are recovered and the // generation indeed makes progress. @@ -634,8 +640,14 @@ func (dl *diskLayer) generate(stats *generatorStats) { stats.storage += common.StorageSize(1 + common.HashLength + dataLen) stats.accounts++ } + marker := accountHash[:] + // If the snap generation goes here after interrupted, genMarker may go backward + // when last genMarker is consisted of accountHash and storageHash + if accMarker != nil && bytes.Equal(marker, accMarker) && len(dl.genMarker) > common.HashLength { + marker = dl.genMarker[:] + } // If we've exceeded our batch allowance or termination was requested, flush to disk - if err := checkAndFlush(accountHash[:]); err != nil { + if err := checkAndFlush(marker); err != nil { return err } // If the iterated account is the contract, create a further loop to diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 55be200d59..5da80c9d3a 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1028,8 +1028,8 @@ func (d *Downloader) findAncestorBinarySearch(p *peerConnection, mode SyncMode, } header := d.lightchain.GetHeaderByHash(h) // Independent of sync mode, header surely exists if header == nil { - p.log.Error("header not found", "number", header.Number, "hash", header.Hash(), "request", check) - return 0, fmt.Errorf("%w: header no found (%d)", errBadPeer, header.Number) + p.log.Error("header not found", "hash", h, "request", check) + return 0, fmt.Errorf("%w: header no found (%s)", errBadPeer, h) } if header.Number.Uint64() != check { p.log.Warn("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check) From b71cbdfe29e188ed115c18d4246c22ca54fe24d6 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Mon, 25 Oct 2021 16:33:16 +0800 Subject: [PATCH 051/117] implement bep 95 fix test cases add upgrade name fix comments --- core/systemcontracts/upgrade.go | 39 +++++++++++++++++++++++++++++++++ eth/catalyst/api_test.go | 1 + params/config.go | 34 +++++++++++++++++++++++----- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/core/systemcontracts/upgrade.go b/core/systemcontracts/upgrade.go index eaae5b1a49..a040bf8d64 100644 --- a/core/systemcontracts/upgrade.go +++ b/core/systemcontracts/upgrade.go @@ -41,6 +41,8 @@ var ( nielsUpgrade = make(map[string]*Upgrade) mirrorUpgrade = make(map[string]*Upgrade) + + brunoUpgrade = make(map[string]*Upgrade) ) func init() { @@ -274,6 +276,39 @@ func init() { }, }, } + + brunoUpgrade[mainNet] = &Upgrade{ + UpgradeName: "bruno", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(ValidatorContract), + CommitUrl: "https://github.com/binance-chain/bsc-genesis-contract/commit/ce622fef469d84ee418fa6181f3ac962412a5f4f", + Code: "6080604052600436106102e45760003560e01c80638624988211610190578063c8509d81116100dc578063eb57e20211610095578063f9a2bbc71161006f578063f9a2bbc714610a54578063fc3e590814610a69578063fccc281314610a7e578063fd6a687914610a93576102e4565b8063eb57e202146109e6578063eda5868c14610a19578063f340fa0114610a2e576102e4565b8063c8509d81146106d8578063d86222d51461097d578063daacdb6614610992578063dc927faf146109a7578063e086c7b1146109bc578063e1c7392a146109d1576102e4565b8063aaf5eb6811610149578063ad3c9da611610123578063ad3c9da6146108d0578063b7ab4db514610903578063bf9f4995146104c0578063c81b166214610968576102e4565b8063aaf5eb68146107db578063ab51bb96146107f0578063ac43175114610805576102e4565b8063862498821461075d57806396713da9146107725780639dc0926214610787578063a1a11bf51461079c578063a5422d5c146107b1578063a78abc16146107c6576102e4565b806351e806721161024f57806370fd5bad116102085780637942fd05116101e25780637942fd05146106ae57806381650b62146106c3578063831d65d1146106d8578063853230aa14610699576102e4565b806370fd5bad1461066f57806375d47a0a1461068457806378dfed4a14610699576102e4565b806351e8067214610572578063565c56b3146105875780635667515a146105ba5780635d77156c146105cf5780636969a25c146105e45780636e47b4821461065a576102e4565b80633de0f0d8116102a15780633de0f0d8146104ab5780633dffc387146104c057806343756e5c146104eb578063493279b11461051c5780634bf6c882146105485780635192c82c1461055d576102e4565b80630bee7a67146102e95780631182b87514610317578063152ad3b8146104115780631ff180691461043a578063219f22d51461046157806335409f7f14610476575b600080fd5b3480156102f557600080fd5b506102fe610aa8565b6040805163ffffffff9092168252519081900360200190f35b34801561032357600080fd5b5061039c6004803603604081101561033a57600080fd5b60ff8235169190810190604081016020820135600160201b81111561035e57600080fd5b82018360208201111561037057600080fd5b803590602001918460018302840111600160201b8311171561039157600080fd5b509092509050610aad565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103d65781810151838201526020016103be565b50505050905090810190601f1680156104035780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041d57600080fd5b50610426610c9a565b604080519115158252519081900360200190f35b34801561044657600080fd5b5061044f610ca3565b60408051918252519081900360200190f35b34801561046d57600080fd5b506102fe610ca9565b34801561048257600080fd5b506104a96004803603602081101561049957600080fd5b50356001600160a01b0316610cae565b005b3480156104b757600080fd5b5061044f610fc2565b3480156104cc57600080fd5b506104d5610fc8565b6040805160ff9092168252519081900360200190f35b3480156104f757600080fd5b50610500610fcd565b604080516001600160a01b039092168252519081900360200190f35b34801561052857600080fd5b50610531610fd3565b6040805161ffff9092168252519081900360200190f35b34801561055457600080fd5b506104d5610fd8565b34801561056957600080fd5b5061044f610fdd565b34801561057e57600080fd5b50610500610fe3565b34801561059357600080fd5b5061044f600480360360208110156105aa57600080fd5b50356001600160a01b0316610fe9565b3480156105c657600080fd5b506104d561103b565b3480156105db57600080fd5b506102fe611040565b3480156105f057600080fd5b5061060e6004803603602081101561060757600080fd5b5035611045565b604080516001600160a01b039788168152958716602087015293909516848401526001600160401b0390911660608401521515608083015260a082019290925290519081900360c00190f35b34801561066657600080fd5b506105006110a9565b34801561067b57600080fd5b506104d56110af565b34801561069057600080fd5b506105006110b4565b3480156106a557600080fd5b5061044f6110ba565b3480156106ba57600080fd5b506104d56110c0565b3480156106cf57600080fd5b506102fe6110c5565b3480156106e457600080fd5b506104a9600480360360408110156106fb57600080fd5b60ff8235169190810190604081016020820135600160201b81111561071f57600080fd5b82018360208201111561073157600080fd5b803590602001918460018302840111600160201b8311171561075257600080fd5b5090925090506110ca565b34801561076957600080fd5b5061044f61117d565b34801561077e57600080fd5b506104d5611183565b34801561079357600080fd5b50610500611188565b3480156107a857600080fd5b5061050061118e565b3480156107bd57600080fd5b5061039c611194565b3480156107d257600080fd5b506104266111b3565b3480156107e757600080fd5b5061044f6111bc565b3480156107fc57600080fd5b506102fe61103b565b34801561081157600080fd5b506104a96004803603604081101561082857600080fd5b810190602081018135600160201b81111561084257600080fd5b82018360208201111561085457600080fd5b803590602001918460018302840111600160201b8311171561087557600080fd5b919390929091602081019035600160201b81111561089257600080fd5b8201836020820111156108a457600080fd5b803590602001918460018302840111600160201b831117156108c557600080fd5b5090925090506111c5565b3480156108dc57600080fd5b5061044f600480360360208110156108f357600080fd5b50356001600160a01b03166115bc565b34801561090f57600080fd5b506109186115ce565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561095457818101518382015260200161093c565b505050509050019250505060405180910390f35b34801561097457600080fd5b506105006116f4565b34801561098957600080fd5b5061044f6116fa565b34801561099e57600080fd5b5061044f611706565b3480156109b357600080fd5b5061050061170c565b3480156109c857600080fd5b5061044f611712565b3480156109dd57600080fd5b506104a9611717565b3480156109f257600080fd5b506104a960048036036020811015610a0957600080fd5b50356001600160a01b031661191a565b348015610a2557600080fd5b506102fe611ae9565b6104a960048036036020811015610a4457600080fd5b50356001600160a01b0316611aee565b348015610a6057600080fd5b50610500611df3565b348015610a7557600080fd5b506104d5611df9565b348015610a8a57600080fd5b50610500611dfe565b348015610a9f57600080fd5b50610500611e04565b606481565b60005460609060ff16610b03576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b3361200014610b435760405162461bcd60e51b815260040180806020018281038252602f815260200180614951602f913960400191505060405180910390fd5b610b4b614158565b6000610b8c85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611e0a92505050565b9150915080610ba857610b9f6064611f63565b92505050610c93565b815160009060ff16610bc857610bc18360200151611fc4565b9050610c5f565b825160ff1660011415610c5b57826020015151600114610c35577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb26040518080602001828103825260258152602001806142866025913960400191505060405180910390a1506067610c56565b610bc18360200151600081518110610c4957fe5b6020026020010151612dca565b610c5f565b5060655b63ffffffff8116610c845750506040805160008152602081019091529150610c939050565b610c8d81611f63565b93505050505b9392505050565b60075460ff1681565b60035481565b606881565b3361100114610cee5760405162461bcd60e51b81526004018080602001828103825260298152602001806149ad6029913960400191505060405180910390fd5b6001600160a01b03811660009081526004602052604090205480610d125750610fbf565b600181039050600060018281548110610d2757fe5b60009182526020909120600360049092020101546001549091506000190180610d7657600060018481548110610d5957fe5b906000526020600020906004020160030181905550505050610fbf565b6040805183815290516001600160a01b038616917f3b6f9ef90462b512a1293ecec018670bf7b7f1876fb727590a8a6d7643130a70919081900360200190a26001600160a01b038416600090815260046020526040812055600154600019018314610ef857600180546000198101908110610ded57fe5b906000526020600020906004020160018481548110610e0857fe5b6000918252602082208354600492830290910180546001600160a01b03199081166001600160a01b0393841617825560018087015481840180548416918616919091179055600280880180549185018054909416919095161780835584546001600160401b03600160a01b91829004160267ffffffffffffffff60a01b1990911617808355935460ff600160e01b918290041615150260ff60e01b199094169390931790556003948501549401939093558254868401939192919087908110610ecd57fe5b600091825260208083206004909202909101546001600160a01b031683528201929092526040019020555b6001805480610f0357fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b03191690556003018190559155818381610f5657fe5b0490508015610fba5760015460005b81811015610fb7578260018281548110610f7b57fe5b9060005260206000209060040201600301540160018281548110610f9b57fe5b6000918252602090912060036004909202010155600101610f65565b50505b505050505b50565b61271081565b600181565b61100181565b603881565b600881565b60065481565b61200081565b6001600160a01b03811660009081526004602052604081205480611011576000915050611036565b60018082038154811061102057fe5b9060005260206000209060040201600301549150505b919050565b600081565b606781565b6001818154811061105257fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509082169291821691600160a01b81046001600160401b031691600160e01b90910460ff169086565b61100581565b600281565b61100881565b6103e881565b600b81565b606681565b336120001461110a5760405162461bcd60e51b815260040180806020018281038252602f815260200180614951602f913960400191505060405180910390fd5b7f41ce201247b6ceb957dcdb217d0b8acb50b9ea0e12af9af4f5e7f38902101605838383604051808460ff1660ff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b60025481565b600981565b61100781565b61100681565b6040518061062001604052806105ef81526020016143626105ef913981565b60005460ff1681565b6402540be40081565b60005460ff16611218576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b33611007146112585760405162461bcd60e51b815260040180806020018281038252602e8152602001806142cc602e913960400191505060405180910390fd5b6112c284848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526013815272065787069726554696d655365636f6e6447617606c1b60208201529150612f419050565b1561139d57602081146113065760405162461bcd60e51b815260040180806020018281038252602681526020018061431b6026913960400191505060405180910390fd5b604080516020601f84018190048102820181019092528281526000916113449185858083850183828082843760009201919091525061302992505050565b90506064811015801561135a5750620186a08111155b6113955760405162461bcd60e51b815260040180806020018281038252602781526020018061425f6027913960400191505060405180910390fd5b60025561152a565b6113fd84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260098152686275726e526174696f60b81b60208201529150612f419050565b156114ed5760208114611457576040805162461bcd60e51b815260206004820152601c60248201527f6c656e677468206f66206275726e526174696f206d69736d6174636800000000604482015290519081900360640190fd5b604080516020601f84018190048102820181019092528281526000916114959185858083850183828082843760009201919091525061302992505050565b90506127108111156114d85760405162461bcd60e51b815260040180806020018281038252602b815260200180614209602b913960400191505060405180910390fd5b6006556007805460ff1916600117905561152a565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b60046020526000908152604090205481565b6001546060906000805b8281101561161f57600181815481106115ed57fe5b9060005260206000209060040201600201601c9054906101000a900460ff16611617576001909101905b6001016115d8565b5060608160405190808252806020026020018201604052801561164c578160200160208202803683370190505b50600092509050815b838110156116ec576001818154811061166a57fe5b9060005260206000209060040201600201601c9054906101000a900460ff166116e4576001818154811061169a57fe5b600091825260209091206004909102015482516001600160a01b03909116908390859081106116c557fe5b6001600160a01b03909216602092830291909101909101526001909201915b600101611655565b509250505090565b61100281565b67016345785d8a000081565b60055481565b61100381565b602981565b60005460ff161561176f576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b611777614158565b600061179d6040518061062001604052806105ef81526020016143626105ef9139611e0a565b91509150806117dd5760405162461bcd60e51b81526004018080602001828103825260218152602001806143416021913960400191505060405180910390fd5b60005b826020015151811015611902576001836020015182815181106117ff57fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782558587015182850180549185169183169190911790556040860151600283018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590981692909516919091179290921694909417161790915560a0909301516003909301929092559186015180519185019391859081106118d557fe5b602090810291909101810151516001600160a01b03168252810191909152604001600020556001016117e0565b50506103e8600255506000805460ff19166001179055565b336110011461195a5760405162461bcd60e51b81526004018080602001828103825260298152602001806149ad6029913960400191505060405180910390fd5b6001600160a01b0381166000908152600460205260409020548061197e5750610fbf565b60018103905060006001828154811061199357fe5b90600052602060002090600402016003015490506000600183815481106119b657fe5b906000526020600020906004020160030181905550600060018080549050039050836001600160a01b03167f8cd4e147d8af98a9e3b6724021b8bf6aed2e5dac71c38f2dce8161b82585b25d836040518082815260200191505060405180910390a280611a2557505050610fbf565b6000818381611a3057fe5b0490508015610fba5760005b84811015611a8e578160018281548110611a5257fe5b9060005260206000209060040201600301540160018281548110611a7257fe5b6000918252602090912060036004909202010155600101611a3c565b50600180549085015b81811015610fb7578260018281548110611aad57fe5b9060005260206000209060040201600301540160018281548110611acd57fe5b6000918252602090912060036004909202010155600101611a97565b606581565b334114611b2c5760405162461bcd60e51b815260040180806020018281038252602d815260200180614980602d913960400191505060405180910390fd5b60005460ff16611b7f576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b60003411611bcc576040805162461bcd60e51b81526020600482015260156024820152746465706f7369742076616c7565206973207a65726f60581b604482015290519081900360640190fd5b6001600160a01b0381166000908152600460205260409020546007543491906103e89060ff1615611bfc57506006545b600083118015611c0c5750600081115b15611cb5576000611c35612710611c29868563ffffffff61302e16565b9063ffffffff61308716565b90508015611cb35760405161dead9082156108fc029083906000818181858888f19350505050158015611c6c573d6000803e3d6000fd5b506040805182815290517f627059660ea01c4733a328effb2294d2f86905bf806da763a89cee254de8bee59181900360200190a1611cb0848263ffffffff6130c916565b93505b505b8115611dad576000600180840381548110611ccc57fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff1615611d37576040805185815290516001600160a01b038716917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a2611da7565b600354611d4a908563ffffffff61310b16565b6003908155810154611d62908563ffffffff61310b16565b60038201556040805185815290516001600160a01b038716917f93a090ecc682c002995fad3c85b30c5651d7fd29b0be5da9d784a3302aedc055919081900360200190a25b50611ded565b6040805184815290516001600160a01b038616917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a25b50505050565b61100081565b600381565b61dead81565b61100481565b611e12614158565b6000611e1c614158565b611e24614170565b611e35611e3086613165565b61318a565b90506000805b611e44836131d4565b15611f555780611e6957611e5f611e5a846131f5565b613243565b60ff168452611f4d565b8060011415611f48576060611e85611e80856131f5565b6132fa565b90508051604051908082528060200260200182016040528015611ec257816020015b611eaf614190565b815260200190600190039081611ea75790505b50602086015260005b8151811015611f3d57611edc614190565b6000611efa848481518110611eed57fe5b60200260200101516133cb565b9150915080611f1757876000995099505050505050505050611f5e565b8188602001518481518110611f2857fe5b60209081029190910101525050600101611ecb565b506001925050611f4d565b611f55565b600101611e3b565b50919350909150505b915091565b604080516001808252818301909252606091829190816020015b6060815260200190600190039081611f7d579050509050611fa38363ffffffff166134a8565b81600081518110611fb057fe5b6020026020010181905250610c93816134bb565b6000806060611fd284613545565b915091508161207f577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2816040518080602001828103825283818151815260200191508051906020019080838360005b8381101561203a578181015183820152602001612022565b50505050905090810190601f1680156120675780820380516001836020036101000a031916815260200191505b509250505060405180910390a1606692505050611036565b600080805b6001548110156120fc5767016345785d8a0000600182815481106120a457fe5b906000526020600020906004020160030154106120c6576001909201916120f4565b6000600182815481106120d557fe5b90600052602060002090600402016003015411156120f4576001909101905b600101612084565b50606082604051908082528060200260200182016040528015612129578160200160208202803683370190505b509050606083604051908082528060200260200182016040528015612158578160200160208202803683370190505b509050606084604051908082528060200260200182016040528015612187578160200160208202803683370190505b5090506060856040519080825280602002602001820160405280156121b6578160200160208202803683370190505b50905060006060866040519080825280602002602001820160405280156121e7578160200160208202803683370190505b509050606087604051908082528060200260200182016040528015612216578160200160208202803683370190505b509050600098506000975060608d905060006110046001600160a01b031663149d14d96040518163ffffffff1660e01b815260040160206040518083038186803b15801561226357600080fd5b505afa158015612277573d6000803e3d6000fd5b505050506040513d602081101561228d57600080fd5b5051905067016345785d8a0000811115612302577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb26040518080602001828103825260218152602001806142fa6021913960400191505060405180910390a160689d5050505050505050505050505050611036565b60005b6001548110156125755767016345785d8a00006001828154811061232557fe5b906000526020600020906004020160030154106124ab576001818154811061234957fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b03168a8d8151811061237a57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006402540be400600183815481106123af57fe5b906000526020600020906004020160030154816123c857fe5b06600183815481106123d657fe5b9060005260206000209060040201600301540390506123fe83826130c990919063ffffffff16565b8a8e8151811061240a57fe5b6020026020010181815250506001828154811061242357fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316888e8151811061245457fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081898e8151811061248157fe5b602090810291909101015261249c878263ffffffff61310b16565b6001909d019c965061256d9050565b6000600182815481106124ba57fe5b906000526020600020906004020160030154111561256d57600181815481106124df57fe5b906000526020600020906004020160010160009054906101000a90046001600160a01b0316858c8151811061251057fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001818154811061253d57fe5b906000526020600020906004020160030154848c8151811061255b57fe5b60209081029190910101526001909a01995b600101612305565b50600085156129b3576110046001600160a01b0316636e056520878c8c8b60025442016040518663ffffffff1660e01b815260040180806020018060200180602001856001600160401b03166001600160401b03168152602001848103845288818151815260200191508051906020019060200280838360005b838110156126075781810151838201526020016125ef565b50505050905001848103835287818151815260200191508051906020019060200280838360005b8381101561264657818101518382015260200161262e565b50505050905001848103825286818151815260200191508051906020019060200280838360005b8381101561268557818101518382015260200161266d565b505050509050019750505050505050506020604051808303818588803b1580156126ae57600080fd5b505af1935050505080156126d457506040513d60208110156126cf57600080fd5b505160015b61290f576040516000815260443d10156126f05750600061278b565b60046000803e60005160e01c6308c379a0811461271157600091505061278b565b60043d036004833e81513d60248201116001600160401b038211171561273c5760009250505061278b565b80830180516001600160401b0381111561275d57600094505050505061278b565b8060208301013d860181111561277b5760009550505050505061278b565b601f01601f191660405250925050505b80612796575061283a565b60019150867fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280826040518080602001828103825283818151815260200191508051906020019080838360005b838110156127fa5781810151838201526020016127e2565b50505050905090810190601f1680156128275780820380516001836020036101000a031916815260200191505b509250505060405180910390a25061290a565b3d808015612864576040519150601f19603f3d011682016040523d82523d6000602084013e612869565b606091505b5060019150867fbfa884552dd8921b6ce90bfe906952ae5b3b29be0cc1a951d4f62697635a3a45826040518080602001828103825283818151815260200191508051906020019080838360005b838110156128ce5781810151838201526020016128b6565b50505050905090810190601f1680156128fb5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505b6129b3565b801561294d576040805188815290517fa217d08e65f80c73121cd9db834d81652d544bfbf452f6d04922b16c90a37b709181900360200190a16129b1565b604080516020808252601b908201527f6261746368207472616e736665722072657475726e2066616c7365000000000081830152905188917fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280919081900360600190a25b505b8015612b695760005b8851811015612b675760008982815181106129d357fe5b602002602001015190506000600182815481106129ec57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116916108fc9185908110612a1d57fe5b9060005260206000209060040201600301549081150290604051600060405180830381858888f1935050505090508015612ad95760018281548110612a5e57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d9185908110612aad57fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a2612b5d565b60018281548110612ae657fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d9185908110612b3557fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a25b50506001016129bc565b505b845115612cb35760005b8551811015612cb1576000868281518110612b8a57fe5b60200260200101516001600160a01b03166108fc878481518110612baa57fe5b60200260200101519081150290604051600060405180830381858888f1935050505090508015612c4057868281518110612be057fe5b60200260200101516001600160a01b03167f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d878481518110612c1e57fe5b60200260200101516040518082815260200191505060405180910390a2612ca8565b868281518110612c4c57fe5b60200260200101516001600160a01b03167f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d878481518110612c8a57fe5b60200260200101516040518082815260200191505060405180910390a25b50600101612b73565b505b4715612d1c576040805147815290517f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d9181900360200190a1604051611002904780156108fc02916000818181858888f19350505050158015612d1a573d6000803e3d6000fd5b505b60006003819055600555825115612d3657612d3683613627565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d7357600080fd5b505af1158015612d87573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a15060009f9e505050505050505050505050505050565b80516001600160a01b0316600090815260046020526040812054801580612e1b5750600180820381548110612dfb57fe5b9060005260206000209060040201600201601c9054906101000a900460ff165b15612e615782516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a26000915050611036565b600154600554600019820111801590612eb75784516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a260009350505050611036565b600580546001908101909155805481906000198601908110612ed557fe5b6000918252602082206002600490920201018054921515600160e01b0260ff60e01b199093169290921790915585516040516001600160a01b03909116917ff226e7d8f547ff903d9d419cf5f54e0d7d07efa9584135a53a057c5f1f27f49a91a2506000949350505050565b6000816040516020018082805190602001908083835b60208310612f765780518252601f199092019160209182019101612f57565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b60208310612fe45780518252601f199092019160209182019101612fc5565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201490505b92915050565b015190565b60008261303d57506000613023565b8282028284828161304a57fe5b0414610c935760405162461bcd60e51b81526004018080602001828103825260218152602001806142ab6021913960400191505060405180910390fd5b6000610c9383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ae8565b6000610c9383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b8a565b600082820183811015610c93576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b61316d6141c5565b506040805180820190915281518152602082810190820152919050565b613192614170565b61319b82613be4565b6131a457600080fd5b60006131b38360200151613c1e565b60208085015160408051808201909152868152920190820152915050919050565b60006131de6141c5565b505080518051602091820151919092015191011190565b6131fd6141c5565b613206826131d4565b61320f57600080fd5b6020820151600061321f82613c81565b80830160209586015260408051808201909152908152938401919091525090919050565b80516000901580159061325857508151602110155b61326157600080fd5b60006132708360200151613c1e565b905080836000015110156132cb576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b8251602080850151830180519284900392918310156132f157826020036101000a820491505b50949350505050565b606061330582613be4565b61330e57600080fd5b600061331983613db4565b905060608160405190808252806020026020018201604052801561335757816020015b6133446141c5565b81526020019060019003908161333c5790505b50905060006133698560200151613c1e565b60208601510190506000805b848110156133c05761338683613c81565b91506040518060400160405280838152602001848152508482815181106133a957fe5b602090810291909101015291810191600101613375565b509195945050505050565b6133d3614190565b60006133dd614190565b6133e5614170565b6133ee8561318a565b90506000805b6133fd836131d4565b15611f55578061342857613418613413846131f5565b613e10565b6001600160a01b031684526134a0565b80600114156134505761343d613413846131f5565b6001600160a01b031660208501526134a0565b806002141561347857613465613413846131f5565b6001600160a01b031660408501526134a0565b8060031415611f485761348d611e5a846131f5565b6001600160401b03166060850152600191505b6001016133f4565b60606130236134b683613e2a565b613f10565b60608151600014156134dc5750604080516000815260208101909152611036565b6060826000815181106134eb57fe5b602002602001015190506000600190505b835181101561352c576135228285838151811061351557fe5b6020026020010151613f62565b91506001016134fc565b50610c9361353f825160c060ff16613fdf565b82613f62565b600060606029835111156135775760006040518060600160405280602981526020016141e06029913991509150611f5e565b60005b835181101561360d5760005b818110156136045784818151811061359a57fe5b6020026020010151600001516001600160a01b03168583815181106135bb57fe5b6020026020010151600001516001600160a01b031614156135fc5760006040518060600160405280602b8152602001614234602b9139935093505050611f5e565b600101613586565b5060010161357a565b505060408051602081019091526000815260019150915091565b600154815160005b82811015613744576001613641614190565b6001838154811061364e57fe5b600091825260208083206040805160c08101825260049490940290910180546001600160a01b0390811685526001820154811693850193909352600281015492831691840191909152600160a01b82046001600160401b03166060840152600160e01b90910460ff16151560808301526003015460a082015291505b84811015613718578681815181106136de57fe5b6020026020010151600001516001600160a01b031682600001516001600160a01b031614156137105760009250613718565b6001016136ca565b50811561373a5780516001600160a01b03166000908152600460205260408120555b505060010161362f565b50808211156137b957805b828110156137b757600180548061376257fe5b60008281526020812060046000199093019283020180546001600160a01b03199081168255600182810180549092169091556002820180546001600160e81b031916905560039091019190915591550161374f565b505b60008183106137c857816137ca565b825b905060005b818110156139c45761387c8582815181106137e657fe5b6020026020010151600183815481106137fb57fe5b60009182526020918290206040805160c08101825260049390930290910180546001600160a01b0390811684526001820154811694840194909452600281015493841691830191909152600160a01b83046001600160401b03166060830152600160e01b90920460ff161515608082015260039091015460a08201526140d7565b61399757806001016004600087848151811061389457fe5b6020026020010151600001516001600160a01b03166001600160a01b03168152602001908152602001600020819055508481815181106138d057fe5b6020026020010151600182815481106138e557fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a0909101516003909101556139bc565b6000600182815481106139a657fe5b9060005260206000209060040201600301819055505b6001016137cf565b5082821115611ded57825b82811015610fba5760018582815181106139e557fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782559585015181840180549184169188169190911790556040850151600282018054606088015160808901511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590971692909a169190911792909216939093171695909517905560a09092015160039093019290925587519084019290889085908110613abb57fe5b602090810291909101810151516001600160a01b03168252810191909152604001600020556001016139cf565b60008183613b745760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613b39578181015183820152602001613b21565b50505050905090810190601f168015613b665780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613b8057fe5b0495945050505050565b60008184841115613bdc5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613b39578181015183820152602001613b21565b505050900390565b8051600090613bf557506000611036565b6020820151805160001a9060c0821015613c1457600092505050611036565b5060019392505050565b8051600090811a6080811015613c38576000915050611036565b60b8811080613c53575060c08110801590613c53575060f881105b15613c62576001915050611036565b60c0811015613c765760b519019050611036565b60f519019050611036565b80516000908190811a6080811015613c9c5760019150613dad565b60b8811015613cb157607e1981019150613dad565b60c0811015613d2b57600060b78203600186019550806020036101000a865104915060018101820193505080831015613d25576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b50613dad565b60f8811015613d405760be1981019150613dad565b600060f78203600186019550806020036101000a865104915060018101820193505080831015613dab576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b8051600090613dc557506000611036565b60008090506000613dd98460200151613c1e565b602085015185519181019250015b80821015613e0757613df882613c81565b60019093019290910190613de7565b50909392505050565b8051600090601514613e2157600080fd5b61302382613243565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff198416613e6e57506018613e92565b6fffffffffffffffffffffffffffffffff198416613e8e57506010613e92565b5060005b6020811015613ec857818181518110613ea757fe5b01602001516001600160f81b03191615613ec057613ec8565b600101613e92565b60008160200390506060816040519080825280601f01601f191660200182016040528015613efd576020820181803683370190505b5080830196909652508452509192915050565b606081516001148015613f425750607f60f81b82600081518110613f3057fe5b01602001516001600160f81b03191611155b15613f4e575080611036565b613023613f608351608060ff16613fdf565b835b6060806040519050835180825260208201818101602087015b81831015613f93578051835260209283019201613f7b565b50855184518101855292509050808201602086015b81831015613fc0578051835260209283019201613fa8565b508651929092011591909101601f01601f191660405250905092915050565b606068010000000000000000831061402f576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116140895782840160f81b8160008151811061406b57fe5b60200101906001600160f81b031916908160001a9053509050613023565b606061409485613e2a565b90508381510160370160f81b826000815181106140ad57fe5b60200101906001600160f81b031916908160001a9053506140ce8282613f62565b95945050505050565b805182516000916001600160a01b039182169116148015614111575081602001516001600160a01b031683602001516001600160a01b0316145b8015614136575081604001516001600160a01b031683604001516001600160a01b0316145b8015610c935750506060908101519101516001600160401b0390811691161490565b60408051808201909152600081526060602082015290565b60405180604001604052806141836141c5565b8152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60405180604001604052806000815260200160008152509056fe746865206e756d626572206f662076616c696461746f72732065786365656420746865206c696d6974746865206275726e526174696f206d757374206265206e6f2067726561746572207468616e2031303030306475706c696361746520636f6e73656e7375732061646472657373206f662076616c696461746f725365747468652065787069726554696d655365636f6e64476170206973206f7574206f662072616e67656c656e677468206f66206a61696c2076616c696461746f7273206d757374206265206f6e65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374666565206973206c6172676572207468616e2044555354595f494e434f4d494e476c656e677468206f662065787069726554696d655365636f6e64476170206d69736d617463686661696c656420746f20706172736520696e69742076616c696461746f72536574f905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a2000746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f6475636572746865206d6573736167652073656e646572206d75737420626520736c61736820636f6e7472616374a2646970667358221220b806ba3d9dd9e078bac9726f79b32c9b62db327924a189cc1a9e4e106ffbe50d64736f6c63430006040033", + }, + }, + } + + brunoUpgrade[chapelNet] = &Upgrade{ + UpgradeName: "bruno", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(ValidatorContract), + CommitUrl: "https://github.com/binance-chain/bsc-genesis-contract/commit/ce622fef469d84ee418fa6181f3ac962412a5f4f", + Code: "6080604052600436106102e45760003560e01c80638624988211610190578063c8509d81116100dc578063eb57e20211610095578063f9a2bbc71161006f578063f9a2bbc714610a54578063fc3e590814610a69578063fccc281314610a7e578063fd6a687914610a93576102e4565b8063eb57e202146109e6578063eda5868c14610a19578063f340fa0114610a2e576102e4565b8063c8509d81146106d8578063d86222d51461097d578063daacdb6614610992578063dc927faf146109a7578063e086c7b1146109bc578063e1c7392a146109d1576102e4565b8063aaf5eb6811610149578063ad3c9da611610123578063ad3c9da6146108d0578063b7ab4db514610903578063bf9f4995146104c0578063c81b166214610968576102e4565b8063aaf5eb68146107db578063ab51bb96146107f0578063ac43175114610805576102e4565b8063862498821461075d57806396713da9146107725780639dc0926214610787578063a1a11bf51461079c578063a5422d5c146107b1578063a78abc16146107c6576102e4565b806351e806721161024f57806370fd5bad116102085780637942fd05116101e25780637942fd05146106ae57806381650b62146106c3578063831d65d1146106d8578063853230aa14610699576102e4565b806370fd5bad1461066f57806375d47a0a1461068457806378dfed4a14610699576102e4565b806351e8067214610572578063565c56b3146105875780635667515a146105ba5780635d77156c146105cf5780636969a25c146105e45780636e47b4821461065a576102e4565b80633de0f0d8116102a15780633de0f0d8146104ab5780633dffc387146104c057806343756e5c146104eb578063493279b11461051c5780634bf6c882146105485780635192c82c1461055d576102e4565b80630bee7a67146102e95780631182b87514610317578063152ad3b8146104115780631ff180691461043a578063219f22d51461046157806335409f7f14610476575b600080fd5b3480156102f557600080fd5b506102fe610aa8565b6040805163ffffffff9092168252519081900360200190f35b34801561032357600080fd5b5061039c6004803603604081101561033a57600080fd5b60ff8235169190810190604081016020820135600160201b81111561035e57600080fd5b82018360208201111561037057600080fd5b803590602001918460018302840111600160201b8311171561039157600080fd5b509092509050610aad565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103d65781810151838201526020016103be565b50505050905090810190601f1680156104035780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041d57600080fd5b50610426610c9a565b604080519115158252519081900360200190f35b34801561044657600080fd5b5061044f610ca3565b60408051918252519081900360200190f35b34801561046d57600080fd5b506102fe610ca9565b34801561048257600080fd5b506104a96004803603602081101561049957600080fd5b50356001600160a01b0316610cae565b005b3480156104b757600080fd5b5061044f610fc2565b3480156104cc57600080fd5b506104d5610fc8565b6040805160ff9092168252519081900360200190f35b3480156104f757600080fd5b50610500610fcd565b604080516001600160a01b039092168252519081900360200190f35b34801561052857600080fd5b50610531610fd3565b6040805161ffff9092168252519081900360200190f35b34801561055457600080fd5b506104d5610fd8565b34801561056957600080fd5b5061044f610fdd565b34801561057e57600080fd5b50610500610fe3565b34801561059357600080fd5b5061044f600480360360208110156105aa57600080fd5b50356001600160a01b0316610fe9565b3480156105c657600080fd5b506104d561103b565b3480156105db57600080fd5b506102fe611040565b3480156105f057600080fd5b5061060e6004803603602081101561060757600080fd5b5035611045565b604080516001600160a01b039788168152958716602087015293909516848401526001600160401b0390911660608401521515608083015260a082019290925290519081900360c00190f35b34801561066657600080fd5b506105006110a9565b34801561067b57600080fd5b506104d56110af565b34801561069057600080fd5b506105006110b4565b3480156106a557600080fd5b5061044f6110ba565b3480156106ba57600080fd5b506104d56110c0565b3480156106cf57600080fd5b506102fe6110c5565b3480156106e457600080fd5b506104a9600480360360408110156106fb57600080fd5b60ff8235169190810190604081016020820135600160201b81111561071f57600080fd5b82018360208201111561073157600080fd5b803590602001918460018302840111600160201b8311171561075257600080fd5b5090925090506110ca565b34801561076957600080fd5b5061044f61117d565b34801561077e57600080fd5b506104d5611183565b34801561079357600080fd5b50610500611188565b3480156107a857600080fd5b5061050061118e565b3480156107bd57600080fd5b5061039c611194565b3480156107d257600080fd5b506104266111b3565b3480156107e757600080fd5b5061044f6111bc565b3480156107fc57600080fd5b506102fe61103b565b34801561081157600080fd5b506104a96004803603604081101561082857600080fd5b810190602081018135600160201b81111561084257600080fd5b82018360208201111561085457600080fd5b803590602001918460018302840111600160201b8311171561087557600080fd5b919390929091602081019035600160201b81111561089257600080fd5b8201836020820111156108a457600080fd5b803590602001918460018302840111600160201b831117156108c557600080fd5b5090925090506111c5565b3480156108dc57600080fd5b5061044f600480360360208110156108f357600080fd5b50356001600160a01b03166115bc565b34801561090f57600080fd5b506109186115ce565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561095457818101518382015260200161093c565b505050509050019250505060405180910390f35b34801561097457600080fd5b506105006116f4565b34801561098957600080fd5b5061044f6116fa565b34801561099e57600080fd5b5061044f611706565b3480156109b357600080fd5b5061050061170c565b3480156109c857600080fd5b5061044f611712565b3480156109dd57600080fd5b506104a9611717565b3480156109f257600080fd5b506104a960048036036020811015610a0957600080fd5b50356001600160a01b031661191a565b348015610a2557600080fd5b506102fe611ae9565b6104a960048036036020811015610a4457600080fd5b50356001600160a01b0316611aee565b348015610a6057600080fd5b50610500611df3565b348015610a7557600080fd5b506104d5611df9565b348015610a8a57600080fd5b50610500611dfe565b348015610a9f57600080fd5b50610500611e04565b606481565b60005460609060ff16610b03576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b3361200014610b435760405162461bcd60e51b815260040180806020018281038252602f81526020018061450d602f913960400191505060405180910390fd5b610b4b614158565b6000610b8c85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611e0a92505050565b9150915080610ba857610b9f6064611f63565b92505050610c93565b815160009060ff16610bc857610bc18360200151611fc4565b9050610c5f565b825160ff1660011415610c5b57826020015151600114610c35577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb26040518080602001828103825260258152602001806144316025913960400191505060405180910390a1506067610c56565b610bc18360200151600081518110610c4957fe5b6020026020010151612dca565b610c5f565b5060655b63ffffffff8116610c845750506040805160008152602081019091529150610c939050565b610c8d81611f63565b93505050505b9392505050565b60075460ff1681565b60035481565b606881565b3361100114610cee5760405162461bcd60e51b81526004018080602001828103825260298152602001806145696029913960400191505060405180910390fd5b6001600160a01b03811660009081526004602052604090205480610d125750610fbf565b600181039050600060018281548110610d2757fe5b60009182526020909120600360049092020101546001549091506000190180610d7657600060018481548110610d5957fe5b906000526020600020906004020160030181905550505050610fbf565b6040805183815290516001600160a01b038616917f3b6f9ef90462b512a1293ecec018670bf7b7f1876fb727590a8a6d7643130a70919081900360200190a26001600160a01b038416600090815260046020526040812055600154600019018314610ef857600180546000198101908110610ded57fe5b906000526020600020906004020160018481548110610e0857fe5b6000918252602082208354600492830290910180546001600160a01b03199081166001600160a01b0393841617825560018087015481840180548416918616919091179055600280880180549185018054909416919095161780835584546001600160401b03600160a01b91829004160267ffffffffffffffff60a01b1990911617808355935460ff600160e01b918290041615150260ff60e01b199094169390931790556003948501549401939093558254868401939192919087908110610ecd57fe5b600091825260208083206004909202909101546001600160a01b031683528201929092526040019020555b6001805480610f0357fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b03191690556003018190559155818381610f5657fe5b0490508015610fba5760015460005b81811015610fb7578260018281548110610f7b57fe5b9060005260206000209060040201600301540160018281548110610f9b57fe5b6000918252602090912060036004909202010155600101610f65565b50505b505050505b50565b61271081565b600181565b61100181565b606181565b600881565b60065481565b61200081565b6001600160a01b03811660009081526004602052604081205480611011576000915050611036565b60018082038154811061102057fe5b9060005260206000209060040201600301549150505b919050565b600081565b606781565b6001818154811061105257fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509082169291821691600160a01b81046001600160401b031691600160e01b90910460ff169086565b61100581565b600281565b61100881565b6103e881565b600b81565b606681565b336120001461110a5760405162461bcd60e51b815260040180806020018281038252602f81526020018061450d602f913960400191505060405180910390fd5b7f41ce201247b6ceb957dcdb217d0b8acb50b9ea0e12af9af4f5e7f38902101605838383604051808460ff1660ff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b60025481565b600981565b61100781565b61100681565b604051806101e001604052806101ab81526020016141e06101ab913981565b60005460ff1681565b6402540be40081565b60005460ff16611218576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b33611007146112585760405162461bcd60e51b815260040180806020018281038252602e815260200180614477602e913960400191505060405180910390fd5b6112c284848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526013815272065787069726554696d655365636f6e6447617606c1b60208201529150612f419050565b1561139d57602081146113065760405162461bcd60e51b81526004018080602001828103825260268152602001806144c66026913960400191505060405180910390fd5b604080516020601f84018190048102820181019092528281526000916113449185858083850183828082843760009201919091525061302992505050565b90506064811015801561135a5750620186a08111155b6113955760405162461bcd60e51b815260040180806020018281038252602781526020018061440a6027913960400191505060405180910390fd5b60025561152a565b6113fd84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260098152686275726e526174696f60b81b60208201529150612f419050565b156114ed5760208114611457576040805162461bcd60e51b815260206004820152601c60248201527f6c656e677468206f66206275726e526174696f206d69736d6174636800000000604482015290519081900360640190fd5b604080516020601f84018190048102820181019092528281526000916114959185858083850183828082843760009201919091525061302992505050565b90506127108111156114d85760405162461bcd60e51b815260040180806020018281038252602b8152602001806143b4602b913960400191505060405180910390fd5b6006556007805460ff1916600117905561152a565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b60046020526000908152604090205481565b6001546060906000805b8281101561161f57600181815481106115ed57fe5b9060005260206000209060040201600201601c9054906101000a900460ff16611617576001909101905b6001016115d8565b5060608160405190808252806020026020018201604052801561164c578160200160208202803683370190505b50600092509050815b838110156116ec576001818154811061166a57fe5b9060005260206000209060040201600201601c9054906101000a900460ff166116e4576001818154811061169a57fe5b600091825260209091206004909102015482516001600160a01b03909116908390859081106116c557fe5b6001600160a01b03909216602092830291909101909101526001909201915b600101611655565b509250505090565b61100281565b67016345785d8a000081565b60055481565b61100381565b602981565b60005460ff161561176f576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b611777614158565b600061179d604051806101e001604052806101ab81526020016141e06101ab9139611e0a565b91509150806117dd5760405162461bcd60e51b81526004018080602001828103825260218152602001806144ec6021913960400191505060405180910390fd5b60005b826020015151811015611902576001836020015182815181106117ff57fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782558587015182850180549185169183169190911790556040860151600283018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590981692909516919091179290921694909417161790915560a0909301516003909301929092559186015180519185019391859081106118d557fe5b602090810291909101810151516001600160a01b03168252810191909152604001600020556001016117e0565b50506103e8600255506000805460ff19166001179055565b336110011461195a5760405162461bcd60e51b81526004018080602001828103825260298152602001806145696029913960400191505060405180910390fd5b6001600160a01b0381166000908152600460205260409020548061197e5750610fbf565b60018103905060006001828154811061199357fe5b90600052602060002090600402016003015490506000600183815481106119b657fe5b906000526020600020906004020160030181905550600060018080549050039050836001600160a01b03167f8cd4e147d8af98a9e3b6724021b8bf6aed2e5dac71c38f2dce8161b82585b25d836040518082815260200191505060405180910390a280611a2557505050610fbf565b6000818381611a3057fe5b0490508015610fba5760005b84811015611a8e578160018281548110611a5257fe5b9060005260206000209060040201600301540160018281548110611a7257fe5b6000918252602090912060036004909202010155600101611a3c565b50600180549085015b81811015610fb7578260018281548110611aad57fe5b9060005260206000209060040201600301540160018281548110611acd57fe5b6000918252602090912060036004909202010155600101611a97565b606581565b334114611b2c5760405162461bcd60e51b815260040180806020018281038252602d81526020018061453c602d913960400191505060405180910390fd5b60005460ff16611b7f576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b60003411611bcc576040805162461bcd60e51b81526020600482015260156024820152746465706f7369742076616c7565206973207a65726f60581b604482015290519081900360640190fd5b6001600160a01b0381166000908152600460205260409020546007543491906103e89060ff1615611bfc57506006545b600083118015611c0c5750600081115b15611cb5576000611c35612710611c29868563ffffffff61302e16565b9063ffffffff61308716565b90508015611cb35760405161dead9082156108fc029083906000818181858888f19350505050158015611c6c573d6000803e3d6000fd5b506040805182815290517f627059660ea01c4733a328effb2294d2f86905bf806da763a89cee254de8bee59181900360200190a1611cb0848263ffffffff6130c916565b93505b505b8115611dad576000600180840381548110611ccc57fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff1615611d37576040805185815290516001600160a01b038716917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a2611da7565b600354611d4a908563ffffffff61310b16565b6003908155810154611d62908563ffffffff61310b16565b60038201556040805185815290516001600160a01b038716917f93a090ecc682c002995fad3c85b30c5651d7fd29b0be5da9d784a3302aedc055919081900360200190a25b50611ded565b6040805184815290516001600160a01b038616917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a25b50505050565b61100081565b600381565b61dead81565b61100481565b611e12614158565b6000611e1c614158565b611e24614170565b611e35611e3086613165565b61318a565b90506000805b611e44836131d4565b15611f555780611e6957611e5f611e5a846131f5565b613243565b60ff168452611f4d565b8060011415611f48576060611e85611e80856131f5565b6132fa565b90508051604051908082528060200260200182016040528015611ec257816020015b611eaf614190565b815260200190600190039081611ea75790505b50602086015260005b8151811015611f3d57611edc614190565b6000611efa848481518110611eed57fe5b60200260200101516133cb565b9150915080611f1757876000995099505050505050505050611f5e565b8188602001518481518110611f2857fe5b60209081029190910101525050600101611ecb565b506001925050611f4d565b611f55565b600101611e3b565b50919350909150505b915091565b604080516001808252818301909252606091829190816020015b6060815260200190600190039081611f7d579050509050611fa38363ffffffff166134a8565b81600081518110611fb057fe5b6020026020010181905250610c93816134bb565b6000806060611fd284613545565b915091508161207f577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2816040518080602001828103825283818151815260200191508051906020019080838360005b8381101561203a578181015183820152602001612022565b50505050905090810190601f1680156120675780820380516001836020036101000a031916815260200191505b509250505060405180910390a1606692505050611036565b600080805b6001548110156120fc5767016345785d8a0000600182815481106120a457fe5b906000526020600020906004020160030154106120c6576001909201916120f4565b6000600182815481106120d557fe5b90600052602060002090600402016003015411156120f4576001909101905b600101612084565b50606082604051908082528060200260200182016040528015612129578160200160208202803683370190505b509050606083604051908082528060200260200182016040528015612158578160200160208202803683370190505b509050606084604051908082528060200260200182016040528015612187578160200160208202803683370190505b5090506060856040519080825280602002602001820160405280156121b6578160200160208202803683370190505b50905060006060866040519080825280602002602001820160405280156121e7578160200160208202803683370190505b509050606087604051908082528060200260200182016040528015612216578160200160208202803683370190505b509050600098506000975060608d905060006110046001600160a01b031663149d14d96040518163ffffffff1660e01b815260040160206040518083038186803b15801561226357600080fd5b505afa158015612277573d6000803e3d6000fd5b505050506040513d602081101561228d57600080fd5b5051905067016345785d8a0000811115612302577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb26040518080602001828103825260218152602001806144a56021913960400191505060405180910390a160689d5050505050505050505050505050611036565b60005b6001548110156125755767016345785d8a00006001828154811061232557fe5b906000526020600020906004020160030154106124ab576001818154811061234957fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b03168a8d8151811061237a57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006402540be400600183815481106123af57fe5b906000526020600020906004020160030154816123c857fe5b06600183815481106123d657fe5b9060005260206000209060040201600301540390506123fe83826130c990919063ffffffff16565b8a8e8151811061240a57fe5b6020026020010181815250506001828154811061242357fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316888e8151811061245457fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081898e8151811061248157fe5b602090810291909101015261249c878263ffffffff61310b16565b6001909d019c965061256d9050565b6000600182815481106124ba57fe5b906000526020600020906004020160030154111561256d57600181815481106124df57fe5b906000526020600020906004020160010160009054906101000a90046001600160a01b0316858c8151811061251057fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001818154811061253d57fe5b906000526020600020906004020160030154848c8151811061255b57fe5b60209081029190910101526001909a01995b600101612305565b50600085156129b3576110046001600160a01b0316636e056520878c8c8b60025442016040518663ffffffff1660e01b815260040180806020018060200180602001856001600160401b03166001600160401b03168152602001848103845288818151815260200191508051906020019060200280838360005b838110156126075781810151838201526020016125ef565b50505050905001848103835287818151815260200191508051906020019060200280838360005b8381101561264657818101518382015260200161262e565b50505050905001848103825286818151815260200191508051906020019060200280838360005b8381101561268557818101518382015260200161266d565b505050509050019750505050505050506020604051808303818588803b1580156126ae57600080fd5b505af1935050505080156126d457506040513d60208110156126cf57600080fd5b505160015b61290f576040516000815260443d10156126f05750600061278b565b60046000803e60005160e01c6308c379a0811461271157600091505061278b565b60043d036004833e81513d60248201116001600160401b038211171561273c5760009250505061278b565b80830180516001600160401b0381111561275d57600094505050505061278b565b8060208301013d860181111561277b5760009550505050505061278b565b601f01601f191660405250925050505b80612796575061283a565b60019150867fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280826040518080602001828103825283818151815260200191508051906020019080838360005b838110156127fa5781810151838201526020016127e2565b50505050905090810190601f1680156128275780820380516001836020036101000a031916815260200191505b509250505060405180910390a25061290a565b3d808015612864576040519150601f19603f3d011682016040523d82523d6000602084013e612869565b606091505b5060019150867fbfa884552dd8921b6ce90bfe906952ae5b3b29be0cc1a951d4f62697635a3a45826040518080602001828103825283818151815260200191508051906020019080838360005b838110156128ce5781810151838201526020016128b6565b50505050905090810190601f1680156128fb5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505b6129b3565b801561294d576040805188815290517fa217d08e65f80c73121cd9db834d81652d544bfbf452f6d04922b16c90a37b709181900360200190a16129b1565b604080516020808252601b908201527f6261746368207472616e736665722072657475726e2066616c7365000000000081830152905188917fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280919081900360600190a25b505b8015612b695760005b8851811015612b675760008982815181106129d357fe5b602002602001015190506000600182815481106129ec57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116916108fc9185908110612a1d57fe5b9060005260206000209060040201600301549081150290604051600060405180830381858888f1935050505090508015612ad95760018281548110612a5e57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d9185908110612aad57fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a2612b5d565b60018281548110612ae657fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d9185908110612b3557fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a25b50506001016129bc565b505b845115612cb35760005b8551811015612cb1576000868281518110612b8a57fe5b60200260200101516001600160a01b03166108fc878481518110612baa57fe5b60200260200101519081150290604051600060405180830381858888f1935050505090508015612c4057868281518110612be057fe5b60200260200101516001600160a01b03167f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d878481518110612c1e57fe5b60200260200101516040518082815260200191505060405180910390a2612ca8565b868281518110612c4c57fe5b60200260200101516001600160a01b03167f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d878481518110612c8a57fe5b60200260200101516040518082815260200191505060405180910390a25b50600101612b73565b505b4715612d1c576040805147815290517f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d9181900360200190a1604051611002904780156108fc02916000818181858888f19350505050158015612d1a573d6000803e3d6000fd5b505b60006003819055600555825115612d3657612d3683613627565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d7357600080fd5b505af1158015612d87573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a15060009f9e505050505050505050505050505050565b80516001600160a01b0316600090815260046020526040812054801580612e1b5750600180820381548110612dfb57fe5b9060005260206000209060040201600201601c9054906101000a900460ff165b15612e615782516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a26000915050611036565b600154600554600019820111801590612eb75784516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a260009350505050611036565b600580546001908101909155805481906000198601908110612ed557fe5b6000918252602082206002600490920201018054921515600160e01b0260ff60e01b199093169290921790915585516040516001600160a01b03909116917ff226e7d8f547ff903d9d419cf5f54e0d7d07efa9584135a53a057c5f1f27f49a91a2506000949350505050565b6000816040516020018082805190602001908083835b60208310612f765780518252601f199092019160209182019101612f57565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b60208310612fe45780518252601f199092019160209182019101612fc5565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201490505b92915050565b015190565b60008261303d57506000613023565b8282028284828161304a57fe5b0414610c935760405162461bcd60e51b81526004018080602001828103825260218152602001806144566021913960400191505060405180910390fd5b6000610c9383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ae8565b6000610c9383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b8a565b600082820183811015610c93576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b61316d6141c5565b506040805180820190915281518152602082810190820152919050565b613192614170565b61319b82613be4565b6131a457600080fd5b60006131b38360200151613c1e565b60208085015160408051808201909152868152920190820152915050919050565b60006131de6141c5565b505080518051602091820151919092015191011190565b6131fd6141c5565b613206826131d4565b61320f57600080fd5b6020820151600061321f82613c81565b80830160209586015260408051808201909152908152938401919091525090919050565b80516000901580159061325857508151602110155b61326157600080fd5b60006132708360200151613c1e565b905080836000015110156132cb576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b8251602080850151830180519284900392918310156132f157826020036101000a820491505b50949350505050565b606061330582613be4565b61330e57600080fd5b600061331983613db4565b905060608160405190808252806020026020018201604052801561335757816020015b6133446141c5565b81526020019060019003908161333c5790505b50905060006133698560200151613c1e565b60208601510190506000805b848110156133c05761338683613c81565b91506040518060400160405280838152602001848152508482815181106133a957fe5b602090810291909101015291810191600101613375565b509195945050505050565b6133d3614190565b60006133dd614190565b6133e5614170565b6133ee8561318a565b90506000805b6133fd836131d4565b15611f55578061342857613418613413846131f5565b613e10565b6001600160a01b031684526134a0565b80600114156134505761343d613413846131f5565b6001600160a01b031660208501526134a0565b806002141561347857613465613413846131f5565b6001600160a01b031660408501526134a0565b8060031415611f485761348d611e5a846131f5565b6001600160401b03166060850152600191505b6001016133f4565b60606130236134b683613e2a565b613f10565b60608151600014156134dc5750604080516000815260208101909152611036565b6060826000815181106134eb57fe5b602002602001015190506000600190505b835181101561352c576135228285838151811061351557fe5b6020026020010151613f62565b91506001016134fc565b50610c9361353f825160c060ff16613fdf565b82613f62565b6000606060298351111561357757600060405180606001604052806029815260200161438b6029913991509150611f5e565b60005b835181101561360d5760005b818110156136045784818151811061359a57fe5b6020026020010151600001516001600160a01b03168583815181106135bb57fe5b6020026020010151600001516001600160a01b031614156135fc5760006040518060600160405280602b81526020016143df602b9139935093505050611f5e565b600101613586565b5060010161357a565b505060408051602081019091526000815260019150915091565b600154815160005b82811015613744576001613641614190565b6001838154811061364e57fe5b600091825260208083206040805160c08101825260049490940290910180546001600160a01b0390811685526001820154811693850193909352600281015492831691840191909152600160a01b82046001600160401b03166060840152600160e01b90910460ff16151560808301526003015460a082015291505b84811015613718578681815181106136de57fe5b6020026020010151600001516001600160a01b031682600001516001600160a01b031614156137105760009250613718565b6001016136ca565b50811561373a5780516001600160a01b03166000908152600460205260408120555b505060010161362f565b50808211156137b957805b828110156137b757600180548061376257fe5b60008281526020812060046000199093019283020180546001600160a01b03199081168255600182810180549092169091556002820180546001600160e81b031916905560039091019190915591550161374f565b505b60008183106137c857816137ca565b825b905060005b818110156139c45761387c8582815181106137e657fe5b6020026020010151600183815481106137fb57fe5b60009182526020918290206040805160c08101825260049390930290910180546001600160a01b0390811684526001820154811694840194909452600281015493841691830191909152600160a01b83046001600160401b03166060830152600160e01b90920460ff161515608082015260039091015460a08201526140d7565b61399757806001016004600087848151811061389457fe5b6020026020010151600001516001600160a01b03166001600160a01b03168152602001908152602001600020819055508481815181106138d057fe5b6020026020010151600182815481106138e557fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a0909101516003909101556139bc565b6000600182815481106139a657fe5b9060005260206000209060040201600301819055505b6001016137cf565b5082821115611ded57825b82811015610fba5760018582815181106139e557fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782559585015181840180549184169188169190911790556040850151600282018054606088015160808901511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590971692909a169190911792909216939093171695909517905560a09092015160039093019290925587519084019290889085908110613abb57fe5b602090810291909101810151516001600160a01b03168252810191909152604001600020556001016139cf565b60008183613b745760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613b39578181015183820152602001613b21565b50505050905090810190601f168015613b665780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613b8057fe5b0495945050505050565b60008184841115613bdc5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613b39578181015183820152602001613b21565b505050900390565b8051600090613bf557506000611036565b6020820151805160001a9060c0821015613c1457600092505050611036565b5060019392505050565b8051600090811a6080811015613c38576000915050611036565b60b8811080613c53575060c08110801590613c53575060f881105b15613c62576001915050611036565b60c0811015613c765760b519019050611036565b60f519019050611036565b80516000908190811a6080811015613c9c5760019150613dad565b60b8811015613cb157607e1981019150613dad565b60c0811015613d2b57600060b78203600186019550806020036101000a865104915060018101820193505080831015613d25576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b50613dad565b60f8811015613d405760be1981019150613dad565b600060f78203600186019550806020036101000a865104915060018101820193505080831015613dab576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b8051600090613dc557506000611036565b60008090506000613dd98460200151613c1e565b602085015185519181019250015b80821015613e0757613df882613c81565b60019093019290910190613de7565b50909392505050565b8051600090601514613e2157600080fd5b61302382613243565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff198416613e6e57506018613e92565b6fffffffffffffffffffffffffffffffff198416613e8e57506010613e92565b5060005b6020811015613ec857818181518110613ea757fe5b01602001516001600160f81b03191615613ec057613ec8565b600101613e92565b60008160200390506060816040519080825280601f01601f191660200182016040528015613efd576020820181803683370190505b5080830196909652508452509192915050565b606081516001148015613f425750607f60f81b82600081518110613f3057fe5b01602001516001600160f81b03191611155b15613f4e575080611036565b613023613f608351608060ff16613fdf565b835b6060806040519050835180825260208201818101602087015b81831015613f93578051835260209283019201613f7b565b50855184518101855292509050808201602086015b81831015613fc0578051835260209283019201613fa8565b508651929092011591909101601f01601f191660405250905092915050565b606068010000000000000000831061402f576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116140895782840160f81b8160008151811061406b57fe5b60200101906001600160f81b031916908160001a9053509050613023565b606061409485613e2a565b90508381510160370160f81b826000815181106140ad57fe5b60200101906001600160f81b031916908160001a9053506140ce8282613f62565b95945050505050565b805182516000916001600160a01b039182169116148015614111575081602001516001600160a01b031683602001516001600160a01b0316145b8015614136575081604001516001600160a01b031683604001516001600160a01b0316145b8015610c935750506060908101519101516001600160401b0390811691161490565b60408051808201909152600081526060602082015290565b60405180604001604052806141836141c5565b8152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60405180604001604052806000815260200160008152509056fef901a880f901a4f844941284214b9b9c85549ab3d2b972df0deef66ac2c9946ddf42a51534fc98d0c0a3b42c963cace8441ddf946ddf42a51534fc98d0c0a3b42c963cace8441ddf8410000000f84494a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0948081ef03f1d9e0bb4a5bf38f16285c879299f07f948081ef03f1d9e0bb4a5bf38f16285c879299f07f8410000000f8449435552c16704d214347f29fa77f77da6d75d7c75294dc4973e838e3949c77aced16ac2315dc2d7ab11194dc4973e838e3949c77aced16ac2315dc2d7ab1118410000000f84494980a75ecd1309ea12fa2ed87a8744fbfc9b863d594cc6ac05c95a99c1f7b5f88de0e3486c82293b27094cc6ac05c95a99c1f7b5f88de0e3486c82293b2708410000000f84494f474cf03cceff28abc65c9cbae594f725c80e12d94e61a183325a18a173319dd8e19c8d069459e217594e61a183325a18a173319dd8e19c8d069459e21758410000000f84494b71b214cb885500844365e95cd9942c7276e7fd894d22ca3ba2141d23adab65ce4940eb7665ea2b6a794d22ca3ba2141d23adab65ce4940eb7665ea2b6a78410000000746865206e756d626572206f662076616c696461746f72732065786365656420746865206c696d6974746865206275726e526174696f206d757374206265206e6f2067726561746572207468616e2031303030306475706c696361746520636f6e73656e7375732061646472657373206f662076616c696461746f725365747468652065787069726554696d655365636f6e64476170206973206f7574206f662072616e67656c656e677468206f66206a61696c2076616c696461746f7273206d757374206265206f6e65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374666565206973206c6172676572207468616e2044555354595f494e434f4d494e476c656e677468206f662065787069726554696d655365636f6e64476170206d69736d617463686661696c656420746f20706172736520696e69742076616c696461746f72536574746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f6475636572746865206d6573736167652073656e646572206d75737420626520736c61736820636f6e7472616374a26469706673582212206138cbef6a4ba7db6b97f06990dc0d96f124bc0b841fa4a56690968e7b85982b64736f6c63430006040033", + }, + }, + } + + brunoUpgrade[rialtoNet] = &Upgrade{ + UpgradeName: "bruno", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(ValidatorContract), + CommitUrl: "https://github.com/binance-chain/bsc-genesis-contract/commit/ce622fef469d84ee418fa6181f3ac962412a5f4f", + Code: "6080604052600436106102e45760003560e01c80638624988211610190578063c8509d81116100dc578063eb57e20211610095578063f9a2bbc71161006f578063f9a2bbc714610a54578063fc3e590814610a69578063fccc281314610a7e578063fd6a687914610a93576102e4565b8063eb57e202146109e6578063eda5868c14610a19578063f340fa0114610a2e576102e4565b8063c8509d81146106d8578063d86222d51461097d578063daacdb6614610992578063dc927faf146109a7578063e086c7b1146109bc578063e1c7392a146109d1576102e4565b8063aaf5eb6811610149578063ad3c9da611610123578063ad3c9da6146108d0578063b7ab4db514610903578063bf9f4995146104c0578063c81b166214610968576102e4565b8063aaf5eb68146107db578063ab51bb96146107f0578063ac43175114610805576102e4565b8063862498821461075d57806396713da9146107725780639dc0926214610787578063a1a11bf51461079c578063a5422d5c146107b1578063a78abc16146107c6576102e4565b806351e806721161024f57806370fd5bad116102085780637942fd05116101e25780637942fd05146106ae57806381650b62146106c3578063831d65d1146106d8578063853230aa14610699576102e4565b806370fd5bad1461066f57806375d47a0a1461068457806378dfed4a14610699576102e4565b806351e8067214610572578063565c56b3146105875780635667515a146105ba5780635d77156c146105cf5780636969a25c146105e45780636e47b4821461065a576102e4565b80633de0f0d8116102a15780633de0f0d8146104ab5780633dffc387146104c057806343756e5c146104eb578063493279b11461051c5780634bf6c882146105485780635192c82c1461055d576102e4565b80630bee7a67146102e95780631182b87514610317578063152ad3b8146104115780631ff180691461043a578063219f22d51461046157806335409f7f14610476575b600080fd5b3480156102f557600080fd5b506102fe610aa8565b6040805163ffffffff9092168252519081900360200190f35b34801561032357600080fd5b5061039c6004803603604081101561033a57600080fd5b60ff8235169190810190604081016020820135600160201b81111561035e57600080fd5b82018360208201111561037057600080fd5b803590602001918460018302840111600160201b8311171561039157600080fd5b509092509050610aad565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103d65781810151838201526020016103be565b50505050905090810190601f1680156104035780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041d57600080fd5b50610426610c9a565b604080519115158252519081900360200190f35b34801561044657600080fd5b5061044f610ca3565b60408051918252519081900360200190f35b34801561046d57600080fd5b506102fe610ca9565b34801561048257600080fd5b506104a96004803603602081101561049957600080fd5b50356001600160a01b0316610cae565b005b3480156104b757600080fd5b5061044f610fc2565b3480156104cc57600080fd5b506104d5610fc8565b6040805160ff9092168252519081900360200190f35b3480156104f757600080fd5b50610500610fcd565b604080516001600160a01b039092168252519081900360200190f35b34801561052857600080fd5b50610531610fd3565b6040805161ffff9092168252519081900360200190f35b34801561055457600080fd5b506104d5610fd9565b34801561056957600080fd5b5061044f610fde565b34801561057e57600080fd5b50610500610fe4565b34801561059357600080fd5b5061044f600480360360208110156105aa57600080fd5b50356001600160a01b0316610fea565b3480156105c657600080fd5b506104d561103c565b3480156105db57600080fd5b506102fe611041565b3480156105f057600080fd5b5061060e6004803603602081101561060757600080fd5b5035611046565b604080516001600160a01b039788168152958716602087015293909516848401526001600160401b0390911660608401521515608083015260a082019290925290519081900360c00190f35b34801561066657600080fd5b506105006110aa565b34801561067b57600080fd5b506104d56110b0565b34801561069057600080fd5b506105006110b5565b3480156106a557600080fd5b5061044f6110bb565b3480156106ba57600080fd5b506104d56110c1565b3480156106cf57600080fd5b506102fe6110c6565b3480156106e457600080fd5b506104a9600480360360408110156106fb57600080fd5b60ff8235169190810190604081016020820135600160201b81111561071f57600080fd5b82018360208201111561073157600080fd5b803590602001918460018302840111600160201b8311171561075257600080fd5b5090925090506110cb565b34801561076957600080fd5b5061044f61117e565b34801561077e57600080fd5b506104d5611184565b34801561079357600080fd5b50610500611189565b3480156107a857600080fd5b5061050061118f565b3480156107bd57600080fd5b5061039c611195565b3480156107d257600080fd5b506104266111b4565b3480156107e757600080fd5b5061044f6111bd565b3480156107fc57600080fd5b506102fe61103c565b34801561081157600080fd5b506104a96004803603604081101561082857600080fd5b810190602081018135600160201b81111561084257600080fd5b82018360208201111561085457600080fd5b803590602001918460018302840111600160201b8311171561087557600080fd5b919390929091602081019035600160201b81111561089257600080fd5b8201836020820111156108a457600080fd5b803590602001918460018302840111600160201b831117156108c557600080fd5b5090925090506111c6565b3480156108dc57600080fd5b5061044f600480360360208110156108f357600080fd5b50356001600160a01b03166115bd565b34801561090f57600080fd5b506109186115cf565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561095457818101518382015260200161093c565b505050509050019250505060405180910390f35b34801561097457600080fd5b506105006116f5565b34801561098957600080fd5b5061044f6116fb565b34801561099e57600080fd5b5061044f611707565b3480156109b357600080fd5b5061050061170d565b3480156109c857600080fd5b5061044f611713565b3480156109dd57600080fd5b506104a9611718565b3480156109f257600080fd5b506104a960048036036020811015610a0957600080fd5b50356001600160a01b031661191b565b348015610a2557600080fd5b506102fe611aea565b6104a960048036036020811015610a4457600080fd5b50356001600160a01b0316611aef565b348015610a6057600080fd5b50610500611df4565b348015610a7557600080fd5b506104d5611dfa565b348015610a8a57600080fd5b50610500611dff565b348015610a9f57600080fd5b50610500611e05565b606481565b60005460609060ff16610b03576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b3361200014610b435760405162461bcd60e51b815260040180806020018281038252602f815260200180614952602f913960400191505060405180910390fd5b610b4b614159565b6000610b8c85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611e0b92505050565b9150915080610ba857610b9f6064611f64565b92505050610c93565b815160009060ff16610bc857610bc18360200151611fc5565b9050610c5f565b825160ff1660011415610c5b57826020015151600114610c35577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb26040518080602001828103825260258152602001806142876025913960400191505060405180910390a1506067610c56565b610bc18360200151600081518110610c4957fe5b6020026020010151612dcb565b610c5f565b5060655b63ffffffff8116610c845750506040805160008152602081019091529150610c939050565b610c8d81611f64565b93505050505b9392505050565b60075460ff1681565b60035481565b606881565b3361100114610cee5760405162461bcd60e51b81526004018080602001828103825260298152602001806149ae6029913960400191505060405180910390fd5b6001600160a01b03811660009081526004602052604090205480610d125750610fbf565b600181039050600060018281548110610d2757fe5b60009182526020909120600360049092020101546001549091506000190180610d7657600060018481548110610d5957fe5b906000526020600020906004020160030181905550505050610fbf565b6040805183815290516001600160a01b038616917f3b6f9ef90462b512a1293ecec018670bf7b7f1876fb727590a8a6d7643130a70919081900360200190a26001600160a01b038416600090815260046020526040812055600154600019018314610ef857600180546000198101908110610ded57fe5b906000526020600020906004020160018481548110610e0857fe5b6000918252602082208354600492830290910180546001600160a01b03199081166001600160a01b0393841617825560018087015481840180548416918616919091179055600280880180549185018054909416919095161780835584546001600160401b03600160a01b91829004160267ffffffffffffffff60a01b1990911617808355935460ff600160e01b918290041615150260ff60e01b199094169390931790556003948501549401939093558254868401939192919087908110610ecd57fe5b600091825260208083206004909202909101546001600160a01b031683528201929092526040019020555b6001805480610f0357fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b03191690556003018190559155818381610f5657fe5b0490508015610fba5760015460005b81811015610fb7578260018281548110610f7b57fe5b9060005260206000209060040201600301540160018281548110610f9b57fe5b6000918252602090912060036004909202010155600101610f65565b50505b505050505b50565b61271081565b600181565b61100181565b6102ca81565b600881565b60065481565b61200081565b6001600160a01b03811660009081526004602052604081205480611012576000915050611037565b60018082038154811061102157fe5b9060005260206000209060040201600301549150505b919050565b600081565b606781565b6001818154811061105357fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509082169291821691600160a01b81046001600160401b031691600160e01b90910460ff169086565b61100581565b600281565b61100881565b6103e881565b600b81565b606681565b336120001461110b5760405162461bcd60e51b815260040180806020018281038252602f815260200180614952602f913960400191505060405180910390fd5b7f41ce201247b6ceb957dcdb217d0b8acb50b9ea0e12af9af4f5e7f38902101605838383604051808460ff1660ff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b60025481565b600981565b61100781565b61100681565b6040518061062001604052806105ef81526020016143636105ef913981565b60005460ff1681565b6402540be40081565b60005460ff16611219576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b33611007146112595760405162461bcd60e51b815260040180806020018281038252602e8152602001806142cd602e913960400191505060405180910390fd5b6112c384848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526013815272065787069726554696d655365636f6e6447617606c1b60208201529150612f429050565b1561139e57602081146113075760405162461bcd60e51b815260040180806020018281038252602681526020018061431c6026913960400191505060405180910390fd5b604080516020601f84018190048102820181019092528281526000916113459185858083850183828082843760009201919091525061302a92505050565b90506064811015801561135b5750620186a08111155b6113965760405162461bcd60e51b81526004018080602001828103825260278152602001806142606027913960400191505060405180910390fd5b60025561152b565b6113fe84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260098152686275726e526174696f60b81b60208201529150612f429050565b156114ee5760208114611458576040805162461bcd60e51b815260206004820152601c60248201527f6c656e677468206f66206275726e526174696f206d69736d6174636800000000604482015290519081900360640190fd5b604080516020601f84018190048102820181019092528281526000916114969185858083850183828082843760009201919091525061302a92505050565b90506127108111156114d95760405162461bcd60e51b815260040180806020018281038252602b81526020018061420a602b913960400191505060405180910390fd5b6006556007805460ff1916600117905561152b565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b60046020526000908152604090205481565b6001546060906000805b8281101561162057600181815481106115ee57fe5b9060005260206000209060040201600201601c9054906101000a900460ff16611618576001909101905b6001016115d9565b5060608160405190808252806020026020018201604052801561164d578160200160208202803683370190505b50600092509050815b838110156116ed576001818154811061166b57fe5b9060005260206000209060040201600201601c9054906101000a900460ff166116e5576001818154811061169b57fe5b600091825260209091206004909102015482516001600160a01b03909116908390859081106116c657fe5b6001600160a01b03909216602092830291909101909101526001909201915b600101611656565b509250505090565b61100281565b67016345785d8a000081565b60055481565b61100381565b602981565b60005460ff1615611770576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b611778614159565b600061179e6040518061062001604052806105ef81526020016143636105ef9139611e0b565b91509150806117de5760405162461bcd60e51b81526004018080602001828103825260218152602001806143426021913960400191505060405180910390fd5b60005b8260200151518110156119035760018360200151828151811061180057fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782558587015182850180549185169183169190911790556040860151600283018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590981692909516919091179290921694909417161790915560a0909301516003909301929092559186015180519185019391859081106118d657fe5b602090810291909101810151516001600160a01b03168252810191909152604001600020556001016117e1565b50506103e8600255506000805460ff19166001179055565b336110011461195b5760405162461bcd60e51b81526004018080602001828103825260298152602001806149ae6029913960400191505060405180910390fd5b6001600160a01b0381166000908152600460205260409020548061197f5750610fbf565b60018103905060006001828154811061199457fe5b90600052602060002090600402016003015490506000600183815481106119b757fe5b906000526020600020906004020160030181905550600060018080549050039050836001600160a01b03167f8cd4e147d8af98a9e3b6724021b8bf6aed2e5dac71c38f2dce8161b82585b25d836040518082815260200191505060405180910390a280611a2657505050610fbf565b6000818381611a3157fe5b0490508015610fba5760005b84811015611a8f578160018281548110611a5357fe5b9060005260206000209060040201600301540160018281548110611a7357fe5b6000918252602090912060036004909202010155600101611a3d565b50600180549085015b81811015610fb7578260018281548110611aae57fe5b9060005260206000209060040201600301540160018281548110611ace57fe5b6000918252602090912060036004909202010155600101611a98565b606581565b334114611b2d5760405162461bcd60e51b815260040180806020018281038252602d815260200180614981602d913960400191505060405180910390fd5b60005460ff16611b80576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b60003411611bcd576040805162461bcd60e51b81526020600482015260156024820152746465706f7369742076616c7565206973207a65726f60581b604482015290519081900360640190fd5b6001600160a01b0381166000908152600460205260409020546007543491906103e89060ff1615611bfd57506006545b600083118015611c0d5750600081115b15611cb6576000611c36612710611c2a868563ffffffff61302f16565b9063ffffffff61308816565b90508015611cb45760405161dead9082156108fc029083906000818181858888f19350505050158015611c6d573d6000803e3d6000fd5b506040805182815290517f627059660ea01c4733a328effb2294d2f86905bf806da763a89cee254de8bee59181900360200190a1611cb1848263ffffffff6130ca16565b93505b505b8115611dae576000600180840381548110611ccd57fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff1615611d38576040805185815290516001600160a01b038716917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a2611da8565b600354611d4b908563ffffffff61310c16565b6003908155810154611d63908563ffffffff61310c16565b60038201556040805185815290516001600160a01b038716917f93a090ecc682c002995fad3c85b30c5651d7fd29b0be5da9d784a3302aedc055919081900360200190a25b50611dee565b6040805184815290516001600160a01b038616917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a25b50505050565b61100081565b600381565b61dead81565b61100481565b611e13614159565b6000611e1d614159565b611e25614171565b611e36611e3186613166565b61318b565b90506000805b611e45836131d5565b15611f565780611e6a57611e60611e5b846131f6565b613244565b60ff168452611f4e565b8060011415611f49576060611e86611e81856131f6565b6132fb565b90508051604051908082528060200260200182016040528015611ec357816020015b611eb0614191565b815260200190600190039081611ea85790505b50602086015260005b8151811015611f3e57611edd614191565b6000611efb848481518110611eee57fe5b60200260200101516133cc565b9150915080611f1857876000995099505050505050505050611f5f565b8188602001518481518110611f2957fe5b60209081029190910101525050600101611ecc565b506001925050611f4e565b611f56565b600101611e3c565b50919350909150505b915091565b604080516001808252818301909252606091829190816020015b6060815260200190600190039081611f7e579050509050611fa48363ffffffff166134a9565b81600081518110611fb157fe5b6020026020010181905250610c93816134bc565b6000806060611fd384613546565b9150915081612080577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2816040518080602001828103825283818151815260200191508051906020019080838360005b8381101561203b578181015183820152602001612023565b50505050905090810190601f1680156120685780820380516001836020036101000a031916815260200191505b509250505060405180910390a1606692505050611037565b600080805b6001548110156120fd5767016345785d8a0000600182815481106120a557fe5b906000526020600020906004020160030154106120c7576001909201916120f5565b6000600182815481106120d657fe5b90600052602060002090600402016003015411156120f5576001909101905b600101612085565b5060608260405190808252806020026020018201604052801561212a578160200160208202803683370190505b509050606083604051908082528060200260200182016040528015612159578160200160208202803683370190505b509050606084604051908082528060200260200182016040528015612188578160200160208202803683370190505b5090506060856040519080825280602002602001820160405280156121b7578160200160208202803683370190505b50905060006060866040519080825280602002602001820160405280156121e8578160200160208202803683370190505b509050606087604051908082528060200260200182016040528015612217578160200160208202803683370190505b509050600098506000975060608d905060006110046001600160a01b031663149d14d96040518163ffffffff1660e01b815260040160206040518083038186803b15801561226457600080fd5b505afa158015612278573d6000803e3d6000fd5b505050506040513d602081101561228e57600080fd5b5051905067016345785d8a0000811115612303577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb26040518080602001828103825260218152602001806142fb6021913960400191505060405180910390a160689d5050505050505050505050505050611037565b60005b6001548110156125765767016345785d8a00006001828154811061232657fe5b906000526020600020906004020160030154106124ac576001818154811061234a57fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b03168a8d8151811061237b57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006402540be400600183815481106123b057fe5b906000526020600020906004020160030154816123c957fe5b06600183815481106123d757fe5b9060005260206000209060040201600301540390506123ff83826130ca90919063ffffffff16565b8a8e8151811061240b57fe5b6020026020010181815250506001828154811061242457fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316888e8151811061245557fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081898e8151811061248257fe5b602090810291909101015261249d878263ffffffff61310c16565b6001909d019c965061256e9050565b6000600182815481106124bb57fe5b906000526020600020906004020160030154111561256e57600181815481106124e057fe5b906000526020600020906004020160010160009054906101000a90046001600160a01b0316858c8151811061251157fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001818154811061253e57fe5b906000526020600020906004020160030154848c8151811061255c57fe5b60209081029190910101526001909a01995b600101612306565b50600085156129b4576110046001600160a01b0316636e056520878c8c8b60025442016040518663ffffffff1660e01b815260040180806020018060200180602001856001600160401b03166001600160401b03168152602001848103845288818151815260200191508051906020019060200280838360005b838110156126085781810151838201526020016125f0565b50505050905001848103835287818151815260200191508051906020019060200280838360005b8381101561264757818101518382015260200161262f565b50505050905001848103825286818151815260200191508051906020019060200280838360005b8381101561268657818101518382015260200161266e565b505050509050019750505050505050506020604051808303818588803b1580156126af57600080fd5b505af1935050505080156126d557506040513d60208110156126d057600080fd5b505160015b612910576040516000815260443d10156126f15750600061278c565b60046000803e60005160e01c6308c379a0811461271257600091505061278c565b60043d036004833e81513d60248201116001600160401b038211171561273d5760009250505061278c565b80830180516001600160401b0381111561275e57600094505050505061278c565b8060208301013d860181111561277c5760009550505050505061278c565b601f01601f191660405250925050505b80612797575061283b565b60019150867fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280826040518080602001828103825283818151815260200191508051906020019080838360005b838110156127fb5781810151838201526020016127e3565b50505050905090810190601f1680156128285780820380516001836020036101000a031916815260200191505b509250505060405180910390a25061290b565b3d808015612865576040519150601f19603f3d011682016040523d82523d6000602084013e61286a565b606091505b5060019150867fbfa884552dd8921b6ce90bfe906952ae5b3b29be0cc1a951d4f62697635a3a45826040518080602001828103825283818151815260200191508051906020019080838360005b838110156128cf5781810151838201526020016128b7565b50505050905090810190601f1680156128fc5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505b6129b4565b801561294e576040805188815290517fa217d08e65f80c73121cd9db834d81652d544bfbf452f6d04922b16c90a37b709181900360200190a16129b2565b604080516020808252601b908201527f6261746368207472616e736665722072657475726e2066616c7365000000000081830152905188917fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280919081900360600190a25b505b8015612b6a5760005b8851811015612b685760008982815181106129d457fe5b602002602001015190506000600182815481106129ed57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116916108fc9185908110612a1e57fe5b9060005260206000209060040201600301549081150290604051600060405180830381858888f1935050505090508015612ada5760018281548110612a5f57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d9185908110612aae57fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a2612b5e565b60018281548110612ae757fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d9185908110612b3657fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a25b50506001016129bd565b505b845115612cb45760005b8551811015612cb2576000868281518110612b8b57fe5b60200260200101516001600160a01b03166108fc878481518110612bab57fe5b60200260200101519081150290604051600060405180830381858888f1935050505090508015612c4157868281518110612be157fe5b60200260200101516001600160a01b03167f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d878481518110612c1f57fe5b60200260200101516040518082815260200191505060405180910390a2612ca9565b868281518110612c4d57fe5b60200260200101516001600160a01b03167f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d878481518110612c8b57fe5b60200260200101516040518082815260200191505060405180910390a25b50600101612b74565b505b4715612d1d576040805147815290517f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d9181900360200190a1604051611002904780156108fc02916000818181858888f19350505050158015612d1b573d6000803e3d6000fd5b505b60006003819055600555825115612d3757612d3783613628565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d7457600080fd5b505af1158015612d88573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a15060009f9e505050505050505050505050505050565b80516001600160a01b0316600090815260046020526040812054801580612e1c5750600180820381548110612dfc57fe5b9060005260206000209060040201600201601c9054906101000a900460ff165b15612e625782516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a26000915050611037565b600154600554600019820111801590612eb85784516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a260009350505050611037565b600580546001908101909155805481906000198601908110612ed657fe5b6000918252602082206002600490920201018054921515600160e01b0260ff60e01b199093169290921790915585516040516001600160a01b03909116917ff226e7d8f547ff903d9d419cf5f54e0d7d07efa9584135a53a057c5f1f27f49a91a2506000949350505050565b6000816040516020018082805190602001908083835b60208310612f775780518252601f199092019160209182019101612f58565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b60208310612fe55780518252601f199092019160209182019101612fc6565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201490505b92915050565b015190565b60008261303e57506000613024565b8282028284828161304b57fe5b0414610c935760405162461bcd60e51b81526004018080602001828103825260218152602001806142ac6021913960400191505060405180910390fd5b6000610c9383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ae9565b6000610c9383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b8b565b600082820183811015610c93576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b61316e6141c6565b506040805180820190915281518152602082810190820152919050565b613193614171565b61319c82613be5565b6131a557600080fd5b60006131b48360200151613c1f565b60208085015160408051808201909152868152920190820152915050919050565b60006131df6141c6565b505080518051602091820151919092015191011190565b6131fe6141c6565b613207826131d5565b61321057600080fd5b6020820151600061322082613c82565b80830160209586015260408051808201909152908152938401919091525090919050565b80516000901580159061325957508151602110155b61326257600080fd5b60006132718360200151613c1f565b905080836000015110156132cc576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b8251602080850151830180519284900392918310156132f257826020036101000a820491505b50949350505050565b606061330682613be5565b61330f57600080fd5b600061331a83613db5565b905060608160405190808252806020026020018201604052801561335857816020015b6133456141c6565b81526020019060019003908161333d5790505b509050600061336a8560200151613c1f565b60208601510190506000805b848110156133c15761338783613c82565b91506040518060400160405280838152602001848152508482815181106133aa57fe5b602090810291909101015291810191600101613376565b509195945050505050565b6133d4614191565b60006133de614191565b6133e6614171565b6133ef8561318b565b90506000805b6133fe836131d5565b15611f56578061342957613419613414846131f6565b613e11565b6001600160a01b031684526134a1565b80600114156134515761343e613414846131f6565b6001600160a01b031660208501526134a1565b806002141561347957613466613414846131f6565b6001600160a01b031660408501526134a1565b8060031415611f495761348e611e5b846131f6565b6001600160401b03166060850152600191505b6001016133f5565b60606130246134b783613e2b565b613f11565b60608151600014156134dd5750604080516000815260208101909152611037565b6060826000815181106134ec57fe5b602002602001015190506000600190505b835181101561352d576135238285838151811061351657fe5b6020026020010151613f63565b91506001016134fd565b50610c93613540825160c060ff16613fe0565b82613f63565b600060606029835111156135785760006040518060600160405280602981526020016141e16029913991509150611f5f565b60005b835181101561360e5760005b818110156136055784818151811061359b57fe5b6020026020010151600001516001600160a01b03168583815181106135bc57fe5b6020026020010151600001516001600160a01b031614156135fd5760006040518060600160405280602b8152602001614235602b9139935093505050611f5f565b600101613587565b5060010161357b565b505060408051602081019091526000815260019150915091565b600154815160005b82811015613745576001613642614191565b6001838154811061364f57fe5b600091825260208083206040805160c08101825260049490940290910180546001600160a01b0390811685526001820154811693850193909352600281015492831691840191909152600160a01b82046001600160401b03166060840152600160e01b90910460ff16151560808301526003015460a082015291505b84811015613719578681815181106136df57fe5b6020026020010151600001516001600160a01b031682600001516001600160a01b031614156137115760009250613719565b6001016136cb565b50811561373b5780516001600160a01b03166000908152600460205260408120555b5050600101613630565b50808211156137ba57805b828110156137b857600180548061376357fe5b60008281526020812060046000199093019283020180546001600160a01b03199081168255600182810180549092169091556002820180546001600160e81b0319169055600390910191909155915501613750565b505b60008183106137c957816137cb565b825b905060005b818110156139c55761387d8582815181106137e757fe5b6020026020010151600183815481106137fc57fe5b60009182526020918290206040805160c08101825260049390930290910180546001600160a01b0390811684526001820154811694840194909452600281015493841691830191909152600160a01b83046001600160401b03166060830152600160e01b90920460ff161515608082015260039091015460a08201526140d8565b61399857806001016004600087848151811061389557fe5b6020026020010151600001516001600160a01b03166001600160a01b03168152602001908152602001600020819055508481815181106138d157fe5b6020026020010151600182815481106138e657fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a0909101516003909101556139bd565b6000600182815481106139a757fe5b9060005260206000209060040201600301819055505b6001016137d0565b5082821115611dee57825b82811015610fba5760018582815181106139e657fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782559585015181840180549184169188169190911790556040850151600282018054606088015160808901511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590971692909a169190911792909216939093171695909517905560a09092015160039093019290925587519084019290889085908110613abc57fe5b602090810291909101810151516001600160a01b03168252810191909152604001600020556001016139d0565b60008183613b755760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613b3a578181015183820152602001613b22565b50505050905090810190601f168015613b675780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613b8157fe5b0495945050505050565b60008184841115613bdd5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613b3a578181015183820152602001613b22565b505050900390565b8051600090613bf657506000611037565b6020820151805160001a9060c0821015613c1557600092505050611037565b5060019392505050565b8051600090811a6080811015613c39576000915050611037565b60b8811080613c54575060c08110801590613c54575060f881105b15613c63576001915050611037565b60c0811015613c775760b519019050611037565b60f519019050611037565b80516000908190811a6080811015613c9d5760019150613dae565b60b8811015613cb257607e1981019150613dae565b60c0811015613d2c57600060b78203600186019550806020036101000a865104915060018101820193505080831015613d26576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b50613dae565b60f8811015613d415760be1981019150613dae565b600060f78203600186019550806020036101000a865104915060018101820193505080831015613dac576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b8051600090613dc657506000611037565b60008090506000613dda8460200151613c1f565b602085015185519181019250015b80821015613e0857613df982613c82565b60019093019290910190613de8565b50909392505050565b8051600090601514613e2257600080fd5b61302482613244565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff198416613e6f57506018613e93565b6fffffffffffffffffffffffffffffffff198416613e8f57506010613e93565b5060005b6020811015613ec957818181518110613ea857fe5b01602001516001600160f81b03191615613ec157613ec9565b600101613e93565b60008160200390506060816040519080825280601f01601f191660200182016040528015613efe576020820181803683370190505b5080830196909652508452509192915050565b606081516001148015613f435750607f60f81b82600081518110613f3157fe5b01602001516001600160f81b03191611155b15613f4f575080611037565b613024613f618351608060ff16613fe0565b835b6060806040519050835180825260208201818101602087015b81831015613f94578051835260209283019201613f7c565b50855184518101855292509050808201602086015b81831015613fc1578051835260209283019201613fa9565b508651929092011591909101601f01601f191660405250905092915050565b6060680100000000000000008310614030576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b6040805160018082528183019092526060916020820181803683370190505090506037841161408a5782840160f81b8160008151811061406c57fe5b60200101906001600160f81b031916908160001a9053509050613024565b606061409585613e2b565b90508381510160370160f81b826000815181106140ae57fe5b60200101906001600160f81b031916908160001a9053506140cf8282613f63565b95945050505050565b805182516000916001600160a01b039182169116148015614112575081602001516001600160a01b031683602001516001600160a01b0316145b8015614137575081604001516001600160a01b031683604001516001600160a01b0316145b8015610c935750506060908101519101516001600160401b0390811691161490565b60408051808201909152600081526060602082015290565b60405180604001604052806141846141c6565b8152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60405180604001604052806000815260200160008152509056fe746865206e756d626572206f662076616c696461746f72732065786365656420746865206c696d6974746865206275726e526174696f206d757374206265206e6f2067726561746572207468616e2031303030306475706c696361746520636f6e73656e7375732061646472657373206f662076616c696461746f725365747468652065787069726554696d655365636f6e64476170206973206f7574206f662072616e67656c656e677468206f66206a61696c2076616c696461746f7273206d757374206265206f6e65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374666565206973206c6172676572207468616e2044555354595f494e434f4d494e476c656e677468206f662065787069726554696d655365636f6e64476170206d69736d617463686661696c656420746f20706172736520696e69742076616c696461746f72536574f905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a2000746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f6475636572746865206d6573736167652073656e646572206d75737420626520736c61736820636f6e7472616374a2646970667358221220b274d764256170addda41fb4f3d964ba036ef5f3a15a0341d0524406e0ac44e864736f6c63430006040033", + }, + }, + } } func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, statedb *state.StateDB) { @@ -306,6 +341,10 @@ func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I applySystemContractUpgrade(mirrorUpgrade[network], blockNumber, statedb, logger) } + if config.IsOnBruno(blockNumber) { + applySystemContractUpgrade(brunoUpgrade[network], blockNumber, statedb, logger) + } + /* apply other upgrades */ diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 001b27147f..593c629446 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -82,6 +82,7 @@ func generateTestChainWithFork(n int, fork int) (*core.Genesis, []*types.Block, RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), + BrunoBlock: big.NewInt(0), Ethash: new(params.EthashConfig), } diff --git a/params/config.go b/params/config.go index 81ff4da9c3..8afc20f882 100644 --- a/params/config.go +++ b/params/config.go @@ -34,7 +34,7 @@ var ( BSCGenesisHash = common.HexToHash("0x0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b") ChapelGenesisHash = common.HexToHash("0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34") - RialtoGenesisHash = common.HexToHash("0x005dc005bddd1967de6187c1c23be801eb7abdd80cebcc24f341b727b70311d6") + RialtoGenesisHash = common.HexToHash("0xaabe549bfa85c84f7aee9da7010b97453ad686f2c2d8ce00503d1a00c72cad54") YoloV3GenesisHash = common.HexToHash("0xf1f2876e8500c77afcc03228757b39477eceffccf645b734967fe3c7e16967b7") ) @@ -75,6 +75,7 @@ var ( RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), + BrunoBlock: big.NewInt(0), BerlinBlock: big.NewInt(12_244_000), Ethash: new(EthashConfig), } @@ -118,6 +119,7 @@ var ( RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), + BrunoBlock: big.NewInt(0), BerlinBlock: big.NewInt(9_812_189), Ethash: new(EthashConfig), } @@ -161,6 +163,7 @@ var ( RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), + BrunoBlock: big.NewInt(0), BerlinBlock: big.NewInt(8_290_928), Clique: &CliqueConfig{ Period: 15, @@ -203,6 +206,7 @@ var ( RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), + BrunoBlock: big.NewInt(0), IstanbulBlock: big.NewInt(1_561_651), MuirGlacierBlock: nil, BerlinBlock: big.NewInt(4_460_644), @@ -246,6 +250,7 @@ var ( RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(5184000), + BrunoBlock: nil, Parlia: &ParliaConfig{ Period: 3, Epoch: 200, @@ -266,6 +271,7 @@ var ( RamanujanBlock: big.NewInt(1010000), NielsBlock: big.NewInt(1014369), MirrorSyncBlock: big.NewInt(5582500), + BrunoBlock: big.NewInt(13837000), Parlia: &ParliaConfig{ Period: 3, Epoch: 200, @@ -286,6 +292,7 @@ var ( RamanujanBlock: big.NewInt(400), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(400), + BrunoBlock: big.NewInt(400), Parlia: &ParliaConfig{ Period: 3, Epoch: 200, @@ -308,6 +315,7 @@ var ( RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), + BrunoBlock: big.NewInt(0), MuirGlacierBlock: nil, BerlinBlock: nil, // Don't enable Berlin directly, we're YOLOing it YoloV3Block: big.NewInt(0), @@ -322,16 +330,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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil} + 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, &CliqueConfig{Period: 0, Epoch: 30000}, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, nil} TestRules = TestChainConfig.Rules(new(big.Int)) ) @@ -418,6 +426,7 @@ type ChainConfig struct { RamanujanBlock *big.Int `json:"ramanujanBlock,omitempty" toml:",omitempty"` // ramanujanBlock switch block (nil = no fork, 0 = already activated) NielsBlock *big.Int `json:"nielsBlock,omitempty" toml:",omitempty"` // nielsBlock switch block (nil = no fork, 0 = already activated) MirrorSyncBlock *big.Int `json:"mirrorSyncBlock,omitempty" toml:",omitempty"` // mirrorSyncBlock switch block (nil = no fork, 0 = already activated) + BrunoBlock *big.Int `json:"brunoBlock,omitempty" toml:",omitempty"` // brunoBlock switch block (nil = no fork, 0 = already activated) // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty" toml:",omitempty"` @@ -468,7 +477,7 @@ func (c *ChainConfig) String() string { 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, Ramanujan: %v, Niels: %v, MirrorSync: %v, Berlin: %v, YOLO v3: %v, Engine: %v}", + 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, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -484,6 +493,7 @@ func (c *ChainConfig) String() string { c.RamanujanBlock, c.NielsBlock, c.MirrorSyncBlock, + c.BrunoBlock, c.BerlinBlock, c.YoloV3Block, engine, @@ -555,6 +565,16 @@ func (c *ChainConfig) IsOnMirrorSync(num *big.Int) bool { return configNumEqual(c.MirrorSyncBlock, num) } +// IsBruno returns whether num is either equal to the Burn fork block or greater. +func (c *ChainConfig) IsBruno(num *big.Int) bool { + return isForked(c.BrunoBlock, num) +} + +// IsOnBruno returns whether num is equal to the Burn fork block +func (c *ChainConfig) IsOnBruno(num *big.Int) bool { + return configNumEqual(c.BrunoBlock, 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) @@ -616,6 +636,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { var lastFork fork for _, cur := range []fork{ {name: "mirrorSyncBlock", block: c.MirrorSyncBlock}, + {name: "brunoBlock", block: c.BrunoBlock}, {name: "berlinBlock", block: c.BerlinBlock}, } { if lastFork.name != "" { @@ -695,6 +716,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.MirrorSyncBlock, newcfg.MirrorSyncBlock, head) { return newCompatError("mirrorSync fork block", c.MirrorSyncBlock, newcfg.MirrorSyncBlock) } + if isForkIncompatible(c.BrunoBlock, newcfg.BrunoBlock, head) { + return newCompatError("bruno fork block", c.BrunoBlock, newcfg.BrunoBlock) + } return nil } From 32855963cd23289fd92a18bf87cf85c7f0d20a1a Mon Sep 17 00:00:00 2001 From: yutianwu Date: Tue, 2 Nov 2021 11:58:18 +0800 Subject: [PATCH 052/117] prepare for release v.1.1.4 (#504) --- CHANGELOG.md | 12 ++++++++++++ params/version.go | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0bd5774f9..78bb469607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,16 @@ # Changelog +## v1.1.4 +Improvement +* [\#472](https://github.com/binance-chain/bsc/pull/472) add metrics for contract code bitmap cache +* [\#473](https://github.com/binance-chain/bsc/pull/473) fix ci test flow + +BUGFIX +* [\#491](https://github.com/binance-chain/bsc/pull/491) fix prefetcher related bugs + +FEATURES +* [\#480](https://github.com/binance-chain/bsc/pull/480) implement bep 95 + + ## v1.1.3 Improvement * [\#456](https://github.com/binance-chain/bsc/pull/456) git-flow support lint, unit test, and integration test diff --git a/params/version.go b/params/version.go index fe8f2938e6..0786d099b5 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 3 // Patch version component of the current release + VersionPatch = 4 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From 94e5e6cfddf2e3494fd2cd35d6722552b2eab599 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Mon, 8 Nov 2021 13:08:02 +0800 Subject: [PATCH 053/117] accelarate get diff accounts with scope (#493) Signed-off-by: Keefe-Liu --- internal/ethapi/api.go | 79 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index da4cf8cad1..53e94d9af6 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1101,6 +1101,66 @@ func (s *PublicBlockChainAPI) GetDiffAccounts(ctx context.Context, blockNr rpc.B return s.b.Chain().GetDiffAccounts(header.Hash()) } +func (s *PublicBlockChainAPI) needToReplay(ctx context.Context, block *types.Block, accounts []common.Address) (bool, error) { + receipts, err := s.b.GetReceipts(ctx, block.Hash()) + if err != nil || len(receipts) != len(block.Transactions()) { + return false, fmt.Errorf("receipt incorrect for block number (%d): %v", block.NumberU64(), err) + } + + accountSet := make(map[common.Address]struct{}, len(accounts)) + for _, account := range accounts { + accountSet[account] = struct{}{} + } + spendValueMap := make(map[common.Address]int64, len(accounts)) + receiveValueMap := make(map[common.Address]int64, len(accounts)) + + signer := types.MakeSigner(s.b.ChainConfig(), block.Number()) + for index, tx := range block.Transactions() { + receipt := receipts[index] + from, err := types.Sender(signer, tx) + if err != nil { + return false, fmt.Errorf("get sender for tx failed: %v", err) + } + + if _, exists := accountSet[from]; exists { + spendValueMap[from] += int64(receipt.GasUsed) * tx.GasPrice().Int64() + if receipt.Status == types.ReceiptStatusSuccessful { + spendValueMap[from] += tx.Value().Int64() + } + } + + if tx.To() == nil { + continue + } + + if _, exists := accountSet[*tx.To()]; exists && receipt.Status == types.ReceiptStatusSuccessful { + receiveValueMap[*tx.To()] += tx.Value().Int64() + } + } + + parent, err := s.b.BlockByHash(ctx, block.ParentHash()) + if err != nil { + return false, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err) + } + parentState, err := s.b.Chain().StateAt(parent.Root()) + if err != nil { + return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64()-1, err) + } + currentState, err := s.b.Chain().StateAt(block.Root()) + if err != nil { + return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64(), err) + } + for _, account := range accounts { + parentBalance := parentState.GetBalance(account).Int64() + currentBalance := currentState.GetBalance(account).Int64() + if receiveValueMap[account]-spendValueMap[account] != currentBalance-parentBalance { + return true, nil + } + } + + return false, nil +} + // GetDiffAccountsWithScope returns detailed changes of some interested accounts in a specific block number. func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, blockNr rpc.BlockNumber, accounts []common.Address) (*types.DiffAccountsInBlock, error) { if s.b.Chain() == nil { @@ -1111,6 +1171,19 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc if err != nil { return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) } + + result := &types.DiffAccountsInBlock{ + Number: uint64(blockNr), + BlockHash: block.Hash(), + Transactions: make([]types.DiffAccountsInTx, 0), + } + + if needReplay, err := s.needToReplay(ctx, block, accounts); err != nil { + return nil, err + } else if !needReplay { + return result, nil + } + parent, err := s.b.BlockByHash(ctx, block.ParentHash()) if err != nil { return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr-1, err) @@ -1120,12 +1193,6 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc return nil, fmt.Errorf("state not found for block number (%d): %v", blockNr-1, err) } - result := &types.DiffAccountsInBlock{ - Number: uint64(blockNr), - BlockHash: block.Hash(), - Transactions: make([]types.DiffAccountsInTx, 0), - } - accountSet := make(map[common.Address]struct{}, len(accounts)) for _, account := range accounts { accountSet[account] = struct{}{} From 176407ae5f9219462dd034f43685abf301758f7b Mon Sep 17 00:00:00 2001 From: SolidityGo <92978704+SolidityGo@users.noreply.github.com> Date: Mon, 8 Nov 2021 13:09:07 +0800 Subject: [PATCH 054/117] [R4R] fix: graceful shutdown bug (#509) * fix: graceful shutdown bug that diff handshake failure caused waitDiffExtension can't receive exit signal * fix: add lock for peerset --- eth/handler_diff.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/eth/handler_diff.go b/eth/handler_diff.go index c996105f0f..a5fbfdb0a8 100644 --- a/eth/handler_diff.go +++ b/eth/handler_diff.go @@ -33,6 +33,18 @@ func (h *diffHandler) Chain() *core.BlockChain { return h.chain } // RunPeer is invoked when a peer joins on the `diff` protocol. func (h *diffHandler) RunPeer(peer *diff.Peer, hand diff.Handler) error { if err := peer.Handshake(h.diffSync); err != nil { + // ensure that waitDiffExtension receives the exit signal normally + // otherwise, can't graceful shutdown + ps := h.peers + id := peer.ID() + + // Ensure nobody can double connect + ps.lock.Lock() + if wait, ok := ps.diffWait[id]; ok { + delete(ps.diffWait, id) + wait <- peer + } + ps.lock.Unlock() return err } defer h.chain.RemoveDiffPeer(peer.ID()) From 9603407407201045913ede81125e030dda3dd3f0 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Tue, 9 Nov 2021 19:39:58 +0800 Subject: [PATCH 055/117] fix useful difflayer item in cache been prune issue (#527) add logs fix useful difflayer item in cache been prune issue fix too many open files --- cmd/utils/flags.go | 4 +- core/blockchain.go | 42 +++++-------------- core/blockchain_diff_test.go | 2 +- core/state_processor.go | 13 +++--- eth/downloader/downloader.go | 68 +++++++++++++++++++------------ eth/downloader/downloader_test.go | 6 +-- eth/downloader/queue.go | 6 ++- eth/downloader/resultstore.go | 4 +- eth/ethconfig/config.go | 2 +- eth/handler_diff.go | 1 - eth/protocols/diff/handler.go | 2 +- node/node.go | 10 ++++- 12 files changed, 80 insertions(+), 80 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index c4dbd84911..49ea0d1de1 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -444,8 +444,8 @@ var ( } DiffBlockFlag = cli.Uint64Flag{ Name: "diffblock", - Usage: "The number of blocks should be persisted in db (default = 864000 )", - Value: uint64(864000), + Usage: "The number of blocks should be persisted in db (default = 86400)", + Value: uint64(86400), } // Miner settings MiningEnabledFlag = cli.BoolFlag{ diff --git a/core/blockchain.go b/core/blockchain.go index 22fe3e5998..4562061337 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -478,6 +478,9 @@ func (bc *BlockChain) cacheReceipts(hash common.Hash, receipts types.Receipts) { } func (bc *BlockChain) cacheDiffLayer(diffLayer *types.DiffLayer) { + if bc.diffLayerCache.Len() >= diffLayerCacheLimit { + bc.diffLayerCache.RemoveOldest() + } bc.diffLayerCache.Add(diffLayer.BlockHash, diffLayer) if bc.db.DiffStore() != nil { // push to priority queue before persisting @@ -2618,34 +2621,6 @@ func (bc *BlockChain) removeDiffLayers(diffHash common.Hash) { } } -func (bc *BlockChain) RemoveDiffPeer(pid string) { - bc.diffMux.Lock() - defer bc.diffMux.Unlock() - if invaliDiffHashes := bc.diffPeersToDiffHashes[pid]; invaliDiffHashes != nil { - for invalidDiffHash := range invaliDiffHashes { - lastDiffHash := false - if peers, ok := bc.diffHashToPeers[invalidDiffHash]; ok { - delete(peers, pid) - if len(peers) == 0 { - lastDiffHash = true - delete(bc.diffHashToPeers, invalidDiffHash) - } - } - if lastDiffHash { - affectedBlockHash := bc.diffHashToBlockHash[invalidDiffHash] - if diffs, exist := bc.blockHashToDiffLayers[affectedBlockHash]; exist { - delete(diffs, invalidDiffHash) - if len(diffs) == 0 { - delete(bc.blockHashToDiffLayers, affectedBlockHash) - } - } - delete(bc.diffHashToBlockHash, invalidDiffHash) - } - } - delete(bc.diffPeersToDiffHashes, pid) - } -} - func (bc *BlockChain) untrustedDiffLayerPruneLoop() { recheck := time.NewTicker(diffLayerPruneRecheckInterval) bc.wg.Add(1) @@ -2713,24 +2688,27 @@ func (bc *BlockChain) HandleDiffLayer(diffLayer *types.DiffLayer, pid string, fu // Basic check currentHeight := bc.CurrentBlock().NumberU64() if diffLayer.Number > currentHeight && diffLayer.Number-currentHeight > maxDiffQueueDist { - log.Error("diff layers too new from current", "pid", pid) + log.Debug("diff layers too new from current", "pid", pid) return nil } if diffLayer.Number < currentHeight && currentHeight-diffLayer.Number > maxDiffForkDist { - log.Error("diff layers too old from current", "pid", pid) + log.Debug("diff layers too old from current", "pid", pid) return nil } bc.diffMux.Lock() defer bc.diffMux.Unlock() + if blockHash, exist := bc.diffHashToBlockHash[diffLayer.DiffHash]; exist && blockHash == diffLayer.BlockHash { + return nil + } if !fulfilled && len(bc.diffPeersToDiffHashes[pid]) > maxDiffLimitForBroadcast { - log.Error("too many accumulated diffLayers", "pid", pid) + log.Debug("too many accumulated diffLayers", "pid", pid) return nil } if len(bc.diffPeersToDiffHashes[pid]) > maxDiffLimit { - log.Error("too many accumulated diffLayers", "pid", pid) + log.Debug("too many accumulated diffLayers", "pid", pid) return nil } if _, exist := bc.diffPeersToDiffHashes[pid]; exist { diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index 67affcff75..8e04363d0c 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -322,7 +322,7 @@ func TestPruneDiffLayer(t *testing.T) { if len(fullBackend.chain.diffNumToBlockHashes) != maxDiffForkDist { t.Error("unexpected size of diffNumToBlockHashes") } - if len(fullBackend.chain.diffPeersToDiffHashes) != 2 { + if len(fullBackend.chain.diffPeersToDiffHashes) != 1 { t.Error("unexpected size of diffPeersToDiffHashes") } if len(fullBackend.chain.blockHashToDiffLayers) != maxDiffForkDist { diff --git a/core/state_processor.go b/core/state_processor.go index b529082063..9f2a09bd36 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -43,8 +43,8 @@ import ( const ( fullProcessCheck = 21 // On diff sync mode, will do full process every fullProcessCheck randomly - recentTime = 2048 * 3 - recentDiffLayerTimeout = 20 + recentTime = 1024 * 3 + recentDiffLayerTimeout = 5 farDiffLayerTimeout = 2 ) @@ -68,15 +68,16 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen } type LightStateProcessor struct { - randomGenerator *rand.Rand + check int64 StateProcessor } func NewLightStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *LightStateProcessor { randomGenerator := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) + check := randomGenerator.Int63n(fullProcessCheck) return &LightStateProcessor{ - randomGenerator: randomGenerator, - StateProcessor: *NewStateProcessor(config, bc, engine), + check: check, + StateProcessor: *NewStateProcessor(config, bc, engine), } } @@ -86,7 +87,7 @@ func (p *LightStateProcessor) Process(block *types.Block, statedb *state.StateDB allowLightProcess = posa.AllowLightProcess(p.bc, block.Header()) } // random fallback to full process - if check := p.randomGenerator.Int63n(fullProcessCheck); allowLightProcess && check != 0 && len(block.Transactions()) != 0 { + if allowLightProcess && block.NumberU64()%fullProcessCheck != uint64(p.check) && len(block.Transactions()) != 0 { var pid string if peer, ok := block.ReceivedFrom.(PeerIDer); ok { pid = peer.ID() diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 5da80c9d3a..0009f41786 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -53,6 +53,9 @@ var ( ttlScaling = 3 // Constant scaling factor for RTT -> TTL conversion ttlLimit = time.Minute // Maximum TTL allowance to prevent reaching crazy timeouts + diffFetchTick = 10 * time.Millisecond + diffFetchLimit = 5 + qosTuningPeers = 5 // Number of peers to tune based on (best peers) qosConfidenceCap = 10 // Number of peers above which not to modify RTT confidence qosTuningImpact = 0.25 // Impact that a new tuning target has on the previous value @@ -161,10 +164,10 @@ type Downloader struct { quitLock sync.Mutex // Lock to prevent double closes // Testing hooks - syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run - bodyFetchHook func([]*types.Header, ...interface{}) // Method to call upon starting a block body fetch - receiptFetchHook func([]*types.Header, ...interface{}) // Method to call upon starting a receipt fetch - chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations) + syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run + 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, chan struct{}) // Method to call upon inserting a chain of blocks (possibly in multiple invocations) } // LightChain encapsulates functions required to synchronise a light chain. @@ -232,27 +235,35 @@ type IPeerSet interface { func EnableDiffFetchOp(peers IPeerSet) DownloadOption { return func(dl *Downloader) *Downloader { - var hook = func(headers []*types.Header, args ...interface{}) { - if len(args) < 2 { - return - } - peerID, ok := args[1].(string) - if !ok { - return - } - mode, ok := args[0].(SyncMode) - if !ok { - return - } - if ep := peers.GetDiffPeer(peerID); mode == FullSync && ep != nil { - hashes := make([]common.Hash, 0, len(headers)) - for _, header := range headers { - hashes = append(hashes, header.Hash()) - } - ep.RequestDiffLayers(hashes) + var hook = func(results []*fetchResult, stop chan struct{}) { + if dl.getMode() == FullSync { + go func() { + ticker := time.NewTicker(diffFetchTick) + defer ticker.Stop() + for _, r := range results { + Wait: + for { + select { + case <-stop: + return + case <-ticker.C: + if dl.blockchain.CurrentHeader().Number.Int64()+int64(diffFetchLimit) > r.Header.Number.Int64() { + break Wait + } + } + } + if ep := peers.GetDiffPeer(r.pid); ep != nil { + // It turns out a diff layer is 5x larger than block, we just request one diffLayer each time + err := ep.RequestDiffLayers([]common.Hash{r.Header.Hash()}) + if err != nil { + return + } + } + } + }() } } - dl.bodyFetchHook = hook + dl.chainInsertHook = hook return dl } } @@ -1405,7 +1416,7 @@ func (d *Downloader) fetchReceipts(from uint64) error { // - 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, ...interface{}), fetch func(*peerConnection, *fetchRequest) error, cancel func(*fetchRequest), capacity func(*peerConnection) int, + 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 @@ -1554,7 +1565,7 @@ func (d *Downloader) fetchParts(deliveryCh chan dataPack, deliver func(dataPack) } // Fetch the chunk and make sure any errors return the hashes to the queue if fetchHook != nil { - fetchHook(request.Headers, d.getMode(), peer.id) + fetchHook(request.Headers) } if err := fetch(peer, request); err != nil { // Although we could try and make an attempt to fix this, this error really @@ -1759,12 +1770,15 @@ func (d *Downloader) processFullSyncContent() error { if len(results) == 0 { return nil } + stop := make(chan struct{}) if d.chainInsertHook != nil { - d.chainInsertHook(results) + d.chainInsertHook(results, stop) } if err := d.importBlockResults(results); err != nil { + close(stop) return err } + close(stop) } } @@ -1850,7 +1864,7 @@ func (d *Downloader) processFastSyncContent() error { } } if d.chainInsertHook != nil { - d.chainInsertHook(results) + d.chainInsertHook(results, nil) } // If we haven't downloaded the pivot block yet, check pivot staleness // notifications from the header downloader diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 66f6872025..4b76b6a5db 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -565,7 +565,7 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { // Wrap the importer to allow stepping blocked, proceed := uint32(0), make(chan struct{}) - tester.downloader.chainInsertHook = func(results []*fetchResult) { + tester.downloader.chainInsertHook = func(results []*fetchResult, _ chan struct{}) { atomic.StoreUint32(&blocked, uint32(len(results))) <-proceed } @@ -921,10 +921,10 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { // Instrument the downloader to signal body requests bodiesHave, receiptsHave := int32(0), int32(0) - tester.downloader.bodyFetchHook = func(headers []*types.Header, _ ...interface{}) { + tester.downloader.bodyFetchHook = func(headers []*types.Header) { atomic.AddInt32(&bodiesHave, int32(len(headers))) } - tester.downloader.receiptFetchHook = func(headers []*types.Header, _ ...interface{}) { + tester.downloader.receiptFetchHook = func(headers []*types.Header) { atomic.AddInt32(&receiptsHave, int32(len(headers))) } // Synchronise with the peer and make sure all blocks were retrieved diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index ac7edc2c68..3b01984da5 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -63,6 +63,7 @@ type fetchRequest struct { // all outstanding pieces complete and the result as a whole can be processed. type fetchResult struct { pending int32 // Flag telling what deliveries are outstanding + pid string Header *types.Header Uncles []*types.Header @@ -70,9 +71,10 @@ type fetchResult struct { Receipts types.Receipts } -func newFetchResult(header *types.Header, fastSync bool) *fetchResult { +func newFetchResult(header *types.Header, fastSync bool, pid string) *fetchResult { item := &fetchResult{ Header: header, + pid: pid, } if !header.EmptyBody() { item.pending |= (1 << bodyType) @@ -503,7 +505,7 @@ func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common // we can ask the resultcache if this header is within the // "prioritized" segment of blocks. If it is not, we need to throttle - stale, throttle, item, err := q.resultCache.AddFetch(header, q.mode == FastSync) + stale, throttle, item, err := q.resultCache.AddFetch(header, q.mode == FastSync, p.id) if stale { // Don't put back in the task queue, this item has already been // delivered upstream diff --git a/eth/downloader/resultstore.go b/eth/downloader/resultstore.go index 21928c2a00..98ce75593b 100644 --- a/eth/downloader/resultstore.go +++ b/eth/downloader/resultstore.go @@ -75,7 +75,7 @@ func (r *resultStore) SetThrottleThreshold(threshold uint64) uint64 { // 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) { +func (r *resultStore) AddFetch(header *types.Header, fastSync bool, pid string) (stale, throttled bool, item *fetchResult, err error) { r.lock.Lock() defer r.lock.Unlock() @@ -85,7 +85,7 @@ func (r *resultStore) AddFetch(header *types.Header, fastSync bool) (stale, thro return stale, throttled, item, err } if item == nil { - item = newFetchResult(header, fastSync) + item = newFetchResult(header, fastSync, pid) r.items[index] = item } return stale, throttled, item, err diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 83db7fc998..010a1fb923 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -80,7 +80,7 @@ var Defaults = Config{ TrieTimeout: 60 * time.Minute, TriesInMemory: 128, SnapshotCache: 102, - DiffBlock: uint64(864000), + DiffBlock: uint64(86400), Miner: miner.Config{ GasFloor: 8000000, GasCeil: 8000000, diff --git a/eth/handler_diff.go b/eth/handler_diff.go index a5fbfdb0a8..6d5436bf9a 100644 --- a/eth/handler_diff.go +++ b/eth/handler_diff.go @@ -47,7 +47,6 @@ func (h *diffHandler) RunPeer(peer *diff.Peer, hand diff.Handler) error { ps.lock.Unlock() return err } - defer h.chain.RemoveDiffPeer(peer.ID()) return (*handler)(h).runDiffExtension(peer, hand) } diff --git a/eth/protocols/diff/handler.go b/eth/protocols/diff/handler.go index 8678ff7f65..18ec4e2541 100644 --- a/eth/protocols/diff/handler.go +++ b/eth/protocols/diff/handler.go @@ -17,7 +17,7 @@ const ( softResponseLimit = 2 * 1024 * 1024 // maxDiffLayerServe is the maximum number of diff layers to serve. - maxDiffLayerServe = 1024 + maxDiffLayerServe = 128 ) var requestTracker = NewTracker(time.Minute) diff --git a/node/node.go b/node/node.go index f1564bea23..c122dad32c 100644 --- a/node/node.go +++ b/node/node.go @@ -68,6 +68,8 @@ const ( closedState ) +const chainDataHandlesPercentage = 80 + // New creates a new P2P node, ready for protocol registration. func New(conf *Config) (*Node, error) { // Copy config and resolve the datadir so future changes to the current @@ -580,12 +582,16 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r } func (n *Node) OpenAndMergeDatabase(name string, cache, handles int, freezer, diff, namespace string, readonly, persistDiff bool) (ethdb.Database, error) { - chainDB, err := n.OpenDatabaseWithFreezer(name, cache, handles, freezer, namespace, readonly) + chainDataHandles := handles + if persistDiff { + chainDataHandles = handles * chainDataHandlesPercentage / 100 + } + chainDB, err := n.OpenDatabaseWithFreezer(name, cache, chainDataHandles, freezer, namespace, readonly) if err != nil { return nil, err } if persistDiff { - diffStore, err := n.OpenDiffDatabase(name, handles, diff, namespace, readonly) + diffStore, err := n.OpenDiffDatabase(name, handles-chainDataHandles, diff, namespace, readonly) if err != nil { chainDB.Close() return nil, err From 288eb52e9f31cbbe7d08c7c15d7b17cd8aedaed2 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Tue, 16 Nov 2021 11:39:50 +0800 Subject: [PATCH 056/117] get diff accounts by replaying block when diff layer not found (#536) Signed-off-by: Keefe-Liu --- core/blockchain.go | 2 +- core/error.go | 3 ++ core/state/statedb.go | 8 +++++ internal/ethapi/api.go | 71 ++++++++++++++++++++++++++++-------------- 4 files changed, 60 insertions(+), 24 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 4562061337..4a7cdf9a54 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1011,7 +1011,7 @@ func (bc *BlockChain) GetDiffAccounts(blockHash common.Hash) ([]common.Address, if diffLayer == nil { if header.TxHash != types.EmptyRootHash { - return nil, fmt.Errorf("no diff layer found") + return nil, ErrDiffLayerNotFound } return nil, nil diff --git a/core/error.go b/core/error.go index 197dd81567..1fbd0d599b 100644 --- a/core/error.go +++ b/core/error.go @@ -31,6 +31,9 @@ var ( // ErrNoGenesis is returned when there is no Genesis Block. ErrNoGenesis = errors.New("genesis not found in chain") + + // ErrDiffLayerNotFound is returned when diff layer not found. + ErrDiffLayerNotFound = errors.New("diff layer not found") ) // List of evm-call-message pre-checking errors. All state transition messages will diff --git a/core/state/statedb.go b/core/state/statedb.go index c7a9d92ef7..6f150915ca 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1493,3 +1493,11 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre } return s.accessList.Contains(addr, slot) } + +func (s *StateDB) GetDirtyAccounts() []common.Address { + accounts := make([]common.Address, 0, len(s.stateObjectsDirty)) + for account := range s.stateObjectsDirty { + accounts = append(accounts, account) + } + return accounts +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 53e94d9af6..091e9e7e82 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1098,7 +1098,21 @@ func (s *PublicBlockChainAPI) GetDiffAccounts(ctx context.Context, blockNr rpc.B return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) } - return s.b.Chain().GetDiffAccounts(header.Hash()) + accounts, err := s.b.Chain().GetDiffAccounts(header.Hash()) + if err == nil || !errors.Is(err, core.ErrDiffLayerNotFound) { + return accounts, err + } + + // Replay the block when diff layer not found, it is very slow. + block, err := s.b.BlockByNumber(ctx, blockNr) + if err != nil { + return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) + } + _, statedb, err := s.replay(ctx, block, nil) + if err != nil { + return nil, err + } + return statedb.GetDirtyAccounts(), nil } func (s *PublicBlockChainAPI) needToReplay(ctx context.Context, block *types.Block, accounts []common.Address) (bool, error) { @@ -1161,36 +1175,20 @@ func (s *PublicBlockChainAPI) needToReplay(ctx context.Context, block *types.Blo return false, nil } -// GetDiffAccountsWithScope returns detailed changes of some interested accounts in a specific block number. -func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, blockNr rpc.BlockNumber, accounts []common.Address) (*types.DiffAccountsInBlock, error) { - if s.b.Chain() == nil { - return nil, fmt.Errorf("blockchain not support get diff accounts") - } - - block, err := s.b.BlockByNumber(ctx, blockNr) - if err != nil { - return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) - } - +func (s *PublicBlockChainAPI) replay(ctx context.Context, block *types.Block, accounts []common.Address) (*types.DiffAccountsInBlock, *state.StateDB, error) { result := &types.DiffAccountsInBlock{ - Number: uint64(blockNr), + Number: block.NumberU64(), BlockHash: block.Hash(), Transactions: make([]types.DiffAccountsInTx, 0), } - if needReplay, err := s.needToReplay(ctx, block, accounts); err != nil { - return nil, err - } else if !needReplay { - return result, nil - } - parent, err := s.b.BlockByHash(ctx, block.ParentHash()) if err != nil { - return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr-1, err) + return nil, nil, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err) } statedb, err := s.b.Chain().StateAt(parent.Root()) if err != nil { - return nil, fmt.Errorf("state not found for block number (%d): %v", blockNr-1, err) + return nil, nil, fmt.Errorf("state not found for block number (%d): %v", block.NumberU64()-1, err) } accountSet := make(map[common.Address]struct{}, len(accounts)) @@ -1240,7 +1238,7 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc } if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { - return nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + return nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) @@ -1259,7 +1257,34 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc } } - return result, nil + return result, statedb, nil +} + +// GetDiffAccountsWithScope returns detailed changes of some interested accounts in a specific block number. +func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, blockNr rpc.BlockNumber, accounts []common.Address) (*types.DiffAccountsInBlock, error) { + if s.b.Chain() == nil { + return nil, fmt.Errorf("blockchain not support get diff accounts") + } + + block, err := s.b.BlockByNumber(ctx, blockNr) + if err != nil { + return nil, fmt.Errorf("block not found for block number (%d): %v", blockNr, err) + } + + needReplay, err := s.needToReplay(ctx, block, accounts) + if err != nil { + return nil, err + } + if !needReplay { + return &types.DiffAccountsInBlock{ + Number: uint64(blockNr), + BlockHash: block.Hash(), + Transactions: make([]types.DiffAccountsInTx, 0), + }, nil + } + + result, _, err := s.replay(ctx, block, accounts) + return result, err } // ExecutionResult groups all structured logs emitted by the EVM From 6fb789de676173b70ad34bb3efeebc50682f74e0 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Tue, 16 Nov 2021 13:51:44 +0800 Subject: [PATCH 057/117] prepare for release v.1.1.5 (#549) --- CHANGELOG.md | 9 +++++++++ params/config.go | 2 +- params/version.go | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78bb469607..5b0b345db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ # Changelog +## v1.1.5 +BUGFIX +* [\#509](https://github.com/binance-chain/bsc/pull/509) fix graceful shutdown bug + +IMPROVEMENT +* [\#536](https://github.com/binance-chain/bsc/pull/536) get diff accounts by replaying block when diff layer not found +* [\#527](https://github.com/binance-chain/bsc/pull/527) improve diffsync protocol in many aspects +* [\#493](https://github.com/binance-chain/bsc/pull/493) implement fast getDiffAccountsWithScope API + ## v1.1.4 Improvement * [\#472](https://github.com/binance-chain/bsc/pull/472) add metrics for contract code bitmap cache diff --git a/params/config.go b/params/config.go index 8afc20f882..c09a576495 100644 --- a/params/config.go +++ b/params/config.go @@ -250,7 +250,7 @@ var ( RamanujanBlock: big.NewInt(0), NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(5184000), - BrunoBlock: nil, + BrunoBlock: big.NewInt(13082000), Parlia: &ParliaConfig{ Period: 3, Epoch: 200, diff --git a/params/version.go b/params/version.go index 0786d099b5..d15c2d94c5 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release + VersionPatch = 5 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From a3f9e232be001182ec786a6f326f5ce54236a70e Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Wed, 24 Nov 2021 10:47:37 +0800 Subject: [PATCH 058/117] eth/protocols/snap, trie: better error-handling (#23657) (#582) Co-authored-by: Martin Holst Swende --- eth/protocols/snap/handler.go | 2 +- trie/trie.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 3d668a2ebb..d9935f455f 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -469,7 +469,7 @@ func handleMessage(backend Backend, peer *Peer) error { // 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 { + if err != nil || account == nil { break } stTrie, err := trie.NewSecure(common.BytesToHash(account.Root), triedb) diff --git a/trie/trie.go b/trie/trie.go index 44de1374a4..1e6e8fd250 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -174,6 +174,10 @@ func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) { } func (t *Trie) tryGetNode(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 + } // If we reached the requested path, return the current node if pos >= len(path) { // Although we most probably have the original node expanded, encoding @@ -193,10 +197,6 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new } // Path still needs to be traversed, descend into children switch n := (origNode).(type) { - case nil: - // Non-existent path requested, abort - return nil, nil, 0, nil - case valueNode: // Path prematurely ended, abort return nil, nil, 0, nil From 1d94308fe9fa7a5ed540ae0c554d875867c42061 Mon Sep 17 00:00:00 2001 From: flywukong <2229306838@qq.com> Date: Wed, 24 Nov 2021 14:23:54 +0800 Subject: [PATCH 059/117] go.mod: update goleveldb (#23417) (#578) Co-authored-by: ucwong --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 4ea9fc689a..c58a45dfd2 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect github.com/go-stack/stack v1.8.0 github.com/golang/protobuf v1.4.3 - github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 + github.com/golang/snappy v0.0.4 github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa github.com/google/uuid v1.1.5 github.com/gorilla/websocket v1.4.2 @@ -65,7 +65,7 @@ require ( 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/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tendermint/go-amino v0.14.1 github.com/tendermint/iavl v0.12.0 github.com/tendermint/tendermint v0.31.11 diff --git a/go.sum b/go.sum index e94241a414..6ab7ca8c45 100644 --- a/go.sum +++ b/go.sum @@ -186,8 +186,8 @@ 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/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/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/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= @@ -387,8 +387,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= -github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +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/tendermint/go-amino v0.14.1 h1:o2WudxNfdLNBwMyl2dqOJxiro5rfrEaU0Ugs6offJMk= github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= github.com/tendermint/iavl v0.12.0 h1:xcaFAr+ycqCj7WN1RzL2EfcBioRDOHcU1oWcg83K028= From fbc52de8f67465e6dd3963d29bf4bd12afbc037c Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Thu, 25 Nov 2021 11:00:14 +0800 Subject: [PATCH 060/117] [R4R]reannounce local pending transactions (#570) * reannouce local pending transactions * add tests for tx_pool reannouce local pending transactions * add tests for handler reannounce local pending transactions --- cmd/geth/main.go | 1 + cmd/geth/usage.go | 1 + cmd/utils/flags.go | 8 +++++ core/events.go | 3 ++ core/tx_pool.go | 72 ++++++++++++++++++++++++++++++++------- core/tx_pool_test.go | 41 ++++++++++++++++++++++ core/types/transaction.go | 5 +++ eth/handler.go | 51 +++++++++++++++++++++++++++ eth/handler_eth_test.go | 53 ++++++++++++++++++++++++++++ eth/handler_test.go | 23 +++++++++++-- eth/peerset.go | 16 +++++++++ 11 files changed, 259 insertions(+), 15 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 8be8d20bf4..e896c7d659 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -90,6 +90,7 @@ var ( utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, + utils.TxPoolReannounceTimeFlag, utils.SyncModeFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 2a208c827b..fba14530b5 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -108,6 +108,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, + utils.TxPoolReannounceTimeFlag, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 49ea0d1de1..67632c031b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -398,6 +398,11 @@ var ( Usage: "Maximum amount of time non-executable transaction are queued", Value: ethconfig.Defaults.TxPool.Lifetime, } + TxPoolReannounceTimeFlag = cli.DurationFlag{ + Name: "txpool.reannouncetime", + Usage: "Duration for announcing local pending transactions again (default = 10 years, minimum = 1 minute)", + Value: ethconfig.Defaults.TxPool.ReannounceTime, + } // Performance tuning settings CacheFlag = cli.IntFlag{ Name: "cache", @@ -1410,6 +1415,9 @@ func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) } + if ctx.GlobalIsSet(TxPoolReannounceTimeFlag.Name) { + cfg.ReannounceTime = ctx.GlobalDuration(TxPoolReannounceTimeFlag.Name) + } } func setEthash(ctx *cli.Context, cfg *ethconfig.Config) { diff --git a/core/events.go b/core/events.go index ac935a137f..5e730a24a7 100644 --- a/core/events.go +++ b/core/events.go @@ -24,6 +24,9 @@ import ( // NewTxsEvent is posted when a batch of transactions enter the transaction pool. type NewTxsEvent struct{ Txs []*types.Transaction } +// ReannoTxsEvent is posted when a batch of local pending transactions exceed a specified duration. +type ReannoTxsEvent struct{ Txs []*types.Transaction } + // NewMinedBlockEvent is posted when a block has been imported. type NewMinedBlockEvent struct{ Block *types.Block } diff --git a/core/tx_pool.go b/core/tx_pool.go index d0304857c3..4c08bc72b3 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -49,6 +49,9 @@ const ( // more expensive to propagate; larger transactions also take more resources // to validate whether they fit into the pool or not. txMaxSize = 4 * txSlotSize // 128KB + + // txReannoMaxNum is the maximum number of transactions a reannounce action can include. + txReannoMaxNum = 1024 ) var ( @@ -88,6 +91,7 @@ var ( var ( evictionInterval = time.Minute // Time interval to check for evictable transactions statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats + reannounceInterval = time.Minute // Time interval to check for reannounce transactions ) var ( @@ -152,7 +156,8 @@ type TxPoolConfig struct { AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts - Lifetime time.Duration // Maximum amount of time non-executable transaction are queued + Lifetime time.Duration // Maximum amount of time non-executable transaction are queued + ReannounceTime time.Duration // Duration for announcing local pending transactions again } // DefaultTxPoolConfig contains the default configurations for the transaction @@ -169,7 +174,8 @@ var DefaultTxPoolConfig = TxPoolConfig{ AccountQueue: 64, GlobalQueue: 1024, - Lifetime: 3 * time.Hour, + Lifetime: 3 * time.Hour, + ReannounceTime: 10 * 365 * 24 * time.Hour, } // sanitize checks the provided user configurations and changes anything that's @@ -208,6 +214,10 @@ func (config *TxPoolConfig) sanitize() TxPoolConfig { log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultTxPoolConfig.Lifetime) conf.Lifetime = DefaultTxPoolConfig.Lifetime } + if conf.ReannounceTime < time.Minute { + log.Warn("Sanitizing invalid txpool reannounce time", "provided", conf.ReannounceTime, "updated", time.Minute) + conf.ReannounceTime = time.Minute + } return conf } @@ -219,14 +229,15 @@ 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 - chainconfig *params.ChainConfig - chain blockChain - gasPrice *big.Int - txFeed event.Feed - scope event.SubscriptionScope - signer types.Signer - mu sync.RWMutex + config TxPoolConfig + chainconfig *params.ChainConfig + chain blockChain + gasPrice *big.Int + txFeed event.Feed + reannoTxFeed event.Feed // Event feed for announcing transactions again + scope event.SubscriptionScope + 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. @@ -323,14 +334,16 @@ func (pool *TxPool) loop() { var ( prevPending, prevQueued, prevStales int // Start the stats reporting and transaction eviction tickers - report = time.NewTicker(statsReportInterval) - evict = time.NewTicker(evictionInterval) - journal = time.NewTicker(pool.config.Rejournal) + report = time.NewTicker(statsReportInterval) + evict = time.NewTicker(evictionInterval) + reannounce = time.NewTicker(reannounceInterval) + journal = time.NewTicker(pool.config.Rejournal) // Track the previous head headers for transaction reorgs head = pool.chain.CurrentBlock() ) defer report.Stop() defer evict.Stop() + defer reannounce.Stop() defer journal.Stop() for { @@ -378,6 +391,33 @@ func (pool *TxPool) loop() { } pool.mu.Unlock() + case <-reannounce.C: + pool.mu.RLock() + reannoTxs := func() []*types.Transaction { + txs := make([]*types.Transaction, 0) + for addr, list := range pool.pending { + if !pool.locals.contains(addr) { + continue + } + + for _, tx := range list.Flatten() { + // Default ReannounceTime is 10 years, won't announce by default. + if time.Since(tx.Time()) < pool.config.ReannounceTime { + break + } + txs = append(txs, tx) + if len(txs) >= txReannoMaxNum { + return txs + } + } + } + return txs + }() + pool.mu.RUnlock() + if len(reannoTxs) > 0 { + pool.reannoTxFeed.Send(ReannoTxsEvent{reannoTxs}) + } + // Handle local transaction journal rotation case <-journal.C: if pool.journal != nil { @@ -412,6 +452,12 @@ func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscripti return pool.scope.Track(pool.txFeed.Subscribe(ch)) } +// SubscribeReannoTxsEvent registers a subscription of ReannoTxsEvent and +// starts sending event to the given channel. +func (pool *TxPool) SubscribeReannoTxsEvent(ch chan<- ReannoTxsEvent) event.Subscription { + return pool.scope.Track(pool.reannoTxFeed.Subscribe(ch)) +} + // GasPrice returns the current gas price enforced by the transaction pool. func (pool *TxPool) GasPrice() *big.Int { pool.mu.RLock() diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 5d555f5a9c..5f27631e15 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -1933,6 +1933,47 @@ func TestTransactionSlotCount(t *testing.T) { } } +// Tests the local pending transaction announced again correctly. +func TestTransactionPendingReannouce(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{statedb, 1000000, new(event.Feed)} + + config := testTxPoolConfig + // This ReannounceTime will be modified to time.Minute when creating tx_pool. + config.ReannounceTime = time.Second + reannounceInterval = time.Second + + pool := NewTxPool(config, params.TestChainConfig, blockchain) + // Modify ReannounceTime to trigger quicker. + pool.config.ReannounceTime = time.Second + defer pool.Stop() + + key, _ := crypto.GenerateKey() + account := crypto.PubkeyToAddress(key.PublicKey) + pool.currentState.AddBalance(account, big.NewInt(1000000)) + + events := make(chan ReannoTxsEvent, testTxPoolConfig.AccountQueue) + sub := pool.reannoTxFeed.Subscribe(events) + defer sub.Unsubscribe() + + // Generate a batch of transactions and add to tx_pool locally. + txs := make([]*types.Transaction, 0, testTxPoolConfig.AccountQueue) + for i := uint64(0); i < testTxPoolConfig.AccountQueue; i++ { + txs = append(txs, transaction(i, 100000, key)) + } + pool.AddLocals(txs) + + select { + case ev := <-events: + t.Logf("received reannouce event, txs length: %d", len(ev.Txs)) + case <-time.After(5 * time.Second): + t.Errorf("reannouce event not fired") + } +} + // Benchmarks the speed of validating the contents of the pending queue of the // transaction pool. func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } diff --git a/core/types/transaction.go b/core/types/transaction.go index b127cb2af6..74c011544b 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -82,6 +82,11 @@ type TxData interface { setSignatureValues(chainID, v, r, s *big.Int) } +// Time returns transaction's time +func (tx *Transaction) Time() time.Time { + return tx.time +} + // EncodeRLP implements rlp.Encoder func (tx *Transaction) EncodeRLP(w io.Writer) error { if tx.Type() == LegacyTxType { diff --git a/eth/handler.go b/eth/handler.go index f00f955b34..9eb448040b 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -73,6 +73,10 @@ type txPool interface { // SubscribeNewTxsEvent should return an event subscription of // NewTxsEvent and send events to the given channel. SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription + + // SubscribeReannoTxsEvent should return an event subscription of + // ReannoTxsEvent and send events to the given channel. + SubscribeReannoTxsEvent(chan<- core.ReannoTxsEvent) event.Subscription } // handlerConfig is the collection of initialization parameters to create a full @@ -120,6 +124,8 @@ type handler struct { eventMux *event.TypeMux txsCh chan core.NewTxsEvent txsSub event.Subscription + reannoTxsCh chan core.ReannoTxsEvent + reannoTxsSub event.Subscription minedBlockSub *event.TypeMuxSubscription whitelist map[uint64]common.Hash @@ -432,6 +438,12 @@ func (h *handler) Start(maxPeers int) { h.txsSub = h.txpool.SubscribeNewTxsEvent(h.txsCh) go h.txBroadcastLoop() + // announce local pending transactions again + h.wg.Add(1) + h.reannoTxsCh = make(chan core.ReannoTxsEvent, txChanSize) + h.reannoTxsSub = h.txpool.SubscribeReannoTxsEvent(h.reannoTxsCh) + go h.txReannounceLoop() + // broadcast mined blocks h.wg.Add(1) h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{}) @@ -445,6 +457,7 @@ func (h *handler) Start(maxPeers int) { func (h *handler) Stop() { h.txsSub.Unsubscribe() // quits txBroadcastLoop + h.reannoTxsSub.Unsubscribe() // quits txReannounceLoop h.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop // Quit chainSync and txsync64. @@ -549,6 +562,31 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { "tx packs", directPeers, "broadcast txs", directCount) } +// ReannounceTransactions will announce a batch of local pending transactions +// to a square root of all peers. +func (h *handler) ReannounceTransactions(txs types.Transactions) { + var ( + annoCount int // Count of announcements made + annos = make(map[*ethPeer][]common.Hash) // Set peer->hash to announce + ) + + // Announce transactions hash to a batch of peers + peersCount := uint(math.Sqrt(float64(h.peers.len()))) + peers := h.peers.headPeers(peersCount) + for _, tx := range txs { + for _, peer := range peers { + annos[peer] = append(annos[peer], tx.Hash()) + } + } + + for peer, hashes := range annos { + annoCount += len(hashes) + peer.AsyncSendPooledTransactionHashes(hashes) + } + log.Debug("Transaction reannounce", "txs", len(txs), + "announce packs", peersCount, "announced hashes", annoCount) +} + // minedBroadcastLoop sends mined blocks to connected peers. func (h *handler) minedBroadcastLoop() { defer h.wg.Done() @@ -573,3 +611,16 @@ func (h *handler) txBroadcastLoop() { } } } + +// txReannounceLoop announces local pending transactions to connected peers again. +func (h *handler) txReannounceLoop() { + defer h.wg.Done() + for { + select { + case event := <-h.reannoTxsCh: + h.ReannounceTransactions(event.Txs) + case <-h.reannoTxsSub.Err(): + return + } + } +} diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 271bae07c7..aad2c72b1b 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -450,6 +450,59 @@ func testTransactionPropagation(t *testing.T, protocol uint) { } } +// Tests that local pending transactions get propagated to peers. +func TestTransactionPendingReannounce(t *testing.T) { + t.Parallel() + + // Create a source handler to announce transactions from and a sink handler + // to receive them. + source := newTestHandler() + defer source.close() + + sink := newTestHandler() + defer sink.close() + sink.handler.acceptTxs = 1 // mark synced to accept transactions + + sourcePipe, sinkPipe := p2p.MsgPipe() + defer sourcePipe.Close() + defer sinkPipe.Close() + + sourcePeer := eth.NewPeer(eth.ETH65, p2p.NewPeer(enode.ID{0}, "", nil), sourcePipe, source.txpool) + sinkPeer := eth.NewPeer(eth.ETH65, p2p.NewPeer(enode.ID{0}, "", nil), sinkPipe, sink.txpool) + defer sourcePeer.Close() + defer sinkPeer.Close() + + go source.handler.runEthPeer(sourcePeer, func(peer *eth.Peer) error { + return eth.Handle((*ethHandler)(source.handler), peer) + }) + go sink.handler.runEthPeer(sinkPeer, func(peer *eth.Peer) error { + return eth.Handle((*ethHandler)(sink.handler), peer) + }) + + // Subscribe transaction pools + txCh := make(chan core.NewTxsEvent, 1024) + sub := sink.txpool.SubscribeNewTxsEvent(txCh) + defer sub.Unsubscribe() + + txs := make([]*types.Transaction, 64) + for nonce := range txs { + tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil) + tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) + + txs[nonce] = tx + } + source.txpool.ReannouceTransactions(txs) + + for arrived := 0; arrived < len(txs); { + select { + case event := <-txCh: + arrived += len(event.Txs) + case <-time.NewTimer(time.Second).C: + t.Errorf("sink: transaction propagation timed out: have %d, want %d", arrived, len(txs)) + } + } +} + // Tests that post eth protocol handshake, clients perform a mutual checkpoint // challenge to validate each other's chains. Hash mismatches, or missing ones // during a fast sync should lead to the peer getting dropped. diff --git a/eth/handler_test.go b/eth/handler_test.go index a90ef5c348..c3b7b769b2 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -48,8 +48,9 @@ var ( type testTxPool struct { pool map[common.Hash]*types.Transaction // Hash map of collected transactions - txFeed event.Feed // Notification feed to allow waiting for inclusion - lock sync.RWMutex // Protects the transaction pool + txFeed event.Feed // Notification feed to allow waiting for inclusion + reannoTxFeed event.Feed // Notification feed to trigger reannouce + lock sync.RWMutex // Protects the transaction pool } // newTestTxPool creates a mock transaction pool. @@ -90,6 +91,18 @@ func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error { return make([]error, len(txs)) } +// ReannouceTransactions announce the transactions to some peers. +func (p *testTxPool) ReannouceTransactions(txs []*types.Transaction) []error { + p.lock.Lock() + defer p.lock.Unlock() + + for _, tx := range txs { + p.pool[tx.Hash()] = tx + } + p.reannoTxFeed.Send(core.ReannoTxsEvent{Txs: txs}) + return make([]error, len(txs)) +} + // Pending returns all the transactions known to the pool func (p *testTxPool) Pending() (map[common.Address]types.Transactions, error) { p.lock.RLock() @@ -112,6 +125,12 @@ func (p *testTxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subs return p.txFeed.Subscribe(ch) } +// SubscribeReannoTxsEvent should return an event subscription of ReannoTxsEvent and +// send events to the given channel. +func (p *testTxPool) SubscribeReannoTxsEvent(ch chan<- core.ReannoTxsEvent) event.Subscription { + return p.reannoTxFeed.Subscribe(ch) +} + // testHandler is a live implementation of the Ethereum protocol handler, just // preinitialized with some sane testing defaults and the transaction pool mocked // out. diff --git a/eth/peerset.go b/eth/peerset.go index f0955f34c6..220b01d832 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -266,6 +266,22 @@ func (ps *peerSet) peer(id string) *ethPeer { return ps.peers[id] } +// headPeers retrieves a specified number list of peers. +func (ps *peerSet) headPeers(num uint) []*ethPeer { + ps.lock.RLock() + defer ps.lock.RUnlock() + + if num > uint(len(ps.peers)) { + num = uint(len(ps.peers)) + } + + list := make([]*ethPeer, 0, num) + for _, p := range ps.peers { + list = append(list, p) + } + return list +} + // peersWithoutBlock retrieves a list of peers that do not have a given block in // their set of known hashes so it might be propagated to them. func (ps *peerSet) peersWithoutBlock(hash common.Hash) []*ethPeer { From 333708122279146e16bf48e17726317af8259be5 Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Fri, 26 Nov 2021 18:48:56 +0800 Subject: [PATCH 061/117] [R4R] pre-release ci flow (#594) * ci: add pre release ci flow * ci: fix change log format --- .github/generate_change_log.sh | 2 +- .github/workflows/pre-release.yml | 183 ++++++++++++++++++++++++++++++ .github/workflows/release.yml | 6 +- 3 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/pre-release.yml diff --git a/.github/generate_change_log.sh b/.github/generate_change_log.sh index 09332b7911..ab8ffff689 100755 --- a/.github/generate_change_log.sh +++ b/.github/generate_change_log.sh @@ -15,7 +15,7 @@ while read line; do if [[ $line == *"$version_prefix"* ]] && [ $start == 1 ]; then break; fi - if [ $start == 1 ] && [[ $line != "" ]]; then + if [ $start == 1 ]; then CHANGE_LOG+="$line\n" fi done < ${change_log_file} diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 0000000000..888fe90096 --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,183 @@ +name: Pre Release + +on: + push: + tags: + - 'pre-*' + +jobs: + build: + name: Build Release + strategy: + matrix: + go-version: [1.16.x] + os: [ubuntu-18.04, macos-11, windows-2019] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - uses: actions/cache@v2 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + # * Build cache (Mac) + # * Build cache (Windows) + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + %LocalAppData%\go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + # ============================== + # Linux/Macos/Windows Build + # ============================== + + - name: Build Binary for ${{matrix.os}} + run: make geth + + # ============================== + # Upload artifacts + # ============================== + + - name: Upload Linux Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: linux + path: ./build/bin/geth + + - name: Upload MacOS Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'macos-11' + with: + name: macos + path: ./build/bin/geth + + - name: Upload Windows Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'windows-2019' + with: + name: windows + path: ./build/bin/geth.exe + + release: + name: Release + needs: build + runs-on: ubuntu-18.04 + steps: + - name: Set Env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + + - name: Checkout Code + uses: actions/checkout@v2 + + # ============================== + # Download artifacts + # ============================== + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: linux + path: ./linux + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: macos + path: ./macos + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: windows + path: ./windows + + - name: Download Config File + run: | + . ./.github/release.env + echo "mainnet.zip url: $MAINNET_FILE_URL" + echo "testnet.zip url: $TESTNET_FILE_URL" + curl -L $MAINNET_FILE_URL -o ./mainnet.zip + curl -L $TESTNET_FILE_URL -o ./testnet.zip + + # ============================== + # Create release + # ============================== + + - name: Create Release + id: create_release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + body: | + versing: ${{ env.RELEASE_VERSION}} + git commit: ${{ github.sha }} + draft: true + prerelease: true + + # Check downloaded files + - run: ls + + - name: Upload Release Asset - Linux + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./linux/geth + asset_name: geth_linux + asset_content_type: application/octet-stream + + - name: Upload Release Asset - MacOS + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./macos/geth + asset_name: geth_mac + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Windows + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./windows/geth.exe + asset_name: geth_windows.exe + asset_content_type: application/octet-stream + + - name: Upload Release Asset - MAINNET.ZIP + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./mainnet.zip + asset_name: mainnet.zip + asset_content_type: application/zip + + - name: Upload Release Asset - TESTNET.ZIP + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./testnet.zip + asset_name: testnet.zip + asset_content_type: application/zip diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1633752c23..77cbbee725 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,14 +15,14 @@ jobs: os: [ubuntu-18.04, macos-11, windows-2019] runs-on: ${{ matrix.os }} steps: + - name: Checkout Code + uses: actions/checkout@v2 + - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - - name: Checkout Code - uses: actions/checkout@v2 - - uses: actions/cache@v2 with: # In order: From a9ac3175716c91d107eda10c7b6035d2e9bcd6b1 Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Mon, 29 Nov 2021 10:59:36 +0800 Subject: [PATCH 062/117] prepare for release v.1.1.6 (#603) --- CHANGELOG.md | 11 +++++++++++ params/version.go | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b0b345db0..babc9e3c22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ # Changelog + +## v1.1.6 +BUGFIX +* [\#582](https://github.com/binance-chain/bsc/pull/582) the DoS vulnerabilities fixed in go-ethereum v1.10.9 + +IMPROVEMENT +* [\#578](https://github.com/binance-chain/bsc/pull/578) reduce memory allocation and upgrade snappy version + +FEATURES +* [\#570](https://github.com/binance-chain/bsc/pull/570) reannounce local pending transactions + ## v1.1.5 BUGFIX * [\#509](https://github.com/binance-chain/bsc/pull/509) fix graceful shutdown bug diff --git a/params/version.go b/params/version.go index d15c2d94c5..1df331e96c 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release + VersionPatch = 6 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From cccd675148f1c46f80ff606610dc6eb6f9e9b101 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Wed, 24 Nov 2021 10:47:37 +0800 Subject: [PATCH 063/117] eth/protocols/snap, trie: better error-handling (#23657) (#582) Co-authored-by: Martin Holst Swende --- eth/protocols/snap/handler.go | 2 +- trie/trie.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 3d668a2ebb..d9935f455f 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -469,7 +469,7 @@ func handleMessage(backend Backend, peer *Peer) error { // 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 { + if err != nil || account == nil { break } stTrie, err := trie.NewSecure(common.BytesToHash(account.Root), triedb) diff --git a/trie/trie.go b/trie/trie.go index 44de1374a4..1e6e8fd250 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -174,6 +174,10 @@ func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) { } func (t *Trie) tryGetNode(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 + } // If we reached the requested path, return the current node if pos >= len(path) { // Although we most probably have the original node expanded, encoding @@ -193,10 +197,6 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new } // Path still needs to be traversed, descend into children switch n := (origNode).(type) { - case nil: - // Non-existent path requested, abort - return nil, nil, 0, nil - case valueNode: // Path prematurely ended, abort return nil, nil, 0, nil From c9f892cd6a05c8c733aa8f2626821b8d9bdc24eb Mon Sep 17 00:00:00 2001 From: flywukong <2229306838@qq.com> Date: Wed, 24 Nov 2021 14:23:54 +0800 Subject: [PATCH 064/117] go.mod: update goleveldb (#23417) (#578) Co-authored-by: ucwong --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 4ea9fc689a..c58a45dfd2 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect github.com/go-stack/stack v1.8.0 github.com/golang/protobuf v1.4.3 - github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 + github.com/golang/snappy v0.0.4 github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa github.com/google/uuid v1.1.5 github.com/gorilla/websocket v1.4.2 @@ -65,7 +65,7 @@ require ( 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/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tendermint/go-amino v0.14.1 github.com/tendermint/iavl v0.12.0 github.com/tendermint/tendermint v0.31.11 diff --git a/go.sum b/go.sum index e94241a414..6ab7ca8c45 100644 --- a/go.sum +++ b/go.sum @@ -186,8 +186,8 @@ 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/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/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/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= @@ -387,8 +387,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= -github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +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/tendermint/go-amino v0.14.1 h1:o2WudxNfdLNBwMyl2dqOJxiro5rfrEaU0Ugs6offJMk= github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= github.com/tendermint/iavl v0.12.0 h1:xcaFAr+ycqCj7WN1RzL2EfcBioRDOHcU1oWcg83K028= From 90fd01423ac2b7e61463e673df4732832fb7d435 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Thu, 25 Nov 2021 11:00:14 +0800 Subject: [PATCH 065/117] [R4R]reannounce local pending transactions (#570) * reannouce local pending transactions * add tests for tx_pool reannouce local pending transactions * add tests for handler reannounce local pending transactions --- cmd/geth/main.go | 1 + cmd/geth/usage.go | 1 + cmd/utils/flags.go | 8 +++++ core/events.go | 3 ++ core/tx_pool.go | 72 ++++++++++++++++++++++++++++++++------- core/tx_pool_test.go | 41 ++++++++++++++++++++++ core/types/transaction.go | 5 +++ eth/handler.go | 51 +++++++++++++++++++++++++++ eth/handler_eth_test.go | 53 ++++++++++++++++++++++++++++ eth/handler_test.go | 23 +++++++++++-- eth/peerset.go | 16 +++++++++ 11 files changed, 259 insertions(+), 15 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 8be8d20bf4..e896c7d659 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -90,6 +90,7 @@ var ( utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, + utils.TxPoolReannounceTimeFlag, utils.SyncModeFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 2a208c827b..fba14530b5 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -108,6 +108,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.TxPoolAccountQueueFlag, utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, + utils.TxPoolReannounceTimeFlag, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 49ea0d1de1..67632c031b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -398,6 +398,11 @@ var ( Usage: "Maximum amount of time non-executable transaction are queued", Value: ethconfig.Defaults.TxPool.Lifetime, } + TxPoolReannounceTimeFlag = cli.DurationFlag{ + Name: "txpool.reannouncetime", + Usage: "Duration for announcing local pending transactions again (default = 10 years, minimum = 1 minute)", + Value: ethconfig.Defaults.TxPool.ReannounceTime, + } // Performance tuning settings CacheFlag = cli.IntFlag{ Name: "cache", @@ -1410,6 +1415,9 @@ func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) } + if ctx.GlobalIsSet(TxPoolReannounceTimeFlag.Name) { + cfg.ReannounceTime = ctx.GlobalDuration(TxPoolReannounceTimeFlag.Name) + } } func setEthash(ctx *cli.Context, cfg *ethconfig.Config) { diff --git a/core/events.go b/core/events.go index ac935a137f..5e730a24a7 100644 --- a/core/events.go +++ b/core/events.go @@ -24,6 +24,9 @@ import ( // NewTxsEvent is posted when a batch of transactions enter the transaction pool. type NewTxsEvent struct{ Txs []*types.Transaction } +// ReannoTxsEvent is posted when a batch of local pending transactions exceed a specified duration. +type ReannoTxsEvent struct{ Txs []*types.Transaction } + // NewMinedBlockEvent is posted when a block has been imported. type NewMinedBlockEvent struct{ Block *types.Block } diff --git a/core/tx_pool.go b/core/tx_pool.go index d0304857c3..4c08bc72b3 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -49,6 +49,9 @@ const ( // more expensive to propagate; larger transactions also take more resources // to validate whether they fit into the pool or not. txMaxSize = 4 * txSlotSize // 128KB + + // txReannoMaxNum is the maximum number of transactions a reannounce action can include. + txReannoMaxNum = 1024 ) var ( @@ -88,6 +91,7 @@ var ( var ( evictionInterval = time.Minute // Time interval to check for evictable transactions statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats + reannounceInterval = time.Minute // Time interval to check for reannounce transactions ) var ( @@ -152,7 +156,8 @@ type TxPoolConfig struct { AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts - Lifetime time.Duration // Maximum amount of time non-executable transaction are queued + Lifetime time.Duration // Maximum amount of time non-executable transaction are queued + ReannounceTime time.Duration // Duration for announcing local pending transactions again } // DefaultTxPoolConfig contains the default configurations for the transaction @@ -169,7 +174,8 @@ var DefaultTxPoolConfig = TxPoolConfig{ AccountQueue: 64, GlobalQueue: 1024, - Lifetime: 3 * time.Hour, + Lifetime: 3 * time.Hour, + ReannounceTime: 10 * 365 * 24 * time.Hour, } // sanitize checks the provided user configurations and changes anything that's @@ -208,6 +214,10 @@ func (config *TxPoolConfig) sanitize() TxPoolConfig { log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultTxPoolConfig.Lifetime) conf.Lifetime = DefaultTxPoolConfig.Lifetime } + if conf.ReannounceTime < time.Minute { + log.Warn("Sanitizing invalid txpool reannounce time", "provided", conf.ReannounceTime, "updated", time.Minute) + conf.ReannounceTime = time.Minute + } return conf } @@ -219,14 +229,15 @@ 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 - chainconfig *params.ChainConfig - chain blockChain - gasPrice *big.Int - txFeed event.Feed - scope event.SubscriptionScope - signer types.Signer - mu sync.RWMutex + config TxPoolConfig + chainconfig *params.ChainConfig + chain blockChain + gasPrice *big.Int + txFeed event.Feed + reannoTxFeed event.Feed // Event feed for announcing transactions again + scope event.SubscriptionScope + 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. @@ -323,14 +334,16 @@ func (pool *TxPool) loop() { var ( prevPending, prevQueued, prevStales int // Start the stats reporting and transaction eviction tickers - report = time.NewTicker(statsReportInterval) - evict = time.NewTicker(evictionInterval) - journal = time.NewTicker(pool.config.Rejournal) + report = time.NewTicker(statsReportInterval) + evict = time.NewTicker(evictionInterval) + reannounce = time.NewTicker(reannounceInterval) + journal = time.NewTicker(pool.config.Rejournal) // Track the previous head headers for transaction reorgs head = pool.chain.CurrentBlock() ) defer report.Stop() defer evict.Stop() + defer reannounce.Stop() defer journal.Stop() for { @@ -378,6 +391,33 @@ func (pool *TxPool) loop() { } pool.mu.Unlock() + case <-reannounce.C: + pool.mu.RLock() + reannoTxs := func() []*types.Transaction { + txs := make([]*types.Transaction, 0) + for addr, list := range pool.pending { + if !pool.locals.contains(addr) { + continue + } + + for _, tx := range list.Flatten() { + // Default ReannounceTime is 10 years, won't announce by default. + if time.Since(tx.Time()) < pool.config.ReannounceTime { + break + } + txs = append(txs, tx) + if len(txs) >= txReannoMaxNum { + return txs + } + } + } + return txs + }() + pool.mu.RUnlock() + if len(reannoTxs) > 0 { + pool.reannoTxFeed.Send(ReannoTxsEvent{reannoTxs}) + } + // Handle local transaction journal rotation case <-journal.C: if pool.journal != nil { @@ -412,6 +452,12 @@ func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscripti return pool.scope.Track(pool.txFeed.Subscribe(ch)) } +// SubscribeReannoTxsEvent registers a subscription of ReannoTxsEvent and +// starts sending event to the given channel. +func (pool *TxPool) SubscribeReannoTxsEvent(ch chan<- ReannoTxsEvent) event.Subscription { + return pool.scope.Track(pool.reannoTxFeed.Subscribe(ch)) +} + // GasPrice returns the current gas price enforced by the transaction pool. func (pool *TxPool) GasPrice() *big.Int { pool.mu.RLock() diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 5d555f5a9c..5f27631e15 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -1933,6 +1933,47 @@ func TestTransactionSlotCount(t *testing.T) { } } +// Tests the local pending transaction announced again correctly. +func TestTransactionPendingReannouce(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{statedb, 1000000, new(event.Feed)} + + config := testTxPoolConfig + // This ReannounceTime will be modified to time.Minute when creating tx_pool. + config.ReannounceTime = time.Second + reannounceInterval = time.Second + + pool := NewTxPool(config, params.TestChainConfig, blockchain) + // Modify ReannounceTime to trigger quicker. + pool.config.ReannounceTime = time.Second + defer pool.Stop() + + key, _ := crypto.GenerateKey() + account := crypto.PubkeyToAddress(key.PublicKey) + pool.currentState.AddBalance(account, big.NewInt(1000000)) + + events := make(chan ReannoTxsEvent, testTxPoolConfig.AccountQueue) + sub := pool.reannoTxFeed.Subscribe(events) + defer sub.Unsubscribe() + + // Generate a batch of transactions and add to tx_pool locally. + txs := make([]*types.Transaction, 0, testTxPoolConfig.AccountQueue) + for i := uint64(0); i < testTxPoolConfig.AccountQueue; i++ { + txs = append(txs, transaction(i, 100000, key)) + } + pool.AddLocals(txs) + + select { + case ev := <-events: + t.Logf("received reannouce event, txs length: %d", len(ev.Txs)) + case <-time.After(5 * time.Second): + t.Errorf("reannouce event not fired") + } +} + // Benchmarks the speed of validating the contents of the pending queue of the // transaction pool. func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } diff --git a/core/types/transaction.go b/core/types/transaction.go index b127cb2af6..74c011544b 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -82,6 +82,11 @@ type TxData interface { setSignatureValues(chainID, v, r, s *big.Int) } +// Time returns transaction's time +func (tx *Transaction) Time() time.Time { + return tx.time +} + // EncodeRLP implements rlp.Encoder func (tx *Transaction) EncodeRLP(w io.Writer) error { if tx.Type() == LegacyTxType { diff --git a/eth/handler.go b/eth/handler.go index f00f955b34..9eb448040b 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -73,6 +73,10 @@ type txPool interface { // SubscribeNewTxsEvent should return an event subscription of // NewTxsEvent and send events to the given channel. SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription + + // SubscribeReannoTxsEvent should return an event subscription of + // ReannoTxsEvent and send events to the given channel. + SubscribeReannoTxsEvent(chan<- core.ReannoTxsEvent) event.Subscription } // handlerConfig is the collection of initialization parameters to create a full @@ -120,6 +124,8 @@ type handler struct { eventMux *event.TypeMux txsCh chan core.NewTxsEvent txsSub event.Subscription + reannoTxsCh chan core.ReannoTxsEvent + reannoTxsSub event.Subscription minedBlockSub *event.TypeMuxSubscription whitelist map[uint64]common.Hash @@ -432,6 +438,12 @@ func (h *handler) Start(maxPeers int) { h.txsSub = h.txpool.SubscribeNewTxsEvent(h.txsCh) go h.txBroadcastLoop() + // announce local pending transactions again + h.wg.Add(1) + h.reannoTxsCh = make(chan core.ReannoTxsEvent, txChanSize) + h.reannoTxsSub = h.txpool.SubscribeReannoTxsEvent(h.reannoTxsCh) + go h.txReannounceLoop() + // broadcast mined blocks h.wg.Add(1) h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{}) @@ -445,6 +457,7 @@ func (h *handler) Start(maxPeers int) { func (h *handler) Stop() { h.txsSub.Unsubscribe() // quits txBroadcastLoop + h.reannoTxsSub.Unsubscribe() // quits txReannounceLoop h.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop // Quit chainSync and txsync64. @@ -549,6 +562,31 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { "tx packs", directPeers, "broadcast txs", directCount) } +// ReannounceTransactions will announce a batch of local pending transactions +// to a square root of all peers. +func (h *handler) ReannounceTransactions(txs types.Transactions) { + var ( + annoCount int // Count of announcements made + annos = make(map[*ethPeer][]common.Hash) // Set peer->hash to announce + ) + + // Announce transactions hash to a batch of peers + peersCount := uint(math.Sqrt(float64(h.peers.len()))) + peers := h.peers.headPeers(peersCount) + for _, tx := range txs { + for _, peer := range peers { + annos[peer] = append(annos[peer], tx.Hash()) + } + } + + for peer, hashes := range annos { + annoCount += len(hashes) + peer.AsyncSendPooledTransactionHashes(hashes) + } + log.Debug("Transaction reannounce", "txs", len(txs), + "announce packs", peersCount, "announced hashes", annoCount) +} + // minedBroadcastLoop sends mined blocks to connected peers. func (h *handler) minedBroadcastLoop() { defer h.wg.Done() @@ -573,3 +611,16 @@ func (h *handler) txBroadcastLoop() { } } } + +// txReannounceLoop announces local pending transactions to connected peers again. +func (h *handler) txReannounceLoop() { + defer h.wg.Done() + for { + select { + case event := <-h.reannoTxsCh: + h.ReannounceTransactions(event.Txs) + case <-h.reannoTxsSub.Err(): + return + } + } +} diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 271bae07c7..aad2c72b1b 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -450,6 +450,59 @@ func testTransactionPropagation(t *testing.T, protocol uint) { } } +// Tests that local pending transactions get propagated to peers. +func TestTransactionPendingReannounce(t *testing.T) { + t.Parallel() + + // Create a source handler to announce transactions from and a sink handler + // to receive them. + source := newTestHandler() + defer source.close() + + sink := newTestHandler() + defer sink.close() + sink.handler.acceptTxs = 1 // mark synced to accept transactions + + sourcePipe, sinkPipe := p2p.MsgPipe() + defer sourcePipe.Close() + defer sinkPipe.Close() + + sourcePeer := eth.NewPeer(eth.ETH65, p2p.NewPeer(enode.ID{0}, "", nil), sourcePipe, source.txpool) + sinkPeer := eth.NewPeer(eth.ETH65, p2p.NewPeer(enode.ID{0}, "", nil), sinkPipe, sink.txpool) + defer sourcePeer.Close() + defer sinkPeer.Close() + + go source.handler.runEthPeer(sourcePeer, func(peer *eth.Peer) error { + return eth.Handle((*ethHandler)(source.handler), peer) + }) + go sink.handler.runEthPeer(sinkPeer, func(peer *eth.Peer) error { + return eth.Handle((*ethHandler)(sink.handler), peer) + }) + + // Subscribe transaction pools + txCh := make(chan core.NewTxsEvent, 1024) + sub := sink.txpool.SubscribeNewTxsEvent(txCh) + defer sub.Unsubscribe() + + txs := make([]*types.Transaction, 64) + for nonce := range txs { + tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil) + tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) + + txs[nonce] = tx + } + source.txpool.ReannouceTransactions(txs) + + for arrived := 0; arrived < len(txs); { + select { + case event := <-txCh: + arrived += len(event.Txs) + case <-time.NewTimer(time.Second).C: + t.Errorf("sink: transaction propagation timed out: have %d, want %d", arrived, len(txs)) + } + } +} + // Tests that post eth protocol handshake, clients perform a mutual checkpoint // challenge to validate each other's chains. Hash mismatches, or missing ones // during a fast sync should lead to the peer getting dropped. diff --git a/eth/handler_test.go b/eth/handler_test.go index a90ef5c348..c3b7b769b2 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -48,8 +48,9 @@ var ( type testTxPool struct { pool map[common.Hash]*types.Transaction // Hash map of collected transactions - txFeed event.Feed // Notification feed to allow waiting for inclusion - lock sync.RWMutex // Protects the transaction pool + txFeed event.Feed // Notification feed to allow waiting for inclusion + reannoTxFeed event.Feed // Notification feed to trigger reannouce + lock sync.RWMutex // Protects the transaction pool } // newTestTxPool creates a mock transaction pool. @@ -90,6 +91,18 @@ func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error { return make([]error, len(txs)) } +// ReannouceTransactions announce the transactions to some peers. +func (p *testTxPool) ReannouceTransactions(txs []*types.Transaction) []error { + p.lock.Lock() + defer p.lock.Unlock() + + for _, tx := range txs { + p.pool[tx.Hash()] = tx + } + p.reannoTxFeed.Send(core.ReannoTxsEvent{Txs: txs}) + return make([]error, len(txs)) +} + // Pending returns all the transactions known to the pool func (p *testTxPool) Pending() (map[common.Address]types.Transactions, error) { p.lock.RLock() @@ -112,6 +125,12 @@ func (p *testTxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subs return p.txFeed.Subscribe(ch) } +// SubscribeReannoTxsEvent should return an event subscription of ReannoTxsEvent and +// send events to the given channel. +func (p *testTxPool) SubscribeReannoTxsEvent(ch chan<- core.ReannoTxsEvent) event.Subscription { + return p.reannoTxFeed.Subscribe(ch) +} + // testHandler is a live implementation of the Ethereum protocol handler, just // preinitialized with some sane testing defaults and the transaction pool mocked // out. diff --git a/eth/peerset.go b/eth/peerset.go index f0955f34c6..220b01d832 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -266,6 +266,22 @@ func (ps *peerSet) peer(id string) *ethPeer { return ps.peers[id] } +// headPeers retrieves a specified number list of peers. +func (ps *peerSet) headPeers(num uint) []*ethPeer { + ps.lock.RLock() + defer ps.lock.RUnlock() + + if num > uint(len(ps.peers)) { + num = uint(len(ps.peers)) + } + + list := make([]*ethPeer, 0, num) + for _, p := range ps.peers { + list = append(list, p) + } + return list +} + // peersWithoutBlock retrieves a list of peers that do not have a given block in // their set of known hashes so it might be propagated to them. func (ps *peerSet) peersWithoutBlock(hash common.Hash) []*ethPeer { From aff68c35a438aeb6b875737447a96930a5b03459 Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Fri, 26 Nov 2021 18:48:56 +0800 Subject: [PATCH 066/117] [R4R] pre-release ci flow (#594) * ci: add pre release ci flow * ci: fix change log format --- .github/generate_change_log.sh | 2 +- .github/workflows/pre-release.yml | 183 ++++++++++++++++++++++++++++++ .github/workflows/release.yml | 6 +- 3 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/pre-release.yml diff --git a/.github/generate_change_log.sh b/.github/generate_change_log.sh index 09332b7911..ab8ffff689 100755 --- a/.github/generate_change_log.sh +++ b/.github/generate_change_log.sh @@ -15,7 +15,7 @@ while read line; do if [[ $line == *"$version_prefix"* ]] && [ $start == 1 ]; then break; fi - if [ $start == 1 ] && [[ $line != "" ]]; then + if [ $start == 1 ]; then CHANGE_LOG+="$line\n" fi done < ${change_log_file} diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 0000000000..888fe90096 --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,183 @@ +name: Pre Release + +on: + push: + tags: + - 'pre-*' + +jobs: + build: + name: Build Release + strategy: + matrix: + go-version: [1.16.x] + os: [ubuntu-18.04, macos-11, windows-2019] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - uses: actions/cache@v2 + with: + # In order: + # * Module download cache + # * Build cache (Linux) + # * Build cache (Mac) + # * Build cache (Windows) + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + %LocalAppData%\go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + # ============================== + # Linux/Macos/Windows Build + # ============================== + + - name: Build Binary for ${{matrix.os}} + run: make geth + + # ============================== + # Upload artifacts + # ============================== + + - name: Upload Linux Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: linux + path: ./build/bin/geth + + - name: Upload MacOS Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'macos-11' + with: + name: macos + path: ./build/bin/geth + + - name: Upload Windows Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'windows-2019' + with: + name: windows + path: ./build/bin/geth.exe + + release: + name: Release + needs: build + runs-on: ubuntu-18.04 + steps: + - name: Set Env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + + - name: Checkout Code + uses: actions/checkout@v2 + + # ============================== + # Download artifacts + # ============================== + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: linux + path: ./linux + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: macos + path: ./macos + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: windows + path: ./windows + + - name: Download Config File + run: | + . ./.github/release.env + echo "mainnet.zip url: $MAINNET_FILE_URL" + echo "testnet.zip url: $TESTNET_FILE_URL" + curl -L $MAINNET_FILE_URL -o ./mainnet.zip + curl -L $TESTNET_FILE_URL -o ./testnet.zip + + # ============================== + # Create release + # ============================== + + - name: Create Release + id: create_release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + body: | + versing: ${{ env.RELEASE_VERSION}} + git commit: ${{ github.sha }} + draft: true + prerelease: true + + # Check downloaded files + - run: ls + + - name: Upload Release Asset - Linux + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./linux/geth + asset_name: geth_linux + asset_content_type: application/octet-stream + + - name: Upload Release Asset - MacOS + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./macos/geth + asset_name: geth_mac + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Windows + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./windows/geth.exe + asset_name: geth_windows.exe + asset_content_type: application/octet-stream + + - name: Upload Release Asset - MAINNET.ZIP + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./mainnet.zip + asset_name: mainnet.zip + asset_content_type: application/zip + + - name: Upload Release Asset - TESTNET.ZIP + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./testnet.zip + asset_name: testnet.zip + asset_content_type: application/zip diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1633752c23..77cbbee725 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,14 +15,14 @@ jobs: os: [ubuntu-18.04, macos-11, windows-2019] runs-on: ${{ matrix.os }} steps: + - name: Checkout Code + uses: actions/checkout@v2 + - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - - name: Checkout Code - uses: actions/checkout@v2 - - uses: actions/cache@v2 with: # In order: From 0b575443c43f47f2f50ed5549d2bcaf7ccc39ab4 Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Mon, 29 Nov 2021 10:59:36 +0800 Subject: [PATCH 067/117] prepare for release v.1.1.6 (#603) --- CHANGELOG.md | 11 +++++++++++ params/version.go | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b0b345db0..babc9e3c22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ # Changelog + +## v1.1.6 +BUGFIX +* [\#582](https://github.com/binance-chain/bsc/pull/582) the DoS vulnerabilities fixed in go-ethereum v1.10.9 + +IMPROVEMENT +* [\#578](https://github.com/binance-chain/bsc/pull/578) reduce memory allocation and upgrade snappy version + +FEATURES +* [\#570](https://github.com/binance-chain/bsc/pull/570) reannounce local pending transactions + ## v1.1.5 BUGFIX * [\#509](https://github.com/binance-chain/bsc/pull/509) fix graceful shutdown bug diff --git a/params/version.go b/params/version.go index d15c2d94c5..1df331e96c 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release + VersionPatch = 6 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From ec8d46e05987e6bf9c5b31de100e1a2141391882 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Fri, 3 Dec 2021 13:43:39 +0800 Subject: [PATCH 068/117] reorganize the logic of reannouncing transactions (#620) --- eth/handler.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/eth/handler.go b/eth/handler.go index 9eb448040b..cbc6eca809 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -565,26 +565,19 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { // ReannounceTransactions will announce a batch of local pending transactions // to a square root of all peers. func (h *handler) ReannounceTransactions(txs types.Transactions) { - var ( - annoCount int // Count of announcements made - annos = make(map[*ethPeer][]common.Hash) // Set peer->hash to announce - ) + hashes := make([]common.Hash, 0, txs.Len()) + for _, tx := range txs { + hashes = append(hashes, tx.Hash()) + } // Announce transactions hash to a batch of peers peersCount := uint(math.Sqrt(float64(h.peers.len()))) peers := h.peers.headPeers(peersCount) - for _, tx := range txs { - for _, peer := range peers { - annos[peer] = append(annos[peer], tx.Hash()) - } - } - - for peer, hashes := range annos { - annoCount += len(hashes) + for _, peer := range peers { peer.AsyncSendPooledTransactionHashes(hashes) } log.Debug("Transaction reannounce", "txs", len(txs), - "announce packs", peersCount, "announced hashes", annoCount) + "announce packs", peersCount, "announced hashes", peersCount*uint(len(hashes))) } // minedBroadcastLoop sends mined blocks to connected peers. From a8618952fdd6eb213488c48ad291261f7d47be0a Mon Sep 17 00:00:00 2001 From: guagualvcha <296179868@qq.com> Date: Sun, 5 Dec 2021 01:13:56 +0800 Subject: [PATCH 069/117] fix state inconsistent between snapshot and MPT when doing diffsync --- core/blockchain_diff_test.go | 115 ++++++++++++++++++++++++++++++----- core/state_processor.go | 2 +- 2 files changed, 101 insertions(+), 16 deletions(-) diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index 8e04363d0c..facd86b52b 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -21,6 +21,8 @@ package core import ( + "bytes" + "encoding/hex" "math/big" "testing" "time" @@ -42,9 +44,43 @@ import ( var ( // testKey is a private key to use for funding a tester account. - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + contractCode, _ = hex.DecodeString("608060405260016000806101000a81548160ff02191690831515021790555034801561002a57600080fd5b506101688061003a6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806389a2d8011461003b578063b0483f4814610059575b600080fd5b610043610075565b60405161005091906100f4565b60405180910390f35b610073600480360381019061006e91906100bc565b61008b565b005b60008060009054906101000a900460ff16905090565b806000806101000a81548160ff02191690831515021790555050565b6000813590506100b68161011b565b92915050565b6000602082840312156100ce57600080fd5b60006100dc848285016100a7565b91505092915050565b6100ee8161010f565b82525050565b600060208201905061010960008301846100e5565b92915050565b60008115159050919050565b6101248161010f565b811461012f57600080fd5b5056fea264697066735822122092f788b569bfc3786e90601b5dbec01cfc3d76094164fd66ca7d599c4239fc5164736f6c63430008000033") + contractAddr = common.HexToAddress("0xe74a3c7427cda785e0000d42a705b1f3fd371e09") + contractSlot = common.HexToHash("0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") + contractData1, _ = hex.DecodeString("b0483f480000000000000000000000000000000000000000000000000000000000000000") + contractData2, _ = hex.DecodeString("b0483f480000000000000000000000000000000000000000000000000000000000000001") + commonGas = 192138 // testAddr is the Ethereum address of the tester account. testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + + checkBlocks = map[int]checkBlockParam{ + 12: { + txs: []checkTransactionParam{ + { + to: &contractAddr, + slot: contractSlot, + value: []byte{01}, + }, + }}, + + 13: { + txs: []checkTransactionParam{ + { + to: &contractAddr, + slot: contractSlot, + value: []byte{}, + }, + }}, + 14: { + txs: []checkTransactionParam{ + { + to: &contractAddr, + slot: contractSlot, + value: []byte{01}, + }, + }}, + } // testBlocks is the test parameters array for specific blocks. testBlocks = []testBlockParam{ { @@ -52,7 +88,7 @@ var ( blockNr: 11, txs: []testTransactionParam{ { - to: common.Address{0x01}, + to: &common.Address{0x01}, value: big.NewInt(1), gasPrice: big.NewInt(1), data: nil, @@ -63,51 +99,74 @@ var ( blockNr: 12, txs: []testTransactionParam{ { - to: common.Address{0x01}, + to: &common.Address{0x01}, value: big.NewInt(1), gasPrice: big.NewInt(1), data: nil, }, { - to: common.Address{0x02}, + to: &common.Address{0x02}, value: big.NewInt(2), gasPrice: big.NewInt(2), data: nil, }, + { + to: nil, + value: big.NewInt(0), + gasPrice: big.NewInt(2), + data: contractCode, + }, }, }, { blockNr: 13, txs: []testTransactionParam{ { - to: common.Address{0x01}, + to: &common.Address{0x01}, value: big.NewInt(1), gasPrice: big.NewInt(1), data: nil, }, { - to: common.Address{0x02}, + to: &common.Address{0x02}, value: big.NewInt(2), gasPrice: big.NewInt(2), data: nil, }, { - to: common.Address{0x03}, + to: &common.Address{0x03}, value: big.NewInt(3), gasPrice: big.NewInt(3), data: nil, }, + { + to: &contractAddr, + value: big.NewInt(0), + gasPrice: big.NewInt(3), + data: contractData1, + }, }, }, { blockNr: 14, + txs: []testTransactionParam{ + { + to: &contractAddr, + value: big.NewInt(0), + gasPrice: big.NewInt(3), + data: contractData2, + }, + }, + }, + { + blockNr: 15, txs: []testTransactionParam{}, }, } ) type testTransactionParam struct { - to common.Address + to *common.Address value *big.Int gasPrice *big.Int data []byte @@ -118,6 +177,16 @@ type testBlockParam struct { txs []testTransactionParam } +type checkTransactionParam struct { + to *common.Address + slot common.Hash + value []byte +} + +type checkBlockParam struct { + txs []checkTransactionParam +} + // 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. @@ -153,8 +222,15 @@ func newTestBackendWithGenerator(blocks int, lightProcess bool) *testBackend { // Specific block setting, the index in this generator has 1 diff from specified blockNr. if i+1 == testBlock.blockNr { for _, testTransaction := range testBlock.txs { - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, - testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) + var transaction *types.Transaction + if testTransaction.to == nil { + transaction = types.NewContractCreation(block.TxNonce(testAddr), + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data) + } else { + transaction = types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data) + } + tx, err := types.SignTx(transaction, signer, testKey) if err != nil { panic(err) } @@ -168,8 +244,8 @@ func newTestBackendWithGenerator(blocks int, lightProcess bool) *testBackend { // We want to simulate an empty middle block, having the same state as the // first one. The last is needs a state change again to force a reorg. for _, testTransaction := range testBlocks[0].txs { - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, - testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data), signer, testKey) if err != nil { panic(err) } @@ -241,6 +317,14 @@ func TestProcessDiffLayer(t *testing.T) { lightBackend.Chain().HandleDiffLayer(diff, "testpid", true) } _, err := lightBackend.chain.insertChain([]*types.Block{block}, true) + if checks, exist := checkBlocks[i]; exist { + for _, check := range checks.txs { + s, _ := lightBackend.Chain().Snapshots().Snapshot(block.Root()).Storage(crypto.Keccak256Hash((*check.to)[:]), check.slot) + if !bytes.Equal(s, check.value) { + t.Fatalf("Expected value %x, get %x", check.value, s) + } + } + } if err != nil { t.Errorf("failed to insert block %v", err) } @@ -385,13 +469,14 @@ func TestGetDiffAccounts(t *testing.T) { t.Errorf("the diff accounts does't include addr: %v", testAddr) } } - for _, transaction := range testBlock.txs { + if transaction.to == nil || len(transaction.data) > 0 { + continue + } for idx, account := range accounts { - if transaction.to == account { + if *transaction.to == account { break } - if idx == len(accounts)-1 { t.Errorf("the diff accounts does't include addr: %v", transaction.to) } diff --git a/core/state_processor.go b/core/state_processor.go index 9f2a09bd36..6ca99f2eec 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -253,7 +253,7 @@ func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *ty //update storage latestRoot := common.BytesToHash(latestAccount.Root) - if latestRoot != previousAccount.Root && latestRoot != types.EmptyRootHash { + if latestRoot != previousAccount.Root { accountTrie, err := statedb.Database().OpenStorageTrie(addrHash, previousAccount.Root) if err != nil { errChan <- err From 2bf7d669ea47806ab7989f00e7470308e2a0dd71 Mon Sep 17 00:00:00 2001 From: guagualvcha <296179868@qq.com> Date: Sun, 5 Dec 2021 11:55:59 +0800 Subject: [PATCH 070/117] change the release env --- .github/release.env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/release.env b/.github/release.env index c65f709a26..37739d157e 100644 --- a/.github/release.env +++ b/.github/release.env @@ -1,2 +1,2 @@ -MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.2/mainnet.zip" -TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.2/testnet.zip" +MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.6/mainnet.zip" +TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.6/testnet.zip" From d7e48bf8243ae397d1a807ceb496f662aa0fd463 Mon Sep 17 00:00:00 2001 From: guagualvcha <296179868@qq.com> Date: Sun, 5 Dec 2021 11:58:07 +0800 Subject: [PATCH 071/117] add change logs && prelease v1.1.7 --- CHANGELOG.md | 5 +++++ params/version.go | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index babc9e3c22..4d5bf0877f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## v1.1.7 + +BUGFIX +* [\#628](https://github.com/binance-chain/bsc/pull/628) fix state inconsistent when doing diffsync + ## v1.1.6 BUGFIX * [\#582](https://github.com/binance-chain/bsc/pull/582) the DoS vulnerabilities fixed in go-ethereum v1.10.9 diff --git a/params/version.go b/params/version.go index 1df331e96c..0cab1d8822 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release + VersionPatch = 7 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From 7c1c8e2e88d493be644be2ad2a1a90f69959de6d Mon Sep 17 00:00:00 2001 From: yutianwu Date: Mon, 13 Dec 2021 11:16:03 +0800 Subject: [PATCH 072/117] [R4R] add timeout for stopping p2p server (#643) * add timeout for stopping p2p server * extend extension wait time * add unit tests * fix lint issue --- eth/handler_eth_test.go | 70 +++++++++++++++++++++++++++++++++ eth/peerset.go | 36 +++++++++++++++-- eth/protocols/diff/handshake.go | 2 +- p2p/peer.go | 10 +++++ p2p/server.go | 16 +++++++- p2p/server_test.go | 23 +++++++++++ 6 files changed, 151 insertions(+), 6 deletions(-) diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index aad2c72b1b..e85c74e6f2 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -239,6 +239,76 @@ func testForkIDSplit(t *testing.T, protocol uint) { func TestRecvTransactions65(t *testing.T) { testRecvTransactions(t, eth.ETH65) } func TestRecvTransactions66(t *testing.T) { testRecvTransactions(t, eth.ETH66) } +func TestWaitDiffExtensionTimout(t *testing.T) { + t.Parallel() + + // Create a message handler, configure it to accept transactions and watch them + handler := newTestHandler() + defer handler.close() + + // Create a source peer to send messages through and a sink handler to receive them + _, p2pSink := p2p.MsgPipe() + defer p2pSink.Close() + + protos := []p2p.Protocol{ + { + Name: "diff", + Version: 1, + }, + } + + sink := eth.NewPeer(eth.ETH67, p2p.NewPeerWithProtocols(enode.ID{2}, protos, "", []p2p.Cap{ + { + Name: "diff", + Version: 1, + }, + }), p2pSink, nil) + defer sink.Close() + + err := handler.handler.runEthPeer(sink, func(peer *eth.Peer) error { + return eth.Handle((*ethHandler)(handler.handler), peer) + }) + + if err == nil || err.Error() != "peer wait timeout" { + t.Fatalf("error should be `peer wait timeout`") + } +} + +func TestWaitSnapExtensionTimout(t *testing.T) { + t.Parallel() + + // Create a message handler, configure it to accept transactions and watch them + handler := newTestHandler() + defer handler.close() + + // Create a source peer to send messages through and a sink handler to receive them + _, p2pSink := p2p.MsgPipe() + defer p2pSink.Close() + + protos := []p2p.Protocol{ + { + Name: "snap", + Version: 1, + }, + } + + sink := eth.NewPeer(eth.ETH67, p2p.NewPeerWithProtocols(enode.ID{2}, protos, "", []p2p.Cap{ + { + Name: "snap", + Version: 1, + }, + }), p2pSink, nil) + defer sink.Close() + + err := handler.handler.runEthPeer(sink, func(peer *eth.Peer) error { + return eth.Handle((*ethHandler)(handler.handler), peer) + }) + + if err == nil || err.Error() != "peer wait timeout" { + t.Fatalf("error should be `peer wait timeout`") + } +} + func testRecvTransactions(t *testing.T, protocol uint) { t.Parallel() diff --git a/eth/peerset.go b/eth/peerset.go index 220b01d832..0f5245a05e 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -20,6 +20,7 @@ import ( "errors" "math/big" "sync" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/eth/downloader" @@ -38,19 +39,28 @@ var ( // to the peer set, but one with the same id already exists. errPeerAlreadyRegistered = errors.New("peer already registered") + // errPeerWaitTimeout is returned if a peer waits extension for too long + errPeerWaitTimeout = errors.New("peer wait timeout") + // errPeerNotRegistered is returned if a peer is attempted to be removed from // a peer set, but no peer with the given id exists. 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") // errDiffWithoutEth is returned if a peer attempts to connect only on the - // diff protocol without advertizing the eth main protocol. + // diff protocol without advertising the eth main protocol. errDiffWithoutEth = errors.New("peer connected on diff without compatible eth support") ) +const ( + // extensionWaitTimeout is the maximum allowed time for the extension wait to + // complete before dropping the connection as malicious. + extensionWaitTimeout = 10 * time.Second +) + // peerSet represents the collection of active peers currently participating in // the `eth` protocol, with or without the `snap` extension. type peerSet struct { @@ -169,7 +179,16 @@ func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { ps.snapWait[id] = wait ps.lock.Unlock() - return <-wait, nil + select { + case peer := <-wait: + return peer, nil + + case <-time.After(extensionWaitTimeout): + ps.lock.Lock() + delete(ps.snapWait, id) + ps.lock.Unlock() + return nil, errPeerWaitTimeout + } } // waitDiffExtension blocks until all satellite protocols are connected and tracked @@ -203,7 +222,16 @@ func (ps *peerSet) waitDiffExtension(peer *eth.Peer) (*diff.Peer, error) { ps.diffWait[id] = wait ps.lock.Unlock() - return <-wait, nil + select { + case peer := <-wait: + return peer, nil + + case <-time.After(extensionWaitTimeout): + ps.lock.Lock() + delete(ps.diffWait, id) + ps.lock.Unlock() + return nil, errPeerWaitTimeout + } } func (ps *peerSet) GetDiffPeer(pid string) downloader.IDiffPeer { diff --git a/eth/protocols/diff/handshake.go b/eth/protocols/diff/handshake.go index 4198ea88a1..0f17fb9e8b 100644 --- a/eth/protocols/diff/handshake.go +++ b/eth/protocols/diff/handshake.go @@ -26,7 +26,7 @@ import ( const ( // handshakeTimeout is the maximum allowed time for the `diff` handshake to - // complete before dropping the connection.= as malicious. + // complete before dropping the connection as malicious. handshakeTimeout = 5 * time.Second ) diff --git a/p2p/peer.go b/p2p/peer.go index e057e689f6..3b633108db 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -129,6 +129,16 @@ func NewPeer(id enode.ID, name string, caps []Cap) *Peer { return peer } +// NewPeerWithProtocols returns a peer for testing purposes. +func NewPeerWithProtocols(id enode.ID, protocols []Protocol, name string, caps []Cap) *Peer { + pipe, _ := net.Pipe() + node := enode.SignNull(new(enr.Record), id) + conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name} + peer := newPeer(log.Root(), conn, protocols) + close(peer.closed) // ensures Disconnect doesn't block + return peer +} + // ID returns the node's public key. func (p *Peer) ID() enode.ID { return p.rw.node.ID() diff --git a/p2p/server.go b/p2p/server.go index dbaee12ea1..2a38550abf 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -63,6 +63,9 @@ const ( // Maximum amount of time allowed for writing a complete message. frameWriteTimeout = 20 * time.Second + + // Maximum time to wait before stop the p2p server + stopTimeout = 5 * time.Second ) var errServerStopped = errors.New("server stopped") @@ -403,7 +406,18 @@ func (srv *Server) Stop() { } close(srv.quit) srv.lock.Unlock() - srv.loopWG.Wait() + + stopChan := make(chan struct{}) + go func() { + srv.loopWG.Wait() + close(stopChan) + }() + + select { + case <-stopChan: + case <-time.After(stopTimeout): + srv.log.Warn("stop p2p server timeout, forcing stop") + } } // sharedUDPConn implements a shared connection. Write sends messages to the underlying connection while read returns diff --git a/p2p/server_test.go b/p2p/server_test.go index a5b3190aed..4ad8eb18e6 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -203,6 +203,29 @@ func TestServerDial(t *testing.T) { } } +func TestServerStopTimeout(t *testing.T) { + srv := &Server{Config: Config{ + PrivateKey: newkey(), + MaxPeers: 1, + NoDiscovery: true, + Logger: testlog.Logger(t, log.LvlTrace).New("server", "1"), + }} + srv.Start() + srv.loopWG.Add(1) + + stopChan := make(chan struct{}) + go func() { + srv.Stop() + close(stopChan) + }() + + select { + case <-stopChan: + case <-time.After(10 * time.Second): + t.Error("server should be shutdown in 10 seconds") + } +} + // This test checks that RemovePeer disconnects the peer if it is connected. func TestServerRemovePeerDisconnect(t *testing.T) { srv1 := &Server{Config: Config{ From 5218949ba96b6304919171286ab7af1814b37282 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Mon, 20 Dec 2021 12:15:34 +0800 Subject: [PATCH 073/117] trie: reject deletions when verifying range proofs (#667) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Péter Szilágyi --- trie/proof.go | 7 +++- trie/proof_test.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/trie/proof.go b/trie/proof.go index 08a9e40422..51ecea0c39 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -472,12 +472,17 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key if len(keys) != len(values) { return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values)) } - // Ensure the received batch is monotonic increasing. + // Ensure the received batch is monotonic increasing and contains no deletions for i := 0; i < len(keys)-1; i++ { if bytes.Compare(keys[i], keys[i+1]) >= 0 { return false, errors.New("range is not monotonically increasing") } } + for _, value := range values { + if len(value) == 0 { + return false, errors.New("range contains deletion") + } + } // Special case, there is no edge proof at all. The given range is expected // to be the whole leaf-set in the trie. if proof == nil { diff --git a/trie/proof_test.go b/trie/proof_test.go index a35b7144c0..95ad6169c3 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -813,6 +813,85 @@ func TestBloatedProof(t *testing.T) { } } +// TestEmptyValueRangeProof tests normal range proof with both edge proofs +// as the existent proof, but with an extra empty value included, which is a +// noop technically, but practically should be rejected. +func TestEmptyValueRangeProof(t *testing.T) { + trie, values := randomTrie(512) + var entries entrySlice + for _, kv := range values { + entries = append(entries, kv) + } + sort.Sort(entries) + + // Create a new entry with a slightly modified key + mid := len(entries) / 2 + key := common.CopyBytes(entries[mid-1].k) + for n := len(key) - 1; n >= 0; n-- { + if key[n] < 0xff { + key[n]++ + break + } + } + noop := &kv{key, []byte{}, false} + entries = append(append(append([]*kv{}, entries[:mid]...), noop), entries[mid:]...) + + start, end := 1, len(entries)-1 + + proof := memorydb.New() + if err := trie.Prove(entries[start].k, 0, proof); err != nil { + t.Fatalf("Failed to prove the first node %v", err) + } + if err := trie.Prove(entries[end-1].k, 0, proof); err != nil { + t.Fatalf("Failed to prove the last node %v", err) + } + var keys [][]byte + var vals [][]byte + for i := start; i < end; i++ { + keys = append(keys, entries[i].k) + vals = append(vals, entries[i].v) + } + _, err := VerifyRangeProof(trie.Hash(), keys[0], keys[len(keys)-1], keys, vals, proof) + if err == nil { + t.Fatalf("Expected failure on noop entry") + } +} + +// TestAllElementsEmptyValueRangeProof tests the range proof with all elements, +// but with an extra empty value included, which is a noop technically, but +// practically should be rejected. +func TestAllElementsEmptyValueRangeProof(t *testing.T) { + trie, values := randomTrie(512) + var entries entrySlice + for _, kv := range values { + entries = append(entries, kv) + } + sort.Sort(entries) + + // Create a new entry with a slightly modified key + mid := len(entries) / 2 + key := common.CopyBytes(entries[mid-1].k) + for n := len(key) - 1; n >= 0; n-- { + if key[n] < 0xff { + key[n]++ + break + } + } + noop := &kv{key, []byte{}, false} + entries = append(append(append([]*kv{}, entries[:mid]...), noop), entries[mid:]...) + + var keys [][]byte + var vals [][]byte + for i := 0; i < len(entries); i++ { + keys = append(keys, entries[i].k) + vals = append(vals, entries[i].v) + } + _, err := VerifyRangeProof(trie.Hash(), nil, nil, keys, vals, nil) + if err == nil { + t.Fatalf("Expected failure on noop entry") + } +} + // mutateByte changes one byte in b. func mutateByte(b []byte) { for r := mrand.Intn(len(b)); ; { From 50ad4e3f60ac2c35ed859eddb09f16666045def7 Mon Sep 17 00:00:00 2001 From: Delweng Date: Mon, 27 Dec 2021 10:09:12 +0800 Subject: [PATCH 074/117] [R4R]Feature/backport geth native trace (#581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * eth/tracers: implement debug.intermediateRoots (#23594) This PR implements a new debug method, which I've talked briefly about to some other client developers. It allows the caller to obtain the intermediate state roots for a block (which might be either a canon block or a 'bad' block). Signed-off-by: wenbiao * core, rpc: disable memory output by default in traces (#23558) * core: cmd: invert disableMemory * core: fix missed inversion * cmd/evm: preserve Flags but change default value * Apply suggestions from code review Co-authored-by: Martin Holst Swende Co-authored-by: Martin Holst Swende Signed-off-by: wenbiao * eth/tracers: abort evm execution when trace is aborted (#23580) Signed-off-by: wenbiao * eth/tracers: avoid unsyncronized mutations on trie database (#23632) This PR fixes an issue in traceChain, where the statedb Commit operation was performed asynchronously with dereference-operations agains the underlying trie.Database instance. Due to how the reference counting works within the trie database (where parent count is recursively updated when new parents are added), doing dereferencing in the middle of Commit can cause the refcount to become wrong, leading to an inconsistent state. This was fixed by doing Commit/Deref from the same routine. Signed-off-by: wenbiao * core,eth: call frame tracing (#23087) This change introduces 2 new optional methods; `enter()` and `exit()` for js tracers, and makes `step()` optiona. The two new methods are invoked when entering and exiting a call frame (but not invoked for the outermost scope, which has it's own methods). Currently these are the data fields passed to each of them: enter: type (opcode), from, to, input, gas, value exit: output, gasUsed, error The PR also comes with a re-write of the callTracer. As a backup we keep the previous tracing script under the name `callTracerLegacy`. Behaviour of both tracers are equivalent for the most part, although there are some small differences (improvements), where the new tracer is more correct / has more information. Signed-off-by: wenbiao * eth/tracers: re-write of 4byte tracer using enter/exit (#23622) * eth/tracers: add re-write of 4byte tracer using enter/exit * eth/tracers: fix 4byte indent Signed-off-by: wenbiao * eth/tracers: tx.BaseFee not implemented Signed-off-by: wenbiao * eth/tracers: do the JSON serialization via .js to capture C faults Signed-off-by: wenbiao * eth/tracers: fix callTracer fault handling (#23667) * eth/tracers: fix calltracer fault handling * eth/tracers: fix calltracer indentation Signed-off-by: wenbiao * eth/tracers: invoke enter/exit on 0-value calls to inex accounts (#23828) Signed-off-by: wenbiao * eth: make traceChain avoid OOM on long-running tracing (#23736) This PR changes long-running chain tracing, so that it at some points releases the memory trie db, and switch over to a fresh disk-backed trie. Signed-off-by: wenbiao * eth/tracers: expose contextual infos (block hash, tx hash, tx index) Signed-off-by: wenbiao * eth/tracers: redefine Context Signed-off-by: wenbiao * eth/tracers: support for golang tracers + add golang callTracer (#23708) * eth/tracers: add basic native loader * eth/tracers: add GetResult to tracer interface * eth/tracers: add native call tracer * eth/tracers: fix call tracer json result * eth/tracers: minor fix * eth/tracers: fix * eth/tracers: fix benchTracer * eth/tracers: test native call tracer * eth/tracers: fix * eth/tracers: rm extra make Co-authored-by: Martin Holst Swende * eth/tracers: rm extra make * eth/tracers: make callFrame private * eth/tracers: clean-up and comments * eth/tracers: add license * eth/tracers: rework the model a bit * eth/tracers: move tracecall tests to subpackage * cmd/geth: load native tracers * eth/tracers: minor fix * eth/tracers: impl stop * eth/tracers: add native noop tracer * renamings Co-authored-by: Martin Holst Swende * eth/tracers: more renamings * eth/tracers: make jstracer non-exported, avoid cast * eth/tracers, core/vm: rename vm.Tracer to vm.EVMLogger for clarity * eth/tracers: minor comment fix * eth/tracers/testing: lint nitpicks * core,eth: cancel evm on nativecalltracer stop * Revert "core,eth: cancel evm on nativecalltracer stop" This reverts commit 01bb908790a369c1bb9d3937df9325c6857bf855. * eth/tracers: linter nits * eth/tracers: fix output on err Co-authored-by: Martin Holst Swende Signed-off-by: wenbiao * eth/tracers: make native calltracer default (#23867) Signed-off-by: wenbiao * eth/tracers: package restructuring (#23857) * eth/tracers: restructure tracer package * core/vm/runtime: load js tracers * eth/tracers: mv bigint js code to own file * eth/tracers: add method docs for native tracers * eth/tracers: minor doc fix * core,eth: cancel evm on nativecalltracer stop * core/vm: fix failing test Co-authored-by: Sina Mahmoodi Signed-off-by: wenbiao * eth/tracers: ethapi.TransactionArgs was not merged Signed-off-by: wenbiao * eth/tracers: fix the api_test with ErrInsufficientFunds to ErrInsufficientFundsForTransfer Signed-off-by: wenbiao * eth/tracers: check posa before statedb.Prepare in IntermiateRoots api Signed-off-by: wenbiao * eth/tracers: make js calltracer default, compatible with old version Signed-off-by: wenbiao * eth/tracers: fix the default callTrace name of callTracerJs Signed-off-by: wenbiao * Revert "eth/tracers: fix the default callTrace name of callTracerJs" This reverts commit 62a3bc215d9f07e422a4c659289bb3ba4f9ed2fa. Signed-off-by: wenbiao * Revert "eth/tracers: make js calltracer default, compatible with old version" This reverts commit 85ef42c0ea651f0b228d4209b1b2598b24e12f1f. Signed-off-by: wenbiao * eth/tracers: fix the variable race condition Signed-off-by: wenbiao Co-authored-by: Martin Holst Swende Co-authored-by: Marius van der Wijden Co-authored-by: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Co-authored-by: Péter Szilágyi Co-authored-by: Sina Mahmoodi --- cmd/evm/disasm.go | 2 +- cmd/evm/internal/t8ntool/execution.go | 2 +- cmd/evm/internal/t8ntool/flags.go | 4 +- cmd/evm/internal/t8ntool/transition.go | 16 +- cmd/evm/main.go | 6 +- cmd/evm/runner.go | 12 +- cmd/evm/staterunner.go | 10 +- cmd/geth/main.go | 5 + core/vm/access_list_tracer.go | 9 +- core/vm/evm.go | 76 +- core/vm/instructions.go | 4 + core/vm/interpreter.go | 20 +- core/vm/logger.go | 62 +- core/vm/logger_json.go | 19 +- core/vm/logger_test.go | 3 +- core/vm/runtime/runtime_test.go | 272 +++++- core/vm/stack.go | 2 +- eth/api_backend.go | 4 +- eth/state_accessor.go | 26 +- eth/tracers/api.go | 216 +++-- eth/tracers/api_test.go | 337 +++---- .../internal/tracers/call_tracer_js.js | 112 +++ .../internal/tracetest/calltrace_test.go | 394 ++++++++ .../testdata/call_tracer/create.json} | 0 .../testdata/call_tracer/deep_calls.json} | 0 .../testdata/call_tracer/delegatecall.json} | 0 .../inner_create_oog_outer_throw.json | 77 ++ .../testdata/call_tracer/inner_instafail.json | 63 ++ .../inner_throw_outer_revert.json} | 0 .../tracetest/testdata/call_tracer/oog.json} | 0 .../testdata/call_tracer/revert.json} | 0 .../testdata/call_tracer/revert_reason.json} | 0 .../testdata/call_tracer/selfdestruct.json | 75 ++ .../testdata/call_tracer/simple.json | 80 ++ .../testdata/call_tracer/throw.json} | 0 .../testdata/call_tracer_legacy/create.json | 58 ++ .../call_tracer_legacy/deep_calls.json | 415 +++++++++ .../call_tracer_legacy/delegatecall.json | 97 ++ .../inner_create_oog_outer_throw.json} | 0 .../call_tracer_legacy/inner_instafail.json} | 0 .../inner_throw_outer_revert.json | 81 ++ .../testdata/call_tracer_legacy/oog.json | 60 ++ .../testdata/call_tracer_legacy/revert.json | 58 ++ .../call_tracer_legacy/revert_reason.json | 64 ++ .../call_tracer_legacy/selfdestruct.json | 73 ++ .../testdata/call_tracer_legacy/simple.json} | 0 .../testdata/call_tracer_legacy/throw.json | 62 ++ eth/tracers/{tracer.go => js/bigint.go} | 636 +------------ .../js/internal/tracers/4byte_tracer.js | 65 ++ .../internal/tracers/4byte_tracer_legacy.js} | 0 .../{ => js}/internal/tracers/assets.go | 102 +- .../internal/tracers/bigram_tracer.js | 0 .../js/internal/tracers/call_tracer_js.js | 112 +++ .../internal/tracers/call_tracer_legacy.js} | 0 .../internal/tracers/evmdis_tracer.js | 0 .../{ => js}/internal/tracers/noop_tracer.js | 0 .../internal/tracers/opcount_tracer.js | 0 .../internal/tracers/prestate_tracer.js | 0 .../{ => js}/internal/tracers/tracers.go | 0 .../internal/tracers/trigram_tracer.js | 0 .../internal/tracers/unigram_tracer.js | 0 eth/tracers/js/tracer.go | 880 ++++++++++++++++++ eth/tracers/{ => js}/tracer_test.go | 123 ++- eth/tracers/native/call.go | 182 ++++ eth/tracers/native/noop.go | 74 ++ eth/tracers/native/tracer.go | 79 ++ eth/tracers/tracers.go | 65 +- eth/tracers/tracers_test.go | 260 +----- internal/web3ext/web3ext.go | 6 + les/api_backend.go | 2 +- tests/state_test.go | 2 +- 71 files changed, 4123 insertions(+), 1341 deletions(-) create mode 100644 eth/tracers/internal/tracers/call_tracer_js.js create mode 100644 eth/tracers/internal/tracetest/calltrace_test.go rename eth/tracers/{testdata/call_tracer_create.json => internal/tracetest/testdata/call_tracer/create.json} (100%) rename eth/tracers/{testdata/call_tracer_deep_calls.json => internal/tracetest/testdata/call_tracer/deep_calls.json} (100%) rename eth/tracers/{testdata/call_tracer_delegatecall.json => internal/tracetest/testdata/call_tracer/delegatecall.json} (100%) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json rename eth/tracers/{testdata/call_tracer_inner_throw_outer_revert.json => internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json} (100%) rename eth/tracers/{testdata/call_tracer_oog.json => internal/tracetest/testdata/call_tracer/oog.json} (100%) rename eth/tracers/{testdata/call_tracer_revert.json => internal/tracetest/testdata/call_tracer/revert.json} (100%) rename eth/tracers/{testdata/call_tracer_revert_reason.json => internal/tracetest/testdata/call_tracer/revert_reason.json} (100%) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/simple.json rename eth/tracers/{testdata/call_tracer_throw.json => internal/tracetest/testdata/call_tracer/throw.json} (100%) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json rename eth/tracers/{testdata/call_tracer_inner_create_oog_outer_throw.json => internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json} (100%) rename eth/tracers/{testdata/call_tracer_inner_instafail.json => internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json} (100%) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json rename eth/tracers/{testdata/call_tracer_simple.json => internal/tracetest/testdata/call_tracer_legacy/simple.json} (100%) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json rename eth/tracers/{tracer.go => js/bigint.go} (57%) create mode 100644 eth/tracers/js/internal/tracers/4byte_tracer.js rename eth/tracers/{internal/tracers/4byte_tracer.js => js/internal/tracers/4byte_tracer_legacy.js} (100%) rename eth/tracers/{ => js}/internal/tracers/assets.go (57%) rename eth/tracers/{ => js}/internal/tracers/bigram_tracer.js (100%) create mode 100644 eth/tracers/js/internal/tracers/call_tracer_js.js rename eth/tracers/{internal/tracers/call_tracer.js => js/internal/tracers/call_tracer_legacy.js} (100%) rename eth/tracers/{ => js}/internal/tracers/evmdis_tracer.js (100%) rename eth/tracers/{ => js}/internal/tracers/noop_tracer.js (100%) rename eth/tracers/{ => js}/internal/tracers/opcount_tracer.js (100%) rename eth/tracers/{ => js}/internal/tracers/prestate_tracer.js (100%) rename eth/tracers/{ => js}/internal/tracers/tracers.go (100%) rename eth/tracers/{ => js}/internal/tracers/trigram_tracer.js (100%) rename eth/tracers/{ => js}/internal/tracers/unigram_tracer.js (100%) create mode 100644 eth/tracers/js/tracer.go rename eth/tracers/{ => js}/tracer_test.go (51%) create mode 100644 eth/tracers/native/call.go create mode 100644 eth/tracers/native/noop.go create mode 100644 eth/tracers/native/tracer.go diff --git a/cmd/evm/disasm.go b/cmd/evm/disasm.go index 68a09cbf50..f9719497fe 100644 --- a/cmd/evm/disasm.go +++ b/cmd/evm/disasm.go @@ -46,7 +46,7 @@ func disasmCmd(ctx *cli.Context) error { case ctx.GlobalIsSet(InputFlag.Name): in = ctx.GlobalString(InputFlag.Name) default: - return errors.New("Missing filename or --input value") + return errors.New("missing filename or --input value") } code := strings.TrimSpace(in) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 0471037ed8..2a9426540a 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -82,7 +82,7 @@ type stEnvMarshaling struct { // Apply applies a set of transactions to a pre-state func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txs types.Transactions, miningReward int64, - getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error)) (*state.StateDB, *ExecutionResult, error) { + 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 diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index a599462cc6..a3ba9acc2a 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -30,7 +30,7 @@ var ( Name: "trace", Usage: "Output full trace logs to files .jsonl", } - TraceDisableMemoryFlag = cli.BoolFlag{ + TraceDisableMemoryFlag = cli.BoolTFlag{ Name: "trace.nomemory", Usage: "Disable full memory dump in traces", } @@ -38,7 +38,7 @@ var ( Name: "trace.nostack", Usage: "Disable stack output in traces", } - TraceDisableReturnDataFlag = cli.BoolFlag{ + TraceDisableReturnDataFlag = cli.BoolTFlag{ Name: "trace.noreturndata", Usage: "Disable return data output in traces", } diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index fedcd12435..f5c0dd42f0 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -81,10 +81,10 @@ func Main(ctx *cli.Context) error { var ( err error - tracer vm.Tracer + tracer vm.EVMLogger baseDir = "" ) - var getTracer func(txIndex int, txHash common.Hash) (vm.Tracer, error) + var getTracer func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) // If user specified a basedir, make sure it exists if ctx.IsSet(OutputBasedir.Name) { @@ -99,10 +99,10 @@ func Main(ctx *cli.Context) error { if ctx.Bool(TraceFlag.Name) { // Configure the EVM logger logConfig := &vm.LogConfig{ - DisableStack: ctx.Bool(TraceDisableStackFlag.Name), - DisableMemory: ctx.Bool(TraceDisableMemoryFlag.Name), - DisableReturnData: ctx.Bool(TraceDisableReturnDataFlag.Name), - Debug: true, + DisableStack: ctx.Bool(TraceDisableStackFlag.Name), + EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name), + EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name), + Debug: true, } var prevFile *os.File // This one closes the last file @@ -111,7 +111,7 @@ func Main(ctx *cli.Context) error { prevFile.Close() } }() - getTracer = func(txIndex int, txHash common.Hash) (vm.Tracer, error) { + getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { if prevFile != nil { prevFile.Close() } @@ -123,7 +123,7 @@ func Main(ctx *cli.Context) error { return vm.NewJSONLogger(logConfig, traceFile), nil } } else { - getTracer = func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error) { + getTracer = func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error) { return nil, nil } } diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 8a3e4e0ea2..d78970e7dc 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -113,7 +113,7 @@ var ( Name: "receiver", Usage: "The transaction receiver (execution context)", } - DisableMemoryFlag = cli.BoolFlag{ + DisableMemoryFlag = cli.BoolTFlag{ Name: "nomemory", Usage: "disable memory output", } @@ -125,9 +125,9 @@ var ( Name: "nostorage", Usage: "disable storage output", } - DisableReturnDataFlag = cli.BoolFlag{ + DisableReturnDataFlag = cli.BoolTFlag{ Name: "noreturndata", - Usage: "disable return data output", + Usage: "enable return data output", } EVMInterpreterFlag = cli.StringFlag{ Name: "vm.evm", diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 4063767cb8..f522233e71 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -108,15 +108,15 @@ func runCmd(ctx *cli.Context) error { glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) log.Root().SetHandler(glogger) logconfig := &vm.LogConfig{ - DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name), - DisableStack: ctx.GlobalBool(DisableStackFlag.Name), - DisableStorage: ctx.GlobalBool(DisableStorageFlag.Name), - DisableReturnData: ctx.GlobalBool(DisableReturnDataFlag.Name), - Debug: ctx.GlobalBool(DebugFlag.Name), + 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), } var ( - tracer vm.Tracer + tracer vm.EVMLogger debugLogger *vm.StructLogger statedb *state.StateDB chainConfig *params.ChainConfig diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index c4df936c75..bfc243b471 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -59,13 +59,13 @@ func stateTestCmd(ctx *cli.Context) error { // Configure the EVM logger config := &vm.LogConfig{ - DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name), - DisableStack: ctx.GlobalBool(DisableStackFlag.Name), - DisableStorage: ctx.GlobalBool(DisableStorageFlag.Name), - DisableReturnData: ctx.GlobalBool(DisableReturnDataFlag.Name), + EnableMemory: !ctx.GlobalBool(DisableMemoryFlag.Name), + DisableStack: ctx.GlobalBool(DisableStackFlag.Name), + DisableStorage: ctx.GlobalBool(DisableStorageFlag.Name), + EnableReturnData: !ctx.GlobalBool(DisableReturnDataFlag.Name), } var ( - tracer vm.Tracer + tracer vm.EVMLogger debugger *vm.StructLogger ) switch { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index e896c7d659..3e2585fed6 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -39,6 +39,11 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" + + // Force-load the tracer engines to trigger registration + _ "github.com/ethereum/go-ethereum/eth/tracers/js" + _ "github.com/ethereum/go-ethereum/eth/tracers/native" + "gopkg.in/urfave/cli.v1" ) diff --git a/core/vm/access_list_tracer.go b/core/vm/access_list_tracer.go index b5bc961c84..d7993b4f73 100644 --- a/core/vm/access_list_tracer.go +++ b/core/vm/access_list_tracer.go @@ -141,7 +141,7 @@ func (a *AccessListTracer) CaptureStart(env *EVM, from common.Address, to common } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. -func (a *AccessListTracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { +func (a *AccessListTracer) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { stack := scope.Stack if (op == SLOAD || op == SSTORE) && stack.len() >= 1 { slot := common.Hash(stack.data[stack.len()-1].Bytes32()) @@ -161,11 +161,16 @@ func (a *AccessListTracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cos } } -func (*AccessListTracer) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) { +func (*AccessListTracer) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) { } func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {} +func (*AccessListTracer) CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +} + +func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} + // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { return a.list.accessList() diff --git a/core/vm/evm.go b/core/vm/evm.go index 26a5fa7c45..53e2e8797b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -232,9 +232,14 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas 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.vmConfig.Debug && evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) - evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) + if evm.vmConfig.Debug { + if evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) + evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) + } else { + evm.vmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) + evm.vmConfig.Tracer.CaptureExit(ret, 0, nil) + } } return nil, gas, nil } @@ -243,11 +248,19 @@ 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.vmConfig.Debug && evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) - defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters - evm.vmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) - }(gas, time.Now()) + if evm.vmConfig.Debug { + if evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) + defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters + evm.vmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) + }(gas, time.Now()) + } else { + // Handle tracer events for entering and exiting a call frame + evm.vmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) + defer func(startGas uint64) { + evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err) + }(gas) + } } if isPrecompile { @@ -307,6 +320,14 @@ 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.vmConfig.Debug { + evm.vmConfig.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) + defer func(startGas uint64) { + evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err) + }(gas) + } + // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas) @@ -343,6 +364,14 @@ 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.vmConfig.Debug { + evm.vmConfig.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, nil) + defer func(startGas uint64) { + evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err) + }(gas) + } + // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas) @@ -388,6 +417,14 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // future scenarios evm.StateDB.AddBalance(addr, big0) + // Invoke tracer hooks that signal entering/exiting a call frame + if evm.vmConfig.Debug { + evm.vmConfig.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) + defer func(startGas uint64) { + evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err) + }(gas) + } + if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas) } else { @@ -427,7 +464,7 @@ func (c *codeAndHash) Hash() common.Hash { } // create creates a new contract using code as deployment code. -func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { +func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) { // Depth check execution. Fail if we're trying to execute above the // limit. if evm.depth > int(params.CallCreateDepth) { @@ -465,9 +502,14 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, return nil, address, gas, nil } - if evm.vmConfig.Debug && evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) + if evm.vmConfig.Debug { + if evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) + } else { + evm.vmConfig.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) + } } + start := time.Now() ret, err := run(evm, contract, nil, false) @@ -500,8 +542,12 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } } - if evm.vmConfig.Debug && evm.depth == 0 { - evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + if evm.vmConfig.Debug { + if evm.depth == 0 { + evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + } else { + evm.vmConfig.Tracer.CaptureExit(ret, gas-contract.Gas, err) + } } return ret, address, contract.Gas, err } @@ -509,7 +555,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // Create creates a new contract using code as deployment code. func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) - return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr) + return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE) } // Create2 creates a new contract using code as deployment code. @@ -519,7 +565,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { codeAndHash := &codeAndHash{code: code} contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) - return evm.create(caller, codeAndHash, gas, endowment, contractAddr) + return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2) } // ChainConfig returns the environment's chain configuration diff --git a/core/vm/instructions.go b/core/vm/instructions.go index f0eac1cc34..0ecf28d59a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -791,6 +791,10 @@ func opSuicide(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) + } return nil, nil } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index c004672cae..1155037a1e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -34,10 +34,10 @@ var EVMInterpreterPool = sync.Pool{ // Config are the configuration options for the Interpreter type Config struct { - Debug bool // Enables debugging - Tracer Tracer // Opcode logger - NoRecursion bool // Disables call, callcode, delegate call and create - EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages + Debug bool // Enables debugging + Tracer EVMLogger // Opcode logger + NoRecursion bool // Disables call, callcode, delegate call and create + EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages JumpTable [256]*operation // EVM instruction table, automatically populated if unset @@ -183,9 +183,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( pc = uint64(0) // program counter cost uint64 // copies used by tracer - pcCopy uint64 // needed for the deferred Tracer - gasCopy uint64 // for Tracer to log gas remaining before execution - logged bool // deferred Tracer should ignore already logged steps + pcCopy uint64 // needed for the deferred EVMLogger + gasCopy uint64 // for EVMLogger to log gas remaining before execution + logged bool // deferred EVMLogger should ignore already logged steps res []byte // result of the opcode execution function ) // Don't move this deferrred function, it's placed before the capturestate-deferred method, @@ -200,9 +200,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( defer func() { if err != nil { if !logged { - in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) + in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) } else { - in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) + in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) } } }() @@ -284,7 +284,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } if in.cfg.Debug { - in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) + in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) logged = true } diff --git a/core/vm/logger.go b/core/vm/logger.go index be24f315c2..f8f08e7265 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -47,12 +47,12 @@ func (s Storage) Copy() Storage { // LogConfig are the configuration options for structured logger the EVM type LogConfig struct { - DisableMemory bool // disable memory capture - DisableStack bool // disable stack capture - DisableStorage bool // disable storage capture - DisableReturnData bool // disable return data capture - Debug bool // print output during capture end - Limit int // maximum length of output, but zero means unlimited + EnableMemory bool // enable memory capture + DisableStack bool // disable stack capture + DisableStorage bool // disable storage capture + EnableReturnData bool // enable return data capture + Debug bool // print output during capture end + Limit int // maximum length of output, but zero means unlimited // Chain overrides, can be used to execute a trace using future fork rules Overrides *params.ChainConfig `json:"overrides,omitempty"` } @@ -99,25 +99,28 @@ func (s *StructLog) ErrorString() string { return "" } -// Tracer is used to collect execution traces from an EVM transaction +// EVMLogger is used to collect execution traces from an EVM transaction // execution. CaptureState is called for each step of the VM with the // current VM state. // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. -type Tracer interface { +type EVMLogger interface { CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) - CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) + CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) + CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) + CaptureExit(output []byte, gasUsed uint64, err error) + CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) } -// StructLogger is an EVM state logger and implements Tracer. +// StructLogger is an EVM state logger and implements EVMLogger. // // StructLogger can capture state based on the given Log configuration and also keeps // a track record of modified storage which is used in reporting snapshots of the // contract their storage. type StructLogger struct { cfg LogConfig + env *EVM storage map[common.Address]Storage logs []StructLog @@ -144,14 +147,15 @@ func (l *StructLogger) Reset() { l.err = nil } -// CaptureStart implements the Tracer interface to initialize the tracing operation. +// CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + l.env = env } // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { +func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { memory := scope.Memory stack := scope.Stack contract := scope.Contract @@ -161,7 +165,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui } // Copy a snapshot of the current memory state to a new buffer var mem []byte - if !l.cfg.DisableMemory { + if l.cfg.EnableMemory { mem = make([]byte, len(memory.Data())) copy(mem, memory.Data()) } @@ -185,7 +189,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui if op == SLOAD && stack.len() >= 1 { var ( address = common.Hash(stack.data[stack.len()-1].Bytes32()) - value = env.StateDB.GetState(contract.Address(), address) + value = l.env.StateDB.GetState(contract.Address(), address) ) l.storage[contract.Address()][address] = value storage = l.storage[contract.Address()].Copy() @@ -200,18 +204,18 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui } } var rdata []byte - if !l.cfg.DisableReturnData { + if l.cfg.EnableReturnData { rdata = make([]byte, len(rData)) copy(rdata, rData) } // create a new snapshot of the EVM. - log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err} + log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} l.logs = append(l.logs, log) } -// CaptureFault implements the Tracer interface to trace an execution fault +// CaptureFault implements the EVMLogger interface to trace an execution fault // while running an opcode. -func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) { +func (l *StructLogger) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) { } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -226,6 +230,11 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration } } +func (l *StructLogger) CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +} + +func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} + // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -285,12 +294,13 @@ func WriteLogs(writer io.Writer, logs []*types.Log) { type mdLogger struct { out io.Writer cfg *LogConfig + env *EVM } // NewMarkdownLogger creates a logger which outputs information in a format adapted // for human readability, and is also a valid markdown table func NewMarkdownLogger(cfg *LogConfig, writer io.Writer) *mdLogger { - l := &mdLogger{writer, cfg} + l := &mdLogger{out: writer, cfg: cfg} if l.cfg == nil { l.cfg = &LogConfig{} } @@ -298,6 +308,7 @@ func NewMarkdownLogger(cfg *LogConfig, writer io.Writer) *mdLogger { } func (t *mdLogger) CaptureStart(env *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", from.String(), to.String(), @@ -315,7 +326,7 @@ func (t *mdLogger) CaptureStart(env *EVM, from common.Address, to common.Address } // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { +func (t *mdLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { stack := scope.Stack fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) @@ -328,14 +339,14 @@ func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64 b := fmt.Sprintf("[%v]", strings.Join(a, ",")) fmt.Fprintf(t.out, "%10v |", b) } - fmt.Fprintf(t.out, "%10v |", env.StateDB.GetRefund()) + fmt.Fprintf(t.out, "%10v |", t.env.StateDB.GetRefund()) fmt.Fprintln(t.out, "") if err != nil { fmt.Fprintf(t.out, "Error: %v\n", err) } } -func (t *mdLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) { +func (t *mdLogger) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) { fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } @@ -343,3 +354,8 @@ func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, tm time.Duration, e fmt.Fprintf(t.out, "\nOutput: `0x%x`\nConsumed gas: `%d`\nError: `%v`\n", output, gasUsed, err) } + +func (t *mdLogger) CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +} + +func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} diff --git a/core/vm/logger_json.go b/core/vm/logger_json.go index 0975452b60..c249dba7e2 100644 --- a/core/vm/logger_json.go +++ b/core/vm/logger_json.go @@ -29,12 +29,13 @@ import ( type JSONLogger struct { encoder *json.Encoder cfg *LogConfig + env *EVM } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects // into the provided stream. func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger { - l := &JSONLogger{json.NewEncoder(writer), cfg} + l := &JSONLogger{encoder: json.NewEncoder(writer), cfg: cfg} if l.cfg == nil { l.cfg = &LogConfig{} } @@ -42,12 +43,13 @@ func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger { } func (l *JSONLogger) CaptureStart(env *EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + l.env = env } -func (l *JSONLogger) CaptureFault(*EVM, uint64, OpCode, uint64, uint64, *ScopeContext, int, error) {} +func (l *JSONLogger) CaptureFault(uint64, OpCode, uint64, uint64, *ScopeContext, int, error) {} // CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { +func (l *JSONLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { memory := scope.Memory stack := scope.Stack @@ -58,16 +60,16 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint GasCost: cost, MemorySize: memory.Len(), Depth: depth, - RefundCounter: env.StateDB.GetRefund(), + RefundCounter: l.env.StateDB.GetRefund(), Err: err, } - if !l.cfg.DisableMemory { + if l.cfg.EnableMemory { log.Memory = memory.Data() } if !l.cfg.DisableStack { log.Stack = stack.data } - if !l.cfg.DisableReturnData { + if l.cfg.EnableReturnData { log.ReturnData = rData } l.encoder.Encode(log) @@ -86,3 +88,8 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, } l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""}) } + +func (l *JSONLogger) CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +} + +func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index 9c936af36a..5d1aa8e54d 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -63,7 +63,8 @@ func TestStoreCapture(t *testing.T) { scope.Stack.push(uint256.NewInt().SetUint64(1)) scope.Stack.push(uint256.NewInt()) var index common.Hash - logger.CaptureState(env, 0, SSTORE, 0, 0, scope, nil, 0, nil) + logger.CaptureStart(env, common.Address{}, contract.Address(), false, nil, 0, nil) + logger.CaptureState(0, SSTORE, 0, 0, scope, nil, 0, nil) if len(logger.storage[contract.Address()]) == 0 { t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.storage[contract.Address()])) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index dcf2d0d447..fea7817ff7 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -33,7 +33,11 @@ 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/params" + + // force-load js tracers to trigger registration + _ "github.com/ethereum/go-ethereum/eth/tracers/js" ) func TestDefaults(t *testing.T) { @@ -329,12 +333,12 @@ type stepCounter struct { 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(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +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(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, 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) @@ -342,11 +346,21 @@ func (s *stepCounter) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, co // 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, b *testing.B) { +func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode string, b *testing.B) { cfg := new(Config) setDefaults(cfg) 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)) + if err != nil { + b.Fatal(err) + } + cfg.EVMConfig = vm.Config{ + Debug: true, + Tracer: tracer, + } + } var ( destination = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) @@ -486,12 +500,12 @@ func BenchmarkSimpleLoop(b *testing.B) { // Tracer: tracer, // }}) // 100M gas - benchmarkNonModifyingCode(100000000, staticCallIdentity, "staticcall-identity-100M", b) - benchmarkNonModifyingCode(100000000, callIdentity, "call-identity-100M", 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, staticCallIdentity, "staticcall-identity-100M", "", b) + benchmarkNonModifyingCode(100000000, callIdentity, "call-identity-100M", "", 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(10000000, staticCallIdentity, "staticcall-identity-10M", b) //benchmarkNonModifyingCode(10000000, loopingCode, "loop-10M", b) @@ -500,7 +514,7 @@ func BenchmarkSimpleLoop(b *testing.B) { // TestEip2929Cases contains various testcases that are used for // EIP-2929 about gas repricings func TestEip2929Cases(t *testing.T) { - + t.Skip("Test only useful for generating documentation") id := 1 prettyPrint := func(comment string, code []byte) { @@ -688,3 +702,241 @@ func TestColdAccountAccessCost(t *testing.T) { } } } + +func TestRuntimeJSTracer(t *testing.T) { + jsTracers := []string{ + `{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, steps:0, + step: function() { this.steps++}, + fault: function() {}, + result: function() { + return [this.enters, this.exits,this.enterGas,this.gasUsed, this.steps].join(",") + }, + enter: function(frame) { + this.enters++; + this.enterGas = frame.getGas(); + }, + exit: function(res) { + this.exits++; + this.gasUsed = res.getGasUsed(); + }}`, + `{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, steps:0, + fault: function() {}, + result: function() { + return [this.enters, this.exits,this.enterGas,this.gasUsed, this.steps].join(",") + }, + enter: function(frame) { + this.enters++; + this.enterGas = frame.getGas(); + }, + exit: function(res) { + this.exits++; + this.gasUsed = res.getGasUsed(); + }}`} + tests := []struct { + code []byte + // One result per tracer + results []string + }{ + { + // CREATE + code: []byte{ + // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) + byte(vm.PUSH5), + // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), + byte(vm.PUSH1), 0, + byte(vm.MSTORE), + // length, offset, value + byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, + byte(vm.CREATE), + byte(vm.POP), + }, + results: []string{`"1,1,4294935775,6,12"`, `"1,1,4294935775,6,0"`}, + }, + { + // CREATE2 + code: []byte{ + // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) + byte(vm.PUSH5), + // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), + byte(vm.PUSH1), 0, + byte(vm.MSTORE), + // salt, length, offset, value + byte(vm.PUSH1), 1, byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, + byte(vm.CREATE2), + byte(vm.POP), + }, + results: []string{`"1,1,4294935766,6,13"`, `"1,1,4294935766,6,0"`}, + }, + { + // CALL + code: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, + byte(vm.PUSH1), 0, // value + byte(vm.PUSH1), 0xbb, //address + byte(vm.GAS), // gas + byte(vm.CALL), + byte(vm.POP), + }, + results: []string{`"1,1,4294964716,6,13"`, `"1,1,4294964716,6,0"`}, + }, + { + // CALLCODE + code: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, + byte(vm.PUSH1), 0, // value + byte(vm.PUSH1), 0xcc, //address + byte(vm.GAS), // gas + byte(vm.CALLCODE), + byte(vm.POP), + }, + results: []string{`"1,1,4294964716,6,13"`, `"1,1,4294964716,6,0"`}, + }, + { + // STATICCALL + code: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, + byte(vm.PUSH1), 0xdd, //address + byte(vm.GAS), // gas + byte(vm.STATICCALL), + byte(vm.POP), + }, + results: []string{`"1,1,4294964719,6,12"`, `"1,1,4294964719,6,0"`}, + }, + { + // DELEGATECALL + code: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, + byte(vm.PUSH1), 0xee, //address + byte(vm.GAS), // gas + byte(vm.DELEGATECALL), + byte(vm.POP), + }, + results: []string{`"1,1,4294964719,6,12"`, `"1,1,4294964719,6,0"`}, + }, + { + // CALL self-destructing contract + code: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, + byte(vm.PUSH1), 0, // value + byte(vm.PUSH1), 0xff, //address + byte(vm.GAS), // gas + byte(vm.CALL), + byte(vm.POP), + }, + results: []string{`"2,2,0,5003,12"`, `"2,2,0,5003,0"`}, + }, + } + calleeCode := []byte{ + byte(vm.PUSH1), 0, + byte(vm.PUSH1), 0, + byte(vm.RETURN), + } + depressedCode := []byte{ + byte(vm.PUSH1), 0xaa, + byte(vm.SELFDESTRUCT), + } + main := common.HexToAddress("0xaa") + for i, jsTracer := range jsTracers { + for j, tc := range tests { + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb.SetCode(main, tc.code) + statedb.SetCode(common.HexToAddress("0xbb"), calleeCode) + statedb.SetCode(common.HexToAddress("0xcc"), calleeCode) + statedb.SetCode(common.HexToAddress("0xdd"), calleeCode) + statedb.SetCode(common.HexToAddress("0xee"), calleeCode) + statedb.SetCode(common.HexToAddress("0xff"), depressedCode) + + tracer, err := tracers.New(jsTracer, new(tracers.Context)) + if err != nil { + t.Fatal(err) + } + _, _, err = Call(main, nil, &Config{ + State: statedb, + EVMConfig: vm.Config{ + Debug: true, + Tracer: tracer, + }}) + if err != nil { + t.Fatal("didn't expect error", err) + } + res, err := tracer.GetResult() + if err != nil { + t.Fatal(err) + } + if have, want := string(res), tc.results[i]; have != want { + t.Errorf("wrong result for tracer %d testcase %d, have \n%v\nwant\n%v\n", i, j, have, want) + } + } + } +} + +func TestJSTracerCreateTx(t *testing.T) { + jsTracer := ` + {enters: 0, exits: 0, + step: function() {}, + fault: function() {}, + result: function() { return [this.enters, this.exits].join(",") }, + enter: function(frame) { this.enters++ }, + exit: function(res) { this.exits++ }}` + 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)) + if err != nil { + t.Fatal(err) + } + _, _, _, err = Create(code, &Config{ + State: statedb, + EVMConfig: vm.Config{ + Debug: true, + Tracer: tracer, + }}) + if err != nil { + t.Fatal(err) + } + + res, err := tracer.GetResult() + if err != nil { + t.Fatal(err) + } + if have, want := string(res), `"0,0"`; have != want { + t.Errorf("wrong result for tracer, have \n%v\nwant\n%v\n", have, want) + } +} + +func BenchmarkTracerStepVsCallFrame(b *testing.B) { + // Simply pushes and pops some values in a loop + code := []byte{ + byte(vm.JUMPDEST), + byte(vm.PUSH1), 0, + byte(vm.PUSH1), 0, + byte(vm.POP), + byte(vm.POP), + byte(vm.PUSH1), 0, // jumpdestination + byte(vm.JUMP), + } + + stepTracer := ` + { + step: function() {}, + fault: function() {}, + result: function() {}, + }` + callFrameTracer := ` + { + enter: function() {}, + exit: function() {}, + fault: function() {}, + result: function() {}, + }` + + benchmarkNonModifyingCode(10000000, code, "tracer-step-10M", stepTracer, b) + benchmarkNonModifyingCode(10000000, code, "tracer-call-frame-10M", callFrameTracer, b) +} diff --git a/core/vm/stack.go b/core/vm/stack.go index c71d2653a5..220f97c89f 100644 --- a/core/vm/stack.go +++ b/core/vm/stack.go @@ -91,7 +91,7 @@ func (st *Stack) Print() { fmt.Println("### stack ###") if len(st.data) > 0 { for i, val := range st.data { - fmt.Printf("%-3d %v\n", i, val) + fmt.Printf("%-3d %s\n", i, val.String()) } } else { fmt.Println("-- empty --") diff --git a/eth/api_backend.go b/eth/api_backend.go index 18514b7cc3..daf6c19ece 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -338,8 +338,8 @@ 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 bool) (*state.StateDB, error) { - return b.eth.stateAtBlock(block, reexec, base, checkLive) +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) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) { diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 461dc491fb..6ea3161d61 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -37,7 +37,17 @@ import ( // 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 // parent block. -func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (statedb *state.StateDB, err error) { +// 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 preferrable 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 database state.Database @@ -52,6 +62,15 @@ func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state } } if base != nil { + if preferDisk { + // 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 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 + } + } // 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) @@ -121,7 +140,8 @@ func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state // 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, err + return 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 { @@ -153,7 +173,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, err := eth.stateAtBlock(parent, reexec, nil, true) + statedb, err := eth.stateAtBlock(parent, reexec, nil, true, false) if err != nil { return nil, vm.BlockContext{}, nil, err } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 5f20858b2e..a44982b864 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -55,6 +55,13 @@ const ( // and reexecute to produce missing historical state necessary to run a specific // trace. defaultTraceReexec = uint64(128) + + // defaultTracechainMemLimit is the size of the triedb, at which traceChain + // switches over and tries to use a disk-backed database instead of building + // on top of memory. + // 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) ) // Backend interface provides the common API services (that are provided by @@ -69,7 +76,10 @@ type Backend interface { ChainConfig() *params.ChainConfig Engine() consensus.Engine ChainDb() ethdb.Database - StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (*state.StateDB, error) + // 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) } @@ -180,13 +190,6 @@ type StdTraceConfig struct { TxHash common.Hash } -// txTraceContext is the contextual infos about a transaction before it gets run. -type txTraceContext struct { - index int // Index of the transaction within the block - hash common.Hash // Hash of the transaction - block common.Hash // Hash of the block containing the transaction -} - // txTraceResult is the result of a single transaction trace. type txTraceResult struct { Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer @@ -274,10 +277,10 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config // Trace all the transactions contained within for i, tx := range task.block.Transactions() { msg, _ := tx.AsMessage(signer) - txctx := &txTraceContext{ - index: i, - hash: tx.Hash(), - block: task.block.Hash(), + txctx := &Context{ + BlockHash: task.block.Hash(), + TxIndex: i, + TxHash: tx.Hash(), } res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { @@ -299,7 +302,11 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config }) } // Start a goroutine to feed all the blocks into the tracers - begin := time.Now() + var ( + begin = time.Now() + derefTodo []common.Hash // list of hashes to dereference from the db + derefsMu sync.Mutex // mutex for the derefs + ) gopool.Submit(func() { var ( @@ -325,6 +332,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config } close(results) }() + 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 @@ -333,6 +341,14 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config 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() @@ -346,18 +362,24 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config } // 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) + statedb, err = api.backend.StateAtBlock(localctx, block, reexec, statedb, false, preferDisk) if err != nil { failed = err break } - if statedb.Database().TrieDB() != nil { + if trieDb := statedb.Database().TrieDB(); trieDb != nil { // Hold the reference for tracer, will be released at the final stage - statedb.Database().TrieDB().Reference(block.Root(), common.Hash{}) + trieDb.Reference(block.Root(), common.Hash{}) // Release the parent state because it's already held by the tracer if parent != (common.Hash{}) { - statedb.Database().TrieDB().Dereference(parent) + 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 } } parent = block.Root() @@ -391,12 +413,11 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config Hash: res.block.Hash(), Traces: res.results, } + // Schedule any parent tries held in memory by this task for dereferencing done[uint64(result.Block)] = result - - // Dereference any parent tries held in memory by this task - if res.statedb.Database().TrieDB() != nil { - res.statedb.Database().TrieDB().Dereference(res.rootref) - } + derefsMu.Lock() + derefTodo = append(derefTodo, res.rootref) + derefsMu.Unlock() // Stream completed traces to the user, aborting on the first error for result, ok := done[next]; ok; result, ok = done[next] { if len(result.Traces) > 0 || next == end.NumberU64() { @@ -454,12 +475,11 @@ func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *Tra // EVM against a block pulled from the pool of bad ones and returns them as a JSON // object. func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) { - for _, block := range rawdb.ReadAllBadBlocks(api.backend.ChainDb()) { - if block.Hash() == hash { - return api.traceBlock(ctx, block, config) - } + block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash) + if block == nil { + return nil, fmt.Errorf("bad block %#x not found", hash) } - return nil, fmt.Errorf("bad block %#x not found", hash) + return api.traceBlock(ctx, block, config) } // StandardTraceBlockToFile dumps the structured logs created during the @@ -473,16 +493,83 @@ func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, return api.standardTraceBlockToFile(ctx, block, config) } +// IntermediateRoots executes a block (bad- or canon- or side-), and returns a list +// of intermediate roots: the stateroot after each transaction. +func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) { + block, _ := api.blockByHash(ctx, hash) + if block == nil { + // Check in the bad blocks + block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash) + } + if block == nil { + return nil, fmt.Errorf("block %#x not found", hash) + } + if block.NumberU64() == 0 { + return nil, errors.New("genesis is not traceable") + } + parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) + if err != nil { + return nil, err + } + reexec := defaultTraceReexec + if config != nil && config.Reexec != nil { + reexec = *config.Reexec + } + statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) + if err != nil { + return nil, err + } + var ( + roots []common.Hash + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + chainConfig = api.backend.ChainConfig() + vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) + ) + for i, tx := range block.Transactions() { + var ( + msg, _ = tx.AsMessage(signer) + txContext = core.NewEVMTxContext(msg) + vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) + ) + + if posa, ok := api.backend.Engine().(consensus.PoSA); ok { + if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem { + balance := statedb.GetBalance(consensus.SystemAddress) + if balance.Cmp(common.Big0) > 0 { + statedb.SetBalance(consensus.SystemAddress, big.NewInt(0)) + statedb.AddBalance(vmctx.Coinbase, balance) + } + } + } + + statedb.Prepare(tx.Hash(), block.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 + // return the roots. Most likely, the caller already knows that a certain transaction fails to + // be included, but still want the intermediate roots that led to that point. + // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be + // executable. + // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. + return roots, nil + } + // calling IntermediateRoot will internally call Finalize on the state + // so any modifications are written to the trie + roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects)) + } + return roots, nil +} + // StandardTraceBadBlockToFile dumps the structured logs created during the // execution of EVM against a block pulled from the pool of bad ones to the // local file system and returns a list of files to the caller. func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) { - for _, block := range rawdb.ReadAllBadBlocks(api.backend.ChainDb()) { - if block.Hash() == hash { - return api.standardTraceBlockToFile(ctx, block, config) - } + block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash) + if block == nil { + return nil, fmt.Errorf("bad block %#x not found", hash) } - return nil, fmt.Errorf("bad block %#x not found", hash) + return api.standardTraceBlockToFile(ctx, block, config) } // traceBlock configures a new tracer according to the provided configuration, and @@ -500,7 +587,7 @@ 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) + statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, err } @@ -520,16 +607,18 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) blockHash := block.Hash() for th := 0; th < threads; th++ { + blockCtx := blockCtx + pend.Add(1) gopool.Submit(func() { defer pend.Done() // Fetch and execute the next transaction trace tasks for task := range jobs { msg, _ := txs[task.index].AsMessage(signer) - txctx := &txTraceContext{ - index: task.index, - hash: txs[task.index].Hash(), - block: blockHash, + txctx := &Context{ + BlockHash: blockHash, + TxIndex: task.index, + TxHash: txs[task.index].Hash(), } res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { @@ -542,6 +631,7 @@ 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) for i, tx := range txs { // Send the trace task over for execution jobs <- &txTraceTask{statedb: statedb.Copy(), index: i} @@ -600,7 +690,7 @@ 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) + statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, err } @@ -740,10 +830,10 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * if err != nil { return nil, err } - txctx := &txTraceContext{ - index: int(index), - hash: hash, - block: blockHash, + txctx := &Context{ + BlockHash: blockHash, + TxIndex: int(index), + TxHash: hash, } return api.traceTx(ctx, msg, txctx, vmctx, statedb, config) } @@ -773,7 +863,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHa if config != nil && config.Reexec != nil { reexec = *config.Reexec } - statedb, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true) + statedb, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false) if err != nil { return nil, err } @@ -796,21 +886,23 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHa Reexec: config.Reexec, } } - return api.traceTx(ctx, msg, new(txTraceContext), vmctx, statedb, traceConfig) + return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig) } // 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 *txTraceContext, 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) { // Assemble the structured logger or the JavaScript tracer var ( - tracer vm.Tracer + tracer vm.EVMLogger err error txContext = core.NewEVMTxContext(message) ) switch { - case config != nil && config.Tracer != nil: + case config == nil: + tracer = vm.NewStructLogger(nil) + case config.Tracer != nil: // Define a meaningful timeout of a single transaction trace timeout := defaultTraceTimeout if config.Timeout != nil { @@ -818,23 +910,19 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac return nil, err } } - // Constuct the JavaScript tracer to execute with - if tracer, err = New(*config.Tracer, txContext); err != nil { + if t, err := New(*config.Tracer, txctx); err != nil { return nil, err + } else { + deadlineCtx, cancel := context.WithTimeout(ctx, timeout) + go func() { + <-deadlineCtx.Done() + if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) { + t.Stop(errors.New("execution timeout")) + } + }() + defer cancel() + tracer = t } - // Handle timeouts and RPC cancellations - deadlineCtx, cancel := context.WithTimeout(ctx, timeout) - gopool.Submit(func() { - <-deadlineCtx.Done() - if deadlineCtx.Err() == context.DeadlineExceeded { - tracer.(*Tracer).Stop(errors.New("execution timeout")) - } - }) - defer cancel() - - case config == nil: - tracer = vm.NewStructLogger(nil) - default: tracer = vm.NewStructLogger(config.LogConfig) } @@ -851,7 +939,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac } // Call Prepare to clear out the statedb access list - statedb.Prepare(txctx.hash, txctx.block, txctx.index) + statedb.Prepare(txctx.TxHash, txctx.BlockHash, txctx.TxIndex) result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) if err != nil { @@ -873,7 +961,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac StructLogs: ethapi.FormatLogs(tracer.StructLogs()), }, nil - case *Tracer: + case Tracer: return tracer.GetResult() default: diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 598c84c3b1..6a64de0e3a 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -139,7 +139,7 @@ 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) (*state.StateDB, error) { +func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error) { statedb, err := b.chain.StateAt(block.Root()) if err != nil { return nil, errStateNotFound @@ -307,147 +307,6 @@ func TestTraceCall(t *testing.T) { } } -func TestOverridenTraceCall(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)}, - }} - genBlocks := 10 - signer := types.HomesteadSigner{} - api := NewAPI(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, big.NewInt(0), nil), signer, accounts[0].key) - b.AddTx(tx) - })) - randomAccounts, tracer := newAccounts(3), "callTracer" - - var testSuite = []struct { - blockNumber rpc.BlockNumber - call ethapi.CallArgs - config *TraceCallConfig - expectErr error - expect *callTrace - }{ - // Succcessful call with state overriding - { - blockNumber: rpc.PendingBlockNumber, - call: ethapi.CallArgs{ - From: &randomAccounts[0].addr, - To: &randomAccounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - config: &TraceCallConfig{ - Tracer: &tracer, - StateOverrides: ðapi.StateOverride{ - randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, - }, - }, - expectErr: nil, - expect: &callTrace{ - Type: "CALL", - From: randomAccounts[0].addr, - To: randomAccounts[1].addr, - Gas: newRPCUint64(24979000), - GasUsed: newRPCUint64(0), - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - }, - // Invalid call without state overriding - { - blockNumber: rpc.PendingBlockNumber, - call: ethapi.CallArgs{ - From: &randomAccounts[0].addr, - To: &randomAccounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - config: &TraceCallConfig{ - Tracer: &tracer, - }, - expectErr: core.ErrInsufficientFundsForTransfer, - expect: nil, - }, - // Successful simple contract call - // - // // SPDX-License-Identifier: GPL-3.0 - // - // pragma solidity >=0.7.0 <0.8.0; - // - // /** - // * @title Storage - // * @dev Store & retrieve value in a variable - // */ - // contract Storage { - // uint256 public number; - // constructor() { - // number = block.number; - // } - // } - { - blockNumber: rpc.PendingBlockNumber, - call: ethapi.CallArgs{ - From: &randomAccounts[0].addr, - To: &randomAccounts[2].addr, - Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number() - }, - config: &TraceCallConfig{ - Tracer: &tracer, - StateOverrides: ðapi.StateOverride{ - randomAccounts[2].addr: ethapi.OverrideAccount{ - Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")), - StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}), - }, - }, - }, - expectErr: nil, - expect: &callTrace{ - Type: "CALL", - From: randomAccounts[0].addr, - To: randomAccounts[2].addr, - Input: hexutil.Bytes(common.Hex2Bytes("8381f58a")), - Output: hexutil.Bytes(common.BigToHash(big.NewInt(123)).Bytes()), - Gas: newRPCUint64(24978936), - GasUsed: newRPCUint64(2283), - Value: (*hexutil.Big)(big.NewInt(0)), - }, - }, - } - for _, testspec := range testSuite { - result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config) - if testspec.expectErr != nil { - if err == nil { - t.Errorf("Expect error %v, get nothing", testspec.expectErr) - continue - } - if !errors.Is(err, testspec.expectErr) { - t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err) - } - } else { - if err != nil { - t.Errorf("Expect no error, get %v", err) - continue - } - ret := new(callTrace) - if err := json.Unmarshal(result.(json.RawMessage), ret); err != nil { - t.Fatalf("failed to unmarshal trace result: %v", err) - } - if !jsonEqual(ret, testspec.expect) { - // uncomment this for easier debugging - //have, _ := json.MarshalIndent(ret, "", " ") - //want, _ := json.MarshalIndent(testspec.expect, "", " ") - //t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want)) - t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, testspec.expect) - } - } - } -} - func TestTraceTransaction(t *testing.T) { t.Parallel() @@ -504,90 +363,177 @@ func TestTraceBlock(t *testing.T) { var testSuite = []struct { blockNumber rpc.BlockNumber config *TraceConfig - expect interface{} + want string expectErr error }{ // Trace genesis block, expect error { blockNumber: rpc.BlockNumber(0), - config: nil, - expect: nil, expectErr: errors.New("genesis is not traceable"), }, // Trace head block { blockNumber: rpc.BlockNumber(genBlocks), - config: nil, - expectErr: nil, - expect: []*txTraceResult{ - { - Result: ðapi.ExecutionResult{ - Gas: params.TxGas, - Failed: false, - ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, - }, - }, - }, + want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, }, // Trace non-existent block { blockNumber: rpc.BlockNumber(genBlocks + 1), - config: nil, expectErr: fmt.Errorf("block #%d not found", genBlocks+1), - expect: nil, }, // Trace latest block { blockNumber: rpc.LatestBlockNumber, - config: nil, - expectErr: nil, - expect: []*txTraceResult{ - { - Result: ðapi.ExecutionResult{ - Gas: params.TxGas, - Failed: false, - ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, - }, + want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, + }, + // Trace pending block + { + blockNumber: rpc.PendingBlockNumber, + want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, + }, + } + for i, tc := range testSuite { + result, err := api.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config) + if tc.expectErr != nil { + if err == nil { + t.Errorf("test %d, want error %v", i, tc.expectErr) + continue + } + if !reflect.DeepEqual(err, tc.expectErr) { + t.Errorf("test %d: error mismatch, want %v, get %v", i, tc.expectErr, err) + } + continue + } + if err != nil { + t.Errorf("test %d, want no error, have %v", i, err) + continue + } + have, _ := json.Marshal(result) + want := tc.want + if string(have) != want { + t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(have), want) + } + } +} + +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)}, + }} + genBlocks := 10 + signer := types.HomesteadSigner{} + api := NewAPI(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, big.NewInt(0), nil), signer, accounts[0].key) + b.AddTx(tx) + })) + randomAccounts := newAccounts(3) + type res struct { + Gas int + Failed bool + returnValue string + } + var testSuite = []struct { + blockNumber rpc.BlockNumber + call ethapi.CallArgs + config *TraceCallConfig + expectErr error + want string + }{ + // Call which can only succeed if state is state overridden + { + blockNumber: rpc.PendingBlockNumber, + call: ethapi.CallArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + config: &TraceCallConfig{ + StateOverrides: ðapi.StateOverride{ + randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, }, }, + want: `{"gas":21000,"failed":false,"returnValue":""}`, }, - // Trace pending block + // Invalid call without state overriding + { + blockNumber: rpc.PendingBlockNumber, + call: ethapi.CallArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + config: &TraceCallConfig{}, + expectErr: core.ErrInsufficientFundsForTransfer, + }, + // Successful simple contract call + // + // // SPDX-License-Identifier: GPL-3.0 + // + // pragma solidity >=0.7.0 <0.8.0; + // + // /** + // * @title Storage + // * @dev Store & retrieve value in a variable + // */ + // contract Storage { + // uint256 public number; + // constructor() { + // number = block.number; + // } + // } { blockNumber: rpc.PendingBlockNumber, - config: nil, - expectErr: nil, - expect: []*txTraceResult{ - { - Result: ðapi.ExecutionResult{ - Gas: params.TxGas, - Failed: false, - ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + call: ethapi.CallArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number() + }, + config: &TraceCallConfig{ + //Tracer: &tracer, + StateOverrides: ðapi.StateOverride{ + randomAccounts[2].addr: ethapi.OverrideAccount{ + Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")), + StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}), }, }, }, + want: `{"gas":23347,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`, }, } - for _, testspec := range testSuite { - result, err := api.TraceBlockByNumber(context.Background(), testspec.blockNumber, testspec.config) - if testspec.expectErr != nil { + for i, tc := range testSuite { + result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config) + if tc.expectErr != nil { if err == nil { - t.Errorf("Expect error %v, get nothing", testspec.expectErr) + t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) continue } - if !reflect.DeepEqual(err, testspec.expectErr) { - t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err) - } - } else { - if err != nil { - t.Errorf("Expect no error, get %v", err) - continue - } - if !reflect.DeepEqual(result, testspec.expect) { - t.Errorf("Result mismatch, want %v, get %v", testspec.expect, result) + if !errors.Is(err, tc.expectErr) { + t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) } + continue + } + if err != nil { + t.Errorf("test %d: want no error, have %v", i, err) + continue + } + // Turn result into res-struct + var ( + have res + want res + ) + resBytes, _ := json.Marshal(result) + 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) } } } @@ -618,11 +564,6 @@ func newRPCBalance(balance *big.Int) **hexutil.Big { return &rpcBalance } -func newRPCUint64(number uint64) *hexutil.Uint64 { - rpcUint64 := hexutil.Uint64(number) - return &rpcUint64 -} - func newRPCBytes(bytes []byte) *hexutil.Bytes { rpcBytes := hexutil.Bytes(bytes) return &rpcBytes diff --git a/eth/tracers/internal/tracers/call_tracer_js.js b/eth/tracers/internal/tracers/call_tracer_js.js new file mode 100644 index 0000000000..7da7bf216a --- /dev/null +++ b/eth/tracers/internal/tracers/call_tracer_js.js @@ -0,0 +1,112 @@ +// 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 . + + +// callFrameTracer uses the new call frame tracing methods to report useful information +// about internal messages of a transaction. +{ + callstack: [{}], + fault: function(log, db) {}, + result: function(ctx, db) { + // Prepare outer message info + var result = { + type: ctx.type, + from: toHex(ctx.from), + to: toHex(ctx.to), + value: '0x' + ctx.value.toString(16), + gas: '0x' + bigInt(ctx.gas).toString(16), + gasUsed: '0x' + bigInt(ctx.gasUsed).toString(16), + input: toHex(ctx.input), + output: toHex(ctx.output), + } + if (this.callstack[0].calls !== undefined) { + result.calls = this.callstack[0].calls + } + if (this.callstack[0].error !== undefined) { + result.error = this.callstack[0].error + } else if (ctx.error !== undefined) { + result.error = ctx.error + } + if (result.error !== undefined && (result.error !== "execution reverted" || result.output ==="0x")) { + delete result.output + } + + return this.finalize(result) + }, + enter: function(frame) { + var call = { + type: frame.getType(), + from: toHex(frame.getFrom()), + to: toHex(frame.getTo()), + input: toHex(frame.getInput()), + gas: '0x' + bigInt(frame.getGas()).toString('16'), + } + if (frame.getValue() !== undefined){ + call.value='0x' + bigInt(frame.getValue()).toString(16) + } + this.callstack.push(call) + }, + exit: function(frameResult) { + var len = this.callstack.length + if (len > 1) { + var call = this.callstack.pop() + call.gasUsed = '0x' + bigInt(frameResult.getGasUsed()).toString('16') + var error = frameResult.getError() + if (error === undefined) { + call.output = toHex(frameResult.getOutput()) + } else { + call.error = error + if (call.type === 'CREATE' || call.type === 'CREATE2') { + delete call.to + } + } + len -= 1 + if (this.callstack[len-1].calls === undefined) { + this.callstack[len-1].calls = [] + } + this.callstack[len-1].calls.push(call) + } + }, + // finalize recreates a call object using the final desired field oder for json + // serialization. This is a nicety feature to pass meaningfully ordered results + // to users who don't interpret it, just display it. + finalize: function(call) { + var sorted = { + type: call.type, + from: call.from, + to: call.to, + value: call.value, + gas: call.gas, + gasUsed: call.gasUsed, + input: call.input, + output: call.output, + error: call.error, + time: call.time, + calls: call.calls, + } + for (var key in sorted) { + if (sorted[key] === undefined) { + delete sorted[key] + } + } + if (sorted.calls !== undefined) { + for (var i=0; i. + +package tracetest + +import ( + "encoding/json" + "io/ioutil" + "math/big" + "path/filepath" + "reflect" + "strings" + "testing" + "unicode" + + "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/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" + "github.com/ethereum/go-ethereum/tests" + + // 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) { + 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"` + Time math.HexOrDecimal64 `json:"timestamp"` + GasLimit math.HexOrDecimal64 `json:"gasLimit"` + Miner common.Address `json:"miner"` +} + +// 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"` +} + +// 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"` +} + +// Iterates over all the input-output datasets in the tracer test harness and +// runs the JavaScript tracers against them. +func TestCallTracerLegacy(t *testing.T) { + testCallTracer("callTracerLegacy", "call_tracer_legacy", t) +} + +func TestCallTracerJs(t *testing.T) { + testCallTracer("callTracerJs", "call_tracer", t) +} + +func TestCallTracerNative(t *testing.T) { + testCallTracer("callTracer", "call_tracer", t) +} + +func testCallTracer(tracerName string, dirPath string, t *testing.T) { + files, err := ioutil.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(callTracerTest) + tx = new(types.Transaction) + ) + // Call tracer test found, read if from disk + if blob, err := ioutil.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)) + 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) + 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 := new(callTrace) + if err := json.Unmarshal(res, ret); err != nil { + t.Fatalf("failed to unmarshal trace result: %v", err) + } + + if !jsonEqual(ret, test.Result) { + // 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) + } + }) + } +} + +// 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 := ioutil.ReadDir(filepath.Join("testdata", "call_tracer")) + if err != nil { + b.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 + b.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(b *testing.B) { + blob, err := ioutil.ReadFile(filepath.Join("testdata", "call_tracer", file.Name())) + if err != nil { + b.Fatalf("failed to read testcase: %v", err) + } + test := new(callTracerTest) + if err := json.Unmarshal(blob, test); err != nil { + b.Fatalf("failed to parse testcase: %v", err) + } + benchTracer("callTracerNative", test, b) + }) + } +} + +func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { + // Configure a blockchain with the given prestate + tx := new(types.Transaction) + if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { + 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) + if err != nil { + b.Fatalf("failed to prepare transaction for tracing: %v", err) + } + 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) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + tracer, err := tracers.New(tracerName, new(tracers.Context)) + 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}) + snap := statedb.Snapshot() + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if _, err = st.TransitionDb(); err != nil { + b.Fatalf("failed to execute transaction: %v", err) + } + if _, err = tracer.GetResult(); err != nil { + b.Fatal(err) + } + statedb.RevertToSnapshot(snap) + } +} + +// 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: new(big.Int).SetUint64(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), + } + var alloc = core.GenesisAlloc{ + to: core.GenesisAccount{ + Nonce: 1, + Code: code, + }, + origin: core.GenesisAccount{ + Nonce: 0, + Balance: big.NewInt(500000000000000), + }, + } + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) + // Create the tracer, the EVM environment and run it + tracer, err := tracers.New("callTracer", 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 := tx.AsMessage(signer) + 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) + } + 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) { + t.Error("have != want") + } +} diff --git a/eth/tracers/testdata/call_tracer_create.json b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json similarity index 100% rename from eth/tracers/testdata/call_tracer_create.json rename to eth/tracers/internal/tracetest/testdata/call_tracer/create.json diff --git a/eth/tracers/testdata/call_tracer_deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json similarity index 100% rename from eth/tracers/testdata/call_tracer_deep_calls.json rename to eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json diff --git a/eth/tracers/testdata/call_tracer_delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json similarity index 100% rename from eth/tracers/testdata/call_tracer_delegatecall.json rename to eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json 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 new file mode 100644 index 0000000000..9395eb401c --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json @@ -0,0 +1,77 @@ +{ + "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": { + "calls": [ + { + "error": "contract creation code storage out of gas", + "from": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", + "gas": "0x39ff0", + "gasUsed": "0x39ff0", + "input": "0x606060405234620000005760405160208062001fd283398101604052515b805b600a8054600160a060020a031916600160a060020a0383161790555b506001600d819055600e81905560408051808201909152600c8082527f566f74696e672053746f636b00000000000000000000000000000000000000006020928301908152600b805460008290528251601860ff1990911617825590947f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9600291831615610100026000190190921604601f0193909304830192906200010c565b828001600101855582156200010c579182015b828111156200010c578251825591602001919060010190620000ef565b5b50620001309291505b808211156200012c576000815560010162000116565b5090565b50506040805180820190915260038082527f43565300000000000000000000000000000000000000000000000000000000006020928301908152600c805460008290528251600660ff1990911617825590937fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c760026001841615610100026000190190931692909204601f010481019291620001f7565b82800160010185558215620001f7579182015b82811115620001f7578251825591602001919060010190620001da565b5b506200021b9291505b808211156200012c576000815560010162000116565b5090565b50505b505b611da280620002306000396000f3006060604052361561019a5763ffffffff60e060020a600035041662e1986d811461019f57806302a72a4c146101d657806306eb4e421461020157806306fdde0314610220578063095ea7b3146102ad578063158ccb99146102dd57806318160ddd146102f85780631cf65a781461031757806323b872dd146103365780632c71e60a1461036c57806333148fd6146103ca578063435ebc2c146103f55780635eeb6e451461041e578063600e85b71461043c5780636103d70b146104a157806362c1e46a146104b05780636c182e99146104ba578063706dc87c146104f057806370a082311461052557806377174f851461055057806395d89b411461056f578063a7771ee3146105fc578063a9059cbb14610629578063ab377daa14610659578063b25dbb5e14610685578063b89a73cb14610699578063ca5eb5e1146106c6578063cbcf2e5a146106e1578063d21f05ba1461070e578063d347c2051461072d578063d96831e114610765578063dd62ed3e14610777578063df3c211b146107a8578063e2982c21146107d6578063eb944e4c14610801575b610000565b34610000576101d4600160a060020a036004351660243567ffffffffffffffff6044358116906064358116906084351661081f565b005b34610000576101ef600160a060020a0360043516610a30565b60408051918252519081900360200190f35b34610000576101ef610a4f565b60408051918252519081900360200190f35b346100005761022d610a55565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516602435610ae3565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516610b4e565b005b34610000576101ef610b89565b60408051918252519081900360200190f35b34610000576101ef610b8f565b60408051918252519081900360200190f35b34610000576102c9600160a060020a0360043581169060243516604435610b95565b604080519115158252519081900360200190f35b3461000057610388600160a060020a0360043516602435610bb7565b60408051600160a060020a039096168652602086019490945267ffffffffffffffff928316858501529082166060850152166080830152519081900360a00190f35b34610000576101ef600160a060020a0360043516610c21565b60408051918252519081900360200190f35b3461000057610402610c40565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d4600160a060020a0360043516602435610c4f565b005b3461000057610458600160a060020a0360043516602435610cc9565b60408051600160a060020a03909716875260208701959095528585019390935267ffffffffffffffff9182166060860152811660808501521660a0830152519081900360c00190f35b34610000576101d4610d9e565b005b6101d4610e1e565b005b34610000576104d3600160a060020a0360043516610e21565b6040805167ffffffffffffffff9092168252519081900360200190f35b3461000057610402600160a060020a0360043516610ead565b60408051600160a060020a039092168252519081900360200190f35b34610000576101ef600160a060020a0360043516610ef9565b60408051918252519081900360200190f35b34610000576101ef610f18565b60408051918252519081900360200190f35b346100005761022d610f1e565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516610fac565b604080519115158252519081900360200190f35b34610000576102c9600160a060020a0360043516602435610fc2565b604080519115158252519081900360200190f35b3461000057610402600435610fe2565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d46004351515610ffd565b005b34610000576102c9600160a060020a036004351661104c565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516611062565b005b34610000576102c9600160a060020a0360043516611070565b604080519115158252519081900360200190f35b34610000576101ef6110f4565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351667ffffffffffffffff602435166110fa565b60408051918252519081900360200190f35b34610000576101d4600435611121565b005b34610000576101ef600160a060020a03600435811690602435166111c6565b60408051918252519081900360200190f35b34610000576101ef6004356024356044356064356084356111f3565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351661128c565b60408051918252519081900360200190f35b34610000576101d4600160a060020a036004351660243561129e565b005b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff848116908416101561086457610000565b8367ffffffffffffffff168267ffffffffffffffff16101561088557610000565b8267ffffffffffffffff168267ffffffffffffffff1610156108a657610000565b506040805160a081018252600160a060020a033381168252602080830188905267ffffffffffffffff80871684860152858116606085015287166080840152908816600090815260039091529190912080546001810180835582818380158290116109615760030281600302836000526020600020918201910161096191905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050916000526020600020906003020160005b5082518154600160a060020a031916600160a060020a03909116178155602083015160018201556040830151600290910180546060850151608086015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff00000000000000001916604060020a918516919091021777ffffffffffffffff000000000000000000000000000000001916608060020a939091169290920291909117905550610a268686610fc2565b505b505050505050565b600160a060020a0381166000908152600360205260409020545b919050565b60055481565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b600a5433600160a060020a03908116911614610b6957610000565b600a8054600160a060020a031916600160a060020a0383161790555b5b50565b60005481565b60005b90565b6000610ba2848484611600565b610bad8484846116e2565b90505b9392505050565b600360205281600052604060002081815481101561000057906000526020600020906003020160005b5080546001820154600290920154600160a060020a03909116935090915067ffffffffffffffff80821691604060020a8104821691608060020a9091041685565b600160a060020a0381166000908152600860205260409020545b919050565b600a54600160a060020a031681565b600a5433600160a060020a03908116911614610c6a57610000565b610c7660005482611714565b6000908155600160a060020a038316815260016020526040902054610c9b9082611714565b600160a060020a038316600090815260016020526040812091909155610cc390839083611600565b5b5b5050565b6000600060006000600060006000600360008a600160a060020a0316600160a060020a0316815260200190815260200160002088815481101561000057906000526020600020906003020160005b508054600182015460028301546040805160a081018252600160a060020a039094168085526020850184905267ffffffffffffffff808416928601839052604060020a8404811660608701819052608060020a9094041660808601819052909c50929a509197509095509350909150610d90904261172d565b94505b509295509295509295565b33600160a060020a038116600090815260066020526040902054801515610dc457610000565b8030600160a060020a0316311015610ddb57610000565b600160a060020a0382166000818152600660205260408082208290555183156108fc0291849190818181858888f193505050501515610cc357610000565b5b5050565b5b565b600160a060020a03811660009081526003602052604081205442915b81811015610ea557600160a060020a03841660009081526003602052604090208054610e9a9190839081101561000057906000526020600020906003020160005b5060020154604060020a900467ffffffffffffffff168461177d565b92505b600101610e3d565b5b5050919050565b600160a060020a0380821660009081526007602052604081205490911615610eef57600160a060020a0380831660009081526007602052604090205416610ef1565b815b90505b919050565b600160a060020a0381166000908152600160205260409020545b919050565b600d5481565b600c805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b60006000610fb983610c21565b1190505b919050565b6000610fcf338484611600565b610fd983836117ac565b90505b92915050565b600460205260009081526040902054600160a060020a031681565b8015801561101a575061100f33610ef9565b61101833610c21565b115b1561102457610000565b33600160a060020a03166000908152600960205260409020805460ff19168215151790555b50565b60006000610fb983610ef9565b1190505b919050565b610b8533826117dc565b5b50565b600a54604080516000602091820181905282517fcbcf2e5a000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015293519194939093169263cbcf2e5a92602480830193919282900301818787803b156100005760325a03f115610000575050604051519150505b919050565b600e5481565b6000610fd961110984846118b2565b61111385856119b6565b611a05565b90505b92915050565b600a5433600160a060020a0390811691161461113c57610000565b61114860005482611a1f565b600055600554600190101561116c57600a5461116c90600160a060020a0316611a47565b5b600a54600160a060020a03166000908152600160205260409020546111929082611a1f565b600a8054600160a060020a039081166000908152600160205260408120939093559054610b8592911683611600565b5b5b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b6000600060008487101561120a5760009250611281565b8387111561121a57879250611281565b61123f6112308961122b888a611714565b611a90565b61123a8689611714565b611abc565b915081925061124e8883611714565b905061127e8361127961126a8461122b8c8b611714565b611a90565b61123a888b611714565b611abc565b611a1f565b92505b505095945050505050565b60066020526000908152604090205481565b600160a060020a03821660009081526003602052604081208054829190849081101561000057906000526020600020906003020160005b50805490925033600160a060020a039081169116146112f357610000565b6040805160a0810182528354600160a060020a0316815260018401546020820152600284015467ffffffffffffffff80821693830193909352604060020a810483166060830152608060020a900490911660808201526113539042611af9565b600160a060020a0385166000908152600360205260409020805491925090849081101561000057906000526020600020906003020160005b508054600160a060020a031916815560006001820181905560029091018054600160c060020a0319169055600160a060020a0385168152600360205260409020805460001981019081101561000057906000526020600020906003020160005b50600160a060020a03851660009081526003602052604090208054859081101561000057906000526020600020906003020160005b5081548154600160a060020a031916600160a060020a03918216178255600180840154908301556002928301805493909201805467ffffffffffffffff191667ffffffffffffffff948516178082558354604060020a908190048616026fffffffffffffffff000000000000000019909116178082559254608060020a9081900490941690930277ffffffffffffffff00000000000000000000000000000000199092169190911790915584166000908152600360205260409020805460001981018083559190829080158290116115485760030281600302836000526020600020918201910161154891905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050600160a060020a033316600090815260016020526040902054611570915082611a1f565b600160a060020a03338116600090815260016020526040808220939093559086168152205461159f9082611714565b600160a060020a038086166000818152600160209081526040918290209490945580518581529051339093169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35b50505050565b600160a060020a0383161561166e576116466008600061161f86610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611714565b6008600061165386610ead565b600160a060020a031681526020810191909152604001600020555b600160a060020a038216156116dc576116b46008600061168d85610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611a1f565b600860006116c185610ead565b600160a060020a031681526020810191909152604001600020555b5b505050565b600083826116f082426110fa565b8111156116fc57610000565b611707868686611b1b565b92505b5b50509392505050565b600061172283831115611b4d565b508082035b92915050565b6000610fd983602001518367ffffffffffffffff16856080015167ffffffffffffffff16866040015167ffffffffffffffff16876060015167ffffffffffffffff166111f3565b90505b92915050565b60008167ffffffffffffffff168367ffffffffffffffff1610156117a15781610fd9565b825b90505b92915050565b600033826117ba82426110fa565b8111156117c657610000565b6117d08585611b5d565b92505b5b505092915050565b6117e582610ef9565b6117ee83610c21565b11156117f957610000565b600160a060020a03811660009081526009602052604090205460ff16158015611834575081600160a060020a031681600160a060020a031614155b1561183e57610000565b61184782611070565b1561185157610000565b611864828261185f85610ef9565b611600565b600160a060020a0382811660009081526007602052604090208054600160a060020a031916918316918217905561189a82610ead565b600160a060020a031614610cc357610000565b5b5050565b600160a060020a038216600090815260036020526040812054815b818110156119885761197d836112796003600089600160a060020a0316600160a060020a0316815260200190815260200160002084815481101561000057906000526020600020906003020160005b506040805160a0810182528254600160a060020a031681526001830154602082015260029092015467ffffffffffffffff80821692840192909252604060020a810482166060840152608060020a900416608082015287611af9565b611a1f565b92505b6001016118cd565b600160a060020a0385166000908152600160205260409020546117d09084611714565b92505b505092915050565b600060006119c384611070565b80156119d157506000600d54115b90506119fb816119e9576119e485610ef9565b6119ec565b60005b6111138686611b7b565b611a05565b91505b5092915050565b60008183106117a15781610fd9565b825b90505b92915050565b6000828201611a3c848210801590611a375750838210155b611b4d565b8091505b5092915050565b611a508161104c565b15611a5a57610b85565b6005805460009081526004602052604090208054600160a060020a031916600160a060020a038416179055805460010190555b50565b6000828202611a3c841580611a37575083858381156100005704145b611b4d565b8091505b5092915050565b60006000611acc60008411611b4d565b8284811561000057049050611a3c838581156100005706828502018514611b4d565b8091505b5092915050565b6000610fd98360200151611b0d858561172d565b611714565b90505b92915050565b60008382611b2982426110fa565b811115611b3557610000565b611707868686611b8f565b92505b5b50509392505050565b801515610b8557610000565b5b50565b6000611b6883611a47565b610fd98383611c92565b90505b92915050565b6000610fd983610ef9565b90505b92915050565b600160a060020a038084166000908152600260209081526040808320338516845282528083205493861683526001909152812054909190611bd09084611a1f565b600160a060020a038086166000908152600160205260408082209390935590871681522054611bff9084611714565b600160a060020a038616600090815260016020526040902055611c228184611714565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60003382611ca082426110fa565b811115611cac57610000565b6117d08585611cc2565b92505b5b505092915050565b600160a060020a033316600090815260016020526040812054611ce59083611714565b600160a060020a033381166000908152600160205260408082209390935590851681522054611d149083611a1f565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b929150505600a165627a7a72305820bfa5ddd3fecf3f43aed25385ec7ec3ef79638c2e58d99f85d9a3cc494183bf160029000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182", + "type": "CREATE", + "value": "0x0" + } + ], + "error": "invalid jump destination", + "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", + "gas": "0x435c8", + "gasUsed": "0x435c8", + "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", + "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json new file mode 100644 index 0000000000..6e221b3c07 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json @@ -0,0 +1,63 @@ +{ + "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": { + "type": "CALL", + "from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", + "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", + "value": "0x0", + "gas": "0x1a466", + "gasUsed": "0x1dc6", + "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", + "output": "0x", + "calls": [] + } +} diff --git a/eth/tracers/testdata/call_tracer_inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json similarity index 100% rename from eth/tracers/testdata/call_tracer_inner_throw_outer_revert.json rename to eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json diff --git a/eth/tracers/testdata/call_tracer_oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json similarity index 100% rename from eth/tracers/testdata/call_tracer_oog.json rename to eth/tracers/internal/tracetest/testdata/call_tracer/oog.json diff --git a/eth/tracers/testdata/call_tracer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json similarity index 100% rename from eth/tracers/testdata/call_tracer_revert.json rename to eth/tracers/internal/tracetest/testdata/call_tracer/revert.json diff --git a/eth/tracers/testdata/call_tracer_revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json similarity index 100% rename from eth/tracers/testdata/call_tracer_revert_reason.json rename to eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json new file mode 100644 index 0000000000..dd717906bc --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json @@ -0,0 +1,75 @@ +{ + "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": "0x61deadff", + "nonce": "1", + "storage": {} + }, + "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": { + "calls": [ + { + "from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "gas": "0x0", + "gasUsed": "0x0", + "input": "0x", + "to": "0x000000000000000000000000000000000000dEaD", + "type": "SELFDESTRUCT", + "value": "0x4d87094125a369d9bd5" + } + ], + "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", + "gas": "0x10738", + "gasUsed": "0x7533", + "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "output": "0x", + "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json new file mode 100644 index 0000000000..08cb7b2d00 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json @@ -0,0 +1,80 @@ +{ + "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": { + "calls": [ + { + "from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "gas": "0x6d05", + "gasUsed": "0x0", + "input": "0x", + "to": "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "type": "CALL", + "value": "0x6f05b59d3b20000" + } + ], + "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", + "gas": "0x10738", + "gasUsed": "0x3ef9", + "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/testdata/call_tracer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json similarity index 100% rename from eth/tracers/testdata/call_tracer_throw.json rename to eth/tracers/internal/tracetest/testdata/call_tracer/throw.json diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json new file mode 100644 index 0000000000..8699bf3e7e --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json @@ -0,0 +1,58 @@ +{ + "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": { + "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", + "gas": "0x5e106", + "gasUsed": "0x5e106", + "input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", + "output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", + "to": "0x7dc9c9730689ff0b0fd506c67db815f12d90a448", + "type": "CREATE", + "value": "0x0" + } +} 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 new file mode 100644 index 0000000000..0353d4cfa9 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json @@ -0,0 +1,415 @@ +{ + "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": { + "calls": [ + { + "from": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "gas": "0x31217", + "gasUsed": "0x334", + "input": "0xe16c7d98636f6e7472616374617069000000000000000000000000000000000000000000", + "output": "0x000000000000000000000000b4fe7aa695b326c9d219158d2ca50db77b39f99f", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "calls": [ + { + "from": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "gas": "0x2a68d", + "gasUsed": "0x334", + "input": "0xe16c7d98636f6e747261637463746c000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "calls": [ + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x23ac9", + "gasUsed": "0x334", + "input": "0xe16c7d98636f6e7472616374646200000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000007986bad81f4cbd9317f5a46861437dae58d69113", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x23366", + "gasUsed": "0x273", + "input": "0x16c66cc6000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x7986bad81f4cbd9317f5a46861437dae58d69113", + "type": "CALL", + "value": "0x0" + } + ], + "from": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "gas": "0x29f35", + "gasUsed": "0xf8d", + "input": "0x16c66cc6000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "gas": "0x28a9e", + "gasUsed": "0x334", + "input": "0xe16c7d98636f6e747261637463746c000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "calls": [ + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x21d79", + "gasUsed": "0x24d", + "input": "0x13bc6d4b000000000000000000000000b4fe7aa695b326c9d219158d2ca50db77b39f99f", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x2165b", + "gasUsed": "0x334", + "input": "0xe16c7d986d61726b65746462000000000000000000000000000000000000000000000000", + "output": "0x000000000000000000000000cf00ffd997ad14939736f026006498e3f099baaf", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "calls": [ + { + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x1a8e8", + "gasUsed": "0x24d", + "input": "0x13bc6d4b0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x1a2c6", + "gasUsed": "0x3cb", + "input": "0xc9503fe2", + "output": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x19b72", + "gasUsed": "0x3cb", + "input": "0xc9503fe2", + "output": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x19428", + "gasUsed": "0x305", + "input": "0x6f265b93", + "output": "0x0000000000000000000000000000000000000000000000283c7b9181eca20000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x18d45", + "gasUsed": "0x229", + "input": "0x2e94420f", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x1734e", + "gasUsed": "0x229", + "input": "0x2e94420f", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + } + ], + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x20ee1", + "gasUsed": "0x5374", + "input": "0x581d5d60000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b0000000000000000000000000000000000000000000000280faf689c35ac0000", + "output": "0x", + "to": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x1b6c1", + "gasUsed": "0x334", + "input": "0xe16c7d986c6f676d67720000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000002a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x1af69", + "gasUsed": "0x229", + "input": "0x2e94420f", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + }, + { + "calls": [ + { + "from": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "gas": "0x143a5", + "gasUsed": "0x24d", + "input": "0x13bc6d4b0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + } + ], + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x1a91d", + "gasUsed": "0x12fa", + "input": "0x0accce0600000000000000000000000000000000000000000000000000000000000000025842545553440000000000000000000000000000000000000000000000000000000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x", + "to": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x19177", + "gasUsed": "0x334", + "input": "0xe16c7d986c6f676d67720000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000002a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x18a22", + "gasUsed": "0x229", + "input": "0x2e94420f", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x18341", + "gasUsed": "0x334", + "input": "0xe16c7d986d61726b65746462000000000000000000000000000000000000000000000000", + "output": "0x000000000000000000000000cf00ffd997ad14939736f026006498e3f099baaf", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x17bec", + "gasUsed": "0x229", + "input": "0x2e94420f", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + }, + { + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x1764e", + "gasUsed": "0x45c", + "input": "0xf92eb7745842545553440000000000000000000000000000000000000000000000000000", + "output": "0x00000000000000000000000000000000000000000000002816d180e30c390000", + "to": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "type": "CALL", + "value": "0x0" + }, + { + "calls": [ + { + "from": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "gas": "0x108ba", + "gasUsed": "0x24d", + "input": "0x13bc6d4b0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "type": "CALL", + "value": "0x0" + } + ], + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x16e62", + "gasUsed": "0xebb", + "input": "0x645a3b72584254555344000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002816d180e30c390000", + "output": "0x", + "to": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "type": "CALL", + "value": "0x0" + } + ], + "from": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "gas": "0x283b9", + "gasUsed": "0xc51c", + "input": "0x949ae479000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b0000000000000000000000000000000000000000000000280faf689c35ac0000", + "output": "0x", + "to": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "type": "CALL", + "value": "0x0" + } + ], + "from": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "gas": "0x30b4a", + "gasUsed": "0xedb7", + "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", + "output": "0x", + "to": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "type": "CALL", + "value": "0x0" + } + ], + "from": "0x70c9217d814985faef62b124420f8dfbddd96433", + "gas": "0x37b38", + "gasUsed": "0x12bb3", + "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", + "output": "0x", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json new file mode 100644 index 0000000000..f7ad6df5f5 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json @@ -0,0 +1,97 @@ +{ + "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": { + "calls": [ + { + "calls": [ + { + "from": "0x13204f5d64c28326fd7bd05fd4ea855302d7f2ff", + "gas": "0x2bf459", + "gasUsed": "0x2aa", + "input": "0x7d65837a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a529806c67cc6486d4d62024471772f47f6fd672", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x42b02b5deeb78f34cd5ac896473b63e6c99a71a2", + "type": "DELEGATECALL" + } + ], + "from": "0x269296dddce321a6bcbaa2f0181127593d732cba", + "gas": "0x2cae73", + "gasUsed": "0xa9d", + "input": "0x5dbe47e8000000000000000000000000a529806c67cc6486d4d62024471772f47f6fd672", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x13204f5d64c28326fd7bd05fd4ea855302d7f2ff", + "type": "CALL", + "value": "0x0" + } + ], + "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", + "gas": "0x2d6e28", + "gasUsed": "0x64bd", + "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", + "output": "0x", + "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/testdata/call_tracer_inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json similarity index 100% rename from eth/tracers/testdata/call_tracer_inner_create_oog_outer_throw.json rename to eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json diff --git a/eth/tracers/testdata/call_tracer_inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json similarity index 100% rename from eth/tracers/testdata/call_tracer_inner_instafail.json rename to eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json 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 new file mode 100644 index 0000000000..7627c8c23d --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json @@ -0,0 +1,81 @@ +{ + "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": { + "calls": [ + { + "error": "invalid opcode: opcode 0xfe not defined", + "from": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", + "gas": "0x75fe3", + "gasUsed": "0x75fe3", + "input": "0xa9059cbb000000000000000000000000d4fcab9f0a6dc0493af47c864f6f17a8a5e2e82600000000000000000000000000000000000000000000000000000000000002f4", + "to": "0xe819f024b41358d2c08e3a868a5c5dd0566078d4", + "type": "CALL", + "value": "0x0" + } + ], + "error": "execution reverted", + "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", + "gas": "0x78d9e", + "gasUsed": "0x76fc0", + "input": "0x", + "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", + "type": "CALL", + "value": "0xe92596fd6290000" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json new file mode 100644 index 0000000000..de4fed6ab1 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json @@ -0,0 +1,60 @@ +{ + "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": { + "error": "out of gas", + "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", + "gas": "0x7045", + "gasUsed": "0x7045", + "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", + "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json new file mode 100644 index 0000000000..059040a1c8 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json @@ -0,0 +1,58 @@ +{ + "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": { + "error": "execution reverted", + "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", + "gas": "0x2d55e8", + "gasUsed": "0xc3", + "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", + "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", + "type": "CALL", + "value": "0x0" + } +} 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 new file mode 100644 index 0000000000..094b044677 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json @@ -0,0 +1,64 @@ +{ + "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": { + "error": "execution reverted", + "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", + "gas": "0x2d7308", + "gasUsed": "0x588", + "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", + "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", + "type": "CALL", + "value": "0x0", + "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e0000" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json new file mode 100644 index 0000000000..132cefa168 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json @@ -0,0 +1,73 @@ +{ + "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": "0x61deadff", + "nonce": "1", + "storage": {} + }, + "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": { + "calls": [ + { + "from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "input": "0x", + "to": "0x000000000000000000000000000000000000dEaD", + "type": "SELFDESTRUCT", + "value": "0x4d87094125a369d9bd5" + } + ], + "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", + "gas": "0x10738", + "gasUsed": "0x7533", + "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "output": "0x", + "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/testdata/call_tracer_simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json similarity index 100% rename from eth/tracers/testdata/call_tracer_simple.json rename to eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json new file mode 100644 index 0000000000..09cf449776 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json @@ -0,0 +1,62 @@ +{ + "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": { + "error": "invalid jump destination", + "from": "0x70c9217d814985faef62b124420f8dfbddd96433", + "gas": "0x37b38", + "gasUsed": "0x37b38", + "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/tracer.go b/eth/tracers/js/bigint.go similarity index 57% rename from eth/tracers/tracer.go rename to eth/tracers/js/bigint.go index ba65925373..9aeb330420 100644 --- a/eth/tracers/tracer.go +++ b/eth/tracers/js/bigint.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// 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 @@ -14,639 +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 tracers - -import ( - "encoding/json" - "errors" - "fmt" - "math/big" - "sync/atomic" - "time" - "unsafe" - - "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/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "gopkg.in/olebedev/go-duktape.v3" -) +package js // bigIntegerJS is the minified version of https://github.com/peterolson/BigInteger.js. const bigIntegerJS = `var bigInt=function(undefined){"use strict";var BASE=1e7,LOG_BASE=7,MAX_INT=9007199254740992,MAX_INT_ARR=smallToArray(MAX_INT),LOG_MAX_INT=Math.log(MAX_INT);function Integer(v,radix){if(typeof v==="undefined")return Integer[0];if(typeof radix!=="undefined")return+radix===10?parseValue(v):parseBase(v,radix);return parseValue(v)}function BigInteger(value,sign){this.value=value;this.sign=sign;this.isSmall=false}BigInteger.prototype=Object.create(Integer.prototype);function SmallInteger(value){this.value=value;this.sign=value<0;this.isSmall=true}SmallInteger.prototype=Object.create(Integer.prototype);function isPrecise(n){return-MAX_INT0)return Math.floor(n);return Math.ceil(n)}function add(a,b){var l_a=a.length,l_b=b.length,r=new Array(l_a),carry=0,base=BASE,sum,i;for(i=0;i=base?1:0;r[i]=sum-carry*base}while(i0)r.push(carry);return r}function addAny(a,b){if(a.length>=b.length)return add(a,b);return add(b,a)}function addSmall(a,carry){var l=a.length,r=new Array(l),base=BASE,sum,i;for(i=0;i0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}BigInteger.prototype.add=function(v){var n=parseValue(v);if(this.sign!==n.sign){return this.subtract(n.negate())}var a=this.value,b=n.value;if(n.isSmall){return new BigInteger(addSmall(a,Math.abs(b)),this.sign)}return new BigInteger(addAny(a,b),this.sign)};BigInteger.prototype.plus=BigInteger.prototype.add;SmallInteger.prototype.add=function(v){var n=parseValue(v);var a=this.value;if(a<0!==n.sign){return this.subtract(n.negate())}var b=n.value;if(n.isSmall){if(isPrecise(a+b))return new SmallInteger(a+b);b=smallToArray(Math.abs(b))}return new BigInteger(addSmall(b,Math.abs(a)),a<0)};SmallInteger.prototype.plus=SmallInteger.prototype.add;function subtract(a,b){var a_l=a.length,b_l=b.length,r=new Array(a_l),borrow=0,base=BASE,i,difference;for(i=0;i=0){value=subtract(a,b)}else{value=subtract(b,a);sign=!sign}value=arrayToSmall(value);if(typeof value==="number"){if(sign)value=-value;return new SmallInteger(value)}return new BigInteger(value,sign)}function subtractSmall(a,b,sign){var l=a.length,r=new Array(l),carry=-b,base=BASE,i,difference;for(i=0;i=0)};SmallInteger.prototype.minus=SmallInteger.prototype.subtract;BigInteger.prototype.negate=function(){return new BigInteger(this.value,!this.sign)};SmallInteger.prototype.negate=function(){var sign=this.sign;var small=new SmallInteger(-this.value);small.sign=!sign;return small};BigInteger.prototype.abs=function(){return new BigInteger(this.value,false)};SmallInteger.prototype.abs=function(){return new SmallInteger(Math.abs(this.value))};function multiplyLong(a,b){var a_l=a.length,b_l=b.length,l=a_l+b_l,r=createArray(l),base=BASE,product,carry,i,a_i,b_j;for(i=0;i0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}function shiftLeft(x,n){var r=[];while(n-- >0)r.push(0);return r.concat(x)}function multiplyKaratsuba(x,y){var n=Math.max(x.length,y.length);if(n<=30)return multiplyLong(x,y);n=Math.ceil(n/2);var b=x.slice(n),a=x.slice(0,n),d=y.slice(n),c=y.slice(0,n);var ac=multiplyKaratsuba(a,c),bd=multiplyKaratsuba(b,d),abcd=multiplyKaratsuba(addAny(a,b),addAny(c,d));var product=addAny(addAny(ac,shiftLeft(subtract(subtract(abcd,ac),bd),n)),shiftLeft(bd,2*n));trim(product);return product}function useKaratsuba(l1,l2){return-.012*l1-.012*l2+15e-6*l1*l2>0}BigInteger.prototype.multiply=function(v){var n=parseValue(v),a=this.value,b=n.value,sign=this.sign!==n.sign,abs;if(n.isSmall){if(b===0)return Integer[0];if(b===1)return this;if(b===-1)return this.negate();abs=Math.abs(b);if(abs=0;shift--){quotientDigit=base-1;if(remainder[shift+b_l]!==divisorMostSignificantDigit){quotientDigit=Math.floor((remainder[shift+b_l]*base+remainder[shift+b_l-1])/divisorMostSignificantDigit)}carry=0;borrow=0;l=divisor.length;for(i=0;ib_l){highx=(highx+1)*base}guess=Math.ceil(highx/highy);do{check=multiplySmall(b,guess);if(compareAbs(check,part)<=0)break;guess--}while(guess);result.push(guess);part=subtract(part,check)}result.reverse();return[arrayToSmall(result),arrayToSmall(part)]}function divModSmall(value,lambda){var length=value.length,quotient=createArray(length),base=BASE,i,q,remainder,divisor;remainder=0;for(i=length-1;i>=0;--i){divisor=remainder*base+value[i];q=truncate(divisor/lambda);remainder=divisor-q*lambda;quotient[i]=q|0}return[quotient,remainder|0]}function divModAny(self,v){var value,n=parseValue(v);var a=self.value,b=n.value;var quotient;if(b===0)throw new Error("Cannot divide by zero");if(self.isSmall){if(n.isSmall){return[new SmallInteger(truncate(a/b)),new SmallInteger(a%b)]}return[Integer[0],self]}if(n.isSmall){if(b===1)return[self,Integer[0]];if(b==-1)return[self.negate(),Integer[0]];var abs=Math.abs(b);if(absb.length?1:-1}for(var i=a.length-1;i>=0;i--){if(a[i]!==b[i])return a[i]>b[i]?1:-1}return 0}BigInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall)return 1;return compareAbs(a,b)};SmallInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=Math.abs(this.value),b=n.value;if(n.isSmall){b=Math.abs(b);return a===b?0:a>b?1:-1}return-1};BigInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(this.sign!==n.sign){return n.sign?1:-1}if(n.isSmall){return this.sign?-1:1}return compareAbs(a,b)*(this.sign?-1:1)};BigInteger.prototype.compareTo=BigInteger.prototype.compare;SmallInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall){return a==b?0:a>b?1:-1}if(a<0!==n.sign){return a<0?-1:1}return a<0?1:-1};SmallInteger.prototype.compareTo=SmallInteger.prototype.compare;BigInteger.prototype.equals=function(v){return this.compare(v)===0};SmallInteger.prototype.eq=SmallInteger.prototype.equals=BigInteger.prototype.eq=BigInteger.prototype.equals;BigInteger.prototype.notEquals=function(v){return this.compare(v)!==0};SmallInteger.prototype.neq=SmallInteger.prototype.notEquals=BigInteger.prototype.neq=BigInteger.prototype.notEquals;BigInteger.prototype.greater=function(v){return this.compare(v)>0};SmallInteger.prototype.gt=SmallInteger.prototype.greater=BigInteger.prototype.gt=BigInteger.prototype.greater;BigInteger.prototype.lesser=function(v){return this.compare(v)<0};SmallInteger.prototype.lt=SmallInteger.prototype.lesser=BigInteger.prototype.lt=BigInteger.prototype.lesser;BigInteger.prototype.greaterOrEquals=function(v){return this.compare(v)>=0};SmallInteger.prototype.geq=SmallInteger.prototype.greaterOrEquals=BigInteger.prototype.geq=BigInteger.prototype.greaterOrEquals;BigInteger.prototype.lesserOrEquals=function(v){return this.compare(v)<=0};SmallInteger.prototype.leq=SmallInteger.prototype.lesserOrEquals=BigInteger.prototype.leq=BigInteger.prototype.lesserOrEquals;BigInteger.prototype.isEven=function(){return(this.value[0]&1)===0};SmallInteger.prototype.isEven=function(){return(this.value&1)===0};BigInteger.prototype.isOdd=function(){return(this.value[0]&1)===1};SmallInteger.prototype.isOdd=function(){return(this.value&1)===1};BigInteger.prototype.isPositive=function(){return!this.sign};SmallInteger.prototype.isPositive=function(){return this.value>0};BigInteger.prototype.isNegative=function(){return this.sign};SmallInteger.prototype.isNegative=function(){return this.value<0};BigInteger.prototype.isUnit=function(){return false};SmallInteger.prototype.isUnit=function(){return Math.abs(this.value)===1};BigInteger.prototype.isZero=function(){return false};SmallInteger.prototype.isZero=function(){return this.value===0};BigInteger.prototype.isDivisibleBy=function(v){var n=parseValue(v);var value=n.value;if(value===0)return false;if(value===1)return true;if(value===2)return this.isEven();return this.mod(n).equals(Integer[0])};SmallInteger.prototype.isDivisibleBy=BigInteger.prototype.isDivisibleBy;function isBasicPrime(v){var n=v.abs();if(n.isUnit())return false;if(n.equals(2)||n.equals(3)||n.equals(5))return true;if(n.isEven()||n.isDivisibleBy(3)||n.isDivisibleBy(5))return false;if(n.lesser(25))return true}BigInteger.prototype.isPrime=function(){var isPrime=isBasicPrime(this);if(isPrime!==undefined)return isPrime;var n=this.abs(),nPrev=n.prev();var a=[2,3,5,7,11,13,17,19],b=nPrev,d,t,i,x;while(b.isEven())b=b.divide(2);for(i=0;i-MAX_INT)return new SmallInteger(value-1);return new BigInteger(MAX_INT_ARR,true)};var powersOfTwo=[1];while(2*powersOfTwo[powersOfTwo.length-1]<=BASE)powersOfTwo.push(2*powersOfTwo[powersOfTwo.length-1]);var powers2Length=powersOfTwo.length,highestPower2=powersOfTwo[powers2Length-1];function shift_isSmall(n){return(typeof n==="number"||typeof n==="string")&&+Math.abs(n)<=BASE||n instanceof BigInteger&&n.value.length<=1}BigInteger.prototype.shiftLeft=function(n){if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}n=+n;if(n<0)return this.shiftRight(-n);var result=this;while(n>=powers2Length){result=result.multiply(highestPower2);n-=powers2Length-1}return result.multiply(powersOfTwo[n])};SmallInteger.prototype.shiftLeft=BigInteger.prototype.shiftLeft;BigInteger.prototype.shiftRight=function(n){var remQuo;if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}n=+n;if(n<0)return this.shiftLeft(-n);var result=this;while(n>=powers2Length){if(result.isZero())return result;remQuo=divModAny(result,highestPower2);result=remQuo[1].isNegative()?remQuo[0].prev():remQuo[0];n-=powers2Length-1}remQuo=divModAny(result,powersOfTwo[n]);return remQuo[1].isNegative()?remQuo[0].prev():remQuo[0]};SmallInteger.prototype.shiftRight=BigInteger.prototype.shiftRight;function bitwise(x,y,fn){y=parseValue(y);var xSign=x.isNegative(),ySign=y.isNegative();var xRem=xSign?x.not():x,yRem=ySign?y.not():y;var xDigit=0,yDigit=0;var xDivMod=null,yDivMod=null;var result=[];while(!xRem.isZero()||!yRem.isZero()){xDivMod=divModAny(xRem,highestPower2);xDigit=xDivMod[1].toJSNumber();if(xSign){xDigit=highestPower2-1-xDigit}yDivMod=divModAny(yRem,highestPower2);yDigit=yDivMod[1].toJSNumber();if(ySign){yDigit=highestPower2-1-yDigit}xRem=xDivMod[0];yRem=yDivMod[0];result.push(fn(xDigit,yDigit))}var sum=fn(xSign?1:0,ySign?1:0)!==0?bigInt(-1):bigInt(0);for(var i=result.length-1;i>=0;i-=1){sum=sum.multiply(highestPower2).add(bigInt(result[i]))}return sum}BigInteger.prototype.not=function(){return this.negate().prev()};SmallInteger.prototype.not=BigInteger.prototype.not;BigInteger.prototype.and=function(n){return bitwise(this,n,function(a,b){return a&b})};SmallInteger.prototype.and=BigInteger.prototype.and;BigInteger.prototype.or=function(n){return bitwise(this,n,function(a,b){return a|b})};SmallInteger.prototype.or=BigInteger.prototype.or;BigInteger.prototype.xor=function(n){return bitwise(this,n,function(a,b){return a^b})};SmallInteger.prototype.xor=BigInteger.prototype.xor;var LOBMASK_I=1<<30,LOBMASK_BI=(BASE&-BASE)*(BASE&-BASE)|LOBMASK_I;function roughLOB(n){var v=n.value,x=typeof v==="number"?v|LOBMASK_I:v[0]+v[1]*BASE|LOBMASK_BI;return x&-x}function max(a,b){a=parseValue(a);b=parseValue(b);return a.greater(b)?a:b}function min(a,b){a=parseValue(a);b=parseValue(b);return a.lesser(b)?a:b}function gcd(a,b){a=parseValue(a).abs();b=parseValue(b).abs();if(a.equals(b))return a;if(a.isZero())return b;if(b.isZero())return a;var c=Integer[1],d,t;while(a.isEven()&&b.isEven()){d=Math.min(roughLOB(a),roughLOB(b));a=a.divide(d);b=b.divide(d);c=c.multiply(d)}while(a.isEven()){a=a.divide(roughLOB(a))}do{while(b.isEven()){b=b.divide(roughLOB(b))}if(a.greater(b)){t=b;b=a;a=t}b=b.subtract(a)}while(!b.isZero());return c.isUnit()?a:a.multiply(c)}function lcm(a,b){a=parseValue(a).abs();b=parseValue(b).abs();return a.divide(gcd(a,b)).multiply(b)}function randBetween(a,b){a=parseValue(a);b=parseValue(b);var low=min(a,b),high=max(a,b);var range=high.subtract(low).add(1);if(range.isSmall)return low.add(Math.floor(Math.random()*range));var length=range.value.length-1;var result=[],restricted=true;for(var i=length;i>=0;i--){var top=restricted?range.value[i]:BASE;var digit=truncate(Math.random()*top);result.unshift(digit);if(digit=absBase){if(c==="1"&&absBase===1)continue;throw new Error(c+" is not a valid digit in base "+base+".")}else if(c.charCodeAt(0)-87>=absBase){throw new Error(c+" is not a valid digit in base "+base+".")}}}if(2<=base&&base<=36){if(length<=LOG_MAX_INT/Math.log(base)){var result=parseInt(text,base);if(isNaN(result)){throw new Error(c+" is not a valid digit in base "+base+".")}return new SmallInteger(parseInt(text,base))}}base=parseValue(base);var digits=[];var isNegative=text[0]==="-";for(i=isNegative?1:0;i");digits.push(parseValue(text.slice(start+1,i)))}else throw new Error(c+" is not a valid character")}return parseBaseFromArray(digits,base,isNegative)};function parseBaseFromArray(digits,base,isNegative){var val=Integer[0],pow=Integer[1],i;for(i=digits.length-1;i>=0;i--){val=val.add(digits[i].times(pow));pow=pow.times(base)}return isNegative?val.negate():val}function stringify(digit){var v=digit.value;if(typeof v==="number")v=[v];if(v.length===1&&v[0]<=35){return"0123456789abcdefghijklmnopqrstuvwxyz".charAt(v[0])}return"<"+v+">"}function toBase(n,base){base=bigInt(base);if(base.isZero()){if(n.isZero())return"0";throw new Error("Cannot convert nonzero numbers to base 0.")}if(base.equals(-1)){if(n.isZero())return"0";if(n.isNegative())return new Array(1-n).join("10");return"1"+new Array(+n).join("01")}var minusSign="";if(n.isNegative()&&base.isPositive()){minusSign="-";n=n.abs()}if(base.equals(1)){if(n.isZero())return"0";return minusSign+new Array(+n+1).join(1)}var out=[];var left=n,divmod;while(left.isNegative()||left.compareAbs(base)>=0){divmod=left.divmod(base);left=divmod.quotient;var digit=divmod.remainder;if(digit.isNegative()){digit=base.minus(digit).abs();left=left.next()}out.push(stringify(digit))}out.push(stringify(left));return minusSign+out.reverse().join("")}BigInteger.prototype.toString=function(radix){if(radix===undefined)radix=10;if(radix!==10)return toBase(this,radix);var v=this.value,l=v.length,str=String(v[--l]),zeros="0000000",digit;while(--l>=0){digit=String(v[l]);str+=zeros.slice(digit.length)+digit}var sign=this.sign?"-":"";return sign+str};SmallInteger.prototype.toString=function(radix){if(radix===undefined)radix=10;if(radix!=10)return toBase(this,radix);return String(this.value)};BigInteger.prototype.toJSON=SmallInteger.prototype.toJSON=function(){return this.toString()};BigInteger.prototype.valueOf=function(){return+this.toString()};BigInteger.prototype.toJSNumber=BigInteger.prototype.valueOf;SmallInteger.prototype.valueOf=function(){return this.value};SmallInteger.prototype.toJSNumber=SmallInteger.prototype.valueOf;function parseStringValue(v){if(isPrecise(+v)){var x=+v;if(x===truncate(x))return new SmallInteger(x);throw"Invalid integer: "+v}var sign=v[0]==="-";if(sign)v=v.slice(1);var split=v.split(/e/i);if(split.length>2)throw new Error("Invalid integer: "+split.join("e"));if(split.length===2){var exp=split[1];if(exp[0]==="+")exp=exp.slice(1);exp=+exp;if(exp!==truncate(exp)||!isPrecise(exp))throw new Error("Invalid integer: "+exp+" is not a valid exponent.");var text=split[0];var decimalPlace=text.indexOf(".");if(decimalPlace>=0){exp-=text.length-decimalPlace-1;text=text.slice(0,decimalPlace)+text.slice(decimalPlace+1)}if(exp<0)throw new Error("Cannot include negative exponent part for integers");text+=new Array(exp+1).join("0");v=text}var isValid=/^([0-9][0-9]*)$/.test(v);if(!isValid)throw new Error("Invalid integer: "+v);var r=[],max=v.length,l=LOG_BASE,min=max-l;while(max>0){r.push(+v.slice(min,max));min-=l;if(min<0)min=0;max-=l}trim(r);return new BigInteger(r,sign)}function parseNumberValue(v){if(isPrecise(v)){if(v!==truncate(v))throw new Error(v+" is not an integer.");return new SmallInteger(v)}return parseStringValue(v.toString())}function parseValue(v){if(typeof v==="number"){return parseNumberValue(v)}if(typeof v==="string"){return parseStringValue(v)}return v}for(var i=0;i<1e3;i++){Integer[i]=new SmallInteger(i);if(i>0)Integer[-i]=new SmallInteger(-i)}Integer.one=Integer[1];Integer.zero=Integer[0];Integer.minusOne=Integer[-1];Integer.max=max;Integer.min=min;Integer.gcd=gcd;Integer.lcm=lcm;Integer.isInstance=function(x){return x instanceof BigInteger||x instanceof SmallInteger};Integer.randBetween=randBetween;Integer.fromArray=function(digits,base,isNegative){return parseBaseFromArray(digits.map(parseValue),parseValue(base||10),isNegative)};return Integer}();if(typeof module!=="undefined"&&module.hasOwnProperty("exports")){module.exports=bigInt}if(typeof define==="function"&&define.amd){define("big-integer",[],function(){return bigInt})}; bigInt` - -// makeSlice convert an unsafe memory pointer with the given type into a Go byte -// slice. -// -// Note, the returned slice uses the same memory area as the input arguments. -// If those are duktape stack items, popping them off **will** make the slice -// contents change. -func makeSlice(ptr unsafe.Pointer, size uint) []byte { - var sl = struct { - addr uintptr - len int - cap int - }{uintptr(ptr), int(size), int(size)} - - return *(*[]byte)(unsafe.Pointer(&sl)) -} - -// popSlice pops a buffer off the JavaScript stack and returns it as a slice. -func popSlice(ctx *duktape.Context) []byte { - blob := common.CopyBytes(makeSlice(ctx.GetBuffer(-1))) - ctx.Pop() - return blob -} - -// pushBigInt create a JavaScript BigInteger in the VM. -func pushBigInt(n *big.Int, ctx *duktape.Context) { - ctx.GetGlobalString("bigInt") - ctx.PushString(n.String()) - ctx.Call(1) -} - -// opWrapper provides a JavaScript wrapper around OpCode. -type opWrapper struct { - op vm.OpCode -} - -// pushObject assembles a JSVM object wrapping a swappable opcode and pushes it -// onto the VM stack. -func (ow *opWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(int(ow.op)); return 1 }) - vm.PutPropString(obj, "toNumber") - - vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushString(ow.op.String()); return 1 }) - vm.PutPropString(obj, "toString") - - vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushBoolean(ow.op.IsPush()); return 1 }) - vm.PutPropString(obj, "isPush") -} - -// memoryWrapper provides a JavaScript wrapper around vm.Memory. -type memoryWrapper struct { - memory *vm.Memory -} - -// slice returns the requested range of memory as a byte slice. -func (mw *memoryWrapper) slice(begin, end int64) []byte { - if end == begin { - return []byte{} - } - if end < begin || begin < 0 { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound memory", "offset", begin, "end", end) - return nil - } - if mw.memory.Len() < int(end) { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", begin, "size", end-begin) - return nil - } - return mw.memory.GetCopy(begin, end-begin) -} - -// getUint returns the 32 bytes at the specified address interpreted as a uint. -func (mw *memoryWrapper) getUint(addr int64) *big.Int { - if mw.memory.Len() < int(addr)+32 || addr < 0 { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", addr, "size", 32) - return new(big.Int) - } - return new(big.Int).SetBytes(mw.memory.GetPtr(addr, 32)) -} - -// pushObject assembles a JSVM object wrapping a swappable memory and pushes it -// onto the VM stack. -func (mw *memoryWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - // Generate the `slice` method which takes two ints and returns a buffer - vm.PushGoFunction(func(ctx *duktape.Context) int { - blob := mw.slice(int64(ctx.GetInt(-2)), int64(ctx.GetInt(-1))) - ctx.Pop2() - - ptr := ctx.PushFixedBuffer(len(blob)) - copy(makeSlice(ptr, uint(len(blob))), blob) - return 1 - }) - vm.PutPropString(obj, "slice") - - // Generate the `getUint` method which takes an int and returns a bigint - vm.PushGoFunction(func(ctx *duktape.Context) int { - offset := int64(ctx.GetInt(-1)) - ctx.Pop() - - pushBigInt(mw.getUint(offset), ctx) - return 1 - }) - vm.PutPropString(obj, "getUint") -} - -// stackWrapper provides a JavaScript wrapper around vm.Stack. -type stackWrapper struct { - stack *vm.Stack -} - -// peek returns the nth-from-the-top element of the stack. -func (sw *stackWrapper) peek(idx int) *big.Int { - if len(sw.stack.Data()) <= idx || idx < 0 { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx) - return new(big.Int) - } - return sw.stack.Back(idx).ToBig() -} - -// pushObject assembles a JSVM object wrapping a swappable stack and pushes it -// onto the VM stack. -func (sw *stackWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(len(sw.stack.Data())); return 1 }) - vm.PutPropString(obj, "length") - - // Generate the `peek` method which takes an int and returns a bigint - vm.PushGoFunction(func(ctx *duktape.Context) int { - offset := ctx.GetInt(-1) - ctx.Pop() - - pushBigInt(sw.peek(offset), ctx) - return 1 - }) - vm.PutPropString(obj, "peek") -} - -// dbWrapper provides a JavaScript wrapper around vm.Database. -type dbWrapper struct { - db vm.StateDB -} - -// pushObject assembles a JSVM object wrapping a swappable database and pushes it -// onto the VM stack. -func (dw *dbWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - // Push the wrapper for statedb.GetBalance - vm.PushGoFunction(func(ctx *duktape.Context) int { - pushBigInt(dw.db.GetBalance(common.BytesToAddress(popSlice(ctx))), ctx) - return 1 - }) - vm.PutPropString(obj, "getBalance") - - // Push the wrapper for statedb.GetNonce - vm.PushGoFunction(func(ctx *duktape.Context) int { - ctx.PushInt(int(dw.db.GetNonce(common.BytesToAddress(popSlice(ctx))))) - return 1 - }) - vm.PutPropString(obj, "getNonce") - - // Push the wrapper for statedb.GetCode - vm.PushGoFunction(func(ctx *duktape.Context) int { - code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx))) - - ptr := ctx.PushFixedBuffer(len(code)) - copy(makeSlice(ptr, uint(len(code))), code) - return 1 - }) - vm.PutPropString(obj, "getCode") - - // Push the wrapper for statedb.GetState - vm.PushGoFunction(func(ctx *duktape.Context) int { - hash := popSlice(ctx) - addr := popSlice(ctx) - - state := dw.db.GetState(common.BytesToAddress(addr), common.BytesToHash(hash)) - - ptr := ctx.PushFixedBuffer(len(state)) - copy(makeSlice(ptr, uint(len(state))), state[:]) - return 1 - }) - vm.PutPropString(obj, "getState") - - // Push the wrapper for statedb.Exists - vm.PushGoFunction(func(ctx *duktape.Context) int { - ctx.PushBoolean(dw.db.Exist(common.BytesToAddress(popSlice(ctx)))) - return 1 - }) - vm.PutPropString(obj, "exists") -} - -// contractWrapper provides a JavaScript wrapper around vm.Contract -type contractWrapper struct { - contract *vm.Contract -} - -// pushObject assembles a JSVM object wrapping a swappable contract and pushes it -// onto the VM stack. -func (cw *contractWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - // Push the wrapper for contract.Caller - vm.PushGoFunction(func(ctx *duktape.Context) int { - ptr := ctx.PushFixedBuffer(20) - copy(makeSlice(ptr, 20), cw.contract.Caller().Bytes()) - return 1 - }) - vm.PutPropString(obj, "getCaller") - - // Push the wrapper for contract.Address - vm.PushGoFunction(func(ctx *duktape.Context) int { - ptr := ctx.PushFixedBuffer(20) - copy(makeSlice(ptr, 20), cw.contract.Address().Bytes()) - return 1 - }) - vm.PutPropString(obj, "getAddress") - - // Push the wrapper for contract.Value - vm.PushGoFunction(func(ctx *duktape.Context) int { - pushBigInt(cw.contract.Value(), ctx) - return 1 - }) - vm.PutPropString(obj, "getValue") - - // Push the wrapper for contract.Input - vm.PushGoFunction(func(ctx *duktape.Context) int { - blob := cw.contract.Input - - ptr := ctx.PushFixedBuffer(len(blob)) - copy(makeSlice(ptr, uint(len(blob))), blob) - return 1 - }) - vm.PutPropString(obj, "getInput") -} - -// Tracer provides an implementation of Tracer that evaluates a Javascript -// function for each VM execution step. -type Tracer struct { - vm *duktape.Context // Javascript VM instance - - tracerObject int // Stack index of the tracer JavaScript object - stateObject int // Stack index of the global state to pull arguments from - - opWrapper *opWrapper // Wrapper around the VM opcode - stackWrapper *stackWrapper // Wrapper around the VM stack - memoryWrapper *memoryWrapper // Wrapper around the VM memory - contractWrapper *contractWrapper // Wrapper around the contract object - dbWrapper *dbWrapper // Wrapper around the VM environment - - pcValue *uint // Swappable pc value wrapped by a log accessor - gasValue *uint // Swappable gas value wrapped by a log accessor - costValue *uint // Swappable cost value wrapped by a log accessor - depthValue *uint // Swappable depth value wrapped by a log accessor - errorValue *string // Swappable error value wrapped by a log accessor - refundValue *uint // Swappable refund value wrapped by a log accessor - - ctx map[string]interface{} // Transaction context gathered throughout execution - err error // Error, if one has occurred - - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption -} - -// New instantiates a new tracer instance. code specifies a Javascript snippet, -// which must evaluate to an expression returning an object with 'step', 'fault' -// and 'result' functions. -func New(code string, txCtx vm.TxContext) (*Tracer, error) { - // Resolve any tracers by name and assemble the tracer object - if tracer, ok := tracer(code); ok { - code = tracer - } - tracer := &Tracer{ - vm: duktape.New(), - ctx: make(map[string]interface{}), - opWrapper: new(opWrapper), - stackWrapper: new(stackWrapper), - memoryWrapper: new(memoryWrapper), - contractWrapper: new(contractWrapper), - dbWrapper: new(dbWrapper), - pcValue: new(uint), - gasValue: new(uint), - costValue: new(uint), - depthValue: new(uint), - refundValue: new(uint), - } - tracer.ctx["gasPrice"] = txCtx.GasPrice - - // Set up builtins for this environment - tracer.vm.PushGlobalGoFunction("toHex", func(ctx *duktape.Context) int { - ctx.PushString(hexutil.Encode(popSlice(ctx))) - return 1 - }) - tracer.vm.PushGlobalGoFunction("toWord", func(ctx *duktape.Context) int { - var word common.Hash - if ptr, size := ctx.GetBuffer(-1); ptr != nil { - word = common.BytesToHash(makeSlice(ptr, size)) - } else { - word = common.HexToHash(ctx.GetString(-1)) - } - ctx.Pop() - copy(makeSlice(ctx.PushFixedBuffer(32), 32), word[:]) - return 1 - }) - tracer.vm.PushGlobalGoFunction("toAddress", func(ctx *duktape.Context) int { - var addr common.Address - if ptr, size := ctx.GetBuffer(-1); ptr != nil { - addr = common.BytesToAddress(makeSlice(ptr, size)) - } else { - addr = common.HexToAddress(ctx.GetString(-1)) - } - ctx.Pop() - copy(makeSlice(ctx.PushFixedBuffer(20), 20), addr[:]) - return 1 - }) - tracer.vm.PushGlobalGoFunction("toContract", func(ctx *duktape.Context) int { - var from common.Address - if ptr, size := ctx.GetBuffer(-2); ptr != nil { - from = common.BytesToAddress(makeSlice(ptr, size)) - } else { - from = common.HexToAddress(ctx.GetString(-2)) - } - nonce := uint64(ctx.GetInt(-1)) - ctx.Pop2() - - contract := crypto.CreateAddress(from, nonce) - copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) - return 1 - }) - tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int { - var from common.Address - if ptr, size := ctx.GetBuffer(-3); ptr != nil { - from = common.BytesToAddress(makeSlice(ptr, size)) - } else { - from = common.HexToAddress(ctx.GetString(-3)) - } - // Retrieve salt hex string from js stack - salt := common.HexToHash(ctx.GetString(-2)) - // Retrieve code slice from js stack - var code []byte - if ptr, size := ctx.GetBuffer(-1); ptr != nil { - code = common.CopyBytes(makeSlice(ptr, size)) - } else { - code = common.FromHex(ctx.GetString(-1)) - } - codeHash := crypto.Keccak256(code) - ctx.Pop3() - contract := crypto.CreateAddress2(from, salt, codeHash) - copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) - return 1 - }) - tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int { - _, ok := vm.PrecompiledContractsIstanbul[common.BytesToAddress(popSlice(ctx))] - ctx.PushBoolean(ok) - return 1 - }) - tracer.vm.PushGlobalGoFunction("slice", func(ctx *duktape.Context) int { - start, end := ctx.GetInt(-2), ctx.GetInt(-1) - ctx.Pop2() - - blob := popSlice(ctx) - size := end - start - - if start < 0 || start > end || end > len(blob) { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound memory", "available", len(blob), "offset", start, "size", size) - ctx.PushFixedBuffer(0) - return 1 - } - copy(makeSlice(ctx.PushFixedBuffer(size), uint(size)), blob[start:end]) - return 1 - }) - // Push the JavaScript tracer as object #0 onto the JSVM stack and validate it - if err := tracer.vm.PevalString("(" + code + ")"); err != nil { - log.Warn("Failed to compile tracer", "err", err) - return nil, err - } - tracer.tracerObject = 0 // yeah, nice, eval can't return the index itself - - if !tracer.vm.GetPropString(tracer.tracerObject, "step") { - return nil, fmt.Errorf("trace object must expose a function step()") - } - tracer.vm.Pop() - - if !tracer.vm.GetPropString(tracer.tracerObject, "fault") { - return nil, fmt.Errorf("trace object must expose a function fault()") - } - tracer.vm.Pop() - - if !tracer.vm.GetPropString(tracer.tracerObject, "result") { - return nil, fmt.Errorf("trace object must expose a function result()") - } - tracer.vm.Pop() - - // Tracer is valid, inject the big int library to access large numbers - tracer.vm.EvalString(bigIntegerJS) - tracer.vm.PutGlobalString("bigInt") - - // Push the global environment state as object #1 into the JSVM stack - tracer.stateObject = tracer.vm.PushObject() - - logObject := tracer.vm.PushObject() - - tracer.opWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(logObject, "op") - - tracer.stackWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(logObject, "stack") - - tracer.memoryWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(logObject, "memory") - - tracer.contractWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(logObject, "contract") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.pcValue); return 1 }) - tracer.vm.PutPropString(logObject, "getPC") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.gasValue); return 1 }) - tracer.vm.PutPropString(logObject, "getGas") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.costValue); return 1 }) - tracer.vm.PutPropString(logObject, "getCost") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.depthValue); return 1 }) - tracer.vm.PutPropString(logObject, "getDepth") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.refundValue); return 1 }) - tracer.vm.PutPropString(logObject, "getRefund") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { - if tracer.errorValue != nil { - ctx.PushString(*tracer.errorValue) - } else { - ctx.PushUndefined() - } - return 1 - }) - tracer.vm.PutPropString(logObject, "getError") - - tracer.vm.PutPropString(tracer.stateObject, "log") - - tracer.dbWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(tracer.stateObject, "db") - - return tracer, nil -} - -// Stop terminates execution of the tracer at the first opportune moment. -func (jst *Tracer) Stop(err error) { - jst.reason = err - atomic.StoreUint32(&jst.interrupt, 1) -} - -// call executes a method on a JS object, catching any errors, formatting and -// returning them as error objects. -func (jst *Tracer) call(method string, args ...string) (json.RawMessage, error) { - // Execute the JavaScript call and return any error - jst.vm.PushString(method) - for _, arg := range args { - jst.vm.GetPropString(jst.stateObject, arg) - } - code := jst.vm.PcallProp(jst.tracerObject, len(args)) - defer jst.vm.Pop() - - if code != 0 { - err := jst.vm.SafeToString(-1) - return nil, errors.New(err) - } - // No error occurred, extract return value and return - return json.RawMessage(jst.vm.JsonEncode(-1)), nil -} - -func wrapError(context string, err error) error { - return fmt.Errorf("%v in server-side tracer function '%v'", err, context) -} - -// CaptureStart implements the Tracer interface to initialize the tracing operation. -func (jst *Tracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - jst.ctx["type"] = "CALL" - if create { - jst.ctx["type"] = "CREATE" - } - jst.ctx["from"] = from - jst.ctx["to"] = to - jst.ctx["input"] = input - jst.ctx["gas"] = gas - jst.ctx["value"] = value - - // Initialize the context - jst.ctx["block"] = env.Context.BlockNumber.Uint64() - jst.dbWrapper.db = env.StateDB - // Compute intrinsic gas - isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) - isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) - intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul) - if err != nil { - return - } - jst.ctx["intrinsicGas"] = intrinsicGas -} - -// CaptureState implements the Tracer interface to trace a single step of VM execution. -func (jst *Tracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - if jst.err != nil { - return - } - // If tracing was interrupted, set the error and stop - if atomic.LoadUint32(&jst.interrupt) > 0 { - jst.err = jst.reason - return - } - jst.opWrapper.op = op - jst.stackWrapper.stack = scope.Stack - jst.memoryWrapper.memory = scope.Memory - jst.contractWrapper.contract = scope.Contract - - *jst.pcValue = uint(pc) - *jst.gasValue = uint(gas) - *jst.costValue = uint(cost) - *jst.depthValue = uint(depth) - *jst.refundValue = uint(env.StateDB.GetRefund()) - - jst.errorValue = nil - if err != nil { - jst.errorValue = new(string) - *jst.errorValue = err.Error() - } - - if _, err := jst.call("step", "log", "db"); err != nil { - jst.err = wrapError("step", err) - } -} - -// CaptureFault implements the Tracer interface to trace an execution fault -func (jst *Tracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { - if jst.err != nil { - return - } - // Apart from the error, everything matches the previous invocation - jst.errorValue = new(string) - *jst.errorValue = err.Error() - - if _, err := jst.call("fault", "log", "db"); err != nil { - jst.err = wrapError("fault", err) - } -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (jst *Tracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) { - jst.ctx["output"] = output - jst.ctx["time"] = t.String() - jst.ctx["gasUsed"] = gasUsed - - if err != nil { - jst.ctx["error"] = err.Error() - } -} - -// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error -func (jst *Tracer) GetResult() (json.RawMessage, error) { - // Transform the context into a JavaScript object and inject into the state - obj := jst.vm.PushObject() - - for key, val := range jst.ctx { - switch val := val.(type) { - case uint64: - jst.vm.PushUint(uint(val)) - - case string: - jst.vm.PushString(val) - - case []byte: - ptr := jst.vm.PushFixedBuffer(len(val)) - copy(makeSlice(ptr, uint(len(val))), val) - - case common.Address: - ptr := jst.vm.PushFixedBuffer(20) - copy(makeSlice(ptr, 20), val[:]) - - case *big.Int: - pushBigInt(val, jst.vm) - - default: - panic(fmt.Sprintf("unsupported type: %T", val)) - } - jst.vm.PutPropString(obj, key) - } - jst.vm.PutPropString(jst.stateObject, "ctx") - - // Finalize the trace and return the results - result, err := jst.call("result", "ctx", "db") - if err != nil { - jst.err = wrapError("result", err) - } - // Clean up the JavaScript environment - jst.vm.DestroyHeap() - jst.vm.Destroy() - - return result, jst.err -} diff --git a/eth/tracers/js/internal/tracers/4byte_tracer.js b/eth/tracers/js/internal/tracers/4byte_tracer.js new file mode 100644 index 0000000000..9ec3209f8b --- /dev/null +++ b/eth/tracers/js/internal/tracers/4byte_tracer.js @@ -0,0 +1,65 @@ +// 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 . + +// 4byteTracer searches for 4byte-identifiers, and collects them for post-processing. +// It collects the methods identifiers along with the size of the supplied data, so +// 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 +// } +{ + // ids aggregates the 4byte ids found. + ids : {}, + + // store save the given indentifier and datasize. + store: function(id, size){ + var key = "" + toHex(id) + "-" + size; + this.ids[key] = this.ids[key] + 1 || 1; + }, + + enter: function(frame) { + // Skip any pre-compile invocations, those are just fancy opcodes + if (isPrecompiled(frame.getTo())) { + return; + } + var input = frame.getInput() + if (input.length >= 4) { + this.store(slice(input, 0, 4), input.length - 4); + } + }, + + exit: function(frameResult) {}, + + // fault is invoked when the actual execution of an opcode fails. + fault: function(log, db) {}, + + // result is invoked when all the opcodes have been iterated over and returns + // the final result of the tracing. + result: function(ctx) { + // Save the outer calldata also + if (ctx.input.length >= 4) { + this.store(slice(ctx.input, 0, 4), ctx.input.length-4) + } + return this.ids; + }, +} diff --git a/eth/tracers/internal/tracers/4byte_tracer.js b/eth/tracers/js/internal/tracers/4byte_tracer_legacy.js similarity index 100% rename from eth/tracers/internal/tracers/4byte_tracer.js rename to eth/tracers/js/internal/tracers/4byte_tracer_legacy.js diff --git a/eth/tracers/internal/tracers/assets.go b/eth/tracers/js/internal/tracers/assets.go similarity index 57% rename from eth/tracers/internal/tracers/assets.go rename to eth/tracers/js/internal/tracers/assets.go index 7f45ab286e..37e3702400 100644 --- a/eth/tracers/internal/tracers/assets.go +++ b/eth/tracers/js/internal/tracers/assets.go @@ -1,8 +1,10 @@ // Code generated by go-bindata. DO NOT EDIT. // sources: -// 4byte_tracer.js (2.933kB) +// 4byte_tracer.js (2.224kB) +// 4byte_tracer_legacy.js (2.933kB) // bigram_tracer.js (1.712kB) -// call_tracer.js (8.956kB) +// call_tracer_js.js (3.497kB) +// call_tracer_legacy.js (8.956kB) // evmdis_tracer.js (4.195kB) // noop_tracer.js (1.271kB) // opcount_tracer.js (1.372kB) @@ -77,7 +79,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var __4byte_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x56\x5b\x6f\xdb\x4a\x0e\x7e\xb6\x7f\x05\xd7\x2f\xb5\x51\x59\x8e\x2f\x89\x2f\xd9\x16\xf0\xe6\xa4\x6d\x80\x9c\x24\x88\xdd\x3d\x28\x16\xfb\x30\x9e\xa1\xac\xd9\xc8\x33\xc2\x0c\xe5\x4b\x73\xf2\xdf\x17\x1c\x49\x89\x93\xd3\x62\xbb\x4f\x96\x47\xc3\x8f\x1f\xc9\x8f\xa4\x7a\x3d\xb8\xb0\xf9\xc1\xe9\x75\x4a\x30\x38\xe9\x8f\x61\x99\x22\xac\x6d\x17\x29\x45\x87\xc5\x06\xe6\x05\xa5\xd6\xf9\x66\xaf\x07\xcb\x54\x7b\x48\x74\x86\xa0\x3d\xe4\xc2\x11\xd8\x04\xe8\xcd\xfd\x4c\xaf\x9c\x70\x87\xb8\xd9\xeb\x95\x36\x3f\x7c\xcd\x08\x89\x43\x04\x6f\x13\xda\x09\x87\x33\x38\xd8\x02\xa4\x30\xe0\x50\x69\x4f\x4e\xaf\x0a\x42\xd0\x04\xc2\xa8\x9e\x75\xb0\xb1\x4a\x27\x07\x86\xd4\x04\x85\x51\xe8\x82\x6b\x42\xb7\xf1\x35\x8f\xcf\x37\x5f\xe1\x1a\xbd\x47\x07\x9f\xd1\xa0\x13\x19\xdc\x15\xab\x4c\x4b\xb8\xd6\x12\x8d\x47\x10\x1e\x72\x3e\xf1\x29\x2a\x58\x05\x38\x36\xfc\xc4\x54\x16\x15\x15\xf8\x64\x0b\xa3\x04\x69\x6b\x22\x40\xcd\xcc\x61\x8b\xce\x6b\x6b\x60\x58\xbb\xaa\x00\x23\xb0\x8e\x41\xda\x82\x38\x00\x07\x36\x67\xbb\x0e\x08\x73\x80\x4c\xd0\x8b\xe9\x2f\x24\xe4\x25\x6e\x05\xda\x04\x37\xa9\xcd\x11\x28\x15\xc4\x51\xef\x74\x96\xc1\x0a\xa1\xf0\x98\x14\x59\xc4\x68\xab\x82\xe0\x8f\xab\xe5\x97\xdb\xaf\x4b\x98\xdf\x7c\x83\x3f\xe6\xf7\xf7\xf3\x9b\xe5\xb7\x73\xd8\x69\x4a\x6d\x41\x80\x5b\x2c\xa1\xf4\x26\xcf\x34\x2a\xd8\x09\xe7\x84\xa1\x03\xd8\x84\x11\x7e\xbf\xbc\xbf\xf8\x32\xbf\x59\xce\xff\x71\x75\x7d\xb5\xfc\x06\xd6\xc1\xa7\xab\xe5\xcd\xe5\x62\x01\x9f\x6e\xef\x61\x0e\x77\xf3\xfb\xe5\xd5\xc5\xd7\xeb\xf9\x3d\xdc\x7d\xbd\xbf\xbb\x5d\x5c\xc6\xb0\x40\x66\x85\x6c\xff\xbf\x73\x9e\x84\xea\x39\x04\x85\x24\x74\xe6\xeb\x4c\x7c\xb3\x05\xf8\xd4\x16\x99\x82\x54\x6c\x11\x1c\x4a\xd4\x5b\x54\x20\x40\xda\xfc\xf0\xcb\x45\x65\x2c\x91\x59\xb3\x0e\x31\xff\x54\x90\x70\x95\x80\xb1\x14\x81\x47\x84\xbf\xa7\x44\xf9\xac\xd7\xdb\xed\x76\xf1\xda\x14\xb1\x75\xeb\x5e\x56\xc2\xf9\xde\xc7\xb8\xc9\x98\xa3\xd5\x81\x70\xe9\x84\x44\x07\x1e\x85\x93\x29\xfa\x10\x4c\x78\xd1\xd5\x0a\x0d\xe9\x44\xa3\xf3\x11\x8b\x14\xa4\xcd\x32\x94\xe4\x99\xc1\x26\x5c\xcc\xad\xa7\x6e\xee\xac\x44\xef\xb5\x59\x73\xe0\x70\x45\xaf\x2e\xc2\x06\x29\xb5\xca\xc3\x11\xdc\xdb\x68\xbc\xfe\x8e\x75\x36\x7c\x91\x97\x65\x54\x82\x44\x04\xde\x86\xe8\xc1\x21\xcb\x0c\x15\x78\xbd\x36\x82\x0a\x87\xa1\x97\x56\x08\x1b\x41\x92\xc5\x2e\xd6\x42\x1b\x4f\x7f\x01\x64\x9c\xba\x22\x97\x7b\xb1\xc9\x33\x9c\xf1\x33\xc0\x47\x50\xb8\x2a\xd6\x31\x71\x0a\x96\x4e\x18\x2f\x24\x8b\xbb\x0d\xad\x93\xfd\xa0\x3f\xc2\xd3\xe9\x18\x87\xa7\x4a\x9c\x4c\x86\x67\xd3\x41\x72\x3a\x9c\x9c\xf5\x47\x7d\x3c\x9b\x26\xa3\x31\x4e\xc7\xc3\xd5\x40\x9e\x9e\xe1\x58\x4c\x4e\xc6\xc3\x55\x1f\xc5\xc9\x24\x51\xe3\xd3\x71\x1f\xa7\x0a\x5b\x11\x3c\x06\x60\x37\x83\xd6\x51\xa6\x5b\x4f\x9d\xd2\xfb\x63\xf9\x03\x70\xb2\x1f\x8c\x95\x1c\x4c\xc7\xd8\xed\x0f\x26\x33\xe8\x47\x2f\x6f\x86\x13\x29\x47\x93\x61\xbf\x7b\x32\x83\xc1\xd1\xf9\xe9\x60\x94\x0c\x27\x93\x69\x77\x7a\xf6\xda\x40\xa8\xe4\x74\x9a\x4c\xa7\xdd\xc1\xe4\x0d\x94\x1c\x4c\xfa\xaa\x3f\x45\x86\xea\x97\xc7\x4f\xcd\xc7\x66\x83\x07\x8e\xf2\x20\xd6\x6b\x87\x6b\x41\x58\x56\x2d\x30\x0e\x2f\x12\x1e\x16\x71\xb3\xc1\xcf\x33\x78\x7c\x8a\x9a\xc1\x46\x8a\x2c\x5b\x1e\x72\x56\x35\x15\xce\x78\x78\x97\x88\xcc\xe3\xbb\xa0\x0b\x63\x4d\x97\x2f\x78\x1e\x1f\x01\x2f\x47\x7c\xe8\x6a\xa3\x70\x1f\x2e\xf0\x51\xa2\x9d\x27\x1e\xb3\x62\x13\x10\x45\xc2\xd3\xe4\xdd\x56\x64\x05\xbe\x8b\x40\xc7\x18\xc3\x06\x37\x5c\x54\xe1\x28\x6e\x36\x6a\x97\x33\x48\x0a\x53\x56\xca\xe6\x9e\x5c\xe7\xb1\xd9\x68\xf8\x9d\x26\x99\x1e\x1d\x48\xe1\x11\x5a\x17\xf3\xeb\xeb\xd6\x0c\x5e\xfe\x5c\xdc\xfe\x76\xd9\x9a\x35\x1b\x0d\x76\xb9\x16\x2c\x6d\xa5\x5c\x04\x5b\x91\x45\xa5\xbb\xea\xc7\x7f\x0f\x0f\xb6\xa0\xfa\xd7\x7f\x67\xb3\x32\x5e\x18\x9e\x43\xaf\x07\x9e\x84\x7c\x80\x9c\x1c\x90\x2d\xcd\x9a\xcf\xae\x7f\xbb\xbc\xbe\xfc\x3c\x5f\x5e\xbe\xa2\xb0\x58\xce\x97\x57\x17\xe5\xd1\x5f\x49\xfc\x1f\xfe\x07\x3f\xf3\xdf\x68\x3c\x35\x9f\x6f\x85\x9a\x9c\x37\x1b\x75\xd5\x3c\xf1\x9c\xf2\x3c\x8d\xc2\x18\xd1\x3c\x3c\xb9\x2c\x55\x6b\x86\x3e\xe7\x8e\xe1\x0e\x8a\x9b\x8d\x70\xff\x28\xdf\x5a\x45\xa1\xb9\x42\x86\xb7\xc2\xc1\x03\x1e\xe0\x03\xb4\x5a\xf0\x1e\xc8\x7e\xc1\x7d\x5b\xab\x0e\xbc\x87\x56\x97\x4f\xf8\xe6\x79\xb3\xd1\xa0\x54\xfb\x58\x2b\xff\xaf\x07\x3c\xfc\x1b\x3e\xc0\xeb\xff\xef\xa1\x0f\x7f\xfe\x09\xfd\x57\x34\x31\xe7\x85\xa1\xcd\xd6\x3e\xa0\x0a\x92\xe1\x01\x70\x00\x9b\x4b\xab\xaa\x8d\xc1\x11\xfc\xf3\x77\xc0\x3d\xca\x82\xd0\x07\xba\x98\x1f\xb1\xcd\xec\x3a\x02\xb5\xea\x00\xb3\xed\xf5\x60\xf1\xa0\xf3\xb0\xb8\x4a\x14\x5f\xc2\xf0\x46\x34\x96\x40\x1b\x42\x67\x44\x16\xa4\xed\xab\xf8\x24\xd5\x7c\x6b\xf5\x31\x6a\x6c\xf3\x98\xec\x82\x9c\x36\xeb\x76\xa7\xc3\x31\xea\x04\xda\x7f\x93\x54\xfa\xaa\xd2\x7f\x5e\x15\xe3\xd8\x75\xee\xb0\x2b\xed\x26\x0f\x5f\x19\x66\x6b\x65\xd8\xc3\x3e\x02\x4a\x2d\xef\x6f\x87\xf0\x9f\xc2\x13\x24\xc2\xc8\x67\xa2\x15\xbe\xf6\x77\x0e\x2b\x63\xd5\x26\x3b\x57\xca\xa1\xf7\x81\x51\x50\x42\xcc\x6d\xd6\xee\x77\x5e\xc8\xf5\xcf\x3a\x9d\xce\xcf\x48\x7d\x16\x61\xf7\xbf\x0a\xbc\x5e\x62\x55\xfc\xda\x2c\xbe\xc3\x07\x78\xe3\x41\x12\x57\xad\x13\x87\x5e\xbd\x4d\xda\xcf\x19\x08\xd7\x3f\x7e\x80\x51\xe5\xb2\x84\xb8\x4d\x92\x1f\x61\xbc\xb1\x2f\x65\x12\x14\x17\x22\x62\xd1\xbb\x43\xec\x79\x6d\xb5\x03\x48\x54\x61\xbd\x87\x51\x27\x0a\xd4\xba\xa3\x4e\x15\x4f\x2d\x9d\x44\x14\x19\x1d\x6b\x67\x97\x56\xdf\x07\x42\x52\x21\xb2\x4a\x2e\xfc\xad\x63\x13\x10\xa6\x56\x54\x52\x6e\xee\x46\xb0\xff\xa1\x86\xa0\x76\xe1\xd0\xff\xc8\x07\x27\x8f\xfd\xd4\xe2\x0a\x3b\x7f\x85\xdc\x60\x84\x4e\xf0\x47\x8f\xdd\x56\x2d\x56\x0d\xcd\x00\x57\xce\x42\xce\x7f\x05\x5c\x2d\x2e\xde\x1e\x61\xa9\x36\xca\xf3\x23\x52\x92\xf6\x2f\xa2\xae\x9b\xd9\x16\x3c\x3f\xb9\x86\xdc\xc0\x20\x32\x6f\xab\xaa\x48\xda\xc7\xda\xe4\x05\xc5\x19\x9a\x35\xa5\xc7\x15\x3a\x4a\x7a\x99\xe9\xe7\xcb\x11\x9c\x44\x21\xd1\x6f\xcd\xbb\xa3\xce\xeb\x29\x53\xf7\x73\xd9\xc1\x4f\xcd\xff\x06\x00\x00\xff\xff\x8e\xc8\x27\x72\x75\x0b\x00\x00") +var __4byte_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x55\x5b\x6f\x22\x39\x13\x7d\x86\x5f\x71\xc4\x13\x68\x9a\x4b\x73\x09\x97\xf9\x32\x12\xdf\x28\x99\x41\xca\x66\x22\x42\x34\x8a\x56\xfb\x60\xda\xd5\xdd\xde\x18\xbb\x65\xbb\xb9\x6c\x26\xff\x7d\x65\x37\xe4\x36\xbb\xda\x79\x02\xec\xaa\x73\xaa\x4e\x1d\x17\xdd\x2e\x3e\xeb\xe2\x60\x44\x96\x3b\xf4\x7b\xf1\x18\xab\x9c\x90\xe9\x36\xb9\x9c\x0c\x95\x1b\xcc\x4b\x97\x6b\x63\xeb\xdd\x2e\x56\xb9\xb0\x48\x85\x24\x08\x8b\x82\x19\x07\x9d\xc2\xbd\x8b\x97\x62\x6d\x98\x39\x74\xea\xdd\x6e\x95\xf3\x8f\xd7\x1e\x21\x35\x44\xb0\x3a\x75\x3b\x66\x68\x86\x83\x2e\x91\x30\x05\x43\x5c\x58\x67\xc4\xba\x74\x04\xe1\xc0\x14\xef\x6a\x83\x8d\xe6\x22\x3d\x78\x48\xe1\x50\x2a\x4e\x26\x50\x3b\x32\x1b\x7b\xaa\xe3\xcb\xf5\x1d\xae\xc8\x5a\x32\xf8\x42\x8a\x0c\x93\xb8\x29\xd7\x52\x24\xb8\x12\x09\x29\x4b\x60\x16\x85\x3f\xb1\x39\x71\xac\x03\x9c\x4f\xbc\xf4\xa5\xdc\x1e\x4b\xc1\xa5\x2e\x15\x67\x4e\x68\x15\x81\x84\xaf\x1c\x5b\x32\x56\x68\x85\xc1\x89\xea\x08\x18\x41\x1b\x0f\xd2\x64\xce\x37\x60\xa0\x0b\x9f\xd7\x02\x53\x07\x48\xe6\x5e\x52\x7f\x41\x90\x97\xbe\x39\x84\x0a\x34\xb9\x2e\x08\x2e\x67\xce\x77\xbd\x13\x52\x62\x4d\x28\x2d\xa5\xa5\x8c\x3c\xda\xba\x74\xf8\xbe\x58\x7d\xfd\x76\xb7\xc2\xfc\xfa\x1e\xdf\xe7\xcb\xe5\xfc\x7a\x75\xff\x11\x3b\xe1\x72\x5d\x3a\xd0\x96\x2a\x28\xb1\x29\xa4\x20\x8e\x1d\x33\x86\x29\x77\x80\x4e\x3d\xc2\x6f\x17\xcb\xcf\x5f\xe7\xd7\xab\xf9\xff\x17\x57\x8b\xd5\x3d\xb4\xc1\xe5\x62\x75\x7d\x71\x7b\x8b\xcb\x6f\x4b\xcc\x71\x33\x5f\xae\x16\x9f\xef\xae\xe6\x4b\xdc\xdc\x2d\x6f\xbe\xdd\x5e\x74\x70\x4b\xbe\x2a\xf2\xf9\xff\xad\x79\x1a\xa6\x67\x08\x9c\x1c\x13\xd2\x9e\x94\xb8\xd7\x25\x6c\xae\x4b\xc9\x91\xb3\x2d\xc1\x50\x42\x62\x4b\x1c\x0c\x89\x2e\x0e\xbf\x3c\x54\x8f\xc5\xa4\x56\x59\xe8\xf9\x5f\x0d\x89\x45\x0a\xa5\x5d\x04\x4b\x84\xff\xe5\xce\x15\xb3\x6e\x77\xb7\xdb\x75\x32\x55\x76\xb4\xc9\xba\xb2\x82\xb3\xdd\x4f\x9d\xba\xc7\x1c\xae\x0f\x8e\x56\x86\x25\x64\x60\x89\x99\x24\x27\x1b\x9a\x09\x17\x6d\xc1\x49\x39\x91\x0a\x32\x36\xf2\x26\x45\xa2\xa5\xa4\xc4\x59\x5f\xc1\x26\x04\x16\xda\xba\x76\x61\x74\x42\xd6\x0a\x95\xf9\xc6\xb1\x70\x6f\x02\xb1\x21\x97\x6b\x6e\xf1\x0a\xee\x7d\x37\x56\xfc\x45\x27\x35\x6c\x59\x54\x63\xe4\xcc\xb1\x08\x56\x87\xee\x61\xc8\xdb\x8c\x38\xac\xc8\x14\x73\xa5\xa1\xf0\x96\xd6\x84\x0d\x73\x89\x37\x3b\xcb\x98\x50\xd6\xfd\x04\xe8\x71\x4e\x13\xb9\xd8\xb3\x4d\x21\x69\xe6\xbf\x03\x9f\xc0\x69\x5d\x66\x1d\xe7\x25\x58\x19\xa6\x2c\x4b\xbc\xb9\x9b\x68\xf4\xf6\xfd\x78\x48\xa3\xe9\x98\x06\x23\xce\x7a\x93\xc1\xd9\xb4\x9f\x8e\x06\x93\xb3\x78\x18\xd3\xd9\x34\x1d\x8e\x69\x3a\x1e\xac\xfb\xc9\xe8\x8c\xc6\x6c\xd2\x1b\x0f\xd6\x31\xb1\xde\x24\xe5\xe3\xd1\x38\xa6\x29\xa7\x46\x84\xc7\x00\x6c\x66\x68\xbc\x52\xba\xf1\xd4\xaa\xd8\x1f\xab\x0f\xa0\xb7\xef\x8f\x79\xd2\x9f\x8e\xa9\x1d\xf7\x27\x33\xc4\xd1\xcb\xcd\x60\x92\x24\xc3\xc9\x20\x6e\xf7\x66\xe8\xbf\x3a\x1f\xf5\x87\xe9\x60\x32\x99\xb6\xa7\x67\x6f\x13\x18\x4f\x47\xd3\x74\x3a\x6d\xf7\x27\xef\xa0\x92\xfe\x24\xe6\xf1\x94\x3c\x54\x5c\x1d\x3f\xd5\x1f\xeb\x35\xbf\x70\xb8\x05\xcb\x32\x43\x19\x73\x54\x4d\x2d\x54\x1c\x2e\x52\xbf\x2c\x3a\xf5\x9a\xff\x3e\xc3\xe3\x53\x54\x0f\x39\xd6\x79\xc7\x5b\xef\xeb\x60\x48\xe1\x9f\xa1\x50\xcf\x43\x0e\x8e\xf1\xda\xfb\x59\x74\xea\xb5\x10\x3f\x43\x5a\xaa\x4a\x63\xc1\xa3\x30\xa6\xd6\x63\xbd\x56\xdb\x32\x83\x07\x3a\xe0\x1c\x8d\x06\x3e\xc0\xe9\xaf\xb4\x6f\x0a\xde\xc2\x07\x34\xda\xfe\xc4\x47\x7e\xac\xd7\x6a\x2e\x17\xb6\x23\xb8\xfd\xfd\x81\x0e\x7f\xe0\x1c\x6f\x7f\x7f\x40\x8c\x1f\x3f\x10\x7f\xac\xd7\x42\x99\xa4\x9c\x97\xff\x99\x33\x35\x6c\x43\x2d\x78\xc6\x6e\x17\xb7\x0f\xa2\x08\x6b\xac\x30\xd4\x4e\xf4\xa6\x08\x8b\x5f\x6d\x75\x12\x56\xa3\x8d\xe0\x72\xed\x57\xaa\x21\xfc\x59\x5a\x87\x94\xa9\xe4\x00\x5d\x24\x9a\x93\xad\xd7\x6a\x22\x45\x53\xd8\x1b\x43\xc7\x64\x5e\x11\x74\x32\x72\x2b\xdd\x6c\xb5\x2a\xa6\x9a\x21\x57\x1a\xe5\xab\x7f\x3a\xb6\x2a\x54\x51\x3a\x9c\xe3\x39\x7c\xe1\x0f\x9a\xad\x13\xa6\xff\xd5\x91\xa4\x32\x97\xe3\xd3\x39\x86\x47\xa0\xd0\x6c\xd0\xb1\x69\xfd\x5b\xae\x02\x23\xf4\x22\x0c\x5b\x11\xde\xa4\xb5\x31\x6c\x1d\x29\x2b\x29\xf6\xc2\xbd\x57\x62\x49\xb6\x94\xae\xf5\x32\xd3\x94\x95\xd2\xf9\x45\xed\x55\x78\xf0\xab\x34\x3f\xee\x56\x96\xb8\x92\x49\xd0\x9e\x92\xd2\x03\xf8\xc7\xc5\xd4\x51\x0b\xa4\xd5\xd6\xab\x85\xfc\x57\x2c\x52\x67\x11\xf8\xfa\x15\x83\x09\x94\x3f\x51\x30\x29\x03\xcd\x51\xdb\x6a\x5d\xae\xc9\x3b\xca\x91\x61\xfe\xff\x42\x6f\x8f\x9e\xaa\xe4\xb4\x01\xce\xe7\xa4\x42\x31\x79\x02\x3e\xbe\x79\xff\xf0\xc2\x3e\xaa\x55\xe7\xaf\x6a\x4a\xdc\xfe\xc5\x01\x27\xf7\xea\xd2\xff\x91\x25\x4c\x4a\xef\x58\x30\x69\xf5\x71\x16\x89\xdb\x77\x7e\x79\x1e\xcf\xc1\xcf\x33\x79\x9f\xde\x1e\xb6\x8e\x3e\xa8\xda\x78\x36\x70\x65\xd9\xa7\xfa\xdf\x01\x00\x00\xff\xff\xf6\xa8\xa1\xb9\xb0\x08\x00\x00") func _4byte_tracerJsBytes() ([]byte, error) { return bindataRead( @@ -93,6 +95,26 @@ func _4byte_tracerJs() (*asset, error) { } info := bindataFileInfo{name: "4byte_tracer.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6b, 0xa8, 0x46, 0xa2, 0x3a, 0x2b, 0xaa, 0xb9, 0xb9, 0xba, 0xe2, 0x22, 0x10, 0xe, 0xe7, 0x4c, 0x24, 0xfc, 0x4c, 0x85, 0xeb, 0x96, 0x48, 0xe8, 0x7f, 0xc8, 0xe0, 0xd0, 0xd, 0x26, 0xa1, 0xb2}} + return a, nil +} + +var __4byte_tracer_legacyJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x56\x5b\x6f\xdb\x4a\x0e\x7e\xb6\x7f\x05\xd7\x2f\xb5\x51\x59\x8e\x2f\x89\x2f\xd9\x16\xf0\xe6\xa4\x6d\x80\x9c\x24\x88\xdd\x3d\x28\x16\xfb\x30\x9e\xa1\xac\xd9\xc8\x33\xc2\x0c\xe5\x4b\x73\xf2\xdf\x17\x1c\x49\x89\x93\xd3\x62\xbb\x4f\x96\x47\xc3\x8f\x1f\xc9\x8f\xa4\x7a\x3d\xb8\xb0\xf9\xc1\xe9\x75\x4a\x30\x38\xe9\x8f\x61\x99\x22\xac\x6d\x17\x29\x45\x87\xc5\x06\xe6\x05\xa5\xd6\xf9\x66\xaf\x07\xcb\x54\x7b\x48\x74\x86\xa0\x3d\xe4\xc2\x11\xd8\x04\xe8\xcd\xfd\x4c\xaf\x9c\x70\x87\xb8\xd9\xeb\x95\x36\x3f\x7c\xcd\x08\x89\x43\x04\x6f\x13\xda\x09\x87\x33\x38\xd8\x02\xa4\x30\xe0\x50\x69\x4f\x4e\xaf\x0a\x42\xd0\x04\xc2\xa8\x9e\x75\xb0\xb1\x4a\x27\x07\x86\xd4\x04\x85\x51\xe8\x82\x6b\x42\xb7\xf1\x35\x8f\xcf\x37\x5f\xe1\x1a\xbd\x47\x07\x9f\xd1\xa0\x13\x19\xdc\x15\xab\x4c\x4b\xb8\xd6\x12\x8d\x47\x10\x1e\x72\x3e\xf1\x29\x2a\x58\x05\x38\x36\xfc\xc4\x54\x16\x15\x15\xf8\x64\x0b\xa3\x04\x69\x6b\x22\x40\xcd\xcc\x61\x8b\xce\x6b\x6b\x60\x58\xbb\xaa\x00\x23\xb0\x8e\x41\xda\x82\x38\x00\x07\x36\x67\xbb\x0e\x08\x73\x80\x4c\xd0\x8b\xe9\x2f\x24\xe4\x25\x6e\x05\xda\x04\x37\xa9\xcd\x11\x28\x15\xc4\x51\xef\x74\x96\xc1\x0a\xa1\xf0\x98\x14\x59\xc4\x68\xab\x82\xe0\x8f\xab\xe5\x97\xdb\xaf\x4b\x98\xdf\x7c\x83\x3f\xe6\xf7\xf7\xf3\x9b\xe5\xb7\x73\xd8\x69\x4a\x6d\x41\x80\x5b\x2c\xa1\xf4\x26\xcf\x34\x2a\xd8\x09\xe7\x84\xa1\x03\xd8\x84\x11\x7e\xbf\xbc\xbf\xf8\x32\xbf\x59\xce\xff\x71\x75\x7d\xb5\xfc\x06\xd6\xc1\xa7\xab\xe5\xcd\xe5\x62\x01\x9f\x6e\xef\x61\x0e\x77\xf3\xfb\xe5\xd5\xc5\xd7\xeb\xf9\x3d\xdc\x7d\xbd\xbf\xbb\x5d\x5c\xc6\xb0\x40\x66\x85\x6c\xff\xbf\x73\x9e\x84\xea\x39\x04\x85\x24\x74\xe6\xeb\x4c\x7c\xb3\x05\xf8\xd4\x16\x99\x82\x54\x6c\x11\x1c\x4a\xd4\x5b\x54\x20\x40\xda\xfc\xf0\xcb\x45\x65\x2c\x91\x59\xb3\x0e\x31\xff\x54\x90\x70\x95\x80\xb1\x14\x81\x47\x84\xbf\xa7\x44\xf9\xac\xd7\xdb\xed\x76\xf1\xda\x14\xb1\x75\xeb\x5e\x56\xc2\xf9\xde\xc7\xb8\xc9\x98\xa3\xd5\x81\x70\xe9\x84\x44\x07\x1e\x85\x93\x29\xfa\x10\x4c\x78\xd1\xd5\x0a\x0d\xe9\x44\xa3\xf3\x11\x8b\x14\xa4\xcd\x32\x94\xe4\x99\xc1\x26\x5c\xcc\xad\xa7\x6e\xee\xac\x44\xef\xb5\x59\x73\xe0\x70\x45\xaf\x2e\xc2\x06\x29\xb5\xca\xc3\x11\xdc\xdb\x68\xbc\xfe\x8e\x75\x36\x7c\x91\x97\x65\x54\x82\x44\x04\xde\x86\xe8\xc1\x21\xcb\x0c\x15\x78\xbd\x36\x82\x0a\x87\xa1\x97\x56\x08\x1b\x41\x92\xc5\x2e\xd6\x42\x1b\x4f\x7f\x01\x64\x9c\xba\x22\x97\x7b\xb1\xc9\x33\x9c\xf1\x33\xc0\x47\x50\xb8\x2a\xd6\x31\x71\x0a\x96\x4e\x18\x2f\x24\x8b\xbb\x0d\xad\x93\xfd\xa0\x3f\xc2\xd3\xe9\x18\x87\xa7\x4a\x9c\x4c\x86\x67\xd3\x41\x72\x3a\x9c\x9c\xf5\x47\x7d\x3c\x9b\x26\xa3\x31\x4e\xc7\xc3\xd5\x40\x9e\x9e\xe1\x58\x4c\x4e\xc6\xc3\x55\x1f\xc5\xc9\x24\x51\xe3\xd3\x71\x1f\xa7\x0a\x5b\x11\x3c\x06\x60\x37\x83\xd6\x51\xa6\x5b\x4f\x9d\xd2\xfb\x63\xf9\x03\x70\xb2\x1f\x8c\x95\x1c\x4c\xc7\xd8\xed\x0f\x26\x33\xe8\x47\x2f\x6f\x86\x13\x29\x47\x93\x61\xbf\x7b\x32\x83\xc1\xd1\xf9\xe9\x60\x94\x0c\x27\x93\x69\x77\x7a\xf6\xda\x40\xa8\xe4\x74\x9a\x4c\xa7\xdd\xc1\xe4\x0d\x94\x1c\x4c\xfa\xaa\x3f\x45\x86\xea\x97\xc7\x4f\xcd\xc7\x66\x83\x07\x8e\xf2\x20\xd6\x6b\x87\x6b\x41\x58\x56\x2d\x30\x0e\x2f\x12\x1e\x16\x71\xb3\xc1\xcf\x33\x78\x7c\x8a\x9a\xc1\x46\x8a\x2c\x5b\x1e\x72\x56\x35\x15\xce\x78\x78\x97\x88\xcc\xe3\xbb\xa0\x0b\x63\x4d\x97\x2f\x78\x1e\x1f\x01\x2f\x47\x7c\xe8\x6a\xa3\x70\x1f\x2e\xf0\x51\xa2\x9d\x27\x1e\xb3\x62\x13\x10\x45\xc2\xd3\xe4\xdd\x56\x64\x05\xbe\x8b\x40\xc7\x18\xc3\x06\x37\x5c\x54\xe1\x28\x6e\x36\x6a\x97\x33\x48\x0a\x53\x56\xca\xe6\x9e\x5c\xe7\xb1\xd9\x68\xf8\x9d\x26\x99\x1e\x1d\x48\xe1\x11\x5a\x17\xf3\xeb\xeb\xd6\x0c\x5e\xfe\x5c\xdc\xfe\x76\xd9\x9a\x35\x1b\x0d\x76\xb9\x16\x2c\x6d\xa5\x5c\x04\x5b\x91\x45\xa5\xbb\xea\xc7\x7f\x0f\x0f\xb6\xa0\xfa\xd7\x7f\x67\xb3\x32\x5e\x18\x9e\x43\xaf\x07\x9e\x84\x7c\x80\x9c\x1c\x90\x2d\xcd\x9a\xcf\xae\x7f\xbb\xbc\xbe\xfc\x3c\x5f\x5e\xbe\xa2\xb0\x58\xce\x97\x57\x17\xe5\xd1\x5f\x49\xfc\x1f\xfe\x07\x3f\xf3\xdf\x68\x3c\x35\x9f\x6f\x85\x9a\x9c\x37\x1b\x75\xd5\x3c\xf1\x9c\xf2\x3c\x8d\xc2\x18\xd1\x3c\x3c\xb9\x2c\x55\x6b\x86\x3e\xe7\x8e\xe1\x0e\x8a\x9b\x8d\x70\xff\x28\xdf\x5a\x45\xa1\xb9\x42\x86\xb7\xc2\xc1\x03\x1e\xe0\x03\xb4\x5a\xf0\x1e\xc8\x7e\xc1\x7d\x5b\xab\x0e\xbc\x87\x56\x97\x4f\xf8\xe6\x79\xb3\xd1\xa0\x54\xfb\x58\x2b\xff\xaf\x07\x3c\xfc\x1b\x3e\xc0\xeb\xff\xef\xa1\x0f\x7f\xfe\x09\xfd\x57\x34\x31\xe7\x85\xa1\xcd\xd6\x3e\xa0\x0a\x92\xe1\x01\x70\x00\x9b\x4b\xab\xaa\x8d\xc1\x11\xfc\xf3\x77\xc0\x3d\xca\x82\xd0\x07\xba\x98\x1f\xb1\xcd\xec\x3a\x02\xb5\xea\x00\xb3\xed\xf5\x60\xf1\xa0\xf3\xb0\xb8\x4a\x14\x5f\xc2\xf0\x46\x34\x96\x40\x1b\x42\x67\x44\x16\xa4\xed\xab\xf8\x24\xd5\x7c\x6b\xf5\x31\x6a\x6c\xf3\x98\xec\x82\x9c\x36\xeb\x76\xa7\xc3\x31\xea\x04\xda\x7f\x93\x54\xfa\xaa\xd2\x7f\x5e\x15\xe3\xd8\x75\xee\xb0\x2b\xed\x26\x0f\x5f\x19\x66\x6b\x65\xd8\xc3\x3e\x02\x4a\x2d\xef\x6f\x87\xf0\x9f\xc2\x13\x24\xc2\xc8\x67\xa2\x15\xbe\xf6\x77\x0e\x2b\x63\xd5\x26\x3b\x57\xca\xa1\xf7\x81\x51\x50\x42\xcc\x6d\xd6\xee\x77\x5e\xc8\xf5\xcf\x3a\x9d\xce\xcf\x48\x7d\x16\x61\xf7\xbf\x0a\xbc\x5e\x62\x55\xfc\xda\x2c\xbe\xc3\x07\x78\xe3\x41\x12\x57\xad\x13\x87\x5e\xbd\x4d\xda\xcf\x19\x08\xd7\x3f\x7e\x80\x51\xe5\xb2\x84\xb8\x4d\x92\x1f\x61\xbc\xb1\x2f\x65\x12\x14\x17\x22\x62\xd1\xbb\x43\xec\x79\x6d\xb5\x03\x48\x54\x61\xbd\x87\x51\x27\x0a\xd4\xba\xa3\x4e\x15\x4f\x2d\x9d\x44\x14\x19\x1d\x6b\x67\x97\x56\xdf\x07\x42\x52\x21\xb2\x4a\x2e\xfc\xad\x63\x13\x10\xa6\x56\x54\x52\x6e\xee\x46\xb0\xff\xa1\x86\xa0\x76\xe1\xd0\xff\xc8\x07\x27\x8f\xfd\xd4\xe2\x0a\x3b\x7f\x85\xdc\x60\x84\x4e\xf0\x47\x8f\xdd\x56\x2d\x56\x0d\xcd\x00\x57\xce\x42\xce\x7f\x05\x5c\x2d\x2e\xde\x1e\x61\xa9\x36\xca\xf3\x23\x52\x92\xf6\x2f\xa2\xae\x9b\xd9\x16\x3c\x3f\xb9\x86\xdc\xc0\x20\x32\x6f\xab\xaa\x48\xda\xc7\xda\xe4\x05\xc5\x19\x9a\x35\xa5\xc7\x15\x3a\x4a\x7a\x99\xe9\xe7\xcb\x11\x9c\x44\x21\xd1\x6f\xcd\xbb\xa3\xce\xeb\x29\x53\xf7\x73\xd9\xc1\x4f\xcd\xff\x06\x00\x00\xff\xff\x8e\xc8\x27\x72\x75\x0b\x00\x00") + +func _4byte_tracer_legacyJsBytes() ([]byte, error) { + return bindataRead( + __4byte_tracer_legacyJs, + "4byte_tracer_legacy.js", + ) +} + +func _4byte_tracer_legacyJs() (*asset, error) { + bytes, err := _4byte_tracer_legacyJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "4byte_tracer_legacy.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb4, 0xc5, 0x48, 0x2d, 0xd9, 0x43, 0x95, 0x93, 0x3b, 0x93, 0x2c, 0x47, 0x8c, 0x84, 0x32, 0x3c, 0x8b, 0x2e, 0xf3, 0x72, 0xc4, 0x57, 0xe6, 0x3a, 0xb3, 0xdf, 0x1d, 0xbf, 0x45, 0x3, 0xfc, 0xa}} return a, nil } @@ -117,22 +139,42 @@ func bigram_tracerJs() (*asset, error) { return a, nil } -var _call_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x5a\xdf\x6f\x1b\x37\xf2\x7f\x96\xfe\x8a\x89\x1f\x6a\x09\x51\x24\x39\xe9\xb7\x5f\xc0\xae\x7a\x50\x1d\x25\x35\xe0\xc6\x81\xad\x34\x08\x82\x3c\x50\xbb\xb3\x12\x6b\x8a\xdc\x92\x5c\xc9\xba\xd6\xff\xfb\x61\x86\xdc\xd5\xae\x24\x3b\xbe\x5e\x71\xe8\xbd\x69\x97\x33\xc3\xe1\xcc\x67\x7e\x71\x35\x18\xc0\xb9\xc9\x37\x56\xce\x17\x1e\x5e\x0e\x4f\xfe\x1f\xa6\x0b\x84\xb9\x79\x81\x7e\x81\x16\x8b\x25\x8c\x0b\xbf\x30\xd6\xb5\x07\x03\x98\x2e\xa4\x83\x4c\x2a\x04\xe9\x20\x17\xd6\x83\xc9\xc0\xef\xd0\x2b\x39\xb3\xc2\x6e\xfa\xed\xc1\x20\xf0\x1c\x5c\x26\x09\x99\x45\x04\x67\x32\xbf\x16\x16\x4f\x61\x63\x0a\x48\x84\x06\x8b\xa9\x74\xde\xca\x59\xe1\x11\xa4\x07\xa1\xd3\x81\xb1\xb0\x34\xa9\xcc\x36\x24\x52\x7a\x28\x74\x8a\x96\xb7\xf6\x68\x97\xae\xd4\xe3\xed\xbb\x0f\x70\x89\xce\xa1\x85\xb7\xa8\xd1\x0a\x05\xef\x8b\x99\x92\x09\x5c\xca\x04\xb5\x43\x10\x0e\x72\x7a\xe3\x16\x98\xc2\x8c\xc5\x11\xe3\x1b\x52\xe5\x26\xaa\x02\x6f\x4c\xa1\x53\xe1\xa5\xd1\x3d\x40\x49\x9a\xc3\x0a\xad\x93\x46\xc3\xab\x72\xab\x28\xb0\x07\xc6\x92\x90\x8e\xf0\x74\x00\x0b\x26\x27\xbe\x2e\x08\xbd\x01\x25\xfc\x96\xf5\x09\x06\xd9\x9e\x3b\x05\xa9\x79\x9b\x85\xc9\x11\xfc\x42\x78\x3a\xf5\x5a\x2a\x05\x33\x84\xc2\x61\x56\xa8\x1e\x49\x9b\x15\x1e\x3e\x5e\x4c\x7f\xba\xfa\x30\x85\xf1\xbb\x4f\xf0\x71\x7c\x7d\x3d\x7e\x37\xfd\x74\x06\x6b\xe9\x17\xa6\xf0\x80\x2b\x0c\xa2\xe4\x32\x57\x12\x53\x58\x0b\x6b\x85\xf6\x1b\x30\x19\x49\xf8\x79\x72\x7d\xfe\xd3\xf8\xdd\x74\xfc\xe3\xc5\xe5\xc5\xf4\x13\x18\x0b\x6f\x2e\xa6\xef\x26\x37\x37\xf0\xe6\xea\x1a\xc6\xf0\x7e\x7c\x3d\xbd\x38\xff\x70\x39\xbe\x86\xf7\x1f\xae\xdf\x5f\xdd\x4c\xfa\x70\x83\xa4\x15\x12\xff\xd7\x6d\x9e\xb1\xf7\x2c\x42\x8a\x5e\x48\xe5\x4a\x4b\x7c\x32\x05\xb8\x85\x29\x54\x0a\x0b\xb1\x42\xb0\x98\xa0\x5c\x61\x0a\x02\x12\x93\x6f\x9e\xec\x54\x92\x25\x94\xd1\x73\x3e\xf3\x83\x80\x84\x8b\x0c\xb4\xf1\x3d\x70\x88\xf0\xfd\xc2\xfb\xfc\x74\x30\x58\xaf\xd7\xfd\xb9\x2e\xfa\xc6\xce\x07\x2a\x88\x73\x83\x1f\xfa\x6d\x92\x99\x08\xa5\xa6\x56\x24\x68\xc9\x39\x02\xb2\x82\xcc\xaf\xcc\x5a\x83\xb7\x42\x3b\x91\x90\xab\xe9\x77\xc2\x60\x14\x1e\xf0\x8e\x9e\xbc\x23\xd0\x82\xc5\xdc\x58\xfa\xad\x54\x89\x33\xa9\x3d\x5a\x2d\x14\xcb\x76\xb0\x14\x29\xc2\x6c\x03\xa2\x2e\xb0\x57\x3f\x0c\xc1\x28\xb8\x1b\xa4\xce\x8c\x5d\x32\x2c\xfb\xed\xdf\xdb\xad\xa8\xa1\xf3\x22\xb9\x25\x05\x49\x7e\x52\x58\x8b\xda\x93\x29\x0b\xeb\xe4\x0a\x99\x04\x02\x4d\xb4\xe7\xe4\x97\x9f\x01\xef\x30\x29\x82\xa4\x56\x25\xe4\x14\x3e\xff\x7e\xff\xa5\xd7\x66\xd1\x29\xba\x04\x75\x8a\x29\x9f\xef\xd6\xc1\x7a\xc1\x16\x85\x35\x1e\xaf\x10\x7e\x2d\x9c\xaf\xd1\x64\xd6\x2c\x41\x68\x30\x05\x21\xbe\x6e\x1d\xa9\xbd\x61\x81\x82\x7e\x6b\xb4\xac\x51\xbf\xdd\xaa\x98\x4f\x21\x13\xca\x61\xdc\xd7\x79\xcc\xe9\x34\x52\xaf\xcc\x2d\x49\x36\x96\x20\x6c\x37\x60\xf2\xc4\xa4\x31\x18\xe8\x1c\xd5\x31\xd0\xf5\xdb\x2d\xe2\x3b\x85\xac\xd0\xbc\x6d\x47\x99\x79\x0f\xd2\x59\x17\x7e\x6f\xb7\x48\xec\xb9\xc8\x7d\x61\x91\xed\x89\xd6\x1a\xeb\x40\x2e\x97\x98\x4a\xe1\x51\x6d\xda\xad\xd6\x4a\xd8\xb0\x00\x23\x50\x66\xde\x9f\xa3\x9f\xd0\x63\xa7\x7b\xd6\x6e\xb5\x64\x06\x9d\xb0\xfa\x6c\x34\xe2\xec\x93\x49\x8d\x69\x10\xdf\xf2\x0b\xe9\xfa\x99\x28\x94\xaf\xf6\x25\xa6\x96\x45\x5f\x58\x4d\x3f\xef\x83\x16\x1f\x11\x8c\x56\x1b\x48\x28\xcb\x88\x19\x85\xa7\xdb\x38\x8f\xcb\x78\x38\xd7\x83\x4c\x38\x32\xa1\xcc\x60\x8d\x90\x5b\x7c\x91\x2c\x90\x7c\xa7\x13\x8c\x5a\xba\x8d\x63\xa7\x8e\x80\x76\xeb\x9b\xbc\xef\xcd\xbb\x62\x39\x43\xdb\xe9\xc2\x37\x30\xbc\xcb\x86\x5d\x18\x8d\xf8\x47\xa9\x7b\xe4\x89\xfa\x92\x14\x93\xc7\x83\x32\xff\x8d\xb7\x52\xcf\xc3\x59\xa3\xae\x17\x19\x08\xd0\xb8\x86\xc4\x68\x06\x35\x79\x65\x86\x52\xcf\x21\xb1\x28\x3c\xa6\x3d\x10\x69\x0a\xde\x04\xe4\x55\x38\x6b\x6e\x09\xdf\x7c\x03\x1d\xda\x6c\x04\xc7\xe7\xd7\x93\xf1\x74\x72\x0c\x7f\xfc\x01\xe1\xcd\x51\x78\xf3\xf2\xa8\x5b\xd3\x4c\xea\xab\x2c\x8b\xca\xb1\xc0\x7e\x8e\x78\xdb\x39\xe9\xf6\x57\x42\x15\x78\x95\x05\x35\x23\xed\x44\xa7\x30\x8a\x3c\xcf\x77\x79\x5e\x36\x78\x88\x69\x30\x80\xb1\x73\xb8\x9c\x29\xdc\x0f\xc8\x18\xb1\x1c\xbc\xce\x53\xc6\x22\xf4\x25\x66\x99\x2b\x24\x54\x95\xbb\x46\xf3\xb3\xc6\x2d\xbf\xc9\xf1\x14\x00\xc0\xe4\x3d\x7e\x41\xb1\xc0\x2f\xbc\xf9\x09\xef\xd8\x47\xa5\x09\x09\x55\xe3\x34\xb5\xe8\x5c\xa7\xdb\x0d\xe4\x52\xe7\x85\x3f\x6d\x90\x2f\x71\x69\xec\xa6\xef\x28\x21\x75\xf8\x68\xbd\x70\xd2\x92\x67\x2e\xdc\x85\x26\x9e\x88\xd4\xb7\xc2\x75\xb6\x4b\xe7\xc6\xf9\xd3\x72\x89\x1e\xca\x35\xb6\x05\xb1\x1d\x0f\xef\x8e\xf7\xad\x35\xec\x6e\x91\x70\xf2\x5d\x97\x58\xee\xcf\x2a\x7c\x57\x69\xa2\x9f\x17\x6e\xd1\x61\x38\x6d\x57\xb7\xa9\x60\x04\xde\x16\x78\x10\xfe\x0c\xa9\x7d\x38\x39\x54\x19\xe5\x12\x6f\x8b\x84\x61\x35\x17\x9c\x69\x38\xd2\x05\x65\x5e\x57\xcc\xd8\xe6\xde\x98\x7d\x74\x45\x70\xdd\x4c\x2e\xdf\xbc\x9e\xdc\x4c\xaf\x3f\x9c\x4f\x8f\x6b\x70\x52\x98\x79\x52\xaa\x79\x06\x85\x7a\xee\x17\xac\x3f\x89\x6b\xae\x7e\x26\x9e\x17\x27\x5f\xc2\x1b\x18\x1d\x08\xf9\xd6\xe3\x1c\xf0\xf9\x0b\xcb\xbe\xdf\x37\x5f\x93\x34\x18\xf3\xaf\x41\x92\x37\x4c\x5c\x92\x7b\x53\x12\x3c\xee\xe7\xbf\x18\x54\xe9\x8c\x28\x7e\x14\x4a\xe8\x04\x1f\xd1\x79\x1f\x6b\xf5\xa4\x79\x20\x0f\x2d\xd1\x2f\x4c\xca\x85\x21\x11\xa1\xb6\x94\x08\x4a\x8d\xc6\x7f\x3f\x1b\x8d\x2f\x2f\x6b\xb9\x88\x9f\xcf\xaf\x5e\xd7\xf3\xd3\xf1\xeb\xc9\xe5\xe4\xed\x78\x3a\xd9\xa5\xbd\x99\x8e\xa7\x17\xe7\xfc\xb6\x4c\x5d\x83\x01\xdc\xdc\xca\x9c\x2b\x0c\xe7\x6d\xb3\xcc\xb9\x55\xae\xf4\x75\x3d\xf0\x0b\x43\x4d\xa8\x8d\x05\x34\x13\x3a\x29\x0b\x9b\x2b\x01\xeb\x0d\xc1\xf5\x21\xe7\x9d\xec\x38\xaf\x82\xb0\x74\xef\x2d\xc6\x4d\xd3\x8e\x37\xa5\x5e\x5b\x83\x06\x34\x72\xf2\xe7\x04\xdb\x79\xfa\x21\xe1\x1f\x30\x84\x53\x38\x89\x59\xf4\x91\x34\xfd\x12\x9e\x93\xf8\x3f\x91\xac\x5f\x1d\xe0\xfc\x7b\xa6\xec\xbd\x40\xfb\xef\xa7\x72\x53\xf8\xab\x2c\x3b\x85\x5d\x23\x7e\xbb\x67\xc4\x8a\xfe\x12\xf5\x3e\xfd\xff\xed\xd1\x6f\xd3\x3e\xa1\xca\xe4\xf0\x6c\x0f\x22\x21\xe9\x3e\xdb\x89\x83\x68\x5c\x6e\xef\x58\x1a\x8c\x1e\x28\x34\x2f\x9b\x18\x7e\x28\x53\xfe\x47\x85\xe6\x60\x9b\x4a\xcd\x68\xb3\x11\xed\x81\x45\x6f\x25\xae\x68\xd4\x3c\x76\x2c\x92\x1a\x76\xb3\xa6\xf4\xd5\x87\x8f\x18\x24\x6a\x44\x4e\x2e\xb1\xc1\xa7\xfe\x8c\x7b\x5e\x6a\xd2\xe3\xa8\xc6\x10\x13\xdc\x87\x5b\x84\xa5\xd8\xd0\xa8\x96\x15\xfa\x76\x03\x73\xe1\x20\xdd\x68\xb1\x94\x89\x0b\xf2\xb8\xb9\xb7\x38\x17\x96\xc5\x5a\xfc\xad\x40\x47\x73\x1f\x01\x59\x24\xbe\x10\x4a\x6d\x60\x2e\x69\x78\x23\xee\xce\xcb\x57\xc3\x21\x38\x2f\x73\xd4\x69\x0f\xbe\x7b\x35\xf8\xee\x5b\xb0\x85\xc2\x6e\xbf\x5d\x2b\x61\xd5\x51\xa3\x37\x68\x21\xa2\xe7\x35\xe6\x7e\xd1\xe9\xc2\x0f\x0f\xd4\xc2\x07\x0a\xdb\x41\x5a\x78\x01\x27\x5f\xfa\xa4\xd7\xa8\x81\xdb\xe0\x49\x40\xe5\x30\x4a\xa3\x81\xf7\xea\xf5\x55\xe7\x56\x58\xa1\xc4\x0c\xbb\xa7\x3c\x00\xb3\xad\xd6\x22\x4e\x40\xe4\x14\xc8\x95\x90\x1a\x44\x92\x98\x42\x7b\x32\x7c\x39\xcc\xa8\x0d\xe5\xf7\x63\x5f\xca\xe3\x59\x51\x24\x09\x3a\x57\xa6\x7b\xf6\x1a\xa9\x23\x96\xc4\x0d\x52\x3b\x99\x62\xcd\x2b\x94\x1d\x0c\xa7\xe6\x48\x41\xa3\x74\x29\x70\x69\x1c\x6d\x32\x43\x58\x5b\x1a\xbc\x9c\xd4\x09\xdf\x3c\xa4\x48\xd6\x76\x60\x34\x08\x50\x86\xaf\x3b\x38\xc6\x41\xd8\xb9\xeb\x87\x7c\x4f\xdb\x52\xce\xd1\x66\xdd\x6f\x02\xb9\x0e\x55\x1e\x71\x76\x5a\x21\x0d\x78\x27\x9d\xe7\x8e\x9a\xb4\x94\x0e\x02\x92\xa5\x9e\xf7\x20\x37\x39\xe7\xe9\xaf\x95\xb3\x98\xac\xaf\x27\xbf\x4c\xae\xab\xc6\xe7\xe9\x4e\x2c\x67\x9e\xa3\x6a\x24\x04\x4b\xf3\x96\xc7\xf4\xe8\xc0\x10\x73\x00\x50\xa3\x07\x00\x45\xf2\xb7\xb5\xf1\x7d\xed\x38\x4a\x38\xbf\x75\xcc\x1c\xc3\x3c\x57\x57\xc0\x15\xca\xbb\x9d\xdc\xbd\x9b\x1c\x4c\x5e\x56\x08\x52\x8a\xd3\x0e\x25\xf6\xdd\x49\xa3\xb1\xb0\x1d\x38\xb6\xf8\xbc\xa8\xd9\x78\xcd\xed\x66\x20\xaa\xa5\x06\x5e\x2f\xfb\x56\x11\xaa\x01\xeb\x6e\x0a\x4f\x70\xa0\xfa\xbd\x4d\x7e\x73\xe1\x3e\x38\xf6\x7a\x4c\x7f\x33\x39\xbf\xd0\xbe\x53\x2e\x5e\x68\x78\x01\xe5\x03\x25\x75\x78\xd1\x88\xa2\x03\xd9\xb1\x95\xa2\x42\x8f\xb0\x15\x71\x06\x3b\xaf\x48\x50\x30\x07\x1b\xcd\xa2\xdf\x2f\xce\xc3\x28\x8d\x0c\xf6\xcc\xa2\xef\xe3\x6f\x85\x50\xae\x33\xac\x9a\x85\x70\x02\x6f\xb8\xbc\x8d\xf6\x3a\x49\xe2\x69\xf6\x8e\x67\x35\xb6\x68\x8d\x92\x2d\x74\x82\xe7\x26\xc5\x47\x25\x44\x11\x31\x6d\x54\xbe\x8c\xc0\x3c\xd4\x7b\xb7\xea\x04\x70\x54\x35\x04\x99\x90\xaa\xb0\x78\x74\x06\x07\xd2\x8e\x2b\x6c\x26\x12\xf6\xa5\x43\xe0\x69\xdd\x81\x33\x4b\x5c\x98\x75\x50\xe0\x50\xf2\xda\x07\x47\x85\x83\x9d\xf2\xc1\xd7\x4e\xc2\x41\xe1\xc4\x1c\x6b\xe0\xa8\x0c\x5e\x3a\xea\xe0\x15\xc2\x9f\x86\xce\xf3\xea\xf1\x09\x28\xba\xff\x6b\xe0\xb1\xe3\xe7\xbd\x3e\xa7\x24\xe2\x6e\xa7\xf6\x50\x2a\x1b\x9a\x91\xbf\x97\xe3\x9f\x1c\x61\xbb\xb4\xe1\x68\x4d\xe2\x70\xc0\x6d\x5f\xf3\x75\xf7\x57\xab\x0f\x79\xfe\xa1\x96\x89\x30\xaa\x7f\xc5\xc4\x6f\x71\xca\x5d\x0e\x3d\xe5\x16\x57\xd2\x14\x54\xc0\xf0\x7f\x69\x1c\xae\x5a\xbe\xfb\x76\xeb\x3e\xde\x0b\xb2\xdf\xea\x17\x83\xeb\x45\xbc\xd7\x0e\xdd\x52\xad\x7c\x18\xae\xad\xf1\xba\x30\x0b\x37\xce\x2d\xe6\x7f\xe4\x82\x30\x06\xba\x37\x39\xb5\x03\xb1\x3a\x29\x8b\x22\xdd\x54\x05\xb1\x17\x1a\x11\x58\x08\x9d\xc6\x61\x44\xa4\xa9\x24\x79\x0c\x42\xd2\x50\xcc\x85\xd4\xed\x83\x66\xfc\x6a\x15\x3e\x84\x8c\xbd\xde\xb6\x5e\x48\xe3\x10\x49\x13\x1f\x6b\xdc\x7e\x42\xc1\xdc\x09\xa2\xdd\xbb\xce\x78\x5d\x6a\xb4\x2b\x96\xdc\x09\x83\x58\x09\xa9\x04\x4d\x5f\xdc\x61\xe9\x14\x12\x85\x42\x87\x2f\x1c\x98\x79\xb3\x42\xeb\xda\x4f\x00\xf9\x9f\xc1\xf8\x4e\x56\x2c\x1f\xa3\x39\x9e\x1e\xb3\x4f\x8d\xd8\x70\xfc\x37\x4a\x78\x1f\xe1\x55\x33\x6f\x88\x2c\xe9\xf9\xe3\x17\x6a\xdf\x7e\x5a\x48\x71\xcf\x44\x34\x3f\xc0\xb0\xd6\x97\xff\x5d\x82\x6c\x1f\x62\x97\x55\x7f\x16\x0f\xef\x8d\xe9\x81\x42\xc1\x53\x52\xf9\x69\xaa\xec\x47\x1f\x1b\xda\xca\xe8\x0d\x1d\xdd\x5e\xf8\xf2\x9d\xde\x02\xcb\x1b\x90\xd0\xda\xcf\x10\x35\x48\x8f\x56\xd0\x3c\x44\xe8\x8a\x5f\x53\x48\x4b\xc7\xe2\xd8\x2f\x92\x82\x2e\x0a\x8e\x9f\x36\xa8\x30\x4b\x3d\xef\xb7\x5b\xe1\x7d\x2d\xde\x13\x7f\xb7\x8d\xf7\x50\x01\x99\x33\xde\x09\x54\x57\x02\x89\xbf\xe3\x6e\x91\xc7\xe6\x9d\x7b\x01\x5a\xa3\x57\x61\xa6\xde\xb9\x05\x60\xc6\x78\x13\xb0\x7b\x27\x46\x6b\xfc\xae\x01\x70\x26\x9d\x0b\x17\xc4\xec\x84\x84\xbf\xdb\x8f\x88\x92\x81\x82\xe1\xf4\x30\x03\x2d\x1d\x60\xda\xb9\x99\x20\x62\x7e\x15\x56\x43\x3d\x3f\xad\xaf\x86\x57\xf1\xa0\x72\x59\xb3\x8d\x5c\xb2\x6d\xee\xcf\x0e\x27\xb9\x61\x89\xc7\xc3\xc9\x8c\x6c\x5e\x01\xf6\x01\xd6\xfa\xac\xb1\x4f\xf2\x58\xaa\x64\xe9\x65\x66\x7b\x80\x95\xa5\xd7\x5a\x0e\x7f\xf7\x74\x91\x15\x71\x5d\xc5\x06\x4d\x43\x08\xdf\x36\xee\x2d\x1f\x9a\xb4\x68\x50\x89\x84\x65\x73\x35\x1a\x1d\x0d\xef\xaa\x0f\x23\x31\x57\x35\x68\x4a\x25\x42\x64\x84\xf3\x72\x54\xc8\x7f\x62\xdc\xb6\x1e\x83\xe5\x12\x58\x0c\x1f\x70\xb8\x9b\xa5\x10\x34\x33\x6e\x20\x0a\x47\xa3\xe8\x36\xb6\x52\x74\xd2\x62\x0a\x99\x44\x95\x82\x49\xd1\xf2\xa0\xfb\xab\x33\x3a\x7c\xaa\x43\x2b\x49\x62\xf8\x24\x19\xfe\x1d\xc0\x1f\x4a\xb5\x4c\xd0\x6f\x20\x43\xc1\xdf\xdc\xbc\x81\x5c\x38\x07\x4b\x14\x34\xda\x66\x85\x52\x1b\x30\x36\x45\x12\x5e\xcd\x7a\x14\xd6\x06\x0a\x87\xd6\xc1\x7a\x61\x62\xa9\xe5\x16\x2f\xa7\x6e\x55\xfa\x5e\xbc\xce\x91\x2e\x57\x62\x03\xd2\x53\x59\x8f\x87\xaa\x47\x7a\xf5\xa1\x8b\xbf\x96\x19\x32\xf0\x7e\x98\x97\x53\x61\x33\xce\xf9\x35\x3d\x35\x23\x3c\x0e\x45\xcd\xd8\xde\x5e\x74\x35\x03\xb9\x2c\x3d\xcd\x68\xad\x17\xb2\x66\x48\xf2\x0a\x3f\x35\x83\xb1\xd6\x6a\xf3\x02\x23\xa8\x62\xe0\xa7\x9d\xf0\x64\x2d\x63\x7c\x86\xcf\xba\x15\x39\x3f\xf5\x22\x60\xc8\x8b\x1d\x32\xce\x2d\x6e\x28\x9b\x07\x1b\xd5\x4a\x53\x78\xf1\xf9\x16\x37\x5f\x0e\x57\xa2\x08\xc7\x1a\x5d\x55\x7a\xca\xb0\x08\x6b\x8f\x24\x83\x4a\x0b\x39\x1a\x9e\x81\xfc\xbe\xce\x50\x56\x4f\x90\xcf\x9f\x97\x7b\xd6\xd7\x3f\xcb\x2f\x65\x84\x57\x88\xdf\x59\xef\x36\x34\x8a\x31\x12\x68\x28\x28\xda\xf7\xed\x7f\x05\x00\x00\xff\xff\xfb\x65\x93\x4f\xfc\x22\x00\x00") +var _call_tracer_jsJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x56\x5f\x6f\xdb\x38\x0c\x7f\x8e\x3f\x05\xaf\x0f\x4b\x82\x65\x71\xbb\x03\xf6\xd0\x2d\x03\x72\x45\xbb\x05\xe8\xb5\x45\x9a\xde\x50\x14\x7d\x50\x6c\xda\xd6\xa6\x48\x86\x44\x37\xcd\x6d\xfd\xee\x07\x4a\x76\x6a\x67\x59\x6f\x2f\x06\x2c\x92\x3f\xfe\xfb\x51\x54\x1c\xc3\x89\x29\x37\x56\xe6\x05\xc1\xdb\xc3\xb7\x47\xb0\x28\x10\x72\xf3\x06\xa9\x40\x8b\xd5\x0a\xa6\x15\x15\xc6\xba\x28\x8e\x61\x51\x48\x07\x99\x54\x08\xd2\x41\x29\x2c\x81\xc9\x80\x76\xf4\x95\x5c\x5a\x61\x37\xe3\x28\x8e\x83\xcd\x5e\x31\x23\x64\x16\x11\x9c\xc9\x68\x2d\x2c\x1e\xc3\xc6\x54\x90\x08\x0d\x16\x53\xe9\xc8\xca\x65\x45\x08\x92\x40\xe8\x34\x36\x16\x56\x26\x95\xd9\x86\x21\x25\x41\xa5\x53\xb4\xde\x35\xa1\x5d\xb9\x26\x8e\x4f\x17\x37\x70\x8e\xce\xa1\x85\x4f\xa8\xd1\x0a\x05\x57\xd5\x52\xc9\x04\xce\x65\x82\xda\x21\x08\x07\x25\x9f\xb8\x02\x53\x58\x7a\x38\x36\x3c\xe3\x50\xae\xeb\x50\xe0\xcc\x54\x3a\x15\x24\x8d\x1e\x01\x4a\x8e\x1c\x1e\xd0\x3a\x69\x34\xfc\xd9\xb8\xaa\x01\x47\x60\x2c\x83\x0c\x04\x71\x02\x16\x4c\xc9\x76\x43\x10\x7a\x03\x4a\xd0\xb3\xe9\x6f\x14\xe4\x39\xef\x14\xa4\xf6\x6e\x0a\x53\x22\x50\x21\x88\xb3\x5e\x4b\xa5\x60\x89\x50\x39\xcc\x2a\x35\x62\xb4\x65\x45\xf0\x65\xb6\xf8\x7c\x79\xb3\x80\xe9\xc5\x2d\x7c\x99\xce\xe7\xd3\x8b\xc5\xed\x7b\x58\x4b\x2a\x4c\x45\x80\x0f\x18\xa0\xe4\xaa\x54\x12\x53\x58\x0b\x6b\x85\xa6\x0d\x98\x8c\x11\xfe\x3e\x9d\x9f\x7c\x9e\x5e\x2c\xa6\x7f\xcd\xce\x67\x8b\x5b\x30\x16\xce\x66\x8b\x8b\xd3\xeb\x6b\x38\xbb\x9c\xc3\x14\xae\xa6\xf3\xc5\xec\xe4\xe6\x7c\x3a\x87\xab\x9b\xf9\xd5\xe5\xf5\xe9\x18\xae\x91\xa3\x42\xb6\xff\xff\x9a\x67\xbe\x7b\x16\x21\x45\x12\x52\xb9\xa6\x12\xb7\xa6\x02\x57\x98\x4a\xa5\x50\x88\x07\x04\x8b\x09\xca\x07\x4c\x41\x40\x62\xca\xcd\x6f\x37\x95\xb1\x84\x32\x3a\xf7\x39\xff\x92\x90\x30\xcb\x40\x1b\x1a\x81\x43\x84\x0f\x05\x51\x79\x1c\xc7\xeb\xf5\x7a\x9c\xeb\x6a\x6c\x6c\x1e\xab\x00\xe7\xe2\x8f\xe3\x28\x62\xd0\x44\x28\x75\x66\xc5\x0a\x17\x56\x24\x68\xb9\xee\xce\xc3\x6b\x5c\x7b\x21\x64\x2c\x05\xb2\x22\x91\x3a\x87\x15\x52\x61\x52\x07\x64\xc0\x62\x69\x2c\xd5\x9d\x02\xa9\x33\x63\x57\x9e\x51\x3e\xd8\x25\x37\x46\x6a\x42\xab\x85\x82\x15\x3a\x27\x72\xf4\x2c\x16\x0c\xa6\x9d\x48\xc8\x53\xe6\x7b\xd4\x63\x3f\x8e\x44\xf2\xed\x18\xee\xbe\x3f\xdd\x8f\xa2\x5e\x26\x2a\x45\xc7\x90\x55\xda\x6b\x0d\x94\xc9\x47\x90\x2e\x87\xf0\xfd\x69\x14\xf5\x2c\xba\xae\x38\xa1\xc7\x5a\x1c\xf5\x7a\x71\x0c\x57\x16\x4b\x66\xb9\xa9\x98\x9d\xb5\x73\x1f\x62\xd4\xeb\x3d\x08\x0b\x01\x01\x26\xde\xa0\x47\x9b\x12\x8f\x01\x00\x12\x7a\x1c\xf3\xcf\x88\x4f\x33\x6b\x56\xfe\x94\xcc\x67\x7c\x64\x1f\x63\x3e\x1a\x7a\x21\x19\x2f\x6a\x0b\xc9\x04\xd1\x83\x50\x95\x87\xeb\x1f\x3e\xf6\xe1\xb5\x07\xf5\x67\x63\x32\xd7\x64\xa5\xce\x07\x47\xef\x82\x6a\x2e\x5c\x80\xa9\x55\x97\x32\x9f\x69\xf2\x68\xb9\x70\xc3\xbd\x06\x37\x0e\xd3\xe3\xfd\x06\x2c\xda\x63\x24\x75\x59\xd1\x71\x27\x56\x7f\x14\xa4\xa6\xa2\x20\x7e\x96\x86\x23\x2f\x7e\x8a\x7a\x3d\x99\xc1\x80\x0a\xe9\xc6\xdb\x3e\xdd\x1d\xde\x87\x1f\xf8\x63\x32\xf1\x37\x55\x26\x35\xa6\xa1\xfe\x75\x7b\x6a\x85\x09\xfc\xc2\xf4\x45\x70\xb4\xd6\xd8\x97\xc0\x83\xc2\x3e\x70\x2f\x61\x70\x40\xe5\x10\x18\x9f\x73\xfa\x6d\xc4\xad\x72\x2b\xc0\x8e\x4a\x07\x03\x5e\xbd\xda\x23\x3e\xc0\x47\x4c\x2a\xa6\x26\x58\x7c\x40\x4b\x98\x1e\xc0\x8f\x1f\x35\xed\xea\xfa\xc2\x64\x32\x39\x38\x7c\x3c\x18\xd6\x71\xa4\xa8\x90\xb0\xab\xe3\x63\x88\x38\x46\xaa\xac\x0e\xd9\x66\x52\x0b\x25\xff\xc5\xda\xed\x30\xea\xf1\x4c\x20\x8f\x5a\x6b\x24\xfc\xd8\x06\x64\x26\xbc\x1f\xe5\x0e\xdd\xbd\xc2\x38\x47\x5a\x6c\x4a\x1c\x0c\x5b\x94\x0f\x44\xd8\xca\xcf\xac\x59\x0d\x86\xcf\xb4\xdf\x11\x2f\x4c\x23\xac\x79\xb6\x23\x9f\xf1\x69\xa3\xe2\x09\xdf\xe5\xee\x56\xf1\x93\x70\x83\x61\x8b\xbe\xfd\xa3\x77\xfd\x0e\x07\xb7\x9a\xff\xf0\x34\x0d\x86\x3b\xdd\xf4\xb9\x71\x9e\x61\xda\x26\xbf\x70\x53\x1b\x77\xe7\xa4\xf6\xd2\x65\xd3\xb8\xac\x5c\x31\xe0\xdf\xa6\xc6\x8f\x92\x76\x4b\x3c\x0f\x4d\xd8\x16\x5a\xa1\xfe\x89\x96\x63\x85\x3a\xa7\xa2\x4e\x83\x35\x3e\xc2\x51\xdd\xf5\x56\x73\x76\xbd\x9b\x72\x30\xdc\xe6\x54\x8f\x37\x4c\xf6\x95\x2f\x04\x51\x17\x91\xd5\x7e\x2e\x64\xe3\xab\xa1\xf9\x8e\xdd\x29\x1f\x07\x77\x1c\x63\xad\xb5\x67\x5a\x42\x34\x0d\x83\xdb\xcd\x7e\x06\xbb\xf4\xd2\xc1\xd0\xc3\xd5\x73\xd8\x32\x6e\x42\x68\xa6\x2c\xb8\xf4\x22\xa6\xa6\x77\xdb\x3f\x99\x9f\x4e\x17\xa7\x7d\x9e\x9a\xbd\x92\xb7\xfd\x26\xa0\x66\x70\x82\x9a\xf1\x67\x4f\x51\xf3\xe1\x6a\xbf\x99\xc0\x51\x93\xd9\xce\x85\xa1\x50\xbf\x39\x6a\x2e\xb3\xbd\xf9\xbe\x68\x00\x77\xf7\x5b\x4f\x2f\x28\x76\x98\xc4\xda\xcc\xa6\x38\x86\x66\x94\xf9\x5d\x60\x51\x10\x3a\x7e\x18\x30\x1b\xcc\xf2\x2b\x26\xbc\x5c\x79\xe9\xf2\x3e\xf6\xaa\x90\xa2\x93\x16\x53\xc8\x24\xaa\x14\x0c\xbf\x10\xf9\xe9\xf1\xd5\x19\xed\x01\x1d\x5a\xc9\x88\x7e\x0f\x8f\xc3\x6b\x56\x32\xa8\x96\x09\xd2\x06\x32\x14\x54\x59\xe4\xf5\x5d\x0a\xe7\x60\x85\x42\x4b\x9d\x67\x95\x52\x1b\x30\x36\x45\x06\x0f\xf7\x8a\xf3\x80\x64\x78\xc1\x5b\x07\xeb\xc2\x40\x6a\x74\xbf\x5e\xea\xa5\x45\x7e\xaf\x8d\xe0\x6b\xe5\x88\x5f\x75\xa5\x12\x1b\x90\x34\x8e\x7a\x4d\x52\xed\xfd\xcc\x99\x6f\x47\xc4\x19\xbe\x10\x7f\x5e\xbe\x4d\x9b\xbb\xdb\xd7\x1f\xf3\x5f\x77\xef\xd6\xdd\xee\x6e\xdc\xe7\xe9\xef\xae\xd7\x66\x82\xba\x3b\xb4\x3d\x57\xdd\x45\xe9\x25\xfe\xaf\xbb\x22\x5b\xdc\xf7\x02\xcf\xe0\xad\x81\xff\x0b\x51\xca\x55\x3b\x27\xb9\x0a\xf1\x78\x2e\x6c\xd5\xfd\x5f\x73\xbf\x71\x17\x07\x5c\x9c\x6f\xb8\xe1\x87\x71\xa8\x51\xcd\x41\xe6\x6d\x38\xb8\xfb\x86\x9b\xfb\xfd\x3c\xad\xa7\xa0\xa5\xd7\x30\xb3\xb9\x3f\x83\xe8\x85\xc5\xbd\x0d\x42\x4e\x0e\xdf\x83\xfc\xd0\x36\xa8\xef\xb0\xf7\x20\x5f\xbf\x6e\x5c\xb6\xe5\x77\xf2\xbe\xb9\xc2\xb6\x0b\x6a\x47\x3e\x6c\x07\x54\x6f\xb4\xa0\x12\xf5\x9e\xa2\xa7\xe8\xbf\x00\x00\x00\xff\xff\x2a\xac\x9f\xff\xa9\x0d\x00\x00") + +func call_tracer_jsJsBytes() ([]byte, error) { + return bindataRead( + _call_tracer_jsJs, + "call_tracer_js.js", + ) +} + +func call_tracer_jsJs() (*asset, error) { + bytes, err := call_tracer_jsJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "call_tracer_js.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x42, 0x13, 0x7a, 0x14, 0xbf, 0xa7, 0x49, 0x4f, 0xb4, 0x4f, 0x45, 0x1, 0xbc, 0x9e, 0xd1, 0x8e, 0xc7, 0xee, 0x61, 0xfa, 0x82, 0x52, 0xa4, 0x78, 0xfe, 0xff, 0xb1, 0x68, 0x1d, 0xcc, 0x1d, 0x8e}} + return a, nil +} + +var _call_tracer_legacyJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x5a\xdf\x6f\x1b\x37\xf2\x7f\x96\xfe\x8a\x89\x1f\x6a\x09\x51\x24\x39\xe9\xb7\x5f\xc0\xae\x7a\x50\x1d\x25\x35\xe0\xc6\x81\xad\x34\x08\x82\x3c\x50\xbb\xb3\x12\x6b\x8a\xdc\x92\x5c\xc9\xba\xd6\xff\xfb\x61\x86\xdc\xd5\xae\x24\x3b\xbe\x5e\x71\xe8\xbd\x69\x97\x33\xc3\xe1\xcc\x67\x7e\x71\x35\x18\xc0\xb9\xc9\x37\x56\xce\x17\x1e\x5e\x0e\x4f\xfe\x1f\xa6\x0b\x84\xb9\x79\x81\x7e\x81\x16\x8b\x25\x8c\x0b\xbf\x30\xd6\xb5\x07\x03\x98\x2e\xa4\x83\x4c\x2a\x04\xe9\x20\x17\xd6\x83\xc9\xc0\xef\xd0\x2b\x39\xb3\xc2\x6e\xfa\xed\xc1\x20\xf0\x1c\x5c\x26\x09\x99\x45\x04\x67\x32\xbf\x16\x16\x4f\x61\x63\x0a\x48\x84\x06\x8b\xa9\x74\xde\xca\x59\xe1\x11\xa4\x07\xa1\xd3\x81\xb1\xb0\x34\xa9\xcc\x36\x24\x52\x7a\x28\x74\x8a\x96\xb7\xf6\x68\x97\xae\xd4\xe3\xed\xbb\x0f\x70\x89\xce\xa1\x85\xb7\xa8\xd1\x0a\x05\xef\x8b\x99\x92\x09\x5c\xca\x04\xb5\x43\x10\x0e\x72\x7a\xe3\x16\x98\xc2\x8c\xc5\x11\xe3\x1b\x52\xe5\x26\xaa\x02\x6f\x4c\xa1\x53\xe1\xa5\xd1\x3d\x40\x49\x9a\xc3\x0a\xad\x93\x46\xc3\xab\x72\xab\x28\xb0\x07\xc6\x92\x90\x8e\xf0\x74\x00\x0b\x26\x27\xbe\x2e\x08\xbd\x01\x25\xfc\x96\xf5\x09\x06\xd9\x9e\x3b\x05\xa9\x79\x9b\x85\xc9\x11\xfc\x42\x78\x3a\xf5\x5a\x2a\x05\x33\x84\xc2\x61\x56\xa8\x1e\x49\x9b\x15\x1e\x3e\x5e\x4c\x7f\xba\xfa\x30\x85\xf1\xbb\x4f\xf0\x71\x7c\x7d\x3d\x7e\x37\xfd\x74\x06\x6b\xe9\x17\xa6\xf0\x80\x2b\x0c\xa2\xe4\x32\x57\x12\x53\x58\x0b\x6b\x85\xf6\x1b\x30\x19\x49\xf8\x79\x72\x7d\xfe\xd3\xf8\xdd\x74\xfc\xe3\xc5\xe5\xc5\xf4\x13\x18\x0b\x6f\x2e\xa6\xef\x26\x37\x37\xf0\xe6\xea\x1a\xc6\xf0\x7e\x7c\x3d\xbd\x38\xff\x70\x39\xbe\x86\xf7\x1f\xae\xdf\x5f\xdd\x4c\xfa\x70\x83\xa4\x15\x12\xff\xd7\x6d\x9e\xb1\xf7\x2c\x42\x8a\x5e\x48\xe5\x4a\x4b\x7c\x32\x05\xb8\x85\x29\x54\x0a\x0b\xb1\x42\xb0\x98\xa0\x5c\x61\x0a\x02\x12\x93\x6f\x9e\xec\x54\x92\x25\x94\xd1\x73\x3e\xf3\x83\x80\x84\x8b\x0c\xb4\xf1\x3d\x70\x88\xf0\xfd\xc2\xfb\xfc\x74\x30\x58\xaf\xd7\xfd\xb9\x2e\xfa\xc6\xce\x07\x2a\x88\x73\x83\x1f\xfa\x6d\x92\x99\x08\xa5\xa6\x56\x24\x68\xc9\x39\x02\xb2\x82\xcc\xaf\xcc\x5a\x83\xb7\x42\x3b\x91\x90\xab\xe9\x77\xc2\x60\x14\x1e\xf0\x8e\x9e\xbc\x23\xd0\x82\xc5\xdc\x58\xfa\xad\x54\x89\x33\xa9\x3d\x5a\x2d\x14\xcb\x76\xb0\x14\x29\xc2\x6c\x03\xa2\x2e\xb0\x57\x3f\x0c\xc1\x28\xb8\x1b\xa4\xce\x8c\x5d\x32\x2c\xfb\xed\xdf\xdb\xad\xa8\xa1\xf3\x22\xb9\x25\x05\x49\x7e\x52\x58\x8b\xda\x93\x29\x0b\xeb\xe4\x0a\x99\x04\x02\x4d\xb4\xe7\xe4\x97\x9f\x01\xef\x30\x29\x82\xa4\x56\x25\xe4\x14\x3e\xff\x7e\xff\xa5\xd7\x66\xd1\x29\xba\x04\x75\x8a\x29\x9f\xef\xd6\xc1\x7a\xc1\x16\x85\x35\x1e\xaf\x10\x7e\x2d\x9c\xaf\xd1\x64\xd6\x2c\x41\x68\x30\x05\x21\xbe\x6e\x1d\xa9\xbd\x61\x81\x82\x7e\x6b\xb4\xac\x51\xbf\xdd\xaa\x98\x4f\x21\x13\xca\x61\xdc\xd7\x79\xcc\xe9\x34\x52\xaf\xcc\x2d\x49\x36\x96\x20\x6c\x37\x60\xf2\xc4\xa4\x31\x18\xe8\x1c\xd5\x31\xd0\xf5\xdb\x2d\xe2\x3b\x85\xac\xd0\xbc\x6d\x47\x99\x79\x0f\xd2\x59\x17\x7e\x6f\xb7\x48\xec\xb9\xc8\x7d\x61\x91\xed\x89\xd6\x1a\xeb\x40\x2e\x97\x98\x4a\xe1\x51\x6d\xda\xad\xd6\x4a\xd8\xb0\x00\x23\x50\x66\xde\x9f\xa3\x9f\xd0\x63\xa7\x7b\xd6\x6e\xb5\x64\x06\x9d\xb0\xfa\x6c\x34\xe2\xec\x93\x49\x8d\x69\x10\xdf\xf2\x0b\xe9\xfa\x99\x28\x94\xaf\xf6\x25\xa6\x96\x45\x5f\x58\x4d\x3f\xef\x83\x16\x1f\x11\x8c\x56\x1b\x48\x28\xcb\x88\x19\x85\xa7\xdb\x38\x8f\xcb\x78\x38\xd7\x83\x4c\x38\x32\xa1\xcc\x60\x8d\x90\x5b\x7c\x91\x2c\x90\x7c\xa7\x13\x8c\x5a\xba\x8d\x63\xa7\x8e\x80\x76\xeb\x9b\xbc\xef\xcd\xbb\x62\x39\x43\xdb\xe9\xc2\x37\x30\xbc\xcb\x86\x5d\x18\x8d\xf8\x47\xa9\x7b\xe4\x89\xfa\x92\x14\x93\xc7\x83\x32\xff\x8d\xb7\x52\xcf\xc3\x59\xa3\xae\x17\x19\x08\xd0\xb8\x86\xc4\x68\x06\x35\x79\x65\x86\x52\xcf\x21\xb1\x28\x3c\xa6\x3d\x10\x69\x0a\xde\x04\xe4\x55\x38\x6b\x6e\x09\xdf\x7c\x03\x1d\xda\x6c\x04\xc7\xe7\xd7\x93\xf1\x74\x72\x0c\x7f\xfc\x01\xe1\xcd\x51\x78\xf3\xf2\xa8\x5b\xd3\x4c\xea\xab\x2c\x8b\xca\xb1\xc0\x7e\x8e\x78\xdb\x39\xe9\xf6\x57\x42\x15\x78\x95\x05\x35\x23\xed\x44\xa7\x30\x8a\x3c\xcf\x77\x79\x5e\x36\x78\x88\x69\x30\x80\xb1\x73\xb8\x9c\x29\xdc\x0f\xc8\x18\xb1\x1c\xbc\xce\x53\xc6\x22\xf4\x25\x66\x99\x2b\x24\x54\x95\xbb\x46\xf3\xb3\xc6\x2d\xbf\xc9\xf1\x14\x00\xc0\xe4\x3d\x7e\x41\xb1\xc0\x2f\xbc\xf9\x09\xef\xd8\x47\xa5\x09\x09\x55\xe3\x34\xb5\xe8\x5c\xa7\xdb\x0d\xe4\x52\xe7\x85\x3f\x6d\x90\x2f\x71\x69\xec\xa6\xef\x28\x21\x75\xf8\x68\xbd\x70\xd2\x92\x67\x2e\xdc\x85\x26\x9e\x88\xd4\xb7\xc2\x75\xb6\x4b\xe7\xc6\xf9\xd3\x72\x89\x1e\xca\x35\xb6\x05\xb1\x1d\x0f\xef\x8e\xf7\xad\x35\xec\x6e\x91\x70\xf2\x5d\x97\x58\xee\xcf\x2a\x7c\x57\x69\xa2\x9f\x17\x6e\xd1\x61\x38\x6d\x57\xb7\xa9\x60\x04\xde\x16\x78\x10\xfe\x0c\xa9\x7d\x38\x39\x54\x19\xe5\x12\x6f\x8b\x84\x61\x35\x17\x9c\x69\x38\xd2\x05\x65\x5e\x57\xcc\xd8\xe6\xde\x98\x7d\x74\x45\x70\xdd\x4c\x2e\xdf\xbc\x9e\xdc\x4c\xaf\x3f\x9c\x4f\x8f\x6b\x70\x52\x98\x79\x52\xaa\x79\x06\x85\x7a\xee\x17\xac\x3f\x89\x6b\xae\x7e\x26\x9e\x17\x27\x5f\xc2\x1b\x18\x1d\x08\xf9\xd6\xe3\x1c\xf0\xf9\x0b\xcb\xbe\xdf\x37\x5f\x93\x34\x18\xf3\xaf\x41\x92\x37\x4c\x5c\x92\x7b\x53\x12\x3c\xee\xe7\xbf\x18\x54\xe9\x8c\x28\x7e\x14\x4a\xe8\x04\x1f\xd1\x79\x1f\x6b\xf5\xa4\x79\x20\x0f\x2d\xd1\x2f\x4c\xca\x85\x21\x11\xa1\xb6\x94\x08\x4a\x8d\xc6\x7f\x3f\x1b\x8d\x2f\x2f\x6b\xb9\x88\x9f\xcf\xaf\x5e\xd7\xf3\xd3\xf1\xeb\xc9\xe5\xe4\xed\x78\x3a\xd9\xa5\xbd\x99\x8e\xa7\x17\xe7\xfc\xb6\x4c\x5d\x83\x01\xdc\xdc\xca\x9c\x2b\x0c\xe7\x6d\xb3\xcc\xb9\x55\xae\xf4\x75\x3d\xf0\x0b\x43\x4d\xa8\x8d\x05\x34\x13\x3a\x29\x0b\x9b\x2b\x01\xeb\x0d\xc1\xf5\x21\xe7\x9d\xec\x38\xaf\x82\xb0\x74\xef\x2d\xc6\x4d\xd3\x8e\x37\xa5\x5e\x5b\x83\x06\x34\x72\xf2\xe7\x04\xdb\x79\xfa\x21\xe1\x1f\x30\x84\x53\x38\x89\x59\xf4\x91\x34\xfd\x12\x9e\x93\xf8\x3f\x91\xac\x5f\x1d\xe0\xfc\x7b\xa6\xec\xbd\x40\xfb\xef\xa7\x72\x53\xf8\xab\x2c\x3b\x85\x5d\x23\x7e\xbb\x67\xc4\x8a\xfe\x12\xf5\x3e\xfd\xff\xed\xd1\x6f\xd3\x3e\xa1\xca\xe4\xf0\x6c\x0f\x22\x21\xe9\x3e\xdb\x89\x83\x68\x5c\x6e\xef\x58\x1a\x8c\x1e\x28\x34\x2f\x9b\x18\x7e\x28\x53\xfe\x47\x85\xe6\x60\x9b\x4a\xcd\x68\xb3\x11\xed\x81\x45\x6f\x25\xae\x68\xd4\x3c\x76\x2c\x92\x1a\x76\xb3\xa6\xf4\xd5\x87\x8f\x18\x24\x6a\x44\x4e\x2e\xb1\xc1\xa7\xfe\x8c\x7b\x5e\x6a\xd2\xe3\xa8\xc6\x10\x13\xdc\x87\x5b\x84\xa5\xd8\xd0\xa8\x96\x15\xfa\x76\x03\x73\xe1\x20\xdd\x68\xb1\x94\x89\x0b\xf2\xb8\xb9\xb7\x38\x17\x96\xc5\x5a\xfc\xad\x40\x47\x73\x1f\x01\x59\x24\xbe\x10\x4a\x6d\x60\x2e\x69\x78\x23\xee\xce\xcb\x57\xc3\x21\x38\x2f\x73\xd4\x69\x0f\xbe\x7b\x35\xf8\xee\x5b\xb0\x85\xc2\x6e\xbf\x5d\x2b\x61\xd5\x51\xa3\x37\x68\x21\xa2\xe7\x35\xe6\x7e\xd1\xe9\xc2\x0f\x0f\xd4\xc2\x07\x0a\xdb\x41\x5a\x78\x01\x27\x5f\xfa\xa4\xd7\xa8\x81\xdb\xe0\x49\x40\xe5\x30\x4a\xa3\x81\xf7\xea\xf5\x55\xe7\x56\x58\xa1\xc4\x0c\xbb\xa7\x3c\x00\xb3\xad\xd6\x22\x4e\x40\xe4\x14\xc8\x95\x90\x1a\x44\x92\x98\x42\x7b\x32\x7c\x39\xcc\xa8\x0d\xe5\xf7\x63\x5f\xca\xe3\x59\x51\x24\x09\x3a\x57\xa6\x7b\xf6\x1a\xa9\x23\x96\xc4\x0d\x52\x3b\x99\x62\xcd\x2b\x94\x1d\x0c\xa7\xe6\x48\x41\xa3\x74\x29\x70\x69\x1c\x6d\x32\x43\x58\x5b\x1a\xbc\x9c\xd4\x09\xdf\x3c\xa4\x48\xd6\x76\x60\x34\x08\x50\x86\xaf\x3b\x38\xc6\x41\xd8\xb9\xeb\x87\x7c\x4f\xdb\x52\xce\xd1\x66\xdd\x6f\x02\xb9\x0e\x55\x1e\x71\x76\x5a\x21\x0d\x78\x27\x9d\xe7\x8e\x9a\xb4\x94\x0e\x02\x92\xa5\x9e\xf7\x20\x37\x39\xe7\xe9\xaf\x95\xb3\x98\xac\xaf\x27\xbf\x4c\xae\xab\xc6\xe7\xe9\x4e\x2c\x67\x9e\xa3\x6a\x24\x04\x4b\xf3\x96\xc7\xf4\xe8\xc0\x10\x73\x00\x50\xa3\x07\x00\x45\xf2\xb7\xb5\xf1\x7d\xed\x38\x4a\x38\xbf\x75\xcc\x1c\xc3\x3c\x57\x57\xc0\x15\xca\xbb\x9d\xdc\xbd\x9b\x1c\x4c\x5e\x56\x08\x52\x8a\xd3\x0e\x25\xf6\xdd\x49\xa3\xb1\xb0\x1d\x38\xb6\xf8\xbc\xa8\xd9\x78\xcd\xed\x66\x20\xaa\xa5\x06\x5e\x2f\xfb\x56\x11\xaa\x01\xeb\x6e\x0a\x4f\x70\xa0\xfa\xbd\x4d\x7e\x73\xe1\x3e\x38\xf6\x7a\x4c\x7f\x33\x39\xbf\xd0\xbe\x53\x2e\x5e\x68\x78\x01\xe5\x03\x25\x75\x78\xd1\x88\xa2\x03\xd9\xb1\x95\xa2\x42\x8f\xb0\x15\x71\x06\x3b\xaf\x48\x50\x30\x07\x1b\xcd\xa2\xdf\x2f\xce\xc3\x28\x8d\x0c\xf6\xcc\xa2\xef\xe3\x6f\x85\x50\xae\x33\xac\x9a\x85\x70\x02\x6f\xb8\xbc\x8d\xf6\x3a\x49\xe2\x69\xf6\x8e\x67\x35\xb6\x68\x8d\x92\x2d\x74\x82\xe7\x26\xc5\x47\x25\x44\x11\x31\x6d\x54\xbe\x8c\xc0\x3c\xd4\x7b\xb7\xea\x04\x70\x54\x35\x04\x99\x90\xaa\xb0\x78\x74\x06\x07\xd2\x8e\x2b\x6c\x26\x12\xf6\xa5\x43\xe0\x69\xdd\x81\x33\x4b\x5c\x98\x75\x50\xe0\x50\xf2\xda\x07\x47\x85\x83\x9d\xf2\xc1\xd7\x4e\xc2\x41\xe1\xc4\x1c\x6b\xe0\xa8\x0c\x5e\x3a\xea\xe0\x15\xc2\x9f\x86\xce\xf3\xea\xf1\x09\x28\xba\xff\x6b\xe0\xb1\xe3\xe7\xbd\x3e\xa7\x24\xe2\x6e\xa7\xf6\x50\x2a\x1b\x9a\x91\xbf\x97\xe3\x9f\x1c\x61\xbb\xb4\xe1\x68\x4d\xe2\x70\xc0\x6d\x5f\xf3\x75\xf7\x57\xab\x0f\x79\xfe\xa1\x96\x89\x30\xaa\x7f\xc5\xc4\x6f\x71\xca\x5d\x0e\x3d\xe5\x16\x57\xd2\x14\x54\xc0\xf0\x7f\x69\x1c\xae\x5a\xbe\xfb\x76\xeb\x3e\xde\x0b\xb2\xdf\xea\x17\x83\xeb\x45\xbc\xd7\x0e\xdd\x52\xad\x7c\x18\xae\xad\xf1\xba\x30\x0b\x37\xce\x2d\xe6\x7f\xe4\x82\x30\x06\xba\x37\x39\xb5\x03\xb1\x3a\x29\x8b\x22\xdd\x54\x05\xb1\x17\x1a\x11\x58\x08\x9d\xc6\x61\x44\xa4\xa9\x24\x79\x0c\x42\xd2\x50\xcc\x85\xd4\xed\x83\x66\xfc\x6a\x15\x3e\x84\x8c\xbd\xde\xb6\x5e\x48\xe3\x10\x49\x13\x1f\x6b\xdc\x7e\x42\xc1\xdc\x09\xa2\xdd\xbb\xce\x78\x5d\x6a\xb4\x2b\x96\xdc\x09\x83\x58\x09\xa9\x04\x4d\x5f\xdc\x61\xe9\x14\x12\x85\x42\x87\x2f\x1c\x98\x79\xb3\x42\xeb\xda\x4f\x00\xf9\x9f\xc1\xf8\x4e\x56\x2c\x1f\xa3\x39\x9e\x1e\xb3\x4f\x8d\xd8\x70\xfc\x37\x4a\x78\x1f\xe1\x55\x33\x6f\x88\x2c\xe9\xf9\xe3\x17\x6a\xdf\x7e\x5a\x48\x71\xcf\x44\x34\x3f\xc0\xb0\xd6\x97\xff\x5d\x82\x6c\x1f\x62\x97\x55\x7f\x16\x0f\xef\x8d\xe9\x81\x42\xc1\x53\x52\xf9\x69\xaa\xec\x47\x1f\x1b\xda\xca\xe8\x0d\x1d\xdd\x5e\xf8\xf2\x9d\xde\x02\xcb\x1b\x90\xd0\xda\xcf\x10\x35\x48\x8f\x56\xd0\x3c\x44\xe8\x8a\x5f\x53\x48\x4b\xc7\xe2\xd8\x2f\x92\x82\x2e\x0a\x8e\x9f\x36\xa8\x30\x4b\x3d\xef\xb7\x5b\xe1\x7d\x2d\xde\x13\x7f\xb7\x8d\xf7\x50\x01\x99\x33\xde\x09\x54\x57\x02\x89\xbf\xe3\x6e\x91\xc7\xe6\x9d\x7b\x01\x5a\xa3\x57\x61\xa6\xde\xb9\x05\x60\xc6\x78\x13\xb0\x7b\x27\x46\x6b\xfc\xae\x01\x70\x26\x9d\x0b\x17\xc4\xec\x84\x84\xbf\xdb\x8f\x88\x92\x81\x82\xe1\xf4\x30\x03\x2d\x1d\x60\xda\xb9\x99\x20\x62\x7e\x15\x56\x43\x3d\x3f\xad\xaf\x86\x57\xf1\xa0\x72\x59\xb3\x8d\x5c\xb2\x6d\xee\xcf\x0e\x27\xb9\x61\x89\xc7\xc3\xc9\x8c\x6c\x5e\x01\xf6\x01\xd6\xfa\xac\xb1\x4f\xf2\x58\xaa\x64\xe9\x65\x66\x7b\x80\x95\xa5\xd7\x5a\x0e\x7f\xf7\x74\x91\x15\x71\x5d\xc5\x06\x4d\x43\x08\xdf\x36\xee\x2d\x1f\x9a\xb4\x68\x50\x89\x84\x65\x73\x35\x1a\x1d\x0d\xef\xaa\x0f\x23\x31\x57\x35\x68\x4a\x25\x42\x64\x84\xf3\x72\x54\xc8\x7f\x62\xdc\xb6\x1e\x83\xe5\x12\x58\x0c\x1f\x70\xb8\x9b\xa5\x10\x34\x33\x6e\x20\x0a\x47\xa3\xe8\x36\xb6\x52\x74\xd2\x62\x0a\x99\x44\x95\x82\x49\xd1\xf2\xa0\xfb\xab\x33\x3a\x7c\xaa\x43\x2b\x49\x62\xf8\x24\x19\xfe\x1d\xc0\x1f\x4a\xb5\x4c\xd0\x6f\x20\x43\xc1\xdf\xdc\xbc\x81\x5c\x38\x07\x4b\x14\x34\xda\x66\x85\x52\x1b\x30\x36\x45\x12\x5e\xcd\x7a\x14\xd6\x06\x0a\x87\xd6\xc1\x7a\x61\x62\xa9\xe5\x16\x2f\xa7\x6e\x55\xfa\x5e\xbc\xce\x91\x2e\x57\x62\x03\xd2\x53\x59\x8f\x87\xaa\x47\x7a\xf5\xa1\x8b\xbf\x96\x19\x32\xf0\x7e\x98\x97\x53\x61\x33\xce\xf9\x35\x3d\x35\x23\x3c\x0e\x45\xcd\xd8\xde\x5e\x74\x35\x03\xb9\x2c\x3d\xcd\x68\xad\x17\xb2\x66\x48\xf2\x0a\x3f\x35\x83\xb1\xd6\x6a\xf3\x02\x23\xa8\x62\xe0\xa7\x9d\xf0\x64\x2d\x63\x7c\x86\xcf\xba\x15\x39\x3f\xf5\x22\x60\xc8\x8b\x1d\x32\xce\x2d\x6e\x28\x9b\x07\x1b\xd5\x4a\x53\x78\xf1\xf9\x16\x37\x5f\x0e\x57\xa2\x08\xc7\x1a\x5d\x55\x7a\xca\xb0\x08\x6b\x8f\x24\x83\x4a\x0b\x39\x1a\x9e\x81\xfc\xbe\xce\x50\x56\x4f\x90\xcf\x9f\x97\x7b\xd6\xd7\x3f\xcb\x2f\x65\x84\x57\x88\xdf\x59\xef\x36\x34\x8a\x31\x12\x68\x28\x28\xda\xf7\xed\x7f\x05\x00\x00\xff\xff\xfb\x65\x93\x4f\xfc\x22\x00\x00") -func call_tracerJsBytes() ([]byte, error) { +func call_tracer_legacyJsBytes() ([]byte, error) { return bindataRead( - _call_tracerJs, - "call_tracer.js", + _call_tracer_legacyJs, + "call_tracer_legacy.js", ) } -func call_tracerJs() (*asset, error) { - bytes, err := call_tracerJsBytes() +func call_tracer_legacyJs() (*asset, error) { + bytes, err := call_tracer_legacyJsBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "call_tracer.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "call_tracer_legacy.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x46, 0x79, 0xb6, 0xbc, 0xd2, 0xc, 0x25, 0xb1, 0x22, 0x56, 0xef, 0x77, 0xb9, 0x5e, 0x2e, 0xf4, 0xda, 0xb2, 0x2f, 0x53, 0xa4, 0xff, 0xc8, 0xac, 0xbb, 0x75, 0x22, 0x46, 0x59, 0xe3, 0x1d, 0x7d}} return a, nil } @@ -348,15 +390,17 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ - "4byte_tracer.js": _4byte_tracerJs, - "bigram_tracer.js": bigram_tracerJs, - "call_tracer.js": call_tracerJs, - "evmdis_tracer.js": evmdis_tracerJs, - "noop_tracer.js": noop_tracerJs, - "opcount_tracer.js": opcount_tracerJs, - "prestate_tracer.js": prestate_tracerJs, - "trigram_tracer.js": trigram_tracerJs, - "unigram_tracer.js": unigram_tracerJs, + "4byte_tracer.js": _4byte_tracerJs, + "4byte_tracer_legacy.js": _4byte_tracer_legacyJs, + "bigram_tracer.js": bigram_tracerJs, + "call_tracer_js.js": call_tracer_jsJs, + "call_tracer_legacy.js": call_tracer_legacyJs, + "evmdis_tracer.js": evmdis_tracerJs, + "noop_tracer.js": noop_tracerJs, + "opcount_tracer.js": opcount_tracerJs, + "prestate_tracer.js": prestate_tracerJs, + "trigram_tracer.js": trigram_tracerJs, + "unigram_tracer.js": unigram_tracerJs, } // AssetDebug is true if the assets were built with the debug flag enabled. @@ -403,15 +447,17 @@ type bintree struct { } var _bintree = &bintree{nil, map[string]*bintree{ - "4byte_tracer.js": {_4byte_tracerJs, map[string]*bintree{}}, - "bigram_tracer.js": {bigram_tracerJs, map[string]*bintree{}}, - "call_tracer.js": {call_tracerJs, map[string]*bintree{}}, - "evmdis_tracer.js": {evmdis_tracerJs, map[string]*bintree{}}, - "noop_tracer.js": {noop_tracerJs, map[string]*bintree{}}, - "opcount_tracer.js": {opcount_tracerJs, map[string]*bintree{}}, - "prestate_tracer.js": {prestate_tracerJs, map[string]*bintree{}}, - "trigram_tracer.js": {trigram_tracerJs, map[string]*bintree{}}, - "unigram_tracer.js": {unigram_tracerJs, map[string]*bintree{}}, + "4byte_tracer.js": {_4byte_tracerJs, map[string]*bintree{}}, + "4byte_tracer_legacy.js": {_4byte_tracer_legacyJs, map[string]*bintree{}}, + "bigram_tracer.js": {bigram_tracerJs, map[string]*bintree{}}, + "call_tracer_js.js": {call_tracer_jsJs, map[string]*bintree{}}, + "call_tracer_legacy.js": {call_tracer_legacyJs, map[string]*bintree{}}, + "evmdis_tracer.js": {evmdis_tracerJs, map[string]*bintree{}}, + "noop_tracer.js": {noop_tracerJs, map[string]*bintree{}}, + "opcount_tracer.js": {opcount_tracerJs, map[string]*bintree{}}, + "prestate_tracer.js": {prestate_tracerJs, map[string]*bintree{}}, + "trigram_tracer.js": {trigram_tracerJs, map[string]*bintree{}}, + "unigram_tracer.js": {unigram_tracerJs, map[string]*bintree{}}, }} // RestoreAsset restores an asset under the given directory. diff --git a/eth/tracers/internal/tracers/bigram_tracer.js b/eth/tracers/js/internal/tracers/bigram_tracer.js similarity index 100% rename from eth/tracers/internal/tracers/bigram_tracer.js rename to eth/tracers/js/internal/tracers/bigram_tracer.js diff --git a/eth/tracers/js/internal/tracers/call_tracer_js.js b/eth/tracers/js/internal/tracers/call_tracer_js.js new file mode 100644 index 0000000000..7da7bf216a --- /dev/null +++ b/eth/tracers/js/internal/tracers/call_tracer_js.js @@ -0,0 +1,112 @@ +// 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 . + + +// callFrameTracer uses the new call frame tracing methods to report useful information +// about internal messages of a transaction. +{ + callstack: [{}], + fault: function(log, db) {}, + result: function(ctx, db) { + // Prepare outer message info + var result = { + type: ctx.type, + from: toHex(ctx.from), + to: toHex(ctx.to), + value: '0x' + ctx.value.toString(16), + gas: '0x' + bigInt(ctx.gas).toString(16), + gasUsed: '0x' + bigInt(ctx.gasUsed).toString(16), + input: toHex(ctx.input), + output: toHex(ctx.output), + } + if (this.callstack[0].calls !== undefined) { + result.calls = this.callstack[0].calls + } + if (this.callstack[0].error !== undefined) { + result.error = this.callstack[0].error + } else if (ctx.error !== undefined) { + result.error = ctx.error + } + if (result.error !== undefined && (result.error !== "execution reverted" || result.output ==="0x")) { + delete result.output + } + + return this.finalize(result) + }, + enter: function(frame) { + var call = { + type: frame.getType(), + from: toHex(frame.getFrom()), + to: toHex(frame.getTo()), + input: toHex(frame.getInput()), + gas: '0x' + bigInt(frame.getGas()).toString('16'), + } + if (frame.getValue() !== undefined){ + call.value='0x' + bigInt(frame.getValue()).toString(16) + } + this.callstack.push(call) + }, + exit: function(frameResult) { + var len = this.callstack.length + if (len > 1) { + var call = this.callstack.pop() + call.gasUsed = '0x' + bigInt(frameResult.getGasUsed()).toString('16') + var error = frameResult.getError() + if (error === undefined) { + call.output = toHex(frameResult.getOutput()) + } else { + call.error = error + if (call.type === 'CREATE' || call.type === 'CREATE2') { + delete call.to + } + } + len -= 1 + if (this.callstack[len-1].calls === undefined) { + this.callstack[len-1].calls = [] + } + this.callstack[len-1].calls.push(call) + } + }, + // finalize recreates a call object using the final desired field oder for json + // serialization. This is a nicety feature to pass meaningfully ordered results + // to users who don't interpret it, just display it. + finalize: function(call) { + var sorted = { + type: call.type, + from: call.from, + to: call.to, + value: call.value, + gas: call.gas, + gasUsed: call.gasUsed, + input: call.input, + output: call.output, + error: call.error, + time: call.time, + calls: call.calls, + } + for (var key in sorted) { + if (sorted[key] === undefined) { + delete sorted[key] + } + } + if (sorted.calls !== undefined) { + for (var i=0; i. + +// package js is a collection of tracers written in javascript. +package js + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "strings" + "sync/atomic" + "time" + "unicode" + "unsafe" + + "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/vm" + "github.com/ethereum/go-ethereum/crypto" + tracers2 "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" + "github.com/ethereum/go-ethereum/log" + "gopkg.in/olebedev/go-duktape.v3" +) + +// 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, "") +} + +var assetTracers = make(map[string]string) + +// init retrieves the JavaScript transaction tracers included in go-ethereum. +func init() { + for _, file := range tracers.AssetNames() { + name := camel(strings.TrimSuffix(file, ".js")) + assetTracers[name] = string(tracers.MustAsset(file)) + } + tracers2.RegisterLookup(true, newJsTracer) +} + +// makeSlice convert an unsafe memory pointer with the given type into a Go byte +// slice. +// +// Note, the returned slice uses the same memory area as the input arguments. +// If those are duktape stack items, popping them off **will** make the slice +// contents change. +func makeSlice(ptr unsafe.Pointer, size uint) []byte { + var sl = struct { + addr uintptr + len int + cap int + }{uintptr(ptr), int(size), int(size)} + + return *(*[]byte)(unsafe.Pointer(&sl)) +} + +// popSlice pops a buffer off the JavaScript stack and returns it as a slice. +func popSlice(ctx *duktape.Context) []byte { + blob := common.CopyBytes(makeSlice(ctx.GetBuffer(-1))) + ctx.Pop() + return blob +} + +// pushBigInt create a JavaScript BigInteger in the VM. +func pushBigInt(n *big.Int, ctx *duktape.Context) { + ctx.GetGlobalString("bigInt") + ctx.PushString(n.String()) + ctx.Call(1) +} + +// opWrapper provides a JavaScript wrapper around OpCode. +type opWrapper struct { + op vm.OpCode +} + +// pushObject assembles a JSVM object wrapping a swappable opcode and pushes it +// onto the VM stack. +func (ow *opWrapper) pushObject(vm *duktape.Context) { + obj := vm.PushObject() + + vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(int(ow.op)); return 1 }) + vm.PutPropString(obj, "toNumber") + + vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushString(ow.op.String()); return 1 }) + vm.PutPropString(obj, "toString") + + vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushBoolean(ow.op.IsPush()); return 1 }) + vm.PutPropString(obj, "isPush") +} + +// memoryWrapper provides a JavaScript wrapper around vm.Memory. +type memoryWrapper struct { + memory *vm.Memory +} + +// slice returns the requested range of memory as a byte slice. +func (mw *memoryWrapper) slice(begin, end int64) []byte { + if end == begin { + return []byte{} + } + if end < begin || begin < 0 { + // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go + // runtime goes belly up https://github.com/golang/go/issues/15639. + log.Warn("Tracer accessed out of bound memory", "offset", begin, "end", end) + return nil + } + if mw.memory.Len() < int(end) { + // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go + // runtime goes belly up https://github.com/golang/go/issues/15639. + log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", begin, "size", end-begin) + return nil + } + return mw.memory.GetCopy(begin, end-begin) +} + +// getUint returns the 32 bytes at the specified address interpreted as a uint. +func (mw *memoryWrapper) getUint(addr int64) *big.Int { + if mw.memory.Len() < int(addr)+32 || addr < 0 { + // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go + // runtime goes belly up https://github.com/golang/go/issues/15639. + log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", addr, "size", 32) + return new(big.Int) + } + return new(big.Int).SetBytes(mw.memory.GetPtr(addr, 32)) +} + +// pushObject assembles a JSVM object wrapping a swappable memory and pushes it +// onto the VM stack. +func (mw *memoryWrapper) pushObject(vm *duktape.Context) { + obj := vm.PushObject() + + // Generate the `slice` method which takes two ints and returns a buffer + vm.PushGoFunction(func(ctx *duktape.Context) int { + blob := mw.slice(int64(ctx.GetInt(-2)), int64(ctx.GetInt(-1))) + ctx.Pop2() + + ptr := ctx.PushFixedBuffer(len(blob)) + copy(makeSlice(ptr, uint(len(blob))), blob) + return 1 + }) + vm.PutPropString(obj, "slice") + + // Generate the `getUint` method which takes an int and returns a bigint + vm.PushGoFunction(func(ctx *duktape.Context) int { + offset := int64(ctx.GetInt(-1)) + ctx.Pop() + + pushBigInt(mw.getUint(offset), ctx) + return 1 + }) + vm.PutPropString(obj, "getUint") +} + +// stackWrapper provides a JavaScript wrapper around vm.Stack. +type stackWrapper struct { + stack *vm.Stack +} + +// peek returns the nth-from-the-top element of the stack. +func (sw *stackWrapper) peek(idx int) *big.Int { + if len(sw.stack.Data()) <= idx || idx < 0 { + // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go + // runtime goes belly up https://github.com/golang/go/issues/15639. + log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx) + return new(big.Int) + } + return sw.stack.Back(idx).ToBig() +} + +// pushObject assembles a JSVM object wrapping a swappable stack and pushes it +// onto the VM stack. +func (sw *stackWrapper) pushObject(vm *duktape.Context) { + obj := vm.PushObject() + + vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(len(sw.stack.Data())); return 1 }) + vm.PutPropString(obj, "length") + + // Generate the `peek` method which takes an int and returns a bigint + vm.PushGoFunction(func(ctx *duktape.Context) int { + offset := ctx.GetInt(-1) + ctx.Pop() + + pushBigInt(sw.peek(offset), ctx) + return 1 + }) + vm.PutPropString(obj, "peek") +} + +// dbWrapper provides a JavaScript wrapper around vm.Database. +type dbWrapper struct { + db vm.StateDB +} + +// pushObject assembles a JSVM object wrapping a swappable database and pushes it +// onto the VM stack. +func (dw *dbWrapper) pushObject(vm *duktape.Context) { + obj := vm.PushObject() + + // Push the wrapper for statedb.GetBalance + vm.PushGoFunction(func(ctx *duktape.Context) int { + pushBigInt(dw.db.GetBalance(common.BytesToAddress(popSlice(ctx))), ctx) + return 1 + }) + vm.PutPropString(obj, "getBalance") + + // Push the wrapper for statedb.GetNonce + vm.PushGoFunction(func(ctx *duktape.Context) int { + ctx.PushInt(int(dw.db.GetNonce(common.BytesToAddress(popSlice(ctx))))) + return 1 + }) + vm.PutPropString(obj, "getNonce") + + // Push the wrapper for statedb.GetCode + vm.PushGoFunction(func(ctx *duktape.Context) int { + code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx))) + + ptr := ctx.PushFixedBuffer(len(code)) + copy(makeSlice(ptr, uint(len(code))), code) + return 1 + }) + vm.PutPropString(obj, "getCode") + + // Push the wrapper for statedb.GetState + vm.PushGoFunction(func(ctx *duktape.Context) int { + hash := popSlice(ctx) + addr := popSlice(ctx) + + state := dw.db.GetState(common.BytesToAddress(addr), common.BytesToHash(hash)) + + ptr := ctx.PushFixedBuffer(len(state)) + copy(makeSlice(ptr, uint(len(state))), state[:]) + return 1 + }) + vm.PutPropString(obj, "getState") + + // Push the wrapper for statedb.Exists + vm.PushGoFunction(func(ctx *duktape.Context) int { + ctx.PushBoolean(dw.db.Exist(common.BytesToAddress(popSlice(ctx)))) + return 1 + }) + vm.PutPropString(obj, "exists") +} + +// contractWrapper provides a JavaScript wrapper around vm.Contract +type contractWrapper struct { + contract *vm.Contract +} + +// pushObject assembles a JSVM object wrapping a swappable contract and pushes it +// onto the VM stack. +func (cw *contractWrapper) pushObject(vm *duktape.Context) { + obj := vm.PushObject() + + // Push the wrapper for contract.Caller + vm.PushGoFunction(func(ctx *duktape.Context) int { + ptr := ctx.PushFixedBuffer(20) + copy(makeSlice(ptr, 20), cw.contract.Caller().Bytes()) + return 1 + }) + vm.PutPropString(obj, "getCaller") + + // Push the wrapper for contract.Address + vm.PushGoFunction(func(ctx *duktape.Context) int { + ptr := ctx.PushFixedBuffer(20) + copy(makeSlice(ptr, 20), cw.contract.Address().Bytes()) + return 1 + }) + vm.PutPropString(obj, "getAddress") + + // Push the wrapper for contract.Value + vm.PushGoFunction(func(ctx *duktape.Context) int { + pushBigInt(cw.contract.Value(), ctx) + return 1 + }) + vm.PutPropString(obj, "getValue") + + // Push the wrapper for contract.Input + vm.PushGoFunction(func(ctx *duktape.Context) int { + blob := cw.contract.Input + + ptr := ctx.PushFixedBuffer(len(blob)) + copy(makeSlice(ptr, uint(len(blob))), blob) + return 1 + }) + vm.PutPropString(obj, "getInput") +} + +type frame struct { + typ *string + from *common.Address + to *common.Address + input []byte + gas *uint + value *big.Int +} + +func newFrame() *frame { + return &frame{ + typ: new(string), + from: new(common.Address), + to: new(common.Address), + gas: new(uint), + } +} + +func (f *frame) pushObject(vm *duktape.Context) { + obj := vm.PushObject() + + vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.typ); return 1 }) + vm.PutPropString(obj, "getType") + + vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.from); return 1 }) + vm.PutPropString(obj, "getFrom") + + vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.to); return 1 }) + vm.PutPropString(obj, "getTo") + + vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, f.input); return 1 }) + vm.PutPropString(obj, "getInput") + + vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.gas); return 1 }) + vm.PutPropString(obj, "getGas") + + vm.PushGoFunction(func(ctx *duktape.Context) int { + if f.value != nil { + pushValue(ctx, f.value) + } else { + ctx.PushUndefined() + } + return 1 + }) + vm.PutPropString(obj, "getValue") +} + +type frameResult struct { + gasUsed *uint + output []byte + errorValue *string +} + +func newFrameResult() *frameResult { + return &frameResult{ + gasUsed: new(uint), + } +} + +func (r *frameResult) pushObject(vm *duktape.Context) { + obj := vm.PushObject() + + vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *r.gasUsed); return 1 }) + vm.PutPropString(obj, "getGasUsed") + + vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, r.output); return 1 }) + vm.PutPropString(obj, "getOutput") + + vm.PushGoFunction(func(ctx *duktape.Context) int { + if r.errorValue != nil { + pushValue(ctx, *r.errorValue) + } else { + ctx.PushUndefined() + } + return 1 + }) + vm.PutPropString(obj, "getError") +} + +// jsTracer provides an implementation of Tracer that evaluates a Javascript +// function for each VM execution step. +type jsTracer struct { + vm *duktape.Context // Javascript VM instance + env *vm.EVM // EVM instance executing the code being traced + + tracerObject int // Stack index of the tracer JavaScript object + stateObject int // Stack index of the global state to pull arguments from + + opWrapper *opWrapper // Wrapper around the VM opcode + stackWrapper *stackWrapper // Wrapper around the VM stack + memoryWrapper *memoryWrapper // Wrapper around the VM memory + contractWrapper *contractWrapper // Wrapper around the contract object + dbWrapper *dbWrapper // Wrapper around the VM environment + + pcValue *uint // Swappable pc value wrapped by a log accessor + gasValue *uint // Swappable gas value wrapped by a log accessor + costValue *uint // Swappable cost value wrapped by a log accessor + depthValue *uint // Swappable depth value wrapped by a log accessor + errorValue *string // Swappable error value wrapped by a log accessor + refundValue *uint // Swappable refund value wrapped by a log accessor + + frame *frame // Represents entry into call frame. Fields are swappable + frameResult *frameResult // Represents exit from a call frame. Fields are swappable + + ctx map[string]interface{} // Transaction context gathered throughout execution + err error // Error, if one has occurred + + interrupt uint32 // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption + + activePrecompiles []common.Address // Updated on CaptureStart based on given rules + traceSteps bool // When true, will invoke step() on each opcode + traceCallFrames bool // When true, will invoke enter() and exit() js funcs +} + +// New instantiates a new tracer instance. code specifies a Javascript snippet, +// which must evaluate to an expression returning an object with 'step', 'fault' +// and 'result' functions. +func newJsTracer(code string, ctx *tracers2.Context) (tracers2.Tracer, error) { + if c, ok := assetTracers[code]; ok { + code = c + } + if ctx == nil { + ctx = new(tracers2.Context) + } + tracer := &jsTracer{ + vm: duktape.New(), + ctx: make(map[string]interface{}), + opWrapper: new(opWrapper), + stackWrapper: new(stackWrapper), + memoryWrapper: new(memoryWrapper), + contractWrapper: new(contractWrapper), + dbWrapper: new(dbWrapper), + pcValue: new(uint), + gasValue: new(uint), + costValue: new(uint), + depthValue: new(uint), + refundValue: new(uint), + frame: newFrame(), + frameResult: newFrameResult(), + } + if ctx.BlockHash != (common.Hash{}) { + tracer.ctx["blockHash"] = ctx.BlockHash + + if ctx.TxHash != (common.Hash{}) { + tracer.ctx["txIndex"] = ctx.TxIndex + tracer.ctx["txHash"] = ctx.TxHash + } + } + // Set up builtins for this environment + tracer.vm.PushGlobalGoFunction("toHex", func(ctx *duktape.Context) int { + ctx.PushString(hexutil.Encode(popSlice(ctx))) + return 1 + }) + tracer.vm.PushGlobalGoFunction("toWord", func(ctx *duktape.Context) int { + var word common.Hash + if ptr, size := ctx.GetBuffer(-1); ptr != nil { + word = common.BytesToHash(makeSlice(ptr, size)) + } else { + word = common.HexToHash(ctx.GetString(-1)) + } + ctx.Pop() + copy(makeSlice(ctx.PushFixedBuffer(32), 32), word[:]) + return 1 + }) + tracer.vm.PushGlobalGoFunction("toAddress", func(ctx *duktape.Context) int { + var addr common.Address + if ptr, size := ctx.GetBuffer(-1); ptr != nil { + addr = common.BytesToAddress(makeSlice(ptr, size)) + } else { + addr = common.HexToAddress(ctx.GetString(-1)) + } + ctx.Pop() + copy(makeSlice(ctx.PushFixedBuffer(20), 20), addr[:]) + return 1 + }) + tracer.vm.PushGlobalGoFunction("toContract", func(ctx *duktape.Context) int { + var from common.Address + if ptr, size := ctx.GetBuffer(-2); ptr != nil { + from = common.BytesToAddress(makeSlice(ptr, size)) + } else { + from = common.HexToAddress(ctx.GetString(-2)) + } + nonce := uint64(ctx.GetInt(-1)) + ctx.Pop2() + + contract := crypto.CreateAddress(from, nonce) + copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) + return 1 + }) + tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int { + var from common.Address + if ptr, size := ctx.GetBuffer(-3); ptr != nil { + from = common.BytesToAddress(makeSlice(ptr, size)) + } else { + from = common.HexToAddress(ctx.GetString(-3)) + } + // Retrieve salt hex string from js stack + salt := common.HexToHash(ctx.GetString(-2)) + // Retrieve code slice from js stack + var code []byte + if ptr, size := ctx.GetBuffer(-1); ptr != nil { + code = common.CopyBytes(makeSlice(ptr, size)) + } else { + code = common.FromHex(ctx.GetString(-1)) + } + codeHash := crypto.Keccak256(code) + ctx.Pop3() + contract := crypto.CreateAddress2(from, salt, codeHash) + copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) + return 1 + }) + tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int { + addr := common.BytesToAddress(popSlice(ctx)) + for _, p := range tracer.activePrecompiles { + if p == addr { + ctx.PushBoolean(true) + return 1 + } + } + ctx.PushBoolean(false) + return 1 + }) + tracer.vm.PushGlobalGoFunction("slice", func(ctx *duktape.Context) int { + start, end := ctx.GetInt(-2), ctx.GetInt(-1) + ctx.Pop2() + + blob := popSlice(ctx) + size := end - start + + if start < 0 || start > end || end > len(blob) { + // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go + // runtime goes belly up https://github.com/golang/go/issues/15639. + log.Warn("Tracer accessed out of bound memory", "available", len(blob), "offset", start, "size", size) + ctx.PushFixedBuffer(0) + return 1 + } + copy(makeSlice(ctx.PushFixedBuffer(size), uint(size)), blob[start:end]) + return 1 + }) + // Push the JavaScript tracer as object #0 onto the JSVM stack and validate it + if err := tracer.vm.PevalString("(" + code + ")"); err != nil { + log.Warn("Failed to compile tracer", "err", err) + return nil, err + } + tracer.tracerObject = 0 // yeah, nice, eval can't return the index itself + + hasStep := tracer.vm.GetPropString(tracer.tracerObject, "step") + tracer.vm.Pop() + + if !tracer.vm.GetPropString(tracer.tracerObject, "fault") { + return nil, fmt.Errorf("trace object must expose a function fault()") + } + tracer.vm.Pop() + + if !tracer.vm.GetPropString(tracer.tracerObject, "result") { + return nil, fmt.Errorf("trace object must expose a function result()") + } + tracer.vm.Pop() + + hasEnter := tracer.vm.GetPropString(tracer.tracerObject, "enter") + tracer.vm.Pop() + hasExit := tracer.vm.GetPropString(tracer.tracerObject, "exit") + tracer.vm.Pop() + if hasEnter != hasExit { + return nil, fmt.Errorf("trace object must expose either both or none of enter() and exit()") + } + tracer.traceCallFrames = hasEnter && hasExit + tracer.traceSteps = hasStep + + // Tracer is valid, inject the big int library to access large numbers + tracer.vm.EvalString(bigIntegerJS) + tracer.vm.PutGlobalString("bigInt") + + // Push the global environment state as object #1 into the JSVM stack + tracer.stateObject = tracer.vm.PushObject() + + logObject := tracer.vm.PushObject() + + tracer.opWrapper.pushObject(tracer.vm) + tracer.vm.PutPropString(logObject, "op") + + tracer.stackWrapper.pushObject(tracer.vm) + tracer.vm.PutPropString(logObject, "stack") + + tracer.memoryWrapper.pushObject(tracer.vm) + tracer.vm.PutPropString(logObject, "memory") + + tracer.contractWrapper.pushObject(tracer.vm) + tracer.vm.PutPropString(logObject, "contract") + + tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.pcValue); return 1 }) + tracer.vm.PutPropString(logObject, "getPC") + + tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.gasValue); return 1 }) + tracer.vm.PutPropString(logObject, "getGas") + + tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.costValue); return 1 }) + tracer.vm.PutPropString(logObject, "getCost") + + tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.depthValue); return 1 }) + tracer.vm.PutPropString(logObject, "getDepth") + + tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.refundValue); return 1 }) + tracer.vm.PutPropString(logObject, "getRefund") + + tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { + if tracer.errorValue != nil { + ctx.PushString(*tracer.errorValue) + } else { + ctx.PushUndefined() + } + return 1 + }) + tracer.vm.PutPropString(logObject, "getError") + + tracer.vm.PutPropString(tracer.stateObject, "log") + + tracer.frame.pushObject(tracer.vm) + tracer.vm.PutPropString(tracer.stateObject, "frame") + + tracer.frameResult.pushObject(tracer.vm) + tracer.vm.PutPropString(tracer.stateObject, "frameResult") + + tracer.dbWrapper.pushObject(tracer.vm) + tracer.vm.PutPropString(tracer.stateObject, "db") + + return tracer, nil +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (jst *jsTracer) Stop(err error) { + jst.reason = err + atomic.StoreUint32(&jst.interrupt, 1) +} + +// call executes a method on a JS object, catching any errors, formatting and +// returning them as error objects. +func (jst *jsTracer) call(noret bool, method string, args ...string) (json.RawMessage, error) { + // Execute the JavaScript call and return any error + jst.vm.PushString(method) + for _, arg := range args { + jst.vm.GetPropString(jst.stateObject, arg) + } + code := jst.vm.PcallProp(jst.tracerObject, len(args)) + defer jst.vm.Pop() + + if code != 0 { + err := jst.vm.SafeToString(-1) + return nil, errors.New(err) + } + // No error occurred, extract return value and return + if noret { + return nil, nil + } + // Push a JSON marshaller onto the stack. We can't marshal from the out- + // side because duktape can crash on large nestings and we can't catch + // C++ exceptions ourselves from Go. TODO(karalabe): Yuck, why wrap?! + jst.vm.PushString("(JSON.stringify)") + jst.vm.Eval() + + jst.vm.Swap(-1, -2) + if code = jst.vm.Pcall(1); code != 0 { + err := jst.vm.SafeToString(-1) + return nil, errors.New(err) + } + return json.RawMessage(jst.vm.SafeToString(-1)), nil +} + +func wrapError(context string, err error) error { + return fmt.Errorf("%v in server-side tracer function '%v'", err, context) +} + +// CaptureStart implements the Tracer interface to initialize the tracing operation. +func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + jst.env = env + jst.ctx["type"] = "CALL" + if create { + jst.ctx["type"] = "CREATE" + } + jst.ctx["from"] = from + jst.ctx["to"] = to + jst.ctx["input"] = input + jst.ctx["gas"] = gas + jst.ctx["gasPrice"] = env.TxContext.GasPrice + jst.ctx["value"] = value + + // Initialize the context + jst.ctx["block"] = env.Context.BlockNumber.Uint64() + jst.dbWrapper.db = env.StateDB + // Update list of precompiles based on current block + rules := env.ChainConfig().Rules(env.Context.BlockNumber) + jst.activePrecompiles = vm.ActivePrecompiles(rules) + + // Compute intrinsic gas + isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) + isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) + intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul) + if err != nil { + return + } + jst.ctx["intrinsicGas"] = intrinsicGas +} + +// CaptureState implements the Tracer interface to trace a single step of VM execution. +func (jst *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + if !jst.traceSteps { + return + } + if jst.err != nil { + return + } + // If tracing was interrupted, set the error and stop + if atomic.LoadUint32(&jst.interrupt) > 0 { + jst.err = jst.reason + jst.env.Cancel() + return + } + jst.opWrapper.op = op + jst.stackWrapper.stack = scope.Stack + jst.memoryWrapper.memory = scope.Memory + jst.contractWrapper.contract = scope.Contract + + *jst.pcValue = uint(pc) + *jst.gasValue = uint(gas) + *jst.costValue = uint(cost) + *jst.depthValue = uint(depth) + *jst.refundValue = uint(jst.env.StateDB.GetRefund()) + + jst.errorValue = nil + if err != nil { + jst.errorValue = new(string) + *jst.errorValue = err.Error() + } + + if _, err := jst.call(true, "step", "log", "db"); err != nil { + jst.err = wrapError("step", err) + } +} + +// CaptureFault implements the Tracer interface to trace an execution fault +func (jst *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { + if jst.err != nil { + return + } + // Apart from the error, everything matches the previous invocation + jst.errorValue = new(string) + *jst.errorValue = err.Error() + + if _, err := jst.call(true, "fault", "log", "db"); err != nil { + jst.err = wrapError("fault", err) + } +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (jst *jsTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) { + jst.ctx["output"] = output + jst.ctx["time"] = t.String() + jst.ctx["gasUsed"] = gasUsed + + if err != nil { + jst.ctx["error"] = err.Error() + } +} + +// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (jst *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if !jst.traceCallFrames { + return + } + if jst.err != nil { + return + } + // If tracing was interrupted, set the error and stop + if atomic.LoadUint32(&jst.interrupt) > 0 { + jst.err = jst.reason + return + } + + *jst.frame.typ = typ.String() + *jst.frame.from = from + *jst.frame.to = to + jst.frame.input = common.CopyBytes(input) + *jst.frame.gas = uint(gas) + jst.frame.value = nil + if value != nil { + jst.frame.value = new(big.Int).SetBytes(value.Bytes()) + } + + if _, err := jst.call(true, "enter", "frame"); err != nil { + jst.err = wrapError("enter", err) + } +} + +// CaptureExit is called when EVM exits a scope, even if the scope didn't +// execute any code. +func (jst *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) { + if !jst.traceCallFrames { + return + } + // If tracing was interrupted, set the error and stop + if atomic.LoadUint32(&jst.interrupt) > 0 { + jst.err = jst.reason + return + } + + jst.frameResult.output = common.CopyBytes(output) + *jst.frameResult.gasUsed = uint(gasUsed) + jst.frameResult.errorValue = nil + if err != nil { + jst.frameResult.errorValue = new(string) + *jst.frameResult.errorValue = err.Error() + } + + if _, err := jst.call(true, "exit", "frameResult"); err != nil { + jst.err = wrapError("exit", err) + } +} + +// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error +func (jst *jsTracer) GetResult() (json.RawMessage, error) { + // Transform the context into a JavaScript object and inject into the state + obj := jst.vm.PushObject() + + for key, val := range jst.ctx { + jst.addToObj(obj, key, val) + } + jst.vm.PutPropString(jst.stateObject, "ctx") + + // Finalize the trace and return the results + result, err := jst.call(false, "result", "ctx", "db") + if err != nil { + jst.err = wrapError("result", err) + } + // Clean up the JavaScript environment + jst.vm.DestroyHeap() + jst.vm.Destroy() + + return result, jst.err +} + +// addToObj pushes a field to a JS object. +func (jst *jsTracer) addToObj(obj int, key string, val interface{}) { + pushValue(jst.vm, val) + jst.vm.PutPropString(obj, key) +} + +func pushValue(ctx *duktape.Context, val interface{}) { + switch val := val.(type) { + case uint64: + ctx.PushUint(uint(val)) + case string: + ctx.PushString(val) + case []byte: + ptr := ctx.PushFixedBuffer(len(val)) + copy(makeSlice(ptr, uint(len(val))), val) + case common.Address: + ptr := ctx.PushFixedBuffer(20) + copy(makeSlice(ptr, 20), val[:]) + case *big.Int: + pushBigInt(val, ctx) + case int: + ctx.PushInt(val) + case uint: + ctx.PushUint(val) + case common.Hash: + ptr := ctx.PushFixedBuffer(32) + copy(makeSlice(ptr, 32), val[:]) + default: + panic(fmt.Sprintf("unsupported type: %T", val)) + } +} diff --git a/eth/tracers/tracer_test.go b/eth/tracers/js/tracer_test.go similarity index 51% rename from eth/tracers/tracer_test.go rename to eth/tracers/js/tracer_test.go index 7cda2e5330..2253ae597c 100644 --- a/eth/tracers/tracer_test.go +++ b/eth/tracers/js/tracer_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 tracers +package js import ( "encoding/json" @@ -26,6 +26,7 @@ import ( "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" "github.com/ethereum/go-ethereum/params" ) @@ -59,13 +60,13 @@ func testCtx() *vmContext { return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} } -func runTrace(tracer *Tracer, vmctx *vmContext) (json.RawMessage, error) { - env := vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) +func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig) (json.RawMessage, error) { var ( + env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Debug: true, Tracer: tracer}) startGas uint64 = 10000 value = big.NewInt(0) + contract = vm.NewContract(account{}, account{}, value, startGas) ) - contract := vm.NewContract(account{}, account{}, value, startGas) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value) @@ -78,22 +79,22 @@ func runTrace(tracer *Tracer, vmctx *vmContext) (json.RawMessage, error) { } func TestTracer(t *testing.T) { - execTracer := func(code string) []byte { + execTracer := func(code string) ([]byte, string) { t.Helper() - ctx := &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} - tracer, err := New(code, ctx.txCtx) + tracer, err := newJsTracer(code, nil) if err != nil { t.Fatal(err) } - ret, err := runTrace(tracer, ctx) + ret, err := runTrace(tracer, testCtx(), params.TestChainConfig) if err != nil { - t.Fatal(err) + return nil, err.Error() // Stringify to allow comparison without nil checks } - return ret + return ret, "" } for i, tt := range []struct { code string want string + fail string }{ { // 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; }}", @@ -116,49 +117,47 @@ func TestTracer(t *testing.T) { }, { // tests intrinsic gas code: "{depths: [], step: function() {}, fault: function() {}, result: function(ctx) { return ctx.gasPrice+'.'+ctx.gasUsed+'.'+ctx.intrinsicGas; }}", want: `"100000.6.21000"`, + }, { // tests too deep object / serialization crash + code: "{step: function() {}, fault: function() {}, result: function() { var o={}; var x=o; for (var i=0; i<1000; i++){ o.foo={}; o=o.foo; } return x; }}", + fail: "RangeError: json encode recursion limit in server-side tracer function 'result'", }, } { - if have := execTracer(tt.code); tt.want != string(have) { - t.Errorf("testcase %d: expected return value to be %s got %s\n\tcode: %v", i, tt.want, string(have), tt.code) + if have, err := execTracer(tt.code); 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) } } } func TestHalt(t *testing.T) { t.Skip("duktape doesn't support abortion") - timeout := errors.New("stahp") - vmctx := testCtx() - tracer, err := New("{step: function() { while(1); }, result: function() { return null; }}", vmctx.txCtx) + tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil) if err != nil { t.Fatal(err) } - go func() { time.Sleep(1 * time.Second) tracer.Stop(timeout) }() - - if _, err = runTrace(tracer, vmctx); err.Error() != "stahp in server-side tracer function 'step'" { + if _, err = runTrace(tracer, testCtx(), params.TestChainConfig); err.Error() != "stahp in server-side tracer function 'step'" { t.Errorf("Expected timeout error, got %v", err) } } func TestHaltBetweenSteps(t *testing.T) { - vmctx := testCtx() - tracer, err := New("{step: function() {}, fault: function() {}, result: function() { return null; }}", vmctx.txCtx) + tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil) if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{}, &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{Debug: true, Tracer: tracer}) scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } - - tracer.CaptureState(env, 0, 0, 0, 0, scope, nil, 0, nil) + tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0)) + tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil) timeout := errors.New("stahp") tracer.Stop(timeout) - tracer.CaptureState(env, 0, 0, 0, 0, scope, nil, 0, nil) + tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil) if _, err := tracer.GetResult(); err.Error() != timeout.Error() { t.Errorf("Expected timeout error, got %v", err) @@ -168,22 +167,16 @@ func TestHaltBetweenSteps(t *testing.T) { // TestNoStepExec tests a regular value transfer (no exec), and accessing the statedb // in 'result' func TestNoStepExec(t *testing.T) { - runEmptyTrace := func(tracer *Tracer, vmctx *vmContext) (json.RawMessage, error) { - env := vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) - startGas := uint64(10000) - contract := vm.NewContract(account{}, account{}, big.NewInt(0), startGas) - tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, big.NewInt(0)) - tracer.CaptureEnd(nil, startGas-contract.Gas, 1, nil) - return tracer.GetResult() - } execTracer := func(code string) []byte { t.Helper() - ctx := &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} - tracer, err := New(code, ctx.txCtx) + tracer, err := newJsTracer(code, nil) if err != nil { t.Fatal(err) } - ret, err := runEmptyTrace(tracer, ctx) + 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) + ret, err := tracer.GetResult() if err != nil { t.Fatal(err) } @@ -203,3 +196,63 @@ 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), CatalystBlock: nil, Ethash: new(params.EthashConfig), Clique: nil} + chaincfg.ByzantiumBlock = big.NewInt(100) + 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) + if err != nil { + t.Fatal(err) + } + + blockCtx := vm.BlockContext{BlockNumber: big.NewInt(150)} + res, err := runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg) + if err != nil { + t.Error(err) + } + if string(res) != "false" { + 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) + blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)} + res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg) + if err != nil { + t.Error(err) + } + if string(res) != "true" { + t.Errorf("Tracer should consider blake2f as precompile in istanbul") + } +} + +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 { + 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 { + 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)) + if err != nil { + t.Fatal(err) + } + scope := &vm.ScopeContext{ + Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), + } + tracer.CaptureEnter(vm.CALL, scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) + tracer.CaptureExit([]byte{}, 400, nil) + + have, err := tracer.GetResult() + if err != nil { + t.Fatal(err) + } + want := `{"enters":1,"exits":1,"enterGas":1000,"gasUsed":400}` + if string(have) != want { + t.Errorf("Number of invocations of enter() and exit() is wrong. Have %s, want %s\n", have, want) + } +} diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go new file mode 100644 index 0000000000..16ea75aa4a --- /dev/null +++ b/eth/tracers/native/call.go @@ -0,0 +1,182 @@ +// 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 + +import ( + "encoding/json" + "errors" + "math/big" + "strconv" + "strings" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" +) + +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 callTracer struct { + env *vm.EVM + callstack []callFrame + interrupt uint32 // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption +} + +// newCallTracer returns a native go tracer which tracks +// call frames of a tx, and implements vm.EVMLogger. +func newCallTracer() tracers.Tracer { + // First callframe contains tx context info + // and is populated on start and end. + t := &callTracer{callstack: make([]callFrame, 1)} + return t +} + +// 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: "CALL", + From: addrToHex(from), + To: addrToHex(to), + Input: bytesToHex(input), + Gas: uintToHex(gas), + Value: bigToHex(value), + } + if create { + t.callstack[0].Type = "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) + if err != nil { + t.callstack[0].Error = err.Error() + if err.Error() == "execution reverted" && len(output) > 0 { + t.callstack[0].Output = bytesToHex(output) + } + } else { + t.callstack[0].Output = bytesToHex(output) + } +} + +// 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) { +} + +// 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) { +} + +// 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) { + // Skip if tracing was interrupted + if atomic.LoadUint32(&t.interrupt) > 0 { + t.env.Cancel() + return + } + + call := callFrame{ + Type: typ.String(), + From: addrToHex(from), + To: addrToHex(to), + Input: bytesToHex(input), + Gas: uintToHex(gas), + Value: bigToHex(value), + } + t.callstack = append(t.callstack, call) +} + +// 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) { + size := len(t.callstack) + if size <= 1 { + return + } + // pop call + call := t.callstack[size-1] + t.callstack = t.callstack[:size-1] + size -= 1 + + call.GasUsed = uintToHex(gasUsed) + if err == nil { + call.Output = bytesToHex(output) + } else { + call.Error = err.Error() + if call.Type == "CREATE" || call.Type == "CREATE2" { + call.To = "" + } + } + t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) +} + +// GetResult returns the json-encoded nested list of call traces, and any +// error arising from the encoding or forceful termination (via `Stop`). +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 + } + return json.RawMessage(res), t.reason +} + +// 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) +} + +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/noop.go b/eth/tracers/native/noop.go new file mode 100644 index 0000000000..ee110ef7df --- /dev/null +++ b/eth/tracers/native/noop.go @@ -0,0 +1,74 @@ +// 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 + +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("noopTracerNative", newNoopTracer) +} + +// noopTracer is a go implementation of the Tracer interface which +// performs no action. It's mostly useful for testing purposes. +type noopTracer struct{} + +// newNoopTracer returns a new noop tracer. +func newNoopTracer() tracers.Tracer { + return &noopTracer{} +} + +// CaptureStart implements the EVMLogger interface to initialize the tracing operation. +func (t *noopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { +} + +// CaptureState implements the EVMLogger interface to trace a single step of VM execution. +func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +} + +// CaptureFault implements the EVMLogger interface to trace an execution fault. +func (t *noopTracer) 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 *noopTracer) 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 *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { +} + +// GetResult returns an empty json object. +func (t *noopTracer) GetResult() (json.RawMessage, error) { + return json.RawMessage(`{}`), nil +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *noopTracer) Stop(err error) { +} diff --git a/eth/tracers/native/tracer.go b/eth/tracers/native/tracer.go new file mode 100644 index 0000000000..3158654f33 --- /dev/null +++ b/eth/tracers/native/tracer.go @@ -0,0 +1,79 @@ +// 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 ( + "errors" + + "github.com/ethereum/go-ethereum/eth/tracers" +) + +// init registers itself this packages as a lookup for tracers. +func init() { + tracers.RegisterLookup(false, lookup) +} + +/* +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]func() tracers.Tracer + +// register is used by native tracers to register their presence. +func register(name string, ctor func() tracers.Tracer) { + if ctors == nil { + ctors = make(map[string]func() tracers.Tracer) + } + ctors[name] = ctor +} + +// lookup returns a tracer, if one can be matched to the given name. +func lookup(name string, ctx *tracers.Context) (tracers.Tracer, error) { + if ctors == nil { + ctors = make(map[string]func() tracers.Tracer) + } + if ctor, ok := ctors[name]; ok { + return ctor(), nil + } + return nil, errors.New("no tracer found") +} diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index 4e1ef23ad2..e7073e7d2e 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -14,40 +14,59 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package tracers is a collection of JavaScript transaction tracers. +// Package tracers is a manager for transaction tracing engines. package tracers import ( - "strings" - "unicode" + "encoding/json" + "errors" - "github.com/ethereum/go-ethereum/eth/tracers/internal/tracers" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" ) -// all contains all the built in JavaScript tracers by name. -var all = make(map[string]string) +// 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) +} -// 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, "") +// Tracer interface extends vm.EVMLogger and additionally +// allows collecting the tracing result. +type Tracer interface { + vm.EVMLogger + GetResult() (json.RawMessage, error) + // Stop terminates execution of the tracer at the first opportune moment. + Stop(err error) } -// init retrieves the JavaScript transaction tracers included in go-ethereum. -func init() { - for _, file := range tracers.AssetNames() { - name := camel(strings.TrimSuffix(file, ".js")) - all[name] = string(tracers.MustAsset(file)) +type lookupFunc func(string, *Context) (Tracer, error) + +var ( + lookups []lookupFunc +) + +// 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...) } } -// tracer retrieves a specific JavaScript tracer by name. -func tracer(name string) (string, bool) { - if tracer, ok := all[name]; ok { - return tracer, true +// New returns a new instance of a tracer, by iterating through the +// registered lookups. +func New(code string, ctx *Context) (Tracer, error) { + for _, lookup := range lookups { + if tracer, err := lookup(code, ctx); err == nil { + return tracer, nil + } } - return "", false + return nil, errors.New("tracer not found") } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 0bc4cd81e6..a3f5fc361d 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -17,79 +17,20 @@ package tracers import ( - "crypto/ecdsa" - "crypto/rand" - "encoding/json" - "io/ioutil" "math/big" - "path/filepath" - "reflect" - "strings" "testing" "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/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/params" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" ) -// 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)); -} -*/ - // callTrace is the result of a callTracer run. type callTrace struct { Type string `json:"type"` @@ -104,203 +45,6 @@ type callTrace struct { Calls []callTrace `json:"calls,omitempty"` } -type callContext struct { - Number math.HexOrDecimal64 `json:"number"` - Difficulty *math.HexOrDecimal256 `json:"difficulty"` - Time math.HexOrDecimal64 `json:"timestamp"` - GasLimit math.HexOrDecimal64 `json:"gasLimit"` - Miner common.Address `json:"miner"` -} - -// 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"` -} - -func TestPrestateTracerCreate2(t *testing.T) { - unsignedTx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"), - new(big.Int), 5000000, big.NewInt(1), []byte{}) - - privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) - if err != nil { - t.Fatalf("err %v", err) - } - signer := types.NewEIP155Signer(big.NewInt(1)) - tx, err := types.SignTx(unsignedTx, signer, privateKeyECDSA) - if err != nil { - t.Fatalf("err %v", err) - } - /** - This comes from one of the test-vectors on the Skinny Create2 - EIP - - address 0x00000000000000000000000000000000deadbeef - salt 0x00000000000000000000000000000000000000000000000000000000cafebabe - init_code 0xdeadbeef - gas (assuming no mem expansion): 32006 - result: 0x60f3f640a8508fC6a86d45DF051962668E1e8AC7 - */ - 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: new(big.Int).SetUint64(5), - Difficulty: big.NewInt(0x30000), - GasLimit: uint64(6000000), - } - alloc := core.GenesisAlloc{} - - // The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns - // the address - alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{ - Nonce: 1, - Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"), - Balance: big.NewInt(1), - } - alloc[origin] = core.GenesisAccount{ - Nonce: 1, - Code: []byte{}, - Balance: big.NewInt(500000000000000), - } - _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) - - // Create the tracer, the EVM environment and run it - tracer, err := New("prestateTracer", txContext) - 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 := tx.AsMessage(signer) - 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 := make(map[string]interface{}) - if err := json.Unmarshal(res, &ret); err != nil { - t.Fatalf("failed to unmarshal trace result: %v", err) - } - if _, has := ret["0x60f3f640a8508fc6a86d45df051962668e1e8ac7"]; !has { - t.Fatalf("Expected 0x60f3f640a8508fc6a86d45df051962668e1e8ac7 in result") - } -} - -// Iterates over all the input-output datasets in the tracer test harness and -// runs the JavaScript tracers against them. -func TestCallTracer(t *testing.T) { - files, err := ioutil.ReadDir("testdata") - if err != nil { - t.Fatalf("failed to retrieve tracer test suite: %v", err) - } - for _, file := range files { - if !strings.HasPrefix(file.Name(), "call_tracer_") { - continue - } - file := file // capture range variable - t.Run(camel(strings.TrimSuffix(strings.TrimPrefix(file.Name(), "call_tracer_"), ".json")), func(t *testing.T) { - t.Parallel() - - // Call tracer test found, read if from disk - blob, err := ioutil.ReadFile(filepath.Join("testdata", file.Name())) - if err != nil { - t.Fatalf("failed to read testcase: %v", err) - } - test := new(callTracerTest) - if err := json.Unmarshal(blob, test); err != nil { - t.Fatalf("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 { - t.Fatalf("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: 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) - - // Create the tracer, the EVM environment and run it - tracer, err := New("callTracer", txContext) - 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) - 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 := new(callTrace) - if err := json.Unmarshal(res, ret); err != nil { - t.Fatalf("failed to unmarshal trace result: %v", err) - } - - if !jsonEqual(ret, test.Result) { - // 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) - } - }) - } -} - -// 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) -} - func BenchmarkTransactionTrace(b *testing.B) { key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") from := crypto.PubkeyToAddress(key.PublicKey) @@ -353,8 +97,8 @@ func BenchmarkTransactionTrace(b *testing.B) { tracer := vm.NewStructLogger(&vm.LogConfig{ Debug: false, //DisableStorage: true, - //DisableMemory: true, - //DisableReturnData: true, + //EnableMemory: false, + //EnableReturnData: false, }) evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer}) msg, err := tx.AsMessage(signer) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 1934412c90..2975720b8a 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -419,6 +419,12 @@ web3._extend({ params: 2, inputFormatter: [null, null] }), + new web3._extend.Method({ + name: 'intermediateRoots', + call: 'debug_intermediateRoots', + params: 2, + inputFormatter: [null, null] + }), new web3._extend.Method({ name: 'standardTraceBlockToFile', call: 'debug_standardTraceBlockToFile', diff --git a/les/api_backend.go b/les/api_backend.go index c8eca2d905..243a0ac811 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -305,7 +305,7 @@ 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) (*state.StateDB, error) { +func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error) { return b.eth.stateAtBlock(ctx, block, reexec) } diff --git a/tests/state_test.go b/tests/state_test.go index c1d9f6a0dc..bb80a162aa 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -105,7 +105,7 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { } buf := new(bytes.Buffer) w := bufio.NewWriter(buf) - tracer := vm.NewJSONLogger(&vm.LogConfig{DisableMemory: true}, w) + tracer := vm.NewJSONLogger(&vm.LogConfig{}, w) config.Debug, config.Tracer = true, tracer err2 := test(config) if !errors.Is(err, err2) { From c78ecfbb4b5d53004929a1e02e6122e84a647851 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Tue, 11 Jan 2022 13:55:30 +0800 Subject: [PATCH 075/117] [R4R]prefetch state by applying the transactions within one block (#704) * prefetch state by apply transactions within one block * resolve comments * stop prefetch once process is done * update comments fix ut --- core/blockchain.go | 21 +++++++--- core/blockchain_diff_test.go | 2 +- core/state_prefetcher.go | 77 ++++++++++++++++++++++-------------- core/state_processor.go | 1 - 4 files changed, 65 insertions(+), 36 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 4a7cdf9a54..6aa5916218 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -90,6 +90,7 @@ const ( maxFutureBlocks = 256 maxTimeFutureBlocks = 30 maxBeyondBlocks = 2048 + prefetchTxNumber = 100 diffLayerFreezerRecheckInterval = 3 * time.Second diffLayerPruneRecheckInterval = 1 * time.Second // The interval to prune unverified diff layers @@ -233,10 +234,11 @@ type BlockChain struct { running int32 // 0 if chain is running, 1 when stopped procInterrupt int32 // interrupt signaler for block processing - engine consensus.Engine - validator Validator // Block and state validator interface - processor Processor // Block transaction processor interface - vmConfig vm.Config + engine consensus.Engine + prefetcher Prefetcher + validator Validator // Block and state validator interface + processor Processor // Block transaction processor interface + vmConfig vm.Config shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. terminateInsert func(common.Hash, uint64) bool // Testing hook used to terminate ancient receipt chain insertion. @@ -295,6 +297,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par diffNumToBlockHashes: make(map[uint64]map[common.Hash]struct{}), diffPeersToDiffHashes: make(map[string]map[common.Hash]struct{}), } + bc.prefetcher = NewStatePrefetcher(chainConfig, bc, engine) bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.processor = NewStateProcessor(chainConfig, bc, engine) @@ -2051,10 +2054,18 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") - + var followupInterrupt uint32 + // For diff sync, it may fallback to full sync, so we still do prefetch + if len(block.Transactions()) >= prefetchTxNumber { + throwaway := statedb.Copy() + go func(start time.Time, followup *types.Block, throwaway *state.StateDB, interrupt *uint32) { + bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) + }(time.Now(), block, throwaway, &followupInterrupt) + } //Process block using the parent state as reference point substart := time.Now() statedb, receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) + atomic.StoreUint32(&followupInterrupt, 1) activeState = statedb if err != nil { bc.reportBlock(block, receipts, err) diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index facd86b52b..451a966589 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -372,7 +372,7 @@ func TestFreezeDiffLayer(t *testing.T) { t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum-1, fullBackend.chain.diffQueue.Size()) } - time.Sleep(diffLayerFreezerRecheckInterval + 1*time.Second) + time.Sleep(diffLayerFreezerRecheckInterval + 2*time.Second) if fullBackend.chain.diffQueue.Size() != int(fullBackend.chain.triesInMemory) { t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum, fullBackend.chain.diffQueue.Size()) } diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index dacd8df404..ec4e7bf972 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -17,6 +17,7 @@ package core import ( + "runtime" "sync/atomic" "github.com/ethereum/go-ethereum/consensus" @@ -35,42 +36,60 @@ type statePrefetcher struct { engine consensus.Engine // Consensus engine used for block rewards } +// NewStatePrefetcher initialises a new statePrefetcher. +func NewStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *statePrefetcher { + return &statePrefetcher{ + config: config, + bc: bc, + engine: engine, + } +} + // 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. +// only goal is to pre-cache transaction signatures and snapshot clean state. func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) { var ( - header = block.Header() - gaspool = new(GasPool).AddGas(block.GasLimit()) - blockContext = NewEVMBlockContext(header, p.bc, nil) - evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) - signer = types.MakeSigner(p.config, header.Number) + header = block.Header() + signer = types.MakeSigner(p.config, header.Number) ) - // Iterate over and process the individual transactions - 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 { - return - } - // Convert the transaction into an executable message and pre-cache its sender - msg, err := tx.AsMessage(signer) - if err != nil { - return // Also invalid block, bail out - } - statedb.Prepare(tx.Hash(), block.Hash(), i) - if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil { - return // Ugh, something went horribly wrong, bail out - } - // If we're pre-byzantium, pre-load trie nodes for the intermediate root - if !byzantium { - statedb.IntermediateRoot(true) - } + transactions := block.Transactions() + threads := runtime.NumCPU() + batch := len(transactions) / (threads + 1) + if batch == 0 { + return } - // If were post-byzantium, pre-load trie nodes for the final root hash - if byzantium { - statedb.IntermediateRoot(true) + // No need to execute the first batch, since the main processor will do it. + for i := 1; i <= threads; i++ { + start := i * batch + end := (i + 1) * batch + if i == threads { + end = len(transactions) + } + go func(start, end int) { + newStatedb := statedb.Copy() + gaspool := new(GasPool).AddGas(block.GasLimit()) + blockContext := NewEVMBlockContext(header, p.bc, nil) + evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) + // Iterate over and process the individual transactions + for i, tx := range transactions[start:end] { + // If block precaching was interrupted, abort + if interrupt != nil && atomic.LoadUint32(interrupt) == 1 { + return + } + // Convert the transaction into an executable message and pre-cache its sender + msg, err := tx.AsMessage(signer) + if err != nil { + return // Also invalid block, bail out + } + newStatedb.Prepare(tx.Hash(), block.Hash(), i) + if err := precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm); err != nil { + return // Ugh, something went horribly wrong, bail out + } + } + }(start, end) } + } // precacheTransaction attempts to apply a transaction to the given state database diff --git a/core/state_processor.go b/core/state_processor.go index 6ca99f2eec..5652547db7 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -378,7 +378,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg gp = new(GasPool).AddGas(block.GasLimit()) ) signer := types.MakeSigner(p.bc.chainConfig, block.Number()) - statedb.TryPreload(block, signer) var receipts = make([]*types.Receipt, 0) // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { From ebc39330c548d576e4f7fa1cd4a09aa10eb3aa7a Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Fri, 14 Jan 2022 15:44:33 +0800 Subject: [PATCH 076/117] ci: add arm binaries for release pipeline (#713) --- .github/generate_change_log.sh | 8 +++ .github/workflows/pre-release.yml | 105 ++++++++++++++++++++++++++++++ .github/workflows/release.yml | 105 ++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+) diff --git a/.github/generate_change_log.sh b/.github/generate_change_log.sh index ab8ffff689..ea8cee0191 100755 --- a/.github/generate_change_log.sh +++ b/.github/generate_change_log.sh @@ -24,6 +24,10 @@ TESTNET_ZIP_SUM="$(checksum ./testnet.zip)" LINUX_BIN_SUM="$(checksum ./linux/geth)" MAC_BIN_SUM="$(checksum ./macos/geth)" WINDOWS_BIN_SUM="$(checksum ./windows/geth.exe)" +ARM5_BIN_SUM="$(checksum ./arm5/geth-linux-arm-5)" +ARM6_BIN_SUM="$(checksum ./arm6/geth-linux-arm-6)" +ARM7_BIN_SUM="$(checksum ./arm7/geth-linux-arm-7)" +ARM64_BIN_SUM="$(checksum ./arm64/geth-linux-arm64)" OUTPUT=$(cat <<-END ## Changelog\n ${CHANGE_LOG}\n @@ -35,6 +39,10 @@ ${CHANGE_LOG}\n | geth_linux | ${LINUX_BIN_SUM} |\n | geth_mac | ${MAC_BIN_SUM} |\n | geth_windows | ${WINDOWS_BIN_SUM} |\n +| geth_linux_arm5 | ${ARM5_BIN_SUM} |\n +| geth_linux_arm6 | ${ARM6_BIN_SUM} |\n +| geth_linux_arm7 | ${ARM7_BIN_SUM} |\n +| geth_linux_arm64 | ${ARM64_BIN_SUM} |\n END ) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 888fe90096..87583d8b54 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -45,6 +45,19 @@ jobs: - name: Build Binary for ${{matrix.os}} run: make geth + # ============================== + # Cross Compile for ARM + # ============================== + + - name: Build Binary for ARM + if: matrix.os == 'ubuntu-18.04' + env: + GOPATH: /home/runner/work/woodpecker/go + run: | + mkdir -p $GOPATH/src/github.com/binance-chain/bsc/ + cp -r ./* $GOPATH/src/github.com/binance-chain/bsc/ + cd $GOPATH/src/github.com/binance-chain/bsc/ && make geth-linux-arm + # ============================== # Upload artifacts # ============================== @@ -70,6 +83,34 @@ jobs: name: windows path: ./build/bin/geth.exe + - name: Upload ARM-5 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm5 + path: /home/runner/work/woodpecker/go/src/github.com/binance-chain/bsc/build/bin/geth-linux-arm-5 + + - name: Upload ARM-6 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm6 + path: /home/runner/work/woodpecker/go/src/github.com/binance-chain/bsc/build/bin/geth-linux-arm-6 + + - name: Upload ARM-7 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm7 + path: /home/runner/work/woodpecker/go/src/github.com/binance-chain/bsc/build/bin/geth-linux-arm-7 + + - name: Upload ARM-64 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm64 + path: /home/runner/work/woodpecker/go/src/github.com/binance-chain/bsc/build/bin/geth-linux-arm64 + release: name: Release needs: build @@ -102,6 +143,30 @@ jobs: with: name: windows path: ./windows + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm5 + path: ./arm5 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm6 + path: ./arm6 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm7 + path: ./arm7 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm64 + path: ./arm64 - name: Download Config File run: | @@ -161,6 +226,46 @@ jobs: asset_path: ./windows/geth.exe asset_name: geth_windows.exe asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 5 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm5/geth-linux-arm-5 + asset_name: geth-linux-arm-5 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 6 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm6/geth-linux-arm-6 + asset_name: geth-linux-arm-6 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 7 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm7/geth-linux-arm-7 + asset_name: geth-linux-arm-7 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm64/geth-linux-arm64 + asset_name: geth-linux-arm64 + asset_content_type: application/octet-stream - name: Upload Release Asset - MAINNET.ZIP uses: actions/upload-release-asset@v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 77cbbee725..63b49e9772 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,6 +46,19 @@ jobs: - name: Build Binary for ${{matrix.os}} run: make geth + # ============================== + # Cross Compile for ARM + # ============================== + + - name: Build Binary for ARM + if: matrix.os == 'ubuntu-18.04' + env: + GOPATH: /home/runner/work/woodpecker/go + run: | + mkdir -p $GOPATH/src/github.com/binance-chain/bsc/ + cp -r ./* $GOPATH/src/github.com/binance-chain/bsc/ + cd $GOPATH/src/github.com/binance-chain/bsc/ && make geth-linux-arm + # ============================== # Upload artifacts # ============================== @@ -71,6 +84,34 @@ jobs: name: windows path: ./build/bin/geth.exe + - name: Upload ARM-5 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm5 + path: /home/runner/work/woodpecker/go/src/github.com/binance-chain/bsc/build/bin/geth-linux-arm-5 + + - name: Upload ARM-6 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm6 + path: /home/runner/work/woodpecker/go/src/github.com/binance-chain/bsc/build/bin/geth-linux-arm-6 + + - name: Upload ARM-7 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm7 + path: /home/runner/work/woodpecker/go/src/github.com/binance-chain/bsc/build/bin/geth-linux-arm-7 + + - name: Upload ARM-64 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm64 + path: /home/runner/work/woodpecker/go/src/github.com/binance-chain/bsc/build/bin/geth-linux-arm64 + release: name: Release needs: build @@ -104,6 +145,30 @@ jobs: name: windows path: ./windows + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm5 + path: ./arm5 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm6 + path: ./arm6 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm7 + path: ./arm7 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm64 + path: ./arm64 + - name: Download Config File run: | . ./.github/release.env @@ -171,6 +236,46 @@ jobs: asset_name: geth_windows.exe asset_content_type: application/octet-stream + - name: Upload Release Asset - Linux ARM 5 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm5/geth-linux-arm-5 + asset_name: geth-linux-arm-5 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 6 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm6/geth-linux-arm-6 + asset_name: geth-linux-arm-6 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 7 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm7/geth-linux-arm-7 + asset_name: geth-linux-arm-7 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm64/geth-linux-arm64 + asset_name: geth-linux-arm64 + asset_content_type: application/octet-stream + - name: Upload Release Asset - MAINNET.ZIP uses: actions/upload-release-asset@v1 env: From 476d5200f7b41ebfa6e47c6c40f5c721e33318a3 Mon Sep 17 00:00:00 2001 From: John <25290445+Mercybudda@users.noreply.github.com> Date: Wed, 19 Jan 2022 18:07:49 +0800 Subject: [PATCH 077/117] [R4R]offline block prune (#543) * offline block prune * update * update * update and add unit test * addressed comments from walt * Addressed comments from walt and Igor * ensure MPT and snapshot matched * add one more parameter to indicate blockprune * update the logic of creating freezerDb * update flag command description * expose the function for db inspect the offset/startBlockNumber * add flags to inspect prune info * rename flag of reserved-recent-blocks to block-amount-reserved * addressed comments from walt * handle the case of command interruption * refined goimports * addressed comments from walt * change the logic as restarting prune after interruption * addressed comments * reclaimed freezer logic * introduce flag to enable/disable check between MPT and snapshot * update the logic of frozen field in freezerDB * update the code in all places related to freezer change * addressed comments from dylan * update the logic for backup block difficulty * addressed comments from dylan --- .gitignore | 2 + cmd/geth/chaincmd.go | 6 +- cmd/geth/dbcmd.go | 34 +++- cmd/geth/main.go | 2 + cmd/geth/pruneblock_test.go | 242 ++++++++++++++++++++++++ cmd/geth/snapshot.go | 194 ++++++++++++++++++- cmd/geth/usage.go | 2 + cmd/utils/flags.go | 25 ++- core/blockchain.go | 10 +- core/blockchain_repair_test.go | 4 +- core/blockchain_sethead_test.go | 2 +- core/blockchain_snapshot_test.go | 4 +- core/blockchain_test.go | 18 +- core/rawdb/accessors_chain_test.go | 2 +- core/rawdb/chain_iterator.go | 5 +- core/rawdb/database.go | 113 ++++++++++- core/rawdb/freezer.go | 28 ++- core/rawdb/schema.go | 6 + core/rawdb/table.go | 10 + core/state/pruner/pruner.go | 211 +++++++++++++++++++++ eth/downloader/downloader.go | 4 +- ethdb/database.go | 6 + node/node.go | 9 +- rlp/safe.go | 2 +- tests/fuzzers/bls12381/bls12381_fuzz.go | 3 +- 25 files changed, 879 insertions(+), 65 deletions(-) create mode 100644 cmd/geth/pruneblock_test.go diff --git a/.gitignore b/.gitignore index 3d05da8816..0271db9ecd 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,5 @@ profile.cov /dashboard/assets/package-lock.json **/yarn-error.log +cmd/geth/node/ +cmd/geth/__debug_bin diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 1152bfdfdd..a30efbbdea 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -458,7 +458,7 @@ func importPreimages(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, false) + db := utils.MakeChainDatabase(ctx, stack, false, false) start := time.Now() if err := utils.ImportPreimages(db, ctx.Args().First()); err != nil { @@ -477,7 +477,7 @@ func exportPreimages(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, true) + db := utils.MakeChainDatabase(ctx, stack, true, false) start := time.Now() if err := utils.ExportPreimages(db, ctx.Args().First()); err != nil { @@ -491,7 +491,7 @@ func dump(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, true) + db := utils.MakeChainDatabase(ctx, stack, true, false) for _, arg := range ctx.Args() { var header *types.Header if hashish(arg) { diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 4c70373e9a..2ac8b803cb 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -62,6 +62,7 @@ Remove blockchain and state databases`, dbPutCmd, dbGetSlotsCmd, dbDumpFreezerIndex, + ancientInspectCmd, }, } dbInspectCmd = cli.Command{ @@ -195,6 +196,16 @@ WARNING: This is a low-level operation which may cause database corruption!`, }, Description: "This command displays information about the freezer index.", } + ancientInspectCmd = cli.Command{ + Action: utils.MigrateFlags(ancientInspect), + Name: "inspect-reserved-oldest-blocks", + Flags: []cli.Flag{ + utils.DataDirFlag, + }, + Usage: "Inspect the ancientStore information", + Description: `This commands will read current offset from kvdb, which is the current offset and starting BlockNumber +of ancientStore, will also displays the reserved number of blocks in ancientStore `, + } ) func removeDB(ctx *cli.Context) error { @@ -282,12 +293,21 @@ func inspect(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, true) + db := utils.MakeChainDatabase(ctx, stack, true, false) defer db.Close() return rawdb.InspectDatabase(db, prefix, start) } +func ancientInspect(ctx *cli.Context) error { + stack, _ := makeConfigNode(ctx) + defer stack.Close() + + db := utils.MakeChainDatabase(ctx, stack, true, true) + defer db.Close() + return rawdb.AncientInspect(db) +} + func showLeveldbStats(db ethdb.Stater) { if stats, err := db.Stat("leveldb.stats"); err != nil { log.Warn("Failed to read database stats", "error", err) @@ -305,7 +325,7 @@ func dbStats(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, true) + db := utils.MakeChainDatabase(ctx, stack, true, false) defer db.Close() showLeveldbStats(db) @@ -316,7 +336,7 @@ func dbCompact(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, false) + db := utils.MakeChainDatabase(ctx, stack, false, false) defer db.Close() log.Info("Stats before compaction") @@ -340,7 +360,7 @@ func dbGet(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, true) + db := utils.MakeChainDatabase(ctx, stack, true, false) defer db.Close() key, err := hexutil.Decode(ctx.Args().Get(0)) @@ -365,7 +385,7 @@ func dbDelete(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, false) + db := utils.MakeChainDatabase(ctx, stack, false, false) defer db.Close() key, err := hexutil.Decode(ctx.Args().Get(0)) @@ -392,7 +412,7 @@ func dbPut(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, false) + db := utils.MakeChainDatabase(ctx, stack, false, false) defer db.Close() var ( @@ -426,7 +446,7 @@ func dbDumpTrie(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, true) + db := utils.MakeChainDatabase(ctx, stack, true, false) defer db.Close() var ( root []byte diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 3e2585fed6..3576fe2e46 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -165,6 +165,8 @@ var ( utils.MinerNotifyFullFlag, configFileFlag, utils.CatalystFlag, + utils.BlockAmountReserved, + utils.CheckSnapshotWithMPT, } rpcFlags = []cli.Flag{ diff --git a/cmd/geth/pruneblock_test.go b/cmd/geth/pruneblock_test.go new file mode 100644 index 0000000000..7d78f444fa --- /dev/null +++ b/cmd/geth/pruneblock_test.go @@ -0,0 +1,242 @@ +// Copyright 2016 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" + "fmt" + "io/ioutil" + "math/big" + "os" + "path/filepath" + "testing" + "time" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "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" + "github.com/ethereum/go-ethereum/core/state/pruner" + "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" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" +) + +var ( + canonicalSeed = 1 + blockPruneBackUpBlockNumber = 128 + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + balance = big.NewInt(10000000) + gspec = &core.Genesis{Config: params.TestChainConfig, Alloc: core.GenesisAlloc{address: {Balance: balance}}} + signer = types.LatestSigner(gspec.Config) + config = &core.CacheConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + SnapshotLimit: 0, // Disable snapshot + TriesInMemory: 128, + } + engine = ethash.NewFullFaker() +) + +func TestOfflineBlockPrune(t *testing.T) { + //Corner case for 0 remain in ancinetStore. + testOfflineBlockPruneWithAmountReserved(t, 0) + //General case. + testOfflineBlockPruneWithAmountReserved(t, 100) +} + +func testOfflineBlockPruneWithAmountReserved(t *testing.T, amountReserved uint64) { + datadir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("Failed to create temporary datadir: %v", err) + } + os.RemoveAll(datadir) + + chaindbPath := filepath.Join(datadir, "chaindata") + oldAncientPath := filepath.Join(chaindbPath, "ancient") + newAncientPath := filepath.Join(chaindbPath, "ancient_back") + + db, blocks, blockList, receiptsList, externTdList, startBlockNumber, _ := BlockchainCreator(t, chaindbPath, oldAncientPath, amountReserved) + node, _ := startEthService(t, gspec, blocks, chaindbPath) + defer node.Close() + + //Initialize a block pruner for pruning, only remain amountReserved blocks backward. + testBlockPruner := pruner.NewBlockPruner(db, node, oldAncientPath, newAncientPath, amountReserved) + if err != nil { + t.Fatalf("failed to make new blockpruner: %v", err) + } + if err := testBlockPruner.BlockPruneBackUp(chaindbPath, 512, utils.MakeDatabaseHandles(), "", false, false); err != nil { + t.Fatalf("Failed to back up block: %v", err) + } + + dbBack, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindbPath, 0, 0, newAncientPath, "", false, true, false) + if err != nil { + t.Fatalf("failed to create database with ancient backend") + } + defer dbBack.Close() + + //check against if the backup data matched original one + for blockNumber := startBlockNumber; blockNumber < startBlockNumber+amountReserved; blockNumber++ { + blockHash := rawdb.ReadCanonicalHash(dbBack, blockNumber) + block := rawdb.ReadBlock(dbBack, blockHash, blockNumber) + + if block.Hash() != blockHash { + t.Fatalf("block data did not match between oldDb and backupDb") + } + if blockList[blockNumber-startBlockNumber].Hash() != blockHash { + t.Fatalf("block data did not match between oldDb and backupDb") + } + + receipts := rawdb.ReadRawReceipts(dbBack, blockHash, blockNumber) + if err := checkReceiptsRLP(receipts, receiptsList[blockNumber-startBlockNumber]); err != nil { + t.Fatalf("receipts did not match between oldDb and backupDb") + } + // // Calculate the total difficulty of the block + td := rawdb.ReadTd(dbBack, blockHash, blockNumber) + if td == nil { + t.Fatalf("Failed to ReadTd: %v", consensus.ErrUnknownAncestor) + } + if td.Cmp(externTdList[blockNumber-startBlockNumber]) != 0 { + t.Fatalf("externTd did not match between oldDb and backupDb") + } + } + + //check if ancientDb freezer replaced successfully + testBlockPruner.AncientDbReplacer() + if _, err := os.Stat(newAncientPath); err != nil { + if !os.IsNotExist(err) { + t.Fatalf("ancientDb replaced unsuccessfully") + } + } + if _, err := os.Stat(oldAncientPath); err != nil { + t.Fatalf("ancientDb replaced unsuccessfully") + } +} + +func BlockchainCreator(t *testing.T, chaindbPath, AncientPath string, blockRemain uint64) (ethdb.Database, []*types.Block, []*types.Block, []types.Receipts, []*big.Int, uint64, *core.BlockChain) { + //create a database with ancient freezer + db, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindbPath, 0, 0, AncientPath, "", false, false, false) + if err != nil { + t.Fatalf("failed to create database with ancient backend") + } + defer db.Close() + genesis := gspec.MustCommit(db) + // Initialize a fresh chain with only a genesis block + blockchain, err := core.NewBlockChain(db, config, gspec.Config, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("Failed to create chain: %v", err) + } + + // Make chain starting from genesis + blocks, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 500, func(i int, block *core.BlockGen) { + block.SetCoinbase(common.Address{0: byte(canonicalSeed), 19: byte(i)}) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key) + if err != nil { + panic(err) + } + block.AddTx(tx) + block.SetDifficulty(big.NewInt(1000000)) + }) + if _, err := blockchain.InsertChain(blocks); err != nil { + t.Fatalf("Failed to import canonical chain start: %v", err) + } + + // Force run a freeze cycle + type freezer interface { + Freeze(threshold uint64) error + Ancients() (uint64, error) + } + db.(freezer).Freeze(10) + + frozen, err := db.Ancients() + //make sure there're frozen items + if err != nil || frozen == 0 { + t.Fatalf("Failed to import canonical chain start: %v", err) + } + if frozen < blockRemain { + t.Fatalf("block amount is not enough for pruning: %v", err) + } + + oldOffSet := rawdb.ReadOffSetOfCurrentAncientFreezer(db) + // Get the actual start block number. + startBlockNumber := frozen - blockRemain + oldOffSet + // Initialize the slice to buffer the block data left. + blockList := make([]*types.Block, 0, blockPruneBackUpBlockNumber) + receiptsList := make([]types.Receipts, 0, blockPruneBackUpBlockNumber) + externTdList := make([]*big.Int, 0, blockPruneBackUpBlockNumber) + // All ancient data within the most recent 128 blocks write into memory buffer for future new ancient_back directory usage. + for blockNumber := startBlockNumber; blockNumber < frozen+oldOffSet; blockNumber++ { + blockHash := rawdb.ReadCanonicalHash(db, blockNumber) + block := rawdb.ReadBlock(db, blockHash, blockNumber) + blockList = append(blockList, block) + receipts := rawdb.ReadRawReceipts(db, blockHash, blockNumber) + receiptsList = append(receiptsList, receipts) + // Calculate the total difficulty of the block + td := rawdb.ReadTd(db, blockHash, blockNumber) + if td == nil { + t.Fatalf("Failed to ReadTd: %v", consensus.ErrUnknownAncestor) + } + externTdList = append(externTdList, td) + } + + return db, blocks, blockList, receiptsList, externTdList, startBlockNumber, blockchain +} + +func checkReceiptsRLP(have, want types.Receipts) error { + if len(have) != len(want) { + return fmt.Errorf("receipts sizes mismatch: have %d, want %d", len(have), len(want)) + } + for i := 0; i < len(want); i++ { + rlpHave, err := rlp.EncodeToBytes(have[i]) + if err != nil { + return err + } + rlpWant, err := rlp.EncodeToBytes(want[i]) + if err != nil { + return err + } + if !bytes.Equal(rlpHave, rlpWant) { + return fmt.Errorf("receipt #%d: receipt mismatch: have %s, want %s", i, hex.EncodeToString(rlpHave), hex.EncodeToString(rlpWant)) + } + } + return nil +} + +// startEthService creates a full node instance for testing. +func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block, chaindbPath string) (*node.Node, *eth.Ethereum) { + t.Helper() + n, err := node.New(&node.Config{DataDir: chaindbPath}) + if err != nil { + t.Fatal("can't create node:", err) + } + + if err := n.Start(); err != nil { + t.Fatal("can't start node:", err) + } + + return n, nil +} diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 2f615a2c18..20920a0f94 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -19,8 +19,14 @@ package main import ( "bytes" "errors" + "fmt" + "os" + "path/filepath" "time" + "github.com/prometheus/tsdb/fileutil" + cli "gopkg.in/urfave/cli.v1" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -28,10 +34,11 @@ import ( "github.com/ethereum/go-ethereum/core/state/pruner" "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - cli "gopkg.in/urfave/cli.v1" ) var ( @@ -78,6 +85,30 @@ WARNING: It's necessary to delete the trie clean cache after the pruning. If you specify another directory for the trie clean cache via "--cache.trie.journal" during the use of Geth, please also specify it here for correct deletion. Otherwise the trie clean cache with default directory will be deleted. +`, + }, + { + Name: "prune-block", + Usage: "Prune block data offline", + Action: utils.MigrateFlags(pruneBlock), + Category: "MISCELLANEOUS COMMANDS", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.AncientFlag, + utils.BlockAmountReserved, + utils.TriesInMemoryFlag, + utils.CheckSnapshotWithMPT, + }, + Description: ` +geth offline prune-block for block data in ancientdb. +The amount of blocks expected for remaining after prune can be specified via block-amount-reserved in this command, +will prune and only remain the specified amount of old block data in ancientdb. +the brief workflow is to backup the the number of this specified amount blocks backward in original ancientdb +into new ancient_backup, then delete the original ancientdb dir and rename the ancient_backup to original one for replacement, +finally assemble the statedb and new ancientDb together. +The purpose of doing it is because the block data will be moved into the ancient store when it +becomes old enough(exceed the Threshold 90000), the disk usage will be very large over time, and is occupied mainly by ancientDb, +so it's very necessary to do block data prune, this feature will handle it. `, }, { @@ -149,11 +180,164 @@ It's also usable without snapshot enabled. } ) +func accessDb(ctx *cli.Context, stack *node.Node) (ethdb.Database, error) { + //The layer of tries trees that keep in memory. + TriesInMemory := int(ctx.GlobalUint64(utils.TriesInMemoryFlag.Name)) + chaindb := utils.MakeChainDatabase(ctx, stack, false, true) + defer chaindb.Close() + + if !ctx.GlobalBool(utils.CheckSnapshotWithMPT.Name) { + return chaindb, nil + } + headBlock := rawdb.ReadHeadBlock(chaindb) + if headBlock == nil { + return nil, errors.New("failed to load head block") + } + headHeader := headBlock.Header() + //Make sure the MPT and snapshot matches before pruning, otherwise the node can not start. + snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, TriesInMemory, headBlock.Root(), false, false, false) + if err != nil { + log.Error("snaptree error", "err", err) + return nil, err // The relevant snapshot(s) might not exist + } + + // Use the HEAD-(n-1) as the target root. The reason for picking it is: + // - in most of the normal cases, the related state is available + // - the probability of this layer being reorg is very low + + // Retrieve all snapshot layers from the current HEAD. + // In theory there are n difflayers + 1 disk layer present, + // so n diff layers are expected to be returned. + layers := snaptree.Snapshots(headHeader.Root, TriesInMemory, true) + if len(layers) != TriesInMemory { + // Reject if the accumulated diff layers are less than n. It + // means in most of normal cases, there is no associated state + // with bottom-most diff layer. + log.Error("snapshot layers != TriesInMemory", "err", err) + return nil, fmt.Errorf("snapshot not old enough yet: need %d more blocks", TriesInMemory-len(layers)) + } + // Use the bottom-most diff layer as the target + targetRoot := layers[len(layers)-1].Root() + + // Ensure the root is really present. The weak assumption + // is the presence of root can indicate the presence of the + // entire trie. + if blob := rawdb.ReadTrieNode(chaindb, targetRoot); len(blob) == 0 { + // 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 + // difflayer won't be created. So HEAD-(n-1) may not paired with + // head-(n-1) layer. Instead the paired layer is higher than the + // bottom-most diff layer. Try to find the bottom-most snapshot + // layer with state available. + // + // Note HEAD is ignored. Usually there is the associated + // state available, but we don't want to use the topmost state + // as the pruning target. + var found bool + for i := len(layers) - 2; i >= 1; i-- { + if blob := rawdb.ReadTrieNode(chaindb, layers[i].Root()); len(blob) != 0 { + targetRoot = layers[i].Root() + found = true + log.Info("Selecting middle-layer as the pruning target", "root", targetRoot, "depth", i) + break + } + } + if !found { + if blob := rawdb.ReadTrieNode(chaindb, snaptree.DiskRoot()); len(blob) != 0 { + targetRoot = snaptree.DiskRoot() + found = true + log.Info("Selecting disk-layer as the pruning target", "root", targetRoot) + } + } + if !found { + if len(layers) > 0 { + log.Error("no snapshot paired state") + return nil, errors.New("no snapshot paired state") + } + return nil, fmt.Errorf("associated state[%x] is not present", targetRoot) + } + } else { + if len(layers) > 0 { + log.Info("Selecting bottom-most difflayer as the pruning target", "root", targetRoot, "height", headHeader.Number.Uint64()-uint64(len(layers)-1)) + } else { + log.Info("Selecting user-specified state as the pruning target", "root", targetRoot) + } + } + return chaindb, nil +} + +func pruneBlock(ctx *cli.Context) error { + stack, config := makeConfigNode(ctx) + defer stack.Close() + blockAmountReserved := ctx.GlobalUint64(utils.BlockAmountReserved.Name) + chaindb, err := accessDb(ctx, stack) + if err != nil { + return err + } + var newAncientPath string + oldAncientPath := ctx.GlobalString(utils.AncientFlag.Name) + if !filepath.IsAbs(oldAncientPath) { + oldAncientPath = stack.ResolvePath(oldAncientPath) + } + + path, _ := filepath.Split(oldAncientPath) + if path == "" { + return errors.New("prune failed, did not specify the AncientPath") + } + newAncientPath = filepath.Join(path, "ancient_back") + + blockpruner := pruner.NewBlockPruner(chaindb, stack, oldAncientPath, newAncientPath, blockAmountReserved) + + lock, exist, err := fileutil.Flock(filepath.Join(oldAncientPath, "PRUNEFLOCK")) + if err != nil { + log.Error("file lock error", "err", err) + return err + } + if exist { + defer lock.Release() + log.Info("file lock existed, waiting for prune recovery and continue", "err", err) + if err := blockpruner.RecoverInterruption("chaindata", config.Eth.DatabaseCache, utils.MakeDatabaseHandles(), "", false); err != nil { + log.Error("Pruning failed", "err", err) + return err + } + log.Info("Block prune successfully") + return nil + } + + if _, err := os.Stat(newAncientPath); err == nil { + // No file lock found for old ancientDB but new ancientDB exsisted, indicating the geth was interrupted + // after old ancientDB removal, this happened after backup successfully, so just rename the new ancientDB + if err := blockpruner.AncientDbReplacer(); err != nil { + log.Error("Failed to rename new ancient directory") + return err + } + log.Info("Block prune successfully") + return nil + } + name := "chaindata" + if err := blockpruner.BlockPruneBackUp(name, config.Eth.DatabaseCache, utils.MakeDatabaseHandles(), "", false, false); err != nil { + log.Error("Failed to back up block", "err", err) + return err + } + + log.Info("backup block successfully") + + //After backing up successfully, rename the new ancientdb name to the original one, and delete the old ancientdb + if err := blockpruner.AncientDbReplacer(); err != nil { + return err + } + + lock.Release() + log.Info("Block prune successfully") + return nil +} + func pruneState(ctx *cli.Context) error { stack, config := makeConfigNode(ctx) defer stack.Close() - chaindb := utils.MakeChainDatabase(ctx, stack, false) + chaindb := utils.MakeChainDatabase(ctx, stack, false, false) pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name), ctx.GlobalUint64(utils.TriesInMemoryFlag.Name)) if err != nil { log.Error("Failed to open snapshot tree", "err", err) @@ -182,7 +366,7 @@ func verifyState(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - chaindb := utils.MakeChainDatabase(ctx, stack, true) + chaindb := utils.MakeChainDatabase(ctx, stack, true, false) headBlock := rawdb.ReadHeadBlock(chaindb) if headBlock == nil { log.Error("Failed to load head block") @@ -220,7 +404,7 @@ func traverseState(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - chaindb := utils.MakeChainDatabase(ctx, stack, true) + chaindb := utils.MakeChainDatabase(ctx, stack, true, false) headBlock := rawdb.ReadHeadBlock(chaindb) if headBlock == nil { log.Error("Failed to load head block") @@ -310,7 +494,7 @@ func traverseRawState(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - chaindb := utils.MakeChainDatabase(ctx, stack, true) + chaindb := utils.MakeChainDatabase(ctx, stack, true, false) headBlock := rawdb.ReadHeadBlock(chaindb) if headBlock == nil { log.Error("Failed to load head block") diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index fba14530b5..a1a0a7d0b4 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -58,6 +58,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.LightKDFFlag, utils.WhitelistFlag, utils.TriesInMemoryFlag, + utils.BlockAmountReserved, + utils.CheckSnapshotWithMPT, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 67632c031b..58f4798aee 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -33,6 +33,10 @@ import ( "text/template" "time" + pcsclite "github.com/gballet/go-libpcsclite" + gopsutil "github.com/shirou/gopsutil/mem" + "gopkg.in/urfave/cli.v1" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" @@ -66,9 +70,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" - pcsclite "github.com/gballet/go-libpcsclite" - gopsutil "github.com/shirou/gopsutil/mem" - "gopkg.in/urfave/cli.v1" ) func init() { @@ -827,6 +828,16 @@ var ( Name: "catalyst", Usage: "Catalyst mode (eth2 integration testing)", } + + BlockAmountReserved = cli.Uint64Flag{ + Name: "block-amount-reserved", + Usage: "Sets the expected remained amount of blocks for offline block prune", + } + + CheckSnapshotWithMPT = cli.BoolFlag{ + Name: "check-snapshot-with-mpt", + Usage: "Enable checking between snapshot and MPT ", + } ) // MakeDataDir retrieves the currently requested data directory, terminating @@ -1764,7 +1775,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(DataDirFlag.Name) { // Check if we have an already initialized chain and fall back to // that if so. Otherwise we need to generate a new genesis spec. - chaindb := MakeChainDatabase(ctx, stack, false) // TODO (MariusVanDerWijden) make this read only + chaindb := MakeChainDatabase(ctx, stack, false, false) // TODO (MariusVanDerWijden) make this read only if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) { cfg.Genesis = nil // fallback to db content } @@ -1883,7 +1894,7 @@ 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 { +func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly, disableFreeze bool) ethdb.Database { var ( cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 handles = MakeDatabaseHandles() @@ -1896,7 +1907,7 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. chainDb, err = stack.OpenDatabase(name, cache, handles, "", readonly) } else { name := "chaindata" - chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly) + chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly, disableFreeze, false) } if err != nil { Fatalf("Could not open database: %v", err) @@ -1926,7 +1937,7 @@ 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 + chainDb = MakeChainDatabase(ctx, stack, false, false) // TODO(rjl493456442) support read-only database config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) if err != nil { Fatalf("%v", err) diff --git a/core/blockchain.go b/core/blockchain.go index 6aa5916218..f4602bc847 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -325,9 +325,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par rawdb.InitDatabaseFromFreezer(bc.db) // If ancient database is not empty, reconstruct all missing // indices in the background. - frozen, _ := bc.db.Ancients() + frozen, _ := bc.db.ItemAmountInAncient() if frozen > 0 { - txIndexBlock = frozen + txIndexBlock, _ = bc.db.Ancients() } } if err := bc.loadLastState(); err != nil { @@ -362,7 +362,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par } } // Ensure that a previous crash in SetHead doesn't leave extra ancients - if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 { + if frozen, err := bc.db.ItemAmountInAncient(); err == nil && frozen > 0 { + frozen, err = bc.db.Ancients() + if err != nil { + return nil, err + } var ( needRewind bool low uint64 diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 5ddb6d2e07..b85f9c9e00 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1762,7 +1762,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { } os.RemoveAll(datadir) - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -1832,7 +1832,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { db.Close() // Start a new blockchain back up and see where the repait leads us - db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false) 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 6caec36eab..bdcca988a3 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1961,7 +1961,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { } os.RemoveAll(datadir) - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false) 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 b61eb741f0..530ad035dd 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -64,7 +64,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo } os.RemoveAll(datadir) - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -248,7 +248,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { db.Close() // 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.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false, false, false) if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 6874534817..8078db774f 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -653,7 +653,7 @@ func TestFastVsFullChains(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -727,7 +727,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(dir) - db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false) + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -1594,7 +1594,7 @@ func TestBlockchainRecovery(t *testing.T) { } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -1651,7 +1651,7 @@ func TestIncompleteAncientReceiptChainInsertion(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -1850,7 +1850,7 @@ func testInsertKnownChainData(t *testing.T, typ string) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(dir) - chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false) + chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2130,7 +2130,7 @@ func TestTransactionIndices(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2158,7 +2158,7 @@ func TestTransactionIndices(t *testing.T) { // 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) + ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2178,7 +2178,7 @@ func TestTransactionIndices(t *testing.T) { } // Reconstruct a block chain which only reserves HEAD-64 tx indices - ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2257,7 +2257,7 @@ func TestSkipStaleTxIndicesInFastSync(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index ea9dc436cf..f99511e456 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -440,7 +440,7 @@ func TestAncientStorage(t *testing.T) { } defer os.Remove(frdir) - db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false) + db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false) if err != nil { t.Fatalf("failed to create database with ancient backend") } diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 4dca06765e..22d5188e91 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -35,7 +35,7 @@ import ( // injects into the database the block hash->number mappings. func InitDatabaseFromFreezer(db ethdb.Database) { // If we can't access the freezer or it's empty, abort - frozen, err := db.Ancients() + frozen, err := db.ItemAmountInAncient() if err != nil || frozen == 0 { return } @@ -44,8 +44,9 @@ func InitDatabaseFromFreezer(db ethdb.Database) { start = time.Now() logged = start.Add(-7 * time.Second) // Unindex during import is fast, don't double log hash common.Hash + offset = db.AncientOffSet() ) - for i := uint64(0); i < frozen; i++ { + for i := uint64(0) + offset; i < frozen+offset; i++ { // Since the freezer has all data in sequential order on a file, // it would be 'neat' to read more data in one go, and let the // freezerdb return N items (e.g up to 1000 items per go) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 82d5df06ce..3342b36f36 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -20,16 +20,18 @@ import ( "bytes" "errors" "fmt" + "math/big" "os" "sync/atomic" "time" + "github.com/olekukonko/tablewriter" + "github.com/ethereum/go-ethereum/common" "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/log" - "github.com/olekukonko/tablewriter" ) // freezerdb is a database wrapper that enabled freezer data retrievals. @@ -112,6 +114,11 @@ func (db *nofreezedb) Ancients() (uint64, error) { return 0, errNotSupported } +// Ancients returns an error as we don't have a backing chain freezer. +func (db *nofreezedb) ItemAmountInAncient() (uint64, error) { + return 0, errNotSupported +} + // AncientSize returns an error as we don't have a backing chain freezer. func (db *nofreezedb) AncientSize(kind string) (uint64, error) { return 0, errNotSupported @@ -140,6 +147,10 @@ func (db *nofreezedb) SetDiffStore(diff ethdb.KeyValueStore) { db.diffStore = diff } +func (db *nofreezedb) AncientOffSet() uint64 { + return 0 +} + // NewDatabase creates a high level database on top of a given key-value data // store without a freezer moving immutable chain segments into cold storage. func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { @@ -148,15 +159,69 @@ func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { } } +func ReadOffSetOfCurrentAncientFreezer(db ethdb.KeyValueReader) uint64 { + offset, _ := db.Get(offSetOfCurrentAncientFreezer) + if offset == nil { + return 0 + } + return new(big.Int).SetBytes(offset).Uint64() +} + +func ReadOffSetOfLastAncientFreezer(db ethdb.KeyValueReader) uint64 { + offset, _ := db.Get(offSetOfLastAncientFreezer) + if offset == nil { + return 0 + } + return new(big.Int).SetBytes(offset).Uint64() +} + +func WriteOffSetOfCurrentAncientFreezer(db ethdb.KeyValueWriter, offset uint64) { + if err := db.Put(offSetOfCurrentAncientFreezer, new(big.Int).SetUint64(offset).Bytes()); err != nil { + log.Crit("Failed to store offSetOfAncientFreezer", "err", err) + } +} +func WriteOffSetOfLastAncientFreezer(db ethdb.KeyValueWriter, offset uint64) { + if err := db.Put(offSetOfLastAncientFreezer, new(big.Int).SetUint64(offset).Bytes()); err != nil { + log.Crit("Failed to store offSetOfAncientFreezer", "err", err) + } +} + +// NewFreezerDb only create a freezer without statedb. +func NewFreezerDb(db ethdb.KeyValueStore, frz, namespace string, readonly bool, newOffSet uint64) (*freezer, error) { + // Create the idle freezer instance, this operation should be atomic to avoid mismatch between offset and acientDB. + frdb, err := newFreezer(frz, namespace, readonly) + if err != nil { + return nil, err + } + frdb.offset = newOffSet + frdb.frozen += newOffSet + return frdb, nil +} + // 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) { +func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace string, readonly, disableFreeze, isLastOffset bool) (ethdb.Database, error) { // Create the idle freezer instance frdb, err := newFreezer(freezer, namespace, readonly) if err != nil { return nil, err } + + var offset uint64 + // The offset of ancientDB should be handled differently in different scenarios. + if isLastOffset { + offset = ReadOffSetOfLastAncientFreezer(db) + } else { + offset = ReadOffSetOfCurrentAncientFreezer(db) + } + + frdb.offset = offset + + // Some blocks in ancientDB may have already been frozen and been pruned, so adding the offset to + // reprensent the absolute number of blocks already frozen. + frdb.frozen += offset + // Since the freezer can be stored separately from the user's key-value database, // there's a fairly high probability that the user requests invalid combinations // of the freezer and database. Ensure that we don't shoot ourselves in the foot @@ -179,7 +244,10 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace st // If the genesis hash is empty, we have a new key-value store, so nothing to // validate in this method. If, however, the genesis hash is not nil, compare // it to the freezer content. - if kvgenesis, _ := db.Get(headerHashKey(0)); len(kvgenesis) > 0 { + // Only to check the followings when offset equal to 0, otherwise the block number + // in ancientdb did not start with 0, no genesis block in ancientdb as well. + + if kvgenesis, _ := db.Get(headerHashKey(0)); offset == 0 && len(kvgenesis) > 0 { if frozen, _ := frdb.Ancients(); frozen > 0 { // If the freezer already contains something, ensure that the genesis blocks // match, otherwise we might mix up freezers across chains and destroy both @@ -221,8 +289,9 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace st // feezer. } } + // Freezer is consistent with the key-value database, permit combining the two - if !frdb.readonly { + if !disableFreeze && !frdb.readonly { go frdb.freeze(db) } return &freezerdb{ @@ -256,12 +325,12 @@ 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) { +func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, freezer string, namespace string, readonly, disableFreeze, isLastOffset 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, freezer, namespace, readonly, disableFreeze, isLastOffset) if err != nil { kvdb.Close() return nil, err @@ -298,6 +367,35 @@ func (s *stat) Size() string { func (s *stat) Count() string { return s.count.String() } +func AncientInspect(db ethdb.Database) error { + offset := counter(ReadOffSetOfCurrentAncientFreezer(db)) + // Get number of ancient rows inside the freezer. + ancients := counter(0) + if count, err := db.ItemAmountInAncient(); err != nil { + log.Error("failed to get the items amount in ancientDB", "err", err) + return err + } else { + ancients = counter(count) + } + var endNumber counter + if offset+ancients <= 0 { + endNumber = 0 + } else { + endNumber = offset + ancients - 1 + } + stats := [][]string{ + {"Offset/StartBlockNumber", "Offset/StartBlockNumber of ancientDB", offset.String()}, + {"Amount of remained items in AncientStore", "Remaining items of ancientDB", ancients.String()}, + {"The last BlockNumber within ancientDB", "The last BlockNumber", endNumber.String()}, + } + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Database", "Category", "Items"}) + table.SetFooter([]string{"", "AncientStore information", ""}) + table.AppendBulk(stats) + table.Render() + + return nil +} // InspectDatabase traverses the entire database and checks the size // of all different categories of data. @@ -431,9 +529,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { } // Get number of ancient rows inside the freezer ancients := counter(0) - if count, err := db.Ancients(); err == nil { + if count, err := db.ItemAmountInAncient(); err == nil { ancients = counter(count) } + // Display the database statistic. stats := [][]string{ {"Key-Value store", "Headers", headers.Size(), headers.Count()}, diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 94b99a64eb..92dfc9604a 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -85,6 +85,8 @@ type freezer struct { quit chan struct{} closeOnce sync.Once + + offset uint64 // Starting BlockNumber in current freezer } // newFreezer creates a chain freezer that moves ancient chain data into @@ -164,7 +166,7 @@ func (f *freezer) Close() error { // in the freezer. func (f *freezer) HasAncient(kind string, number uint64) (bool, error) { if table := f.tables[kind]; table != nil { - return table.has(number), nil + return table.has(number - f.offset), nil } return false, nil } @@ -172,7 +174,7 @@ func (f *freezer) HasAncient(kind string, number uint64) (bool, error) { // Ancient retrieves an ancient binary blob from the append-only immutable files. func (f *freezer) Ancient(kind string, number uint64) ([]byte, error) { if table := f.tables[kind]; table != nil { - return table.Retrieve(number) + return table.Retrieve(number - f.offset) } return nil, errUnknownTable } @@ -182,6 +184,16 @@ func (f *freezer) Ancients() (uint64, error) { return atomic.LoadUint64(&f.frozen), nil } +// ItemAmountInAncient returns the actual length of current ancientDB. +func (f *freezer) ItemAmountInAncient() (uint64, error) { + return atomic.LoadUint64(&f.frozen) - atomic.LoadUint64(&f.offset), nil +} + +// AncientOffSet returns the offset of current ancientDB. +func (f *freezer) AncientOffSet() uint64 { + return atomic.LoadUint64(&f.offset) +} + // AncientSize returns the ancient size of the specified category. func (f *freezer) AncientSize(kind string) (uint64, error) { if table := f.tables[kind]; table != nil { @@ -216,23 +228,23 @@ func (f *freezer) AppendAncient(number uint64, hash, header, body, receipts, td } }() // Inject all the components into the relevant data tables - if err := f.tables[freezerHashTable].Append(f.frozen, hash[:]); err != nil { + if err := f.tables[freezerHashTable].Append(f.frozen-f.offset, hash[:]); err != nil { log.Error("Failed to append ancient hash", "number", f.frozen, "hash", hash, "err", err) return err } - if err := f.tables[freezerHeaderTable].Append(f.frozen, header); err != nil { + if err := f.tables[freezerHeaderTable].Append(f.frozen-f.offset, header); err != nil { log.Error("Failed to append ancient header", "number", f.frozen, "hash", hash, "err", err) return err } - if err := f.tables[freezerBodiesTable].Append(f.frozen, body); err != nil { + if err := f.tables[freezerBodiesTable].Append(f.frozen-f.offset, body); err != nil { log.Error("Failed to append ancient body", "number", f.frozen, "hash", hash, "err", err) return err } - if err := f.tables[freezerReceiptTable].Append(f.frozen, receipts); err != nil { + if err := f.tables[freezerReceiptTable].Append(f.frozen-f.offset, receipts); err != nil { log.Error("Failed to append ancient receipts", "number", f.frozen, "hash", hash, "err", err) return err } - if err := f.tables[freezerDifficultyTable].Append(f.frozen, td); err != nil { + if err := f.tables[freezerDifficultyTable].Append(f.frozen-f.offset, td); err != nil { log.Error("Failed to append ancient difficulty", "number", f.frozen, "hash", hash, "err", err) return err } @@ -249,7 +261,7 @@ func (f *freezer) TruncateAncients(items uint64) error { return nil } for _, table := range f.tables { - if err := table.truncate(items); err != nil { + if err := table.truncate(items - f.offset); err != nil { return err } } diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index b4fb99e451..ece5006c39 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -69,6 +69,12 @@ var ( // fastTxLookupLimitKey tracks the transaction lookup limit during fast sync. fastTxLookupLimitKey = []byte("FastTransactionLookupLimit") + //offSet of new updated ancientDB. + offSetOfCurrentAncientFreezer = []byte("offSetOfCurrentAncientFreezer") + + //offSet of the ancientDB before updated version. + offSetOfLastAncientFreezer = []byte("offSetOfLastAncientFreezer") + // badBlockKey tracks the list of bad blocks seen by local badBlockKey = []byte("InvalidBlock") diff --git a/core/rawdb/table.go b/core/rawdb/table.go index a27f5f8ed7..0dcaf8cfb0 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -68,6 +68,16 @@ func (t *table) Ancients() (uint64, error) { return t.db.Ancients() } +// ItemAmountInAncient returns the actual length of current ancientDB. +func (t *table) ItemAmountInAncient() (uint64, error) { + return t.db.ItemAmountInAncient() +} + +// AncientOffSet returns the offset of current ancientDB. +func (t *table) AncientOffSet() uint64 { + return t.db.AncientOffSet() +} + // AncientSize is a noop passthrough that just forwards the request to the underlying // database. func (t *table) AncientSize(kind string) (uint64, error) { diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index bb599fcd87..5b070f3afa 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -27,7 +27,10 @@ import ( "strings" "time" + "github.com/prometheus/tsdb/fileutil" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" @@ -35,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) @@ -85,6 +89,14 @@ type Pruner struct { triesInMemory uint64 } +type BlockPruner struct { + db ethdb.Database + oldAncientPath string + newAncientPath string + node *node.Node + BlockAmountReserved uint64 +} + // NewPruner creates the pruner instance. func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize, triesInMemory uint64) (*Pruner, error) { headBlock := rawdb.ReadHeadBlock(db) @@ -101,6 +113,7 @@ func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize, trie bloomSize = 256 } stateBloom, err := newStateBloomWithSize(bloomSize) + if err != nil { return nil, err } @@ -115,6 +128,16 @@ func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize, trie }, nil } +func NewBlockPruner(db ethdb.Database, n *node.Node, oldAncientPath, newAncientPath string, BlockAmountReserved uint64) *BlockPruner { + return &BlockPruner{ + db: db, + oldAncientPath: oldAncientPath, + newAncientPath: newAncientPath, + node: n, + BlockAmountReserved: BlockAmountReserved, + } +} + func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, stateBloom *stateBloom, bloomPath string, middleStateRoots map[common.Hash]struct{}, start time.Time) error { // Delete all stale trie nodes in the disk. With the help of state bloom // the trie nodes(and codes) belong to the active state will be filtered @@ -233,6 +256,194 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta return nil } +func (p *BlockPruner) backUpOldDb(name string, cache, handles int, namespace string, readonly, interrupt bool) error { + // Open old db wrapper. + chainDb, err := p.node.OpenDatabaseWithFreezer(name, cache, handles, p.oldAncientPath, namespace, readonly, true, interrupt) + if err != nil { + log.Error("Failed to open ancient database", "err=", err) + return err + } + defer chainDb.Close() + log.Info("chainDB opened successfully") + + // Get the number of items in old ancient db. + itemsOfAncient, err := chainDb.ItemAmountInAncient() + log.Info("the number of items in ancientDB is ", "itemsOfAncient", itemsOfAncient) + + // If we can't access the freezer or it's empty, abort. + if err != nil || itemsOfAncient == 0 { + log.Error("can't access the freezer or it's empty, abort") + return errors.New("can't access the freezer or it's empty, abort") + } + + // If the items in freezer is less than the block amount that we want to reserve, it is not enough, should stop. + if itemsOfAncient < p.BlockAmountReserved { + log.Error("the number of old blocks is not enough to reserve,", "ancient items", itemsOfAncient, "the amount specified", p.BlockAmountReserved) + return errors.New("the number of old blocks is not enough to reserve") + } + + var oldOffSet uint64 + if interrupt { + // The interrupt scecario within this function is specific for old and new ancientDB exsisted concurrently, + // should use last version of offset for oldAncientDB, because current offset is + // actually of the new ancientDB_Backup, but what we want is the offset of ancientDB being backup. + oldOffSet = rawdb.ReadOffSetOfLastAncientFreezer(chainDb) + } else { + // Using current version of ancientDB for oldOffSet because the db for backup is current version. + oldOffSet = rawdb.ReadOffSetOfCurrentAncientFreezer(chainDb) + } + log.Info("the oldOffSet is ", "oldOffSet", oldOffSet) + + // Get the start BlockNumber for pruning. + startBlockNumber := oldOffSet + itemsOfAncient - p.BlockAmountReserved + log.Info("new offset/new startBlockNumber is ", "new offset", startBlockNumber) + + // Create new ancientdb backup and record the new and last version of offset in kvDB as well. + // For every round, newoffset actually equals to the startBlockNumber in ancient backup db. + frdbBack, err := rawdb.NewFreezerDb(chainDb, p.newAncientPath, namespace, readonly, startBlockNumber) + if err != nil { + log.Error("Failed to create ancient freezer backup", "err=", err) + return err + } + defer frdbBack.Close() + + offsetBatch := chainDb.NewBatch() + rawdb.WriteOffSetOfCurrentAncientFreezer(offsetBatch, startBlockNumber) + rawdb.WriteOffSetOfLastAncientFreezer(offsetBatch, oldOffSet) + if err := offsetBatch.Write(); err != nil { + log.Crit("Failed to write offset into disk", "err", err) + } + + // It's guaranteed that the old/new offsets are updated as well as the new ancientDB are created if this flock exist. + lock, _, err := fileutil.Flock(filepath.Join(p.newAncientPath, "PRUNEFLOCKBACK")) + if err != nil { + log.Error("file lock error", "err", err) + return err + } + + log.Info("prune info", "old offset", oldOffSet, "number of items in ancientDB", itemsOfAncient, "amount to reserve", p.BlockAmountReserved) + log.Info("new offset/new startBlockNumber recorded successfully ", "new offset", startBlockNumber) + + start := time.Now() + // All ancient data after and including startBlockNumber should write into new ancientDB ancient_back. + for blockNumber := startBlockNumber; blockNumber < itemsOfAncient+oldOffSet; blockNumber++ { + blockHash := rawdb.ReadCanonicalHash(chainDb, blockNumber) + block := rawdb.ReadBlock(chainDb, blockHash, blockNumber) + receipts := rawdb.ReadRawReceipts(chainDb, blockHash, blockNumber) + // Calculate the total difficulty of the block + td := rawdb.ReadTd(chainDb, blockHash, blockNumber) + if td == nil { + return consensus.ErrUnknownAncestor + } + // Write into new ancient_back db. + rawdb.WriteAncientBlock(frdbBack, block, receipts, td) + // Print the log every 5s for better trace. + if common.PrettyDuration(time.Since(start)) > common.PrettyDuration(5*time.Second) { + log.Info("block backup process running successfully", "current blockNumber for backup", blockNumber) + start = time.Now() + } + } + lock.Release() + log.Info("block back up done", "current start blockNumber in ancientDB", startBlockNumber) + return nil +} + +// Backup the ancient data for the old ancient db, i.e. the most recent 128 blocks in ancient db. +func (p *BlockPruner) BlockPruneBackUp(name string, cache, handles int, namespace string, readonly, interrupt bool) error { + + start := time.Now() + + if err := p.backUpOldDb(name, cache, handles, namespace, readonly, interrupt); err != nil { + return err + } + + log.Info("Block pruning BackUp successfully", "time duration since start is", common.PrettyDuration(time.Since(start))) + return nil +} + +func (p *BlockPruner) RecoverInterruption(name string, cache, handles int, namespace string, readonly bool) error { + log.Info("RecoverInterruption for block prune") + newExist, err := CheckFileExist(p.newAncientPath) + if err != nil { + log.Error("newAncientDb path error") + return err + } + + if newExist { + log.Info("New ancientDB_backup existed in interruption scenario") + flockOfAncientBack, err := CheckFileExist(filepath.Join(p.newAncientPath, "PRUNEFLOCKBACK")) + if err != nil { + log.Error("Failed to check flock of ancientDB_Back %v", err) + return err + } + + // Indicating both old and new ancientDB existed concurrently. + // Delete directly for the new ancientdb to prune from start, e.g.: path ../chaindb/ancient_backup + if err := os.RemoveAll(p.newAncientPath); err != nil { + log.Error("Failed to remove old ancient directory %v", err) + return err + } + if flockOfAncientBack { + // Indicating the oldOffset/newOffset have already been updated. + if err := p.BlockPruneBackUp(name, cache, handles, namespace, readonly, true); err != nil { + log.Error("Failed to prune") + return err + } + } else { + // Indicating the flock did not exist and the new offset did not be updated, so just handle this case as usual. + if err := p.BlockPruneBackUp(name, cache, handles, namespace, readonly, false); err != nil { + log.Error("Failed to prune") + return err + } + } + + if err := p.AncientDbReplacer(); err != nil { + log.Error("Failed to replace ancientDB") + return err + } + } else { + log.Info("New ancientDB_backup did not exist in interruption scenario") + // Indicating new ancientDB even did not be created, just prune starting at backup from startBlockNumber as usual, + // in this case, the new offset have not been written into kvDB. + if err := p.BlockPruneBackUp(name, cache, handles, namespace, readonly, false); err != nil { + log.Error("Failed to prune") + return err + } + if err := p.AncientDbReplacer(); err != nil { + log.Error("Failed to replace ancientDB") + return err + } + } + + return nil +} + +func CheckFileExist(path string) (bool, error) { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + // Indicating the file didn't exist. + return false, nil + } + return true, err + } + return true, nil +} + +func (p *BlockPruner) AncientDbReplacer() error { + // Delete directly for the old ancientdb, e.g.: path ../chaindb/ancient + if err := os.RemoveAll(p.oldAncientPath); err != nil { + log.Error("Failed to remove old ancient directory %v", err) + return err + } + + // Rename the new ancientdb path same to the old + if err := os.Rename(p.newAncientPath, p.oldAncientPath); err != nil { + log.Error("Failed to rename new ancient directory") + return err + } + return nil +} + // Prune deletes all historical state nodes except the nodes belong to the // specified state version. If user doesn't specify the state version, use // the bottom-most snapshot diff layer as the target. diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 0009f41786..e1225e7a1c 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -599,10 +599,10 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I d.ancientLimit = 0 } frozen, _ := d.stateDB.Ancients() // Ignore the error here since light client can also hit here. - + itemAmountInAncient, _ := d.stateDB.ItemAmountInAncient() // If a part of blockchain data has already been written into active store, // disable the ancient style insertion explicitly. - if origin >= frozen && frozen != 0 { + if origin >= frozen && itemAmountInAncient != 0 { d.ancientLimit = 0 log.Info("Disabling direct-ancient mode", "origin", origin, "ancient", frozen-1) } else if d.ancientLimit > 0 { diff --git a/ethdb/database.go b/ethdb/database.go index 40d0e01d57..e437817a20 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -81,6 +81,12 @@ type AncientReader interface { // AncientSize returns the ancient size of the specified category. AncientSize(kind string) (uint64, error) + + // ItemAmountInAncient returns the actual length of current ancientDB. + ItemAmountInAncient() (uint64, error) + + // AncientOffSet returns the offset of current ancientDB. + AncientOffSet() uint64 } // AncientWriter contains the methods required to write to immutable ancient data. diff --git a/node/node.go b/node/node.go index c122dad32c..b6e1246b3d 100644 --- a/node/node.go +++ b/node/node.go @@ -27,6 +27,8 @@ import ( "strings" "sync" + "github.com/prometheus/tsdb/fileutil" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" @@ -35,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" - "github.com/prometheus/tsdb/fileutil" ) // Node is a container on which services can be registered. @@ -586,7 +587,7 @@ func (n *Node) OpenAndMergeDatabase(name string, cache, handles int, freezer, di if persistDiff { chainDataHandles = handles * chainDataHandlesPercentage / 100 } - chainDB, err := n.OpenDatabaseWithFreezer(name, cache, chainDataHandles, freezer, namespace, readonly) + chainDB, err := n.OpenDatabaseWithFreezer(name, cache, chainDataHandles, freezer, namespace, readonly, false, false) if err != nil { return nil, err } @@ -606,7 +607,7 @@ func (n *Node) OpenAndMergeDatabase(name string, cache, handles int, freezer, di // 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, freezer, namespace string, readonly, disableFreeze, isLastOffset bool) (ethdb.Database, error) { n.lock.Lock() defer n.lock.Unlock() if n.state == closedState { @@ -625,7 +626,7 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, case !filepath.IsAbs(freezer): freezer = n.ResolvePath(freezer) } - db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace, readonly) + db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace, readonly, disableFreeze, isLastOffset) } if err == nil { diff --git a/rlp/safe.go b/rlp/safe.go index c881650a0d..a80380aef4 100644 --- a/rlp/safe.go +++ b/rlp/safe.go @@ -22,5 +22,5 @@ import "reflect" // byteArrayBytes returns a slice of the byte array v. func byteArrayBytes(v reflect.Value) []byte { - return v.Slice(0, v.Len()).Bytes() + return v.Slice(0, v.Len()).Bytes() } diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index 298050ad36..5c28b952d3 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -28,6 +28,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/crypto/bls12381" ) @@ -159,7 +160,7 @@ func FuzzCrossG1MultiExp(data []byte) int { gethPoints = append(gethPoints, new(bls12381.PointG1).Set(kp1)) gnarkPoints = append(gnarkPoints, *cp1) } - if len(gethScalars) == 0{ + if len(gethScalars) == 0 { return 0 } // compute multi exponentiation From eb7e3092d5db252a8f464c9b9518d92174598406 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Wed, 26 Jan 2022 14:12:18 +0800 Subject: [PATCH 078/117] [R4R] implement State Verification && Snapshot Commit pipeline (#668) * pipeline commit trie add metrics reopen trie * add unit testcase * resolve keefe's comment * resolve igor's comments * update prefetch remove prefetcher * no need to return error for precacheTransaction * fix lint issue * add some comments * remove useless code * add default option is false * fix diffsync nil point * fix panic on GetProofByHash Co-authored-by: zjubfd --- cmd/evm/internal/t8ntool/execution.go | 8 +- cmd/evm/runner.go | 4 +- cmd/evm/staterunner.go | 3 +- cmd/geth/main.go | 1 + cmd/utils/flags.go | 7 + consensus/clique/clique.go | 4 + core/block_validator.go | 29 ++- core/blockchain.go | 223 ++++++++++++++------- core/blockchain_diff_test.go | 8 +- core/blockchain_test.go | 268 ++++++++++++++++++-------- core/chain_makers.go | 6 +- core/error.go | 3 + core/genesis.go | 2 +- core/state/database.go | 3 + core/state/snapshot/difflayer.go | 36 +++- core/state/snapshot/difflayer_test.go | 36 ++-- core/state/snapshot/disklayer.go | 14 +- core/state/snapshot/disklayer_test.go | 8 +- core/state/snapshot/iterator_test.go | 90 ++++----- core/state/snapshot/journal.go | 2 +- core/state/snapshot/snapshot.go | 19 +- core/state/snapshot/snapshot_test.go | 24 +-- core/state/state_test.go | 12 +- core/state/statedb.go | 256 ++++++++++++++++++------ core/state/statedb_test.go | 35 +++- core/state/sync_test.go | 4 +- core/state/trie_prefetcher.go | 22 ++- core/state_prefetcher.go | 39 ++-- core/state_processor.go | 19 +- core/types.go | 2 +- eth/api_test.go | 6 +- eth/backend.go | 3 + eth/ethconfig/config.go | 1 + eth/state_accessor.go | 4 +- eth/tracers/api.go | 4 +- ethclient/ethclient_test.go | 1 + miner/worker.go | 5 + params/protocol_params.go | 1 - tests/state_test_util.go | 8 +- trie/database.go | 58 ++++-- 40 files changed, 882 insertions(+), 396 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 2a9426540a..aadebdd439 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -223,7 +223,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, statedb.AddBalance(pre.Env.Coinbase, minerReward) } // Commit block - root, _, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) + statedb.Finalise(chainConfig.IsEIP158(vmContext.BlockNumber)) + statedb.AccountsIntermediateRoot() + root, _, err := statedb.Commit(nil) if err != nil { fmt.Fprintf(os.Stderr, "Could not commit state: %v", err) return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) @@ -252,7 +254,9 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB } } // Commit and re-open to start with a clean state. - root, _, _ := statedb.Commit(false) + statedb.Finalise(false) + statedb.AccountsIntermediateRoot() + root, _, _ := statedb.Commit(nil) statedb, _ = state.New(root, sdb, nil) return statedb } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index f522233e71..fd18270182 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -268,7 +268,9 @@ func runCmd(ctx *cli.Context) error { output, leftOverGas, stats, err := timedExec(bench, execFunc) if ctx.GlobalBool(DumpFlag.Name) { - statedb.Commit(true) + statedb.Finalise(true) + statedb.AccountsIntermediateRoot() + statedb.Commit(nil) statedb.IntermediateRoot(true) fmt.Println(string(statedb.Dump(false, false, true))) } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index bfc243b471..c373772fbe 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -101,7 +101,8 @@ func stateTestCmd(ctx *cli.Context) error { _, state, err := test.Run(st, cfg, false) // print state root for evmlab tracing if ctx.GlobalBool(MachineFlag.Name) && state != nil { - fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false)) + root := state.IntermediateRoot(false) + fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", root) } if err != nil { // Test failed, mark as so and dump any state to aid debugging diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 3576fe2e46..e0f29bce77 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -72,6 +72,7 @@ var ( utils.DirectBroadcastFlag, utils.DisableSnapProtocolFlag, utils.DiffSyncFlag, + utils.PipeCommitFlag, utils.RangeLimitFlag, utils.USBFlag, utils.SmartCardDaemonPathFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 58f4798aee..8f5141907f 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -127,6 +127,10 @@ var ( Usage: "Enable diffy sync, Please note that enable diffsync will improve the syncing speed, " + "but will degrade the security to light client level", } + PipeCommitFlag = cli.BoolFlag{ + Name: "pipecommit", + Usage: "Enable MPT pipeline commit, it will improve syncing performance. It is an experimental feature(default is false)", + } RangeLimitFlag = cli.BoolFlag{ Name: "rangelimit", Usage: "Enable 5000 blocks limit for range query", @@ -1632,6 +1636,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(DiffSyncFlag.Name) { cfg.DiffSync = ctx.GlobalBool(DiffSyncFlag.Name) } + if ctx.GlobalIsSet(PipeCommitFlag.Name) { + cfg.PipeCommit = ctx.GlobalBool(PipeCommitFlag.Name) + } if ctx.GlobalIsSet(RangeLimitFlag.Name) { cfg.RangeLimit = ctx.GlobalBool(RangeLimitFlag.Name) } diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index dfec81f6ad..2c8094ca3d 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -560,7 +560,11 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, []*types.Receipt, error) { // No block rewards in PoA, so the state remains as is and uncles are dropped + var err error header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + if err != nil { + return nil, nil, err + } header.UncleHash = types.CalcUncleHash(nil) // Assemble and return the final block for sealing diff --git a/core/block_validator.go b/core/block_validator.go index 12fa908cd0..b109c1e54b 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -18,6 +18,7 @@ package core import ( "fmt" + "time" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" @@ -26,6 +27,8 @@ import ( "github.com/ethereum/go-ethereum/trie" ) +const badBlockCacheExpire = 30 * time.Second + // BlockValidator is responsible for validating block headers, uncles and // processed state. // @@ -54,6 +57,9 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { return ErrKnownBlock } + if v.bc.isCachedBadBlock(block) { + return ErrKnownBadBlock + } // Header validity is known at this point, check the uncles and transactions header := block.Header() if err := v.engine.VerifyUncles(v.bc, block); err != nil { @@ -106,7 +112,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // 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. -func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, skipHeavyVerify bool) error { header := block.Header() if block.GasUsed() != usedGas { return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) @@ -125,17 +131,26 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) if receiptSha != header.ReceiptHash { return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) - } else { - return nil } + return nil }, - func() error { + } + if skipHeavyVerify { + validateFuns = append(validateFuns, func() error { + if err := statedb.WaitPipeVerification(); err != nil { + return err + } + statedb.Finalise(v.config.IsEIP158(header.Number)) + statedb.AccountsIntermediateRoot() + return nil + }) + } else { + validateFuns = append(validateFuns, func() error { 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) - } else { - return nil } - }, + return nil + }) } validateRes := make(chan error, len(validateFuns)) for _, f := range validateFuns { diff --git a/core/blockchain.go b/core/blockchain.go index f4602bc847..6c87ffc708 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -77,7 +77,8 @@ var ( blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil) blockReorgInvalidatedTx = metrics.NewRegisteredMeter("chain/reorg/invalidTx", nil) - errInsertionInterrupted = errors.New("insertion is interrupted") + errInsertionInterrupted = errors.New("insertion is interrupted") + errStateRootVerificationFailed = errors.New("state root verification failed") ) const ( @@ -87,6 +88,7 @@ const ( diffLayerRLPCacheLimit = 256 receiptsCacheLimit = 10000 txLookupCacheLimit = 1024 + maxBadBlockLimit = 16 maxFutureBlocks = 256 maxTimeFutureBlocks = 30 maxBeyondBlocks = 2048 @@ -99,6 +101,8 @@ const ( maxDiffForkDist = 11 // Maximum allowed backward distance from the chain head maxDiffLimitForBroadcast = 128 // Maximum number of unique diff layers a peer may have broadcasted + rewindBadBlockInterval = 1 * time.Second + // BlockChainVersion ensures that an incompatible database forces a resync from scratch. // // Changelog: @@ -177,10 +181,11 @@ 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 + commitLock sync.Mutex // CommitLock is used to protect above field from being modified concurrently // txLookupLimit is the maximum number of blocks from head whose tx indices // are reserved: @@ -213,6 +218,7 @@ type BlockChain struct { 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 + badBlockCache *lru.Cache // Cache for the blocks that failed to pass MPT root verification // trusted diff layers diffLayerCache *lru.Cache // Cache for the diffLayers @@ -239,6 +245,7 @@ type BlockChain struct { validator Validator // Block and state validator interface processor Processor // Block transaction processor interface vmConfig vm.Config + pipeCommit bool shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. terminateInsert func(common.Hash, uint64) bool // Testing hook used to terminate ancient receipt chain insertion. @@ -262,6 +269,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par receiptsCache, _ := lru.New(receiptsCacheLimit) blockCache, _ := lru.New(blockCacheLimit) txLookupCache, _ := lru.New(txLookupCacheLimit) + badBlockCache, _ := lru.New(maxBadBlockLimit) + futureBlocks, _ := lru.New(maxFutureBlocks) diffLayerCache, _ := lru.New(diffLayerCacheLimit) diffLayerRLPCache, _ := lru.New(diffLayerRLPCacheLimit) @@ -283,6 +292,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par bodyRLPCache: bodyRLPCache, receiptsCache: receiptsCache, blockCache: blockCache, + badBlockCache: badBlockCache, diffLayerCache: diffLayerCache, diffLayerRLPCache: diffLayerRLPCache, txLookupCache: txLookupCache, @@ -461,7 +471,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par go bc.trustedDiffLayerLoop() } go bc.untrustedDiffLayerPruneLoop() - + if bc.pipeCommit { + // check current block and rewind invalid one + go bc.rewindInvalidHeaderBlockLoop() + } return bc, nil } @@ -577,6 +590,25 @@ func (bc *BlockChain) SetHead(head uint64) error { return err } +func (bc *BlockChain) tryRewindBadBlocks() { + bc.chainmu.Lock() + defer bc.chainmu.Unlock() + block := bc.CurrentBlock() + snaps := bc.snaps + // Verified and Result is false + if snaps != nil && snaps.Snapshot(block.Root()) != nil && + snaps.Snapshot(block.Root()).Verified() && !snaps.Snapshot(block.Root()).WaitAndGetVerifyRes() { + // Rewind by one block + log.Warn("current block verified failed, rewind to its parent", "height", block.NumberU64(), "hash", block.Hash()) + bc.futureBlocks.Remove(block.Hash()) + bc.badBlockCache.Add(block.Hash(), time.Now()) + bc.diffLayerCache.Remove(block.Hash()) + bc.diffLayerRLPCache.Remove(block.Hash()) + bc.reportBlock(block, nil, errStateRootVerificationFailed) + bc.setHeadBeyondRoot(block.NumberU64()-1, common.Hash{}) + } +} + // SetHeadBeyondRoot rewinds the local chain to a new head with the extra condition // that the rewind must pass the specified state root. This method is meant to be // used when rewinding with snapshots enabled to ensure that we go back further than @@ -588,7 +620,10 @@ func (bc *BlockChain) SetHead(head uint64) error { func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64, error) { bc.chainmu.Lock() defer bc.chainmu.Unlock() + return bc.setHeadBeyondRoot(head, root) +} +func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash) (uint64, error) { // Track the block number of the requested root hash var rootNumber uint64 // (no root == always 0) @@ -1056,6 +1091,12 @@ func (bc *BlockChain) HasFastBlock(hash common.Hash, number uint64) bool { // HasState checks if state trie is fully present in the database or not. func (bc *BlockChain) HasState(hash common.Hash) bool { + if bc.pipeCommit && bc.snaps != nil { + // If parent snap is pending on verification, treat it as state exist + if s := bc.snaps.Snapshot(hash); s != nil && !s.Verified() { + return true + } + } _, err := bc.stateCache.OpenTrie(hash) return err == nil } @@ -1667,8 +1708,78 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } wg.Done() }() + + tryCommitTrieDB := func() error { + bc.commitLock.Lock() + defer bc.commitLock.Unlock() + + triedb := bc.stateCache.TrieDB() + // If we're running an archive node, always flush + if bc.cacheConfig.TrieDirtyDisabled { + err := triedb.Commit(block.Root(), false, nil) + if err != nil { + return err + } + } else { + // Full but not archive node, do proper garbage collection + triedb.Reference(block.Root(), common.Hash{}) // metadata reference to keep trie alive + bc.triegc.Push(block.Root(), -int64(block.NumberU64())) + + if current := block.NumberU64(); current > bc.triesInMemory { + // If we exceeded our memory allowance, flush matured singleton nodes to disk + var ( + nodes, imgs = triedb.Size() + limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 + ) + if nodes > limit || imgs > 4*1024*1024 { + triedb.Cap(limit - ethdb.IdealBatchSize) + } + // Find the next state trie we need to commit + chosen := current - bc.triesInMemory + + // If we exceeded out time allowance, flush an entire trie to disk + if bc.gcproc > bc.cacheConfig.TrieTimeLimit { + canWrite := true + if posa, ok := bc.engine.(consensus.PoSA); ok { + if !posa.EnoughDistance(bc, block.Header()) { + canWrite = false + } + } + if canWrite { + // 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+bc.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)/float64(bc.triesInMemory)) + } + // Flush an entire trie and restart the counters + 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 + } + go triedb.Dereference(root.(common.Hash)) + } + } + } + return nil + } + // Commit all cached state changes into underlying memory database. - root, diffLayer, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) + _, diffLayer, err := state.Commit(bc.tryRewindBadBlocks, tryCommitTrieDB) if err != nil { return NonStatTy, err } @@ -1681,69 +1792,9 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. diffLayer.Number = block.NumberU64() bc.cacheDiffLayer(diffLayer) } - triedb := bc.stateCache.TrieDB() - // If we're running an archive node, always flush - if bc.cacheConfig.TrieDirtyDisabled { - if err := triedb.Commit(root, false, nil); err != nil { - return NonStatTy, err - } - } else { - // Full but not archive node, do proper garbage collection - triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive - bc.triegc.Push(root, -int64(block.NumberU64())) - - if current := block.NumberU64(); current > bc.triesInMemory { - // If we exceeded our memory allowance, flush matured singleton nodes to disk - var ( - nodes, imgs = triedb.Size() - limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 - ) - if nodes > limit || imgs > 4*1024*1024 { - triedb.Cap(limit - ethdb.IdealBatchSize) - } - // Find the next state trie we need to commit - chosen := current - bc.triesInMemory - - // If we exceeded out time allowance, flush an entire trie to disk - if bc.gcproc > bc.cacheConfig.TrieTimeLimit { - canWrite := true - if posa, ok := bc.engine.(consensus.PoSA); ok { - if !posa.EnoughDistance(bc, block.Header()) { - canWrite = false - } - } - if canWrite { - // 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+bc.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)/float64(bc.triesInMemory)) - } - // Flush an entire trie and restart the counters - 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 - } - go triedb.Dereference(root.(common.Hash)) - } - } - } wg.Wait() + // If the total difficulty is higher than our known, add it to the canonical chain // Second clause in the if statement reduces the vulnerability to selfish mining. // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf @@ -2068,6 +2119,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er } //Process block using the parent state as reference point substart := time.Now() + if bc.pipeCommit { + statedb.EnablePipeCommit() + } + statedb.SetExpectedStateRoot(block.Root()) statedb, receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) atomic.StoreUint32(&followupInterrupt, 1) activeState = statedb @@ -2088,7 +2143,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er // Validate the state using the default validator substart = time.Now() if !statedb.IsLightProcessed() { - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, bc.pipeCommit); err != nil { log.Error("validate state failed", "error", err) bc.reportBlock(block, receipts, err) return it.index, err @@ -2503,6 +2558,19 @@ func (bc *BlockChain) update() { } } +func (bc *BlockChain) rewindInvalidHeaderBlockLoop() { + recheck := time.NewTicker(rewindBadBlockInterval) + defer recheck.Stop() + for { + select { + case <-recheck.C: + bc.tryRewindBadBlocks() + case <-bc.quit: + return + } + } +} + func (bc *BlockChain) trustedDiffLayerLoop() { recheck := time.NewTicker(diffLayerFreezerRecheckInterval) bc.wg.Add(1) @@ -2839,6 +2907,18 @@ func (bc *BlockChain) maintainTxIndex(ancients uint64) { } } +func (bc *BlockChain) isCachedBadBlock(block *types.Block) bool { + if timeAt, exist := bc.badBlockCache.Get(block.Hash()); exist { + putAt := timeAt.(time.Time) + if time.Since(putAt) >= badBlockCacheExpire { + bc.badBlockCache.Remove(block.Hash()) + return false + } + return true + } + return false +} + // reportBlock logs a bad block error. func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) { rawdb.WriteBadBlock(bc.db, block) @@ -3009,6 +3089,11 @@ func EnableLightProcessor(bc *BlockChain) *BlockChain { return bc } +func EnablePipelineCommit(bc *BlockChain) *BlockChain { + bc.pipeCommit = true + return bc +} + func EnablePersistDiff(limit uint64) BlockChainOption { return func(chain *BlockChain) *BlockChain { chain.diffLayerFreezerBlockLimit = limit diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index 451a966589..2575843a92 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -317,6 +317,9 @@ func TestProcessDiffLayer(t *testing.T) { lightBackend.Chain().HandleDiffLayer(diff, "testpid", true) } _, err := lightBackend.chain.insertChain([]*types.Block{block}, true) + if err != nil { + t.Errorf("failed to insert block %v", err) + } if checks, exist := checkBlocks[i]; exist { for _, check := range checks.txs { s, _ := lightBackend.Chain().Snapshots().Snapshot(block.Root()).Storage(crypto.Keccak256Hash((*check.to)[:]), check.slot) @@ -325,9 +328,6 @@ func TestProcessDiffLayer(t *testing.T) { } } } - if err != nil { - t.Errorf("failed to insert block %v", err) - } } currentBlock := lightBackend.chain.CurrentBlock() nextBlock := fullBackend.chain.GetBlockByNumber(currentBlock.NumberU64() + 1) @@ -368,7 +368,7 @@ func TestFreezeDiffLayer(t *testing.T) { // Wait for the buffer to be zero. } // Minus one empty block. - if fullBackend.chain.diffQueue.Size() != blockNum-1 { + if fullBackend.chain.diffQueue.Size() > blockNum-1 && fullBackend.chain.diffQueue.Size() < blockNum-2 { t.Errorf("size of diff queue is wrong, expected: %d, get: %d", blockNum-1, fullBackend.chain.diffQueue.Size()) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 8078db774f..50d02e0acc 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -43,7 +43,8 @@ import ( // So we can deterministically seed different blockchains var ( canonicalSeed = 1 - forkSeed = 2 + forkSeed1 = 2 + forkSeed2 = 3 TestTriesInMemory = 128 ) @@ -51,14 +52,18 @@ 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) { +func newCanonical(engine consensus.Engine, n int, full, pipeline bool) (ethdb.Database, *BlockChain, error) { var ( db = rawdb.NewMemoryDatabase() genesis = new(Genesis).MustCommit(db) ) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + var ops []BlockChainOption + if pipeline { + ops = append(ops, EnablePipelineCommit) + } + blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, ops...) // Create and inject the requested chain if n == 0 { return db, blockchain, nil @@ -76,9 +81,53 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B } // 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)) { +func testInvalidStateRootBlockImport(t *testing.T, blockchain *BlockChain, i, n int, pipeline bool) { // Copy old chain up to #i into a new db - db, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) + db, blockchain2, err := newCanonical(ethash.NewFaker(), i, true, pipeline) + if err != nil { + t.Fatal("could not make new canonical in testFork", err) + } + defer blockchain2.Stop() + + // Assert the chains have the same header/block at #i + hash1 := blockchain.GetBlockByNumber(uint64(i)).Hash() + hash2 := blockchain2.GetBlockByNumber(uint64(i)).Hash() + if hash1 != hash2 { + t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", i, hash2, hash1) + } + // Extend the newly created chain + blockChainB := makeBlockChain(blockchain2.CurrentBlock(), n, ethash.NewFaker(), db, forkSeed1) + for idx, block := range blockChainB { + block.SetRoot(common.Hash{0: byte(forkSeed1), 19: byte(idx)}) + } + previousBlock := blockchain.CurrentBlock() + // Sanity check that the forked chain can be imported into the original + if _, err := blockchain.InsertChain(blockChainB); err == nil { + t.Fatalf("failed to report insert error") + } + + time.Sleep(2 * rewindBadBlockInterval) + latestBlock := blockchain.CurrentBlock() + if latestBlock.Hash() != previousBlock.Hash() || latestBlock.NumberU64() != previousBlock.NumberU64() { + t.Fatalf("rewind do not take effect") + } + db, blockchain3, err := newCanonical(ethash.NewFaker(), i, true, pipeline) + if err != nil { + t.Fatal("could not make new canonical in testFork", err) + } + defer blockchain3.Stop() + + blockChainC := makeBlockChain(blockchain3.CurrentBlock(), n, ethash.NewFaker(), db, forkSeed2) + + if _, err := blockchain.InsertChain(blockChainC); err != nil { + t.Fatalf("failed to insert forking chain: %v", err) + } +} + +// Test fork of length N starting from block i +func testFork(t *testing.T, blockchain *BlockChain, i, n int, full, pipeline 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, pipeline) if err != nil { t.Fatal("could not make new canonical in testFork", err) } @@ -102,12 +151,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.CurrentBlock(), n, ethash.NewFaker(), db, forkSeed1) 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.CurrentHeader(), n, ethash.NewFaker(), db, forkSeed1) if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } @@ -117,7 +166,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara if full { tdPre = blockchain.GetTdByHash(blockchain.CurrentBlock().Hash()) - if err := testBlockChainImport(blockChainB, blockchain); err != nil { + if err := testBlockChainImport(blockChainB, pipeline, blockchain); err != nil { t.Fatalf("failed to import forked block chain: %v", err) } tdPost = blockchain.GetTdByHash(blockChainB[len(blockChainB)-1].Hash()) @@ -134,7 +183,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara // testBlockChainImport tries to process a chain of blocks, writing them into // the database if successful. -func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { +func testBlockChainImport(chain types.Blocks, pipelineCommit bool, blockchain *BlockChain) error { for _, block := range chain { // Try and process the block err := blockchain.engine.VerifyHeader(blockchain, block.Header(), true) @@ -151,12 +200,16 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } + statedb.SetExpectedStateRoot(block.Root()) + if pipelineCommit { + statedb.EnablePipeCommit() + } statedb, receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{}) if err != nil { blockchain.reportBlock(block, receipts, err) return err } - err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas) + err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, pipelineCommit) if err != nil { blockchain.reportBlock(block, receipts, err) return err @@ -164,7 +217,9 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.chainmu.Lock() rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash()))) rawdb.WriteBlock(blockchain.db, block) - statedb.Commit(false) + statedb.Finalise(false) + statedb.AccountsIntermediateRoot() + statedb.Commit(nil) blockchain.chainmu.Unlock() } return nil @@ -187,8 +242,22 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error return nil } +func TestBlockImportVerification(t *testing.T) { + length := 5 + + // Make first chain starting from genesis + _, processor, err := newCanonical(ethash.NewFaker(), length, true, true) + if err != nil { + t.Fatalf("failed to make new canonical chain: %v", err) + } + defer processor.Stop() + // Start fork from current height + processor = EnablePipelineCommit(processor) + testInvalidStateRootBlockImport(t, processor, length, 10, true) +} + func TestLastBlock(t *testing.T) { - _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) + _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true, false) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -205,14 +274,20 @@ func TestLastBlock(t *testing.T) { // Tests that given a starting canonical chain of a given size, it can be extended // with various length chains. -func TestExtendCanonicalHeaders(t *testing.T) { testExtendCanonical(t, false) } -func TestExtendCanonicalBlocks(t *testing.T) { testExtendCanonical(t, true) } +func TestExtendCanonicalHeaders(t *testing.T) { + testExtendCanonical(t, false, false) -func testExtendCanonical(t *testing.T, full bool) { +} +func TestExtendCanonicalBlocks(t *testing.T) { + testExtendCanonical(t, true, false) + testExtendCanonical(t, true, true) +} + +func testExtendCanonical(t *testing.T, full, pipeline bool) { length := 5 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, processor, err := newCanonical(ethash.NewFaker(), length, full, pipeline) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -225,22 +300,25 @@ func testExtendCanonical(t *testing.T, full bool) { } } // Start fork from current height - testFork(t, processor, length, 1, full, better) - testFork(t, processor, length, 2, full, better) - testFork(t, processor, length, 5, full, better) - testFork(t, processor, length, 10, full, better) + testFork(t, processor, length, 1, full, pipeline, better) + testFork(t, processor, length, 2, full, pipeline, better) + testFork(t, processor, length, 5, full, pipeline, better) + testFork(t, processor, length, 10, full, pipeline, better) } // Tests that given a starting canonical chain of a given size, creating shorter // forks do not take canonical ownership. -func TestShorterForkHeaders(t *testing.T) { testShorterFork(t, false) } -func TestShorterForkBlocks(t *testing.T) { testShorterFork(t, true) } +func TestShorterForkHeaders(t *testing.T) { testShorterFork(t, false, false) } +func TestShorterForkBlocks(t *testing.T) { + testShorterFork(t, true, false) + testShorterFork(t, true, true) +} -func testShorterFork(t *testing.T, full bool) { +func testShorterFork(t *testing.T, full, pipeline bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, processor, err := newCanonical(ethash.NewFaker(), length, full, pipeline) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -253,24 +331,30 @@ func testShorterFork(t *testing.T, full bool) { } } // Sum of numbers must be less than `length` for this to be a shorter fork - testFork(t, processor, 0, 3, full, worse) - testFork(t, processor, 0, 7, full, worse) - testFork(t, processor, 1, 1, full, worse) - testFork(t, processor, 1, 7, full, worse) - testFork(t, processor, 5, 3, full, worse) - testFork(t, processor, 5, 4, full, worse) + testFork(t, processor, 0, 3, full, pipeline, worse) + testFork(t, processor, 0, 7, full, pipeline, worse) + testFork(t, processor, 1, 1, full, pipeline, worse) + testFork(t, processor, 1, 7, full, pipeline, worse) + testFork(t, processor, 5, 3, full, pipeline, worse) + testFork(t, processor, 5, 4, full, pipeline, worse) } // Tests that given a starting canonical chain of a given size, creating longer // forks do take canonical ownership. -func TestLongerForkHeaders(t *testing.T) { testLongerFork(t, false) } -func TestLongerForkBlocks(t *testing.T) { testLongerFork(t, true) } +func TestLongerForkHeaders(t *testing.T) { + testLongerFork(t, false, false) +} +func TestLongerForkBlocks(t *testing.T) { + testLongerFork(t, true, false) + testLongerFork(t, true, true) + +} -func testLongerFork(t *testing.T, full bool) { +func testLongerFork(t *testing.T, full, pipeline bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, processor, err := newCanonical(ethash.NewFaker(), length, full, pipeline) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -283,24 +367,28 @@ func testLongerFork(t *testing.T, full bool) { } } // Sum of numbers must be greater than `length` for this to be a longer fork - testFork(t, processor, 0, 11, full, better) - testFork(t, processor, 0, 15, full, better) - testFork(t, processor, 1, 10, full, better) - testFork(t, processor, 1, 12, full, better) - testFork(t, processor, 5, 6, full, better) - testFork(t, processor, 5, 8, full, better) + testFork(t, processor, 0, 11, full, pipeline, better) + testFork(t, processor, 0, 15, full, pipeline, better) + testFork(t, processor, 1, 10, full, pipeline, better) + testFork(t, processor, 1, 12, full, pipeline, better) + testFork(t, processor, 5, 6, full, pipeline, better) + testFork(t, processor, 5, 8, full, pipeline, better) } // Tests that given a starting canonical chain of a given size, creating equal // forks do take canonical ownership. -func TestEqualForkHeaders(t *testing.T) { testEqualFork(t, false) } -func TestEqualForkBlocks(t *testing.T) { testEqualFork(t, true) } +func TestEqualForkHeaders(t *testing.T) { testEqualFork(t, false, false) } +func TestEqualForkBlocks(t *testing.T) { + testEqualFork(t, true, true) + testEqualFork(t, true, false) -func testEqualFork(t *testing.T, full bool) { +} + +func testEqualFork(t *testing.T, full, pipeline bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, processor, err := newCanonical(ethash.NewFaker(), length, full, pipeline) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -313,21 +401,24 @@ func testEqualFork(t *testing.T, full bool) { } } // Sum of numbers must be equal to `length` for this to be an equal fork - testFork(t, processor, 0, 10, full, equal) - testFork(t, processor, 1, 9, full, equal) - testFork(t, processor, 2, 8, full, equal) - testFork(t, processor, 5, 5, full, equal) - testFork(t, processor, 6, 4, full, equal) - testFork(t, processor, 9, 1, full, equal) + testFork(t, processor, 0, 10, full, pipeline, equal) + testFork(t, processor, 1, 9, full, pipeline, equal) + testFork(t, processor, 2, 8, full, pipeline, equal) + testFork(t, processor, 5, 5, full, pipeline, equal) + testFork(t, processor, 6, 4, full, pipeline, equal) + testFork(t, processor, 9, 1, full, pipeline, equal) } // Tests that chains missing links do not get accepted by the processor. -func TestBrokenHeaderChain(t *testing.T) { testBrokenChain(t, false) } -func TestBrokenBlockChain(t *testing.T) { testBrokenChain(t, true) } +func TestBrokenHeaderChain(t *testing.T) { testBrokenChain(t, false, false) } +func TestBrokenBlockChain(t *testing.T) { + testBrokenChain(t, true, false) + testBrokenChain(t, true, true) +} -func testBrokenChain(t *testing.T, full bool) { +func testBrokenChain(t *testing.T, full, pipeline bool) { // Make chain starting from genesis - db, blockchain, err := newCanonical(ethash.NewFaker(), 10, full) + db, blockchain, err := newCanonical(ethash.NewFaker(), 10, full, pipeline) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -335,12 +426,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:] - if err := testBlockChainImport(chain, blockchain); err == nil { + chain := makeBlockChain(blockchain.CurrentBlock(), 5, ethash.NewFaker(), db, forkSeed1)[1:] + if err := testBlockChainImport(chain, pipeline, blockchain); err == nil { t.Errorf("broken block chain not reported") } } else { - chain := makeHeaderChain(blockchain.CurrentHeader(), 5, ethash.NewFaker(), db, forkSeed)[1:] + chain := makeHeaderChain(blockchain.CurrentHeader(), 5, ethash.NewFaker(), db, forkSeed1)[1:] if err := testHeaderChainImport(chain, blockchain); err == nil { t.Errorf("broken header chain not reported") } @@ -349,19 +440,25 @@ func testBrokenChain(t *testing.T, full bool) { // Tests that reorganising a long difficult chain after a short easy one // overwrites the canonical numbers and links in the database. -func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) } -func TestReorgLongBlocks(t *testing.T) { testReorgLong(t, true) } +func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false, false) } +func TestReorgLongBlocks(t *testing.T) { + testReorgLong(t, true, false) + testReorgLong(t, true, true) +} -func testReorgLong(t *testing.T, full bool) { - testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280, full) +func testReorgLong(t *testing.T, full, pipeline bool) { + testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280, full, pipeline) } // Tests that reorganising a short difficult chain after a long easy one // overwrites the canonical numbers and links in the database. -func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false) } -func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) } +func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false, false) } +func TestReorgShortBlocks(t *testing.T) { + testReorgShort(t, true, false) + testReorgShort(t, true, true) +} -func testReorgShort(t *testing.T, full bool) { +func testReorgShort(t *testing.T, full, pipeline 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. @@ -373,12 +470,12 @@ func testReorgShort(t *testing.T, full bool) { for i := 0; i < len(diff); i++ { diff[i] = -9 } - testReorg(t, easy, diff, 12615120, full) + testReorg(t, easy, diff, 12615120, full, pipeline) } -func testReorg(t *testing.T, first, second []int64, td int64, full bool) { +func testReorg(t *testing.T, first, second []int64, td int64, full, pipeline bool) { // Create a pristine chain and database - db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, pipeline) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -444,12 +541,16 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) { } // Tests that the insertion functions detect banned hashes. -func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) } -func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } +func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false, false) } +func TestBadBlockHashes(t *testing.T) { + testBadHashes(t, true, true) + testBadHashes(t, true, false) + +} -func testBadHashes(t *testing.T, full bool) { +func testBadHashes(t *testing.T, full, pipeline bool) { // Create a pristine chain and database - db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, pipeline) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -478,12 +579,16 @@ func testBadHashes(t *testing.T, full bool) { // Tests that bad hashes are detected on boot, and the chain rolled back to a // good state prior to the bad hash. -func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) } -func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } +func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false, false) } +func TestReorgBadBlockHashes(t *testing.T) { + testReorgBadHashes(t, true, false) + testReorgBadHashes(t, true, true) -func testReorgBadHashes(t *testing.T, full bool) { +} + +func testReorgBadHashes(t *testing.T, full, pipeline bool) { // Create a pristine chain and database - db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, pipeline) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -533,13 +638,16 @@ func testReorgBadHashes(t *testing.T, full bool) { } // Tests chain insertions in the face of one entity containing an invalid nonce. -func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false) } -func TestBlocksInsertNonceError(t *testing.T) { testInsertNonceError(t, true) } +func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false, false) } +func TestBlocksInsertNonceError(t *testing.T) { + testInsertNonceError(t, true, false) + testInsertNonceError(t, true, true) +} -func testInsertNonceError(t *testing.T, full bool) { +func testInsertNonceError(t *testing.T, full, pipeline bool) { for i := 1; i < 25 && !t.Failed(); i++ { // Create a pristine chain and database - db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, pipeline) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -1212,7 +1320,7 @@ 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) + _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true, false) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } diff --git a/core/chain_makers.go b/core/chain_makers.go index d8e3ee012f..0e3f9256e2 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -223,7 +223,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse block, _, _ := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) // Write state changes to db - root, _, err := statedb.Commit(config.IsEIP158(b.header.Number)) + root, _, err := statedb.Commit(nil) if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } @@ -254,9 +254,9 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S } else { time = parent.Time() + 10 // block time is fixed at 10 seconds } - + root := state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())) return &types.Header{ - Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())), + Root: root, ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), Difficulty: engine.CalcDifficulty(chain, time, &types.Header{ diff --git a/core/error.go b/core/error.go index 1fbd0d599b..0830a699fe 100644 --- a/core/error.go +++ b/core/error.go @@ -34,6 +34,9 @@ var ( // ErrDiffLayerNotFound is returned when diff layer not found. ErrDiffLayerNotFound = errors.New("diff layer not found") + + // ErrKnownBadBlock is return when the block is a known bad block + ErrKnownBadBlock = errors.New("already known bad block") ) // List of evm-call-message pre-checking errors. All state transition messages will diff --git a/core/genesis.go b/core/genesis.go index 9303522947..94bb06dd77 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -298,7 +298,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { if g.Difficulty == nil { head.Difficulty = params.GenesisDifficulty } - statedb.Commit(false) + statedb.Commit(nil) statedb.Database().TrieDB().Commit(root, true, nil) return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)) diff --git a/core/state/database.go b/core/state/database.go index b65dfca158..487589324c 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -257,6 +257,9 @@ func (db *cachingDB) Purge() { // CopyTrie returns an independent copy of the given trie. func (db *cachingDB) CopyTrie(t Trie) Trie { + if t == nil { + return nil + } switch t := t.(type) { case *trie.SecureTrie: return t.Copy() diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index c0f0dab568..65b2729d9c 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -118,6 +118,9 @@ type diffLayer struct { storageList map[common.Hash][]common.Hash // List of storage slots for iterated retrievals, one per account. Any existing lists are sorted if non-nil storageData map[common.Hash]map[common.Hash][]byte // Keyed storage slots for direct retrieval. one per account (nil means deleted) + verifiedCh chan struct{} // the difflayer is verified when verifiedCh is nil or closed + valid bool // mark the difflayer is valid or not. + diffed *bloomfilter.Filter // Bloom filter tracking all the diffed items up to the disk layer lock sync.RWMutex @@ -168,7 +171,7 @@ func (h storageBloomHasher) Sum64() uint64 { // newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low // level persistent database or a hierarchical diff already. -func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { +func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte, verified chan struct{}) *diffLayer { // Create the new layer with some pre-allocated data segments dl := &diffLayer{ parent: parent, @@ -177,6 +180,7 @@ func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]s accountData: accounts, storageData: storage, storageList: make(map[common.Hash][]common.Hash), + verifiedCh: verified, } switch parent := parent.(type) { case *diskLayer: @@ -256,6 +260,32 @@ func (dl *diffLayer) Root() common.Hash { return dl.root } +// WaitAndGetVerifyRes will wait until the diff layer been verified and return the verification result +func (dl *diffLayer) WaitAndGetVerifyRes() bool { + if dl.verifiedCh == nil { + return true + } + <-dl.verifiedCh + return dl.valid +} + +func (dl *diffLayer) MarkValid() { + dl.valid = true +} + +// Represent whether the difflayer is been verified, does not means it is a valid or invalid difflayer +func (dl *diffLayer) Verified() bool { + if dl.verifiedCh == nil { + return true + } + select { + case <-dl.verifiedCh: + return true + default: + return false + } +} + // Parent returns the subsequent layer of a diff layer. func (dl *diffLayer) Parent() snapshot { return dl.parent @@ -423,8 +453,8 @@ func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([ // Update creates a new layer on top of the existing snapshot diff tree with // the specified data items. -func (dl *diffLayer) Update(blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { - return newDiffLayer(dl, blockRoot, destructs, accounts, storage) +func (dl *diffLayer) Update(blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte, verified chan struct{}) *diffLayer { + return newDiffLayer(dl, blockRoot, destructs, accounts, storage, verified) } // flatten pushes all data from this point downwards, flattening everything into diff --git a/core/state/snapshot/difflayer_test.go b/core/state/snapshot/difflayer_test.go index 919af5fa86..5311a0d689 100644 --- a/core/state/snapshot/difflayer_test.go +++ b/core/state/snapshot/difflayer_test.go @@ -79,11 +79,11 @@ func TestMergeBasics(t *testing.T) { } } // Add some (identical) layers on top - parent := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) - child := newDiffLayer(parent, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) - child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) - child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) - child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) + parent := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage), nil) + child := newDiffLayer(parent, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage), nil) + child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage), nil) + child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage), nil) + child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage), nil) // And flatten merged := (child.flatten()).(*diffLayer) @@ -151,13 +151,13 @@ func TestMergeDelete(t *testing.T) { } } // Add some flipAccs-flopping layers on top - parent := newDiffLayer(emptyLayer(), common.Hash{}, flipDrops(), flipAccs(), storage) - child := parent.Update(common.Hash{}, flopDrops(), flopAccs(), storage) - child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage) - child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage) - child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage) - child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage) - child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage) + parent := newDiffLayer(emptyLayer(), common.Hash{}, flipDrops(), flipAccs(), storage, nil) + child := parent.Update(common.Hash{}, flopDrops(), flopAccs(), storage, nil) + child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage, nil) + child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage, nil) + child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage, nil) + child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage, nil) + child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage, nil) if data, _ := child.Account(h1); data == nil { t.Errorf("last diff layer: expected %x account to be non-nil", h1) @@ -209,7 +209,7 @@ func TestInsertAndMerge(t *testing.T) { accounts = make(map[common.Hash][]byte) storage = make(map[common.Hash]map[common.Hash][]byte) ) - parent = newDiffLayer(emptyLayer(), common.Hash{}, destructs, accounts, storage) + parent = newDiffLayer(emptyLayer(), common.Hash{}, destructs, accounts, storage, nil) } { var ( @@ -220,7 +220,7 @@ func TestInsertAndMerge(t *testing.T) { accounts[acc] = randomAccount() storage[acc] = make(map[common.Hash][]byte) storage[acc][slot] = []byte{0x01} - child = newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + child = newDiffLayer(parent, common.Hash{}, destructs, accounts, storage, nil) } // And flatten merged := (child.flatten()).(*diffLayer) @@ -256,7 +256,7 @@ func BenchmarkSearch(b *testing.B) { for i := 0; i < 10000; i++ { accounts[randomHash()] = randomAccount() } - return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage, nil) } var layer snapshot layer = emptyLayer() @@ -298,7 +298,7 @@ func BenchmarkSearchSlot(b *testing.B) { accStorage[randomHash()] = value storage[accountKey] = accStorage } - return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage, nil) } var layer snapshot layer = emptyLayer() @@ -336,7 +336,7 @@ func BenchmarkFlatten(b *testing.B) { } storage[accountKey] = accStorage } - return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage, nil) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -386,7 +386,7 @@ func BenchmarkJournal(b *testing.B) { } storage[accountKey] = accStorage } - return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage, nil) } layer := snapshot(new(diskLayer)) for i := 1; i < 128; i++ { diff --git a/core/state/snapshot/disklayer.go b/core/state/snapshot/disklayer.go index 7cbf6e293d..c1de41782c 100644 --- a/core/state/snapshot/disklayer.go +++ b/core/state/snapshot/disklayer.go @@ -49,6 +49,16 @@ func (dl *diskLayer) Root() common.Hash { return dl.root } +func (dl *diskLayer) WaitAndGetVerifyRes() bool { + return true +} + +func (dl *diskLayer) MarkValid() {} + +func (dl *diskLayer) Verified() bool { + return true +} + // Parent always returns nil as there's no layer below the disk. func (dl *diskLayer) Parent() snapshot { return nil @@ -161,6 +171,6 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro // Update creates a new layer on top of the existing snapshot diff tree with // the specified data items. Note, the maps are retained by the method to avoid // copying everything. -func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { - return newDiffLayer(dl, blockHash, destructs, accounts, storage) +func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte, verified chan struct{}) *diffLayer { + return newDiffLayer(dl, blockHash, destructs, accounts, storage, verified) } diff --git a/core/state/snapshot/disklayer_test.go b/core/state/snapshot/disklayer_test.go index 362edba90d..689ed38773 100644 --- a/core/state/snapshot/disklayer_test.go +++ b/core/state/snapshot/disklayer_test.go @@ -134,7 +134,7 @@ func TestDiskMerge(t *testing.T) { conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])}, conDelNoCache: {conDelNoCacheSlot: nil}, conDelCache: {conDelCacheSlot: nil}, - }); err != nil { + }, nil); err != nil { t.Fatalf("failed to update snapshot tree: %v", err) } if err := snaps.Cap(diffRoot, 0); err != nil { @@ -357,7 +357,7 @@ func TestDiskPartialMerge(t *testing.T) { conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])}, conDelNoCache: {conDelNoCacheSlot: nil}, conDelCache: {conDelCacheSlot: nil}, - }); err != nil { + }, nil); err != nil { t.Fatalf("test %d: failed to update snapshot tree: %v", i, err) } if err := snaps.Cap(diffRoot, 0); err != nil { @@ -468,7 +468,7 @@ func TestDiskGeneratorPersistence(t *testing.T) { // Modify or delete some accounts, flatten everything onto disk if err := snaps.update(diffRoot, baseRoot, nil, map[common.Hash][]byte{ accTwo: accTwo[:], - }, nil); err != nil { + }, nil, nil); err != nil { t.Fatalf("failed to update snapshot tree: %v", err) } if err := snaps.Cap(diffRoot, 0); err != nil { @@ -488,7 +488,7 @@ func TestDiskGeneratorPersistence(t *testing.T) { accThree: accThree.Bytes(), }, map[common.Hash]map[common.Hash][]byte{ accThree: {accThreeSlot: accThreeSlot.Bytes()}, - }); err != nil { + }, nil); err != nil { t.Fatalf("failed to update snapshot tree: %v", err) } diskLayer := snaps.layers[snaps.diskRoot()].(*diskLayer) diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index 2a27b01577..3ffaff32ed 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -53,7 +53,7 @@ func TestAccountIteratorBasics(t *testing.T) { } } // Add some (identical) layers on top - diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) + diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage), nil) it := diffLayer.AccountIterator(common.Hash{}) verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator @@ -91,7 +91,7 @@ func TestStorageIteratorBasics(t *testing.T) { nilStorage[h] = nilstorage } // Add some (identical) layers on top - diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, nil, copyAccounts(accounts), copyStorage(storage)) + diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, nil, copyAccounts(accounts), copyStorage(storage), nil) for account := range accounts { it, _ := diffLayer.StorageIterator(account, common.Hash{}) verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator @@ -222,13 +222,13 @@ func TestAccountIteratorTraversal(t *testing.T) { } // Stack three diff layers on top with various overlaps snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, - randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) + randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil) snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, - randomAccountSet("0xbb", "0xdd", "0xf0"), nil) + randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil) snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, - randomAccountSet("0xcc", "0xf0", "0xff"), nil) + randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil) // Verify the single and multi-layer iterators head := snaps.Snapshot(common.HexToHash("0x04")) @@ -269,13 +269,13 @@ func TestStorageIteratorTraversal(t *testing.T) { } // Stack three diff layers on top with various overlaps snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil)) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil), nil) snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil)) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil), nil) snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil)) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil), nil) // Verify the single and multi-layer iterators head := snaps.Snapshot(common.HexToHash("0x04")) @@ -353,14 +353,14 @@ func TestAccountIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, a, nil) - snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, b, nil) - snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, c, nil) - snaps.update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, d, nil) - snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, e, nil) - snaps.update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, f, nil) - snaps.update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, g, nil) - snaps.update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, h, nil) + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, a, nil, nil) + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, b, nil, nil) + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, c, nil, nil) + snaps.update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, d, nil, nil) + snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, e, nil, nil) + snaps.update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, f, nil, nil) + snaps.update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, g, nil, nil) + snaps.update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, h, nil, nil) it, _ := snaps.AccountIterator(common.HexToHash("0x09"), common.Hash{}) head := snaps.Snapshot(common.HexToHash("0x09")) @@ -452,14 +452,14 @@ func TestStorageIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), wrapStorage(a)) - snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), wrapStorage(b)) - snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), wrapStorage(c)) - snaps.update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), wrapStorage(d)) - snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, randomAccountSet("0xaa"), wrapStorage(e)) - snaps.update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, randomAccountSet("0xaa"), wrapStorage(e)) - snaps.update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, randomAccountSet("0xaa"), wrapStorage(g)) - snaps.update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, randomAccountSet("0xaa"), wrapStorage(h)) + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), wrapStorage(a), nil) + snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), wrapStorage(b), nil) + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), wrapStorage(c), nil) + snaps.update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), wrapStorage(d), nil) + snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, randomAccountSet("0xaa"), wrapStorage(e), nil) + snaps.update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, randomAccountSet("0xaa"), wrapStorage(e), nil) + snaps.update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, randomAccountSet("0xaa"), wrapStorage(g), nil) + snaps.update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, randomAccountSet("0xaa"), wrapStorage(h), nil) it, _ := snaps.StorageIterator(common.HexToHash("0x09"), common.HexToHash("0xaa"), common.Hash{}) head := snaps.Snapshot(common.HexToHash("0x09")) @@ -522,7 +522,7 @@ func TestAccountIteratorLargeTraversal(t *testing.T) { }, } for i := 1; i < 128; i++ { - snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) + snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil, nil) } // Iterate the entire stack and ensure everything is hit only once head := snaps.Snapshot(common.HexToHash("0x80")) @@ -567,13 +567,13 @@ func TestAccountIteratorFlattening(t *testing.T) { } // Create a stack of diffs on top snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, - randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) + randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil) snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, - randomAccountSet("0xbb", "0xdd", "0xf0"), nil) + randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil) snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, - randomAccountSet("0xcc", "0xf0", "0xff"), nil) + randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil) // Create an iterator and flatten the data from underneath it it, _ := snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{}) @@ -598,13 +598,13 @@ func TestAccountIteratorSeek(t *testing.T) { }, } snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, - randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) + randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil) snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, - randomAccountSet("0xbb", "0xdd", "0xf0"), nil) + randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil) snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, - randomAccountSet("0xcc", "0xf0", "0xff"), nil) + randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil) // Account set is now // 02: aa, ee, f0, ff @@ -662,13 +662,13 @@ func TestStorageIteratorSeek(t *testing.T) { } // Stack three diff layers on top with various overlaps snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil)) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil), nil) snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil)) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil), nil) snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil)) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil), nil) // Account set is now // 02: 01, 03, 05 @@ -725,17 +725,17 @@ func TestAccountIteratorDeletions(t *testing.T) { } // Stack three diff layers on top with various overlaps snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), - nil, randomAccountSet("0x11", "0x22", "0x33"), nil) + nil, randomAccountSet("0x11", "0x22", "0x33"), nil, nil) deleted := common.HexToHash("0x22") destructed := map[common.Hash]struct{}{ deleted: {}, } snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), - destructed, randomAccountSet("0x11", "0x33"), nil) + destructed, randomAccountSet("0x11", "0x33"), nil, nil) snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), - nil, randomAccountSet("0x33", "0x44", "0x55"), nil) + nil, randomAccountSet("0x33", "0x44", "0x55"), nil, nil) // The output should be 11,33,44,55 it, _ := snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{}) @@ -771,10 +771,10 @@ func TestStorageIteratorDeletions(t *testing.T) { } // Stack three diff layers on top with various overlaps snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil)) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil), nil) snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}})) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}}), nil) // The output should be 02,04,05,06 it, _ := snaps.StorageIterator(common.HexToHash("0x03"), common.HexToHash("0xaa"), common.Hash{}) @@ -790,7 +790,7 @@ func TestStorageIteratorDeletions(t *testing.T) { destructed := map[common.Hash]struct{}{ common.HexToHash("0xaa"): {}, } - snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), destructed, nil, nil) + snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), destructed, nil, nil, nil) it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 0, it, verifyStorage) @@ -798,7 +798,7 @@ func TestStorageIteratorDeletions(t *testing.T) { // Re-insert the slots of the same account snaps.update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, - randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil)) + randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil), nil) // The output should be 07,08,09 it, _ = snaps.StorageIterator(common.HexToHash("0x05"), common.HexToHash("0xaa"), common.Hash{}) @@ -806,7 +806,7 @@ func TestStorageIteratorDeletions(t *testing.T) { it.Release() // Destruct the whole storage but re-create the account in the same layer - snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil)) + snaps.update(common.HexToHash("0x06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil), nil) it, _ = snaps.StorageIterator(common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12 it.Release() @@ -848,7 +848,7 @@ func BenchmarkAccountIteratorTraversal(b *testing.B) { }, } for i := 1; i <= 100; i++ { - snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) + snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil, nil) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. @@ -943,9 +943,9 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) { base.root: base, }, } - snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil) + snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil, nil) for i := 2; i <= 100; i++ { - snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil) + snaps.update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil, nil) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 5cfb9a9f2a..35c69cfd6b 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -243,7 +243,7 @@ func loadDiffLayer(parent snapshot, r *rlp.Stream) (snapshot, error) { } storageData[entry.Hash] = slots } - return loadDiffLayer(newDiffLayer(parent, root, destructSet, accountData, storageData), r) + return loadDiffLayer(newDiffLayer(parent, root, destructSet, accountData, storageData, nil), r) } // Journal terminates any in-progress snapshot generation, also implicitly pushing diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 46d1b06def..8ac93f28e4 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -101,6 +101,15 @@ type Snapshot interface { // Root returns the root hash for which this snapshot was made. Root() common.Hash + // WaitAndGetVerifyRes will wait until the snapshot been verified and return verification result + WaitAndGetVerifyRes() bool + + // Verified returns whether the snapshot is verified + Verified() bool + + // Store the verification result + MarkValid() + // Account directly retrieves the account associated with a particular hash in // the snapshot slim data format. Account(hash common.Hash) (*Account, error) @@ -130,7 +139,7 @@ type snapshot interface { // the specified data items. // // Note, the maps are retained by the method to avoid copying everything. - Update(blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer + Update(blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte, verified chan struct{}) *diffLayer // Journal commits an entire diff hierarchy to disk into a single journal entry. // This is meant to be used during shutdown to persist the snapshot without @@ -322,14 +331,14 @@ func (t *Tree) Snapshots(root common.Hash, limits int, nodisk bool) []Snapshot { return ret } -func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Address]struct{}, accounts map[common.Address][]byte, storage map[common.Address]map[string][]byte) error { +func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Address]struct{}, accounts map[common.Address][]byte, storage map[common.Address]map[string][]byte, verified chan struct{}) error { hashDestructs, hashAccounts, hashStorage := transformSnapData(destructs, accounts, storage) - return t.update(blockRoot, parentRoot, hashDestructs, hashAccounts, hashStorage) + return t.update(blockRoot, parentRoot, hashDestructs, hashAccounts, hashStorage, verified) } // Update adds a new snapshot into the tree, if that can be linked to an existing // old parent. It is disallowed to insert a disk layer (the origin of all). -func (t *Tree) update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { +func (t *Tree) update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte, verified chan struct{}) error { // Reject noop updates to avoid self-loops in the snapshot tree. This is a // special case that can only happen for Clique networks where empty blocks // don't modify the state (0 block subsidy). @@ -344,7 +353,7 @@ func (t *Tree) update(blockRoot common.Hash, parentRoot common.Hash, destructs m if parent == nil { return fmt.Errorf("parent [%#x] snapshot missing", parentRoot) } - snap := parent.(snapshot).Update(blockRoot, destructs, accounts, storage) + snap := parent.(snapshot).Update(blockRoot, destructs, accounts, storage, verified) // Save the new snapshot for later t.lock.Lock() diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index f8ced63665..187186a3be 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -105,7 +105,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 2 { @@ -149,10 +149,10 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 3 { @@ -197,13 +197,13 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, accounts, nil); err != nil { + if err := snaps.update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, accounts, nil, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 4 { @@ -257,12 +257,12 @@ func TestPostCapBasicDataAccess(t *testing.T) { }, } // The lowest difflayer - snaps.update(common.HexToHash("0xa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil) - snaps.update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil) - snaps.update(common.HexToHash("0xb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil) + snaps.update(common.HexToHash("0xa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil, nil) + snaps.update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil, nil) + snaps.update(common.HexToHash("0xb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil, nil) - snaps.update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil) - snaps.update(common.HexToHash("0xb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil) + snaps.update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil, nil) + snaps.update(common.HexToHash("0xb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil, nil) // checkExist verifies if an account exiss in a snapshot checkExist := func(layer *diffLayer, key string) error { @@ -357,7 +357,7 @@ func TestSnaphots(t *testing.T) { ) for i := 0; i < 129; i++ { head = makeRoot(uint64(i + 2)) - snaps.update(head, last, nil, setAccount(fmt.Sprintf("%d", i+2)), nil) + snaps.update(head, last, nil, setAccount(fmt.Sprintf("%d", i+2)), nil, nil) last = head snaps.Cap(head, 128) // 130 layers (128 diffs + 1 accumulator + 1 disk) } diff --git a/core/state/state_test.go b/core/state/state_test.go index 77847772c6..4be9ae8ce3 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -54,7 +54,9 @@ func TestDump(t *testing.T) { // write some of them to the trie s.state.updateStateObject(obj1) s.state.updateStateObject(obj2) - s.state.Commit(false) + s.state.Finalise(false) + s.state.AccountsIntermediateRoot() + s.state.Commit(nil) // check that DumpToCollector contains the state objects that are in trie got := string(s.state.Dump(false, false, true)) @@ -95,7 +97,9 @@ func TestNull(t *testing.T) { var value common.Hash s.state.SetState(address, common.Hash{}, value) - s.state.Commit(false) + s.state.Finalise(false) + s.state.AccountsIntermediateRoot() + s.state.Commit(nil) if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) { t.Errorf("expected empty current value, got %x", value) @@ -167,7 +171,9 @@ func TestSnapshot2(t *testing.T) { so0.deleted = false state.SetStateObject(so0) - root, _, _ := state.Commit(false) + state.Finalise(false) + state.AccountsIntermediateRoot() + root, _, _ := state.Commit(nil) state, _ = New(root, state.db, state.snaps) // and one with deleted == true diff --git a/core/state/statedb.go b/core/state/statedb.go index 6f150915ca..5ea84f4032 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -74,14 +74,20 @@ func (n *proofList) Delete(key []byte) error { // * Accounts type StateDB struct { db Database + prefetcherLock sync.Mutex prefetcher *triePrefetcher originalRoot common.Hash // The pre-state root, before any changes were made + expectedRoot common.Hash // The state root in the block header + stateRoot common.Hash // The calculation result of IntermediateRoot + trie Trie hasher crypto.KeccakState diffLayer *types.DiffLayer diffTries map[common.Address]Trie diffCode map[common.Hash][]byte lightProcessed bool + fullProcessed bool + pipeCommit bool snapMux sync.Mutex snaps *snapshot.Tree @@ -154,11 +160,6 @@ func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, journal: newJournal(), hasher: crypto.NewKeccakState(), } - tr, err := db.OpenTrie(root) - if err != nil { - return nil, err - } - sdb.trie = tr if sdb.snaps != nil { if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil { sdb.snapDestructs = make(map[common.Address]struct{}) @@ -166,6 +167,14 @@ func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, sdb.snapStorage = make(map[common.Address]map[string][]byte) } } + + snapVerified := sdb.snap != nil && sdb.snap.Verified() + tr, err := db.OpenTrie(root) + // return error when 1. failed to open trie and 2. the snap is nil or the snap is not nil and done verification + if err != nil && (sdb.snap == nil || snapVerified) { + return nil, err + } + sdb.trie = tr return sdb, nil } @@ -173,6 +182,8 @@ func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. func (s *StateDB) StartPrefetcher(namespace string) { + s.prefetcherLock.Lock() + defer s.prefetcherLock.Unlock() if s.prefetcher != nil { s.prefetcher.close() s.prefetcher = nil @@ -185,17 +196,36 @@ func (s *StateDB) StartPrefetcher(namespace string) { // StopPrefetcher terminates a running prefetcher and reports any leftover stats // from the gathered metrics. func (s *StateDB) StopPrefetcher() { + s.prefetcherLock.Lock() + defer s.prefetcherLock.Unlock() if s.prefetcher != nil { s.prefetcher.close() s.prefetcher = nil } } +// Mark that the block is processed by diff layer +func (s *StateDB) SetExpectedStateRoot(root common.Hash) { + s.expectedRoot = root +} + // Mark that the block is processed by diff layer func (s *StateDB) MarkLightProcessed() { s.lightProcessed = true } +// Enable the pipeline commit function of statedb +func (s *StateDB) EnablePipeCommit() { + if s.snap != nil { + s.pipeCommit = true + } +} + +// Mark that the block is full processed +func (s *StateDB) MarkFullProcessed() { + s.fullProcessed = true +} + func (s *StateDB) IsLightProcessed() bool { return s.lightProcessed } @@ -211,8 +241,20 @@ func (s *StateDB) Error() error { return s.dbErr } -func (s *StateDB) Trie() Trie { - return s.trie +// Not thread safe +func (s *StateDB) Trie() (Trie, error) { + if s.trie == nil { + err := s.WaitPipeVerification() + if err != nil { + return nil, err + } + tr, err := s.db.OpenTrie(s.originalRoot) + if err != nil { + return nil, err + } + s.trie = tr + } + return s.trie, nil } func (s *StateDB) SetDiff(diffLayer *types.DiffLayer, diffTries map[common.Address]Trie, diffCode map[common.Hash][]byte) { @@ -360,6 +402,9 @@ func (s *StateDB) GetProof(addr common.Address) ([][]byte, error) { // GetProofByHash returns the Merkle proof for a given account. func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) { var proof proofList + if _, err := s.Trie(); err != nil { + return nil, err + } err := s.trie.Prove(addrHash[:], 0, &proof) return proof, err } @@ -904,6 +949,17 @@ func (s *StateDB) GetRefund() uint64 { return s.refund } +// GetRefund returns the current value of the refund counter. +func (s *StateDB) WaitPipeVerification() error { + // We need wait for the parent trie to commit + if s.snap != nil { + if valid := s.snap.WaitAndGetVerifyRes(); !valid { + return fmt.Errorf("verification on parent snap failed") + } + } + return nil +} + // Finalise finalises the state by removing the s 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. @@ -963,22 +1019,11 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } // Finalise all the dirty storage states and write them into the tries s.Finalise(deleteEmptyObjects) + s.AccountsIntermediateRoot() + return s.StateIntermediateRoot() +} - // If there was a trie prefetcher operating, it gets aborted and irrevocably - // modified after we start retrieving tries. Remove it from the statedb after - // this round of use. - // - // This is weird pre-byzantium since the first tx runs with a prefetcher and - // the remainder without, but pre-byzantium even the initial prefetcher is - // useless, so no sleep lost. - prefetcher := s.prefetcher - if s.prefetcher != nil { - defer func() { - s.prefetcher.close() - s.prefetcher = nil - }() - } - +func (s *StateDB) AccountsIntermediateRoot() { tasks := make(chan func()) finishCh := make(chan struct{}) defer close(finishCh) @@ -995,6 +1040,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 @@ -1026,6 +1072,27 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } } wg.Wait() +} + +func (s *StateDB) StateIntermediateRoot() common.Hash { + // If there was a trie prefetcher operating, it gets aborted and irrevocably + // modified after we start retrieving tries. Remove it from the statedb after + // this round of use. + // + // This is weird pre-byzantium since the first tx runs with a prefetcher and + // the remainder without, but pre-byzantium even the initial prefetcher is + // useless, so no sleep lost. + prefetcher := s.prefetcher + defer func() { + s.prefetcherLock.Lock() + if s.prefetcher != nil { + s.prefetcher.close() + s.prefetcher = nil + } + // try not use defer inside defer + s.prefetcherLock.Unlock() + }() + // Now we're about to start to write changes to the trie. The trie is so far // _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. @@ -1037,7 +1104,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if s.trie == nil { tr, err := s.db.OpenTrie(s.originalRoot) if err != nil { - panic("Failed to open trie tree") + panic(fmt.Sprintf("Failed to open trie tree %s", s.originalRoot)) } s.trie = tr } @@ -1081,9 +1148,12 @@ func (s *StateDB) clearJournalAndRefund() { s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entires } -func (s *StateDB) LightCommit(root common.Hash) (common.Hash, *types.DiffLayer, error) { +func (s *StateDB) LightCommit() (common.Hash, *types.DiffLayer, error) { codeWriter := s.db.TrieDB().DiskDB().NewBatch() + // light process already verified it, expectedRoot is trustworthy. + root := s.expectedRoot + commitFuncs := []func() error{ func() error { for codeHash, code := range s.diffCode { @@ -1171,7 +1241,8 @@ func (s *StateDB) LightCommit(root common.Hash) (common.Hash, *types.DiffLayer, } // 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 { + // for light commit, always do sync commit + if err := s.snaps.Update(root, parent, s.snapDestructs, s.snapAccounts, s.snapStorage, nil); err != nil { log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) } // Keep n diff layers in the memory @@ -1205,23 +1276,42 @@ func (s *StateDB) LightCommit(root common.Hash) (common.Hash, *types.DiffLayer, } // Commit writes the state to the underlying in-memory trie database. -func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer, error) { +func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() error) (common.Hash, *types.DiffLayer, error) { if s.dbErr != nil { return common.Hash{}, nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) } // Finalize any pending changes and merge everything into the tries - root := s.IntermediateRoot(deleteEmptyObjects) if s.lightProcessed { - return s.LightCommit(root) + root, diff, err := s.LightCommit() + if err != nil { + return root, diff, err + } + for _, postFunc := range postCommitFuncs { + err = postFunc() + if err != nil { + return root, diff, err + } + } + return root, diff, nil } var diffLayer *types.DiffLayer + var verified chan struct{} + var snapUpdated chan struct{} if s.snap != nil { diffLayer = &types.DiffLayer{} } - commitFuncs := []func() error{ - func() error { - // Commit objects to the trie, measuring the elapsed time - tasks := make(chan func(batch ethdb.KeyValueWriter)) + if s.pipeCommit { + // async commit the MPT + verified = make(chan struct{}) + snapUpdated = make(chan struct{}) + } + + commmitTrie := func() error { + commitErr := func() error { + if s.stateRoot = s.StateIntermediateRoot(); s.fullProcessed && s.expectedRoot != s.stateRoot { + return fmt.Errorf("invalid merkle root (remote: %x local: %x)", s.expectedRoot, s.stateRoot) + } + tasks := make(chan func()) taskResults := make(chan error, len(s.stateObjectsDirty)) tasksNum := 0 finishCh := make(chan struct{}) @@ -1232,17 +1322,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer wg.Add(1) go func() { defer wg.Done() - codeWriter := s.db.TrieDB().DiskDB().NewBatch() for { select { case task := <-tasks: - task(codeWriter) + task() case <-finishCh: - if codeWriter.ValueSize() > 0 { - if err := codeWriter.Write(); err != nil { - log.Crit("Failed to commit dirty codes", "error", err) - } - } return } } @@ -1265,11 +1349,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer for addr := range s.stateObjectsDirty { if obj := s.stateObjects[addr]; !obj.deleted { // Write any contract code associated with the state object - tasks <- func(codeWriter ethdb.KeyValueWriter) { - if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) - obj.dirtyCode = false - } + tasks <- func() { // Write any storage changes in the state object to its storage trie if err := obj.CommitTrie(s.db); err != nil { taskResults <- err @@ -1289,14 +1369,6 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer } close(finishCh) - if len(s.stateObjectsDirty) > 0 { - s.stateObjectsDirty = make(map[common.Address]struct{}, len(s.stateObjectsDirty)/2) - } - // Write the account trie changes, measuing the amount of wasted time - var start time.Time - 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 Account @@ -1312,14 +1384,60 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer if err != nil { return err } - if metrics.EnabledExpensive { - s.AccountCommits += time.Since(start) - } if root != emptyRoot { s.db.CacheAccount(root, s.trie) } + for _, postFunc := range postCommitFuncs { + err = postFunc() + if err != nil { + return err + } + } wg.Wait() return nil + }() + + if s.pipeCommit { + if commitErr == nil { + <-snapUpdated + s.snaps.Snapshot(s.stateRoot).MarkValid() + } else { + // The blockchain will do the further rewind if write block not finish yet + if failPostCommitFunc != nil { + <-snapUpdated + failPostCommitFunc() + } + log.Error("state verification failed", "err", commitErr) + } + close(verified) + } + return commitErr + } + + commitFuncs := []func() error{ + func() error { + codeWriter := s.db.TrieDB().DiskDB().NewBatch() + for addr := range s.stateObjectsDirty { + if obj := s.stateObjects[addr]; !obj.deleted { + if obj.code != nil && obj.dirtyCode { + rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) + obj.dirtyCode = false + if codeWriter.ValueSize() > ethdb.IdealBatchSize { + if err := codeWriter.Write(); err != nil { + return err + } + codeWriter.Reset() + } + } + } + } + if codeWriter.ValueSize() > 0 { + if err := codeWriter.Write(); err != nil { + log.Crit("Failed to commit dirty codes", "error", err) + return err + } + } + return nil }, func() error { // If snapshotting is enabled, update the snapshot tree with this new version @@ -1327,18 +1445,23 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer if metrics.EnabledExpensive { defer func(start time.Time) { s.SnapshotCommits += time.Since(start) }(time.Now()) } + if s.pipeCommit { + defer close(snapUpdated) + } // 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 { - log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) + if parent := s.snap.Root(); parent != s.expectedRoot { + if err := s.snaps.Update(s.expectedRoot, parent, s.snapDestructs, s.snapAccounts, s.snapStorage, verified); err != nil { + log.Warn("Failed to update snapshot tree", "from", parent, "to", s.expectedRoot, "err", err) } // Keep n diff layers in the memory // - head layer is paired with HEAD state // - head-1 layer is paired with HEAD-1 state // - head-(n-1) layer(bottom-most diff layer) is paired with HEAD-(n-1)state - if err := s.snaps.Cap(root, s.snaps.CapLimit()); err != nil { - log.Warn("Failed to cap snapshot tree", "root", root, "layers", s.snaps.CapLimit(), "err", err) - } + go func() { + if err := s.snaps.Cap(s.expectedRoot, s.snaps.CapLimit()); err != nil { + log.Warn("Failed to cap snapshot tree", "root", s.expectedRoot, "layers", s.snaps.CapLimit(), "err", err) + } + }() } } return nil @@ -1350,6 +1473,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer return nil }, } + if s.pipeCommit { + go commmitTrie() + } else { + commitFuncs = append(commitFuncs, commmitTrie) + } commitRes := make(chan error, len(commitFuncs)) for _, f := range commitFuncs { tmpFunc := f @@ -1363,7 +1491,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, *types.DiffLayer return common.Hash{}, nil, r } } - s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil + root := s.stateRoot + if s.pipeCommit { + root = s.expectedRoot + } + return root, diffLayer, nil } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 2c0b9296ff..acbbf1cd2f 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -102,7 +102,9 @@ func TestIntermediateLeaks(t *testing.T) { } // Commit and cross check the databases. - transRoot, _, err := transState.Commit(false) + transState.Finalise(false) + transState.AccountsIntermediateRoot() + transRoot, _, err := transState.Commit(nil) if err != nil { t.Fatalf("failed to commit transition state: %v", err) } @@ -110,7 +112,9 @@ func TestIntermediateLeaks(t *testing.T) { t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) } - finalRoot, _, err := finalState.Commit(false) + finalState.Finalise(false) + finalState.AccountsIntermediateRoot() + finalRoot, _, err := finalState.Commit(nil) if err != nil { t.Fatalf("failed to commit final state: %v", err) } @@ -473,7 +477,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { func TestTouchDelete(t *testing.T) { s := newStateTest() s.state.GetOrNewStateObject(common.Address{}) - root, _, _ := s.state.Commit(false) + root, _, _ := s.state.Commit(nil) s.state, _ = New(root, s.state.db, s.state.snaps) snapshot := s.state.Snapshot() @@ -546,7 +550,9 @@ func TestCopyCommitCopy(t *testing.T) { t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) } - copyOne.Commit(false) + copyOne.Finalise(false) + copyOne.AccountsIntermediateRoot() + copyOne.Commit(nil) if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("first copy post-commit balance mismatch: have %v, want %v", balance, 42) } @@ -631,7 +637,10 @@ func TestCopyCopyCommitCopy(t *testing.T) { if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) } - copyTwo.Commit(false) + + copyTwo.Finalise(false) + copyTwo.AccountsIntermediateRoot() + copyTwo.Commit(nil) if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42) } @@ -675,7 +684,9 @@ func TestDeleteCreateRevert(t *testing.T) { addr := common.BytesToAddress([]byte("so")) state.SetBalance(addr, big.NewInt(1)) - root, _, _ := state.Commit(false) + state.Finalise(false) + state.AccountsIntermediateRoot() + root, _, _ := state.Commit(nil) state, _ = New(root, state.db, state.snaps) // Simulate self-destructing in one transaction, then create-reverting in another @@ -686,8 +697,10 @@ func TestDeleteCreateRevert(t *testing.T) { state.SetBalance(addr, big.NewInt(2)) state.RevertToSnapshot(id) + state.Finalise(true) + state.AccountsIntermediateRoot() // Commit the entire state and make sure we don't crash and have the correct state - root, _, _ = state.Commit(true) + root, _, _ = state.Commit(nil) state, _ = New(root, state.db, state.snaps) if state.getStateObject(addr) != nil { @@ -712,7 +725,9 @@ func TestMissingTrieNodes(t *testing.T) { a2 := common.BytesToAddress([]byte("another")) state.SetBalance(a2, big.NewInt(100)) state.SetCode(a2, []byte{1, 2, 4}) - root, _, _ = state.Commit(false) + state.Finalise(false) + state.AccountsIntermediateRoot() + root, _, _ = state.Commit(nil) t.Logf("root: %x", root) // force-flush state.Database().TrieDB().Cap(0) @@ -736,7 +751,9 @@ func TestMissingTrieNodes(t *testing.T) { } // Modify the state state.SetBalance(addr, big.NewInt(2)) - root, _, err := state.Commit(false) + state.Finalise(false) + state.AccountsIntermediateRoot() + root, _, err := state.Commit(nil) if err == nil { t.Fatalf("expected error, got root :%x", root) } diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 24cae59004..fe896791d3 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -69,7 +69,9 @@ func makeTestState() (Database, common.Hash, []*testAccount) { state.updateStateObject(obj) accounts = append(accounts, acc) } - root, _, _ := state.Commit(false) + state.Finalise(false) + state.AccountsIntermediateRoot() + root, _, _ := state.Commit(nil) // Return the generated state return db, root, accounts diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index ddecd7a202..ed60c811d2 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -20,7 +20,6 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" ) @@ -106,7 +105,7 @@ func (p *triePrefetcher) close() { for _, fetcher := range p.fetchers { p.abortChan <- fetcher // safe to do multiple times <-fetcher.term - if metrics.Enabled { + if metrics.EnabledExpensive { if fetcher.root == p.root { p.accountLoadMeter.Mark(int64(len(fetcher.seen))) p.accountDupMeter.Mark(int64(fetcher.dups)) @@ -257,9 +256,7 @@ func newSubfetcher(db Database, root common.Hash, accountHash common.Hash) *subf seen: make(map[string]struct{}), accountHash: accountHash, } - gopool.Submit(func() { - sf.loop() - }) + go sf.loop() return sf } @@ -322,8 +319,7 @@ func (sf *subfetcher) loop() { trie, err = sf.db.OpenStorageTrie(sf.accountHash, sf.root) } if err != nil { - log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) - return + log.Debug("Trie prefetcher failed opening trie", "root", sf.root, "err", err) } sf.trie = trie @@ -332,6 +328,18 @@ func (sf *subfetcher) loop() { select { case <-sf.wake: // Subfetcher was woken up, retrieve any tasks to avoid spinning the lock + if sf.trie == nil { + if sf.accountHash == emptyAddr { + sf.trie, err = sf.db.OpenTrie(sf.root) + } else { + // address is useless + sf.trie, err = sf.db.OpenStorageTrie(sf.accountHash, sf.root) + } + if err != nil { + continue + } + } + sf.lock.Lock() tasks := sf.tasks sf.tasks = nil diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index ec4e7bf972..d559a03a0f 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -17,7 +17,6 @@ package core import ( - "runtime" "sync/atomic" "github.com/ethereum/go-ethereum/consensus" @@ -27,6 +26,8 @@ import ( "github.com/ethereum/go-ethereum/params" ) +const prefetchThread = 2 + // statePrefetcher is a basic Prefetcher, which blindly executes a block on top // of an arbitrary state with the goal of prefetching potentially useful state // data from disk before the main block processor start executing. @@ -54,25 +55,23 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c signer = types.MakeSigner(p.config, header.Number) ) transactions := block.Transactions() - threads := runtime.NumCPU() - batch := len(transactions) / (threads + 1) - if batch == 0 { - return + sortTransactions := make([][]*types.Transaction, prefetchThread) + for i := 0; i < prefetchThread; i++ { + sortTransactions[i] = make([]*types.Transaction, 0, len(transactions)/prefetchThread) + } + for idx := range transactions { + threadIdx := idx % prefetchThread + sortTransactions[threadIdx] = append(sortTransactions[threadIdx], transactions[idx]) } // No need to execute the first batch, since the main processor will do it. - for i := 1; i <= threads; i++ { - start := i * batch - end := (i + 1) * batch - if i == threads { - end = len(transactions) - } - go func(start, end int) { + for i := 0; i < prefetchThread; i++ { + go func(idx int) { newStatedb := statedb.Copy() gaspool := new(GasPool).AddGas(block.GasLimit()) blockContext := NewEVMBlockContext(header, p.bc, nil) evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) // Iterate over and process the individual transactions - for i, tx := range transactions[start:end] { + for i, tx := range sortTransactions[idx] { // If block precaching was interrupted, abort if interrupt != nil && atomic.LoadUint32(interrupt) == 1 { return @@ -82,23 +81,19 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c if err != nil { return // Also invalid block, bail out } - newStatedb.Prepare(tx.Hash(), block.Hash(), i) - if err := precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm); err != nil { - return // Ugh, something went horribly wrong, bail out - } + newStatedb.Prepare(tx.Hash(), header.Hash(), i) + precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm) } - }(start, end) + }(i) } - } // 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 types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) { // Update the evm with the new transaction context. evm.Reset(NewEVMTxContext(msg), statedb) // Add addresses to access list if applicable - _, err := ApplyMessage(evm, msg, gaspool) - return err + ApplyMessage(evm, msg, gaspool) } diff --git a/core/state_processor.go b/core/state_processor.go index 5652547db7..14fe9b4b92 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -123,6 +123,10 @@ func (p *LightStateProcessor) Process(block *types.Block, statedb *state.StateDB statedb.StopPrefetcher() parent := p.bc.GetHeader(block.ParentHash(), block.NumberU64()-1) statedb, err = state.New(parent.Root, p.bc.stateCache, p.bc.snaps) + statedb.SetExpectedStateRoot(block.Root()) + if p.bc.pipeCommit { + statedb.EnablePipeCommit() + } if err != nil { return statedb, nil, nil, 0, err } @@ -148,9 +152,12 @@ func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *ty for _, c := range diffLayer.Codes { fullDiffCode[c.Hash] = c.Code } - + stateTrie, err := statedb.Trie() + if err != nil { + return nil, nil, 0, err + } for des := range snapDestructs { - statedb.Trie().TryDelete(des[:]) + stateTrie.TryDelete(des[:]) } threads := gopool.Threads(len(snapAccounts)) @@ -191,7 +198,7 @@ func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *ty // fetch previous state var previousAccount state.Account stateMux.Lock() - enc, err := statedb.Trie().TryGet(diffAccount[:]) + enc, err := stateTrie.TryGet(diffAccount[:]) stateMux.Unlock() if err != nil { errChan <- err @@ -303,7 +310,7 @@ func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *ty return } stateMux.Lock() - err = statedb.Trie().TryUpdate(diffAccount[:], bz) + err = stateTrie.TryUpdate(diffAccount[:], bz) stateMux.Unlock() if err != nil { errChan <- err @@ -330,7 +337,7 @@ func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *ty } // Do validate in advance so that we can fall back to full process - if err := p.bc.validator.ValidateState(block, statedb, diffLayer.Receipts, gasUsed); err != nil { + if err := p.bc.validator.ValidateState(block, statedb, diffLayer.Receipts, gasUsed, false); err != nil { log.Error("validate state failed during diff sync", "error", err) return nil, nil, 0, err } @@ -378,6 +385,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg gp = new(GasPool).AddGas(block.GasLimit()) ) signer := types.MakeSigner(p.bc.chainConfig, block.Number()) + statedb.TryPreload(block, signer) var receipts = make([]*types.Receipt, 0) // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { @@ -396,6 +404,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // initilise bloom processors bloomProcessors := NewAsyncReceiptBloomGenerator(txNum) + statedb.MarkFullProcessed() // usually do have two tx, one for validator set contract, another for system reward contract. systemTxs := make([]*types.Transaction, 0, 2) diff --git a/core/types.go b/core/types.go index 49bd58e086..5ed4817e68 100644 --- a/core/types.go +++ b/core/types.go @@ -31,7 +31,7 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error + ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, skipHeavyVerify bool) error } // Prefetcher is an interface for pre-caching transaction signatures and state. diff --git a/eth/api_test.go b/eth/api_test.go index b44eed40bc..359671579b 100644 --- a/eth/api_test.go +++ b/eth/api_test.go @@ -77,7 +77,9 @@ func TestAccountRange(t *testing.T) { m[addr] = true } } - state.Commit(true) + state.Finalise(true) + state.AccountsIntermediateRoot() + state.Commit(nil) root := state.IntermediateRoot(true) trie, err := statedb.OpenTrie(root) @@ -134,7 +136,7 @@ func TestEmptyAccountRange(t *testing.T) { statedb = state.NewDatabase(rawdb.NewMemoryDatabase()) state, _ = state.New(common.Hash{}, statedb, nil) ) - state.Commit(true) + state.Commit(nil) state.IntermediateRoot(true) results := state.IteratorDump(true, true, true, (common.Hash{}).Bytes(), AccountRangeMaxResults) if bytes.Equal(results.Next, (common.Hash{}).Bytes()) { diff --git a/eth/backend.go b/eth/backend.go index f6599529db..ab93006437 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -203,6 +203,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.DiffSync { bcOps = append(bcOps, core.EnableLightProcessor) } + if config.PipeCommit { + bcOps = append(bcOps, core.EnablePipelineCommit) + } if config.PersistDiff { bcOps = append(bcOps, core.EnablePersistDiff(config.DiffBlock)) } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 010a1fb923..09baad1e1c 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -137,6 +137,7 @@ type Config struct { DirectBroadcast bool DisableSnapProtocol bool //Whether disable snap protocol DiffSync bool // Whether support diff sync + PipeCommit bool RangeLimit bool TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 6ea3161d61..24a0e776f6 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -138,7 +138,9 @@ func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state return 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())) + statedb.Finalise(eth.blockchain.Config().IsEIP158(current.Number())) + statedb.AccountsIntermediateRoot() + root, _, err := statedb.Commit(nil) if err != nil { return nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", current.NumberU64(), current.Root().Hex(), err) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index a44982b864..8ee2c22ffd 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -556,7 +556,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config } // calling IntermediateRoot will internally call Finalize on the state // so any modifications are written to the trie - roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects)) + root := statedb.IntermediateRoot(deleteEmptyObjects) + + roots = append(roots, root) } return roots, nil } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 380481a22d..f38625bd23 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -271,6 +271,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { config := ðconfig.Config{Genesis: genesis} config.Ethash.PowMode = ethash.ModeFake config.SnapshotCache = 256 + config.TriesInMemory = 128 ethservice, err := eth.New(n, config) if err != nil { t.Fatalf("can't create new ethereum service: %v", err) diff --git a/miner/worker.go b/miner/worker.go index 2dcb75ac10..28ef170e40 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -634,6 +634,7 @@ func (w *worker) resultLoop() { logs = append(logs, receipt.Logs...) } // Commit block and state to database. + task.state.SetExpectedStateRoot(block.Root()) _, err := w.chain.WriteBlockWithState(block, receipts, logs, task.state, true) if err != nil { log.Error("Failed writing block to chain", "err", err) @@ -994,6 +995,10 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) // and commits new work if consensus engine is running. func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { s := w.current.state + err := s.WaitPipeVerification() + if err != nil { + return err + } block, receipts, err := w.engine.FinalizeAndAssemble(w.chain, types.CopyHeader(w.current.header), s, w.current.txs, uncles, w.current.receipts) if err != nil { return err diff --git a/params/protocol_params.go b/params/protocol_params.go index 857bb9a582..84515869b6 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -114,7 +114,6 @@ const ( // Precompiled contract gas prices - //TODO need further discussion TendermintHeaderValidateGas uint64 = 3000 // Gas for validate tendermiint consensus state IAVLMerkleProofValidateGas uint64 = 3000 // Gas for validate merkle proof diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 77d4fd08d4..a688254a20 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -198,7 +198,9 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh } // Commit block - statedb.Commit(config.IsEIP158(block.Number())) + statedb.Finalise(config.IsEIP158(block.Number())) + statedb.AccountsIntermediateRoot() + statedb.Commit(nil) // Add 0-value mining reward. This only makes a difference in the cases // where // - the coinbase suicided, or @@ -226,7 +228,9 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo } } // Commit and re-open to start with a clean state. - root, _, _ := statedb.Commit(false) + statedb.Finalise(false) + statedb.AccountsIntermediateRoot() + root, _, _ := statedb.Commit(nil) var snaps *snapshot.Tree if snapshotter { diff --git a/trie/database.go b/trie/database.go index 76f8b26ccd..b6a3154d48 100644 --- a/trie/database.go +++ b/trie/database.go @@ -605,14 +605,16 @@ func (db *Database) Cap(limit common.StorageSize) error { // 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 // by only uncaching existing data when the database write finalizes. + db.lock.RLock() nodes, storage, start := len(db.dirties), db.dirtiesSize, time.Now() - batch := db.diskdb.NewBatch() - // db.dirtiesSize only contains the useful data in the cache, but when reporting // the total memory consumption, the maintenance metadata is also needed to be // counted. size := db.dirtiesSize + common.StorageSize((len(db.dirties)-1)*cachedNodeSize) size += db.childrenSize - common.StorageSize(len(db.dirties[common.Hash{}].children)*(common.HashLength+2)) + db.lock.RUnlock() + + batch := db.diskdb.NewBatch() // If the preimage cache got large enough, push to disk. If it's still small // leave for later to deduplicate writes. @@ -632,27 +634,35 @@ func (db *Database) Cap(limit common.StorageSize) error { } // Keep committing nodes from the flush-list until we're below allowance oldest := db.oldest - 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()) - - // If we exceeded the ideal batch size, commit and reset - if batch.ValueSize() >= ethdb.IdealBatchSize { - if err := batch.Write(); err != nil { - log.Error("Failed to write flush list to disk", "err", err) - return err + err := func() error { + db.lock.RLock() + defer db.lock.RUnlock() + 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()) + + // If we exceeded the ideal batch size, commit and reset + if batch.ValueSize() >= ethdb.IdealBatchSize { + if err := batch.Write(); err != nil { + log.Error("Failed to write flush list to disk", "err", err) + return err + } + batch.Reset() } - batch.Reset() - } - // Iterate to the next flush item, or abort if the size cap was achieved. Size - // is the total size, including the useful cached data (hash -> blob), the - // cache item metadata, as well as external children mappings. - size -= common.StorageSize(common.HashLength + int(node.size) + cachedNodeSize) - if node.children != nil { - size -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) + // Iterate to the next flush item, or abort if the size cap was achieved. Size + // is the total size, including the useful cached data (hash -> blob), the + // cache item metadata, as well as external children mappings. + size -= common.StorageSize(common.HashLength + int(node.size) + cachedNodeSize) + if node.children != nil { + size -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) + } + oldest = node.flushNext } - oldest = node.flushNext + return nil + }() + if err != nil { + return err } // Flush out any remainder data from the last batch if err := batch.Write(); err != nil { @@ -722,7 +732,9 @@ func (db *Database) Commit(node common.Hash, report bool, callback func(common.H batch.Reset() } // Move the trie itself into the batch, flushing if enough data is accumulated + db.lock.RLock() nodes, storage := len(db.dirties), db.dirtiesSize + db.lock.RUnlock() uncacher := &cleaner{db} if err := db.commit(node, batch, uncacher, callback); err != nil { @@ -766,10 +778,14 @@ 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 { // If the node does not exist, it's a previously committed node + db.lock.RLock() node, ok := db.dirties[hash] if !ok { + db.lock.RUnlock() return nil } + db.lock.RUnlock() + var err error node.forChilds(func(child common.Hash) { if err == nil { From 6499b3f890dd18f0d4bda20a532604b056e3243a Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Wed, 26 Jan 2022 14:30:07 +0800 Subject: [PATCH 079/117] doc: update discord link (#740) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b74ec4d0a5..bc7f7a85ef 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Binance Smart Chain starts its development based on go-ethereum fork. So you may [![API Reference]( https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 )](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc) -[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/5Z3C3SdxDw) +[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/z2VpC455eU) But from that baseline of EVM compatible, Binance Smart Chain introduces a system of 21 validators with Proof of Staked Authority (PoSA) consensus that can support short block time and lower fees. The most bonded validator candidates of staking will become validators and produce blocks. The double-sign detection and other slashing logic guarantee security, stability, and chain finality. @@ -203,7 +203,7 @@ from anyone on the internet, and are grateful for even the smallest of fixes! If you'd like to contribute to bsc, please fork, fix, commit and send a pull request for the maintainers to review and merge into the main code base. If you wish to submit -more complex changes though, please check up with the core devs first on [our discord channel](https://discord.gg/5Z3C3SdxDw) +more complex changes though, please check up with the core devs first on [our discord channel](https://discord.gg/z2VpC455eU) to ensure those changes are in line with the general philosophy of the project and/or get some early feedback which can make both your efforts much lighter as well as our review and merge procedures quick and simple. From 21a3b11d17573371e85127b3c9c9d19685f63bb7 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Wed, 26 Jan 2022 14:57:22 +0800 Subject: [PATCH 080/117] prepare for relase v1.1.8 (#741) --- .github/release.env | 4 ++-- CHANGELOG.md | 15 +++++++++++++++ PULL_REQUEST_TEMPLATE | 14 -------------- params/version.go | 2 +- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/.github/release.env b/.github/release.env index 37739d157e..2034c1d3fa 100644 --- a/.github/release.env +++ b/.github/release.env @@ -1,2 +1,2 @@ -MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.6/mainnet.zip" -TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.6/testnet.zip" +MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.7/mainnet.zip" +TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.7/testnet.zip" diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d5bf0877f..4dfa55dfb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## v1.1.8 +FEATURES +* [\#668](https://github.com/binance-chain/bsc/pull/668) implement State Verification && Snapshot Commit pipeline +* [\#581](https://github.com/binance-chain/bsc/pull/581) implement geth native trace +* [\#543](https://github.com/binance-chain/bsc/pull/543) implement offline block prune tools + +IMPROVEMENT +* [\#704](https://github.com/binance-chain/bsc/pull/704) prefetch state by applying the transactions within one block +* [\#713](https://github.com/binance-chain/bsc/pull/713) add ARM binaries for release pipeline + +BUGFIX +* [\#667](https://github.com/binance-chain/bsc/pull/667) trie: reject deletions when verifying range proofs #667 +* [\#643](https://github.com/binance-chain/bsc/pull/643) add timeout for stopping p2p server to fix can not gracefully shutdown issue +* [\#740](https://github.com/binance-chain/bsc/pull/740) update discord link which won't expire + ## v1.1.7 BUGFIX diff --git a/PULL_REQUEST_TEMPLATE b/PULL_REQUEST_TEMPLATE index 69f29fecf8..acf0007d89 100644 --- a/PULL_REQUEST_TEMPLATE +++ b/PULL_REQUEST_TEMPLATE @@ -15,17 +15,3 @@ add an example CLI or API response... Notable changes: * add each change in a bullet point here * ... - -### Preflight checks - -- [ ] build passed (`make build`) -- [ ] tests passed (`make test`) -- [ ] manual transaction test passed - -### Already reviewed by - -... - -### Related issues - -... reference related issue #'s here ... diff --git a/params/version.go b/params/version.go index 0cab1d8822..8faa4bb644 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 7 // Patch version component of the current release + VersionPatch = 8 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From c0c639650998e407e58d7267749a576e885506d9 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 25 Mar 2022 15:22:21 +0800 Subject: [PATCH 081/117] fix pruner block tool bug, add some check logic --- cmd/geth/snapshot.go | 3 ++- core/headerchain.go | 3 +++ core/rawdb/chain_iterator.go | 5 ++++- eth/state_accessor.go | 3 +++ internal/ethapi/api.go | 6 ++++++ 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 20920a0f94..c00334ee9e 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -278,7 +278,8 @@ func pruneBlock(ctx *cli.Context) error { var newAncientPath string oldAncientPath := ctx.GlobalString(utils.AncientFlag.Name) if !filepath.IsAbs(oldAncientPath) { - oldAncientPath = stack.ResolvePath(oldAncientPath) + // force absolute paths, which often fail due to the splicing of relative paths + return errors.New("datadir.ancient not abs path") } path, _ := filepath.Split(oldAncientPath) diff --git a/core/headerchain.go b/core/headerchain.go index fe4770a469..3e50c1eb07 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -250,6 +250,9 @@ func (hc *HeaderChain) writeHeaders(headers []*types.Header) (result *headerWrit headHeader = hc.GetHeader(headHash, headNumber) ) for rawdb.ReadCanonicalHash(hc.chainDb, headNumber) != headHash { + if frozen, _ := hc.chainDb.Ancients(); frozen == headNumber { + break + } rawdb.WriteCanonicalHash(markerBatch, headHash, headNumber) headHash = headHeader.ParentHash headNumber = headHeader.Number.Uint64() - 1 diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 22d5188e91..883e17b782 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -95,7 +95,10 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool number uint64 rlp rlp.RawValue } - if to == from { + if offset := db.AncientOffSet(); offset > from { + from = offset + } + if to <= from { return nil } threads := to - from diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 24a0e776f6..156e3f1daf 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -74,6 +74,9 @@ func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state // 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) + if current == nil { + return nil, fmt.Errorf("missing parent block %v %d", block.ParentHash(), block.NumberU64()-1) + } } else { // Otherwise try to reexec blocks until we find a state or reach our limit current = block diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 091e9e7e82..7a3f0ad8bd 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1774,10 +1774,16 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceiptsByBlockNumber(ctx conte if err != nil { return nil, err } + if receipts == nil { + return nil, fmt.Errorf("block %d receipts not found", blockNumber) + } block, err := s.b.BlockByHash(ctx, blockHash) if err != nil { return nil, err } + if block == nil { + return nil, fmt.Errorf("block %d not found", blockNumber) + } txs := block.Transactions() if len(txs) != len(receipts) { return nil, fmt.Errorf("txs length doesn't equal to receipts' length") From 91d7cd5fd25bda42931cd48ad5d538361f417cb0 Mon Sep 17 00:00:00 2001 From: Leon <316032931@qq.com> Date: Mon, 28 Mar 2022 10:12:38 +0800 Subject: [PATCH 082/117] [R4R]Prefetch state data on mining process (#803) * perf(miner):add mining prefetcher * fix ineffassign * fix comments * fix comments * fix comments: add AsMessagePrefetch to skip nonce check * fix comment:refactor check order of method Forward * fix comments:rename variables * fix comments: rename * rename * fix comments: refactor * update --- core/state_prefetcher.go | 58 ++++++++++++++++++++++++++++ core/types.go | 2 + core/types/transaction.go | 62 ++++++++++++++++++++++++++++++ core/types/transaction_test.go | 69 ++++++++++++++++++++++++++++++++++ miner/worker.go | 12 +++++- 5 files changed, 202 insertions(+), 1 deletion(-) diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index d559a03a0f..0e18bdc8bb 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -27,6 +27,7 @@ import ( ) const prefetchThread = 2 +const checkInterval = 10 // statePrefetcher is a basic Prefetcher, which blindly executes a block on top // of an arbitrary state with the goal of prefetching potentially useful state @@ -88,6 +89,63 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c } } +// PrefetchMining 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 snapshot clean state. Only used for mining stage +func (p *statePrefetcher) PrefetchMining(txs *types.TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction) { + var signer = types.MakeSigner(p.config, header.Number) + + txCh := make(chan *types.Transaction, 2*prefetchThread) + for i := 0; i < prefetchThread; i++ { + go func(startCh <-chan *types.Transaction, stopCh <-chan struct{}) { + idx := 0 + newStatedb := statedb.Copy() + gaspool := new(GasPool).AddGas(gasLimit) + blockContext := NewEVMBlockContext(header, p.bc, nil) + evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) + // Iterate over and process the individual transactions + for { + select { + case tx := <-startCh: + // Convert the transaction into an executable message and pre-cache its sender + msg, err := tx.AsMessageNoNonceCheck(signer) + if err != nil { + return // Also invalid block, bail out + } + idx++ + newStatedb.Prepare(tx.Hash(), header.Hash(), idx) + precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm) + gaspool = new(GasPool).AddGas(gasLimit) + case <-stopCh: + return + } + } + }(txCh, interruptCh) + } + go func(txset *types.TransactionsByPriceAndNonce) { + count := 0 + for { + tx := txset.Peek() + if tx == nil { + return + } + select { + case <-interruptCh: + return + default: + } + if count++; count%checkInterval == 0 { + if *txCurr == nil { + return + } + txset.Forward(*txCurr) + } + txCh <- tx + txset.Shift() + } + }(txs) +} + // 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. diff --git a/core/types.go b/core/types.go index 5ed4817e68..61722aea74 100644 --- a/core/types.go +++ b/core/types.go @@ -40,6 +40,8 @@ type Prefetcher interface { // 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) + // PrefetchMining used for pre-caching transaction signatures and state trie nodes. Only used for mining stage. + PrefetchMining(txs *types.TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction) } // Processor is an interface for processing blocks using a given initial state. diff --git a/core/types/transaction.go b/core/types/transaction.go index 74c011544b..e95cec25a6 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -458,6 +458,21 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa } } +// Copy copys a new TransactionsPriceAndNonce with the same *transaction +func (t *TransactionsByPriceAndNonce) Copy() *TransactionsByPriceAndNonce { + heads := make([]*Transaction, len(t.heads)) + copy(heads, t.heads) + txs := make(map[common.Address]Transactions, len(t.txs)) + for acc, txsTmp := range t.txs { + txs[acc] = txsTmp + } + return &TransactionsByPriceAndNonce{ + heads: heads, + txs: txs, + signer: t.signer, + } +} + // Peek returns the next transaction by price. func (t *TransactionsByPriceAndNonce) Peek() *Transaction { if len(t.heads) == 0 { @@ -488,6 +503,44 @@ func (t *TransactionsByPriceAndNonce) CurrentSize() int { return len(t.heads) } +//Forward moves current transaction to be the one which is one index after tx +func (t *TransactionsByPriceAndNonce) Forward(tx *Transaction) { + if tx == nil { + t.heads = t.heads[0:0] + return + } + //check whether target tx exists in t.heads + for _, head := range t.heads { + if tx == head { + //shift t to the position one after tx + txTmp := t.Peek() + for txTmp != tx { + t.Shift() + txTmp = t.Peek() + } + t.Shift() + return + } + } + //get the sender address of tx + acc, _ := Sender(t.signer, tx) + //check whether target tx exists in t.txs + if txs, ok := t.txs[acc]; ok { + for _, txTmp := range txs { + //found the same pointer in t.txs as tx and then shift t to the position one after tx + if txTmp == tx { + txTmp = t.Peek() + for txTmp != tx { + t.Shift() + txTmp = t.Peek() + } + t.Shift() + return + } + } + } +} + // Message is a fully derived transaction and implements core.Message // // NOTE: In a future PR this will be removed. @@ -535,6 +588,15 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) { return msg, err } +// AsMessageNoNonceCheck returns the transaction with checkNonce field set to be false. +func (tx *Transaction) AsMessageNoNonceCheck(s Signer) (Message, error) { + msg, err := tx.AsMessage(s) + if err == nil { + msg.checkNonce = false + } + 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 } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 3cece9c235..c81b7b8647 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -358,6 +358,75 @@ func TestTransactionTimeSort(t *testing.T) { } } +func TestTransactionForward(t *testing.T) { + // Generate a batch of accounts to start with + keys := make([]*ecdsa.PrivateKey, 5) + for i := 0; i < len(keys); i++ { + keys[i], _ = crypto.GenerateKey() + } + signer := HomesteadSigner{} + + // Generate a batch of transactions with overlapping prices, but different creation times + groups := map[common.Address]Transactions{} + for start, key := range keys { + addr := crypto.PubkeyToAddress(key.PublicKey) + + tx, _ := SignTx(NewTransaction(0, common.Address{}, big.NewInt(100), 100, big.NewInt(1), nil), signer, key) + tx2, _ := SignTx(NewTransaction(1, common.Address{}, big.NewInt(100), 100, big.NewInt(1), nil), signer, key) + + tx.time = time.Unix(0, int64(len(keys)-start)) + tx2.time = time.Unix(1, int64(len(keys)-start)) + + groups[addr] = append(groups[addr], tx) + groups[addr] = append(groups[addr], tx2) + + } + // Sort the transactions + txset := NewTransactionsByPriceAndNonce(signer, groups) + txsetCpy := txset.Copy() + + txs := Transactions{} + for tx := txsetCpy.Peek(); tx != nil; tx = txsetCpy.Peek() { + txs = append(txs, tx) + txsetCpy.Shift() + } + + tmp := txset.Copy() + for j := 0; j < 10; j++ { + txset = tmp.Copy() + txsetCpy = tmp.Copy() + i := 0 + for ; i < j; i++ { + txset.Shift() + } + tx := txset.Peek() + txsetCpy.Forward(tx) + txCpy := txsetCpy.Peek() + if txCpy == nil { + if tx == nil { + continue + } + txset.Shift() + if txset.Peek() != nil { + t.Errorf("forward got an incorrect result, got %v, want %v", txCpy, tx) + } else { + continue + } + } + txset.Shift() + for ; i < len(txs)-1; i++ { + tx = txset.Peek() + txCpy = txsetCpy.Peek() + if txCpy != tx { + t.Errorf("forward got an incorrect result, got %v, want %v", txCpy, tx) + } + txsetCpy.Shift() + txset.Shift() + } + + } +} + // TestTransactionCoding tests serializing/de-serializing to/from rlp and JSON. func TestTransactionCoding(t *testing.T) { key, err := crypto.GenerateKey() diff --git a/miner/worker.go b/miner/worker.go index 28ef170e40..2224dc0071 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -130,6 +130,7 @@ type intervalAdjust struct { // worker is the main object which takes care of submitting new work to consensus engine // and gathering the sealing result. type worker struct { + prefetcher core.Prefetcher config *Config chainConfig *params.ChainConfig engine consensus.Engine @@ -196,6 +197,7 @@ type worker struct { func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(*types.Block) bool, init bool) *worker { worker := &worker{ + prefetcher: core.NewStatePrefetcher(chainConfig, eth.BlockChain(), engine), config: config, chainConfig: chainConfig, engine: engine, @@ -778,6 +780,14 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin } bloomProcessors := core.NewAsyncReceiptBloomGenerator(processorCapacity) + interruptCh := make(chan struct{}) + defer close(interruptCh) + tx := &types.Transaction{} + txCurr := &tx + //prefetch txs from all pending txs + txsPrefetch := txs.Copy() + w.prefetcher.PrefetchMining(txsPrefetch, w.current.header, w.current.gasPool.Gas(), w.current.state.Copy(), *w.chain.GetVMConfig(), interruptCh, txCurr) + LOOP: for { // In the following three cases, we will interrupt the execution of the transaction. @@ -814,7 +824,7 @@ LOOP: } } // Retrieve the next transaction and abort if all done - tx := txs.Peek() + tx = txs.Peek() if tx == nil { break } From 58f3b2cd8419d63390a644844be4f0838db4fafc Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Mon, 28 Mar 2022 10:51:53 +0800 Subject: [PATCH 083/117] fix code of difflayer not assgin before return (#808) --- core/state/statedb.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 5ea84f4032..c523de6a92 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1333,19 +1333,6 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er }() } - if s.snap != nil { - for addr := range s.stateObjectsDirty { - if obj := s.stateObjects[addr]; !obj.deleted { - if obj.code != nil && obj.dirtyCode { - diffLayer.Codes = append(diffLayer.Codes, types.DiffCode{ - Hash: common.BytesToHash(obj.CodeHash()), - Code: obj.code, - }) - } - } - } - } - for addr := range s.stateObjectsDirty { if obj := s.stateObjects[addr]; !obj.deleted { // Write any contract code associated with the state object @@ -1422,6 +1409,12 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er if obj.code != nil && obj.dirtyCode { rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) obj.dirtyCode = false + if s.snap != nil { + diffLayer.Codes = append(diffLayer.Codes, types.DiffCode{ + Hash: common.BytesToHash(obj.CodeHash()), + Code: obj.code, + }) + } if codeWriter.ValueSize() > ethdb.IdealBatchSize { if err := codeWriter.Write(); err != nil { return err From 5f1aabeb38a21bff9ffe25e1dd138b2b9d335007 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Mon, 28 Mar 2022 10:52:05 +0800 Subject: [PATCH 084/117] fix race condition on preimage (#797) --- trie/database.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trie/database.go b/trie/database.go index b6a3154d48..649af6dbf9 100644 --- a/trie/database.go +++ b/trie/database.go @@ -722,17 +722,18 @@ func (db *Database) Commit(node common.Hash, report bool, callback func(common.H batch := db.diskdb.NewBatch() // Move all of the accumulated preimages into a write batch + db.lock.RLock() 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 { + db.lock.RUnlock() return err } batch.Reset() } // Move the trie itself into the batch, flushing if enough data is accumulated - db.lock.RLock() nodes, storage := len(db.dirties), db.dirtiesSize db.lock.RUnlock() From 4ff96978cbbcea9e49c98dccb1fdc7199cc85ee1 Mon Sep 17 00:00:00 2001 From: flywukong <2229306838@qq.com> Date: Mon, 28 Mar 2022 11:59:41 +0800 Subject: [PATCH 085/117] [R4R]add sharedStorage for prefetching to L1 (#792) * add sharedStorage for prefetching to L1 * remote originStorage in stateObjects * fix core * fix bug of sync map * remove read lock when get & set keys * statedb copy use CopyWithSharedStorage * reduce lock access * fix comment * avoid sharedPool effects on other modules * remove tryPreload * fix comment * fix var name * fix lint * fix L1 miss data && data condition * fix comment --- core/blockchain.go | 2 +- core/state/shared_pool.go | 39 +++++++++++++++ core/state/state_object.go | 56 +++++++++++++++++----- core/state/statedb.go | 98 +++++++++----------------------------- core/state_prefetcher.go | 1 + core/state_processor.go | 1 - 6 files changed, 108 insertions(+), 89 deletions(-) create mode 100644 core/state/shared_pool.go diff --git a/core/blockchain.go b/core/blockchain.go index 6c87ffc708..fbf9af9db7 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2101,7 +2101,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er if parent == nil { parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1) } - statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) + statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps) if err != nil { return it.index, err } diff --git a/core/state/shared_pool.go b/core/state/shared_pool.go new file mode 100644 index 0000000000..ba96c2c27d --- /dev/null +++ b/core/state/shared_pool.go @@ -0,0 +1,39 @@ +package state + +import ( + "sync" + + "github.com/ethereum/go-ethereum/common" +) + +// sharedPool is used to store maps of originStorage of stateObjects +type StoragePool struct { + sync.RWMutex + sharedMap map[common.Address]*sync.Map +} + +func NewStoragePool() *StoragePool { + sharedMap := make(map[common.Address]*sync.Map) + return &StoragePool{ + sync.RWMutex{}, + sharedMap, + } +} + +// getStorage Check whether the storage exist in pool, +// new one if not exist, the content of storage will be fetched in stateObjects.GetCommittedState() +func (s *StoragePool) getStorage(address common.Address) *sync.Map { + s.RLock() + storageMap, ok := s.sharedMap[address] + s.RUnlock() + if !ok { + s.Lock() + defer s.Unlock() + if storageMap, ok = s.sharedMap[address]; !ok { + m := new(sync.Map) + s.sharedMap[address] = m + return m + } + } + return storageMap +} diff --git a/core/state/state_object.go b/core/state/state_object.go index 298f4305ba..c5212e91cc 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "math/big" + "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -79,7 +80,9 @@ type StateObject struct { trie Trie // storage trie, which becomes non-nil on first access code Code // contract bytecode, which gets set when code is loaded - originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction + sharedOriginStorage *sync.Map // Storage cache of original entries to dedup rewrites, reset for every transaction + originStorage Storage + 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. @@ -120,14 +123,21 @@ func newObject(db *StateDB, address common.Address, data Account) *StateObject { if data.Root == (common.Hash{}) { data.Root = emptyRoot } + var storageMap *sync.Map + // Check whether the storage exist in pool, new originStorage if not exist + if db != nil && db.storagePool != nil { + storageMap = db.GetStorage(address) + } + return &StateObject{ - db: db, - address: address, - addrHash: crypto.Keccak256Hash(address[:]), - data: data, - originStorage: make(Storage), - pendingStorage: make(Storage), - dirtyStorage: make(Storage), + db: db, + address: address, + addrHash: crypto.Keccak256Hash(address[:]), + data: data, + sharedOriginStorage: storageMap, + originStorage: make(Storage), + pendingStorage: make(Storage), + dirtyStorage: make(Storage), } } @@ -194,6 +204,29 @@ func (s *StateObject) GetState(db Database, key common.Hash) common.Hash { return s.GetCommittedState(db, key) } +func (s *StateObject) getOriginStorage(key common.Hash) (common.Hash, bool) { + if value, cached := s.originStorage[key]; cached { + return value, true + } + // if L1 cache miss, try to get it from shared pool + if s.sharedOriginStorage != nil { + val, ok := s.sharedOriginStorage.Load(key) + if !ok { + return common.Hash{}, false + } + s.originStorage[key] = val.(common.Hash) + return val.(common.Hash), true + } + return common.Hash{}, false +} + +func (s *StateObject) setOriginStorage(key common.Hash, value common.Hash) { + if s.db.writeOnSharedStorage && s.sharedOriginStorage != nil { + s.sharedOriginStorage.Store(key, value) + } + s.originStorage[key] = value +} + // 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) @@ -204,7 +237,8 @@ func (s *StateObject) GetCommittedState(db Database, key common.Hash) common.Has if value, pending := s.pendingStorage[key]; pending { return value } - if value, cached := s.originStorage[key]; cached { + + if value, cached := s.getOriginStorage(key); cached { return value } // If no live objects are available, attempt to use snapshots @@ -263,7 +297,7 @@ func (s *StateObject) GetCommittedState(db Database, key common.Hash) common.Has } value.SetBytes(content) } - s.originStorage[key] = value + s.setOriginStorage(key, value) return value } @@ -320,6 +354,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 { s.db.prefetcher.prefetch(s.data.Root, slotsToPrefetch, s.addrHash) } @@ -356,7 +391,6 @@ func (s *StateObject) updateTrie(db Database) Trie { continue } s.originStorage[key] = value - var v []byte if (value == common.Hash{}) { s.setError(tr.TryDelete(key[:])) diff --git a/core/state/statedb.go b/core/state/statedb.go index c523de6a92..c8cb410b0e 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -39,10 +39,7 @@ import ( "github.com/ethereum/go-ethereum/trie" ) -const ( - preLoadLimit = 128 - defaultNumOfSlots = 100 -) +const defaultNumOfSlots = 100 type revision struct { id int @@ -101,6 +98,8 @@ type StateDB struct { 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 + storagePool *StoragePool // sharedPool to store L1 originStorage of stateObjects + writeOnSharedStorage bool // Write to the shared origin storage of a stateObject while reading from the underlying storage layer. // 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 @@ -147,6 +146,16 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) return newStateDB(root, db, snaps) } +// NewWithSharedPool creates a new state with sharedStorge on layer 1.5 +func NewWithSharedPool(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { + statedb, err := newStateDB(root, db, snaps) + if err != nil { + return nil, err + } + statedb.storagePool = NewStoragePool() + return statedb, nil +} + func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { sdb := &StateDB{ db: db, @@ -178,6 +187,10 @@ func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, return sdb, nil } +func (s *StateDB) EnableWriteOnSharedStorage() { + s.writeOnSharedStorage = true +} + // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. @@ -591,78 +604,6 @@ func (s *StateDB) getStateObject(addr common.Address) *StateObject { return nil } -func (s *StateDB) TryPreload(block *types.Block, signer types.Signer) { - accounts := make(map[common.Address]bool, block.Transactions().Len()) - accountsSlice := make([]common.Address, 0, block.Transactions().Len()) - for _, tx := range block.Transactions() { - from, err := types.Sender(signer, tx) - if err != nil { - break - } - accounts[from] = true - if tx.To() != nil { - accounts[*tx.To()] = true - } - } - for account := range accounts { - accountsSlice = append(accountsSlice, account) - } - if len(accountsSlice) >= preLoadLimit && len(accountsSlice) > runtime.NumCPU() { - objsChan := make(chan []*StateObject, runtime.NumCPU()) - for i := 0; i < runtime.NumCPU(); i++ { - start := i * len(accountsSlice) / runtime.NumCPU() - end := (i + 1) * len(accountsSlice) / runtime.NumCPU() - if i+1 == runtime.NumCPU() { - end = len(accountsSlice) - } - go func(start, end int) { - objs := s.preloadStateObject(accountsSlice[start:end]) - objsChan <- objs - }(start, end) - } - for i := 0; i < runtime.NumCPU(); i++ { - objs := <-objsChan - for _, obj := range objs { - s.SetStateObject(obj) - } - } - } -} - -func (s *StateDB) preloadStateObject(address []common.Address) []*StateObject { - // Prefer live objects if any is available - if s.snap == nil { - return nil - } - hasher := crypto.NewKeccakState() - objs := make([]*StateObject, 0, len(address)) - for _, addr := range address { - // If no live objects are available, attempt to use snapshots - if acc, err := s.snap.Account(crypto.HashData(hasher, addr.Bytes())); err == nil { - if acc == nil { - continue - } - data := &Account{ - Nonce: acc.Nonce, - Balance: acc.Balance, - CodeHash: acc.CodeHash, - Root: common.BytesToHash(acc.Root), - } - if len(data.CodeHash) == 0 { - data.CodeHash = emptyCodeHash - } - if data.Root == (common.Hash{}) { - data.Root = emptyRoot - } - // Insert into the live set - obj := newObject(s, addr, *data) - objs = append(objs, obj) - } - // Do not enable this feature when snapshot is not enabled. - } - return objs -} - // getDeletedStateObject is similar to getStateObject, but instead of returning // nil for a deleted state object, it returns the actual object with the deleted // flag set. This is needed by the state journal to revert to the correct s- @@ -828,6 +769,7 @@ func (s *StateDB) Copy() *StateDB { 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)), + storagePool: s.storagePool, refund: s.refund, logs: make(map[common.Hash][]*types.Log, len(s.logs)), logSize: s.logSize, @@ -1626,3 +1568,7 @@ func (s *StateDB) GetDirtyAccounts() []common.Address { } return accounts } + +func (s *StateDB) GetStorage(address common.Address) *sync.Map { + return s.storagePool.getStorage(address) +} diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 0e18bdc8bb..e45a6306df 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -68,6 +68,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c for i := 0; i < prefetchThread; i++ { go func(idx int) { newStatedb := statedb.Copy() + newStatedb.EnableWriteOnSharedStorage() gaspool := new(GasPool).AddGas(block.GasLimit()) blockContext := NewEVMBlockContext(header, p.bc, nil) evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) diff --git a/core/state_processor.go b/core/state_processor.go index 14fe9b4b92..cf2275e722 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -385,7 +385,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg gp = new(GasPool).AddGas(block.GasLimit()) ) signer := types.MakeSigner(p.bc.chainConfig, block.Number()) - statedb.TryPreload(block, signer) var receipts = make([]*types.Receipt, 0) // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { From d8949871fb623373f8908c9ab2018838ad0f26a9 Mon Sep 17 00:00:00 2001 From: WayToFuture <61674316+forcodedancing@users.noreply.github.com> Date: Mon, 28 Mar 2022 16:46:39 +0800 Subject: [PATCH 086/117] [R4R] state verification pipeline (#795) * pipeline state verification * update codes and add logs for debug * refactor * update and add logs * refactor * refactor * remove unneeded logs * fix a blocking issue * fix sync issue when force kill * remove logs * refactor based on comments * refactor based on comments * refactor based on comments * refactor based on comments * refactor based on comments * fix a deadlock issue * fix merkle root mismatch issue during sync * refactor based on review comments * remove unnecessary code * remove unnecessary code * refactor based on review comments * change based on comments * refactor * uew dummyRoot to replace emptyRoot * add nil check * add comments * remove unneeded codes * format comments Co-authored-by: forcodedancing --- core/block_validator.go | 8 ++- core/blockchain.go | 2 +- core/blockchain_test.go | 2 +- core/state/snapshot/difflayer.go | 40 +++++++++++- core/state/snapshot/disklayer.go | 13 ++++ core/state/snapshot/journal.go | 1 + core/state/snapshot/snapshot.go | 22 ++++++- core/state/state_object.go | 21 +++++-- core/state/statedb.go | 102 ++++++++++++++++++++++++++++--- core/state_processor.go | 2 +- core/types.go | 2 +- 11 files changed, 190 insertions(+), 25 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index b109c1e54b..c6a35f1fdf 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -112,7 +112,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // 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. -func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, skipHeavyVerify bool) error { +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { header := block.Header() if block.GasUsed() != usedGas { return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) @@ -135,13 +135,15 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return nil }, } - if skipHeavyVerify { + if statedb.IsPipeCommit() { validateFuns = append(validateFuns, func() error { if err := statedb.WaitPipeVerification(); err != nil { return err } + statedb.CorrectAccountsRoot() statedb.Finalise(v.config.IsEIP158(header.Number)) - statedb.AccountsIntermediateRoot() + // State verification pipeline - accounts root are not calculated here, just populate needed fields for process + statedb.PopulateSnapAccountAndStorage() return nil }) } else { diff --git a/core/blockchain.go b/core/blockchain.go index fbf9af9db7..47ac859441 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2143,7 +2143,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er // Validate the state using the default validator substart = time.Now() if !statedb.IsLightProcessed() { - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, bc.pipeCommit); err != nil { + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { log.Error("validate state failed", "error", err) bc.reportBlock(block, receipts, err) return it.index, err diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 50d02e0acc..07cb51933a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -209,7 +209,7 @@ func testBlockChainImport(chain types.Blocks, pipelineCommit bool, blockchain *B blockchain.reportBlock(block, receipts, err) return err } - err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, pipelineCommit) + err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas) if err != nil { blockchain.reportBlock(block, receipts, err) return err diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 65b2729d9c..d2b1b2778b 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -118,8 +118,9 @@ type diffLayer struct { storageList map[common.Hash][]common.Hash // List of storage slots for iterated retrievals, one per account. Any existing lists are sorted if non-nil storageData map[common.Hash]map[common.Hash][]byte // Keyed storage slots for direct retrieval. one per account (nil means deleted) - verifiedCh chan struct{} // the difflayer is verified when verifiedCh is nil or closed - valid bool // mark the difflayer is valid or not. + verifiedCh chan struct{} // the difflayer is verified when verifiedCh is nil or closed + valid bool // mark the difflayer is valid or not. + accountCorrected bool // mark the accountData has been corrected ort not diffed *bloomfilter.Filter // Bloom filter tracking all the diffed items up to the disk layer @@ -182,6 +183,7 @@ func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]s storageList: make(map[common.Hash][]common.Hash), verifiedCh: verified, } + switch parent := parent.(type) { case *diskLayer: dl.rebloom(parent) @@ -190,6 +192,7 @@ func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]s default: panic("unknown parent type") } + // Sanity check that accounts or storage slots are never nil for accountHash, blob := range accounts { if blob == nil { @@ -286,6 +289,21 @@ func (dl *diffLayer) Verified() bool { } } +func (dl *diffLayer) CorrectAccounts(accounts map[common.Hash][]byte) { + dl.lock.Lock() + defer dl.lock.Unlock() + + dl.accountData = accounts + dl.accountCorrected = true +} + +func (dl *diffLayer) AccountsCorrected() bool { + dl.lock.RLock() + defer dl.lock.RUnlock() + + return dl.accountCorrected +} + // Parent returns the subsequent layer of a diff layer. func (dl *diffLayer) Parent() snapshot { return dl.parent @@ -314,6 +332,24 @@ func (dl *diffLayer) Account(hash common.Hash) (*Account, error) { return account, nil } +// Accounts directly retrieves all accounts in current snapshot in +// the snapshot slim data format. +func (dl *diffLayer) Accounts() (map[common.Hash]*Account, error) { + dl.lock.RLock() + defer dl.lock.RUnlock() + + accounts := make(map[common.Hash]*Account, len(dl.accountData)) + for hash, data := range dl.accountData { + account := new(Account) + if err := rlp.DecodeBytes(data, account); err != nil { + return nil, err + } + accounts[hash] = account + } + + return accounts, nil +} + // AccountRLP directly retrieves the account RLP associated with a particular // hash in the snapshot slim data format. // diff --git a/core/state/snapshot/disklayer.go b/core/state/snapshot/disklayer.go index c1de41782c..6d46496a71 100644 --- a/core/state/snapshot/disklayer.go +++ b/core/state/snapshot/disklayer.go @@ -59,6 +59,13 @@ func (dl *diskLayer) Verified() bool { return true } +func (dl *diskLayer) CorrectAccounts(map[common.Hash][]byte) { +} + +func (dl *diskLayer) AccountsCorrected() bool { + return true +} + // Parent always returns nil as there's no layer below the disk. func (dl *diskLayer) Parent() snapshot { return nil @@ -73,6 +80,12 @@ func (dl *diskLayer) Stale() bool { return dl.stale } +// Accounts directly retrieves all accounts in current snapshot in +// the snapshot slim data format. +func (dl *diskLayer) Accounts() (map[common.Hash]*Account, error) { + return nil, nil +} + // Account directly retrieves the account associated with a particular hash in // the snapshot slim data format. func (dl *diskLayer) Account(hash common.Hash) (*Account, error) { diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 35c69cfd6b..587f78a474 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -288,6 +288,7 @@ func (dl *diffLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) { if dl.Stale() { return common.Hash{}, ErrSnapshotStale } + // Everything below was journalled, persist this layer too if err := rlp.Encode(buffer, dl.root); err != nil { return common.Hash{}, err diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 8ac93f28e4..7ad4bcc91b 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -107,13 +107,23 @@ type Snapshot interface { // Verified returns whether the snapshot is verified Verified() bool - // Store the verification result + // MarkValid stores the verification result MarkValid() + // CorrectAccounts updates account data for storing the correct data during pipecommit + CorrectAccounts(map[common.Hash][]byte) + + // AccountsCorrected checks whether the account data has been corrected during pipecommit + AccountsCorrected() bool + // Account directly retrieves the account associated with a particular hash in // the snapshot slim data format. Account(hash common.Hash) (*Account, error) + // Accounts directly retrieves all accounts in current snapshot in + // the snapshot slim data format. + Accounts() (map[common.Hash]*Account, error) + // AccountRLP directly retrieves the account RLP associated with a particular // hash in the snapshot slim data format. AccountRLP(hash common.Hash) ([]byte, error) @@ -240,6 +250,11 @@ func (t *Tree) waitBuild() { } } +// Layers returns the number of layers +func (t *Tree) Layers() int { + return len(t.layers) +} + // Disable interrupts any pending snapshot generator, deletes all the snapshot // layers in memory and marks snapshots disabled globally. In order to resume // the snapshot functionality, the caller must invoke Rebuild. @@ -666,6 +681,11 @@ func (t *Tree) Journal(root common.Hash) (common.Hash, error) { if snap == nil { return common.Hash{}, fmt.Errorf("snapshot [%#x] missing", root) } + // Wait the snapshot(difflayer) is verified, it means the account data also been refreshed with the correct data + if !snap.WaitAndGetVerifyRes() { + return common.Hash{}, ErrSnapshotStale + } + // Run the journaling t.lock.Lock() defer t.lock.Unlock() diff --git a/core/state/state_object.go b/core/state/state_object.go index c5212e91cc..a89feebf28 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -64,10 +64,11 @@ func (s Storage) Copy() Storage { // Account values can be accessed and modified through the object. // 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 - data Account - db *StateDB + address common.Address + addrHash common.Hash // hash of ethereum address of the account + data Account + db *StateDB + rootCorrected bool // To indicate whether the root has been corrected in pipecommit mode // DB error. // State objects are used by the consensus core and VM which are @@ -355,7 +356,17 @@ func (s *StateObject) finalise(prefetch bool) { } } - if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != emptyRoot { + // The account root need to be updated before prefetch, otherwise the account root is empty + if s.db.pipeCommit && s.data.Root == dummyRoot && !s.rootCorrected && s.db.snap.AccountsCorrected() { + if acc, err := s.db.snap.Account(crypto.HashData(s.db.hasher, s.address.Bytes())); err == nil { + if acc != nil && len(acc.Root) != 0 { + s.data.Root = common.BytesToHash(acc.Root) + s.rootCorrected = true + } + } + } + + if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != emptyRoot && s.data.Root != dummyRoot { s.db.prefetcher.prefetch(s.data.Root, slotsToPrefetch, s.addrHash) } if len(s.dirtyStorage) > 0 { diff --git a/core/state/statedb.go b/core/state/statedb.go index c8cb410b0e..2621907f6c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -50,6 +50,10 @@ var ( // emptyRoot is the known root hash of an empty trie. emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + // dummyRoot is the dummy account root before corrected in pipecommit sync mode, + // the value is 542e5fc2709de84248e9bce43a9c0c8943a608029001360f8ab55bf113b23d28 + dummyRoot = crypto.Keccak256Hash([]byte("dummy_account_root")) + emptyAddr = crypto.Keccak256Hash(common.Address{}.Bytes()) ) @@ -229,11 +233,16 @@ func (s *StateDB) MarkLightProcessed() { // Enable the pipeline commit function of statedb func (s *StateDB) EnablePipeCommit() { - if s.snap != nil { + if s.snap != nil && s.snaps.Layers() > 1 { s.pipeCommit = true } } +// IsPipeCommit checks whether pipecommit is enabled on the statedb or not +func (s *StateDB) IsPipeCommit() bool { + return s.pipeCommit +} + // Mark that the block is full processed func (s *StateDB) MarkFullProcessed() { s.fullProcessed = true @@ -965,6 +974,65 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { return s.StateIntermediateRoot() } +//CorrectAccountsRoot will fix account roots in pipecommit mode +func (s *StateDB) CorrectAccountsRoot() { + if accounts, err := s.snap.Accounts(); err == nil && accounts != nil { + for _, obj := range s.stateObjects { + if !obj.deleted && !obj.rootCorrected && obj.data.Root == dummyRoot { + if account, exist := accounts[crypto.Keccak256Hash(obj.address[:])]; exist && len(account.Root) != 0 { + obj.data.Root = common.BytesToHash(account.Root) + } + } + } + } +} + +//PopulateSnapAccountAndStorage tries to populate required accounts and storages for pipecommit +func (s *StateDB) PopulateSnapAccountAndStorage() { + for addr := range s.stateObjectsPending { + if obj := s.stateObjects[addr]; !obj.deleted { + if s.snap != nil && !obj.deleted { + root := obj.data.Root + storageChanged := s.populateSnapStorage(obj) + if storageChanged { + root = dummyRoot + } + s.snapAccounts[obj.address] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, root, obj.data.CodeHash) + } + } + } +} + +//populateSnapStorage tries to populate required storages for pipecommit, and returns a flag to indicate whether the storage root changed or not +func (s *StateDB) populateSnapStorage(obj *StateObject) bool { + for key, value := range obj.dirtyStorage { + obj.pendingStorage[key] = value + } + if len(obj.pendingStorage) == 0 { + return false + } + var storage map[string][]byte + for key, value := range obj.pendingStorage { + var v []byte + if (value != common.Hash{}) { + // Encoding []byte cannot fail, ok to ignore the error. + v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) + } + // If state snapshotting is active, cache the data til commit + if obj.db.snap != nil { + if storage == nil { + // Retrieve the old storage map, if available, create a new one otherwise + if storage = obj.db.snapStorage[obj.address]; storage == nil { + storage = make(map[string][]byte) + obj.db.snapStorage[obj.address] = storage + } + } + storage[string(key[:])] = v // v will be nil if value is 0x00 + } + } + return true +} + func (s *StateDB) AccountsIntermediateRoot() { tasks := make(chan func()) finishCh := make(chan struct{}) @@ -1050,6 +1118,7 @@ func (s *StateDB) StateIntermediateRoot() common.Hash { } s.trie = tr } + usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) for addr := range s.stateObjectsPending { if obj := s.stateObjects[addr]; obj.deleted { @@ -1062,6 +1131,7 @@ func (s *StateDB) StateIntermediateRoot() common.Hash { if prefetcher != nil { prefetcher.used(s.originalRoot, usedAddrs) } + if len(s.stateObjectsPending) > 0 { s.stateObjectsPending = make(map[common.Address]struct{}) } @@ -1239,6 +1309,7 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er var diffLayer *types.DiffLayer var verified chan struct{} var snapUpdated chan struct{} + if s.snap != nil { diffLayer = &types.DiffLayer{} } @@ -1250,9 +1321,24 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er commmitTrie := func() error { commitErr := func() error { + if s.pipeCommit { + <-snapUpdated + // Due to state verification pipeline, the accounts roots are not updated, leading to the data in the difflayer is not correct, capture the correct data here + s.AccountsIntermediateRoot() + if parent := s.snap.Root(); parent != s.expectedRoot { + accountData := make(map[common.Hash][]byte) + for k, v := range s.snapAccounts { + accountData[crypto.Keccak256Hash(k[:])] = v + } + s.snaps.Snapshot(s.expectedRoot).CorrectAccounts(accountData) + } + } + if s.stateRoot = s.StateIntermediateRoot(); s.fullProcessed && s.expectedRoot != s.stateRoot { + log.Error("Invalid merkle root", "remote", s.expectedRoot, "local", s.stateRoot) return fmt.Errorf("invalid merkle root (remote: %x local: %x)", s.expectedRoot, s.stateRoot) } + tasks := make(chan func()) taskResults := make(chan error, len(s.stateObjectsDirty)) tasksNum := 0 @@ -1328,12 +1414,10 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er if s.pipeCommit { if commitErr == nil { - <-snapUpdated s.snaps.Snapshot(s.stateRoot).MarkValid() } else { // The blockchain will do the further rewind if write block not finish yet if failPostCommitFunc != nil { - <-snapUpdated failPostCommitFunc() } log.Error("state verification failed", "err", commitErr) @@ -1383,11 +1467,15 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er if s.pipeCommit { defer close(snapUpdated) } + diffLayer.Destructs, diffLayer.Accounts, diffLayer.Storages = s.SnapToDiffLayer() // Only update if there's a state transition (skip empty Clique blocks) if parent := s.snap.Root(); parent != s.expectedRoot { - if err := s.snaps.Update(s.expectedRoot, parent, s.snapDestructs, s.snapAccounts, s.snapStorage, verified); err != nil { + err := s.snaps.Update(s.expectedRoot, parent, s.snapDestructs, s.snapAccounts, s.snapStorage, verified) + + if err != nil { log.Warn("Failed to update snapshot tree", "from", parent, "to", s.expectedRoot, "err", err) } + // Keep n diff layers in the memory // - head layer is paired with HEAD state // - head-1 layer is paired with HEAD-1 state @@ -1401,12 +1489,6 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er } return nil }, - func() error { - if s.snap != nil { - diffLayer.Destructs, diffLayer.Accounts, diffLayer.Storages = s.SnapToDiffLayer() - } - return nil - }, } if s.pipeCommit { go commmitTrie() diff --git a/core/state_processor.go b/core/state_processor.go index cf2275e722..26f5f84fb9 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -337,7 +337,7 @@ func (p *LightStateProcessor) LightProcess(diffLayer *types.DiffLayer, block *ty } // Do validate in advance so that we can fall back to full process - if err := p.bc.validator.ValidateState(block, statedb, diffLayer.Receipts, gasUsed, false); err != nil { + if err := p.bc.validator.ValidateState(block, statedb, diffLayer.Receipts, gasUsed); err != nil { log.Error("validate state failed during diff sync", "error", err) return nil, nil, 0, err } diff --git a/core/types.go b/core/types.go index 61722aea74..c9061233e6 100644 --- a/core/types.go +++ b/core/types.go @@ -31,7 +31,7 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, skipHeavyVerify bool) error + ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error } // Prefetcher is an interface for pre-caching transaction signatures and state. From cde35b0b3692fca263841620e142b7cbde4f876a Mon Sep 17 00:00:00 2001 From: flywukong <2229306838@qq.com> Date: Tue, 29 Mar 2022 14:22:10 +0800 Subject: [PATCH 087/117] add sharedStorage to the prefetcher of miner (#818) * add sharedStorage to the prefetcher of miner * fix miner prefetcher copy --- core/blockchain.go | 5 +++++ core/state/state_object.go | 4 ++-- core/state_prefetcher.go | 1 + miner/worker.go | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 47ac859441..eeaf1b7e0a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -842,6 +842,11 @@ func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) { return state.New(root, bc.stateCache, bc.snaps) } +// StateAtWithSharedPool returns a new mutable state based on a particular point in time with sharedStorage +func (bc *BlockChain) StateAtWithSharedPool(root common.Hash) (*state.StateDB, error) { + return state.NewWithSharedPool(root, bc.stateCache, bc.snaps) +} + // StateCache returns the caching database underpinning the blockchain instance. func (bc *BlockChain) StateCache() state.Database { return bc.stateCache diff --git a/core/state/state_object.go b/core/state/state_object.go index a89feebf28..b40a8a2f85 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -81,8 +81,8 @@ type StateObject struct { trie Trie // storage trie, which becomes non-nil on first access code Code // contract bytecode, which gets set when code is loaded - sharedOriginStorage *sync.Map // Storage cache of original entries to dedup rewrites, reset for every transaction - originStorage Storage + sharedOriginStorage *sync.Map // Point to the entry of the stateObject in sharedPool + 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 diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index e45a6306df..4909cc3081 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -101,6 +101,7 @@ func (p *statePrefetcher) PrefetchMining(txs *types.TransactionsByPriceAndNonce, go func(startCh <-chan *types.Transaction, stopCh <-chan struct{}) { idx := 0 newStatedb := statedb.Copy() + newStatedb.EnableWriteOnSharedStorage() gaspool := new(GasPool).AddGas(gasLimit) blockContext := NewEVMBlockContext(header, p.bc, nil) evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) diff --git a/miner/worker.go b/miner/worker.go index 2224dc0071..34b3c2fc89 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -661,7 +661,7 @@ func (w *worker) resultLoop() { func (w *worker) makeCurrent(parent *types.Block, header *types.Header) 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.StateAtWithSharedPool(parent.Root()) if err != nil { return err } From 4598334a9a0710a811fc9250ade6573cf443ad07 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Wed, 30 Mar 2022 11:22:00 +0800 Subject: [PATCH 088/117] disable diffsync when pipecommit is enabled (#820) --- cmd/utils/flags.go | 2 +- eth/backend.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 8f5141907f..85d1cef887 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -129,7 +129,7 @@ var ( } PipeCommitFlag = cli.BoolFlag{ Name: "pipecommit", - Usage: "Enable MPT pipeline commit, it will improve syncing performance. It is an experimental feature(default is false)", + Usage: "Enable MPT pipeline commit, it will improve syncing performance. It is an experimental feature(default is false), diffsync will be disable if pipeline commit is enabled", } RangeLimitFlag = cli.BoolFlag{ Name: "rangelimit", diff --git a/eth/backend.go b/eth/backend.go index ab93006437..3f782ff6a8 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -200,7 +200,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } ) bcOps := make([]core.BlockChainOption, 0) - if config.DiffSync { + // TODO diffsync performance is not as expected, disable it when pipecommit is enabled for now + if config.DiffSync && !config.PipeCommit { bcOps = append(bcOps, core.EnableLightProcessor) } if config.PipeCommit { From c57b02c293abeee794c48edd14539a3f2f5387e3 Mon Sep 17 00:00:00 2001 From: flywukong <2229306838@qq.com> Date: Fri, 1 Apr 2022 21:56:23 +0800 Subject: [PATCH 089/117] change prefetch thread num (#830) --- core/state_prefetcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 4909cc3081..bf0a6b80c6 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -26,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum/params" ) -const prefetchThread = 2 +const prefetchThread = 3 const checkInterval = 10 // statePrefetcher is a basic Prefetcher, which blindly executes a block on top From f5a1c073bc9ac786652457719e5540f08abf87ec Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Sat, 2 Apr 2022 11:52:03 +0800 Subject: [PATCH 090/117] fix deadlock when failed to verify state root (#834) --- core/state/statedb.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 2621907f6c..2cdd757a22 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1415,14 +1415,15 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er if s.pipeCommit { if commitErr == nil { s.snaps.Snapshot(s.stateRoot).MarkValid() + close(verified) } else { // The blockchain will do the further rewind if write block not finish yet + close(verified) if failPostCommitFunc != nil { failPostCommitFunc() } log.Error("state verification failed", "err", commitErr) } - close(verified) } return commitErr } From 05925da696fdfbcfa97a42e3f14b18361d237938 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Sat, 2 Apr 2022 17:53:19 +0800 Subject: [PATCH 091/117] fix deadlock on miner module when failed to commit trie (#835) --- core/state/statedb.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 2cdd757a22..76983b2a9c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1366,10 +1366,8 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er // Write any contract code associated with the state object tasks <- func() { // Write any storage changes in the state object to its storage trie - if err := obj.CommitTrie(s.db); err != nil { - taskResults <- err - } - taskResults <- nil + err := obj.CommitTrie(s.db) + taskResults <- err } tasksNum++ } From 1ff47214341cd83ae0cf8b58b5b633d78e345c38 Mon Sep 17 00:00:00 2001 From: qinglin89 <316032931@qq.com> Date: Wed, 6 Apr 2022 13:29:41 +0800 Subject: [PATCH 092/117] fix:replace fake transaction with first peek for txCurr --- miner/worker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 34b3c2fc89..6715213e94 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -782,10 +782,10 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin interruptCh := make(chan struct{}) defer close(interruptCh) - tx := &types.Transaction{} - txCurr := &tx //prefetch txs from all pending txs txsPrefetch := txs.Copy() + tx := txsPrefetch.Peek() + txCurr := &tx w.prefetcher.PrefetchMining(txsPrefetch, w.current.header, w.current.gasPool.Gas(), w.current.state.Copy(), *w.chain.GetVMConfig(), interruptCh, txCurr) LOOP: From 343b3150303f1768940efdc161cde49fa38a2552 Mon Sep 17 00:00:00 2001 From: WayToFuture <61674316+forcodedancing@users.noreply.github.com> Date: Wed, 6 Apr 2022 18:21:54 +0800 Subject: [PATCH 093/117] put error check to the correct location (#842) Co-authored-by: forcodedancing --- 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 26f5f84fb9..8e9422a8e8 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -123,13 +123,13 @@ func (p *LightStateProcessor) Process(block *types.Block, statedb *state.StateDB statedb.StopPrefetcher() parent := p.bc.GetHeader(block.ParentHash(), block.NumberU64()-1) statedb, err = state.New(parent.Root, p.bc.stateCache, p.bc.snaps) + if err != nil { + return statedb, nil, nil, 0, err + } statedb.SetExpectedStateRoot(block.Root()) if p.bc.pipeCommit { statedb.EnablePipeCommit() } - if err != nil { - return statedb, nil, nil, 0, err - } // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") } From 1aeadc143aa876a64ab6783e2cce8b62c66b14f7 Mon Sep 17 00:00:00 2001 From: WayToFuture <61674316+forcodedancing@users.noreply.github.com> Date: Fri, 8 Apr 2022 15:59:40 +0800 Subject: [PATCH 094/117] [R4R] prepare for release of v1.1.9 (#849) * prepare release of v1.1.9 * prepare release of v1.1.9 * prepare release of v1.1.9 Co-authored-by: forcodedancing --- .github/release.env | 4 ++-- CHANGELOG.md | 19 +++++++++++++++++++ params/version.go | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.github/release.env b/.github/release.env index 2034c1d3fa..62e94fa4bd 100644 --- a/.github/release.env +++ b/.github/release.env @@ -1,2 +1,2 @@ -MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.7/mainnet.zip" -TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.7/testnet.zip" +MAINNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.8/mainnet.zip" +TESTNET_FILE_URL="https://github.com/binance-chain/bsc/releases/download/v1.1.8/testnet.zip" diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dfa55dfb8..9100249fa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## v1.1.9 + +IMPROVEMENT +* [\#792](https://github.com/binance-chain/bsc/pull/792) add shared storage for prefetching state data +* [\#795](https://github.com/binance-chain/bsc/pull/795) implement state verification pipeline in pipecommit +* [\#803](https://github.com/binance-chain/bsc/pull/803) prefetch state data during the mining process +* [\#812](https://github.com/bnb-chain/bsc/pull/812) skip verification on account storage root to tolerate with fastnode when doing diffsync +* [\#818](https://github.com/bnb-chain/bsc/pull/818) add shared storage to the prefetcher of miner +* [\#820](https://github.com/bnb-chain/bsc/pull/820) disable diffsync when pipecommit is enabled +* [\#830](https://github.com/bnb-chain/bsc/pull/830) change the number of prefetch threads + +BUGFIX +* [\#797](https://github.com/bnb-chain/bsc/pull/797) fix race condition on preimage in pipecommit +* [\#808](https://github.com/bnb-chain/bsc/pull/808) fix code of difflayer not assign when new smart contract created +* [\#817](https://github.com/bnb-chain/bsc/pull/817) fix bugs of prune block tool +* [\#834](https://github.com/bnb-chain/bsc/pull/834) fix deadlock when failed to verify state root in pipecommit +* [\#835](https://github.com/bnb-chain/bsc/pull/835) fix deadlock on miner module when failed to commit trie +* [\#842](https://github.com/bnb-chain/bsc/pull/842) fix invalid nil check of statedb in diffsync + ## v1.1.8 FEATURES * [\#668](https://github.com/binance-chain/bsc/pull/668) implement State Verification && Snapshot Commit pipeline diff --git a/params/version.go b/params/version.go index 8faa4bb644..634f527876 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 8 // Patch version component of the current release + VersionPatch = 9 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From 15bc2548c134aae697cb1081727d3d49bd373025 Mon Sep 17 00:00:00 2001 From: Jolly Zhao Date: Sun, 24 Apr 2022 14:24:07 +0800 Subject: [PATCH 095/117] fix logic issue: handlers.removePeer() is called twice. (#856) * fix logic issue: handlers.removePeer() is called twice. There is a logic issue which cause "Ethereum peer removal failed, err=peer not registered" occur quite often. handler.runEthPeer set up a defer removePeer(). This is always called after a peer is disconnected. However removePeer is also called by mulitple functions like downloader/fetcher. After those kind of functions removePeer(), peer handler executes defer removePeer(). This makes removePeer() happened twice, and this is the reason we often see "Ethereum peer removal failed, err=peer not registered". To solve this, removePeer only needs to hard Disconnect peer from networking layer. Then defer unregisterPeer() will do the cleanup task after then. * fix: modify test function for close testing. reference from go-thereum. Co-authored-by: zjubfd <296179868@qq.com> --- eth/handler.go | 16 +++++++++++----- eth/handler_eth_test.go | 17 ++++++++++++----- p2p/peer.go | 16 +++++++++++++++- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/eth/handler.go b/eth/handler.go index cbc6eca809..d6d2cfd6c6 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -313,7 +313,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Error("Ethereum peer registration failed", "err", err) return err } - defer h.removePeer(peer.ID()) + defer h.unregisterPeer(peer.ID()) p := h.peers.peer(peer.ID()) if p == nil { @@ -395,9 +395,17 @@ func (h *handler) runDiffExtension(peer *diff.Peer, handler diff.Handler) error return handler(peer) } -// removePeer unregisters a peer from the downloader and fetchers, removes it from -// the set of tracked peers and closes the network connection to it. +// removePeer requests disconnection of a peer. func (h *handler) removePeer(id string) { + peer := h.peers.peer(id) + if peer != nil { + // Hard disconnect at the networking layer. Handler will get an EOF and terminate the peer. defer unregisterPeer will do the cleanup task after then. + peer.Peer.Disconnect(p2p.DiscUselessPeer) + } +} + +// unregisterPeer removes a peer from the downloader, fetchers and main peer set. +func (h *handler) unregisterPeer(id string) { // Create a custom logger to avoid printing the entire id var logger log.Logger if len(id) < 16 { @@ -425,8 +433,6 @@ func (h *handler) removePeer(id string) { if err := h.peers.unregisterPeer(id); err != nil { logger.Error("Ethereum peer removal failed", "err", err) } - // Hard disconnect at the networking layer - peer.Peer.Disconnect(p2p.DiscUselessPeer) } func (h *handler) Start(maxPeers int) { diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index e85c74e6f2..1aedadd225 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -641,14 +641,20 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo defer p2pLocal.Close() defer p2pRemote.Close() - local := eth.NewPeer(eth.ETH65, p2p.NewPeer(enode.ID{1}, "", nil), p2pLocal, handler.txpool) - remote := eth.NewPeer(eth.ETH65, p2p.NewPeer(enode.ID{2}, "", nil), p2pRemote, handler.txpool) + local := eth.NewPeer(eth.ETH65, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pLocal), p2pLocal, handler.txpool) + remote := eth.NewPeer(eth.ETH65, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pRemote), p2pRemote, handler.txpool) defer local.Close() defer remote.Close() - go handler.handler.runEthPeer(local, func(peer *eth.Peer) error { - return eth.Handle((*ethHandler)(handler.handler), peer) - }) + handlerDone := make(chan struct{}) + go func() { + defer close(handlerDone) + handler.handler.runEthPeer(local, func(peer *eth.Peer) error { + err := eth.Handle((*ethHandler)(handler.handler), peer) + return err + }) + }() + // Run the handshake locally to avoid spinning up a remote handler var ( genesis = handler.chain.Genesis() @@ -685,6 +691,7 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo // Verify that the remote peer is maintained or dropped if drop { + <-handlerDone if peers := handler.handler.peers.len(); peers != 0 { t.Fatalf("peer count mismatch: have %d, want %d", peers, 0) } diff --git a/p2p/peer.go b/p2p/peer.go index 3b633108db..7b9e4d5940 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -116,7 +116,8 @@ type Peer struct { disc chan DiscReason // events receives message send / receive events if set - events *event.Feed + events *event.Feed + testPipe *MsgPipeRW // for testing } // NewPeer returns a peer for testing purposes. @@ -129,6 +130,15 @@ func NewPeer(id enode.ID, name string, caps []Cap) *Peer { return peer } +// NewPeerPipe creates a peer for testing purposes. +// The message pipe given as the last parameter is closed when +// Disconnect is called on the peer. +func NewPeerPipe(id enode.ID, name string, caps []Cap, pipe *MsgPipeRW) *Peer { + p := NewPeer(id, name, caps) + p.testPipe = pipe + return p +} + // NewPeerWithProtocols returns a peer for testing purposes. func NewPeerWithProtocols(id enode.ID, protocols []Protocol, name string, caps []Cap) *Peer { pipe, _ := net.Pipe() @@ -196,6 +206,10 @@ func (p *Peer) LocalAddr() net.Addr { // Disconnect terminates the peer connection with the given reason. // It returns immediately and does not wait until the connection is closed. func (p *Peer) Disconnect(reason DiscReason) { + if p.testPipe != nil { + p.testPipe.Close() + } + select { case p.disc <- reason: case <-p.closed: From 0f5a4c87dbb5a7223d21fa6cc9d7020f676dfa05 Mon Sep 17 00:00:00 2001 From: Leon <316032931@qq.com> Date: Mon, 25 Apr 2022 10:47:02 +0800 Subject: [PATCH 096/117] [R4R]fix:Shift panic for zero length of heads (#870) * fix:Shift panic for zero length of heads * fix: make sure peek before shift * refactor and update ut * refactor --- core/state_prefetcher.go | 18 ++++++++---------- core/types/transaction.go | 4 +++- core/types/transaction_test.go | 5 ++++- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index bf0a6b80c6..a2c2df16a4 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -127,23 +127,21 @@ func (p *statePrefetcher) PrefetchMining(txs *types.TransactionsByPriceAndNonce, go func(txset *types.TransactionsByPriceAndNonce) { count := 0 for { - tx := txset.Peek() - if tx == nil { - return - } select { case <-interruptCh: return default: - } - if count++; count%checkInterval == 0 { - if *txCurr == nil { + if count++; count%checkInterval == 0 { + txset.Forward(*txCurr) + } + tx := txset.Peek() + if tx == nil { return } - txset.Forward(*txCurr) + txCh <- tx + txset.Shift() + } - txCh <- tx - txset.Shift() } }(txs) } diff --git a/core/types/transaction.go b/core/types/transaction.go index e95cec25a6..5c8d04c010 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -506,7 +506,9 @@ func (t *TransactionsByPriceAndNonce) CurrentSize() int { //Forward moves current transaction to be the one which is one index after tx func (t *TransactionsByPriceAndNonce) Forward(tx *Transaction) { if tx == nil { - t.heads = t.heads[0:0] + if len(t.heads) > 0 { + t.heads = t.heads[0:0] + } return } //check whether target tx exists in t.heads diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index c81b7b8647..a5fbb50928 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -392,7 +392,7 @@ func TestTransactionForward(t *testing.T) { } tmp := txset.Copy() - for j := 0; j < 10; j++ { + for j := 0; j < 11; j++ { txset = tmp.Copy() txsetCpy = tmp.Copy() i := 0 @@ -400,6 +400,9 @@ func TestTransactionForward(t *testing.T) { txset.Shift() } tx := txset.Peek() + if tx == nil { + continue + } txsetCpy.Forward(tx) txCpy := txsetCpy.Peek() if txCpy == nil { From 717b38c5f53b623054280c528b55ad7db711ba5a Mon Sep 17 00:00:00 2001 From: Leon <316032931@qq.com> Date: Thu, 28 Apr 2022 18:22:02 +0800 Subject: [PATCH 097/117] [R4R] fix:defer bloomprocessor close (#860) * fix:defer bloomprocessor close * fix: fix deadlock in Close * perf:rm defer bloomprocessors Close and manual close before return --- core/state_processor.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/state_processor.go b/core/state_processor.go index 8e9422a8e8..cdaaf1e643 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -410,6 +410,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for i, tx := range block.Transactions() { if isPoSA { if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { + bloomProcessors.Close() return statedb, nil, nil, 0, err } else if isSystemTx { systemTxs = append(systemTxs, tx) @@ -419,11 +420,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg msg, err := tx.AsMessage(signer) if err != nil { + bloomProcessors.Close() return statedb, nil, nil, 0, err } statedb.Prepare(tx.Hash(), block.Hash(), i) receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv, bloomProcessors) if err != nil { + bloomProcessors.Close() return statedb, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } From 5b5abc4e225b11cae36c8e4669508248513b1330 Mon Sep 17 00:00:00 2001 From: WayToFuture Date: Fri, 29 Apr 2022 15:45:55 +0800 Subject: [PATCH 098/117] [R4R] fix validator pipecommit issue (#877) * fix validator account root issue in piepecommit * fix test and imports * add check for snap * refacto a bit --- core/block_validator.go | 5 ++--- core/state/statedb.go | 17 +++++++++++++++-- miner/worker.go | 3 +++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index c6a35f1fdf..4cf53a6cdc 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -20,6 +20,7 @@ import ( "fmt" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -140,10 +141,8 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD if err := statedb.WaitPipeVerification(); err != nil { return err } - statedb.CorrectAccountsRoot() + statedb.CorrectAccountsRoot(common.Hash{}) statedb.Finalise(v.config.IsEIP158(header.Number)) - // State verification pipeline - accounts root are not calculated here, just populate needed fields for process - statedb.PopulateSnapAccountAndStorage() return nil }) } else { diff --git a/core/state/statedb.go b/core/state/statedb.go index 76983b2a9c..ade1b5804f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -975,12 +975,23 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } //CorrectAccountsRoot will fix account roots in pipecommit mode -func (s *StateDB) CorrectAccountsRoot() { - if accounts, err := s.snap.Accounts(); err == nil && accounts != nil { +func (s *StateDB) CorrectAccountsRoot(blockRoot common.Hash) { + var snapshot snapshot.Snapshot + if blockRoot == (common.Hash{}) { + snapshot = s.snap + } else if s.snaps != nil { + snapshot = s.snaps.Snapshot(blockRoot) + } + + if snapshot == nil { + return + } + if accounts, err := snapshot.Accounts(); err == nil && accounts != nil { for _, obj := range s.stateObjects { if !obj.deleted && !obj.rootCorrected && obj.data.Root == dummyRoot { if account, exist := accounts[crypto.Keccak256Hash(obj.address[:])]; exist && len(account.Root) != 0 { obj.data.Root = common.BytesToHash(account.Root) + obj.rootCorrected = true } } } @@ -1465,6 +1476,8 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er } if s.pipeCommit { defer close(snapUpdated) + // State verification pipeline - accounts root are not calculated here, just populate needed fields for process + s.PopulateSnapAccountAndStorage() } diffLayer.Destructs, diffLayer.Accounts, diffLayer.Storages = s.SnapToDiffLayer() // Only update if there's a state transition (skip empty Clique blocks) diff --git a/miner/worker.go b/miner/worker.go index 6715213e94..2b9bf43305 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1009,6 +1009,9 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st if err != nil { return err } + + s.CorrectAccountsRoot(w.chain.CurrentBlock().Root()) + block, receipts, err := w.engine.FinalizeAndAssemble(w.chain, types.CopyHeader(w.current.header), s, w.current.txs, uncles, w.current.receipts) if err != nil { return err From 4feb52e5b027f4d7e72c74796b7ca1bf5d17102e Mon Sep 17 00:00:00 2001 From: Gothery <90246878+gothery001@users.noreply.github.com> Date: Fri, 29 Apr 2022 18:03:22 +0800 Subject: [PATCH 099/117] [R4R]: add Euler Hardfork, including BEP-127 and BEP-131 (#885) * feat: add BEP-127 and BEP-131 hardfork bytecode to upgrade * feat: force check that Euler height cannot be a multiple of 200, fix getCurrentValidators, raise SystemTxsGas after Euler fork Co-authored-by: goth --- consensus/parlia/abi.go | 1035 ++++++++++++++++++++++++++++--- consensus/parlia/parlia.go | 9 +- core/systemcontracts/upgrade.go | 55 ++ eth/catalyst/api_test.go | 1 + miner/worker.go | 7 +- params/config.go | 43 +- 6 files changed, 1048 insertions(+), 102 deletions(-) diff --git a/consensus/parlia/abi.go b/consensus/parlia/abi.go index a0b49800c4..e841eb5cd5 100644 --- a/consensus/parlia/abi.go +++ b/consensus/parlia/abi.go @@ -6,7 +6,7 @@ const validatorSetABI = ` "anonymous": false, "inputs": [ { - "indexed": true, + "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" @@ -15,6 +15,44 @@ const validatorSetABI = ` "name": "batchTransfer", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "batchTransferFailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + } + ], + "name": "batchTransferLowerFailed", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -25,7 +63,7 @@ const validatorSetABI = ` "type": "address" }, { - "indexed": true, + "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" @@ -44,7 +82,7 @@ const validatorSetABI = ` "type": "address" }, { - "indexed": true, + "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" @@ -58,6 +96,70 @@ const validatorSetABI = ` "inputs": [ { "indexed": true, + "internalType": "address payable", + "name": "validator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "directTransferFail", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "message", + "type": "string" + } + ], + "name": "failReasonWithStr", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "feeBurned", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "key", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "value", + "type": "bytes" + } + ], + "name": "paramChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" @@ -66,6 +168,25 @@ const validatorSetABI = ` "name": "systemTransfer", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "channelId", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "msgBytes", + "type": "bytes" + } + ], + "name": "unexpectedPackage", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -76,7 +197,7 @@ const validatorSetABI = ` "type": "address" }, { - "indexed": true, + "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" @@ -93,9 +214,48 @@ const validatorSetABI = ` "internalType": "address", "name": "validator", "type": "address" - }, + } + ], + "name": "validatorEmptyJailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "validatorEnterMaintenance", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "validatorExitMaintenance", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" @@ -127,7 +287,7 @@ const validatorSetABI = ` "type": "address" }, { - "indexed": true, + "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" @@ -144,7 +304,7 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "CHANNEL_ID", + "name": "BIND_CHANNELID", "outputs": [ { "internalType": "uint8", @@ -157,12 +317,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "DUSTY_INCOMING", + "name": "BURN_ADDRESS", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", @@ -170,7 +330,7 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "EXTRA_FEE", + "name": "BURN_RATIO_SCALE", "outputs": [ { "internalType": "uint256", @@ -183,12 +343,25 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "JAIL_MESSAGE_TYPE", + "name": "CODE_OK", "outputs": [ { - "internalType": "uint8", + "internalType": "uint32", "name": "", - "type": "uint8" + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CROSS_CHAIN_CONTRACT_ADDR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" } ], "stateMutability": "view", @@ -196,7 +369,7 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "RELAYER_REWARD", + "name": "DUSTY_INCOMING", "outputs": [ { "internalType": "uint256", @@ -209,12 +382,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "SYSTEM_ADDRESS", + "name": "EPOCH", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -222,12 +395,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "VALIDATORS_UPDATE_MESSAGE_TYPE", + "name": "ERROR_FAIL_CHECK_VALIDATORS", "outputs": [ { - "internalType": "uint8", + "internalType": "uint32", "name": "", - "type": "uint8" + "type": "uint32" } ], "stateMutability": "view", @@ -235,55 +408,63 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "alreadyInit", + "name": "ERROR_FAIL_DECODE", "outputs": [ { - "internalType": "bool", + "internalType": "uint32", "name": "", - "type": "bool" + "type": "uint32" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "ERROR_LEN_OF_VAL_MISMATCH", + "outputs": [ { - "internalType": "uint256", + "internalType": "uint32", "name": "", - "type": "uint256" + "type": "uint32" } ], - "name": "currentValidatorSet", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ERROR_RELAYFEE_TOO_LARGE", "outputs": [ { - "internalType": "address", - "name": "consensusAddress", - "type": "address" - }, - { - "internalType": "address payable", - "name": "feeAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "BBCFeeAddress", - "type": "address" - }, - { - "internalType": "uint64", - "name": "votingPower", - "type": "uint64" - }, + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ERROR_UNKNOWN_PACKAGE_TYPE", + "outputs": [ { - "internalType": "bool", - "name": "jailed", - "type": "bool" - }, + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "EXPIRE_TIME_SECOND_GAP", + "outputs": [ { "internalType": "uint256", - "name": "incoming", + "name": "", "type": "uint256" } ], @@ -292,12 +473,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "fromChainId", + "name": "GOV_CHANNELID", "outputs": [ { - "internalType": "uint16", + "internalType": "uint8", "name": "", - "type": "uint16" + "type": "uint8" } ], "stateMutability": "view", @@ -305,7 +486,7 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "initLightClientAddr", + "name": "GOV_HUB_ADDR", "outputs": [ { "internalType": "address", @@ -318,7 +499,7 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "initSlashContract", + "name": "INCENTIVIZE_ADDR", "outputs": [ { "internalType": "address", @@ -331,12 +512,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "initSystemRewardAddr", + "name": "INIT_BURN_RATIO", "outputs": [ { - "internalType": "address payable", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -344,12 +525,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "initTokenHubAddr", + "name": "INIT_MAINTAIN_SLASH_SCALE", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -357,12 +538,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "initValidatorSetBytes", + "name": "INIT_MAX_NUM_OF_MAINTAINING", "outputs": [ { - "internalType": "bytes", + "internalType": "uint256", "name": "", - "type": "bytes" + "type": "uint256" } ], "stateMutability": "view", @@ -370,12 +551,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "keyPrefix", + "name": "INIT_NUM_OF_CABINETS", "outputs": [ { - "internalType": "bytes", + "internalType": "uint256", "name": "", - "type": "bytes" + "type": "uint256" } ], "stateMutability": "view", @@ -383,12 +564,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "previousDepositHeight", + "name": "INIT_VALIDATORSET_BYTES", "outputs": [ { - "internalType": "uint64", + "internalType": "bytes", "name": "", - "type": "uint64" + "type": "bytes" } ], "stateMutability": "view", @@ -396,12 +577,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "sequence", + "name": "JAIL_MESSAGE_TYPE", "outputs": [ { - "internalType": "uint64", + "internalType": "uint8", "name": "", - "type": "uint64" + "type": "uint8" } ], "stateMutability": "view", @@ -409,12 +590,12 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "toChainId", + "name": "LIGHT_CLIENT_ADDR", "outputs": [ { - "internalType": "uint16", + "internalType": "address", "name": "", - "type": "uint16" + "type": "address" } ], "stateMutability": "view", @@ -422,7 +603,7 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "totalInComing", + "name": "MAX_NUM_OF_VALIDATORS", "outputs": [ { "internalType": "uint256", @@ -435,9 +616,403 @@ const validatorSetABI = ` }, { "inputs": [], - "name": "init", - "outputs": [], - "stateMutability": "nonpayable", + "name": "PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RELAYERHUB_CONTRACT_ADDR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SLASH_CHANNELID", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SLASH_CONTRACT_ADDR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STAKING_CHANNELID", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SYSTEM_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SYSTEM_REWARD_ADDR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN_HUB_ADDR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN_MANAGER_ADDR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TRANSFER_IN_CHANNELID", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TRANSFER_OUT_CHANNELID", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VALIDATORS_UPDATE_MESSAGE_TYPE", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VALIDATOR_CONTRACT_ADDR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "alreadyInit", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bscChainID", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "burnRatio", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "burnRatioInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "currentValidatorSet", + "outputs": [ + { + "internalType": "address", + "name": "consensusAddress", + "type": "address" + }, + { + "internalType": "address payable", + "name": "feeAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "BBCFeeAddress", + "type": "address" + }, + { + "internalType": "uint64", + "name": "votingPower", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "jailed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "incoming", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "currentValidatorSetMap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "expireTimeSecondGap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maintainSlashScale", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxNumOfCandidates", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxNumOfMaintaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxNumOfWorkingCandidates", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numOfCabinets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numOfJailed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numOfMaintaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalInComing", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", "type": "function" }, { @@ -446,41 +1021,175 @@ const validatorSetABI = ` "internalType": "address", "name": "valAddr", "type": "address" + }, + { + "internalType": "address", + "name": "slashAddr", + "type": "address" + }, + { + "internalType": "address", + "name": "rewardAddr", + "type": "address" + }, + { + "internalType": "address", + "name": "lightAddr", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenHubAddr", + "type": "address" + }, + { + "internalType": "address", + "name": "incentivizeAddr", + "type": "address" + }, + { + "internalType": "address", + "name": "relayerHubAddr", + "type": "address" + }, + { + "internalType": "address", + "name": "govHub", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenManagerAddr", + "type": "address" + }, + { + "internalType": "address", + "name": "crossChain", + "type": "address" } ], - "name": "deposit", + "name": "updateContractAddr", "outputs": [], - "stateMutability": "payable", + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "validatorExtraSet", + "outputs": [ + { + "internalType": "uint256", + "name": "enterMaintenanceHeight", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isMaintaining", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + }, { "internalType": "bytes", "name": "msgBytes", "type": "bytes" - }, + } + ], + "name": "handleSynPackage", + "outputs": [ { "internalType": "bytes", - "name": "proof", + "name": "responsePayload", "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "channelId", + "type": "uint8" }, { - "internalType": "uint64", - "name": "height", - "type": "uint64" + "internalType": "bytes", + "name": "msgBytes", + "type": "bytes" + } + ], + "name": "handleAckPackage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "channelId", + "type": "uint8" }, { - "internalType": "uint64", - "name": "packageSequence", - "type": "uint64" + "internalType": "bytes", + "name": "msgBytes", + "type": "bytes" } ], - "name": "update", + "name": "handleFailAckPackage", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "valAddr", + "type": "address" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "getMiningValidators", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "getValidators", @@ -494,6 +1203,25 @@ const validatorSetABI = ` "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "isWorkingValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -513,6 +1241,25 @@ const validatorSetABI = ` "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "isCurrentValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -538,6 +1285,108 @@ const validatorSetABI = ` "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validator", + "type": "address" + } + ], + "name": "getCurrentValidatorIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "canEnterMaintenance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "enterMaintenance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "exitMaintenance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "key", + "type": "string" + }, + { + "internalType": "bytes", + "name": "value", + "type": "bytes" + } + ], + "name": "updateParam", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "isValidatorExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaintainingValidators", + "outputs": [ + { + "internalType": "address[]", + "name": "maintainingValidators", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" } ] ` diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 7ff9219877..e954b42229 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -616,7 +616,7 @@ func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header header.Extra = append(header.Extra, nextForkHash[:]...) if number%p.config.Epoch == 0 { - newValidators, err := p.getCurrentValidators(header.ParentHash) + newValidators, err := p.getCurrentValidators(header.ParentHash, new(big.Int).Sub(header.Number, common.Big1)) if err != nil { return err } @@ -662,7 +662,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade // If the block is a epoch end block, verify the validator list // The verification can only be done when the state is ready, it can't be done in VerifyHeader. if header.Number.Uint64()%p.config.Epoch == 0 { - newValidators, err := p.getCurrentValidators(header.ParentHash) + newValidators, err := p.getCurrentValidators(header.ParentHash, new(big.Int).Sub(header.Number, common.Big1)) if err != nil { return err } @@ -997,12 +997,15 @@ func (p *Parlia) Close() error { // ========================== interaction with contract/account ========= // getCurrentValidators get current validators -func (p *Parlia) getCurrentValidators(blockHash common.Hash) ([]common.Address, error) { +func (p *Parlia) getCurrentValidators(blockHash common.Hash, blockNumber *big.Int) ([]common.Address, error) { // block blockNr := rpc.BlockNumberOrHashWithHash(blockHash, false) // method method := "getValidators" + if p.chainConfig.IsEuler(blockNumber) { + method = "getMiningValidators" + } ctx, cancel := context.WithCancel(context.Background()) defer cancel() // cancel when we are finished consuming integers diff --git a/core/systemcontracts/upgrade.go b/core/systemcontracts/upgrade.go index a040bf8d64..b5e6c7e781 100644 --- a/core/systemcontracts/upgrade.go +++ b/core/systemcontracts/upgrade.go @@ -43,6 +43,8 @@ var ( mirrorUpgrade = make(map[string]*Upgrade) brunoUpgrade = make(map[string]*Upgrade) + + eulerUpgrade = make(map[string]*Upgrade) ) func init() { @@ -309,6 +311,55 @@ func init() { }, }, } + + eulerUpgrade[mainNet] = &Upgrade{ + UpgradeName: "euler", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(ValidatorContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/db8bb560ac5a1265c685b719c7e976dced162310", + Code: "6080604052600436106104055760003560e01c80638d19a41011610213578063c81b166211610123578063eb57e202116100ab578063f9a2bbc71161007a578063f9a2bbc714610d55578063fc3e590814610d6a578063fccc281314610d7f578063fd4ad81f14610d94578063fd6a687914610dd757610405565b8063eb57e20214610cd2578063eda5868c14610d05578063f340fa0114610d1a578063f92eb86b14610d4057610405565b8063daacdb66116100f2578063daacdb6614610c69578063dc927faf14610c7e578063e086c7b114610c93578063e1c7392a14610ca8578063e40716a114610cbd57610405565b8063c81b166214610c2a578063c8509d8114610939578063d68fb56a14610c3f578063d86222d514610c5457610405565b8063a78abc16116101a6578063ad3c9da611610175578063ad3c9da614610bb8578063b7ab4db514610beb578063b8cf4ef114610c00578063bf9f49951461065f578063c6d3394514610c1557610405565b8063a78abc1614610aae578063aaf5eb6814610ac3578063ab51bb9614610ad8578063ac43175114610aed57610405565b80639fe0f816116101e25780639fe0f81614610a5a578063a0dc275814610a6f578063a1a11bf514610a84578063a5422d5c14610a9957610405565b80638d19a410146109e85780639369d7de14610a1b57806396713da914610a305780639dc0926214610a4557610405565b80635192c82c1161031957806375d47a0a116102a157806381650b621161027057806381650b6214610924578063831d65d114610939578063853230aa146108e557806386249882146109be5780638b5ad0c9146109d357610405565b806375d47a0a146108d057806378dfed4a146108e55780637942fd05146108fa5780637a84ca2a1461090f57610405565b80635667515a116102e85780635667515a146108065780635d77156c1461081b5780636969a25c146108305780636e47b482146108a657806370fd5bad146108bb57610405565b80635192c82c1461077657806351e806721461078b57806355614fcc146107a0578063565c56b3146107d357610405565b80633365af3a1161039c57806343756e5c1161036b57806343756e5c1461068a57806345cf9daf146106bb578063493279b1146106d05780634bf6c882146106fc5780634df6e0c31461071157610405565b80633365af3a146105ed57806335409f7f146106175780633de0f0d81461064a5780633dffc3871461065f57610405565b8063152ad3b8116103d8578063152ad3b8146105705780631ff1806914610599578063219f22d5146105ae578063321d398a146105c357610405565b806304c4fec61461040a57806307a56847146104215780630bee7a67146104485780631182b87514610476575b600080fd5b34801561041657600080fd5b5061041f610dec565b005b34801561042d57600080fd5b50610436610e7f565b60408051918252519081900360200190f35b34801561045457600080fd5b5061045d610e85565b6040805163ffffffff9092168252519081900360200190f35b34801561048257600080fd5b506104fb6004803603604081101561049957600080fd5b60ff8235169190810190604081016020820135600160201b8111156104bd57600080fd5b8201836020820111156104cf57600080fd5b803590602001918460018302840111600160201b831117156104f057600080fd5b509092509050610e8a565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561053557818101518382015260200161051d565b50505050905090810190601f1680156105625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561057c57600080fd5b5061058561111c565b604080519115158252519081900360200190f35b3480156105a557600080fd5b50610436611125565b3480156105ba57600080fd5b5061045d61112b565b3480156105cf57600080fd5b50610585600480360360208110156105e657600080fd5b5035611130565b3480156105f957600080fd5b506105856004803603602081101561061057600080fd5b50356111ff565b34801561062357600080fd5b5061041f6004803603602081101561063a57600080fd5b50356001600160a01b03166112b0565b34801561065657600080fd5b5061043661140f565b34801561066b57600080fd5b50610674611415565b6040805160ff9092168252519081900360200190f35b34801561069657600080fd5b5061069f61141a565b604080516001600160a01b039092168252519081900360200190f35b3480156106c757600080fd5b50610436611420565b3480156106dc57600080fd5b506106e5611426565b6040805161ffff9092168252519081900360200190f35b34801561070857600080fd5b5061067461142b565b34801561071d57600080fd5b50610726611430565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561076257818101518382015260200161074a565b505050509050019250505060405180910390f35b34801561078257600080fd5b5061043661152b565b34801561079757600080fd5b5061069f611531565b3480156107ac57600080fd5b50610585600480360360208110156107c357600080fd5b50356001600160a01b0316611537565b3480156107df57600080fd5b50610436600480360360208110156107f657600080fd5b50356001600160a01b031661156c565b34801561081257600080fd5b506106746115bd565b34801561082757600080fd5b5061045d6115c2565b34801561083c57600080fd5b5061085a6004803603602081101561085357600080fd5b50356115c7565b604080516001600160a01b039788168152958716602087015293909516848401526001600160401b0390911660608401521515608083015260a082019290925290519081900360c00190f35b3480156108b257600080fd5b5061069f61162b565b3480156108c757600080fd5b50610674611631565b3480156108dc57600080fd5b5061069f611636565b3480156108f157600080fd5b5061043661163c565b34801561090657600080fd5b50610674611642565b34801561091b57600080fd5b50610436611647565b34801561093057600080fd5b5061045d61164d565b34801561094557600080fd5b5061041f6004803603604081101561095c57600080fd5b60ff8235169190810190604081016020820135600160201b81111561098057600080fd5b82018360208201111561099257600080fd5b803590602001918460018302840111600160201b831117156109b357600080fd5b509092509050611652565b3480156109ca57600080fd5b50610436611705565b3480156109df57600080fd5b5061043661170b565b3480156109f457600080fd5b5061043660048036036020811015610a0b57600080fd5b50356001600160a01b0316611711565b348015610a2757600080fd5b5061041f611786565b348015610a3c57600080fd5b506106746118a0565b348015610a5157600080fd5b5061069f6118a5565b348015610a6657600080fd5b506104366118ab565b348015610a7b57600080fd5b506104366118b0565b348015610a9057600080fd5b5061069f6118b5565b348015610aa557600080fd5b506104fb6118bb565b348015610aba57600080fd5b506105856118da565b348015610acf57600080fd5b506104366118e3565b348015610ae457600080fd5b5061045d6115bd565b348015610af957600080fd5b5061041f60048036036040811015610b1057600080fd5b810190602081018135600160201b811115610b2a57600080fd5b820183602082011115610b3c57600080fd5b803590602001918460018302840111600160201b83111715610b5d57600080fd5b919390929091602081019035600160201b811115610b7a57600080fd5b820183602082011115610b8c57600080fd5b803590602001918460018302840111600160201b83111715610bad57600080fd5b5090925090506118ec565b348015610bc457600080fd5b5061043660048036036020811015610bdb57600080fd5b50356001600160a01b0316612329565b348015610bf757600080fd5b5061072661233b565b348015610c0c57600080fd5b5061043661241e565b348015610c2157600080fd5b50610436611631565b348015610c3657600080fd5b5061069f612423565b348015610c4b57600080fd5b50610436612429565b348015610c6057600080fd5b50610436612468565b348015610c7557600080fd5b50610436612474565b348015610c8a57600080fd5b5061069f61247a565b348015610c9f57600080fd5b50610436612480565b348015610cb457600080fd5b5061041f612485565b348015610cc957600080fd5b50610436612688565b348015610cde57600080fd5b5061041f60048036036020811015610cf557600080fd5b50356001600160a01b031661268e565b348015610d1157600080fd5b5061045d61279c565b61041f60048036036020811015610d3057600080fd5b50356001600160a01b03166127a1565b348015610d4c57600080fd5b50610436612aa6565b348015610d6157600080fd5b5061069f612aac565b348015610d7657600080fd5b506106746118ab565b348015610d8b57600080fd5b5061069f612ab2565b348015610da057600080fd5b50610dbe60048036036020811015610db757600080fd5b5035612ab8565b6040805192835290151560208301528051918290030190f35b348015610de357600080fd5b5061069f612ae6565b6000610df733611711565b9050600b8181548110610e0657fe5b600091825260209091206001601690920201015460ff16610e63576040805162461bcd60e51b81526020600482015260126024820152716e6f7420696e206d61696e74656e616e636560701b604482015290519081900360640190fd5b6000610e6d612429565b9050610e7a338383612aec565b505050565b60095481565b606481565b60005460609060ff16610ee0576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b3361200014610f205760405162461bcd60e51b815260040180806020018281038252602f81526020018061648b602f913960400191505060405180910390fd5b600b54610fc557610f2f6159e0565b60015460005b81811015610fc157600b80546001810182556000919091528351600080516020615e15833981519152601690920291820190815560208501516000805160206165148339815191528301805460ff191691151591909117905560408501518592610fb391600080516020615e5b833981519152909101906014615a04565b505050806001019050610f35565b5050505b610fcd615a3e565b600061100e85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612ce092505050565b915091508061102a576110216064612e39565b92505050611115565b815160009060ff1661104a576110438360200151612e9a565b90506110e1565b825160ff16600114156110dd578260200151516001146110b7577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2604051808060200182810382526025815260200180615d5b6025913960400191505060405180910390a15060676110d8565b61104383602001516000815181106110cb57fe5b6020026020010151613caa565b6110e1565b5060655b63ffffffff811661110657505060408051600081526020810190915291506111159050565b61110f81612e39565b93505050505b9392505050565b60075460ff1681565b60035481565b606881565b6001546000908210611144575060006111fa565b60006001600160a01b03166001838154811061115c57fe5b60009182526020909120600490910201546001600160a01b0316148061118c5750600854158061118c5750600a54155b8061119b575060085460095410155b806111ac57506111aa826111ff565b155b806111d557506000600b83815481106111c157fe5b906000526020600020906016020160000154115b806111e9575060016111e561233b565b5111155b156111f6575060006111fa565b5060015b919050565b6001546000908210611213575060006111fa565b600b548210611250576001828154811061122957fe5b9060005260206000209060040201600201601c9054906101000a900460ff161590506111fa565b6001828154811061125d57fe5b9060005260206000209060040201600201601c9054906101000a900460ff161580156112aa5750600b828154811061129157fe5b600091825260209091206001601690920201015460ff16155b92915050565b33611001146112f05760405162461bcd60e51b81526004018080602001828103825260298152602001806165346029913960400191505060405180910390fd5b600b54611395576112ff6159e0565b60015460005b8181101561139157600b80546001810182556000919091528351600080516020615e15833981519152601690920291820190815560208501516000805160206165148339815191528301805460ff19169115159190911790556040850151859261138391600080516020615e5b833981519152909101906014615a04565b505050806001019050611305565b5050505b6001600160a01b038116600090815260046020526040902054806113b9575061140c565b6001810390506000600b82815481106113ce57fe5b600091825260209091206001601690920201015460ff1690506113f18383613e21565b80156113fa5750805b15610e7a576009805460001901905550505b50565b61271081565b600181565b61100181565b60085481565b603881565b600881565b600e54600c546060919080611443575060155b606061144d61233b565b905081815111611461579250611528915050565b82828251031015611473578181510392505b82156114a75760c8430461148e82828686036000888861419d565b6114a582828686038787038889898951030161419d565b505b6060826040519080825280602002602001820160405280156114d3578160200160208202803683370190505b50905060005b83811015611521578281815181106114ed57fe5b602002602001015182828151811061150157fe5b6001600160a01b03909216602092830291909101909101526001016114d9565b5093505050505b90565b60065481565b61200081565b6001600160a01b0381166000908152600460205260408120548061155f5760009150506111fa565b60001901611115816111ff565b6001600160a01b038116600090815260046020526040812054806115945760009150506111fa565b6001808203815481106115a357fe5b906000526020600020906004020160030154915050919050565b600081565b606781565b600181815481106115d457fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509082169291821691600160a01b81046001600160401b031691600160e01b90910460ff169086565b61100581565b600281565b61100881565b6103e881565b600b81565b600c5481565b606681565b33612000146116925760405162461bcd60e51b815260040180806020018281038252602f81526020018061648b602f913960400191505060405180910390fd5b7f41ce201247b6ceb957dcdb217d0b8acb50b9ea0e12af9af4f5e7f38902101605838383604051808460ff1660ff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b60025481565b600a5481565b6001600160a01b0381166000908152600460205260408120548061177c576040805162461bcd60e51b815260206004820152601760248201527f6f6e6c792063757272656e742076616c696461746f7273000000000000000000604482015290519081900360640190fd5b6000190192915050565b600b5461182b576117956159e0565b60015460005b8181101561182757600b80546001810182556000919091528351600080516020615e15833981519152601690920291820190815560208501516000805160206165148339815191528301805460ff19169115159190911790556040850151859261181991600080516020615e5b833981519152909101906014615a04565b50505080600101905061179b565b5050505b6008546118385760036008555b600a54611845576002600a555b600061185033611711565b905061185b81611130565b6118965760405162461bcd60e51b8152600401808060200182810382526023815260200180615d386023913960400191505060405180910390fd5b61140c338261428c565b600981565b61100781565b600381565b60c881565b61100681565b6040518061062001604052806105ef8152602001615e9c6105ef913981565b60005460ff1681565b6402540be40081565b60005460ff1661193f576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b336110071461197f5760405162461bcd60e51b815260040180806020018281038252602e815260200180615da1602e913960400191505060405180910390fd5b6119e984848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526013815272065787069726554696d655365636f6e6447617606c1b602082015291506143249050565b15611ac45760208114611a2d5760405162461bcd60e51b8152600401808060200182810382526026815260200180615e356026913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611a6b9185858083850183828082843760009201919091525061440b92505050565b905060648110158015611a815750620186a08111155b611abc5760405162461bcd60e51b8152600401808060200182810382526027815260200180615cc86027913960400191505060405180910390fd5b600255612297565b611b2484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260098152686275726e526174696f60b81b602082015291506143249050565b15611c145760208114611b7e576040805162461bcd60e51b815260206004820152601c60248201527f6c656e677468206f66206275726e526174696f206d69736d6174636800000000604482015290519081900360640190fd5b604080516020601f8401819004810282018101909252828152600091611bbc9185858083850183828082843760009201919091525061440b92505050565b9050612710811115611bff5760405162461bcd60e51b815260040180806020018281038252602b815260200180615c72602b913960400191505060405180910390fd5b6006556007805460ff19166001179055612297565b611c7e84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260138152726d61784e756d4f664d61696e7461696e696e6760681b602082015291506143249050565b15611d565760208114611cc25760405162461bcd60e51b8152600401808060200182810382526026815260200180615b396026913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611d009185858083850183828082843760009201919091525061440b92505050565b600c5490915080611d0f575060155b808210611d4d5760405162461bcd60e51b8152600401808060200182810382526038815260200180615bb06038913960400191505060405180910390fd5b50600855612297565b611dbf84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61696e7461696e536c6173685363616c6560701b602082015291506143249050565b15611e8a5760208114611e035760405162461bcd60e51b8152600401808060200182810382526025815260200180615b8b6025913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611e419185858083850183828082843760009201919091525061440b92505050565b905060008111611e825760405162461bcd60e51b815260040180806020018281038252602d8152602001806164e7602d913960400191505060405180910390fd5b600a55612297565b611efe84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601981527f6d61784e756d4f66576f726b696e6743616e6469646174657300000000000000602082015291506143249050565b15611fcb5760208114611f425760405162461bcd60e51b815260040180806020018281038252602c815260200180615b5f602c913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611f809185858083850183828082843760009201919091525061440b92505050565b9050600d54811115611fc35760405162461bcd60e51b8152600401808060200182810382526049815260200180615cef6049913960600191505060405180910390fd5b600e55612297565b61203484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61784e756d4f6643616e6469646174657360701b602082015291506143249050565b156120d557602081146120785760405162461bcd60e51b8152600401808060200182810382526025815260200180615dcf6025913960400191505060405180910390fd5b604080516020601f84018190048102820181019092528281526000916120b69185858083850183828082843760009201919091525061440b92505050565b600d819055600e549091508110156120cf57600d54600e555b50612297565b61213984848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600d81526c6e756d4f66436162696e65747360981b602082015291506143249050565b1561225a5760208114612193576040805162461bcd60e51b815260206004820181905260248201527f6c656e677468206f66206e756d4f66436162696e657473206d69736d61746368604482015290519081900360640190fd5b604080516020601f84018190048102820181019092528281526000916121d19185858083850183828082843760009201919091525061440b92505050565b9050600081116122125760405162461bcd60e51b8152600401808060200182810382526028815260200180615be86028913960400191505060405180910390fd5b60298111156122525760405162461bcd60e51b8152600401808060200182810382526039815260200180615c106039913960400191505060405180910390fd5b600c55612297565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b60046020526000908152604090205481565b6001546060906000805b8281101561236a57612356816111ff565b15612362576001909101905b600101612345565b50606081604051908082528060200260200182016040528015612397578160200160208202803683370190505b5090506000915060005b83811015612416576123b2816111ff565b1561240e57600181815481106123c457fe5b600091825260209091206004909102015482516001600160a01b03909116908390859081106123ef57fe5b6001600160a01b03909216602092830291909101909101526001909201915b6001016123a1565b509250505090565b601581565b61100281565b600061243361233b565b519050600080600c541161244857601561244c565b600c545b90508082111561245a578091505b8161246457600191505b5090565b67016345785d8a000081565b60055481565b61100381565b602981565b60005460ff16156124dd576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b6124e5615a3e565b600061250b6040518061062001604052806105ef8152602001615e9c6105ef9139612ce0565b915091508061254b5760405162461bcd60e51b8152600401808060200182810382526021815260200180615e7b6021913960400191505060405180910390fd5b60005b8260200151518110156126705760018360200151828151811061256d57fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782558587015182850180549185169183169190911790556040860151600283018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590981692909516919091179290921694909417161790915560a09093015160039093019290925591860151805191850193918590811061264357fe5b602090810291909101810151516001600160a01b031682528101919091526040016000205560010161254e565b50506103e8600255506000805460ff19166001179055565b600d5481565b33611001146126ce5760405162461bcd60e51b81526004018080602001828103825260298152602001806165346029913960400191505060405180910390fd5b600b54612773576126dd6159e0565b60015460005b8181101561276f57600b80546001810182556000919091528351600080516020615e15833981519152601690920291820190815560208501516000805160206165148339815191528301805460ff19169115159190911790556040850151859261276191600080516020615e5b833981519152909101906014615a04565b5050508060010190506126e3565b5050505b600061277e82614410565b905061278981611130565b1561279857612798828261428c565b5050565b606581565b3341146127df5760405162461bcd60e51b815260040180806020018281038252602d8152602001806164ba602d913960400191505060405180910390fd5b60005460ff16612832576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b6000341161287f576040805162461bcd60e51b81526020600482015260156024820152746465706f7369742076616c7565206973207a65726f60581b604482015290519081900360640190fd5b6001600160a01b0381166000908152600460205260409020546007543491906103e89060ff16156128af57506006545b6000831180156128bf5750600081115b156129685760006128e86127106128dc868563ffffffff6145b416565b9063ffffffff61460d16565b905080156129665760405161dead9082156108fc029083906000818181858888f1935050505015801561291f573d6000803e3d6000fd5b506040805182815290517f627059660ea01c4733a328effb2294d2f86905bf806da763a89cee254de8bee59181900360200190a1612963848263ffffffff61464f16565b93505b505b8115612a6057600060018084038154811061297f57fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff16156129ea576040805185815290516001600160a01b038716917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a2612a5a565b6003546129fd908563ffffffff61469116565b6003908155810154612a15908563ffffffff61469116565b60038201556040805185815290516001600160a01b038716917f93a090ecc682c002995fad3c85b30c5651d7fd29b0be5da9d784a3302aedc055919081900360200190a25b50612aa0565b6040805184815290516001600160a01b038616917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a25b50505050565b600e5481565b61100081565b61dead81565b600b8181548110612ac557fe5b60009182526020909120601690910201805460019091015490915060ff1682565b61100481565b6000600a5460001480612afd575081155b80612b085750600954155b15612b1557506000611115565b600960008154809291906001900391905055506000612b62600a546128dc856128dc600b8981548110612b4457fe5b6000918252602090912060169091020154439063ffffffff61464f16565b90506000600b8581548110612b7357fe5b906000526020600020906016020160010160006101000a81548160ff0219169083151502179055506000806110016001600160a01b0316638256ace66040518163ffffffff1660e01b8152600401604080518083038186803b158015612bd857600080fd5b505afa158015612bec573d6000803e3d6000fd5b505050506040513d6040811015612c0257600080fd5b508051602090910151600095509092509050808310612c9057612c258787613e21565b50604080516305bfb49960e41b81526001600160a01b0389166004820152905161100191635bfb499091602480830192600092919082900301818387803b158015612c6f57600080fd5b505af1158015612c83573d6000803e3d6000fd5b5050505060019350612ca2565b818310612ca257612ca087614410565b505b6040516001600160a01b038816907fb9d38178dc641ff1817967a63c9078cbcd955a9f1fcd75e0e3636de615d44d3b90600090a25050509392505050565b612ce8615a3e565b6000612cf2615a3e565b612cfa615a56565b612d0b612d06866146eb565b614710565b90506000805b612d1a8361475a565b15612e2b5780612d3f57612d35612d308461477b565b6147c9565b60ff168452612e23565b8060011415612e1e576060612d5b612d568561477b565b614880565b90508051604051908082528060200260200182016040528015612d9857816020015b612d85615a76565b815260200190600190039081612d7d5790505b50602086015260005b8151811015612e1357612db2615a76565b6000612dd0848481518110612dc357fe5b6020026020010151614951565b9150915080612ded57876000995099505050505050505050612e34565b8188602001518481518110612dfe57fe5b60209081029190910101525050600101612da1565b506001925050612e23565b612e2b565b600101612d11565b50919350909150505b915091565b604080516001808252818301909252606091829190816020015b6060815260200190600190039081612e53579050509050612e798363ffffffff16614a2e565b81600081518110612e8657fe5b602002602001018190525061111581614a41565b6000806060612ea884614acb565b9150915081612f55577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2816040518080602001828103825283818151815260200191508051906020019080838360005b83811015612f10578181015183820152602001612ef8565b50505050905090810190601f168015612f3d5780820380516001836020036101000a031916815260200191505b509250505060405180910390a16066925050506111fa565b50506060612f6283614bad565b6001549091506000908190815b81811015612fe55767016345785d8a000060018281548110612f8d57fe5b90600052602060002090600402016003015410612faf57600190930192612fdd565b600060018281548110612fbe57fe5b9060005260206000209060040201600301541115612fdd576001909201915b600101612f6f565b50606083604051908082528060200260200182016040528015613012578160200160208202803683370190505b509050606084604051908082528060200260200182016040528015613041578160200160208202803683370190505b509050606085604051908082528060200260200182016040528015613070578160200160208202803683370190505b50905060608660405190808252806020026020018201604052801561309f578160200160208202803683370190505b50905060006060876040519080825280602002602001820160405280156130d0578160200160208202803683370190505b5090506060886040519080825280602002602001820160405280156130ff578160200160208202803683370190505b509050600099506000985060006110046001600160a01b031663149d14d96040518163ffffffff1660e01b815260040160206040518083038186803b15801561314757600080fd5b505afa15801561315b573d6000803e3d6000fd5b505050506040513d602081101561317157600080fd5b5051905067016345785d8a00008111156131e5577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2604051808060200182810382526021815260200180615df46021913960400191505060405180910390a160689c505050505050505050505050506111fa565b60005b898110156134565767016345785d8a00006001828154811061320657fe5b9060005260206000209060040201600301541061338c576001818154811061322a57fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316898d8151811061325b57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006402540be4006001838154811061329057fe5b906000526020600020906004020160030154816132a957fe5b06600183815481106132b757fe5b9060005260206000209060040201600301540390506132df838261464f90919063ffffffff16565b898e815181106132eb57fe5b6020026020010181815250506001828154811061330457fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316878e8151811061333557fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081888e8151811061336257fe5b602090810291909101015261337d868263ffffffff61469116565b6001909d019c955061344e9050565b60006001828154811061339b57fe5b906000526020600020906004020160030154111561344e57600181815481106133c057fe5b906000526020600020906004020160010160009054906101000a90046001600160a01b0316848c815181106133f157fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001818154811061341e57fe5b906000526020600020906004020160030154838c8151811061343c57fe5b60209081029190910101526001909a01995b6001016131e8565b5060008415613894576110046001600160a01b0316636e056520868b8b8a60025442016040518663ffffffff1660e01b815260040180806020018060200180602001856001600160401b03166001600160401b03168152602001848103845288818151815260200191508051906020019060200280838360005b838110156134e85781810151838201526020016134d0565b50505050905001848103835287818151815260200191508051906020019060200280838360005b8381101561352757818101518382015260200161350f565b50505050905001848103825286818151815260200191508051906020019060200280838360005b8381101561356657818101518382015260200161354e565b505050509050019750505050505050506020604051808303818588803b15801561358f57600080fd5b505af1935050505080156135b557506040513d60208110156135b057600080fd5b505160015b6137f0576040516000815260443d10156135d15750600061366c565b60046000803e60005160e01c6308c379a081146135f257600091505061366c565b60043d036004833e81513d60248201116001600160401b038211171561361d5760009250505061366c565b80830180516001600160401b0381111561363e57600094505050505061366c565b8060208301013d860181111561365c5760009550505050505061366c565b601f01601f191660405250925050505b80613677575061371b565b60019150857fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280826040518080602001828103825283818151815260200191508051906020019080838360005b838110156136db5781810151838201526020016136c3565b50505050905090810190601f1680156137085780820380516001836020036101000a031916815260200191505b509250505060405180910390a2506137eb565b3d808015613745576040519150601f19603f3d011682016040523d82523d6000602084013e61374a565b606091505b5060019150857fbfa884552dd8921b6ce90bfe906952ae5b3b29be0cc1a951d4f62697635a3a45826040518080602001828103825283818151815260200191508051906020019080838360005b838110156137af578181015183820152602001613797565b50505050905090810190601f1680156137dc5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505b613894565b801561382e576040805187815290517fa217d08e65f80c73121cd9db834d81652d544bfbf452f6d04922b16c90a37b709181900360200190a1613892565b604080516020808252601b908201527f6261746368207472616e736665722072657475726e2066616c7365000000000081830152905187917fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280919081900360600190a25b505b8015613a4a5760005b8751811015613a485760008882815181106138b457fe5b602002602001015190506000600182815481106138cd57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116916108fc91859081106138fe57fe5b9060005260206000209060040201600301549081150290604051600060405180830381858888f19350505050905080156139ba576001828154811061393f57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d918590811061398e57fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a2613a3e565b600182815481106139c757fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d9185908110613a1657fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a25b505060010161389d565b505b835115613b945760005b8451811015613b92576000858281518110613a6b57fe5b60200260200101516001600160a01b03166108fc868481518110613a8b57fe5b60200260200101519081150290604051600060405180830381858888f1935050505090508015613b2157858281518110613ac157fe5b60200260200101516001600160a01b03167f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d868481518110613aff57fe5b60200260200101516040518082815260200191505060405180910390a2613b89565b858281518110613b2d57fe5b60200260200101516001600160a01b03167f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d868481518110613b6b57fe5b60200260200101516040518082815260200191505060405180910390a25b50600101613a54565b505b4715613bfd576040805147815290517f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d9181900360200190a1604051611002904780156108fc02916000818181858888f19350505050158015613bfb573d6000803e3d6000fd5b505b600060038190556005558c5115613c1757613c178d614d7d565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613c5457600080fd5b505af1158015613c68573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a15060009e9d5050505050505050505050505050565b80516001600160a01b0316600090815260046020526040812054801580613cfb5750600180820381548110613cdb57fe5b9060005260206000209060040201600201601c9054906101000a900460ff165b15613d415782516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a260009150506111fa565b600154600554600019820111801590613d975784516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a2600093505050506111fa565b600580546001908101909155805481906000198601908110613db557fe5b6000918252602082206002600490920201018054921515600160e01b0260ff60e01b199093169290921790915585516040516001600160a01b03909116917ff226e7d8f547ff903d9d419cf5f54e0d7d07efa9584135a53a057c5f1f27f49a91a2506000949350505050565b60008060018381548110613e3157fe5b90600052602060002090600402016003015490506000600180805490500390506001613e5b61233b565b5111613e9057600060018581548110613e7057fe5b9060005260206000209060040201600301819055506000925050506112aa565b6040805183815290516001600160a01b038716917f3b6f9ef90462b512a1293ecec018670bf7b7f1876fb727590a8a6d7643130a70919081900360200190a26001600160a01b038516600090815260046020526040812055835b6001546000190181101561408d5760018160010181548110613f0857fe5b906000526020600020906004020160018281548110613f2357fe5b60009182526020909120825460049092020180546001600160a01b03199081166001600160a01b0393841617825560018085015481840180548416918616919091179055600280860180549185018054909416919095161780835584546001600160401b03600160a01b91829004160267ffffffffffffffff60a01b1990911617808355935460ff600160e01b918290041615150260ff60e01b19909416939093179055600392830154920191909155600b805490918301908110613fe457fe5b9060005260206000209060160201600b8281548110613fff57fe5b600091825260209091208254601690920201908155600180830154908201805460ff191660ff909216151591909117905561404260028083019084016014615aab565b5090505080600101600460006001848154811061405b57fe5b600091825260208083206004909202909101546001600160a01b03168352820192909252604001902055600101613eea565b50600180548061409957fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b8054806140ec57fe5b60008281526020812060166000199093019283020181815560018101805460ff191690559061411e6002830182615ad6565b50509055600081838161412d57fe5b04905080156141915760015460005b8181101561418e57826001828154811061415257fe5b906000526020600020906004020160030154016001828154811061417257fe5b600091825260209091206003600490920201015560010161413c565b50505b50600195945050505050565b60005b828110156142835760408051602080820189905287840182840152825180830384018152606090920190925280519101206000908390816141dd57fe5b0690508085018287011461427a57600088838801815181106141fb57fe5b60200260200101519050888287018151811061421357fe5b6020026020010151898489018151811061422957fe5b60200260200101906001600160a01b031690816001600160a01b03168152505080898388018151811061425857fe5b60200260200101906001600160a01b031690816001600160a01b031681525050505b506001016141a0565b50505050505050565b600980546001908101909155600b8054839081106142a657fe5b906000526020600020906016020160010160006101000a81548160ff02191690831515021790555043600b82815481106142dc57fe5b600091825260208220601690910201919091556040516001600160a01b038416917ff62981a567ec3cec866c6fa93c55bcdf841d6292d18b8d522ececa769375d82d91a25050565b6000816040516020018082805190602001908083835b602083106143595780518252601f19909201916020918201910161433a565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b602083106143c75780518252601f1990920191602091820191016143a8565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012014905092915050565b015190565b6001600160a01b03811660009081526004602052604081205480614439575060001990506111fa565b60018103905060006001828154811061444e57fe5b906000526020600020906004020160030154905060006001838154811061447157fe5b906000526020600020906004020160030181905550600060018080549050039050846001600160a01b03167f8cd4e147d8af98a9e3b6724021b8bf6aed2e5dac71c38f2dce8161b82585b25d836040518082815260200191505060405180910390a2806144e3578293505050506111fa565b60008183816144ee57fe5b04905080156145aa5760005b8481101561454c57816001828154811061451057fe5b906000526020600020906004020160030154016001828154811061453057fe5b60009182526020909120600360049092020101556001016144fa565b50600180549085015b818110156145a757826001828154811061456b57fe5b906000526020600020906004020160030154016001828154811061458b57fe5b6000918252602090912060036004909202010155600101614555565b50505b5091949350505050565b6000826145c3575060006112aa565b828202828482816145d057fe5b04146111155760405162461bcd60e51b8152600401808060200182810382526021815260200180615d806021913960400191505060405180910390fd5b600061111583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250615370565b600061111583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250615412565b600082820183811015611115576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6146f3615ae5565b506040805180820190915281518152602082810190820152919050565b614718615a56565b6147218261546c565b61472a57600080fd5b600061473983602001516154a6565b60208085015160408051808201909152868152920190820152915050919050565b6000614764615ae5565b505080518051602091820151919092015191011190565b614783615ae5565b61478c8261475a565b61479557600080fd5b602082015160006147a582615509565b80830160209586015260408051808201909152908152938401919091525090919050565b8051600090158015906147de57508151602110155b6147e757600080fd5b60006147f683602001516154a6565b90508083600001511015614851576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b82516020808501518301805192849003929183101561487757826020036101000a820491505b50949350505050565b606061488b8261546c565b61489457600080fd5b600061489f8361563c565b90506060816040519080825280602002602001820160405280156148dd57816020015b6148ca615ae5565b8152602001906001900390816148c25790505b50905060006148ef85602001516154a6565b60208601510190506000805b848110156149465761490c83615509565b915060405180604001604052808381526020018481525084828151811061492f57fe5b6020908102919091010152918101916001016148fb565b509195945050505050565b614959615a76565b6000614963615a76565b61496b615a56565b61497485614710565b90506000805b6149838361475a565b15612e2b57806149ae5761499e6149998461477b565b615698565b6001600160a01b03168452614a26565b80600114156149d6576149c36149998461477b565b6001600160a01b03166020850152614a26565b80600214156149fe576149eb6149998461477b565b6001600160a01b03166040850152614a26565b8060031415612e1e57614a13612d308461477b565b6001600160401b03166060850152600191505b60010161497a565b60606112aa614a3c836156b2565b615798565b6060815160001415614a6257506040805160008152602081019091526111fa565b606082600081518110614a7157fe5b602002602001015190506000600190505b8351811015614ab257614aa882858381518110614a9b57fe5b60200260200101516157ea565b9150600101614a82565b50611115614ac5825160c060ff16615867565b826157ea565b60006060602983511115614afd576000604051806060016040528060298152602001615c496029913991509150612e34565b60005b8351811015614b935760005b81811015614b8a57848181518110614b2057fe5b6020026020010151600001516001600160a01b0316858381518110614b4157fe5b6020026020010151600001516001600160a01b03161415614b825760006040518060600160405280602b8152602001615c9d602b9139935093505050612e34565b600101614b0c565b50600101614b00565b505060408051602081019091526000815260019150915091565b6060600080808080614bbd612429565b6001549091505b8015614ccb57600181039250600b8381548110614bdd57fe5b600091825260209091206001601690920201015460ff16614bfd57614cc2565b60018381548110614c0a57fe5b60009182526020909120600490910201546001600160a01b03169450614c31858484612aec565b9350831580614c44575060018851038610155b15614c4e57614cc2565b60005b8851811015614cc057856001600160a01b0316898281518110614c7057fe5b6020026020010151600001516001600160a01b03161415614cb8576001898281518110614c9957fe5b6020908102919091010151901515608090910152600190960195614cc0565b600101614c51565b505b60001901614bc4565b5084875103604051908082528060200260200182016040528015614d0957816020015b614cf6615a76565b815260200190600190039081614cee5790505b5095506000915060005b8751811015614d7257878181518110614d2857fe5b602002602001015160800151614d6a57878181518110614d4457fe5b6020026020010151878481518110614d5857fe5b60209081029190910101526001909201915b600101614d13565b505050505050919050565b600154815160005b82811015614e9a576001614d97615a76565b60018381548110614da457fe5b600091825260208083206040805160c08101825260049490940290910180546001600160a01b0390811685526001820154811693850193909352600281015492831691840191909152600160a01b82046001600160401b03166060840152600160e01b90910460ff16151560808301526003015460a082015291505b84811015614e6e57868181518110614e3457fe5b6020026020010151600001516001600160a01b031682600001516001600160a01b03161415614e665760009250614e6e565b600101614e20565b508115614e905780516001600160a01b03166000908152600460205260408120555b5050600101614d85565b5080821115614f4b57805b82811015614f49576001805480614eb857fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b805480614f0b57fe5b60008281526020812060166000199093019283020181815560018101805460ff1916905590614f3d6002830182615ad6565b50509055600101614ea5565b505b6000818310614f5a5781614f5c565b825b905060005b818110156151565761500e858281518110614f7857fe5b602002602001015160018381548110614f8d57fe5b60009182526020918290206040805160c08101825260049390930290910180546001600160a01b0390811684526001820154811694840194909452600281015493841691830191909152600160a01b83046001600160401b03166060830152600160e01b90920460ff161515608082015260039091015460a082015261595f565b61512957806001016004600087848151811061502657fe5b6020026020010151600001516001600160a01b03166001600160a01b031681526020019081526020016000208190555084818151811061506257fe5b60200260200101516001828154811061507757fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a09091015160039091015561514e565b60006001828154811061513857fe5b9060005260206000209060040201600301819055505b600101614f61565b50828211156152fb576151676159e0565b835b838110156152f857600186828151811061517f57fe5b6020908102919091018101518254600181810185556000948552838520835160049093020180546001600160a01b039384166001600160a01b0319918216178255848601518284018054918616918316919091179055604080860151600284018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909a1692909616919091179290921696909617169190911790935560a090930151600390930192909255600b8054928301815590935284516016909102600080516020615e158339815191528101918255918501516000805160206165148339815191528301805491151560ff19909216919091179055918401518492916152b491600080516020615e5b833981519152909101906014615a04565b50505080600101600460008884815181106152cb57fe5b602090810291909101810151516001600160a01b0316825281019190915260400160002055600101615169565b50505b6000600981905560015493505b83811015615369576000600b828154811061531f57fe5b60009182526020822060169190910201600101805460ff191692151592909217909155600b80548390811061535057fe5b6000918252602090912060169091020155600101615308565b5050505050565b600081836153fc5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156153c15781810151838201526020016153a9565b50505050905090810190601f1680156153ee5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161540857fe5b0495945050505050565b600081848411156154645760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156153c15781810151838201526020016153a9565b505050900390565b805160009061547d575060006111fa565b6020820151805160001a9060c082101561549c576000925050506111fa565b5060019392505050565b8051600090811a60808110156154c05760009150506111fa565b60b88110806154db575060c081108015906154db575060f881105b156154ea5760019150506111fa565b60c08110156154fe5760b5190190506111fa565b60f5190190506111fa565b80516000908190811a60808110156155245760019150615635565b60b881101561553957607e1981019150615635565b60c08110156155b357600060b78203600186019550806020036101000a8651049150600181018201935050808310156155ad576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b50615635565b60f88110156155c85760be1981019150615635565b600060f78203600186019550806020036101000a865104915060018101820193505080831015615633576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b805160009061564d575060006111fa565b6000809050600061566184602001516154a6565b602085015185519181019250015b8082101561568f5761568082615509565b6001909301929091019061566f565b50909392505050565b80516000906015146156a957600080fd5b6112aa826147c9565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff1984166156f65750601861571a565b6fffffffffffffffffffffffffffffffff1984166157165750601061571a565b5060005b60208110156157505781818151811061572f57fe5b01602001516001600160f81b0319161561574857615750565b60010161571a565b60008160200390506060816040519080825280601f01601f191660200182016040528015615785576020820181803683370190505b5080830196909652508452509192915050565b6060815160011480156157ca5750607f60f81b826000815181106157b857fe5b01602001516001600160f81b03191611155b156157d65750806111fa565b6112aa6157e88351608060ff16615867565b835b6060806040519050835180825260208201818101602087015b8183101561581b578051835260209283019201615803565b50855184518101855292509050808201602086015b81831015615848578051835260209283019201615830565b508651929092011591909101601f01601f191660405250905092915050565b60606801000000000000000083106158b7576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116159115782840160f81b816000815181106158f357fe5b60200101906001600160f81b031916908160001a90535090506112aa565b606061591c856156b2565b90508381510160370160f81b8260008151811061593557fe5b60200101906001600160f81b031916908160001a90535061595682826157ea565b95945050505050565b805182516000916001600160a01b039182169116148015615999575081602001516001600160a01b031683602001516001600160a01b0316145b80156159be575081604001516001600160a01b031683604001516001600160a01b0316145b80156111155750506060908101519101516001600160401b0390811691161490565b60408051606081018252600080825260208201529081016159ff615aff565b905290565b8260148101928215615a32579160200282015b82811115615a32578251825591602001919060010190615a17565b50612464929150615b1e565b60408051808201909152600081526060602082015290565b6040518060400160405280615a69615ae5565b8152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b8260148101928215615a32579182015b82811115615a32578254825591600101919060010190615abb565b5061140c906014810190615b1e565b604051806040016040528060008152602001600081525090565b6040518061028001604052806014906020820280368337509192915050565b61152891905b808211156124645760008155600101615b2456fe6c656e677468206f66206d61784e756d4f664d61696e7461696e696e67206d69736d617463686c656e677468206f66206d61784e756d4f66576f726b696e6743616e64696461746573206d69736d617463686c656e677468206f66206d61696e7461696e536c6173685363616c65206d69736d61746368746865206d61784e756d4f664d61696e7461696e696e67206d757374206265206c657373207468616e206e756d4f6643616e696e61746573746865206e756d4f66436162696e657473206d7573742062652067726561746572207468616e2030746865206e756d4f66436162696e657473206d757374206265206c657373207468616e204d41585f4e554d5f4f465f56414c494441544f5253746865206e756d626572206f662076616c696461746f72732065786365656420746865206c696d6974746865206275726e526174696f206d757374206265206e6f2067726561746572207468616e2031303030306475706c696361746520636f6e73656e7375732061646472657373206f662076616c696461746f725365747468652065787069726554696d655365636f6e64476170206973206f7574206f662072616e6765746865206d61784e756d4f66576f726b696e6743616e64696461746573206d757374206265206e6f742067726561746572207468616e206d61784e756d4f6643616e6469646174657363616e206e6f7420656e7465722054656d706f72617279204d61696e74656e616e63656c656e677468206f66206a61696c2076616c696461746f7273206d757374206265206f6e65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e74726163746c656e677468206f66206d61784e756d4f6643616e64696461746573206d69736d61746368666565206973206c6172676572207468616e2044555354595f494e434f4d494e470175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db96c656e677468206f662065787069726554696d655365636f6e64476170206d69736d617463680175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb6661696c656420746f20706172736520696e69742076616c696461746f72536574f905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a2000746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f6475636572746865206d61696e7461696e536c6173685363616c65206d7573742062652067726561746572207468616e20300175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba746865206d6573736167652073656e646572206d75737420626520736c61736820636f6e7472616374a264697066735822122091dd90b1dd27923c787e9f55bd1bebe31e8416465e6ce432022dfeb252e6701e64736f6c63430006040033", + }, + { + ContractAddr: common.HexToAddress(SlashContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/db8bb560ac5a1265c685b719c7e976dced162310", + Code: "608060405234801561001057600080fd5b506004361061023d5760003560e01c80638256ace61161013b578063c80d4b8f116100b8578063e1c7392a1161007c578063e1c7392a1461071d578063f9a2bbc714610725578063fc3e59081461072d578063fc4333cd14610735578063fd6a68791461073d5761023d565b8063c80d4b8f14610667578063c81b16621461066f578063c8509d8114610677578063c96be4cb146106ef578063dc927faf146107155761023d565b8063a1a11bf5116100ff578063a1a11bf514610575578063a78abc161461057d578063ab51bb9614610599578063ac0af629146105a1578063ac431751146105a95761023d565b80638256ace6146104dd578063831d65d1146104e557806396713da91461055d5780639bc8e4f2146105655780639dc092621461056d5761023d565b80634bf6c882116101c95780636e47b4821161018d5780636e47b482146104b557806370fd5bad146104bd57806375d47a0a146104c55780637912a65d146104cd5780637942fd05146104d55761023d565b80634bf6c8821461046d57806351e8067214610475578063567a372d1461047d5780635bfb49901461048557806362b72cf5146104ad5761023d565b806337c8dab91161021057806337c8dab9146103cf578063389f4f711461040e5780633dffc3871461042857806343756e5c14610446578063493279b11461044e5761023d565b80630bee7a67146102425780631182b8751461026357806323bac5a21461035057806335aa2e4414610396575b600080fd5b61024a610745565b6040805163ffffffff9092168252519081900360200190f35b6102db6004803603604081101561027957600080fd5b60ff8235169190810190604081016020820135600160201b81111561029d57600080fd5b8201836020820111156102af57600080fd5b803590602001918460018302840111600160201b831117156102d057600080fd5b50909250905061074a565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103155781810151838201526020016102fd565b50505050905090810190601f1680156103425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103766004803603602081101561036657600080fd5b50356001600160a01b031661081e565b604080519384526020840192909252151582820152519081900360600190f35b6103b3600480360360208110156103ac57600080fd5b5035610841565b604080516001600160a01b039092168252519081900360200190f35b6103f5600480360360208110156103e557600080fd5b50356001600160a01b0316610868565b6040805192835260208301919091528051918290030190f35b6104166108bf565b60408051918252519081900360200190f35b6104306108c5565b6040805160ff9092168252519081900360200190f35b6103b36108ca565b6104566108d0565b6040805161ffff9092168252519081900360200190f35b6104306108d5565b6103b36108da565b6104166108e0565b6104ab6004803603602081101561049b57600080fd5b50356001600160a01b03166108e6565b005b610416610a47565b6103b3610a4d565b610430610a53565b6103b3610a58565b610416610a5e565b610430610a63565b6103f5610a68565b6104ab600480360360408110156104fb57600080fd5b60ff8235169190810190604081016020820135600160201b81111561051f57600080fd5b82018360208201111561053157600080fd5b803590602001918460018302840111600160201b8311171561055257600080fd5b509092509050610a72565b610430610bcc565b610416610bd1565b6103b3610bdc565b6103b3610be2565b610585610be8565b604080519115158252519081900360200190f35b61024a610bf1565b610416610bf6565b6104ab600480360360408110156105bf57600080fd5b810190602081018135600160201b8111156105d957600080fd5b8201836020820111156105eb57600080fd5b803590602001918460018302840111600160201b8311171561060c57600080fd5b919390929091602081019035600160201b81111561062957600080fd5b82018360208201111561063b57600080fd5b803590602001918460018302840111600160201b8311171561065c57600080fd5b509092509050610bfb565b610416610fe9565b6103b3610fee565b6104ab6004803603604081101561068d57600080fd5b60ff8235169190810190604081016020820135600160201b8111156106b157600080fd5b8201836020820111156106c357600080fd5b803590602001918460018302840111600160201b831117156106e457600080fd5b509092509050610ff4565b6104ab6004803603602081101561070557600080fd5b50356001600160a01b03166110a7565b6103b361154a565b6104ab611550565b6103b36115c1565b6104306115c7565b6104ab6115cc565b6103b3611a57565b606481565b6060336120001461078c5760405162461bcd60e51b815260040180806020018281038252602f8152602001806124ae602f913960400191505060405180910390fd5b60005460ff166107d1576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b6040805162461bcd60e51b815260206004820152601e60248201527f7265636569766520756e65787065637465642073796e207061636b6167650000604482015290519081900360640190fd5b600260208190526000918252604090912080546001820154919092015460ff1683565b6001818154811061084e57fe5b6000918252602090912001546001600160a01b0316905081565b600080610873612372565b5050506001600160a01b0316600090815260026020818152604092839020835160608101855281548082526001830154938201849052919093015460ff16151592909301919091529091565b60055481565b600181565b61100181565b603881565b600881565b61200081565b60045481565b33611000146109265760405162461bcd60e51b81526004018080602001828103825260308152602001806124096030913960400191505060405180910390fd5b60005460ff1661096b576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b61200063f7a251d7600b61097e84611a5d565b60006040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156109de5781810151838201526020016109c6565b50505050905090810190601f168015610a0b5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015610a2c57600080fd5b505af1158015610a40573d6000803e3d6000fd5b5050505050565b60035481565b61100581565b600281565b61100881565b603281565b600b81565b6004546005549091565b3361200014610ab25760405162461bcd60e51b815260040180806020018281038252602f8152602001806124ae602f913960400191505060405180910390fd5b60005460ff16610af7576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b610aff612395565b6000610b4084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b2f92505050565b915091508015610b8a5781516040805163ffffffff9092168252517f7f0956d47419b9525356e7111652b653b530ec6f5096dccc04589bc38e6299679181900360200190a1610a40565b81516040805163ffffffff9092168252517f7d45f62d17443dd4547bca8a8112c60e2385669318dc300ec61a5d2492f262e79181900360200190a15050505050565b600981565b662386f26fc1000081565b61100781565b61100681565b60005460ff1681565b600081565b600481565b60005460ff16610c40576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b3361100714610c805760405162461bcd60e51b815260040180806020018281038252602e815260200180612439602e913960400191505060405180910390fd5b610ceb84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260148152731b5a5cd9195b59585b9bdc951a1c995cda1bdb1960621b60208201529150611baf9050565b15610dc45760208114610d2f5760405162461bcd60e51b81526004018080602001828103825260278152602001806123e26027913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091610d6d91858580838501838280828437600092019190915250611c9792505050565b905060018110158015610d81575060055481105b610dbc5760405162461bcd60e51b81526004018080602001828103825260258152602001806124896025913960400191505060405180910390fd5b600455610f57565b610e2a84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600f81526e19995b1bdb9e551a1c995cda1bdb19608a1b60208201529150611baf9050565b15610f1a5760208114610e6e5760405162461bcd60e51b81526004018080602001828103825260228152602001806124676022913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091610eac91858580838501838280828437600092019190915250611c9792505050565b90506103e88111158015610ec1575060045481115b610f12576040805162461bcd60e51b815260206004820181905260248201527f7468652066656c6f6e795468726573686f6c64206f7574206f662072616e6765604482015290519081900360640190fd5b600555610f57565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b609681565b61100281565b33612000146110345760405162461bcd60e51b815260040180806020018281038252602f8152602001806124ae602f913960400191505060405180910390fd5b60005460ff16611079576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b6040517f07db600eebe2ac176be8dcebad61858c245a4961bb32ca2aa3d159b09aa0810e90600090a1505050565b3341146110e55760405162461bcd60e51b815260040180806020018281038252602d8152602001806124dd602d913960400191505060405180910390fd5b60005460ff1661112a576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b6003544311611180576040805162461bcd60e51b815260206004820181905260248201527f63616e206e6f7420736c61736820747769636520696e206f6e6520626c6f636b604482015290519081900360640190fd5b3a156111ca576040805162461bcd60e51b81526020600482015260146024820152736761737072696365206973206e6f74207a65726f60601b604482015290519081900360640190fd5b6040805163155853f360e21b81526001600160a01b03831660048201529051611000916355614fcc916024808301926020929190829003018186803b15801561121257600080fd5b505afa158015611226573d6000803e3d6000fd5b505050506040513d602081101561123c57600080fd5b505161124757611543565b61124f612372565b506001600160a01b0381166000908152600260208181526040928390208351606081018552815481526001820154928101929092529091015460ff1615801592820192909252906112aa576020810180516001019052611303565b60016040820181905260208201819052805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b0384161790555b43815260055460208201518161131557fe5b0661146757600060208201819052604080516335409f7f60e01b81526001600160a01b03851660048201529051611000926335409f7f926024808201939182900301818387803b15801561136857600080fd5b505af115801561137c573d6000803e3d6000fd5b505050506120006001600160a01b031663f7a251d7600b61139c85611a5d565b60006040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156113fc5781810151838201526020016113e4565b50505050905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561144a57600080fd5b505af115801561145e573d6000803e3d6000fd5b505050506114dd565b60045481602001518161147657fe5b066114dd57604080516375abf10160e11b81526001600160a01b038416600482015290516110009163eb57e20291602480830192600092919082900301818387803b1580156114c457600080fd5b505af11580156114d8573d6000803e3d6000fd5b505050505b6001600160a01b0382166000818152600260208181526040808420865181559186015160018301558581015191909201805460ff1916911515919091179055517fddb6012116e51abf5436d956a4f0ebd927e92c576ff96d7918290c8782291e3e9190a2505b5043600355565b61100381565b60005460ff16156115a8576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b603260045560966005556000805460ff19166001179055565b61100081565b600381565b336110001461160c5760405162461bcd60e51b81526004018080602001828103825260308152602001806124096030913960400191505060405180910390fd5b60005460ff16611651576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b60015461165d57611a55565b600154600090600019015b808211611a29576000805b8284101561178c57611683612372565b600260006001878154811061169457fe5b60009182526020808320909101546001600160a01b0316835282810193909352604091820190208151606081018352815481526001820154938101939093526002015460ff1615159082015260055490915060049004816020015111156117765760046005548161170157fe5b0481602001510381602001818152505080600260006001888154811061172357fe5b6000918252602080832091909101546001600160a01b0316835282810193909352604091820190208351815591830151600183015591909101516002909101805460ff1916911515919091179055611780565b600192505061178c565b50600190930192611673565b8284116119235761179b612372565b60026000600186815481106117ac57fe5b60009182526020808320909101546001600160a01b0316835282810193909352604091820190208151606081018352815481526001820154938101939093526002015460ff1615159082015260055490915060049004816020015111156118945760046005548161181957fe5b0481602001510381602001818152505080600260006001878154811061183b57fe5b6000918252602080832091909101546001600160a01b03168352828101939093526040918201902083518155918301516001808401919091559201516002909101805460ff191691151591909117905591506119239050565b60026000600186815481106118a557fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120818155600181810192909255600201805460ff191690558054806118e957fe5b600082815260209020810160001990810180546001600160a01b0319169055019055836119165750611923565b506000199092019161178c565b81801561192d5750805b15611a0c57600260006001868154811061194357fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120818155600181810192909255600201805460ff1916905580548490811061198a57fe5b600091825260209091200154600180546001600160a01b0390921691869081106119b057fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060018054806119e957fe5b600082815260209020810160001990810180546001600160a01b03191690550190555b82611a18575050611a29565b505060019091019060001901611668565b6040517fcfdb3b6ccaeccbdc68be3c59c840e3b3c90f0a7c491f5fff1cf56cfda200dd9c90600090a150505b565b61100481565b60408051600480825260a08201909252606091829190816020015b6060815260200190600190039081611a78579050509050611aa1836001600160a01b0316611c9c565b81600081518110611aae57fe5b6020026020010181905250611ac243611cbf565b81600181518110611acf57fe5b6020908102919091010152611ae46038611cbf565b81600281518110611af157fe5b6020026020010181905250611b0542611cbf565b81600381518110611b1257fe5b6020026020010181905250611b2681611cd2565b9150505b919050565b611b37612395565b6000611b41612395565b611b496123a7565b611b5a611b5586611d5c565b611d81565b90506000805b611b6983611dcb565b15611ba25780611b9557611b84611b7f84611dec565b611e3a565b63ffffffff16845260019150611b9a565b611ba2565b600101611b60565b5091935090915050915091565b6000816040516020018082805190602001908083835b60208310611be45780518252601f199092019160209182019101611bc5565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b60208310611c525780518252601f199092019160209182019101611c33565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201490505b92915050565b015190565b60408051600560a21b8318601482015260348101909152606090611b2681611ef1565b6060611c91611ccd83611f47565b611ef1565b6060815160001415611cf35750604080516000815260208101909152611b2a565b606082600081518110611d0257fe5b602002602001015190506000600190505b8351811015611d4357611d3982858381518110611d2c57fe5b602002602001015161202d565b9150600101611d13565b50611b26611d56825160c060ff166120aa565b8261202d565b611d646123c7565b506040805180820190915281518152602082810190820152919050565b611d896123a7565b611d92826121a2565b611d9b57600080fd5b6000611daa83602001516121dc565b60208085015160408051808201909152868152920190820152915050919050565b6000611dd56123c7565b505080518051602091820151919092015191011190565b611df46123c7565b611dfd82611dcb565b611e0657600080fd5b60208201516000611e168261223f565b80830160209586015260408051808201909152908152938401919091525090919050565b805160009015801590611e4f57508151602110155b611e5857600080fd5b6000611e6783602001516121dc565b90508083600001511015611ec2576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b825160208085015183018051928490039291831015611ee857826020036101000a820491505b50949350505050565b606081516001148015611f235750607f60f81b82600081518110611f1157fe5b01602001516001600160f81b03191611155b15611f2f575080611b2a565b611c91611f418351608060ff166120aa565b8361202d565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff198416611f8b57506018611faf565b6fffffffffffffffffffffffffffffffff198416611fab57506010611faf565b5060005b6020811015611fe557818181518110611fc457fe5b01602001516001600160f81b03191615611fdd57611fe5565b600101611faf565b60008160200390506060816040519080825280601f01601f19166020018201604052801561201a576020820181803683370190505b5080830196909652508452509192915050565b6060806040519050835180825260208201818101602087015b8183101561205e578051835260209283019201612046565b50855184518101855292509050808201602086015b8183101561208b578051835260209283019201612073565b508651929092011591909101601f01601f191660405250905092915050565b60606801000000000000000083106120fa576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116121545782840160f81b8160008151811061213657fe5b60200101906001600160f81b031916908160001a9053509050611c91565b606061215f85611f47565b90508381510160370160f81b8260008151811061217857fe5b60200101906001600160f81b031916908160001a905350612199828261202d565b95945050505050565b80516000906121b357506000611b2a565b6020820151805160001a9060c08210156121d257600092505050611b2a565b5060019392505050565b8051600090811a60808110156121f6576000915050611b2a565b60b8811080612211575060c08110801590612211575060f881105b15612220576001915050611b2a565b60c08110156122345760b519019050611b2a565b60f519019050611b2a565b80516000908190811a608081101561225a576001915061236b565b60b881101561226f57607e198101915061236b565b60c08110156122e957600060b78203600186019550806020036101000a8651049150600181018201935050808310156122e3576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b5061236b565b60f88110156122fe5760be198101915061236b565b600060f78203600186019550806020036101000a865104915060018101820193505080831015612369576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b604051806060016040528060008152602001600081526020016000151581525090565b60408051602081019091526000815290565b60405180604001604052806123ba6123c7565b8152602001600081525090565b60405180604001604052806000815260200160008152509056fe6c656e677468206f66206d697364656d65616e6f725468726573686f6c64206d69736d61746368746865206d6573736167652073656e646572206d7573742062652076616c696461746f7253657420636f6e7472616374746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e74726163746c656e677468206f662066656c6f6e795468726573686f6c64206d69736d61746368746865206d697364656d65616e6f725468726573686f6c64206f7574206f662072616e6765746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f647563657274686520636f6e7472616374206e6f7420696e69742079657400000000000000a264697066735822122018b8714d9e81a204e6cb56a28d2122ac3178937ed053b34fef2460106855598d64736f6c63430006040033", + }, + }, + } + + eulerUpgrade[chapelNet] = &Upgrade{ + UpgradeName: "euler", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(ValidatorContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/db8bb560ac5a1265c685b719c7e976dced162310", + Code: "6080604052600436106104055760003560e01c80638d19a41011610213578063c81b166211610123578063eb57e202116100ab578063f9a2bbc71161007a578063f9a2bbc714610d55578063fc3e590814610d6a578063fccc281314610d7f578063fd4ad81f14610d94578063fd6a687914610dd757610405565b8063eb57e20214610cd2578063eda5868c14610d05578063f340fa0114610d1a578063f92eb86b14610d4057610405565b8063daacdb66116100f2578063daacdb6614610c69578063dc927faf14610c7e578063e086c7b114610c93578063e1c7392a14610ca8578063e40716a114610cbd57610405565b8063c81b166214610c2a578063c8509d8114610939578063d68fb56a14610c3f578063d86222d514610c5457610405565b8063a78abc16116101a6578063ad3c9da611610175578063ad3c9da614610bb8578063b7ab4db514610beb578063b8cf4ef114610c00578063bf9f49951461065f578063c6d3394514610c1557610405565b8063a78abc1614610aae578063aaf5eb6814610ac3578063ab51bb9614610ad8578063ac43175114610aed57610405565b80639fe0f816116101e25780639fe0f81614610a5a578063a0dc275814610a6f578063a1a11bf514610a84578063a5422d5c14610a9957610405565b80638d19a410146109e85780639369d7de14610a1b57806396713da914610a305780639dc0926214610a4557610405565b80635192c82c1161031957806375d47a0a116102a157806381650b621161027057806381650b6214610924578063831d65d114610939578063853230aa146108e557806386249882146109be5780638b5ad0c9146109d357610405565b806375d47a0a146108d057806378dfed4a146108e55780637942fd05146108fa5780637a84ca2a1461090f57610405565b80635667515a116102e85780635667515a146108065780635d77156c1461081b5780636969a25c146108305780636e47b482146108a657806370fd5bad146108bb57610405565b80635192c82c1461077657806351e806721461078b57806355614fcc146107a0578063565c56b3146107d357610405565b80633365af3a1161039c57806343756e5c1161036b57806343756e5c1461068a57806345cf9daf146106bb578063493279b1146106d05780634bf6c882146106fc5780634df6e0c31461071157610405565b80633365af3a146105ed57806335409f7f146106175780633de0f0d81461064a5780633dffc3871461065f57610405565b8063152ad3b8116103d8578063152ad3b8146105705780631ff1806914610599578063219f22d5146105ae578063321d398a146105c357610405565b806304c4fec61461040a57806307a56847146104215780630bee7a67146104485780631182b87514610476575b600080fd5b34801561041657600080fd5b5061041f610dec565b005b34801561042d57600080fd5b50610436610e7f565b60408051918252519081900360200190f35b34801561045457600080fd5b5061045d610e85565b6040805163ffffffff9092168252519081900360200190f35b34801561048257600080fd5b506104fb6004803603604081101561049957600080fd5b60ff8235169190810190604081016020820135600160201b8111156104bd57600080fd5b8201836020820111156104cf57600080fd5b803590602001918460018302840111600160201b831117156104f057600080fd5b509092509050610e8a565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561053557818101518382015260200161051d565b50505050905090810190601f1680156105625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561057c57600080fd5b5061058561111c565b604080519115158252519081900360200190f35b3480156105a557600080fd5b50610436611125565b3480156105ba57600080fd5b5061045d61112b565b3480156105cf57600080fd5b50610585600480360360208110156105e657600080fd5b5035611130565b3480156105f957600080fd5b506105856004803603602081101561061057600080fd5b50356111ff565b34801561062357600080fd5b5061041f6004803603602081101561063a57600080fd5b50356001600160a01b03166112b0565b34801561065657600080fd5b5061043661140f565b34801561066b57600080fd5b50610674611415565b6040805160ff9092168252519081900360200190f35b34801561069657600080fd5b5061069f61141a565b604080516001600160a01b039092168252519081900360200190f35b3480156106c757600080fd5b50610436611420565b3480156106dc57600080fd5b506106e5611426565b6040805161ffff9092168252519081900360200190f35b34801561070857600080fd5b5061067461142b565b34801561071d57600080fd5b50610726611430565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561076257818101518382015260200161074a565b505050509050019250505060405180910390f35b34801561078257600080fd5b5061043661152b565b34801561079757600080fd5b5061069f611531565b3480156107ac57600080fd5b50610585600480360360208110156107c357600080fd5b50356001600160a01b0316611537565b3480156107df57600080fd5b50610436600480360360208110156107f657600080fd5b50356001600160a01b031661156c565b34801561081257600080fd5b506106746115bd565b34801561082757600080fd5b5061045d6115c2565b34801561083c57600080fd5b5061085a6004803603602081101561085357600080fd5b50356115c7565b604080516001600160a01b039788168152958716602087015293909516848401526001600160401b0390911660608401521515608083015260a082019290925290519081900360c00190f35b3480156108b257600080fd5b5061069f61162b565b3480156108c757600080fd5b50610674611631565b3480156108dc57600080fd5b5061069f611636565b3480156108f157600080fd5b5061043661163c565b34801561090657600080fd5b50610674611642565b34801561091b57600080fd5b50610436611647565b34801561093057600080fd5b5061045d61164d565b34801561094557600080fd5b5061041f6004803603604081101561095c57600080fd5b60ff8235169190810190604081016020820135600160201b81111561098057600080fd5b82018360208201111561099257600080fd5b803590602001918460018302840111600160201b831117156109b357600080fd5b509092509050611652565b3480156109ca57600080fd5b50610436611705565b3480156109df57600080fd5b5061043661170b565b3480156109f457600080fd5b5061043660048036036020811015610a0b57600080fd5b50356001600160a01b0316611711565b348015610a2757600080fd5b5061041f611786565b348015610a3c57600080fd5b506106746118a0565b348015610a5157600080fd5b5061069f6118a5565b348015610a6657600080fd5b506104366118ab565b348015610a7b57600080fd5b506104366118b0565b348015610a9057600080fd5b5061069f6118b5565b348015610aa557600080fd5b506104fb6118bb565b348015610aba57600080fd5b506105856118da565b348015610acf57600080fd5b506104366118e3565b348015610ae457600080fd5b5061045d6115bd565b348015610af957600080fd5b5061041f60048036036040811015610b1057600080fd5b810190602081018135600160201b811115610b2a57600080fd5b820183602082011115610b3c57600080fd5b803590602001918460018302840111600160201b83111715610b5d57600080fd5b919390929091602081019035600160201b811115610b7a57600080fd5b820183602082011115610b8c57600080fd5b803590602001918460018302840111600160201b83111715610bad57600080fd5b5090925090506118ec565b348015610bc457600080fd5b5061043660048036036020811015610bdb57600080fd5b50356001600160a01b0316612329565b348015610bf757600080fd5b5061072661233b565b348015610c0c57600080fd5b5061043661241e565b348015610c2157600080fd5b50610436611631565b348015610c3657600080fd5b5061069f612423565b348015610c4b57600080fd5b50610436612429565b348015610c6057600080fd5b50610436612468565b348015610c7557600080fd5b50610436612474565b348015610c8a57600080fd5b5061069f61247a565b348015610c9f57600080fd5b50610436612480565b348015610cb457600080fd5b5061041f612485565b348015610cc957600080fd5b50610436612688565b348015610cde57600080fd5b5061041f60048036036020811015610cf557600080fd5b50356001600160a01b031661268e565b348015610d1157600080fd5b5061045d61279c565b61041f60048036036020811015610d3057600080fd5b50356001600160a01b03166127a1565b348015610d4c57600080fd5b50610436612aa6565b348015610d6157600080fd5b5061069f612aac565b348015610d7657600080fd5b506106746118ab565b348015610d8b57600080fd5b5061069f612ab2565b348015610da057600080fd5b50610dbe60048036036020811015610db757600080fd5b5035612ab8565b6040805192835290151560208301528051918290030190f35b348015610de357600080fd5b5061069f612ae6565b6000610df733611711565b9050600b8181548110610e0657fe5b600091825260209091206001601690920201015460ff16610e63576040805162461bcd60e51b81526020600482015260126024820152716e6f7420696e206d61696e74656e616e636560701b604482015290519081900360640190fd5b6000610e6d612429565b9050610e7a338383612aec565b505050565b60095481565b606481565b60005460609060ff16610ee0576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b3361200014610f205760405162461bcd60e51b815260040180806020018281038252602f815260200180616047602f913960400191505060405180910390fd5b600b54610fc557610f2f6159e0565b60015460005b81811015610fc157600b80546001810182556000919091528351600080516020615fc0833981519152601690920291820190815560208501516000805160206160d08339815191528301805460ff191691151591909117905560408501518592610fb391600080516020616006833981519152909101906014615a04565b505050806001019050610f35565b5050505b610fcd615a3e565b600061100e85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612ce092505050565b915091508061102a576110216064612e39565b92505050611115565b815160009060ff1661104a576110438360200151612e9a565b90506110e1565b825160ff16600114156110dd578260200151516001146110b7577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2604051808060200182810382526025815260200180615f066025913960400191505060405180910390a15060676110d8565b61104383602001516000815181106110cb57fe5b6020026020010151613caa565b6110e1565b5060655b63ffffffff811661110657505060408051600081526020810190915291506111159050565b61110f81612e39565b93505050505b9392505050565b60075460ff1681565b60035481565b606881565b6001546000908210611144575060006111fa565b60006001600160a01b03166001838154811061115c57fe5b60009182526020909120600490910201546001600160a01b0316148061118c5750600854158061118c5750600a54155b8061119b575060085460095410155b806111ac57506111aa826111ff565b155b806111d557506000600b83815481106111c157fe5b906000526020600020906016020160000154115b806111e9575060016111e561233b565b5111155b156111f6575060006111fa565b5060015b919050565b6001546000908210611213575060006111fa565b600b548210611250576001828154811061122957fe5b9060005260206000209060040201600201601c9054906101000a900460ff161590506111fa565b6001828154811061125d57fe5b9060005260206000209060040201600201601c9054906101000a900460ff161580156112aa5750600b828154811061129157fe5b600091825260209091206001601690920201015460ff16155b92915050565b33611001146112f05760405162461bcd60e51b81526004018080602001828103825260298152602001806160f06029913960400191505060405180910390fd5b600b54611395576112ff6159e0565b60015460005b8181101561139157600b80546001810182556000919091528351600080516020615fc0833981519152601690920291820190815560208501516000805160206160d08339815191528301805460ff19169115159190911790556040850151859261138391600080516020616006833981519152909101906014615a04565b505050806001019050611305565b5050505b6001600160a01b038116600090815260046020526040902054806113b9575061140c565b6001810390506000600b82815481106113ce57fe5b600091825260209091206001601690920201015460ff1690506113f18383613e21565b80156113fa5750805b15610e7a576009805460001901905550505b50565b61271081565b600181565b61100181565b60085481565b606181565b600881565b600e54600c546060919080611443575060155b606061144d61233b565b905081815111611461579250611528915050565b82828251031015611473578181510392505b82156114a75760c8430461148e82828686036000888861419d565b6114a582828686038787038889898951030161419d565b505b6060826040519080825280602002602001820160405280156114d3578160200160208202803683370190505b50905060005b83811015611521578281815181106114ed57fe5b602002602001015182828151811061150157fe5b6001600160a01b03909216602092830291909101909101526001016114d9565b5093505050505b90565b60065481565b61200081565b6001600160a01b0381166000908152600460205260408120548061155f5760009150506111fa565b60001901611115816111ff565b6001600160a01b038116600090815260046020526040812054806115945760009150506111fa565b6001808203815481106115a357fe5b906000526020600020906004020160030154915050919050565b600081565b606781565b600181815481106115d457fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509082169291821691600160a01b81046001600160401b031691600160e01b90910460ff169086565b61100581565b600281565b61100881565b6103e881565b600b81565b600c5481565b606681565b33612000146116925760405162461bcd60e51b815260040180806020018281038252602f815260200180616047602f913960400191505060405180910390fd5b7f41ce201247b6ceb957dcdb217d0b8acb50b9ea0e12af9af4f5e7f38902101605838383604051808460ff1660ff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b60025481565b600a5481565b6001600160a01b0381166000908152600460205260408120548061177c576040805162461bcd60e51b815260206004820152601760248201527f6f6e6c792063757272656e742076616c696461746f7273000000000000000000604482015290519081900360640190fd5b6000190192915050565b600b5461182b576117956159e0565b60015460005b8181101561182757600b80546001810182556000919091528351600080516020615fc0833981519152601690920291820190815560208501516000805160206160d08339815191528301805460ff19169115159190911790556040850151859261181991600080516020616006833981519152909101906014615a04565b50505080600101905061179b565b5050505b6008546118385760036008555b600a54611845576002600a555b600061185033611711565b905061185b81611130565b6118965760405162461bcd60e51b8152600401808060200182810382526023815260200180615ee36023913960400191505060405180910390fd5b61140c338261428c565b600981565b61100781565b600381565b60c881565b61100681565b604051806101e001604052806101ab8152602001615b396101ab913981565b60005460ff1681565b6402540be40081565b60005460ff1661193f576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b336110071461197f5760405162461bcd60e51b815260040180806020018281038252602e815260200180615f4c602e913960400191505060405180910390fd5b6119e984848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526013815272065787069726554696d655365636f6e6447617606c1b602082015291506143249050565b15611ac45760208114611a2d5760405162461bcd60e51b8152600401808060200182810382526026815260200180615fe06026913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611a6b9185858083850183828082843760009201919091525061440b92505050565b905060648110158015611a815750620186a08111155b611abc5760405162461bcd60e51b8152600401808060200182810382526027815260200180615e736027913960400191505060405180910390fd5b600255612297565b611b2484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260098152686275726e526174696f60b81b602082015291506143249050565b15611c145760208114611b7e576040805162461bcd60e51b815260206004820152601c60248201527f6c656e677468206f66206275726e526174696f206d69736d6174636800000000604482015290519081900360640190fd5b604080516020601f8401819004810282018101909252828152600091611bbc9185858083850183828082843760009201919091525061440b92505050565b9050612710811115611bff5760405162461bcd60e51b815260040180806020018281038252602b815260200180615e1d602b913960400191505060405180910390fd5b6006556007805460ff19166001179055612297565b611c7e84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260138152726d61784e756d4f664d61696e7461696e696e6760681b602082015291506143249050565b15611d565760208114611cc25760405162461bcd60e51b8152600401808060200182810382526026815260200180615ce46026913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611d009185858083850183828082843760009201919091525061440b92505050565b600c5490915080611d0f575060155b808210611d4d5760405162461bcd60e51b8152600401808060200182810382526038815260200180615d5b6038913960400191505060405180910390fd5b50600855612297565b611dbf84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61696e7461696e536c6173685363616c6560701b602082015291506143249050565b15611e8a5760208114611e035760405162461bcd60e51b8152600401808060200182810382526025815260200180615d366025913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611e419185858083850183828082843760009201919091525061440b92505050565b905060008111611e825760405162461bcd60e51b815260040180806020018281038252602d8152602001806160a3602d913960400191505060405180910390fd5b600a55612297565b611efe84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601981527f6d61784e756d4f66576f726b696e6743616e6469646174657300000000000000602082015291506143249050565b15611fcb5760208114611f425760405162461bcd60e51b815260040180806020018281038252602c815260200180615d0a602c913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611f809185858083850183828082843760009201919091525061440b92505050565b9050600d54811115611fc35760405162461bcd60e51b8152600401808060200182810382526049815260200180615e9a6049913960600191505060405180910390fd5b600e55612297565b61203484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61784e756d4f6643616e6469646174657360701b602082015291506143249050565b156120d557602081146120785760405162461bcd60e51b8152600401808060200182810382526025815260200180615f7a6025913960400191505060405180910390fd5b604080516020601f84018190048102820181019092528281526000916120b69185858083850183828082843760009201919091525061440b92505050565b600d819055600e549091508110156120cf57600d54600e555b50612297565b61213984848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600d81526c6e756d4f66436162696e65747360981b602082015291506143249050565b1561225a5760208114612193576040805162461bcd60e51b815260206004820181905260248201527f6c656e677468206f66206e756d4f66436162696e657473206d69736d61746368604482015290519081900360640190fd5b604080516020601f84018190048102820181019092528281526000916121d19185858083850183828082843760009201919091525061440b92505050565b9050600081116122125760405162461bcd60e51b8152600401808060200182810382526028815260200180615d936028913960400191505060405180910390fd5b60298111156122525760405162461bcd60e51b8152600401808060200182810382526039815260200180615dbb6039913960400191505060405180910390fd5b600c55612297565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b60046020526000908152604090205481565b6001546060906000805b8281101561236a57612356816111ff565b15612362576001909101905b600101612345565b50606081604051908082528060200260200182016040528015612397578160200160208202803683370190505b5090506000915060005b83811015612416576123b2816111ff565b1561240e57600181815481106123c457fe5b600091825260209091206004909102015482516001600160a01b03909116908390859081106123ef57fe5b6001600160a01b03909216602092830291909101909101526001909201915b6001016123a1565b509250505090565b601581565b61100281565b600061243361233b565b519050600080600c541161244857601561244c565b600c545b90508082111561245a578091505b8161246457600191505b5090565b67016345785d8a000081565b60055481565b61100381565b602981565b60005460ff16156124dd576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b6124e5615a3e565b600061250b604051806101e001604052806101ab8152602001615b396101ab9139612ce0565b915091508061254b5760405162461bcd60e51b81526004018080602001828103825260218152602001806160266021913960400191505060405180910390fd5b60005b8260200151518110156126705760018360200151828151811061256d57fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782558587015182850180549185169183169190911790556040860151600283018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590981692909516919091179290921694909417161790915560a09093015160039093019290925591860151805191850193918590811061264357fe5b602090810291909101810151516001600160a01b031682528101919091526040016000205560010161254e565b50506103e8600255506000805460ff19166001179055565b600d5481565b33611001146126ce5760405162461bcd60e51b81526004018080602001828103825260298152602001806160f06029913960400191505060405180910390fd5b600b54612773576126dd6159e0565b60015460005b8181101561276f57600b80546001810182556000919091528351600080516020615fc0833981519152601690920291820190815560208501516000805160206160d08339815191528301805460ff19169115159190911790556040850151859261276191600080516020616006833981519152909101906014615a04565b5050508060010190506126e3565b5050505b600061277e82614410565b905061278981611130565b1561279857612798828261428c565b5050565b606581565b3341146127df5760405162461bcd60e51b815260040180806020018281038252602d815260200180616076602d913960400191505060405180910390fd5b60005460ff16612832576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b6000341161287f576040805162461bcd60e51b81526020600482015260156024820152746465706f7369742076616c7565206973207a65726f60581b604482015290519081900360640190fd5b6001600160a01b0381166000908152600460205260409020546007543491906103e89060ff16156128af57506006545b6000831180156128bf5750600081115b156129685760006128e86127106128dc868563ffffffff6145b416565b9063ffffffff61460d16565b905080156129665760405161dead9082156108fc029083906000818181858888f1935050505015801561291f573d6000803e3d6000fd5b506040805182815290517f627059660ea01c4733a328effb2294d2f86905bf806da763a89cee254de8bee59181900360200190a1612963848263ffffffff61464f16565b93505b505b8115612a6057600060018084038154811061297f57fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff16156129ea576040805185815290516001600160a01b038716917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a2612a5a565b6003546129fd908563ffffffff61469116565b6003908155810154612a15908563ffffffff61469116565b60038201556040805185815290516001600160a01b038716917f93a090ecc682c002995fad3c85b30c5651d7fd29b0be5da9d784a3302aedc055919081900360200190a25b50612aa0565b6040805184815290516001600160a01b038616917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a25b50505050565b600e5481565b61100081565b61dead81565b600b8181548110612ac557fe5b60009182526020909120601690910201805460019091015490915060ff1682565b61100481565b6000600a5460001480612afd575081155b80612b085750600954155b15612b1557506000611115565b600960008154809291906001900391905055506000612b62600a546128dc856128dc600b8981548110612b4457fe5b6000918252602090912060169091020154439063ffffffff61464f16565b90506000600b8581548110612b7357fe5b906000526020600020906016020160010160006101000a81548160ff0219169083151502179055506000806110016001600160a01b0316638256ace66040518163ffffffff1660e01b8152600401604080518083038186803b158015612bd857600080fd5b505afa158015612bec573d6000803e3d6000fd5b505050506040513d6040811015612c0257600080fd5b508051602090910151600095509092509050808310612c9057612c258787613e21565b50604080516305bfb49960e41b81526001600160a01b0389166004820152905161100191635bfb499091602480830192600092919082900301818387803b158015612c6f57600080fd5b505af1158015612c83573d6000803e3d6000fd5b5050505060019350612ca2565b818310612ca257612ca087614410565b505b6040516001600160a01b038816907fb9d38178dc641ff1817967a63c9078cbcd955a9f1fcd75e0e3636de615d44d3b90600090a25050509392505050565b612ce8615a3e565b6000612cf2615a3e565b612cfa615a56565b612d0b612d06866146eb565b614710565b90506000805b612d1a8361475a565b15612e2b5780612d3f57612d35612d308461477b565b6147c9565b60ff168452612e23565b8060011415612e1e576060612d5b612d568561477b565b614880565b90508051604051908082528060200260200182016040528015612d9857816020015b612d85615a76565b815260200190600190039081612d7d5790505b50602086015260005b8151811015612e1357612db2615a76565b6000612dd0848481518110612dc357fe5b6020026020010151614951565b9150915080612ded57876000995099505050505050505050612e34565b8188602001518481518110612dfe57fe5b60209081029190910101525050600101612da1565b506001925050612e23565b612e2b565b600101612d11565b50919350909150505b915091565b604080516001808252818301909252606091829190816020015b6060815260200190600190039081612e53579050509050612e798363ffffffff16614a2e565b81600081518110612e8657fe5b602002602001018190525061111581614a41565b6000806060612ea884614acb565b9150915081612f55577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2816040518080602001828103825283818151815260200191508051906020019080838360005b83811015612f10578181015183820152602001612ef8565b50505050905090810190601f168015612f3d5780820380516001836020036101000a031916815260200191505b509250505060405180910390a16066925050506111fa565b50506060612f6283614bad565b6001549091506000908190815b81811015612fe55767016345785d8a000060018281548110612f8d57fe5b90600052602060002090600402016003015410612faf57600190930192612fdd565b600060018281548110612fbe57fe5b9060005260206000209060040201600301541115612fdd576001909201915b600101612f6f565b50606083604051908082528060200260200182016040528015613012578160200160208202803683370190505b509050606084604051908082528060200260200182016040528015613041578160200160208202803683370190505b509050606085604051908082528060200260200182016040528015613070578160200160208202803683370190505b50905060608660405190808252806020026020018201604052801561309f578160200160208202803683370190505b50905060006060876040519080825280602002602001820160405280156130d0578160200160208202803683370190505b5090506060886040519080825280602002602001820160405280156130ff578160200160208202803683370190505b509050600099506000985060006110046001600160a01b031663149d14d96040518163ffffffff1660e01b815260040160206040518083038186803b15801561314757600080fd5b505afa15801561315b573d6000803e3d6000fd5b505050506040513d602081101561317157600080fd5b5051905067016345785d8a00008111156131e5577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2604051808060200182810382526021815260200180615f9f6021913960400191505060405180910390a160689c505050505050505050505050506111fa565b60005b898110156134565767016345785d8a00006001828154811061320657fe5b9060005260206000209060040201600301541061338c576001818154811061322a57fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316898d8151811061325b57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006402540be4006001838154811061329057fe5b906000526020600020906004020160030154816132a957fe5b06600183815481106132b757fe5b9060005260206000209060040201600301540390506132df838261464f90919063ffffffff16565b898e815181106132eb57fe5b6020026020010181815250506001828154811061330457fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316878e8151811061333557fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081888e8151811061336257fe5b602090810291909101015261337d868263ffffffff61469116565b6001909d019c955061344e9050565b60006001828154811061339b57fe5b906000526020600020906004020160030154111561344e57600181815481106133c057fe5b906000526020600020906004020160010160009054906101000a90046001600160a01b0316848c815181106133f157fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001818154811061341e57fe5b906000526020600020906004020160030154838c8151811061343c57fe5b60209081029190910101526001909a01995b6001016131e8565b5060008415613894576110046001600160a01b0316636e056520868b8b8a60025442016040518663ffffffff1660e01b815260040180806020018060200180602001856001600160401b03166001600160401b03168152602001848103845288818151815260200191508051906020019060200280838360005b838110156134e85781810151838201526020016134d0565b50505050905001848103835287818151815260200191508051906020019060200280838360005b8381101561352757818101518382015260200161350f565b50505050905001848103825286818151815260200191508051906020019060200280838360005b8381101561356657818101518382015260200161354e565b505050509050019750505050505050506020604051808303818588803b15801561358f57600080fd5b505af1935050505080156135b557506040513d60208110156135b057600080fd5b505160015b6137f0576040516000815260443d10156135d15750600061366c565b60046000803e60005160e01c6308c379a081146135f257600091505061366c565b60043d036004833e81513d60248201116001600160401b038211171561361d5760009250505061366c565b80830180516001600160401b0381111561363e57600094505050505061366c565b8060208301013d860181111561365c5760009550505050505061366c565b601f01601f191660405250925050505b80613677575061371b565b60019150857fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280826040518080602001828103825283818151815260200191508051906020019080838360005b838110156136db5781810151838201526020016136c3565b50505050905090810190601f1680156137085780820380516001836020036101000a031916815260200191505b509250505060405180910390a2506137eb565b3d808015613745576040519150601f19603f3d011682016040523d82523d6000602084013e61374a565b606091505b5060019150857fbfa884552dd8921b6ce90bfe906952ae5b3b29be0cc1a951d4f62697635a3a45826040518080602001828103825283818151815260200191508051906020019080838360005b838110156137af578181015183820152602001613797565b50505050905090810190601f1680156137dc5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505b613894565b801561382e576040805187815290517fa217d08e65f80c73121cd9db834d81652d544bfbf452f6d04922b16c90a37b709181900360200190a1613892565b604080516020808252601b908201527f6261746368207472616e736665722072657475726e2066616c7365000000000081830152905187917fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280919081900360600190a25b505b8015613a4a5760005b8751811015613a485760008882815181106138b457fe5b602002602001015190506000600182815481106138cd57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116916108fc91859081106138fe57fe5b9060005260206000209060040201600301549081150290604051600060405180830381858888f19350505050905080156139ba576001828154811061393f57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d918590811061398e57fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a2613a3e565b600182815481106139c757fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d9185908110613a1657fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a25b505060010161389d565b505b835115613b945760005b8451811015613b92576000858281518110613a6b57fe5b60200260200101516001600160a01b03166108fc868481518110613a8b57fe5b60200260200101519081150290604051600060405180830381858888f1935050505090508015613b2157858281518110613ac157fe5b60200260200101516001600160a01b03167f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d868481518110613aff57fe5b60200260200101516040518082815260200191505060405180910390a2613b89565b858281518110613b2d57fe5b60200260200101516001600160a01b03167f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d868481518110613b6b57fe5b60200260200101516040518082815260200191505060405180910390a25b50600101613a54565b505b4715613bfd576040805147815290517f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d9181900360200190a1604051611002904780156108fc02916000818181858888f19350505050158015613bfb573d6000803e3d6000fd5b505b600060038190556005558c5115613c1757613c178d614d7d565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613c5457600080fd5b505af1158015613c68573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a15060009e9d5050505050505050505050505050565b80516001600160a01b0316600090815260046020526040812054801580613cfb5750600180820381548110613cdb57fe5b9060005260206000209060040201600201601c9054906101000a900460ff165b15613d415782516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a260009150506111fa565b600154600554600019820111801590613d975784516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a2600093505050506111fa565b600580546001908101909155805481906000198601908110613db557fe5b6000918252602082206002600490920201018054921515600160e01b0260ff60e01b199093169290921790915585516040516001600160a01b03909116917ff226e7d8f547ff903d9d419cf5f54e0d7d07efa9584135a53a057c5f1f27f49a91a2506000949350505050565b60008060018381548110613e3157fe5b90600052602060002090600402016003015490506000600180805490500390506001613e5b61233b565b5111613e9057600060018581548110613e7057fe5b9060005260206000209060040201600301819055506000925050506112aa565b6040805183815290516001600160a01b038716917f3b6f9ef90462b512a1293ecec018670bf7b7f1876fb727590a8a6d7643130a70919081900360200190a26001600160a01b038516600090815260046020526040812055835b6001546000190181101561408d5760018160010181548110613f0857fe5b906000526020600020906004020160018281548110613f2357fe5b60009182526020909120825460049092020180546001600160a01b03199081166001600160a01b0393841617825560018085015481840180548416918616919091179055600280860180549185018054909416919095161780835584546001600160401b03600160a01b91829004160267ffffffffffffffff60a01b1990911617808355935460ff600160e01b918290041615150260ff60e01b19909416939093179055600392830154920191909155600b805490918301908110613fe457fe5b9060005260206000209060160201600b8281548110613fff57fe5b600091825260209091208254601690920201908155600180830154908201805460ff191660ff909216151591909117905561404260028083019084016014615aab565b5090505080600101600460006001848154811061405b57fe5b600091825260208083206004909202909101546001600160a01b03168352820192909252604001902055600101613eea565b50600180548061409957fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b8054806140ec57fe5b60008281526020812060166000199093019283020181815560018101805460ff191690559061411e6002830182615ad6565b50509055600081838161412d57fe5b04905080156141915760015460005b8181101561418e57826001828154811061415257fe5b906000526020600020906004020160030154016001828154811061417257fe5b600091825260209091206003600490920201015560010161413c565b50505b50600195945050505050565b60005b828110156142835760408051602080820189905287840182840152825180830384018152606090920190925280519101206000908390816141dd57fe5b0690508085018287011461427a57600088838801815181106141fb57fe5b60200260200101519050888287018151811061421357fe5b6020026020010151898489018151811061422957fe5b60200260200101906001600160a01b031690816001600160a01b03168152505080898388018151811061425857fe5b60200260200101906001600160a01b031690816001600160a01b031681525050505b506001016141a0565b50505050505050565b600980546001908101909155600b8054839081106142a657fe5b906000526020600020906016020160010160006101000a81548160ff02191690831515021790555043600b82815481106142dc57fe5b600091825260208220601690910201919091556040516001600160a01b038416917ff62981a567ec3cec866c6fa93c55bcdf841d6292d18b8d522ececa769375d82d91a25050565b6000816040516020018082805190602001908083835b602083106143595780518252601f19909201916020918201910161433a565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b602083106143c75780518252601f1990920191602091820191016143a8565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012014905092915050565b015190565b6001600160a01b03811660009081526004602052604081205480614439575060001990506111fa565b60018103905060006001828154811061444e57fe5b906000526020600020906004020160030154905060006001838154811061447157fe5b906000526020600020906004020160030181905550600060018080549050039050846001600160a01b03167f8cd4e147d8af98a9e3b6724021b8bf6aed2e5dac71c38f2dce8161b82585b25d836040518082815260200191505060405180910390a2806144e3578293505050506111fa565b60008183816144ee57fe5b04905080156145aa5760005b8481101561454c57816001828154811061451057fe5b906000526020600020906004020160030154016001828154811061453057fe5b60009182526020909120600360049092020101556001016144fa565b50600180549085015b818110156145a757826001828154811061456b57fe5b906000526020600020906004020160030154016001828154811061458b57fe5b6000918252602090912060036004909202010155600101614555565b50505b5091949350505050565b6000826145c3575060006112aa565b828202828482816145d057fe5b04146111155760405162461bcd60e51b8152600401808060200182810382526021815260200180615f2b6021913960400191505060405180910390fd5b600061111583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250615370565b600061111583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250615412565b600082820183811015611115576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6146f3615ae5565b506040805180820190915281518152602082810190820152919050565b614718615a56565b6147218261546c565b61472a57600080fd5b600061473983602001516154a6565b60208085015160408051808201909152868152920190820152915050919050565b6000614764615ae5565b505080518051602091820151919092015191011190565b614783615ae5565b61478c8261475a565b61479557600080fd5b602082015160006147a582615509565b80830160209586015260408051808201909152908152938401919091525090919050565b8051600090158015906147de57508151602110155b6147e757600080fd5b60006147f683602001516154a6565b90508083600001511015614851576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b82516020808501518301805192849003929183101561487757826020036101000a820491505b50949350505050565b606061488b8261546c565b61489457600080fd5b600061489f8361563c565b90506060816040519080825280602002602001820160405280156148dd57816020015b6148ca615ae5565b8152602001906001900390816148c25790505b50905060006148ef85602001516154a6565b60208601510190506000805b848110156149465761490c83615509565b915060405180604001604052808381526020018481525084828151811061492f57fe5b6020908102919091010152918101916001016148fb565b509195945050505050565b614959615a76565b6000614963615a76565b61496b615a56565b61497485614710565b90506000805b6149838361475a565b15612e2b57806149ae5761499e6149998461477b565b615698565b6001600160a01b03168452614a26565b80600114156149d6576149c36149998461477b565b6001600160a01b03166020850152614a26565b80600214156149fe576149eb6149998461477b565b6001600160a01b03166040850152614a26565b8060031415612e1e57614a13612d308461477b565b6001600160401b03166060850152600191505b60010161497a565b60606112aa614a3c836156b2565b615798565b6060815160001415614a6257506040805160008152602081019091526111fa565b606082600081518110614a7157fe5b602002602001015190506000600190505b8351811015614ab257614aa882858381518110614a9b57fe5b60200260200101516157ea565b9150600101614a82565b50611115614ac5825160c060ff16615867565b826157ea565b60006060602983511115614afd576000604051806060016040528060298152602001615df46029913991509150612e34565b60005b8351811015614b935760005b81811015614b8a57848181518110614b2057fe5b6020026020010151600001516001600160a01b0316858381518110614b4157fe5b6020026020010151600001516001600160a01b03161415614b825760006040518060600160405280602b8152602001615e48602b9139935093505050612e34565b600101614b0c565b50600101614b00565b505060408051602081019091526000815260019150915091565b6060600080808080614bbd612429565b6001549091505b8015614ccb57600181039250600b8381548110614bdd57fe5b600091825260209091206001601690920201015460ff16614bfd57614cc2565b60018381548110614c0a57fe5b60009182526020909120600490910201546001600160a01b03169450614c31858484612aec565b9350831580614c44575060018851038610155b15614c4e57614cc2565b60005b8851811015614cc057856001600160a01b0316898281518110614c7057fe5b6020026020010151600001516001600160a01b03161415614cb8576001898281518110614c9957fe5b6020908102919091010151901515608090910152600190960195614cc0565b600101614c51565b505b60001901614bc4565b5084875103604051908082528060200260200182016040528015614d0957816020015b614cf6615a76565b815260200190600190039081614cee5790505b5095506000915060005b8751811015614d7257878181518110614d2857fe5b602002602001015160800151614d6a57878181518110614d4457fe5b6020026020010151878481518110614d5857fe5b60209081029190910101526001909201915b600101614d13565b505050505050919050565b600154815160005b82811015614e9a576001614d97615a76565b60018381548110614da457fe5b600091825260208083206040805160c08101825260049490940290910180546001600160a01b0390811685526001820154811693850193909352600281015492831691840191909152600160a01b82046001600160401b03166060840152600160e01b90910460ff16151560808301526003015460a082015291505b84811015614e6e57868181518110614e3457fe5b6020026020010151600001516001600160a01b031682600001516001600160a01b03161415614e665760009250614e6e565b600101614e20565b508115614e905780516001600160a01b03166000908152600460205260408120555b5050600101614d85565b5080821115614f4b57805b82811015614f49576001805480614eb857fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b805480614f0b57fe5b60008281526020812060166000199093019283020181815560018101805460ff1916905590614f3d6002830182615ad6565b50509055600101614ea5565b505b6000818310614f5a5781614f5c565b825b905060005b818110156151565761500e858281518110614f7857fe5b602002602001015160018381548110614f8d57fe5b60009182526020918290206040805160c08101825260049390930290910180546001600160a01b0390811684526001820154811694840194909452600281015493841691830191909152600160a01b83046001600160401b03166060830152600160e01b90920460ff161515608082015260039091015460a082015261595f565b61512957806001016004600087848151811061502657fe5b6020026020010151600001516001600160a01b03166001600160a01b031681526020019081526020016000208190555084818151811061506257fe5b60200260200101516001828154811061507757fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a09091015160039091015561514e565b60006001828154811061513857fe5b9060005260206000209060040201600301819055505b600101614f61565b50828211156152fb576151676159e0565b835b838110156152f857600186828151811061517f57fe5b6020908102919091018101518254600181810185556000948552838520835160049093020180546001600160a01b039384166001600160a01b0319918216178255848601518284018054918616918316919091179055604080860151600284018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909a1692909616919091179290921696909617169190911790935560a090930151600390930192909255600b8054928301815590935284516016909102600080516020615fc08339815191528101918255918501516000805160206160d08339815191528301805491151560ff19909216919091179055918401518492916152b491600080516020616006833981519152909101906014615a04565b50505080600101600460008884815181106152cb57fe5b602090810291909101810151516001600160a01b0316825281019190915260400160002055600101615169565b50505b6000600981905560015493505b83811015615369576000600b828154811061531f57fe5b60009182526020822060169190910201600101805460ff191692151592909217909155600b80548390811061535057fe5b6000918252602090912060169091020155600101615308565b5050505050565b600081836153fc5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156153c15781810151838201526020016153a9565b50505050905090810190601f1680156153ee5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161540857fe5b0495945050505050565b600081848411156154645760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156153c15781810151838201526020016153a9565b505050900390565b805160009061547d575060006111fa565b6020820151805160001a9060c082101561549c576000925050506111fa565b5060019392505050565b8051600090811a60808110156154c05760009150506111fa565b60b88110806154db575060c081108015906154db575060f881105b156154ea5760019150506111fa565b60c08110156154fe5760b5190190506111fa565b60f5190190506111fa565b80516000908190811a60808110156155245760019150615635565b60b881101561553957607e1981019150615635565b60c08110156155b357600060b78203600186019550806020036101000a8651049150600181018201935050808310156155ad576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b50615635565b60f88110156155c85760be1981019150615635565b600060f78203600186019550806020036101000a865104915060018101820193505080831015615633576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b805160009061564d575060006111fa565b6000809050600061566184602001516154a6565b602085015185519181019250015b8082101561568f5761568082615509565b6001909301929091019061566f565b50909392505050565b80516000906015146156a957600080fd5b6112aa826147c9565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff1984166156f65750601861571a565b6fffffffffffffffffffffffffffffffff1984166157165750601061571a565b5060005b60208110156157505781818151811061572f57fe5b01602001516001600160f81b0319161561574857615750565b60010161571a565b60008160200390506060816040519080825280601f01601f191660200182016040528015615785576020820181803683370190505b5080830196909652508452509192915050565b6060815160011480156157ca5750607f60f81b826000815181106157b857fe5b01602001516001600160f81b03191611155b156157d65750806111fa565b6112aa6157e88351608060ff16615867565b835b6060806040519050835180825260208201818101602087015b8183101561581b578051835260209283019201615803565b50855184518101855292509050808201602086015b81831015615848578051835260209283019201615830565b508651929092011591909101601f01601f191660405250905092915050565b60606801000000000000000083106158b7576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116159115782840160f81b816000815181106158f357fe5b60200101906001600160f81b031916908160001a90535090506112aa565b606061591c856156b2565b90508381510160370160f81b8260008151811061593557fe5b60200101906001600160f81b031916908160001a90535061595682826157ea565b95945050505050565b805182516000916001600160a01b039182169116148015615999575081602001516001600160a01b031683602001516001600160a01b0316145b80156159be575081604001516001600160a01b031683604001516001600160a01b0316145b80156111155750506060908101519101516001600160401b0390811691161490565b60408051606081018252600080825260208201529081016159ff615aff565b905290565b8260148101928215615a32579160200282015b82811115615a32578251825591602001919060010190615a17565b50612464929150615b1e565b60408051808201909152600081526060602082015290565b6040518060400160405280615a69615ae5565b8152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b8260148101928215615a32579182015b82811115615a32578254825591600101919060010190615abb565b5061140c906014810190615b1e565b604051806040016040528060008152602001600081525090565b6040518061028001604052806014906020820280368337509192915050565b61152891905b808211156124645760008155600101615b2456fef901a880f901a4f844941284214b9b9c85549ab3d2b972df0deef66ac2c9946ddf42a51534fc98d0c0a3b42c963cace8441ddf946ddf42a51534fc98d0c0a3b42c963cace8441ddf8410000000f84494a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0948081ef03f1d9e0bb4a5bf38f16285c879299f07f948081ef03f1d9e0bb4a5bf38f16285c879299f07f8410000000f8449435552c16704d214347f29fa77f77da6d75d7c75294dc4973e838e3949c77aced16ac2315dc2d7ab11194dc4973e838e3949c77aced16ac2315dc2d7ab1118410000000f84494980a75ecd1309ea12fa2ed87a8744fbfc9b863d594cc6ac05c95a99c1f7b5f88de0e3486c82293b27094cc6ac05c95a99c1f7b5f88de0e3486c82293b2708410000000f84494f474cf03cceff28abc65c9cbae594f725c80e12d94e61a183325a18a173319dd8e19c8d069459e217594e61a183325a18a173319dd8e19c8d069459e21758410000000f84494b71b214cb885500844365e95cd9942c7276e7fd894d22ca3ba2141d23adab65ce4940eb7665ea2b6a794d22ca3ba2141d23adab65ce4940eb7665ea2b6a784100000006c656e677468206f66206d61784e756d4f664d61696e7461696e696e67206d69736d617463686c656e677468206f66206d61784e756d4f66576f726b696e6743616e64696461746573206d69736d617463686c656e677468206f66206d61696e7461696e536c6173685363616c65206d69736d61746368746865206d61784e756d4f664d61696e7461696e696e67206d757374206265206c657373207468616e206e756d4f6643616e696e61746573746865206e756d4f66436162696e657473206d7573742062652067726561746572207468616e2030746865206e756d4f66436162696e657473206d757374206265206c657373207468616e204d41585f4e554d5f4f465f56414c494441544f5253746865206e756d626572206f662076616c696461746f72732065786365656420746865206c696d6974746865206275726e526174696f206d757374206265206e6f2067726561746572207468616e2031303030306475706c696361746520636f6e73656e7375732061646472657373206f662076616c696461746f725365747468652065787069726554696d655365636f6e64476170206973206f7574206f662072616e6765746865206d61784e756d4f66576f726b696e6743616e64696461746573206d757374206265206e6f742067726561746572207468616e206d61784e756d4f6643616e6469646174657363616e206e6f7420656e7465722054656d706f72617279204d61696e74656e616e63656c656e677468206f66206a61696c2076616c696461746f7273206d757374206265206f6e65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e74726163746c656e677468206f66206d61784e756d4f6643616e64696461746573206d69736d61746368666565206973206c6172676572207468616e2044555354595f494e434f4d494e470175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db96c656e677468206f662065787069726554696d655365636f6e64476170206d69736d617463680175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb6661696c656420746f20706172736520696e69742076616c696461746f72536574746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f6475636572746865206d61696e7461696e536c6173685363616c65206d7573742062652067726561746572207468616e20300175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba746865206d6573736167652073656e646572206d75737420626520736c61736820636f6e7472616374a2646970667358221220c0dc878fd08b0a4bf6659ead68604aefff201930a1931eca7eb88ebdf3b0a03e64736f6c63430006040033", + }, + { + ContractAddr: common.HexToAddress(SlashContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/db8bb560ac5a1265c685b719c7e976dced162310", + Code: "608060405234801561001057600080fd5b506004361061023d5760003560e01c80638256ace61161013b578063c80d4b8f116100b8578063e1c7392a1161007c578063e1c7392a1461071d578063f9a2bbc714610725578063fc3e59081461072d578063fc4333cd14610735578063fd6a68791461073d5761023d565b8063c80d4b8f14610667578063c81b16621461066f578063c8509d8114610677578063c96be4cb146106ef578063dc927faf146107155761023d565b8063a1a11bf5116100ff578063a1a11bf514610575578063a78abc161461057d578063ab51bb9614610599578063ac0af629146105a1578063ac431751146105a95761023d565b80638256ace6146104dd578063831d65d1146104e557806396713da91461055d5780639bc8e4f2146105655780639dc092621461056d5761023d565b80634bf6c882116101c95780636e47b4821161018d5780636e47b482146104b557806370fd5bad146104bd57806375d47a0a146104c55780637912a65d146104cd5780637942fd05146104d55761023d565b80634bf6c8821461046d57806351e8067214610475578063567a372d1461047d5780635bfb49901461048557806362b72cf5146104ad5761023d565b806337c8dab91161021057806337c8dab9146103cf578063389f4f711461040e5780633dffc3871461042857806343756e5c14610446578063493279b11461044e5761023d565b80630bee7a67146102425780631182b8751461026357806323bac5a21461035057806335aa2e4414610396575b600080fd5b61024a610745565b6040805163ffffffff9092168252519081900360200190f35b6102db6004803603604081101561027957600080fd5b60ff8235169190810190604081016020820135600160201b81111561029d57600080fd5b8201836020820111156102af57600080fd5b803590602001918460018302840111600160201b831117156102d057600080fd5b50909250905061074a565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103155781810151838201526020016102fd565b50505050905090810190601f1680156103425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103766004803603602081101561036657600080fd5b50356001600160a01b031661081e565b604080519384526020840192909252151582820152519081900360600190f35b6103b3600480360360208110156103ac57600080fd5b5035610841565b604080516001600160a01b039092168252519081900360200190f35b6103f5600480360360208110156103e557600080fd5b50356001600160a01b0316610868565b6040805192835260208301919091528051918290030190f35b6104166108bf565b60408051918252519081900360200190f35b6104306108c5565b6040805160ff9092168252519081900360200190f35b6103b36108ca565b6104566108d0565b6040805161ffff9092168252519081900360200190f35b6104306108d5565b6103b36108da565b6104166108e0565b6104ab6004803603602081101561049b57600080fd5b50356001600160a01b03166108e6565b005b610416610a47565b6103b3610a4d565b610430610a53565b6103b3610a58565b610416610a5e565b610430610a63565b6103f5610a68565b6104ab600480360360408110156104fb57600080fd5b60ff8235169190810190604081016020820135600160201b81111561051f57600080fd5b82018360208201111561053157600080fd5b803590602001918460018302840111600160201b8311171561055257600080fd5b509092509050610a72565b610430610bcc565b610416610bd1565b6103b3610bdc565b6103b3610be2565b610585610be8565b604080519115158252519081900360200190f35b61024a610bf1565b610416610bf6565b6104ab600480360360408110156105bf57600080fd5b810190602081018135600160201b8111156105d957600080fd5b8201836020820111156105eb57600080fd5b803590602001918460018302840111600160201b8311171561060c57600080fd5b919390929091602081019035600160201b81111561062957600080fd5b82018360208201111561063b57600080fd5b803590602001918460018302840111600160201b8311171561065c57600080fd5b509092509050610bfb565b610416610fe9565b6103b3610fee565b6104ab6004803603604081101561068d57600080fd5b60ff8235169190810190604081016020820135600160201b8111156106b157600080fd5b8201836020820111156106c357600080fd5b803590602001918460018302840111600160201b831117156106e457600080fd5b509092509050610ff4565b6104ab6004803603602081101561070557600080fd5b50356001600160a01b03166110a7565b6103b361154a565b6104ab611550565b6103b36115c1565b6104306115c7565b6104ab6115cc565b6103b3611a57565b606481565b6060336120001461078c5760405162461bcd60e51b815260040180806020018281038252602f8152602001806124ae602f913960400191505060405180910390fd5b60005460ff166107d1576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b6040805162461bcd60e51b815260206004820152601e60248201527f7265636569766520756e65787065637465642073796e207061636b6167650000604482015290519081900360640190fd5b600260208190526000918252604090912080546001820154919092015460ff1683565b6001818154811061084e57fe5b6000918252602090912001546001600160a01b0316905081565b600080610873612372565b5050506001600160a01b0316600090815260026020818152604092839020835160608101855281548082526001830154938201849052919093015460ff16151592909301919091529091565b60055481565b600181565b61100181565b606181565b600881565b61200081565b60045481565b33611000146109265760405162461bcd60e51b81526004018080602001828103825260308152602001806124096030913960400191505060405180910390fd5b60005460ff1661096b576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b61200063f7a251d7600b61097e84611a5d565b60006040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156109de5781810151838201526020016109c6565b50505050905090810190601f168015610a0b5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015610a2c57600080fd5b505af1158015610a40573d6000803e3d6000fd5b5050505050565b60035481565b61100581565b600281565b61100881565b603281565b600b81565b6004546005549091565b3361200014610ab25760405162461bcd60e51b815260040180806020018281038252602f8152602001806124ae602f913960400191505060405180910390fd5b60005460ff16610af7576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b610aff612395565b6000610b4084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b2f92505050565b915091508015610b8a5781516040805163ffffffff9092168252517f7f0956d47419b9525356e7111652b653b530ec6f5096dccc04589bc38e6299679181900360200190a1610a40565b81516040805163ffffffff9092168252517f7d45f62d17443dd4547bca8a8112c60e2385669318dc300ec61a5d2492f262e79181900360200190a15050505050565b600981565b662386f26fc1000081565b61100781565b61100681565b60005460ff1681565b600081565b600481565b60005460ff16610c40576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b3361100714610c805760405162461bcd60e51b815260040180806020018281038252602e815260200180612439602e913960400191505060405180910390fd5b610ceb84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260148152731b5a5cd9195b59585b9bdc951a1c995cda1bdb1960621b60208201529150611baf9050565b15610dc45760208114610d2f5760405162461bcd60e51b81526004018080602001828103825260278152602001806123e26027913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091610d6d91858580838501838280828437600092019190915250611c9792505050565b905060018110158015610d81575060055481105b610dbc5760405162461bcd60e51b81526004018080602001828103825260258152602001806124896025913960400191505060405180910390fd5b600455610f57565b610e2a84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600f81526e19995b1bdb9e551a1c995cda1bdb19608a1b60208201529150611baf9050565b15610f1a5760208114610e6e5760405162461bcd60e51b81526004018080602001828103825260228152602001806124676022913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091610eac91858580838501838280828437600092019190915250611c9792505050565b90506103e88111158015610ec1575060045481115b610f12576040805162461bcd60e51b815260206004820181905260248201527f7468652066656c6f6e795468726573686f6c64206f7574206f662072616e6765604482015290519081900360640190fd5b600555610f57565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b609681565b61100281565b33612000146110345760405162461bcd60e51b815260040180806020018281038252602f8152602001806124ae602f913960400191505060405180910390fd5b60005460ff16611079576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b6040517f07db600eebe2ac176be8dcebad61858c245a4961bb32ca2aa3d159b09aa0810e90600090a1505050565b3341146110e55760405162461bcd60e51b815260040180806020018281038252602d8152602001806124dd602d913960400191505060405180910390fd5b60005460ff1661112a576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b6003544311611180576040805162461bcd60e51b815260206004820181905260248201527f63616e206e6f7420736c61736820747769636520696e206f6e6520626c6f636b604482015290519081900360640190fd5b3a156111ca576040805162461bcd60e51b81526020600482015260146024820152736761737072696365206973206e6f74207a65726f60601b604482015290519081900360640190fd5b6040805163155853f360e21b81526001600160a01b03831660048201529051611000916355614fcc916024808301926020929190829003018186803b15801561121257600080fd5b505afa158015611226573d6000803e3d6000fd5b505050506040513d602081101561123c57600080fd5b505161124757611543565b61124f612372565b506001600160a01b0381166000908152600260208181526040928390208351606081018552815481526001820154928101929092529091015460ff1615801592820192909252906112aa576020810180516001019052611303565b60016040820181905260208201819052805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b0384161790555b43815260055460208201518161131557fe5b0661146757600060208201819052604080516335409f7f60e01b81526001600160a01b03851660048201529051611000926335409f7f926024808201939182900301818387803b15801561136857600080fd5b505af115801561137c573d6000803e3d6000fd5b505050506120006001600160a01b031663f7a251d7600b61139c85611a5d565b60006040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156113fc5781810151838201526020016113e4565b50505050905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561144a57600080fd5b505af115801561145e573d6000803e3d6000fd5b505050506114dd565b60045481602001518161147657fe5b066114dd57604080516375abf10160e11b81526001600160a01b038416600482015290516110009163eb57e20291602480830192600092919082900301818387803b1580156114c457600080fd5b505af11580156114d8573d6000803e3d6000fd5b505050505b6001600160a01b0382166000818152600260208181526040808420865181559186015160018301558581015191909201805460ff1916911515919091179055517fddb6012116e51abf5436d956a4f0ebd927e92c576ff96d7918290c8782291e3e9190a2505b5043600355565b61100381565b60005460ff16156115a8576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b603260045560966005556000805460ff19166001179055565b61100081565b600381565b336110001461160c5760405162461bcd60e51b81526004018080602001828103825260308152602001806124096030913960400191505060405180910390fd5b60005460ff16611651576040805162461bcd60e51b8152602060048201526019602482015260008051602061250a833981519152604482015290519081900360640190fd5b60015461165d57611a55565b600154600090600019015b808211611a29576000805b8284101561178c57611683612372565b600260006001878154811061169457fe5b60009182526020808320909101546001600160a01b0316835282810193909352604091820190208151606081018352815481526001820154938101939093526002015460ff1615159082015260055490915060049004816020015111156117765760046005548161170157fe5b0481602001510381602001818152505080600260006001888154811061172357fe5b6000918252602080832091909101546001600160a01b0316835282810193909352604091820190208351815591830151600183015591909101516002909101805460ff1916911515919091179055611780565b600192505061178c565b50600190930192611673565b8284116119235761179b612372565b60026000600186815481106117ac57fe5b60009182526020808320909101546001600160a01b0316835282810193909352604091820190208151606081018352815481526001820154938101939093526002015460ff1615159082015260055490915060049004816020015111156118945760046005548161181957fe5b0481602001510381602001818152505080600260006001878154811061183b57fe5b6000918252602080832091909101546001600160a01b03168352828101939093526040918201902083518155918301516001808401919091559201516002909101805460ff191691151591909117905591506119239050565b60026000600186815481106118a557fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120818155600181810192909255600201805460ff191690558054806118e957fe5b600082815260209020810160001990810180546001600160a01b0319169055019055836119165750611923565b506000199092019161178c565b81801561192d5750805b15611a0c57600260006001868154811061194357fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120818155600181810192909255600201805460ff1916905580548490811061198a57fe5b600091825260209091200154600180546001600160a01b0390921691869081106119b057fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060018054806119e957fe5b600082815260209020810160001990810180546001600160a01b03191690550190555b82611a18575050611a29565b505060019091019060001901611668565b6040517fcfdb3b6ccaeccbdc68be3c59c840e3b3c90f0a7c491f5fff1cf56cfda200dd9c90600090a150505b565b61100481565b60408051600480825260a08201909252606091829190816020015b6060815260200190600190039081611a78579050509050611aa1836001600160a01b0316611c9c565b81600081518110611aae57fe5b6020026020010181905250611ac243611cbf565b81600181518110611acf57fe5b6020908102919091010152611ae46061611cbf565b81600281518110611af157fe5b6020026020010181905250611b0542611cbf565b81600381518110611b1257fe5b6020026020010181905250611b2681611cd2565b9150505b919050565b611b37612395565b6000611b41612395565b611b496123a7565b611b5a611b5586611d5c565b611d81565b90506000805b611b6983611dcb565b15611ba25780611b9557611b84611b7f84611dec565b611e3a565b63ffffffff16845260019150611b9a565b611ba2565b600101611b60565b5091935090915050915091565b6000816040516020018082805190602001908083835b60208310611be45780518252601f199092019160209182019101611bc5565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b60208310611c525780518252601f199092019160209182019101611c33565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201490505b92915050565b015190565b60408051600560a21b8318601482015260348101909152606090611b2681611ef1565b6060611c91611ccd83611f47565b611ef1565b6060815160001415611cf35750604080516000815260208101909152611b2a565b606082600081518110611d0257fe5b602002602001015190506000600190505b8351811015611d4357611d3982858381518110611d2c57fe5b602002602001015161202d565b9150600101611d13565b50611b26611d56825160c060ff166120aa565b8261202d565b611d646123c7565b506040805180820190915281518152602082810190820152919050565b611d896123a7565b611d92826121a2565b611d9b57600080fd5b6000611daa83602001516121dc565b60208085015160408051808201909152868152920190820152915050919050565b6000611dd56123c7565b505080518051602091820151919092015191011190565b611df46123c7565b611dfd82611dcb565b611e0657600080fd5b60208201516000611e168261223f565b80830160209586015260408051808201909152908152938401919091525090919050565b805160009015801590611e4f57508151602110155b611e5857600080fd5b6000611e6783602001516121dc565b90508083600001511015611ec2576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b825160208085015183018051928490039291831015611ee857826020036101000a820491505b50949350505050565b606081516001148015611f235750607f60f81b82600081518110611f1157fe5b01602001516001600160f81b03191611155b15611f2f575080611b2a565b611c91611f418351608060ff166120aa565b8361202d565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff198416611f8b57506018611faf565b6fffffffffffffffffffffffffffffffff198416611fab57506010611faf565b5060005b6020811015611fe557818181518110611fc457fe5b01602001516001600160f81b03191615611fdd57611fe5565b600101611faf565b60008160200390506060816040519080825280601f01601f19166020018201604052801561201a576020820181803683370190505b5080830196909652508452509192915050565b6060806040519050835180825260208201818101602087015b8183101561205e578051835260209283019201612046565b50855184518101855292509050808201602086015b8183101561208b578051835260209283019201612073565b508651929092011591909101601f01601f191660405250905092915050565b60606801000000000000000083106120fa576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116121545782840160f81b8160008151811061213657fe5b60200101906001600160f81b031916908160001a9053509050611c91565b606061215f85611f47565b90508381510160370160f81b8260008151811061217857fe5b60200101906001600160f81b031916908160001a905350612199828261202d565b95945050505050565b80516000906121b357506000611b2a565b6020820151805160001a9060c08210156121d257600092505050611b2a565b5060019392505050565b8051600090811a60808110156121f6576000915050611b2a565b60b8811080612211575060c08110801590612211575060f881105b15612220576001915050611b2a565b60c08110156122345760b519019050611b2a565b60f519019050611b2a565b80516000908190811a608081101561225a576001915061236b565b60b881101561226f57607e198101915061236b565b60c08110156122e957600060b78203600186019550806020036101000a8651049150600181018201935050808310156122e3576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b5061236b565b60f88110156122fe5760be198101915061236b565b600060f78203600186019550806020036101000a865104915060018101820193505080831015612369576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b604051806060016040528060008152602001600081526020016000151581525090565b60408051602081019091526000815290565b60405180604001604052806123ba6123c7565b8152602001600081525090565b60405180604001604052806000815260200160008152509056fe6c656e677468206f66206d697364656d65616e6f725468726573686f6c64206d69736d61746368746865206d6573736167652073656e646572206d7573742062652076616c696461746f7253657420636f6e7472616374746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e74726163746c656e677468206f662066656c6f6e795468726573686f6c64206d69736d61746368746865206d697364656d65616e6f725468726573686f6c64206f7574206f662072616e6765746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f647563657274686520636f6e7472616374206e6f7420696e69742079657400000000000000a2646970667358221220a288eb0fb37b1f80ed70929944f149856fbe848d775f3fe9d6a2f46faa67754564736f6c63430006040033", + }, + }, + } + + eulerUpgrade[rialtoNet] = &Upgrade{ + UpgradeName: "euler", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(ValidatorContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/db8bb560ac5a1265c685b719c7e976dced162310", + Code: "6080604052600436106104055760003560e01c80638d19a41011610213578063c81b166211610123578063eb57e202116100ab578063f9a2bbc71161007a578063f9a2bbc714610d55578063fc3e590814610d6a578063fccc281314610d7f578063fd4ad81f14610d94578063fd6a687914610dd757610405565b8063eb57e20214610cd2578063eda5868c14610d05578063f340fa0114610d1a578063f92eb86b14610d4057610405565b8063daacdb66116100f2578063daacdb6614610c69578063dc927faf14610c7e578063e086c7b114610c93578063e1c7392a14610ca8578063e40716a114610cbd57610405565b8063c81b166214610c2a578063c8509d8114610939578063d68fb56a14610c3f578063d86222d514610c5457610405565b8063a78abc16116101a6578063ad3c9da611610175578063ad3c9da614610bb8578063b7ab4db514610beb578063b8cf4ef114610c00578063bf9f49951461065f578063c6d3394514610c1557610405565b8063a78abc1614610aae578063aaf5eb6814610ac3578063ab51bb9614610ad8578063ac43175114610aed57610405565b80639fe0f816116101e25780639fe0f81614610a5a578063a0dc275814610a6f578063a1a11bf514610a84578063a5422d5c14610a9957610405565b80638d19a410146109e85780639369d7de14610a1b57806396713da914610a305780639dc0926214610a4557610405565b80635192c82c1161031957806375d47a0a116102a157806381650b621161027057806381650b6214610924578063831d65d114610939578063853230aa146108e557806386249882146109be5780638b5ad0c9146109d357610405565b806375d47a0a146108d057806378dfed4a146108e55780637942fd05146108fa5780637a84ca2a1461090f57610405565b80635667515a116102e85780635667515a146108065780635d77156c1461081b5780636969a25c146108305780636e47b482146108a657806370fd5bad146108bb57610405565b80635192c82c1461077657806351e806721461078b57806355614fcc146107a0578063565c56b3146107d357610405565b80633365af3a1161039c57806343756e5c1161036b57806343756e5c1461068a57806345cf9daf146106bb578063493279b1146106d05780634bf6c882146106fc5780634df6e0c31461071157610405565b80633365af3a146105ed57806335409f7f146106175780633de0f0d81461064a5780633dffc3871461065f57610405565b8063152ad3b8116103d8578063152ad3b8146105705780631ff1806914610599578063219f22d5146105ae578063321d398a146105c357610405565b806304c4fec61461040a57806307a56847146104215780630bee7a67146104485780631182b87514610476575b600080fd5b34801561041657600080fd5b5061041f610dec565b005b34801561042d57600080fd5b50610436610e7f565b60408051918252519081900360200190f35b34801561045457600080fd5b5061045d610e85565b6040805163ffffffff9092168252519081900360200190f35b34801561048257600080fd5b506104fb6004803603604081101561049957600080fd5b60ff8235169190810190604081016020820135600160201b8111156104bd57600080fd5b8201836020820111156104cf57600080fd5b803590602001918460018302840111600160201b831117156104f057600080fd5b509092509050610e8a565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561053557818101518382015260200161051d565b50505050905090810190601f1680156105625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561057c57600080fd5b5061058561111c565b604080519115158252519081900360200190f35b3480156105a557600080fd5b50610436611125565b3480156105ba57600080fd5b5061045d61112b565b3480156105cf57600080fd5b50610585600480360360208110156105e657600080fd5b5035611130565b3480156105f957600080fd5b506105856004803603602081101561061057600080fd5b50356111ff565b34801561062357600080fd5b5061041f6004803603602081101561063a57600080fd5b50356001600160a01b03166112b0565b34801561065657600080fd5b5061043661140f565b34801561066b57600080fd5b50610674611415565b6040805160ff9092168252519081900360200190f35b34801561069657600080fd5b5061069f61141a565b604080516001600160a01b039092168252519081900360200190f35b3480156106c757600080fd5b50610436611420565b3480156106dc57600080fd5b506106e5611426565b6040805161ffff9092168252519081900360200190f35b34801561070857600080fd5b5061067461142c565b34801561071d57600080fd5b50610726611431565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561076257818101518382015260200161074a565b505050509050019250505060405180910390f35b34801561078257600080fd5b5061043661152c565b34801561079757600080fd5b5061069f611532565b3480156107ac57600080fd5b50610585600480360360208110156107c357600080fd5b50356001600160a01b0316611538565b3480156107df57600080fd5b50610436600480360360208110156107f657600080fd5b50356001600160a01b031661156d565b34801561081257600080fd5b506106746115be565b34801561082757600080fd5b5061045d6115c3565b34801561083c57600080fd5b5061085a6004803603602081101561085357600080fd5b50356115c8565b604080516001600160a01b039788168152958716602087015293909516848401526001600160401b0390911660608401521515608083015260a082019290925290519081900360c00190f35b3480156108b257600080fd5b5061069f61162c565b3480156108c757600080fd5b50610674611632565b3480156108dc57600080fd5b5061069f611637565b3480156108f157600080fd5b5061043661163d565b34801561090657600080fd5b50610674611643565b34801561091b57600080fd5b50610436611648565b34801561093057600080fd5b5061045d61164e565b34801561094557600080fd5b5061041f6004803603604081101561095c57600080fd5b60ff8235169190810190604081016020820135600160201b81111561098057600080fd5b82018360208201111561099257600080fd5b803590602001918460018302840111600160201b831117156109b357600080fd5b509092509050611653565b3480156109ca57600080fd5b50610436611706565b3480156109df57600080fd5b5061043661170c565b3480156109f457600080fd5b5061043660048036036020811015610a0b57600080fd5b50356001600160a01b0316611712565b348015610a2757600080fd5b5061041f611787565b348015610a3c57600080fd5b506106746118a1565b348015610a5157600080fd5b5061069f6118a6565b348015610a6657600080fd5b506104366118ac565b348015610a7b57600080fd5b506104366118b1565b348015610a9057600080fd5b5061069f6118b6565b348015610aa557600080fd5b506104fb6118bc565b348015610aba57600080fd5b506105856118db565b348015610acf57600080fd5b506104366118e4565b348015610ae457600080fd5b5061045d6115be565b348015610af957600080fd5b5061041f60048036036040811015610b1057600080fd5b810190602081018135600160201b811115610b2a57600080fd5b820183602082011115610b3c57600080fd5b803590602001918460018302840111600160201b83111715610b5d57600080fd5b919390929091602081019035600160201b811115610b7a57600080fd5b820183602082011115610b8c57600080fd5b803590602001918460018302840111600160201b83111715610bad57600080fd5b5090925090506118ed565b348015610bc457600080fd5b5061043660048036036020811015610bdb57600080fd5b50356001600160a01b031661232a565b348015610bf757600080fd5b5061072661233c565b348015610c0c57600080fd5b5061043661241f565b348015610c2157600080fd5b50610436611632565b348015610c3657600080fd5b5061069f612424565b348015610c4b57600080fd5b5061043661242a565b348015610c6057600080fd5b50610436612469565b348015610c7557600080fd5b50610436612475565b348015610c8a57600080fd5b5061069f61247b565b348015610c9f57600080fd5b50610436612481565b348015610cb457600080fd5b5061041f612486565b348015610cc957600080fd5b50610436612689565b348015610cde57600080fd5b5061041f60048036036020811015610cf557600080fd5b50356001600160a01b031661268f565b348015610d1157600080fd5b5061045d61279d565b61041f60048036036020811015610d3057600080fd5b50356001600160a01b03166127a2565b348015610d4c57600080fd5b50610436612aa7565b348015610d6157600080fd5b5061069f612aad565b348015610d7657600080fd5b506106746118ac565b348015610d8b57600080fd5b5061069f612ab3565b348015610da057600080fd5b50610dbe60048036036020811015610db757600080fd5b5035612ab9565b6040805192835290151560208301528051918290030190f35b348015610de357600080fd5b5061069f612ae7565b6000610df733611712565b9050600b8181548110610e0657fe5b600091825260209091206001601690920201015460ff16610e63576040805162461bcd60e51b81526020600482015260126024820152716e6f7420696e206d61696e74656e616e636560701b604482015290519081900360640190fd5b6000610e6d61242a565b9050610e7a338383612aed565b505050565b60095481565b606481565b60005460609060ff16610ee0576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b3361200014610f205760405162461bcd60e51b815260040180806020018281038252602f815260200180616048602f913960400191505060405180910390fd5b600b54610fc557610f2f6159e1565b60015460005b81811015610fc157600b80546001810182556000919091528351600080516020615fc1833981519152601690920291820190815560208501516000805160206160d18339815191528301805460ff191691151591909117905560408501518592610fb391600080516020616007833981519152909101906014615a05565b505050806001019050610f35565b5050505b610fcd615a3f565b600061100e85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612ce192505050565b915091508061102a576110216064612e3a565b92505050611115565b815160009060ff1661104a576110438360200151612e9b565b90506110e1565b825160ff16600114156110dd578260200151516001146110b7577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2604051808060200182810382526025815260200180615f076025913960400191505060405180910390a15060676110d8565b61104383602001516000815181106110cb57fe5b6020026020010151613cab565b6110e1565b5060655b63ffffffff811661110657505060408051600081526020810190915291506111159050565b61110f81612e3a565b93505050505b9392505050565b60075460ff1681565b60035481565b606881565b6001546000908210611144575060006111fa565b60006001600160a01b03166001838154811061115c57fe5b60009182526020909120600490910201546001600160a01b0316148061118c5750600854158061118c5750600a54155b8061119b575060085460095410155b806111ac57506111aa826111ff565b155b806111d557506000600b83815481106111c157fe5b906000526020600020906016020160000154115b806111e9575060016111e561233c565b5111155b156111f6575060006111fa565b5060015b919050565b6001546000908210611213575060006111fa565b600b548210611250576001828154811061122957fe5b9060005260206000209060040201600201601c9054906101000a900460ff161590506111fa565b6001828154811061125d57fe5b9060005260206000209060040201600201601c9054906101000a900460ff161580156112aa5750600b828154811061129157fe5b600091825260209091206001601690920201015460ff16155b92915050565b33611001146112f05760405162461bcd60e51b81526004018080602001828103825260298152602001806160f16029913960400191505060405180910390fd5b600b54611395576112ff6159e1565b60015460005b8181101561139157600b80546001810182556000919091528351600080516020615fc1833981519152601690920291820190815560208501516000805160206160d18339815191528301805460ff19169115159190911790556040850151859261138391600080516020616007833981519152909101906014615a05565b505050806001019050611305565b5050505b6001600160a01b038116600090815260046020526040902054806113b9575061140c565b6001810390506000600b82815481106113ce57fe5b600091825260209091206001601690920201015460ff1690506113f18383613e22565b80156113fa5750805b15610e7a576009805460001901905550505b50565b61271081565b600181565b61100181565b60085481565b6102ca81565b600881565b600e54600c546060919080611444575060155b606061144e61233c565b905081815111611462579250611529915050565b82828251031015611474578181510392505b82156114a85760c8430461148f82828686036000888861419e565b6114a682828686038787038889898951030161419e565b505b6060826040519080825280602002602001820160405280156114d4578160200160208202803683370190505b50905060005b83811015611522578281815181106114ee57fe5b602002602001015182828151811061150257fe5b6001600160a01b03909216602092830291909101909101526001016114da565b5093505050505b90565b60065481565b61200081565b6001600160a01b038116600090815260046020526040812054806115605760009150506111fa565b60001901611115816111ff565b6001600160a01b038116600090815260046020526040812054806115955760009150506111fa565b6001808203815481106115a457fe5b906000526020600020906004020160030154915050919050565b600081565b606781565b600181815481106115d557fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509082169291821691600160a01b81046001600160401b031691600160e01b90910460ff169086565b61100581565b600281565b61100881565b6103e881565b600b81565b600c5481565b606681565b33612000146116935760405162461bcd60e51b815260040180806020018281038252602f815260200180616048602f913960400191505060405180910390fd5b7f41ce201247b6ceb957dcdb217d0b8acb50b9ea0e12af9af4f5e7f38902101605838383604051808460ff1660ff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b60025481565b600a5481565b6001600160a01b0381166000908152600460205260408120548061177d576040805162461bcd60e51b815260206004820152601760248201527f6f6e6c792063757272656e742076616c696461746f7273000000000000000000604482015290519081900360640190fd5b6000190192915050565b600b5461182c576117966159e1565b60015460005b8181101561182857600b80546001810182556000919091528351600080516020615fc1833981519152601690920291820190815560208501516000805160206160d18339815191528301805460ff19169115159190911790556040850151859261181a91600080516020616007833981519152909101906014615a05565b50505080600101905061179c565b5050505b6008546118395760036008555b600a54611846576002600a555b600061185133611712565b905061185c81611130565b6118975760405162461bcd60e51b8152600401808060200182810382526023815260200180615ee46023913960400191505060405180910390fd5b61140c338261428d565b600981565b61100781565b600381565b60c881565b61100681565b604051806101e001604052806101ab8152602001615b3a6101ab913981565b60005460ff1681565b6402540be40081565b60005460ff16611940576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b33611007146119805760405162461bcd60e51b815260040180806020018281038252602e815260200180615f4d602e913960400191505060405180910390fd5b6119ea84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526013815272065787069726554696d655365636f6e6447617606c1b602082015291506143259050565b15611ac55760208114611a2e5760405162461bcd60e51b8152600401808060200182810382526026815260200180615fe16026913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611a6c9185858083850183828082843760009201919091525061440c92505050565b905060648110158015611a825750620186a08111155b611abd5760405162461bcd60e51b8152600401808060200182810382526027815260200180615e746027913960400191505060405180910390fd5b600255612298565b611b2584848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260098152686275726e526174696f60b81b602082015291506143259050565b15611c155760208114611b7f576040805162461bcd60e51b815260206004820152601c60248201527f6c656e677468206f66206275726e526174696f206d69736d6174636800000000604482015290519081900360640190fd5b604080516020601f8401819004810282018101909252828152600091611bbd9185858083850183828082843760009201919091525061440c92505050565b9050612710811115611c005760405162461bcd60e51b815260040180806020018281038252602b815260200180615e1e602b913960400191505060405180910390fd5b6006556007805460ff19166001179055612298565b611c7f84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260138152726d61784e756d4f664d61696e7461696e696e6760681b602082015291506143259050565b15611d575760208114611cc35760405162461bcd60e51b8152600401808060200182810382526026815260200180615ce56026913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611d019185858083850183828082843760009201919091525061440c92505050565b600c5490915080611d10575060155b808210611d4e5760405162461bcd60e51b8152600401808060200182810382526038815260200180615d5c6038913960400191505060405180910390fd5b50600855612298565b611dc084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61696e7461696e536c6173685363616c6560701b602082015291506143259050565b15611e8b5760208114611e045760405162461bcd60e51b8152600401808060200182810382526025815260200180615d376025913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611e429185858083850183828082843760009201919091525061440c92505050565b905060008111611e835760405162461bcd60e51b815260040180806020018281038252602d8152602001806160a4602d913960400191505060405180910390fd5b600a55612298565b611eff84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601981527f6d61784e756d4f66576f726b696e6743616e6469646174657300000000000000602082015291506143259050565b15611fcc5760208114611f435760405162461bcd60e51b815260040180806020018281038252602c815260200180615d0b602c913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091611f819185858083850183828082843760009201919091525061440c92505050565b9050600d54811115611fc45760405162461bcd60e51b8152600401808060200182810382526049815260200180615e9b6049913960600191505060405180910390fd5b600e55612298565b61203584848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61784e756d4f6643616e6469646174657360701b602082015291506143259050565b156120d657602081146120795760405162461bcd60e51b8152600401808060200182810382526025815260200180615f7b6025913960400191505060405180910390fd5b604080516020601f84018190048102820181019092528281526000916120b79185858083850183828082843760009201919091525061440c92505050565b600d819055600e549091508110156120d057600d54600e555b50612298565b61213a84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600d81526c6e756d4f66436162696e65747360981b602082015291506143259050565b1561225b5760208114612194576040805162461bcd60e51b815260206004820181905260248201527f6c656e677468206f66206e756d4f66436162696e657473206d69736d61746368604482015290519081900360640190fd5b604080516020601f84018190048102820181019092528281526000916121d29185858083850183828082843760009201919091525061440c92505050565b9050600081116122135760405162461bcd60e51b8152600401808060200182810382526028815260200180615d946028913960400191505060405180910390fd5b60298111156122535760405162461bcd60e51b8152600401808060200182810382526039815260200180615dbc6039913960400191505060405180910390fd5b600c55612298565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b60046020526000908152604090205481565b6001546060906000805b8281101561236b57612357816111ff565b15612363576001909101905b600101612346565b50606081604051908082528060200260200182016040528015612398578160200160208202803683370190505b5090506000915060005b83811015612417576123b3816111ff565b1561240f57600181815481106123c557fe5b600091825260209091206004909102015482516001600160a01b03909116908390859081106123f057fe5b6001600160a01b03909216602092830291909101909101526001909201915b6001016123a2565b509250505090565b601581565b61100281565b600061243461233c565b519050600080600c541161244957601561244d565b600c545b90508082111561245b578091505b8161246557600191505b5090565b67016345785d8a000081565b60055481565b61100381565b602981565b60005460ff16156124de576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b6124e6615a3f565b600061250c604051806101e001604052806101ab8152602001615b3a6101ab9139612ce1565b915091508061254c5760405162461bcd60e51b81526004018080602001828103825260218152602001806160276021913960400191505060405180910390fd5b60005b8260200151518110156126715760018360200151828151811061256e57fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782558587015182850180549185169183169190911790556040860151600283018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590981692909516919091179290921694909417161790915560a09093015160039093019290925591860151805191850193918590811061264457fe5b602090810291909101810151516001600160a01b031682528101919091526040016000205560010161254f565b50506103e8600255506000805460ff19166001179055565b600d5481565b33611001146126cf5760405162461bcd60e51b81526004018080602001828103825260298152602001806160f16029913960400191505060405180910390fd5b600b54612774576126de6159e1565b60015460005b8181101561277057600b80546001810182556000919091528351600080516020615fc1833981519152601690920291820190815560208501516000805160206160d18339815191528301805460ff19169115159190911790556040850151859261276291600080516020616007833981519152909101906014615a05565b5050508060010190506126e4565b5050505b600061277f82614411565b905061278a81611130565b1561279957612799828261428d565b5050565b606581565b3341146127e05760405162461bcd60e51b815260040180806020018281038252602d815260200180616077602d913960400191505060405180910390fd5b60005460ff16612833576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b60003411612880576040805162461bcd60e51b81526020600482015260156024820152746465706f7369742076616c7565206973207a65726f60581b604482015290519081900360640190fd5b6001600160a01b0381166000908152600460205260409020546007543491906103e89060ff16156128b057506006545b6000831180156128c05750600081115b156129695760006128e96127106128dd868563ffffffff6145b516565b9063ffffffff61460e16565b905080156129675760405161dead9082156108fc029083906000818181858888f19350505050158015612920573d6000803e3d6000fd5b506040805182815290517f627059660ea01c4733a328effb2294d2f86905bf806da763a89cee254de8bee59181900360200190a1612964848263ffffffff61465016565b93505b505b8115612a6157600060018084038154811061298057fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff16156129eb576040805185815290516001600160a01b038716917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a2612a5b565b6003546129fe908563ffffffff61469216565b6003908155810154612a16908563ffffffff61469216565b60038201556040805185815290516001600160a01b038716917f93a090ecc682c002995fad3c85b30c5651d7fd29b0be5da9d784a3302aedc055919081900360200190a25b50612aa1565b6040805184815290516001600160a01b038616917ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4919081900360200190a25b50505050565b600e5481565b61100081565b61dead81565b600b8181548110612ac657fe5b60009182526020909120601690910201805460019091015490915060ff1682565b61100481565b6000600a5460001480612afe575081155b80612b095750600954155b15612b1657506000611115565b600960008154809291906001900391905055506000612b63600a546128dd856128dd600b8981548110612b4557fe5b6000918252602090912060169091020154439063ffffffff61465016565b90506000600b8581548110612b7457fe5b906000526020600020906016020160010160006101000a81548160ff0219169083151502179055506000806110016001600160a01b0316638256ace66040518163ffffffff1660e01b8152600401604080518083038186803b158015612bd957600080fd5b505afa158015612bed573d6000803e3d6000fd5b505050506040513d6040811015612c0357600080fd5b508051602090910151600095509092509050808310612c9157612c268787613e22565b50604080516305bfb49960e41b81526001600160a01b0389166004820152905161100191635bfb499091602480830192600092919082900301818387803b158015612c7057600080fd5b505af1158015612c84573d6000803e3d6000fd5b5050505060019350612ca3565b818310612ca357612ca187614411565b505b6040516001600160a01b038816907fb9d38178dc641ff1817967a63c9078cbcd955a9f1fcd75e0e3636de615d44d3b90600090a25050509392505050565b612ce9615a3f565b6000612cf3615a3f565b612cfb615a57565b612d0c612d07866146ec565b614711565b90506000805b612d1b8361475b565b15612e2c5780612d4057612d36612d318461477c565b6147ca565b60ff168452612e24565b8060011415612e1f576060612d5c612d578561477c565b614881565b90508051604051908082528060200260200182016040528015612d9957816020015b612d86615a77565b815260200190600190039081612d7e5790505b50602086015260005b8151811015612e1457612db3615a77565b6000612dd1848481518110612dc457fe5b6020026020010151614952565b9150915080612dee57876000995099505050505050505050612e35565b8188602001518481518110612dff57fe5b60209081029190910101525050600101612da2565b506001925050612e24565b612e2c565b600101612d12565b50919350909150505b915091565b604080516001808252818301909252606091829190816020015b6060815260200190600190039081612e54579050509050612e7a8363ffffffff16614a2f565b81600081518110612e8757fe5b602002602001018190525061111581614a42565b6000806060612ea984614acc565b9150915081612f56577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2816040518080602001828103825283818151815260200191508051906020019080838360005b83811015612f11578181015183820152602001612ef9565b50505050905090810190601f168015612f3e5780820380516001836020036101000a031916815260200191505b509250505060405180910390a16066925050506111fa565b50506060612f6383614bae565b6001549091506000908190815b81811015612fe65767016345785d8a000060018281548110612f8e57fe5b90600052602060002090600402016003015410612fb057600190930192612fde565b600060018281548110612fbf57fe5b9060005260206000209060040201600301541115612fde576001909201915b600101612f70565b50606083604051908082528060200260200182016040528015613013578160200160208202803683370190505b509050606084604051908082528060200260200182016040528015613042578160200160208202803683370190505b509050606085604051908082528060200260200182016040528015613071578160200160208202803683370190505b5090506060866040519080825280602002602001820160405280156130a0578160200160208202803683370190505b50905060006060876040519080825280602002602001820160405280156130d1578160200160208202803683370190505b509050606088604051908082528060200260200182016040528015613100578160200160208202803683370190505b509050600099506000985060006110046001600160a01b031663149d14d96040518163ffffffff1660e01b815260040160206040518083038186803b15801561314857600080fd5b505afa15801561315c573d6000803e3d6000fd5b505050506040513d602081101561317257600080fd5b5051905067016345785d8a00008111156131e6577f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2604051808060200182810382526021815260200180615fa06021913960400191505060405180910390a160689c505050505050505050505050506111fa565b60005b898110156134575767016345785d8a00006001828154811061320757fe5b9060005260206000209060040201600301541061338d576001818154811061322b57fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316898d8151811061325c57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006402540be4006001838154811061329157fe5b906000526020600020906004020160030154816132aa57fe5b06600183815481106132b857fe5b9060005260206000209060040201600301540390506132e0838261465090919063ffffffff16565b898e815181106132ec57fe5b6020026020010181815250506001828154811061330557fe5b906000526020600020906004020160020160009054906101000a90046001600160a01b0316878e8151811061333657fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081888e8151811061336357fe5b602090810291909101015261337e868263ffffffff61469216565b6001909d019c955061344f9050565b60006001828154811061339c57fe5b906000526020600020906004020160030154111561344f57600181815481106133c157fe5b906000526020600020906004020160010160009054906101000a90046001600160a01b0316848c815181106133f257fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001818154811061341f57fe5b906000526020600020906004020160030154838c8151811061343d57fe5b60209081029190910101526001909a01995b6001016131e9565b5060008415613895576110046001600160a01b0316636e056520868b8b8a60025442016040518663ffffffff1660e01b815260040180806020018060200180602001856001600160401b03166001600160401b03168152602001848103845288818151815260200191508051906020019060200280838360005b838110156134e95781810151838201526020016134d1565b50505050905001848103835287818151815260200191508051906020019060200280838360005b83811015613528578181015183820152602001613510565b50505050905001848103825286818151815260200191508051906020019060200280838360005b8381101561356757818101518382015260200161354f565b505050509050019750505050505050506020604051808303818588803b15801561359057600080fd5b505af1935050505080156135b657506040513d60208110156135b157600080fd5b505160015b6137f1576040516000815260443d10156135d25750600061366d565b60046000803e60005160e01c6308c379a081146135f357600091505061366d565b60043d036004833e81513d60248201116001600160401b038211171561361e5760009250505061366d565b80830180516001600160401b0381111561363f57600094505050505061366d565b8060208301013d860181111561365d5760009550505050505061366d565b601f01601f191660405250925050505b80613678575061371c565b60019150857fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280826040518080602001828103825283818151815260200191508051906020019080838360005b838110156136dc5781810151838201526020016136c4565b50505050905090810190601f1680156137095780820380516001836020036101000a031916815260200191505b509250505060405180910390a2506137ec565b3d808015613746576040519150601f19603f3d011682016040523d82523d6000602084013e61374b565b606091505b5060019150857fbfa884552dd8921b6ce90bfe906952ae5b3b29be0cc1a951d4f62697635a3a45826040518080602001828103825283818151815260200191508051906020019080838360005b838110156137b0578181015183820152602001613798565b50505050905090810190601f1680156137dd5780820380516001836020036101000a031916815260200191505b509250505060405180910390a2505b613895565b801561382f576040805187815290517fa217d08e65f80c73121cd9db834d81652d544bfbf452f6d04922b16c90a37b709181900360200190a1613893565b604080516020808252601b908201527f6261746368207472616e736665722072657475726e2066616c7365000000000081830152905187917fa7cdeed7d0db45e3219a6e5d60838824c16f1d39991fcfe3f963029c844bf280919081900360600190a25b505b8015613a4b5760005b8751811015613a495760008882815181106138b557fe5b602002602001015190506000600182815481106138ce57fe5b60009182526020909120600160049092020181015481546001600160a01b03909116916108fc91859081106138ff57fe5b9060005260206000209060040201600301549081150290604051600060405180830381858888f19350505050905080156139bb576001828154811061394057fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d918590811061398f57fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a2613a3f565b600182815481106139c857fe5b60009182526020909120600160049092020181015481546001600160a01b03909116917f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d9185908110613a1757fe5b9060005260206000209060040201600301546040518082815260200191505060405180910390a25b505060010161389e565b505b835115613b955760005b8451811015613b93576000858281518110613a6c57fe5b60200260200101516001600160a01b03166108fc868481518110613a8c57fe5b60200260200101519081150290604051600060405180830381858888f1935050505090508015613b2257858281518110613ac257fe5b60200260200101516001600160a01b03167f6c61d60f69a7beb3e1c80db7f39f37b208537cbb19da3174511b477812b2fc7d868481518110613b0057fe5b60200260200101516040518082815260200191505060405180910390a2613b8a565b858281518110613b2e57fe5b60200260200101516001600160a01b03167f25d0ce7d2f0cec669a8c17efe49d195c13455bb8872b65fa610ac7f53fe4ca7d868481518110613b6c57fe5b60200260200101516040518082815260200191505060405180910390a25b50600101613a55565b505b4715613bfe576040805147815290517f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d9181900360200190a1604051611002904780156108fc02916000818181858888f19350505050158015613bfc573d6000803e3d6000fd5b505b600060038190556005558c5115613c1857613c188d614d7e565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613c5557600080fd5b505af1158015613c69573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a15060009e9d5050505050505050505050505050565b80516001600160a01b0316600090815260046020526040812054801580613cfc5750600180820381548110613cdc57fe5b9060005260206000209060040201600201601c9054906101000a900460ff165b15613d425782516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a260009150506111fa565b600154600554600019820111801590613d985784516040516001600160a01b03909116907fe209c46bebf57cf265d5d9009a00870e256d9150f3ed5281ab9d9eb3cec6e4be90600090a2600093505050506111fa565b600580546001908101909155805481906000198601908110613db657fe5b6000918252602082206002600490920201018054921515600160e01b0260ff60e01b199093169290921790915585516040516001600160a01b03909116917ff226e7d8f547ff903d9d419cf5f54e0d7d07efa9584135a53a057c5f1f27f49a91a2506000949350505050565b60008060018381548110613e3257fe5b90600052602060002090600402016003015490506000600180805490500390506001613e5c61233c565b5111613e9157600060018581548110613e7157fe5b9060005260206000209060040201600301819055506000925050506112aa565b6040805183815290516001600160a01b038716917f3b6f9ef90462b512a1293ecec018670bf7b7f1876fb727590a8a6d7643130a70919081900360200190a26001600160a01b038516600090815260046020526040812055835b6001546000190181101561408e5760018160010181548110613f0957fe5b906000526020600020906004020160018281548110613f2457fe5b60009182526020909120825460049092020180546001600160a01b03199081166001600160a01b0393841617825560018085015481840180548416918616919091179055600280860180549185018054909416919095161780835584546001600160401b03600160a01b91829004160267ffffffffffffffff60a01b1990911617808355935460ff600160e01b918290041615150260ff60e01b19909416939093179055600392830154920191909155600b805490918301908110613fe557fe5b9060005260206000209060160201600b828154811061400057fe5b600091825260209091208254601690920201908155600180830154908201805460ff191660ff909216151591909117905561404360028083019084016014615aac565b5090505080600101600460006001848154811061405c57fe5b600091825260208083206004909202909101546001600160a01b03168352820192909252604001902055600101613eeb565b50600180548061409a57fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b8054806140ed57fe5b60008281526020812060166000199093019283020181815560018101805460ff191690559061411f6002830182615ad7565b50509055600081838161412e57fe5b04905080156141925760015460005b8181101561418f57826001828154811061415357fe5b906000526020600020906004020160030154016001828154811061417357fe5b600091825260209091206003600490920201015560010161413d565b50505b50600195945050505050565b60005b828110156142845760408051602080820189905287840182840152825180830384018152606090920190925280519101206000908390816141de57fe5b0690508085018287011461427b57600088838801815181106141fc57fe5b60200260200101519050888287018151811061421457fe5b6020026020010151898489018151811061422a57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505080898388018151811061425957fe5b60200260200101906001600160a01b031690816001600160a01b031681525050505b506001016141a1565b50505050505050565b600980546001908101909155600b8054839081106142a757fe5b906000526020600020906016020160010160006101000a81548160ff02191690831515021790555043600b82815481106142dd57fe5b600091825260208220601690910201919091556040516001600160a01b038416917ff62981a567ec3cec866c6fa93c55bcdf841d6292d18b8d522ececa769375d82d91a25050565b6000816040516020018082805190602001908083835b6020831061435a5780518252601f19909201916020918201910161433b565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b602083106143c85780518252601f1990920191602091820191016143a9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012014905092915050565b015190565b6001600160a01b0381166000908152600460205260408120548061443a575060001990506111fa565b60018103905060006001828154811061444f57fe5b906000526020600020906004020160030154905060006001838154811061447257fe5b906000526020600020906004020160030181905550600060018080549050039050846001600160a01b03167f8cd4e147d8af98a9e3b6724021b8bf6aed2e5dac71c38f2dce8161b82585b25d836040518082815260200191505060405180910390a2806144e4578293505050506111fa565b60008183816144ef57fe5b04905080156145ab5760005b8481101561454d57816001828154811061451157fe5b906000526020600020906004020160030154016001828154811061453157fe5b60009182526020909120600360049092020101556001016144fb565b50600180549085015b818110156145a857826001828154811061456c57fe5b906000526020600020906004020160030154016001828154811061458c57fe5b6000918252602090912060036004909202010155600101614556565b50505b5091949350505050565b6000826145c4575060006112aa565b828202828482816145d157fe5b04146111155760405162461bcd60e51b8152600401808060200182810382526021815260200180615f2c6021913960400191505060405180910390fd5b600061111583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250615371565b600061111583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250615413565b600082820183811015611115576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6146f4615ae6565b506040805180820190915281518152602082810190820152919050565b614719615a57565b6147228261546d565b61472b57600080fd5b600061473a83602001516154a7565b60208085015160408051808201909152868152920190820152915050919050565b6000614765615ae6565b505080518051602091820151919092015191011190565b614784615ae6565b61478d8261475b565b61479657600080fd5b602082015160006147a68261550a565b80830160209586015260408051808201909152908152938401919091525090919050565b8051600090158015906147df57508151602110155b6147e857600080fd5b60006147f783602001516154a7565b90508083600001511015614852576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b82516020808501518301805192849003929183101561487857826020036101000a820491505b50949350505050565b606061488c8261546d565b61489557600080fd5b60006148a08361563d565b90506060816040519080825280602002602001820160405280156148de57816020015b6148cb615ae6565b8152602001906001900390816148c35790505b50905060006148f085602001516154a7565b60208601510190506000805b848110156149475761490d8361550a565b915060405180604001604052808381526020018481525084828151811061493057fe5b6020908102919091010152918101916001016148fc565b509195945050505050565b61495a615a77565b6000614964615a77565b61496c615a57565b61497585614711565b90506000805b6149848361475b565b15612e2c57806149af5761499f61499a8461477c565b615699565b6001600160a01b03168452614a27565b80600114156149d7576149c461499a8461477c565b6001600160a01b03166020850152614a27565b80600214156149ff576149ec61499a8461477c565b6001600160a01b03166040850152614a27565b8060031415612e1f57614a14612d318461477c565b6001600160401b03166060850152600191505b60010161497b565b60606112aa614a3d836156b3565b615799565b6060815160001415614a6357506040805160008152602081019091526111fa565b606082600081518110614a7257fe5b602002602001015190506000600190505b8351811015614ab357614aa982858381518110614a9c57fe5b60200260200101516157eb565b9150600101614a83565b50611115614ac6825160c060ff16615868565b826157eb565b60006060602983511115614afe576000604051806060016040528060298152602001615df56029913991509150612e35565b60005b8351811015614b945760005b81811015614b8b57848181518110614b2157fe5b6020026020010151600001516001600160a01b0316858381518110614b4257fe5b6020026020010151600001516001600160a01b03161415614b835760006040518060600160405280602b8152602001615e49602b9139935093505050612e35565b600101614b0d565b50600101614b01565b505060408051602081019091526000815260019150915091565b6060600080808080614bbe61242a565b6001549091505b8015614ccc57600181039250600b8381548110614bde57fe5b600091825260209091206001601690920201015460ff16614bfe57614cc3565b60018381548110614c0b57fe5b60009182526020909120600490910201546001600160a01b03169450614c32858484612aed565b9350831580614c45575060018851038610155b15614c4f57614cc3565b60005b8851811015614cc157856001600160a01b0316898281518110614c7157fe5b6020026020010151600001516001600160a01b03161415614cb9576001898281518110614c9a57fe5b6020908102919091010151901515608090910152600190960195614cc1565b600101614c52565b505b60001901614bc5565b5084875103604051908082528060200260200182016040528015614d0a57816020015b614cf7615a77565b815260200190600190039081614cef5790505b5095506000915060005b8751811015614d7357878181518110614d2957fe5b602002602001015160800151614d6b57878181518110614d4557fe5b6020026020010151878481518110614d5957fe5b60209081029190910101526001909201915b600101614d14565b505050505050919050565b600154815160005b82811015614e9b576001614d98615a77565b60018381548110614da557fe5b600091825260208083206040805160c08101825260049490940290910180546001600160a01b0390811685526001820154811693850193909352600281015492831691840191909152600160a01b82046001600160401b03166060840152600160e01b90910460ff16151560808301526003015460a082015291505b84811015614e6f57868181518110614e3557fe5b6020026020010151600001516001600160a01b031682600001516001600160a01b03161415614e675760009250614e6f565b600101614e21565b508115614e915780516001600160a01b03166000908152600460205260408120555b5050600101614d86565b5080821115614f4c57805b82811015614f4a576001805480614eb957fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b805480614f0c57fe5b60008281526020812060166000199093019283020181815560018101805460ff1916905590614f3e6002830182615ad7565b50509055600101614ea6565b505b6000818310614f5b5781614f5d565b825b905060005b818110156151575761500f858281518110614f7957fe5b602002602001015160018381548110614f8e57fe5b60009182526020918290206040805160c08101825260049390930290910180546001600160a01b0390811684526001820154811694840194909452600281015493841691830191909152600160a01b83046001600160401b03166060830152600160e01b90920460ff161515608082015260039091015460a0820152615960565b61512a57806001016004600087848151811061502757fe5b6020026020010151600001516001600160a01b03166001600160a01b031681526020019081526020016000208190555084818151811061506357fe5b60200260200101516001828154811061507857fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a09091015160039091015561514f565b60006001828154811061513957fe5b9060005260206000209060040201600301819055505b600101614f62565b50828211156152fc576151686159e1565b835b838110156152f957600186828151811061518057fe5b6020908102919091018101518254600181810185556000948552838520835160049093020180546001600160a01b039384166001600160a01b0319918216178255848601518284018054918616918316919091179055604080860151600284018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909a1692909616919091179290921696909617169190911790935560a090930151600390930192909255600b8054928301815590935284516016909102600080516020615fc18339815191528101918255918501516000805160206160d18339815191528301805491151560ff19909216919091179055918401518492916152b591600080516020616007833981519152909101906014615a05565b50505080600101600460008884815181106152cc57fe5b602090810291909101810151516001600160a01b031682528101919091526040016000205560010161516a565b50505b6000600981905560015493505b8381101561536a576000600b828154811061532057fe5b60009182526020822060169190910201600101805460ff191692151592909217909155600b80548390811061535157fe5b6000918252602090912060169091020155600101615309565b5050505050565b600081836153fd5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156153c25781810151838201526020016153aa565b50505050905090810190601f1680156153ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161540957fe5b0495945050505050565b600081848411156154655760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156153c25781810151838201526020016153aa565b505050900390565b805160009061547e575060006111fa565b6020820151805160001a9060c082101561549d576000925050506111fa565b5060019392505050565b8051600090811a60808110156154c15760009150506111fa565b60b88110806154dc575060c081108015906154dc575060f881105b156154eb5760019150506111fa565b60c08110156154ff5760b5190190506111fa565b60f5190190506111fa565b80516000908190811a60808110156155255760019150615636565b60b881101561553a57607e1981019150615636565b60c08110156155b457600060b78203600186019550806020036101000a8651049150600181018201935050808310156155ae576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b50615636565b60f88110156155c95760be1981019150615636565b600060f78203600186019550806020036101000a865104915060018101820193505080831015615634576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b805160009061564e575060006111fa565b6000809050600061566284602001516154a7565b602085015185519181019250015b80821015615690576156818261550a565b60019093019290910190615670565b50909392505050565b80516000906015146156aa57600080fd5b6112aa826147ca565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff1984166156f75750601861571b565b6fffffffffffffffffffffffffffffffff1984166157175750601061571b565b5060005b60208110156157515781818151811061573057fe5b01602001516001600160f81b0319161561574957615751565b60010161571b565b60008160200390506060816040519080825280601f01601f191660200182016040528015615786576020820181803683370190505b5080830196909652508452509192915050565b6060815160011480156157cb5750607f60f81b826000815181106157b957fe5b01602001516001600160f81b03191611155b156157d75750806111fa565b6112aa6157e98351608060ff16615868565b835b6060806040519050835180825260208201818101602087015b8183101561581c578051835260209283019201615804565b50855184518101855292509050808201602086015b81831015615849578051835260209283019201615831565b508651929092011591909101601f01601f191660405250905092915050565b60606801000000000000000083106158b8576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116159125782840160f81b816000815181106158f457fe5b60200101906001600160f81b031916908160001a90535090506112aa565b606061591d856156b3565b90508381510160370160f81b8260008151811061593657fe5b60200101906001600160f81b031916908160001a90535061595782826157eb565b95945050505050565b805182516000916001600160a01b03918216911614801561599a575081602001516001600160a01b031683602001516001600160a01b0316145b80156159bf575081604001516001600160a01b031683604001516001600160a01b0316145b80156111155750506060908101519101516001600160401b0390811691161490565b6040805160608101825260008082526020820152908101615a00615b00565b905290565b8260148101928215615a33579160200282015b82811115615a33578251825591602001919060010190615a18565b50612465929150615b1f565b60408051808201909152600081526060602082015290565b6040518060400160405280615a6a615ae6565b8152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b8260148101928215615a33579182015b82811115615a33578254825591600101919060010190615abc565b5061140c906014810190615b1f565b604051806040016040528060008152602001600081525090565b6040518061028001604052806014906020820280368337509192915050565b61152991905b808211156124655760008155600101615b2556fef901a880f901a4f844941284214b9b9c85549ab3d2b972df0deef66ac2c9946ddf42a51534fc98d0c0a3b42c963cace8441ddf946ddf42a51534fc98d0c0a3b42c963cace8441ddf8410000000f84494a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0948081ef03f1d9e0bb4a5bf38f16285c879299f07f948081ef03f1d9e0bb4a5bf38f16285c879299f07f8410000000f8449435552c16704d214347f29fa77f77da6d75d7c75294dc4973e838e3949c77aced16ac2315dc2d7ab11194dc4973e838e3949c77aced16ac2315dc2d7ab1118410000000f84494980a75ecd1309ea12fa2ed87a8744fbfc9b863d594cc6ac05c95a99c1f7b5f88de0e3486c82293b27094cc6ac05c95a99c1f7b5f88de0e3486c82293b2708410000000f84494f474cf03cceff28abc65c9cbae594f725c80e12d94e61a183325a18a173319dd8e19c8d069459e217594e61a183325a18a173319dd8e19c8d069459e21758410000000f84494b71b214cb885500844365e95cd9942c7276e7fd894d22ca3ba2141d23adab65ce4940eb7665ea2b6a794d22ca3ba2141d23adab65ce4940eb7665ea2b6a784100000006c656e677468206f66206d61784e756d4f664d61696e7461696e696e67206d69736d617463686c656e677468206f66206d61784e756d4f66576f726b696e6743616e64696461746573206d69736d617463686c656e677468206f66206d61696e7461696e536c6173685363616c65206d69736d61746368746865206d61784e756d4f664d61696e7461696e696e67206d757374206265206c657373207468616e206e756d4f6643616e696e61746573746865206e756d4f66436162696e657473206d7573742062652067726561746572207468616e2030746865206e756d4f66436162696e657473206d757374206265206c657373207468616e204d41585f4e554d5f4f465f56414c494441544f5253746865206e756d626572206f662076616c696461746f72732065786365656420746865206c696d6974746865206275726e526174696f206d757374206265206e6f2067726561746572207468616e2031303030306475706c696361746520636f6e73656e7375732061646472657373206f662076616c696461746f725365747468652065787069726554696d655365636f6e64476170206973206f7574206f662072616e6765746865206d61784e756d4f66576f726b696e6743616e64696461746573206d757374206265206e6f742067726561746572207468616e206d61784e756d4f6643616e6469646174657363616e206e6f7420656e7465722054656d706f72617279204d61696e74656e616e63656c656e677468206f66206a61696c2076616c696461746f7273206d757374206265206f6e65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e74726163746c656e677468206f66206d61784e756d4f6643616e64696461746573206d69736d61746368666565206973206c6172676572207468616e2044555354595f494e434f4d494e470175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db96c656e677468206f662065787069726554696d655365636f6e64476170206d69736d617463680175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb6661696c656420746f20706172736520696e69742076616c696461746f72536574746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f6475636572746865206d61696e7461696e536c6173685363616c65206d7573742062652067726561746572207468616e20300175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba746865206d6573736167652073656e646572206d75737420626520736c61736820636f6e7472616374a26469706673582212207d06d87a731c4f784da075c7514dda45d8e95322210e57cff56c67307efa97d164736f6c63430006040033", + }, + { + ContractAddr: common.HexToAddress(SlashContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/db8bb560ac5a1265c685b719c7e976dced162310", + Code: "608060405234801561001057600080fd5b506004361061023d5760003560e01c80638256ace61161013b578063c80d4b8f116100b8578063e1c7392a1161007c578063e1c7392a1461071d578063f9a2bbc714610725578063fc3e59081461072d578063fc4333cd14610735578063fd6a68791461073d5761023d565b8063c80d4b8f14610667578063c81b16621461066f578063c8509d8114610677578063c96be4cb146106ef578063dc927faf146107155761023d565b8063a1a11bf5116100ff578063a1a11bf514610575578063a78abc161461057d578063ab51bb9614610599578063ac0af629146105a1578063ac431751146105a95761023d565b80638256ace6146104dd578063831d65d1146104e557806396713da91461055d5780639bc8e4f2146105655780639dc092621461056d5761023d565b80634bf6c882116101c95780636e47b4821161018d5780636e47b482146104b557806370fd5bad146104bd57806375d47a0a146104c55780637912a65d146104cd5780637942fd05146104d55761023d565b80634bf6c8821461046d57806351e8067214610475578063567a372d1461047d5780635bfb49901461048557806362b72cf5146104ad5761023d565b806337c8dab91161021057806337c8dab9146103cf578063389f4f711461040e5780633dffc3871461042857806343756e5c14610446578063493279b11461044e5761023d565b80630bee7a67146102425780631182b8751461026357806323bac5a21461035057806335aa2e4414610396575b600080fd5b61024a610745565b6040805163ffffffff9092168252519081900360200190f35b6102db6004803603604081101561027957600080fd5b60ff8235169190810190604081016020820135600160201b81111561029d57600080fd5b8201836020820111156102af57600080fd5b803590602001918460018302840111600160201b831117156102d057600080fd5b50909250905061074a565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103155781810151838201526020016102fd565b50505050905090810190601f1680156103425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103766004803603602081101561036657600080fd5b50356001600160a01b031661081e565b604080519384526020840192909252151582820152519081900360600190f35b6103b3600480360360208110156103ac57600080fd5b5035610841565b604080516001600160a01b039092168252519081900360200190f35b6103f5600480360360208110156103e557600080fd5b50356001600160a01b0316610868565b6040805192835260208301919091528051918290030190f35b6104166108bf565b60408051918252519081900360200190f35b6104306108c5565b6040805160ff9092168252519081900360200190f35b6103b36108ca565b6104566108d0565b6040805161ffff9092168252519081900360200190f35b6104306108d6565b6103b36108db565b6104166108e1565b6104ab6004803603602081101561049b57600080fd5b50356001600160a01b03166108e7565b005b610416610a48565b6103b3610a4e565b610430610a54565b6103b3610a59565b610416610a5f565b610430610a64565b6103f5610a69565b6104ab600480360360408110156104fb57600080fd5b60ff8235169190810190604081016020820135600160201b81111561051f57600080fd5b82018360208201111561053157600080fd5b803590602001918460018302840111600160201b8311171561055257600080fd5b509092509050610a73565b610430610bcd565b610416610bd2565b6103b3610bdd565b6103b3610be3565b610585610be9565b604080519115158252519081900360200190f35b61024a610bf2565b610416610bf7565b6104ab600480360360408110156105bf57600080fd5b810190602081018135600160201b8111156105d957600080fd5b8201836020820111156105eb57600080fd5b803590602001918460018302840111600160201b8311171561060c57600080fd5b919390929091602081019035600160201b81111561062957600080fd5b82018360208201111561063b57600080fd5b803590602001918460018302840111600160201b8311171561065c57600080fd5b509092509050610bfc565b610416610fea565b6103b3610fef565b6104ab6004803603604081101561068d57600080fd5b60ff8235169190810190604081016020820135600160201b8111156106b157600080fd5b8201836020820111156106c357600080fd5b803590602001918460018302840111600160201b831117156106e457600080fd5b509092509050610ff5565b6104ab6004803603602081101561070557600080fd5b50356001600160a01b03166110a8565b6103b361154b565b6104ab611551565b6103b36115c2565b6104306115c8565b6104ab6115cd565b6103b3611a58565b606481565b6060336120001461078c5760405162461bcd60e51b815260040180806020018281038252602f8152602001806124b0602f913960400191505060405180910390fd5b60005460ff166107d1576040805162461bcd60e51b8152602060048201526019602482015260008051602061250c833981519152604482015290519081900360640190fd5b6040805162461bcd60e51b815260206004820152601e60248201527f7265636569766520756e65787065637465642073796e207061636b6167650000604482015290519081900360640190fd5b600260208190526000918252604090912080546001820154919092015460ff1683565b6001818154811061084e57fe5b6000918252602090912001546001600160a01b0316905081565b600080610873612374565b5050506001600160a01b0316600090815260026020818152604092839020835160608101855281548082526001830154938201849052919093015460ff16151592909301919091529091565b60055481565b600181565b61100181565b6102ca81565b600881565b61200081565b60045481565b33611000146109275760405162461bcd60e51b815260040180806020018281038252603081526020018061240b6030913960400191505060405180910390fd5b60005460ff1661096c576040805162461bcd60e51b8152602060048201526019602482015260008051602061250c833981519152604482015290519081900360640190fd5b61200063f7a251d7600b61097f84611a5e565b60006040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156109df5781810151838201526020016109c7565b50505050905090810190601f168015610a0c5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015610a2d57600080fd5b505af1158015610a41573d6000803e3d6000fd5b5050505050565b60035481565b61100581565b600281565b61100881565b603281565b600b81565b6004546005549091565b3361200014610ab35760405162461bcd60e51b815260040180806020018281038252602f8152602001806124b0602f913960400191505060405180910390fd5b60005460ff16610af8576040805162461bcd60e51b8152602060048201526019602482015260008051602061250c833981519152604482015290519081900360640190fd5b610b00612397565b6000610b4184848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b3192505050565b915091508015610b8b5781516040805163ffffffff9092168252517f7f0956d47419b9525356e7111652b653b530ec6f5096dccc04589bc38e6299679181900360200190a1610a41565b81516040805163ffffffff9092168252517f7d45f62d17443dd4547bca8a8112c60e2385669318dc300ec61a5d2492f262e79181900360200190a15050505050565b600981565b662386f26fc1000081565b61100781565b61100681565b60005460ff1681565b600081565b600481565b60005460ff16610c41576040805162461bcd60e51b8152602060048201526019602482015260008051602061250c833981519152604482015290519081900360640190fd5b3361100714610c815760405162461bcd60e51b815260040180806020018281038252602e81526020018061243b602e913960400191505060405180910390fd5b610cec84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260148152731b5a5cd9195b59585b9bdc951a1c995cda1bdb1960621b60208201529150611bb19050565b15610dc55760208114610d305760405162461bcd60e51b81526004018080602001828103825260278152602001806123e46027913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091610d6e91858580838501838280828437600092019190915250611c9992505050565b905060018110158015610d82575060055481105b610dbd5760405162461bcd60e51b815260040180806020018281038252602581526020018061248b6025913960400191505060405180910390fd5b600455610f58565b610e2b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600f81526e19995b1bdb9e551a1c995cda1bdb19608a1b60208201529150611bb19050565b15610f1b5760208114610e6f5760405162461bcd60e51b81526004018080602001828103825260228152602001806124696022913960400191505060405180910390fd5b604080516020601f8401819004810282018101909252828152600091610ead91858580838501838280828437600092019190915250611c9992505050565b90506103e88111158015610ec2575060045481115b610f13576040805162461bcd60e51b815260206004820181905260248201527f7468652066656c6f6e795468726573686f6c64206f7574206f662072616e6765604482015290519081900360640190fd5b600555610f58565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b609681565b61100281565b33612000146110355760405162461bcd60e51b815260040180806020018281038252602f8152602001806124b0602f913960400191505060405180910390fd5b60005460ff1661107a576040805162461bcd60e51b8152602060048201526019602482015260008051602061250c833981519152604482015290519081900360640190fd5b6040517f07db600eebe2ac176be8dcebad61858c245a4961bb32ca2aa3d159b09aa0810e90600090a1505050565b3341146110e65760405162461bcd60e51b815260040180806020018281038252602d8152602001806124df602d913960400191505060405180910390fd5b60005460ff1661112b576040805162461bcd60e51b8152602060048201526019602482015260008051602061250c833981519152604482015290519081900360640190fd5b6003544311611181576040805162461bcd60e51b815260206004820181905260248201527f63616e206e6f7420736c61736820747769636520696e206f6e6520626c6f636b604482015290519081900360640190fd5b3a156111cb576040805162461bcd60e51b81526020600482015260146024820152736761737072696365206973206e6f74207a65726f60601b604482015290519081900360640190fd5b6040805163155853f360e21b81526001600160a01b03831660048201529051611000916355614fcc916024808301926020929190829003018186803b15801561121357600080fd5b505afa158015611227573d6000803e3d6000fd5b505050506040513d602081101561123d57600080fd5b505161124857611544565b611250612374565b506001600160a01b0381166000908152600260208181526040928390208351606081018552815481526001820154928101929092529091015460ff1615801592820192909252906112ab576020810180516001019052611304565b60016040820181905260208201819052805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b0384161790555b43815260055460208201518161131657fe5b0661146857600060208201819052604080516335409f7f60e01b81526001600160a01b03851660048201529051611000926335409f7f926024808201939182900301818387803b15801561136957600080fd5b505af115801561137d573d6000803e3d6000fd5b505050506120006001600160a01b031663f7a251d7600b61139d85611a5e565b60006040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156113fd5781810151838201526020016113e5565b50505050905090810190601f16801561142a5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561144b57600080fd5b505af115801561145f573d6000803e3d6000fd5b505050506114de565b60045481602001518161147757fe5b066114de57604080516375abf10160e11b81526001600160a01b038416600482015290516110009163eb57e20291602480830192600092919082900301818387803b1580156114c557600080fd5b505af11580156114d9573d6000803e3d6000fd5b505050505b6001600160a01b0382166000818152600260208181526040808420865181559186015160018301558581015191909201805460ff1916911515919091179055517fddb6012116e51abf5436d956a4f0ebd927e92c576ff96d7918290c8782291e3e9190a2505b5043600355565b61100381565b60005460ff16156115a9576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b603260045560966005556000805460ff19166001179055565b61100081565b600381565b336110001461160d5760405162461bcd60e51b815260040180806020018281038252603081526020018061240b6030913960400191505060405180910390fd5b60005460ff16611652576040805162461bcd60e51b8152602060048201526019602482015260008051602061250c833981519152604482015290519081900360640190fd5b60015461165e57611a56565b600154600090600019015b808211611a2a576000805b8284101561178d57611684612374565b600260006001878154811061169557fe5b60009182526020808320909101546001600160a01b0316835282810193909352604091820190208151606081018352815481526001820154938101939093526002015460ff1615159082015260055490915060049004816020015111156117775760046005548161170257fe5b0481602001510381602001818152505080600260006001888154811061172457fe5b6000918252602080832091909101546001600160a01b0316835282810193909352604091820190208351815591830151600183015591909101516002909101805460ff1916911515919091179055611781565b600192505061178d565b50600190930192611674565b8284116119245761179c612374565b60026000600186815481106117ad57fe5b60009182526020808320909101546001600160a01b0316835282810193909352604091820190208151606081018352815481526001820154938101939093526002015460ff1615159082015260055490915060049004816020015111156118955760046005548161181a57fe5b0481602001510381602001818152505080600260006001878154811061183c57fe5b6000918252602080832091909101546001600160a01b03168352828101939093526040918201902083518155918301516001808401919091559201516002909101805460ff191691151591909117905591506119249050565b60026000600186815481106118a657fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120818155600181810192909255600201805460ff191690558054806118ea57fe5b600082815260209020810160001990810180546001600160a01b0319169055019055836119175750611924565b506000199092019161178d565b81801561192e5750805b15611a0d57600260006001868154811061194457fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120818155600181810192909255600201805460ff1916905580548490811061198b57fe5b600091825260209091200154600180546001600160a01b0390921691869081106119b157fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060018054806119ea57fe5b600082815260209020810160001990810180546001600160a01b03191690550190555b82611a19575050611a2a565b505060019091019060001901611669565b6040517fcfdb3b6ccaeccbdc68be3c59c840e3b3c90f0a7c491f5fff1cf56cfda200dd9c90600090a150505b565b61100481565b60408051600480825260a08201909252606091829190816020015b6060815260200190600190039081611a79579050509050611aa2836001600160a01b0316611c9e565b81600081518110611aaf57fe5b6020026020010181905250611ac343611cc1565b81600181518110611ad057fe5b6020908102919091010152611ae66102ca611cc1565b81600281518110611af357fe5b6020026020010181905250611b0742611cc1565b81600381518110611b1457fe5b6020026020010181905250611b2881611cd4565b9150505b919050565b611b39612397565b6000611b43612397565b611b4b6123a9565b611b5c611b5786611d5e565b611d83565b90506000805b611b6b83611dcd565b15611ba45780611b9757611b86611b8184611dee565b611e3c565b63ffffffff16845260019150611b9c565b611ba4565b600101611b62565b5091935090915050915091565b6000816040516020018082805190602001908083835b60208310611be65780518252601f199092019160209182019101611bc7565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b60208310611c545780518252601f199092019160209182019101611c35565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201490505b92915050565b015190565b60408051600560a21b8318601482015260348101909152606090611b2881611ef3565b6060611c93611ccf83611f49565b611ef3565b6060815160001415611cf55750604080516000815260208101909152611b2c565b606082600081518110611d0457fe5b602002602001015190506000600190505b8351811015611d4557611d3b82858381518110611d2e57fe5b602002602001015161202f565b9150600101611d15565b50611b28611d58825160c060ff166120ac565b8261202f565b611d666123c9565b506040805180820190915281518152602082810190820152919050565b611d8b6123a9565b611d94826121a4565b611d9d57600080fd5b6000611dac83602001516121de565b60208085015160408051808201909152868152920190820152915050919050565b6000611dd76123c9565b505080518051602091820151919092015191011190565b611df66123c9565b611dff82611dcd565b611e0857600080fd5b60208201516000611e1882612241565b80830160209586015260408051808201909152908152938401919091525090919050565b805160009015801590611e5157508151602110155b611e5a57600080fd5b6000611e6983602001516121de565b90508083600001511015611ec4576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b825160208085015183018051928490039291831015611eea57826020036101000a820491505b50949350505050565b606081516001148015611f255750607f60f81b82600081518110611f1357fe5b01602001516001600160f81b03191611155b15611f31575080611b2c565b611c93611f438351608060ff166120ac565b8361202f565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff198416611f8d57506018611fb1565b6fffffffffffffffffffffffffffffffff198416611fad57506010611fb1565b5060005b6020811015611fe757818181518110611fc657fe5b01602001516001600160f81b03191615611fdf57611fe7565b600101611fb1565b60008160200390506060816040519080825280601f01601f19166020018201604052801561201c576020820181803683370190505b5080830196909652508452509192915050565b6060806040519050835180825260208201818101602087015b81831015612060578051835260209283019201612048565b50855184518101855292509050808201602086015b8183101561208d578051835260209283019201612075565b508651929092011591909101601f01601f191660405250905092915050565b60606801000000000000000083106120fc576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116121565782840160f81b8160008151811061213857fe5b60200101906001600160f81b031916908160001a9053509050611c93565b606061216185611f49565b90508381510160370160f81b8260008151811061217a57fe5b60200101906001600160f81b031916908160001a90535061219b828261202f565b95945050505050565b80516000906121b557506000611b2c565b6020820151805160001a9060c08210156121d457600092505050611b2c565b5060019392505050565b8051600090811a60808110156121f8576000915050611b2c565b60b8811080612213575060c08110801590612213575060f881105b15612222576001915050611b2c565b60c08110156122365760b519019050611b2c565b60f519019050611b2c565b80516000908190811a608081101561225c576001915061236d565b60b881101561227157607e198101915061236d565b60c08110156122eb57600060b78203600186019550806020036101000a8651049150600181018201935050808310156122e5576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b5061236d565b60f88110156123005760be198101915061236d565b600060f78203600186019550806020036101000a86510491506001810182019350508083101561236b576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b604051806060016040528060008152602001600081526020016000151581525090565b60408051602081019091526000815290565b60405180604001604052806123bc6123c9565b8152602001600081525090565b60405180604001604052806000815260200160008152509056fe6c656e677468206f66206d697364656d65616e6f725468726573686f6c64206d69736d61746368746865206d6573736167652073656e646572206d7573742062652076616c696461746f7253657420636f6e7472616374746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e74726163746c656e677468206f662066656c6f6e795468726573686f6c64206d69736d61746368746865206d697364656d65616e6f725468726573686f6c64206f7574206f662072616e6765746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d6573736167652073656e646572206d7573742062652074686520626c6f636b2070726f647563657274686520636f6e7472616374206e6f7420696e69742079657400000000000000a2646970667358221220cc16be27360652de46deaec4be6263ad1d90d5a454d0f34c9ca0f4c36e67819264736f6c63430006040033", + }, + }, + } + } func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, statedb *state.StateDB) { @@ -345,6 +396,10 @@ func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I applySystemContractUpgrade(brunoUpgrade[network], blockNumber, statedb, logger) } + if config.IsOnEuler(blockNumber) { + applySystemContractUpgrade(eulerUpgrade[network], blockNumber, statedb, logger) + } + /* apply other upgrades */ diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 593c629446..f6ed0282d1 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -83,6 +83,7 @@ func generateTestChainWithFork(n int, fork int) (*core.Genesis, []*types.Block, NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), BrunoBlock: big.NewInt(0), + EulerBlock: big.NewInt(0), Ethash: new(params.EthashConfig), } diff --git a/miner/worker.go b/miner/worker.go index 2b9bf43305..863726cf47 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -761,7 +761,12 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin if w.current.gasPool == nil { w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) - w.current.gasPool.SubGas(params.SystemTxsGas) + if w.chain.Config().IsEuler(w.current.header.Number) { + w.current.gasPool.SubGas(params.SystemTxsGas * 3) + } else { + w.current.gasPool.SubGas(params.SystemTxsGas) + } + } var coalescedLogs []*types.Log diff --git a/params/config.go b/params/config.go index c09a576495..92275d5a9c 100644 --- a/params/config.go +++ b/params/config.go @@ -34,7 +34,7 @@ var ( BSCGenesisHash = common.HexToHash("0x0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b") ChapelGenesisHash = common.HexToHash("0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34") - RialtoGenesisHash = common.HexToHash("0xaabe549bfa85c84f7aee9da7010b97453ad686f2c2d8ce00503d1a00c72cad54") + RialtoGenesisHash = common.HexToHash("0xee835a629f9cf5510b48b6ba41d69e0ff7d6ef10f977166ef939db41f59f5501") YoloV3GenesisHash = common.HexToHash("0xf1f2876e8500c77afcc03228757b39477eceffccf645b734967fe3c7e16967b7") ) @@ -76,6 +76,7 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), BrunoBlock: big.NewInt(0), + EulerBlock: big.NewInt(0), BerlinBlock: big.NewInt(12_244_000), Ethash: new(EthashConfig), } @@ -120,6 +121,7 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), BrunoBlock: big.NewInt(0), + EulerBlock: big.NewInt(0), BerlinBlock: big.NewInt(9_812_189), Ethash: new(EthashConfig), } @@ -164,6 +166,7 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), BrunoBlock: big.NewInt(0), + EulerBlock: big.NewInt(0), BerlinBlock: big.NewInt(8_290_928), Clique: &CliqueConfig{ Period: 15, @@ -207,6 +210,7 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), BrunoBlock: big.NewInt(0), + EulerBlock: big.NewInt(0), IstanbulBlock: big.NewInt(1_561_651), MuirGlacierBlock: nil, BerlinBlock: big.NewInt(4_460_644), @@ -251,6 +255,10 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(5184000), BrunoBlock: big.NewInt(13082000), + + // TODO modify blockNumber + EulerBlock: nil, + Parlia: &ParliaConfig{ Period: 3, Epoch: 200, @@ -272,6 +280,10 @@ var ( NielsBlock: big.NewInt(1014369), MirrorSyncBlock: big.NewInt(5582500), BrunoBlock: big.NewInt(13837000), + + // TODO modify blockNumber + EulerBlock: nil, + Parlia: &ParliaConfig{ Period: 3, Epoch: 200, @@ -293,6 +305,10 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(400), BrunoBlock: big.NewInt(400), + + // TODO + EulerBlock: nil, + Parlia: &ParliaConfig{ Period: 3, Epoch: 200, @@ -316,6 +332,7 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(0), BrunoBlock: big.NewInt(0), + EulerBlock: big.NewInt(0), MuirGlacierBlock: nil, BerlinBlock: nil, // Don't enable Berlin directly, we're YOLOing it YoloV3Block: big.NewInt(0), @@ -330,16 +347,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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil} + 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, &CliqueConfig{Period: 0, Epoch: 30000}, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, 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), nil, nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, nil} TestRules = TestChainConfig.Rules(new(big.Int)) ) @@ -427,6 +444,7 @@ type ChainConfig struct { NielsBlock *big.Int `json:"nielsBlock,omitempty" toml:",omitempty"` // nielsBlock switch block (nil = no fork, 0 = already activated) MirrorSyncBlock *big.Int `json:"mirrorSyncBlock,omitempty" toml:",omitempty"` // mirrorSyncBlock switch block (nil = no fork, 0 = already activated) BrunoBlock *big.Int `json:"brunoBlock,omitempty" toml:",omitempty"` // brunoBlock switch block (nil = no fork, 0 = already activated) + EulerBlock *big.Int `json:"eulerBlock,omitempty" toml:",omitempty"` // eulerBlock switch block (nil = no fork, 0 = already activated) // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty" toml:",omitempty"` @@ -477,7 +495,7 @@ func (c *ChainConfig) String() string { 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, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, Engine: %v}", + 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, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, Euler: %v, Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -496,6 +514,7 @@ func (c *ChainConfig) String() string { c.BrunoBlock, c.BerlinBlock, c.YoloV3Block, + c.EulerBlock, engine, ) } @@ -575,6 +594,16 @@ func (c *ChainConfig) IsOnBruno(num *big.Int) bool { return configNumEqual(c.BrunoBlock, num) } +// IsEuler returns whether num is either equal to the euler fork block or greater. +func (c *ChainConfig) IsEuler(num *big.Int) bool { + return isForked(c.EulerBlock, num) +} + +// IsOnEuler returns whether num is equal to the euler fork block +func (c *ChainConfig) IsOnEuler(num *big.Int) bool { + return configNumEqual(c.EulerBlock, 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) @@ -637,6 +666,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { for _, cur := range []fork{ {name: "mirrorSyncBlock", block: c.MirrorSyncBlock}, {name: "brunoBlock", block: c.BrunoBlock}, + {name: "eulerBlock", block: c.EulerBlock}, {name: "berlinBlock", block: c.BerlinBlock}, } { if lastFork.name != "" { @@ -719,6 +749,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.BrunoBlock, newcfg.BrunoBlock, head) { return newCompatError("bruno fork block", c.BrunoBlock, newcfg.BrunoBlock) } + if isForkIncompatible(c.EulerBlock, newcfg.EulerBlock, head) { + return newCompatError("euler fork block", c.EulerBlock, newcfg.EulerBlock) + } return nil } From b679ba81f2ba047977a9d0139106ed8f2d431263 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Thu, 5 May 2022 11:29:33 +0800 Subject: [PATCH 100/117] prepare for release v1.1.10 (#889) --- CHANGELOG.md | 12 ++++++++++++ README.md | 2 +- params/config.go | 4 +--- params/version.go | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9100249fa0..faddee659b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## v1.1.10 + +FEATURE +* [\#885](https://github.com/binance-chain/bsc/pull/885) add Euler Hardfork, including BEP-127 and BEP-131 + + +BUGFIX +* [\#856](https://github.com/binance-chain/bsc/pull/856) fix logic issue: handlers.removePeer() is called twice +* [\#860](https://github.com/binance-chain/bsc/pull/860) fix:defer bloomprocessor close +* [\#877](https://github.com/binance-chain/bsc/pull/877) fix validator pipecommit issue +* [\#870](https://github.com/binance-chain/bsc/pull/870) fix:Shift panic for zero length of heads + ## v1.1.9 IMPROVEMENT diff --git a/README.md b/README.md index bc7f7a85ef..c8833941ad 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ This command will: Steps: -1. Download the binary, config and genesis files from [release](https://github.com/binance-chain/bsc/releases/download/v1.0.0-alpha.0/binary.zip), or compile the binary by `make geth`. +1. Download the binary, config and genesis files from [release](https://github.com/bnb-chain/bsc/releases/tag/v1.1.10), or compile the binary by `make geth`. 2. Init genesis state: `./geth --datadir node init genesis.json`. 3. Start your fullnode: `./geth --config ./config.toml --datadir ./node`. 4. Or start a validator node: `./geth --config ./config.toml --datadir ./node -unlock ${validatorAddr} --mine --allow-insecure-unlock`. The ${validatorAddr} is the wallet account address of your running validator node. diff --git a/params/config.go b/params/config.go index 92275d5a9c..fbf4c4259b 100644 --- a/params/config.go +++ b/params/config.go @@ -280,9 +280,7 @@ var ( NielsBlock: big.NewInt(1014369), MirrorSyncBlock: big.NewInt(5582500), BrunoBlock: big.NewInt(13837000), - - // TODO modify blockNumber - EulerBlock: nil, + EulerBlock: big.NewInt(19203503), Parlia: &ParliaConfig{ Period: 3, diff --git a/params/version.go b/params/version.go index 634f527876..d4a04cfba2 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 9 // Patch version component of the current release + VersionPatch = 10 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From 55ef216c66069ae54b16e88d97f67c304cf551e6 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Thu, 5 May 2022 13:32:24 +0800 Subject: [PATCH 101/117] relace binance to bnb in changelog --- CHANGELOG.md | 184 +++++++++++++++++++++++++-------------------------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faddee659b..626151225c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,21 +3,21 @@ ## v1.1.10 FEATURE -* [\#885](https://github.com/binance-chain/bsc/pull/885) add Euler Hardfork, including BEP-127 and BEP-131 +* [\#885](https://github.com/bnb-chain/bsc/pull/885) add Euler Hardfork, including BEP-127 and BEP-131 BUGFIX -* [\#856](https://github.com/binance-chain/bsc/pull/856) fix logic issue: handlers.removePeer() is called twice -* [\#860](https://github.com/binance-chain/bsc/pull/860) fix:defer bloomprocessor close -* [\#877](https://github.com/binance-chain/bsc/pull/877) fix validator pipecommit issue -* [\#870](https://github.com/binance-chain/bsc/pull/870) fix:Shift panic for zero length of heads +* [\#856](https://github.com/bnb-chain/bsc/pull/856) fix logic issue: handlers.removePeer() is called twice +* [\#860](https://github.com/bnb-chain/bsc/pull/860) fix:defer bloomprocessor close +* [\#877](https://github.com/bnb-chain/bsc/pull/877) fix validator pipecommit issue +* [\#870](https://github.com/bnb-chain/bsc/pull/870) fix:Shift panic for zero length of heads ## v1.1.9 IMPROVEMENT -* [\#792](https://github.com/binance-chain/bsc/pull/792) add shared storage for prefetching state data -* [\#795](https://github.com/binance-chain/bsc/pull/795) implement state verification pipeline in pipecommit -* [\#803](https://github.com/binance-chain/bsc/pull/803) prefetch state data during the mining process +* [\#792](https://github.com/bnb-chain/bsc/pull/792) add shared storage for prefetching state data +* [\#795](https://github.com/bnb-chain/bsc/pull/795) implement state verification pipeline in pipecommit +* [\#803](https://github.com/bnb-chain/bsc/pull/803) prefetch state data during the mining process * [\#812](https://github.com/bnb-chain/bsc/pull/812) skip verification on account storage root to tolerate with fastnode when doing diffsync * [\#818](https://github.com/bnb-chain/bsc/pull/818) add shared storage to the prefetcher of miner * [\#820](https://github.com/bnb-chain/bsc/pull/820) disable diffsync when pipecommit is enabled @@ -33,195 +33,195 @@ BUGFIX ## v1.1.8 FEATURES -* [\#668](https://github.com/binance-chain/bsc/pull/668) implement State Verification && Snapshot Commit pipeline -* [\#581](https://github.com/binance-chain/bsc/pull/581) implement geth native trace -* [\#543](https://github.com/binance-chain/bsc/pull/543) implement offline block prune tools +* [\#668](https://github.com/bnb-chain/bsc/pull/668) implement State Verification && Snapshot Commit pipeline +* [\#581](https://github.com/bnb-chain/bsc/pull/581) implement geth native trace +* [\#543](https://github.com/bnb-chain/bsc/pull/543) implement offline block prune tools IMPROVEMENT -* [\#704](https://github.com/binance-chain/bsc/pull/704) prefetch state by applying the transactions within one block -* [\#713](https://github.com/binance-chain/bsc/pull/713) add ARM binaries for release pipeline +* [\#704](https://github.com/bnb-chain/bsc/pull/704) prefetch state by applying the transactions within one block +* [\#713](https://github.com/bnb-chain/bsc/pull/713) add ARM binaries for release pipeline BUGFIX -* [\#667](https://github.com/binance-chain/bsc/pull/667) trie: reject deletions when verifying range proofs #667 -* [\#643](https://github.com/binance-chain/bsc/pull/643) add timeout for stopping p2p server to fix can not gracefully shutdown issue -* [\#740](https://github.com/binance-chain/bsc/pull/740) update discord link which won't expire +* [\#667](https://github.com/bnb-chain/bsc/pull/667) trie: reject deletions when verifying range proofs #667 +* [\#643](https://github.com/bnb-chain/bsc/pull/643) add timeout for stopping p2p server to fix can not gracefully shutdown issue +* [\#740](https://github.com/bnb-chain/bsc/pull/740) update discord link which won't expire ## v1.1.7 BUGFIX -* [\#628](https://github.com/binance-chain/bsc/pull/628) fix state inconsistent when doing diffsync +* [\#628](https://github.com/bnb-chain/bsc/pull/628) fix state inconsistent when doing diffsync ## v1.1.6 BUGFIX -* [\#582](https://github.com/binance-chain/bsc/pull/582) the DoS vulnerabilities fixed in go-ethereum v1.10.9 +* [\#582](https://github.com/bnb-chain/bsc/pull/582) the DoS vulnerabilities fixed in go-ethereum v1.10.9 IMPROVEMENT -* [\#578](https://github.com/binance-chain/bsc/pull/578) reduce memory allocation and upgrade snappy version +* [\#578](https://github.com/bnb-chain/bsc/pull/578) reduce memory allocation and upgrade snappy version FEATURES -* [\#570](https://github.com/binance-chain/bsc/pull/570) reannounce local pending transactions +* [\#570](https://github.com/bnb-chain/bsc/pull/570) reannounce local pending transactions ## v1.1.5 BUGFIX -* [\#509](https://github.com/binance-chain/bsc/pull/509) fix graceful shutdown bug +* [\#509](https://github.com/bnb-chain/bsc/pull/509) fix graceful shutdown bug IMPROVEMENT -* [\#536](https://github.com/binance-chain/bsc/pull/536) get diff accounts by replaying block when diff layer not found -* [\#527](https://github.com/binance-chain/bsc/pull/527) improve diffsync protocol in many aspects -* [\#493](https://github.com/binance-chain/bsc/pull/493) implement fast getDiffAccountsWithScope API +* [\#536](https://github.com/bnb-chain/bsc/pull/536) get diff accounts by replaying block when diff layer not found +* [\#527](https://github.com/bnb-chain/bsc/pull/527) improve diffsync protocol in many aspects +* [\#493](https://github.com/bnb-chain/bsc/pull/493) implement fast getDiffAccountsWithScope API ## v1.1.4 Improvement -* [\#472](https://github.com/binance-chain/bsc/pull/472) add metrics for contract code bitmap cache -* [\#473](https://github.com/binance-chain/bsc/pull/473) fix ci test flow +* [\#472](https://github.com/bnb-chain/bsc/pull/472) add metrics for contract code bitmap cache +* [\#473](https://github.com/bnb-chain/bsc/pull/473) fix ci test flow BUGFIX -* [\#491](https://github.com/binance-chain/bsc/pull/491) fix prefetcher related bugs +* [\#491](https://github.com/bnb-chain/bsc/pull/491) fix prefetcher related bugs FEATURES -* [\#480](https://github.com/binance-chain/bsc/pull/480) implement bep 95 +* [\#480](https://github.com/bnb-chain/bsc/pull/480) implement bep 95 ## v1.1.3 Improvement -* [\#456](https://github.com/binance-chain/bsc/pull/456) git-flow support lint, unit test, and integration test -* [\#449](https://github.com/binance-chain/bsc/pull/449) cache bitmap and change the cache type of GetCode -* [\#454](https://github.com/binance-chain/bsc/pull/454) fix cache key do not have hash func -* [\#446](https://github.com/binance-chain/bsc/pull/446) parallel bloom calculation -* [\#442](https://github.com/binance-chain/bsc/pull/442) ignore empty tx in GetDiffAccountsWithScope -* [\#426](https://github.com/binance-chain/bsc/pull/426) add block proccess backoff time when validator is not in turn and received in turn block -* [\#398](https://github.com/binance-chain/bsc/pull/398) ci pipeline for release page +* [\#456](https://github.com/bnb-chain/bsc/pull/456) git-flow support lint, unit test, and integration test +* [\#449](https://github.com/bnb-chain/bsc/pull/449) cache bitmap and change the cache type of GetCode +* [\#454](https://github.com/bnb-chain/bsc/pull/454) fix cache key do not have hash func +* [\#446](https://github.com/bnb-chain/bsc/pull/446) parallel bloom calculation +* [\#442](https://github.com/bnb-chain/bsc/pull/442) ignore empty tx in GetDiffAccountsWithScope +* [\#426](https://github.com/bnb-chain/bsc/pull/426) add block proccess backoff time when validator is not in turn and received in turn block +* [\#398](https://github.com/bnb-chain/bsc/pull/398) ci pipeline for release page BUGFIX -* [\#446](https://github.com/binance-chain/bsc/pull/446) fix concurrent write of subfetcher -* [\#444](https://github.com/binance-chain/bsc/pull/444) fix blockhash not correct for the logs of system tx receipt -* [\#409](https://github.com/binance-chain/bsc/pull/409) fix nil point in downloader -* [\#408](https://github.com/binance-chain/bsc/pull/408) core/state/snapshot: fix typo +* [\#446](https://github.com/bnb-chain/bsc/pull/446) fix concurrent write of subfetcher +* [\#444](https://github.com/bnb-chain/bsc/pull/444) fix blockhash not correct for the logs of system tx receipt +* [\#409](https://github.com/bnb-chain/bsc/pull/409) fix nil point in downloader +* [\#408](https://github.com/bnb-chain/bsc/pull/408) core/state/snapshot: fix typo FEATURES -* [\#431](https://github.com/binance-chain/bsc/pull/431) Export get diff accounts in block api -* [\#412](https://github.com/binance-chain/bsc/pull/412) add extension in eth protocol handshake to disable tx broadcast -* [\#376](https://github.com/binance-chain/bsc/pull/376) implement diff sync +* [\#431](https://github.com/bnb-chain/bsc/pull/431) Export get diff accounts in block api +* [\#412](https://github.com/bnb-chain/bsc/pull/412) add extension in eth protocol handshake to disable tx broadcast +* [\#376](https://github.com/bnb-chain/bsc/pull/376) implement diff sync ## v1.1.2 Security -* [\#379](https://github.com/binance-chain/bsc/pull/379) A pre-announced hotfix release to patch a vulnerability in the EVM (CVE-2021-39137). +* [\#379](https://github.com/bnb-chain/bsc/pull/379) A pre-announced hotfix release to patch a vulnerability in the EVM (CVE-2021-39137). ## v1.1.1 IMPROVEMENT -* [\#355](https://github.com/binance-chain/bsc/pull/355) miner should propose block on a proper fork +* [\#355](https://github.com/bnb-chain/bsc/pull/355) miner should propose block on a proper fork BUGFIX -* [\#350](https://github.com/binance-chain/bsc/pull/350) flag: fix TriesInmemory specified but not work -* [\#358](https://github.com/binance-chain/bsc/pull/358) miner: fix null pending block -* [\#360](https://github.com/binance-chain/bsc/pull/360) pruner: fix state bloom sync permission in Windows -* [\#366](https://github.com/binance-chain/bsc/pull/366) fix double close channel of subfetcher +* [\#350](https://github.com/bnb-chain/bsc/pull/350) flag: fix TriesInmemory specified but not work +* [\#358](https://github.com/bnb-chain/bsc/pull/358) miner: fix null pending block +* [\#360](https://github.com/bnb-chain/bsc/pull/360) pruner: fix state bloom sync permission in Windows +* [\#366](https://github.com/bnb-chain/bsc/pull/366) fix double close channel of subfetcher ## v1.1.1-beta -* [\#333](https://github.com/binance-chain/bsc/pull/333) improve block fetcher efficiency -* [\#326](https://github.com/binance-chain/bsc/pull/326) eth/tracers: improve tracing performance -* [\#257](https://github.com/binance-chain/bsc/pull/257) performance improvement in many aspects +* [\#333](https://github.com/bnb-chain/bsc/pull/333) improve block fetcher efficiency +* [\#326](https://github.com/bnb-chain/bsc/pull/326) eth/tracers: improve tracing performance +* [\#257](https://github.com/bnb-chain/bsc/pull/257) performance improvement in many aspects ## v1.1.0 -* [\#282](https://github.com/binance-chain/bsc/pull/282) update discord link -* [\#280](https://github.com/binance-chain/bsc/pull/280) update discord link -* [\#227](https://github.com/binance-chain/bsc/pull/227) use more aggressive write cache policy +* [\#282](https://github.com/bnb-chain/bsc/pull/282) update discord link +* [\#280](https://github.com/bnb-chain/bsc/pull/280) update discord link +* [\#227](https://github.com/bnb-chain/bsc/pull/227) use more aggressive write cache policy ## v1.1.0-beta -* [\#152](https://github.com/binance-chain/bsc/pull/152) upgrade to go-ethereum 1.10.3 +* [\#152](https://github.com/bnb-chain/bsc/pull/152) upgrade to go-ethereum 1.10.3 ## v1.0.7-hf.2 BUGFIX -* [\#194](https://github.com/binance-chain/bsc/pull/194) bump btcd to v0.20.1-beta +* [\#194](https://github.com/bnb-chain/bsc/pull/194) bump btcd to v0.20.1-beta ## v1.0.7-hf.1 BUGFIX -* [\#190](https://github.com/binance-chain/bsc/pull/190) fix disk increase dramaticly -* [\#191](https://github.com/binance-chain/bsc/pull/191) fix the reorg routine of tx pool stuck issue +* [\#190](https://github.com/bnb-chain/bsc/pull/190) fix disk increase dramaticly +* [\#191](https://github.com/bnb-chain/bsc/pull/191) fix the reorg routine of tx pool stuck issue ## v1.0.7 -* [\#120](https://github.com/binance-chain/bsc/pull/120) add health check endpoint -* [\#116](https://github.com/binance-chain/bsc/pull/116) validator only write database state when enough distance -* [\#115](https://github.com/binance-chain/bsc/pull/115) add batch query methods -* [\#112](https://github.com/binance-chain/bsc/pull/112) apply max commit tx time for miner worker to avoid empty block -* [\#101](https://github.com/binance-chain/bsc/pull/101) apply block number limit for the `eth_getLogs` api -* [\#99](https://github.com/binance-chain/bsc/pull/99) enable directbroadcast flag to decrease the block propagation time -* [\#90](https://github.com/binance-chain/bsc/pull/90) add tini in docker image -* [\#84](https://github.com/binance-chain/bsc/pull/84) add jq in docker image +* [\#120](https://github.com/bnb-chain/bsc/pull/120) add health check endpoint +* [\#116](https://github.com/bnb-chain/bsc/pull/116) validator only write database state when enough distance +* [\#115](https://github.com/bnb-chain/bsc/pull/115) add batch query methods +* [\#112](https://github.com/bnb-chain/bsc/pull/112) apply max commit tx time for miner worker to avoid empty block +* [\#101](https://github.com/bnb-chain/bsc/pull/101) apply block number limit for the `eth_getLogs` api +* [\#99](https://github.com/bnb-chain/bsc/pull/99) enable directbroadcast flag to decrease the block propagation time +* [\#90](https://github.com/bnb-chain/bsc/pull/90) add tini in docker image +* [\#84](https://github.com/bnb-chain/bsc/pull/84) add jq in docker image ## v1.0.6 -* [\#68](https://github.com/binance-chain/bsc/pull/68) apply mirror sync upgrade on mainnet +* [\#68](https://github.com/bnb-chain/bsc/pull/68) apply mirror sync upgrade on mainnet ## v1.0.5 SECURITY -* [\#63](https://github.com/binance-chain/bsc/pull/63) security patches from go-ethereum -* [\#54](https://github.com/binance-chain/bsc/pull/54) les: fix GetProofsV2 that could potentially cause a panic. +* [\#63](https://github.com/bnb-chain/bsc/pull/63) security patches from go-ethereum +* [\#54](https://github.com/bnb-chain/bsc/pull/54) les: fix GetProofsV2 that could potentially cause a panic. FEATURES -* [\#56](https://github.com/binance-chain/bsc/pull/56) apply mirror sync upgrade -* [\#53](https://github.com/binance-chain/bsc/pull/53) support fork id in header; elegant upgrade +* [\#56](https://github.com/bnb-chain/bsc/pull/56) apply mirror sync upgrade +* [\#53](https://github.com/bnb-chain/bsc/pull/53) support fork id in header; elegant upgrade IMPROVEMENT -* [\#61](https://github.com/binance-chain/bsc/pull/61)Add `x-forward-for` log message when handle message failed -* [\#60](https://github.com/binance-chain/bsc/pull/61) add rpc method request gauge +* [\#61](https://github.com/bnb-chain/bsc/pull/61)Add `x-forward-for` log message when handle message failed +* [\#60](https://github.com/bnb-chain/bsc/pull/61) add rpc method request gauge BUGFIX -* [\#59](https://github.com/binance-chain/bsc/pull/59) fix potential deadlock of pub/sub module +* [\#59](https://github.com/bnb-chain/bsc/pull/59) fix potential deadlock of pub/sub module ## v1.0.4 IMPROVEMENT -* [\#35](https://github.com/binance-chain/bsc/pull/35) use fixed gas price when network is idle -* [\#38](https://github.com/binance-chain/bsc/pull/38) disable noisy log from consensus engine -* [\#47](https://github.com/binance-chain/bsc/pull/47) upgrade to golang1.15.5 -* [\#49](https://github.com/binance-chain/bsc/pull/49) Create pull request template for all developer to follow +* [\#35](https://github.com/bnb-chain/bsc/pull/35) use fixed gas price when network is idle +* [\#38](https://github.com/bnb-chain/bsc/pull/38) disable noisy log from consensus engine +* [\#47](https://github.com/bnb-chain/bsc/pull/47) upgrade to golang1.15.5 +* [\#49](https://github.com/bnb-chain/bsc/pull/49) Create pull request template for all developer to follow ## v1.0.3 IMPROVEMENT -* [\#36](https://github.com/binance-chain/bsc/pull/36) add max gas allwance calculation +* [\#36](https://github.com/bnb-chain/bsc/pull/36) add max gas allwance calculation ## v1.0.2 IMPROVEMENT -* [\#29](https://github.com/binance-chain/bsc/pull/29) eth/tracers: revert reason in call_tracer + error for failed internal… +* [\#29](https://github.com/bnb-chain/bsc/pull/29) eth/tracers: revert reason in call_tracer + error for failed internal… ## v1.0.1-beta IMPROVEMENT -* [\#22](https://github.com/binance-chain/bsc/pull/22) resolve best practice advice +* [\#22](https://github.com/bnb-chain/bsc/pull/22) resolve best practice advice FEATURES -* [\#23](https://github.com/binance-chain/bsc/pull/23) enforce backoff time for out-turn validator +* [\#23](https://github.com/bnb-chain/bsc/pull/23) enforce backoff time for out-turn validator BUGFIX -* [\#25](https://github.com/binance-chain/bsc/pull/25) minor fix for ramanujan upgrade +* [\#25](https://github.com/bnb-chain/bsc/pull/25) minor fix for ramanujan upgrade UPGRADE -* [\#26](https://github.com/binance-chain/bsc/pull/26) update chapel network config for ramanujan fork +* [\#26](https://github.com/bnb-chain/bsc/pull/26) update chapel network config for ramanujan fork ## v1.0.0-beta.0 FEATURES -* [\#5](https://github.com/binance-chain/bsc/pull/5) enable bep2e tokens for faucet -* [\#14](https://github.com/binance-chain/bsc/pull/14) add cross chain contract to system contract -* [\#15](https://github.com/binance-chain/bsc/pull/15) Allow liveness slash fail +* [\#5](https://github.com/bnb-chain/bsc/pull/5) enable bep2e tokens for faucet +* [\#14](https://github.com/bnb-chain/bsc/pull/14) add cross chain contract to system contract +* [\#15](https://github.com/bnb-chain/bsc/pull/15) Allow liveness slash fail IMPROVEMENT -* [\#11](https://github.com/binance-chain/bsc/pull/11) remove redundant gaslimit check +* [\#11](https://github.com/bnb-chain/bsc/pull/11) remove redundant gaslimit check BUGFIX -* [\#4](https://github.com/binance-chain/bsc/pull/4) fix validator failed to sync a block produced by itself -* [\#6](https://github.com/binance-chain/bsc/pull/6) modify params for Parlia consensus with 21 validators -* [\#10](https://github.com/binance-chain/bsc/pull/10) add gas limit check in parlia implement -* [\#13](https://github.com/binance-chain/bsc/pull/13) fix debug_traceTransaction crashed issue +* [\#4](https://github.com/bnb-chain/bsc/pull/4) fix validator failed to sync a block produced by itself +* [\#6](https://github.com/bnb-chain/bsc/pull/6) modify params for Parlia consensus with 21 validators +* [\#10](https://github.com/bnb-chain/bsc/pull/10) add gas limit check in parlia implement +* [\#13](https://github.com/bnb-chain/bsc/pull/13) fix debug_traceTransaction crashed issue From fe2d84bd4a0511e44bd0066097e5e358bb1eda3c Mon Sep 17 00:00:00 2001 From: forcodedancing Date: Thu, 12 May 2022 10:07:01 +0800 Subject: [PATCH 102/117] improve snap mutex --- core/state/state_object.go | 4 ++-- core/state/statedb.go | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index b40a8a2f85..e1621a9d02 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -412,7 +412,7 @@ func (s *StateObject) updateTrie(db Database) Trie { } // If state snapshotting is active, cache the data til commit if s.db.snap != nil { - s.db.snapMux.Lock() + s.db.snapStorageMux.Lock() if storage == nil { // Retrieve the old storage map, if available, create a new one otherwise if storage = s.db.snapStorage[s.address]; storage == nil { @@ -421,7 +421,7 @@ func (s *StateObject) updateTrie(db Database) Trie { } } storage[string(key[:])] = v // v will be nil if value is 0x00 - s.db.snapMux.Unlock() + s.db.snapStorageMux.Unlock() } usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure } diff --git a/core/state/statedb.go b/core/state/statedb.go index ade1b5804f..fd81148826 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -90,12 +90,13 @@ type StateDB struct { fullProcessed bool pipeCommit bool - snapMux sync.Mutex - snaps *snapshot.Tree - snap snapshot.Snapshot - snapDestructs map[common.Address]struct{} - snapAccounts map[common.Address][]byte - snapStorage map[common.Address]map[string][]byte + snaps *snapshot.Tree + snap snapshot.Snapshot + snapAccountMux sync.Mutex // Mutex for snap account access + snapStorageMux sync.Mutex // Mutex for snap storage access + snapDestructs map[common.Address]struct{} + snapAccounts map[common.Address][]byte + snapStorage map[common.Address]map[string][]byte // This map holds 'live' objects, which will get modified while processing a state transition. stateObjects map[common.Address]*StateObject @@ -1078,10 +1079,10 @@ func (s *StateDB) AccountsIntermediateRoot() { // enough to track account updates at commit time, deletions need tracking // at transaction boundary level to ensure we capture state clearing. if s.snap != nil && !obj.deleted { - s.snapMux.Lock() + s.snapAccountMux.Lock() // It is possible to add unnecessary change, but it is fine. s.snapAccounts[obj.address] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash) - s.snapMux.Unlock() + s.snapAccountMux.Unlock() } data, err := rlp.EncodeToBytes(obj) if err != nil { From b8413b129e9d2f2f559cb803c2303e0bcaa00ed5 Mon Sep 17 00:00:00 2001 From: goth Date: Thu, 26 May 2022 09:44:58 +0800 Subject: [PATCH 103/117] chores: add BEP-127 operation readme --- docs/parlia/README-BEP-127.md | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/parlia/README-BEP-127.md diff --git a/docs/parlia/README-BEP-127.md b/docs/parlia/README-BEP-127.md new file mode 100644 index 0000000000..f79b07141f --- /dev/null +++ b/docs/parlia/README-BEP-127.md @@ -0,0 +1,47 @@ +## BEP-127: Temporary Maintenance Mode for Validators + +Temporary Maintenance is supposed to last one or a few hours. The validator seat will be temporarily dropped from the block producing rotation during the maintenance. Since long-time offline maintenance is not encouraged, the validator will still be slashed if the maintenance lasts too long. To lower the impact from poorly-operating validators who forget to claim its maintenance, they will be forced to enter Temporary Maintenance mode too. + +- **enterMaintenance**: Validator can claim itself to enter scheduled maintenance by sending a transaction signed by the consensus key. +- **exitMaintenance**: The validator can claim itself to exit maintenance by sending another transaction. + +More details in [BEP-127](https://github.com/bnb-chain/BEPs/blob/master/BEP127.md). + + +## How to enter/exit maintenance + +### Running `geth` +make sure you have unlocked the consensus address of your validator + +### Running `built-in interactive` +```shell +$ geth attach geth.ipc +``` + +This command will: +* Start up `geth`'s 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://web3js.readthedocs.io/en/) + (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). + + +### enter maintenance +``` +web3.eth.sendTransaction({ + from: "consensus address of your validator", + to: "0x0000000000000000000000000000000000001000", + data: "0x9369d7de" +}) +``` + +### exit maintenance +``` +web3.eth.sendTransaction({ + from: "consensus address of your validator", + to: "0x0000000000000000000000000000000000001000", + data: "0x04c4fec6" +}) +``` + + + From fea1c96d28cff2d0103185aaf441935ac8a7da9e Mon Sep 17 00:00:00 2001 From: flywukong <2229306838@qq.com> Date: Sat, 7 May 2022 16:55:17 +0800 Subject: [PATCH 104/117] asynchronous update snap in updatetrie --- core/state/state_object.go | 46 +++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index e1621a9d02..ad6fbf5f89 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -390,12 +390,11 @@ func (s *StateObject) updateTrie(db Database) Trie { s.db.MetricsMux.Unlock() }(time.Now()) } - // The snapshot storage map for the object - var storage map[string][]byte // Insert all the pending updates into the trie tr := s.getTrie(db) usedStorage := make([][]byte, 0, len(s.pendingStorage)) + dirtyStorage := make(map[common.Hash][]byte) for key, value := range s.pendingStorage { // Skip noop changes, persist actual changes if value == s.originStorage[key] { @@ -403,28 +402,45 @@ func (s *StateObject) updateTrie(db Database) Trie { } s.originStorage[key] = value var v []byte - if (value == common.Hash{}) { - s.setError(tr.TryDelete(key[:])) - } else { + if (value != common.Hash{}) { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - s.setError(tr.TryUpdate(key[:], v)) } + dirtyStorage[key] = v + } + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + for key, value := range dirtyStorage { + if len(value) == 0 { + s.setError(tr.TryDelete(key[:])) + } else { + s.setError(tr.TryUpdate(key[:], value)) + } + usedStorage = append(usedStorage, common.CopyBytes(key[:])) + } + }() + if s.db.snap != nil { // If state snapshotting is active, cache the data til commit - if s.db.snap != nil { + wg.Add(1) + go func() { + defer wg.Done() s.db.snapStorageMux.Lock() + // The snapshot storage map for the object + storage := s.db.snapStorage[s.address] if storage == nil { - // Retrieve the old storage map, if available, create a new one otherwise - if storage = s.db.snapStorage[s.address]; storage == nil { - storage = make(map[string][]byte) - s.db.snapStorage[s.address] = storage - } + storage = make(map[string][]byte, len(dirtyStorage)) + s.db.snapStorage[s.address] = storage + } + for key, value := range dirtyStorage { + storage[string(key[:])] = value } - storage[string(key[:])] = v // v will be nil if value is 0x00 s.db.snapStorageMux.Unlock() - } - usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure + }() } + wg.Wait() + if s.db.prefetcher != nil { s.db.prefetcher.used(s.data.Root, usedStorage) } From 0080707fc73f514fa9a448f31ff54c85e8178d4d Mon Sep 17 00:00:00 2001 From: cosinlink Date: Tue, 7 Jun 2022 16:52:10 +0800 Subject: [PATCH 105/117] feat: update Euler Fork blockNumber --- params/config.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/params/config.go b/params/config.go index fbf4c4259b..8c3fb1c8e7 100644 --- a/params/config.go +++ b/params/config.go @@ -255,9 +255,7 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(5184000), BrunoBlock: big.NewInt(13082000), - - // TODO modify blockNumber - EulerBlock: nil, + EulerBlock: big.NewInt(18907621), Parlia: &ParliaConfig{ Period: 3, @@ -303,9 +301,7 @@ var ( NielsBlock: big.NewInt(0), MirrorSyncBlock: big.NewInt(400), BrunoBlock: big.NewInt(400), - - // TODO - EulerBlock: nil, + EulerBlock: nil, Parlia: &ParliaConfig{ Period: 3, From 979bb8fca9c3bb1de7a79c1bd214a4033b55c52a Mon Sep 17 00:00:00 2001 From: cosinlink Date: Tue, 7 Jun 2022 17:19:26 +0800 Subject: [PATCH 106/117] feat: add release info of BSC v1.1.11 --- CHANGELOG.md | 7 +++++++ README.md | 2 +- params/version.go | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 626151225c..deefb9d12a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## v1.1.11 + +UPGRADE +* [\#927](https://github.com/bnb-chain/bsc/pull/927) add readme for validators about how to enter/exit maintenance +* [\#942](https://github.com/bnb-chain/bsc/pull/942) update the blockNumber of Euler Fork upgrade on BSC Mainnet + + ## v1.1.10 FEATURE diff --git a/README.md b/README.md index c8833941ad..394281dadb 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ This command will: Steps: -1. Download the binary, config and genesis files from [release](https://github.com/bnb-chain/bsc/releases/tag/v1.1.10), or compile the binary by `make geth`. +1. Download the binary, config and genesis files from [release](https://github.com/bnb-chain/bsc/releases/tag/v1.1.11), or compile the binary by `make geth`. 2. Init genesis state: `./geth --datadir node init genesis.json`. 3. Start your fullnode: `./geth --config ./config.toml --datadir ./node`. 4. Or start a validator node: `./geth --config ./config.toml --datadir ./node -unlock ${validatorAddr} --mine --allow-insecure-unlock`. The ${validatorAddr} is the wallet account address of your running validator node. diff --git a/params/version.go b/params/version.go index d4a04cfba2..0dc16e482a 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 10 // Patch version component of the current release + VersionPatch = 11 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From 02e91287d6f3b062e4843e4bf5afabcb0c9bcc00 Mon Sep 17 00:00:00 2001 From: RumeelHussainbnb <93580180+RumeelHussainbnb@users.noreply.github.com> Date: Fri, 10 Jun 2022 13:22:59 +0500 Subject: [PATCH 107/117] Updated Links to docs.bnbchain.org --- README.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 394281dadb..32a0951e08 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -## Binance Smart Chain +## BNB Smart Chain -The goal of Binance Smart Chain is to bring programmability and interoperability to Binance Chain. In order to embrace the existing popular community and advanced technology, it will bring huge benefits by staying compatible with all the existing smart contracts on Ethereum and Ethereum tooling. And to achieve that, the easiest solution is to develop based on go-ethereum fork, as we respect the great work of Ethereum very much. +The goal of BNB Smart Chain is to bring programmability and interoperability to Binance Chain. In order to embrace the existing popular community and advanced technology, it will bring huge benefits by staying compatible with all the existing smart contracts on Ethereum and Ethereum tooling. And to achieve that, the easiest solution is to develop based on go-ethereum fork, as we respect the great work of Ethereum very much. -Binance Smart Chain starts its development based on go-ethereum fork. So you may see many toolings, binaries and also docs are based on Ethereum ones, such as the name “geth”. +BNB Smart Chain starts its development based on go-ethereum fork. So you may see many toolings, binaries and also docs are based on Ethereum ones, such as the name “geth”. [![API Reference]( https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 @@ -18,7 +18,7 @@ Cross-chain transfer and other communication are possible due to native support - **Interoperable**: Comes with efficient native dual chain communication; Optimized for scaling high-performance dApps that require fast and smooth user experience. - **Distributed with on-chain governance**: Proof of Staked Authority brings in decentralization and community participants. As the native token, BNB will serve as both the gas of smart contract execution and tokens for staking. -More details in [White Paper](http://binance.org/en#smartChain). +More details in [White Paper](https://www.bnbchain.org/en#smartChain). ## Key features @@ -36,7 +36,7 @@ To combine DPoS and PoA for consensus, Binance Smart Chain implement a novel con 2. Validators take turns to produce blocks in a PoA manner, similar to Ethereum's Clique consensus engine. 3. Validator set are elected in and out based on a staking based governance on Binance Chain. 4. The validator set change is relayed via a cross-chain communication mechanism. -5. Parlia consensus engine will interact with a set of [system contracts](https://github.com/binance-chain/docs-site/blob/add-bsc/docs/smart-chain/guides/concepts/system-contract.md) to achieve liveness slash, revenue distributing and validator set renewing func. +5. Parlia consensus engine will interact with a set of [system contracts](https://docs.bnbchain.org/docs/learn/system-contract) to achieve liveness slash, revenue distributing and validator set renewing func. ### Light Client of Binance Chain @@ -44,8 +44,8 @@ To combine DPoS and PoA for consensus, Binance Smart Chain implement a novel con To achieve the cross-chain communication from Binance Chain to Binance Smart Chain, need introduce a on-chain light client verification algorithm. It contains two parts: -1. [Stateless Precompiled contracts](https://github.com/binance-chain/bsc/blob/master/core/vm/contracts_lightclient.go) to do tendermint header verification and Merkle Proof verification. -2. [Stateful solidity contracts](https://github.com/binance-chain/bsc-genesis-contract/blob/master/contracts/TendermintLightClient.sol) to store validator set and trusted appHash. +1. [Stateless Precompiled contracts](https://github.com/bnb-chain/bsc/blob/master/core/vm/contracts_lightclient.go) to do tendermint header verification and Merkle Proof verification. +2. [Stateful solidity contracts](https://github.com/bnb-chain/bsc-genesis-contract/blob/master/contracts/TendermintLightClient.sol) to store validator set and trusted appHash. ## Native Token @@ -131,7 +131,9 @@ Steps: *Note: The default p2p port is 30311 and the RPC port is 8575 which is different from Ethereum.* -More details about [running a node](https://docs.binance.org/smart-chain/developer/fullnode.html) and [becoming a validator](https://docs.binance.org/smart-chain/validator/candidate.html). +More details about [running a node](https://docs.bnbchain.org/docs/validator/fullnode) and [becoming a validator](https://docs.bnbchain.org/docs/validator/testnet/) + + *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 @@ -230,4 +232,4 @@ also included in our repository in the `COPYING.LESSER` file. The bsc binaries (i.e. all code inside of the `cmd` directory) is 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. \ No newline at end of file +included in our repository in the `COPYING` file. From 85371535d787792a761bfe855e3add632d024163 Mon Sep 17 00:00:00 2001 From: WayToFuture Date: Mon, 13 Jun 2022 16:40:14 +0800 Subject: [PATCH 108/117] fix pipecommit issue (#932) --- core/state/statedb.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index fd81148826..d4d02ad039 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -901,9 +901,9 @@ func (s *StateDB) GetRefund() uint64 { return s.refund } -// GetRefund returns the current value of the refund counter. +// WaitPipeVerification waits until the snapshot been verified func (s *StateDB) WaitPipeVerification() error { - // We need wait for the parent trie to commit + // Need to wait for the parent trie to commit if s.snap != nil { if valid := s.snap.WaitAndGetVerifyRes(); !valid { return fmt.Errorf("verification on parent snap failed") @@ -990,7 +990,7 @@ func (s *StateDB) CorrectAccountsRoot(blockRoot common.Hash) { if accounts, err := snapshot.Accounts(); err == nil && accounts != nil { for _, obj := range s.stateObjects { if !obj.deleted && !obj.rootCorrected && obj.data.Root == dummyRoot { - if account, exist := accounts[crypto.Keccak256Hash(obj.address[:])]; exist && len(account.Root) != 0 { + if account, exist := accounts[crypto.Keccak256Hash(obj.address[:])]; exist { obj.data.Root = common.BytesToHash(account.Root) obj.rootCorrected = true } @@ -1003,7 +1003,7 @@ func (s *StateDB) CorrectAccountsRoot(blockRoot common.Hash) { func (s *StateDB) PopulateSnapAccountAndStorage() { for addr := range s.stateObjectsPending { if obj := s.stateObjects[addr]; !obj.deleted { - if s.snap != nil && !obj.deleted { + if s.snap != nil { root := obj.data.Root storageChanged := s.populateSnapStorage(obj) if storageChanged { @@ -1078,7 +1078,7 @@ func (s *StateDB) AccountsIntermediateRoot() { // update mechanism is not symmetric to the deletion, because whereas it is // enough to track account updates at commit time, deletions need tracking // at transaction boundary level to ensure we capture state clearing. - if s.snap != nil && !obj.deleted { + if s.snap != nil { s.snapAccountMux.Lock() // It is possible to add unnecessary change, but it is fine. s.snapAccounts[obj.address] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash) From 28f80903ddc57f5fd47b8fc594fa7e626a3f4619 Mon Sep 17 00:00:00 2001 From: setunapo Date: Fri, 17 Jun 2022 12:18:29 +0800 Subject: [PATCH 109/117] Improve StatePrefetch, use AsMessageNoNonceCheck to skip nonce check For state prefetch, no need to check transaction's nonce, since the transaction's result will be discarded anyway. --- core/state_prefetcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index a2c2df16a4..4a731d8dfe 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -79,7 +79,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) + msg, err := tx.AsMessageNoNonceCheck(signer) if err != nil { return // Also invalid block, bail out } From 8c36d29f99628057b9d1e02425155214fb1b0440 Mon Sep 17 00:00:00 2001 From: setunapo Date: Fri, 17 Jun 2022 15:14:23 +0800 Subject: [PATCH 110/117] Improve the state prefetch dispatch policy ** replace atomic read by channel close to interrupt state prefetch ** try to do state prefetch when the prefetch thread is idle, no need to divide into 3 sub-arrays it will make the prefetchers workload balance --- core/blockchain.go | 9 ++++---- core/state_prefetcher.go | 48 ++++++++++++++++++++-------------------- core/types.go | 2 +- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index eeaf1b7e0a..d1a99c12f8 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2114,13 +2114,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") - var followupInterrupt uint32 + interruptCh := make(chan struct{}) // For diff sync, it may fallback to full sync, so we still do prefetch if len(block.Transactions()) >= prefetchTxNumber { throwaway := statedb.Copy() - go func(start time.Time, followup *types.Block, throwaway *state.StateDB, interrupt *uint32) { - bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) - }(time.Now(), block, throwaway, &followupInterrupt) + // do Prefetch in a separate goroutine to avoid blocking the critical path + go bc.prefetcher.Prefetch(block, throwaway, &bc.vmConfig, interruptCh) } //Process block using the parent state as reference point substart := time.Now() @@ -2129,7 +2128,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er } statedb.SetExpectedStateRoot(block.Root()) statedb, receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) - atomic.StoreUint32(&followupInterrupt, 1) + close(interruptCh) // state prefetch can be stopped activeState = statedb if err != nil { bc.reportBlock(block, receipts, err) diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 4a731d8dfe..5936fa4a07 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -17,8 +17,6 @@ package core import ( - "sync/atomic" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -50,43 +48,45 @@ 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 snapshot clean state. -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, interruptCh <-chan struct{}) { var ( header = block.Header() signer = types.MakeSigner(p.config, header.Number) ) transactions := block.Transactions() - sortTransactions := make([][]*types.Transaction, prefetchThread) - for i := 0; i < prefetchThread; i++ { - sortTransactions[i] = make([]*types.Transaction, 0, len(transactions)/prefetchThread) - } - for idx := range transactions { - threadIdx := idx % prefetchThread - sortTransactions[threadIdx] = append(sortTransactions[threadIdx], transactions[idx]) - } + txChan := make(chan int, prefetchThread) // No need to execute the first batch, since the main processor will do it. for i := 0; i < prefetchThread; i++ { - go func(idx int) { + go func() { newStatedb := statedb.Copy() newStatedb.EnableWriteOnSharedStorage() gaspool := new(GasPool).AddGas(block.GasLimit()) blockContext := NewEVMBlockContext(header, p.bc, nil) - evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) + evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, *cfg) // Iterate over and process the individual transactions - for i, tx := range sortTransactions[idx] { - // If block precaching was interrupted, abort - if interrupt != nil && atomic.LoadUint32(interrupt) == 1 { + for { + select { + case txIndex := <-txChan: + tx := transactions[txIndex] + // Convert the transaction into an executable message and pre-cache its sender + msg, err := tx.AsMessageNoNonceCheck(signer) + if err != nil { + return // Also invalid block, bail out + } + newStatedb.Prepare(tx.Hash(), header.Hash(), txIndex) + precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm) + + case <-interruptCh: + // If block precaching was interrupted, abort return } - // Convert the transaction into an executable message and pre-cache its sender - msg, err := tx.AsMessageNoNonceCheck(signer) - if err != nil { - return // Also invalid block, bail out - } - newStatedb.Prepare(tx.Hash(), header.Hash(), i) - precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm) } - }(i) + }() + } + + // it should be in a separate goroutine, to avoid blocking the critical path. + for i := 0; i < len(transactions); i++ { + txChan <- i } } diff --git a/core/types.go b/core/types.go index c9061233e6..7736ebacd1 100644 --- a/core/types.go +++ b/core/types.go @@ -39,7 +39,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, interruptCh <-chan struct{}) // PrefetchMining used for pre-caching transaction signatures and state trie nodes. Only used for mining stage. PrefetchMining(txs *types.TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction) } From ebceb251766cc8ef165f44855b8d0c0f245f7b72 Mon Sep 17 00:00:00 2001 From: qinglin89 <316032931@qq.com> Date: Mon, 20 Jun 2022 18:47:25 +0800 Subject: [PATCH 111/117] fix:correct logic for eip check of NewEVMInterpreter --- core/vm/interpreter.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 1155037a1e..23c3cc7284 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -122,13 +122,15 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { default: jt = frontierInstructionSet } - for i, eip := range cfg.ExtraEips { - if err := EnableEIP(eip, &jt); err != nil { + for i := 0; i < len(cfg.ExtraEips); i++ { + if err := EnableEIP(cfg.ExtraEips[i], &jt); 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) + i-- + log.Error("EIP activation failed", "eip", cfg.ExtraEips[i], "error", err) } } + cfg.JumpTable = jt } evmInterpreter := EVMInterpreterPool.Get().(*EVMInterpreter) From 0137f20a312ed4dc952e9ac642878ff44405e676 Mon Sep 17 00:00:00 2001 From: qinglin89 <316032931@qq.com> Date: Tue, 21 Jun 2022 12:36:59 +0800 Subject: [PATCH 112/117] refactor: cuncurrency safe for state_prefetcher --- core/vm/interpreter.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 23c3cc7284..1ecd7b3ce8 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -122,15 +122,16 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { default: jt = frontierInstructionSet } - for i := 0; i < len(cfg.ExtraEips); i++ { - if err := EnableEIP(cfg.ExtraEips[i], &jt); err != nil { + var extraEips []int + for _, eip := range cfg.ExtraEips { + if err := EnableEIP(eip, &jt); err != nil { // Disable it, so caller can check if it's activated or not - cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...) - i-- - log.Error("EIP activation failed", "eip", cfg.ExtraEips[i], "error", err) + log.Error("EIP activation failed", "eip", eip, "error", err) + } else { + extraEips = append(extraEips, eip) } } - + cfg.ExtraEips = extraEips cfg.JumpTable = jt } evmInterpreter := EVMInterpreterPool.Get().(*EVMInterpreter) From 4b8c03b129f472b088d77e6b4602d7ca9f97a875 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 7 Mar 2022 18:25:45 +0100 Subject: [PATCH 113/117] p2p: define DiscReason as uint8 (#24507) All other implementations store disconnect reasons as a single byte, so go-ethereum should do it too. --- p2p/peer.go | 6 +++--- p2p/peer_error.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/p2p/peer.go b/p2p/peer.go index 7b9e4d5940..5e6ef0732e 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -337,11 +337,11 @@ func (p *Peer) handle(msg Msg) error { SendItems(p.rw, pongMsg) }) case msg.Code == discMsg: - var reason [1]DiscReason // This is the last message. We don't need to discard or // check errors because, the connection will be closed after it. - rlp.Decode(msg.Payload, &reason) - return reason[0] + var m struct{ R DiscReason } + rlp.Decode(msg.Payload, &m) + return m.R case msg.Code < baseProtocolLength: // ignore other base protocol messages return msg.Discard() diff --git a/p2p/peer_error.go b/p2p/peer_error.go index ab61bfef06..b0130515d3 100644 --- a/p2p/peer_error.go +++ b/p2p/peer_error.go @@ -54,7 +54,7 @@ func (pe *peerError) Error() string { var errProtocolReturned = errors.New("protocol returned") -type DiscReason uint +type DiscReason uint8 const ( DiscRequested DiscReason = iota From fcfc57feb3b4cdc1913ea74a215986e5d2675430 Mon Sep 17 00:00:00 2001 From: Keefe-Liu Date: Thu, 23 Jun 2022 03:03:36 +0800 Subject: [PATCH 114/117] upgrade docker version to 1.6.1 --- go.mod | 3 +-- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index c58a45dfd2..f11dcc87af 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea github.com/dlclark/regexp2 v1.2.0 // indirect - github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf + github.com/docker/docker v1.6.1 github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 github.com/edsrzf/mmap-go v1.0.0 github.com/etcd-io/bbolt v1.3.3 // indirect @@ -81,5 +81,4 @@ require ( gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/urfave/cli.v1 v1.20.0 - gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 6ab7ca8c45..3eb5f16744 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,8 @@ 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.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmakYiSlqu2425CHyFXLZZnvm7PDpU8M= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.6.1 h1:4xYASHy5cScPkLD7PO0uTmnVc860m9NarPN1X8zeMe8= +github.com/docker/docker v1.6.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 h1:Y9vTBSsV4hSwPSj4bacAU/eSnV3dAxVpepaghAdhGoQ= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= @@ -633,8 +633,6 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 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 5ef4a2b329354466304aaafd7324925307f24b12 Mon Sep 17 00:00:00 2001 From: Keefe-Liu Date: Thu, 23 Jun 2022 03:05:11 +0800 Subject: [PATCH 115/117] upgrade gogo/protobuf to version v1.3.2 --- go.mod | 5 +++++ go.sum | 13 ++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index f11dcc87af..8a4f2dd2bb 100644 --- a/go.mod +++ b/go.mod @@ -82,3 +82,8 @@ require ( gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/urfave/cli.v1 v1.20.0 ) + +replace ( + github.com/gogo/protobuf v1.1.1 => github.com/gogo/protobuf v1.3.2 + github.com/gogo/protobuf v1.3.1 => github.com/gogo/protobuf v1.3.2 +) diff --git a/go.sum b/go.sum index 3eb5f16744..247e4cd33a 100644 --- a/go.sum +++ b/go.sum @@ -161,9 +161,8 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG 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/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 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -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/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 h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -257,7 +256,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -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/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -405,6 +404,7 @@ github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:s github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= 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/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -450,6 +450,7 @@ 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.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/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -468,6 +469,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL 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-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= 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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -532,7 +534,6 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2Y golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/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-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= @@ -556,6 +557,8 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/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-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.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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= From d6b9bdbc84590de7d7b8dc98ff5253dbbe56dce6 Mon Sep 17 00:00:00 2001 From: joeycli <1297465889@qq.com> Date: Wed, 29 Jun 2022 18:47:25 +0800 Subject: [PATCH 116/117] add prune ancient feature (#862) * add prune ancient feature * change notes and log for pr suggest * change StableStateBloc to SafePointBlock and enhanced 'pruneancient' flag hints * change pruneancient usage * fix note misspelling * fix set SafePointBlockNumber by mpt height replace current block number Co-authored-by: user --- cmd/geth/main.go | 1 + cmd/geth/pruneblock_test.go | 4 +- cmd/utils/flags.go | 13 +- core/blockchain.go | 12 ++ core/blockchain_repair_test.go | 4 +- core/blockchain_sethead_test.go | 2 +- core/blockchain_snapshot_test.go | 4 +- core/blockchain_test.go | 18 +- core/headerchain.go | 1 + core/rawdb/accessors_chain_test.go | 2 +- core/rawdb/accessors_metadata.go | 87 +++++++++ core/rawdb/chain_iterator.go | 6 + core/rawdb/database.go | 59 +++--- core/rawdb/freezer.go | 159 ++++++++-------- core/rawdb/prunedfreezer.go | 285 +++++++++++++++++++++++++++++ core/rawdb/schema.go | 9 + core/state/pruner/pruner.go | 2 +- eth/backend.go | 2 +- eth/ethconfig/config.go | 1 + eth/ethconfig/gen_config.go | 6 + eth/handler.go | 4 + eth/sync.go | 5 + node/node.go | 8 +- params/network_params.go | 3 + 24 files changed, 563 insertions(+), 134 deletions(-) create mode 100644 core/rawdb/prunedfreezer.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index e0f29bce77..5187971423 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -125,6 +125,7 @@ var ( utils.CachePreimagesFlag, utils.PersistDiffFlag, utils.DiffBlockFlag, + utils.PruneAncientDataFlag, utils.ListenPortFlag, utils.MaxPeersFlag, utils.MaxPendingPeersFlag, diff --git a/cmd/geth/pruneblock_test.go b/cmd/geth/pruneblock_test.go index 7d78f444fa..78b1d343b5 100644 --- a/cmd/geth/pruneblock_test.go +++ b/cmd/geth/pruneblock_test.go @@ -93,7 +93,7 @@ func testOfflineBlockPruneWithAmountReserved(t *testing.T, amountReserved uint64 t.Fatalf("Failed to back up block: %v", err) } - dbBack, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindbPath, 0, 0, newAncientPath, "", false, true, false) + dbBack, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindbPath, 0, 0, newAncientPath, "", false, true, false, false) if err != nil { t.Fatalf("failed to create database with ancient backend") } @@ -139,7 +139,7 @@ func testOfflineBlockPruneWithAmountReserved(t *testing.T, amountReserved uint64 func BlockchainCreator(t *testing.T, chaindbPath, AncientPath string, blockRemain uint64) (ethdb.Database, []*types.Block, []*types.Block, []types.Receipts, []*big.Int, uint64, *core.BlockChain) { //create a database with ancient freezer - db, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindbPath, 0, 0, AncientPath, "", false, false, false) + db, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindbPath, 0, 0, AncientPath, "", false, false, false, false) if err != nil { t.Fatalf("failed to create database with ancient backend") } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 85d1cef887..218ecfcf3c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -457,6 +457,10 @@ var ( Usage: "The number of blocks should be persisted in db (default = 86400)", Value: uint64(86400), } + PruneAncientDataFlag = cli.BoolFlag{ + Name: "pruneancient", + Usage: "Prune ancient data, recommends to the user who don't care about the ancient data. Note that once be turned on, the ancient data will not be recovered again", + } // Miner settings MiningEnabledFlag = cli.BoolFlag{ Name: "mine", @@ -1621,6 +1625,13 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(DiffBlockFlag.Name) { cfg.DiffBlock = ctx.GlobalUint64(DiffBlockFlag.Name) } + if ctx.GlobalIsSet(PruneAncientDataFlag.Name) { + if cfg.SyncMode == downloader.FullSync { + cfg.PruneAncientData = ctx.GlobalBool(PruneAncientDataFlag.Name) + } else { + log.Crit("pruneancient parameter didn't take effect for current syncmode") + } + } if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } @@ -1914,7 +1925,7 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly, disableFree chainDb, err = stack.OpenDatabase(name, cache, handles, "", readonly) } else { name := "chaindata" - chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly, disableFreeze, false) + chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly, disableFreeze, false, false) } if err != nil { Fatalf("Could not open database: %v", err) diff --git a/core/blockchain.go b/core/blockchain.go index d1a99c12f8..9eb3154cbe 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -441,6 +441,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par } bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, int(bc.cacheConfig.TriesInMemory), head.Root(), !bc.cacheConfig.SnapshotWait, true, recover) } + // write safe point block number + rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().NumberU64()) // do options before start any routine for _, option := range options { bc = option(bc) @@ -543,6 +545,7 @@ func (bc *BlockChain) loadLastState() error { 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())) @@ -927,6 +930,7 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { // Note, this function assumes that the `mu` mutex is held! func (bc *BlockChain) writeHeadBlock(block *types.Block) { // If the block is on a side chain or an unknown one, force other heads onto it too + // read from kvdb, has nothing to do with ancientdb type updateHeads := rawdb.ReadCanonicalHash(bc.db, block.NumberU64()) != block.Hash() // Add the block to the canonical chain number scheme and mark as the head @@ -1258,6 +1262,8 @@ func (bc *BlockChain) Stop() { 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 { log.Error("Failed to commit recent state trie", "err", err) + } else { + rawdb.WriteSafePointBlockNumber(bc.db, recent.NumberU64()) } } } @@ -1265,6 +1271,8 @@ func (bc *BlockChain) Stop() { log.Info("Writing snapshot state to disk", "root", snapBase) if err := triedb.Commit(snapBase, true, nil); err != nil { log.Error("Failed to commit recent state trie", "err", err) + } else { + rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().NumberU64()) } } for !bc.triegc.Empty() { @@ -1764,6 +1772,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } // Flush an entire trie and restart the counters triedb.Commit(header.Root, true, nil) + rawdb.WriteSafePointBlockNumber(bc.db, chosen) lastWrite = chosen bc.gcproc = 0 } @@ -2354,6 +2363,9 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i for i := len(hashes) - 1; i >= 0; i-- { // Append the next block to our batch block := bc.GetBlock(hashes[i], numbers[i]) + if block == nil { + log.Crit("Importing heavy sidechain block is nil", "hash", hashes[i], "number", numbers[i]) + } blocks = append(blocks, block) memory += block.Size() diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index b85f9c9e00..8edfe76c1a 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1762,7 +1762,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { } os.RemoveAll(datadir) - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false) + db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false, false) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -1832,7 +1832,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { db.Close() // Start a new blockchain back up and see where the repait leads us - db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false) + db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false, false) 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 bdcca988a3..2632da65e0 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1961,7 +1961,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { } os.RemoveAll(datadir) - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false) + db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false, false) 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 530ad035dd..cbab105293 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -64,7 +64,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo } os.RemoveAll(datadir) - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false) + db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false, false, false, false) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -248,7 +248,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { db.Close() // Start a new blockchain back up and see where the repair leads us - newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false, false, false) + newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false, false, false, false) if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 07cb51933a..f7a4ff53f1 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -761,7 +761,7 @@ func TestFastVsFullChains(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -835,7 +835,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(dir) - db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false) + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -1702,7 +1702,7 @@ func TestBlockchainRecovery(t *testing.T) { } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -1759,7 +1759,7 @@ func TestIncompleteAncientReceiptChainInsertion(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -1958,7 +1958,7 @@ func testInsertKnownChainData(t *testing.T, typ string) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(dir) - chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false) + chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2238,7 +2238,7 @@ func TestTransactionIndices(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2266,7 +2266,7 @@ func TestTransactionIndices(t *testing.T) { // 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, false, false) + ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2286,7 +2286,7 @@ func TestTransactionIndices(t *testing.T) { } // Reconstruct a block chain which only reserves HEAD-64 tx indices - ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) + ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } @@ -2365,7 +2365,7 @@ func TestSkipStaleTxIndicesInFastSync(t *testing.T) { t.Fatalf("failed to create temp freezer dir: %v", err) } defer os.Remove(frdir) - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } diff --git a/core/headerchain.go b/core/headerchain.go index 3e50c1eb07..2849468dee 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -250,6 +250,7 @@ func (hc *HeaderChain) writeHeaders(headers []*types.Header) (result *headerWrit headHeader = hc.GetHeader(headHash, headNumber) ) for rawdb.ReadCanonicalHash(hc.chainDb, headNumber) != headHash { + // backtracking to ancientdb if frozen, _ := hc.chainDb.Ancients(); frozen == headNumber { break } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index f99511e456..b38c843dc6 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -440,7 +440,7 @@ func TestAncientStorage(t *testing.T) { } defer os.Remove(frdir) - db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false) + db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false, false) if err != nil { t.Fatalf("failed to create database with ancient backend") } diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go index 079e335fa6..fbceab6141 100644 --- a/core/rawdb/accessors_metadata.go +++ b/core/rawdb/accessors_metadata.go @@ -18,6 +18,7 @@ package rawdb import ( "encoding/json" + "math/big" "time" "github.com/ethereum/go-ethereum/common" @@ -27,6 +28,12 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) +// FreezerType enumerator +const ( + EntireFreezerType uint64 = iota // classic ancient type + PruneFreezerType // prune ancient type +) + // ReadDatabaseVersion retrieves the version number of the database. func ReadDatabaseVersion(db ethdb.KeyValueReader) *uint64 { var version uint64 @@ -138,3 +145,83 @@ func PopUncleanShutdownMarker(db ethdb.KeyValueStore) { log.Warn("Failed to clear unclean-shutdown marker", "err", err) } } + +// ReadOffSetOfCurrentAncientFreezer return prune block start +func ReadOffSetOfCurrentAncientFreezer(db ethdb.KeyValueReader) uint64 { + offset, _ := db.Get(offSetOfCurrentAncientFreezer) + if offset == nil { + return 0 + } + return new(big.Int).SetBytes(offset).Uint64() +} + +// WriteOffSetOfCurrentAncientFreezer write prune block start +func WriteOffSetOfCurrentAncientFreezer(db ethdb.KeyValueWriter, offset uint64) { + if err := db.Put(offSetOfCurrentAncientFreezer, new(big.Int).SetUint64(offset).Bytes()); err != nil { + log.Crit("Failed to store offSetOfAncientFreezer", "err", err) + } +} + +// ReadOffSetOfLastAncientFreezer return last prune block start +func ReadOffSetOfLastAncientFreezer(db ethdb.KeyValueReader) uint64 { + offset, _ := db.Get(offSetOfLastAncientFreezer) + if offset == nil { + return 0 + } + return new(big.Int).SetBytes(offset).Uint64() +} + +// WriteOffSetOfLastAncientFreezer wirte before prune block start +func WriteOffSetOfLastAncientFreezer(db ethdb.KeyValueWriter, offset uint64) { + if err := db.Put(offSetOfLastAncientFreezer, new(big.Int).SetUint64(offset).Bytes()); err != nil { + log.Crit("Failed to store offSetOfAncientFreezer", "err", err) + } +} + +// ReadFrozenOfAncientFreezer return freezer block number +func ReadFrozenOfAncientFreezer(db ethdb.KeyValueReader) uint64 { + fozen, _ := db.Get(frozenOfAncientDBKey) + if fozen == nil { + return 0 + } + return new(big.Int).SetBytes(fozen).Uint64() +} + +// WriteFrozenOfAncientFreezer write freezer block number +func WriteFrozenOfAncientFreezer(db ethdb.KeyValueWriter, frozen uint64) { + if err := db.Put(frozenOfAncientDBKey, new(big.Int).SetUint64(frozen).Bytes()); err != nil { + log.Crit("Failed to store offSetOfAncientFreezer", "err", err) + } +} + +// ReadSafePointBlockNumber return the number of block that roothash save to disk +func ReadSafePointBlockNumber(db ethdb.KeyValueReader) uint64 { + num, _ := db.Get(LastSafePointBlockKey) + if num == nil { + return 0 + } + return new(big.Int).SetBytes(num).Uint64() +} + +// WriteSafePointBlockNumber write the number of block that roothash save to disk +func WriteSafePointBlockNumber(db ethdb.KeyValueWriter, number uint64) { + if err := db.Put(LastSafePointBlockKey, new(big.Int).SetUint64(number).Bytes()); err != nil { + log.Crit("Failed to store offSetOfAncientFreezer", "err", err) + } +} + +// ReadAncientType return freezer type +func ReadAncientType(db ethdb.KeyValueReader) uint64 { + data, _ := db.Get(pruneAncientKey) + if data == nil { + return EntireFreezerType + } + return new(big.Int).SetBytes(data).Uint64() +} + +// WriteAncientType write freezer type +func WriteAncientType(db ethdb.KeyValueWriter, flag uint64) { + if err := db.Put(pruneAncientKey, new(big.Int).SetUint64(flag).Bytes()); err != nil { + log.Crit("Failed to store offSetOfAncientFreezer", "err", err) + } +} diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 883e17b782..2fbd637ff6 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -181,6 +181,9 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool // signal received. func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool) { // short circuit for invalid range + if offset := db.AncientOffSet(); offset > from { + from = offset + } if from >= to { return } @@ -272,6 +275,9 @@ func indexTransactionsForTesting(db ethdb.Database, from uint64, to uint64, inte // signal received. func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool) { // short circuit for invalid range + if offset := db.AncientOffSet(); offset > from { + from = offset + } if from >= to { return } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 3342b36f36..21f90f5654 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -20,7 +20,6 @@ import ( "bytes" "errors" "fmt" - "math/big" "os" "sync/atomic" "time" @@ -159,33 +158,6 @@ func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { } } -func ReadOffSetOfCurrentAncientFreezer(db ethdb.KeyValueReader) uint64 { - offset, _ := db.Get(offSetOfCurrentAncientFreezer) - if offset == nil { - return 0 - } - return new(big.Int).SetBytes(offset).Uint64() -} - -func ReadOffSetOfLastAncientFreezer(db ethdb.KeyValueReader) uint64 { - offset, _ := db.Get(offSetOfLastAncientFreezer) - if offset == nil { - return 0 - } - return new(big.Int).SetBytes(offset).Uint64() -} - -func WriteOffSetOfCurrentAncientFreezer(db ethdb.KeyValueWriter, offset uint64) { - if err := db.Put(offSetOfCurrentAncientFreezer, new(big.Int).SetUint64(offset).Bytes()); err != nil { - log.Crit("Failed to store offSetOfAncientFreezer", "err", err) - } -} -func WriteOffSetOfLastAncientFreezer(db ethdb.KeyValueWriter, offset uint64) { - if err := db.Put(offSetOfLastAncientFreezer, new(big.Int).SetUint64(offset).Bytes()); err != nil { - log.Crit("Failed to store offSetOfAncientFreezer", "err", err) - } -} - // NewFreezerDb only create a freezer without statedb. func NewFreezerDb(db ethdb.KeyValueStore, frz, namespace string, readonly bool, newOffSet uint64) (*freezer, error) { // Create the idle freezer instance, this operation should be atomic to avoid mismatch between offset and acientDB. @@ -201,7 +173,29 @@ func NewFreezerDb(db ethdb.KeyValueStore, frz, namespace string, readonly bool, // 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, disableFreeze, isLastOffset bool) (ethdb.Database, error) { +func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace string, readonly, disableFreeze, isLastOffset, pruneAncientData bool) (ethdb.Database, error) { + if pruneAncientData && !disableFreeze && !readonly { + frdb, err := newPrunedFreezer(freezer, db) + if err != nil { + return nil, err + } + + go frdb.freeze() + WriteAncientType(db, PruneFreezerType) + return &freezerdb{ + KeyValueStore: db, + AncientStore: frdb, + }, nil + } + + if pruneAncientData { + log.Error("pruneancient not take effect, disableFreezer or readonly be set") + } + + if ReadAncientType(db) == PruneFreezerType { + log.Warn("prune ancinet flag is set, may start fail, can add pruneancient parameter resolve") + } + // Create the idle freezer instance frdb, err := newFreezer(freezer, namespace, readonly) if err != nil { @@ -289,7 +283,8 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace st // feezer. } } - + // no prune ancinet start success + WriteAncientType(db, EntireFreezerType) // Freezer is consistent with the key-value database, permit combining the two if !disableFreeze && !frdb.readonly { go frdb.freeze(db) @@ -325,12 +320,12 @@ 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, disableFreeze, isLastOffset bool) (ethdb.Database, error) { +func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, freezer string, namespace string, readonly, disableFreeze, isLastOffset, pruneAncientData 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, disableFreeze, isLastOffset) + frdb, err := NewDatabaseWithFreezer(kvdb, freezer, namespace, readonly, disableFreeze, isLastOffset, pruneAncientData) if err != nil { kvdb.Close() return nil, err diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 92dfc9604a..0dbdf94bae 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -310,9 +310,7 @@ func (f *freezer) freeze(db ethdb.KeyValueStore) { } select { case <-time.NewTimer(freezerRecheckInterval).C: - backoff = false case triggered = <-f.trigger: - backoff = false case <-f.quit: return } @@ -397,83 +395,10 @@ func (f *freezer) freeze(db ethdb.KeyValueStore) { if err := f.Sync(); err != nil { log.Crit("Failed to flush frozen tables", "err", err) } - // Wipe out all data from the active database - batch := db.NewBatch() - for i := 0; i < len(ancients); i++ { - // Always keep the genesis block in active database - if first+uint64(i) != 0 { - DeleteBlockWithoutNumber(batch, ancients[i], first+uint64(i)) - DeleteCanonicalHash(batch, first+uint64(i)) - } - } - if err := batch.Write(); err != nil { - log.Crit("Failed to delete frozen canonical blocks", "err", err) - } - batch.Reset() - - // Wipe out side chains also and track dangling side chians - var dangling []common.Hash - for number := first; number < f.frozen; number++ { - // Always keep the genesis block in active database - if number != 0 { - dangling = ReadAllHashes(db, number) - for _, hash := range dangling { - log.Trace("Deleting side chain", "number", number, "hash", hash) - DeleteBlock(batch, hash, number) - } - } - } - if err := batch.Write(); err != nil { - log.Crit("Failed to delete frozen side blocks", "err", err) - } - batch.Reset() - - // Step into the future and delete and dangling side chains - if f.frozen > 0 { - tip := f.frozen - for len(dangling) > 0 { - drop := make(map[common.Hash]struct{}) - for _, hash := range dangling { - log.Debug("Dangling parent from freezer", "number", tip-1, "hash", hash) - drop[hash] = struct{}{} - } - children := ReadAllHashes(db, tip) - for i := 0; i < len(children); i++ { - // Dig up the child and ensure it's dangling - child := ReadHeader(nfdb, children[i], tip) - if child == nil { - log.Error("Missing dangling header", "number", tip, "hash", children[i]) - continue - } - if _, ok := drop[child.ParentHash]; !ok { - children = append(children[:i], children[i+1:]...) - i-- - continue - } - // Delete all block data associated with the child - log.Debug("Deleting dangling block", "number", tip, "hash", children[i], "parent", child.ParentHash) - DeleteBlock(batch, children[i], tip) - } - dangling = children - tip++ - } - if err := batch.Write(); err != nil { - log.Crit("Failed to delete dangling side blocks", "err", err) - } - } - // Log something friendly for the user - context := []interface{}{ - "blocks", f.frozen - first, "elapsed", common.PrettyDuration(time.Since(start)), "number", f.frozen - 1, - } - if n := len(ancients); n > 0 { - context = append(context, []interface{}{"hash", ancients[n-1]}...) - } - log.Info("Deep froze chain segment", context...) - // Avoid database thrashing with tiny writes - if f.frozen-first < freezerBatchLimit { - backoff = true - } + // Batch of blocks have been frozen, flush them before wiping from leveldb + backoff = f.frozen-first >= freezerBatchLimit + gcKvStore(db, ancients, first, f.frozen, start) } } @@ -494,3 +419,81 @@ func (f *freezer) repair() error { atomic.StoreUint64(&f.frozen, min) return nil } + +// delete leveldb data that save to ancientdb, split from func freeze +func gcKvStore(db ethdb.KeyValueStore, ancients []common.Hash, first uint64, frozen uint64, start time.Time) { + // Wipe out all data from the active database + batch := db.NewBatch() + for i := 0; i < len(ancients); i++ { + // Always keep the genesis block in active database + if blockNumber := first + uint64(i); blockNumber != 0 { + DeleteBlockWithoutNumber(batch, ancients[i], blockNumber) + DeleteCanonicalHash(batch, blockNumber) + } + } + if err := batch.Write(); err != nil { + log.Crit("Failed to delete frozen canonical blocks", "err", err) + } + batch.Reset() + + // Wipe out side chains also and track dangling side chians + var dangling []common.Hash + for number := first; number < frozen; number++ { + // Always keep the genesis block in active database + if number != 0 { + dangling = ReadAllHashes(db, number) + for _, hash := range dangling { + log.Trace("Deleting side chain", "number", number, "hash", hash) + DeleteBlock(batch, hash, number) + } + } + } + if err := batch.Write(); err != nil { + log.Crit("Failed to delete frozen side blocks", "err", err) + } + batch.Reset() + + // Step into the future and delete and dangling side chains + if frozen > 0 { + tip := frozen + nfdb := &nofreezedb{KeyValueStore: db} + for len(dangling) > 0 { + drop := make(map[common.Hash]struct{}) + for _, hash := range dangling { + log.Debug("Dangling parent from freezer", "number", tip-1, "hash", hash) + drop[hash] = struct{}{} + } + children := ReadAllHashes(db, tip) + for i := 0; i < len(children); i++ { + // Dig up the child and ensure it's dangling + child := ReadHeader(nfdb, children[i], tip) + if child == nil { + log.Error("Missing dangling header", "number", tip, "hash", children[i]) + continue + } + if _, ok := drop[child.ParentHash]; !ok { + children = append(children[:i], children[i+1:]...) + i-- + continue + } + // Delete all block data associated with the child + log.Debug("Deleting dangling block", "number", tip, "hash", children[i], "parent", child.ParentHash) + DeleteBlock(batch, children[i], tip) + } + dangling = children + tip++ + } + if err := batch.Write(); err != nil { + log.Crit("Failed to delete dangling side blocks", "err", err) + } + } + + // Log something friendly for the user + context := []interface{}{ + "blocks", frozen - first, "elapsed", common.PrettyDuration(time.Since(start)), "number", frozen - 1, + } + if n := len(ancients); n > 0 { + context = append(context, []interface{}{"hash", ancients[n-1]}...) + } + log.Info("Deep froze chain segment", context...) +} diff --git a/core/rawdb/prunedfreezer.go b/core/rawdb/prunedfreezer.go new file mode 100644 index 0000000000..b82993e6ec --- /dev/null +++ b/core/rawdb/prunedfreezer.go @@ -0,0 +1,285 @@ +package rawdb + +import ( + "math" + "os" + "path/filepath" + "sync" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + "github.com/prometheus/tsdb/fileutil" +) + +// prunedfreezer not contain ancient data, only record 'frozen' , the next recycle block number form kvstore. +type prunedfreezer struct { + db ethdb.KeyValueStore // Meta database + // WARNING: The `frozen` 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). + frozen uint64 // BlockNumber of next frozen block + threshold uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests) + + instanceLock fileutil.Releaser // File-system lock to prevent double opens + quit chan struct{} + closeOnce sync.Once +} + +// newNoDataFreezer creates a chain freezer that deletes data enough ‘old’. +func newPrunedFreezer(datadir string, db ethdb.KeyValueStore) (*prunedfreezer, error) { + if info, err := os.Lstat(datadir); !os.IsNotExist(err) { + if info.Mode()&os.ModeSymlink != 0 { + log.Warn("Symbolic link ancient database is not supported", "path", datadir) + return nil, errSymlinkDatadir + } + } + + lock, _, err := fileutil.Flock(filepath.Join(datadir, "../NODATA_ANCIENT_FLOCK")) + if err != nil { + return nil, err + } + + freezer := &prunedfreezer{ + db: db, + threshold: params.FullImmutabilityThreshold, + instanceLock: lock, + quit: make(chan struct{}), + } + + if err := freezer.repair(datadir); err != nil { + return nil, err + } + + log.Info("Opened ancientdb with nodata mode", "database", datadir, "frozen", freezer.frozen) + return freezer, nil +} + +// repair init frozen , compatible disk-ancientdb and pruner-block-tool. +func (f *prunedfreezer) repair(datadir string) error { + // compatible prune-block-tool + offset := ReadOffSetOfCurrentAncientFreezer(f.db) + + // compatible freezer + min := uint64(math.MaxUint64) + for name, disableSnappy := range FreezerNoSnappy { + table, err := NewFreezerTable(datadir, name, disableSnappy) + if err != nil { + return err + } + items := atomic.LoadUint64(&table.items) + if min > items { + min = items + } + table.Close() + } + offset += min + + if frozen := ReadFrozenOfAncientFreezer(f.db); frozen > offset { + offset = frozen + } + + atomic.StoreUint64(&f.frozen, offset) + if err := f.Sync(); err != nil { + return nil + } + return nil +} + +// Close terminates the chain prunedfreezer. +func (f *prunedfreezer) Close() error { + var err error + f.closeOnce.Do(func() { + close(f.quit) + f.Sync() + err = f.instanceLock.Release() + }) + return err +} + +// HasAncient returns an indicator whether the specified ancient data exists, return nil. +func (f *prunedfreezer) HasAncient(kind string, number uint64) (bool, error) { + return false, nil +} + +// Ancient retrieves an ancient binary blob from prunedfreezer, return nil. +func (f *prunedfreezer) Ancient(kind string, number uint64) ([]byte, error) { + if _, ok := FreezerNoSnappy[kind]; ok { + if number >= atomic.LoadUint64(&f.frozen) { + return nil, errOutOfBounds + } + return nil, nil + } + return nil, errUnknownTable +} + +// Ancients returns the last of the frozen items. +func (f *prunedfreezer) Ancients() (uint64, error) { + return atomic.LoadUint64(&f.frozen), nil +} + +// ItemAmountInAncient returns the actual length of current ancientDB, return 0. +func (f *prunedfreezer) ItemAmountInAncient() (uint64, error) { + return 0, nil +} + +// AncientOffSet returns the offset of current ancientDB, offset == frozen. +func (f *prunedfreezer) AncientOffSet() uint64 { + return atomic.LoadUint64(&f.frozen) +} + +// AncientSize returns the ancient size of the specified category, return 0. +func (f *prunedfreezer) AncientSize(kind string) (uint64, error) { + if _, ok := FreezerNoSnappy[kind]; ok { + return 0, nil + } + return 0, errUnknownTable +} + +// AppendAncient update frozen. +// +// Notably, this function is lock free but kind of thread-safe. All out-of-order +// injection will be rejected. But if two injections with same number happen at +// the same time, we can get into the trouble. +func (f *prunedfreezer) AppendAncient(number uint64, hash, header, body, receipts, td []byte) (err error) { + if atomic.LoadUint64(&f.frozen) != number { + return errOutOrderInsertion + } + atomic.AddUint64(&f.frozen, 1) + return nil +} + +// TruncateAncients discards any recent data above the provided threshold number, always success. +func (f *prunedfreezer) TruncateAncients(items uint64) error { + if atomic.LoadUint64(&f.frozen) <= items { + return nil + } + atomic.StoreUint64(&f.frozen, items) + WriteFrozenOfAncientFreezer(f.db, atomic.LoadUint64(&f.frozen)) + return nil +} + +// Sync flushes meta data tables to disk. +func (f *prunedfreezer) Sync() error { + WriteFrozenOfAncientFreezer(f.db, atomic.LoadUint64(&f.frozen)) + return nil +} + +// freeze is a background thread that periodically checks the blockchain for any +// import progress and moves ancient data from the fast database into the freezer. +// +// This functionality is deliberately broken off from block importing to avoid +// incurring additional data shuffling delays on block propagation. +func (f *prunedfreezer) freeze() { + nfdb := &nofreezedb{KeyValueStore: f.db} + + var backoff bool + for { + select { + case <-f.quit: + log.Info("Freezer shutting down") + return + default: + } + if backoff { + select { + case <-time.NewTimer(freezerRecheckInterval).C: + case <-f.quit: + return + } + } + + // Retrieve the freezing threshold. + hash := ReadHeadBlockHash(nfdb) + if hash == (common.Hash{}) { + log.Debug("Current full block hash unavailable") // new chain, empty database + backoff = true + continue + } + number := ReadHeaderNumber(nfdb, hash) + threshold := atomic.LoadUint64(&f.threshold) + + switch { + case number == nil: + log.Error("Current full block number unavailable", "hash", hash) + backoff = true + continue + + case *number < threshold: + log.Debug("Current full block not old enough", "number", *number, "hash", hash, "delay", threshold) + backoff = true + continue + + case *number-threshold <= f.frozen: + log.Debug("Ancient blocks frozen already", "number", *number, "hash", hash, "frozen", f.frozen) + backoff = true + continue + } + head := ReadHeader(nfdb, hash, *number) + if head == nil { + log.Error("Stable state block unavailable", "number", *number, "hash", hash) + backoff = true + continue + } + + stableStabeNumber := ReadSafePointBlockNumber(nfdb) + switch { + case stableStabeNumber < params.StableStateThreshold: + log.Debug("Stable state block not old enough", "number", stableStabeNumber) + backoff = true + continue + + case stableStabeNumber > *number: + log.Warn("Stable state block biger current full block", "number", stableStabeNumber, "number", *number) + backoff = true + continue + } + stableStabeNumber -= params.StableStateThreshold + + // Seems we have data ready to be frozen, process in usable batches + limit := *number - threshold + if limit > stableStabeNumber { + limit = stableStabeNumber + } + + if limit < f.frozen { + log.Debug("Stable state block has prune", "limit", limit, "frozen", f.frozen) + backoff = true + continue + } + + if limit-f.frozen > freezerBatchLimit { + limit = f.frozen + freezerBatchLimit + } + var ( + start = time.Now() + first = f.frozen + ancients = make([]common.Hash, 0, limit-f.frozen) + ) + for f.frozen <= limit { + // Retrieves all the components of the canonical block + hash := ReadCanonicalHash(nfdb, f.frozen) + if hash == (common.Hash{}) { + log.Error("Canonical hash missing, can't freeze", "number", f.frozen) + } + log.Trace("Deep froze ancient block", "number", f.frozen, "hash", hash) + // Inject all the components into the relevant data tables + if err := f.AppendAncient(f.frozen, nil, nil, nil, nil, nil); err != nil { + log.Error("Append ancient err", "number", f.frozen, "hash", hash, "err", err) + break + } + if hash != (common.Hash{}) { + ancients = append(ancients, hash) + } + } + // Batch of blocks have been frozen, flush them before wiping from leveldb + if err := f.Sync(); err != nil { + log.Crit("Failed to flush frozen tables", "err", err) + } + backoff = f.frozen-first >= freezerBatchLimit + gcKvStore(f.db, ancients, first, f.frozen, start) + } +} diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index ece5006c39..77468f43e9 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -75,6 +75,15 @@ var ( //offSet of the ancientDB before updated version. offSetOfLastAncientFreezer = []byte("offSetOfLastAncientFreezer") + //frozenOfAncientDBKey tracks the block number for ancientDB to save. + frozenOfAncientDBKey = []byte("FrozenOfAncientDB") + + //LastSafePointBlockKey tracks the block number for block state that write disk + LastSafePointBlockKey = []byte("LastSafePointBlockNumber") + + //PruneAncientFlag flag whether prune ancient + pruneAncientKey = []byte("PruneAncientFlag") + // badBlockKey tracks the list of bad blocks seen by local badBlockKey = []byte("InvalidBlock") diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 5b070f3afa..b222bb97bb 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -258,7 +258,7 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta func (p *BlockPruner) backUpOldDb(name string, cache, handles int, namespace string, readonly, interrupt bool) error { // Open old db wrapper. - chainDb, err := p.node.OpenDatabaseWithFreezer(name, cache, handles, p.oldAncientPath, namespace, readonly, true, interrupt) + chainDb, err := p.node.OpenDatabaseWithFreezer(name, cache, handles, p.oldAncientPath, namespace, readonly, true, interrupt, false) if err != nil { log.Error("Failed to open ancient database", "err=", err) return err diff --git a/eth/backend.go b/eth/backend.go index 3f782ff6a8..b9c9f9a2cb 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -130,7 +130,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Assemble the Ethereum object chainDb, err := stack.OpenAndMergeDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles, - config.DatabaseFreezer, config.DatabaseDiff, "eth/db/chaindata/", false, config.PersistDiff) + config.DatabaseFreezer, config.DatabaseDiff, "eth/db/chaindata/", false, config.PersistDiff, config.PruneAncientData) if err != nil { return nil, err } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 09baad1e1c..e25b55186e 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -167,6 +167,7 @@ type Config struct { DatabaseDiff string PersistDiff bool DiffBlock uint64 + PruneAncientData bool TrieCleanCache int TrieCleanCacheJournal string `toml:",omitempty"` // Disk journal directory for trie cache to survive node restarts diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index f192a1aace..b3af010714 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -52,6 +52,7 @@ func (c Config) MarshalTOML() (interface{}, error) { Preimages bool PersistDiff bool DiffBlock uint64 `toml:",omitempty"` + PruneAncientData bool Miner miner.Config Ethash ethash.Config TxPool core.TxPoolConfig @@ -100,6 +101,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.Preimages = c.Preimages enc.PersistDiff = c.PersistDiff enc.DiffBlock = c.DiffBlock + enc.PruneAncientData = c.PruneAncientData enc.Miner = c.Miner enc.Ethash = c.Ethash enc.TxPool = c.TxPool @@ -145,6 +147,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { DatabaseDiff *string PersistDiff *bool DiffBlock *uint64 `toml:",omitempty"` + PruneAncientData *bool TrieCleanCache *int TrieCleanCacheJournal *string `toml:",omitempty"` TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` @@ -248,6 +251,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.DiffBlock != nil { c.DiffBlock = *dec.DiffBlock } + if dec.PruneAncientData != nil { + c.PruneAncientData = *dec.PruneAncientData + } if dec.TrieCleanCache != nil { c.TrieCleanCache = *dec.TrieCleanCache } diff --git a/eth/handler.go b/eth/handler.go index d6d2cfd6c6..acf2000293 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -27,6 +27,7 @@ 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/eth/downloader" "github.com/ethereum/go-ethereum/eth/fetcher" @@ -171,6 +172,9 @@ func newHandler(config *handlerConfig) (*handler, error) { // In these cases however it's safe to reenable fast sync. fullBlock, fastBlock := h.chain.CurrentBlock(), h.chain.CurrentFastBlock() if fullBlock.NumberU64() == 0 && fastBlock.NumberU64() > 0 { + if rawdb.ReadAncientType(h.database) == rawdb.PruneFreezerType { + log.Crit("Fast Sync not finish, can't enable pruneancient mode") + } h.fastSync = uint32(1) log.Warn("Switch sync mode from full sync to fast sync") } diff --git a/eth/sync.go b/eth/sync.go index 2256c7cb99..436200bb51 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -284,11 +284,16 @@ func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) { // fast 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 { + if rawdb.ReadAncientType(cs.handler.database) == rawdb.PruneFreezerType { + log.Crit("Current rewound to before the fast sync pivot, can't enable pruneancient mode", "current block number", head.NumberU64(), "pivot", *pivot) + } block := cs.handler.chain.CurrentFastBlock() td := cs.handler.chain.GetTdByHash(block.Hash()) + log.Warn("Switch full sync to fast sync", "current block number", head.NumberU64(), "pivot", *pivot) return downloader.FastSync, td } } + // Nope, we're really full syncing head := cs.handler.chain.CurrentBlock() td := cs.handler.chain.GetTd(head.Hash(), head.NumberU64()) diff --git a/node/node.go b/node/node.go index b6e1246b3d..df0693127f 100644 --- a/node/node.go +++ b/node/node.go @@ -582,12 +582,12 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r return db, err } -func (n *Node) OpenAndMergeDatabase(name string, cache, handles int, freezer, diff, namespace string, readonly, persistDiff bool) (ethdb.Database, error) { +func (n *Node) OpenAndMergeDatabase(name string, cache, handles int, freezer, diff, namespace string, readonly, persistDiff, pruneAncientData bool) (ethdb.Database, error) { chainDataHandles := handles if persistDiff { chainDataHandles = handles * chainDataHandlesPercentage / 100 } - chainDB, err := n.OpenDatabaseWithFreezer(name, cache, chainDataHandles, freezer, namespace, readonly, false, false) + chainDB, err := n.OpenDatabaseWithFreezer(name, cache, chainDataHandles, freezer, namespace, readonly, false, false, pruneAncientData) if err != nil { return nil, err } @@ -607,7 +607,7 @@ func (n *Node) OpenAndMergeDatabase(name string, cache, handles int, freezer, di // 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, disableFreeze, isLastOffset bool) (ethdb.Database, error) { +func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string, readonly, disableFreeze, isLastOffset, pruneAncientData bool) (ethdb.Database, error) { n.lock.Lock() defer n.lock.Unlock() if n.state == closedState { @@ -626,7 +626,7 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, case !filepath.IsAbs(freezer): freezer = n.ResolvePath(freezer) } - db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace, readonly, disableFreeze, isLastOffset) + db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace, readonly, disableFreeze, isLastOffset, pruneAncientData) } if err == nil { diff --git a/params/network_params.go b/params/network_params.go index 9311b5e2d5..cc322e86f4 100644 --- a/params/network_params.go +++ b/params/network_params.go @@ -53,6 +53,9 @@ const ( // CheckpointProcessConfirmations is the number before a checkpoint is generated CheckpointProcessConfirmations = 256 + // StableStateThreshold is the reserve number of block state save to disk before delete ancientdb + StableStateThreshold uint64 = 128 + // FullImmutabilityThreshold is the number of blocks after which a chain segment is // considered immutable (i.e. soft finality). It is used by the downloader as a // hard limit against deep ancestors, by the blockchain against deep reorgs, by From 0483394ef6b86cd9ae51a5e38db1efc4b020567e Mon Sep 17 00:00:00 2001 From: dean <97718205+dean65@users.noreply.github.com> Date: Mon, 4 Jul 2022 09:49:07 +0800 Subject: [PATCH 117/117] [R4R] Separate Processing and State Verification on BSC (#926) Implement Separate Processing and State Verification on BSC --- cmd/geth/main.go | 3 + cmd/geth/snapshot.go | 76 ++++- cmd/geth/usage.go | 3 + cmd/utils/flags.go | 39 ++- core/block_validator.go | 33 +- core/blockchain.go | 233 +++++++++++++-- core/blockchain_diff_test.go | 163 +++++++++- core/blockchain_notries_test.go | 226 ++++++++++++++ core/blockchain_test.go | 2 +- core/error.go | 6 + core/remote_state_verifier.go | 446 ++++++++++++++++++++++++++++ core/state/database.go | 24 +- core/state/pruner/pruner.go | 104 ++++++- core/state/snapshot/journal.go | 9 +- core/state/snapshot/snapshot.go | 4 +- core/state/state_object.go | 23 ++ core/state/statedb.go | 99 ++++-- core/state_processor.go | 5 +- core/types.go | 2 + core/types/block.go | 41 ++- eth/backend.go | 35 ++- eth/downloader/downloader.go | 4 + eth/ethconfig/config.go | 9 +- eth/ethconfig/gen_config.go | 79 ++++- eth/handler.go | 29 +- eth/handler_trust.go | 52 ++++ eth/peer.go | 25 +- eth/peerset.go | 121 +++++++- eth/protocols/diff/protocol.go | 2 +- eth/protocols/trust/discovery.go | 14 + eth/protocols/trust/handler.go | 157 ++++++++++ eth/protocols/trust/handler_test.go | 270 +++++++++++++++++ eth/protocols/trust/peer.go | 66 ++++ eth/protocols/trust/peer_test.go | 42 +++ eth/protocols/trust/protocol.go | 71 +++++ eth/protocols/trust/tracker.go | 10 + ethclient/ethclient.go | 7 + internal/ethapi/api.go | 4 + light/trie.go | 8 + p2p/peer.go | 5 + p2p/server.go | 18 ++ tests/state_test_util.go | 2 +- trie/database.go | 1 + trie/dummy_trie.go | 96 ++++++ 44 files changed, 2559 insertions(+), 109 deletions(-) create mode 100644 core/blockchain_notries_test.go create mode 100644 core/remote_state_verifier.go create mode 100644 eth/handler_trust.go create mode 100644 eth/protocols/trust/discovery.go create mode 100644 eth/protocols/trust/handler.go create mode 100644 eth/protocols/trust/handler_test.go create mode 100644 eth/protocols/trust/peer.go create mode 100644 eth/protocols/trust/peer_test.go create mode 100644 eth/protocols/trust/protocol.go create mode 100644 eth/protocols/trust/tracker.go create mode 100644 trie/dummy_trie.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 5187971423..286be82a2e 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -71,6 +71,8 @@ var ( utils.NoUSBFlag, utils.DirectBroadcastFlag, utils.DisableSnapProtocolFlag, + utils.DisableDiffProtocolFlag, + utils.EnableTrustProtocolFlag, utils.DiffSyncFlag, utils.PipeCommitFlag, utils.RangeLimitFlag, @@ -98,6 +100,7 @@ var ( utils.TxPoolLifetimeFlag, utils.TxPoolReannounceTimeFlag, utils.SyncModeFlag, + utils.TriesVerifyModeFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, utils.SnapshotFlag, diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index c00334ee9e..5405f42e43 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -18,6 +18,7 @@ package main import ( "bytes" + "encoding/json" "errors" "fmt" "os" @@ -29,13 +30,16 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "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/state/pruner" "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -129,6 +133,32 @@ geth snapshot verify-state will traverse the whole accounts and storages set based on the specified snapshot and recalculate the root hash of state for verification. In other words, this command does the snapshot to trie conversion. +`, + }, + { + Name: "insecure-prune-all", + Usage: "Prune all trie state data except genesis block, it will break storage for fullnode, only suitable for fast node " + + "who do not need trie storage at all", + ArgsUsage: "", + Action: utils.MigrateFlags(pruneAllState), + Category: "MISCELLANEOUS COMMANDS", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.AncientFlag, + utils.RopstenFlag, + utils.RinkebyFlag, + utils.GoerliFlag, + }, + Description: ` +will prune all historical trie state data except genesis block. +All trie nodes will be deleted from the database. + +It expects the genesis file as argument. + +WARNING: It's necessary to delete the trie clean cache after the pruning. +If you specify another directory for the trie clean cache via "--cache.trie.journal" +during the use of Geth, please also specify it here for correct deletion. Otherwise +the trie clean cache with default directory will be deleted. `, }, { @@ -195,7 +225,7 @@ func accessDb(ctx *cli.Context, stack *node.Node) (ethdb.Database, error) { } headHeader := headBlock.Header() //Make sure the MPT and snapshot matches before pruning, otherwise the node can not start. - snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, TriesInMemory, headBlock.Root(), false, false, false) + snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, TriesInMemory, headBlock.Root(), false, false, false, false) if err != nil { log.Error("snaptree error", "err", err) return nil, err // The relevant snapshot(s) might not exist @@ -363,6 +393,48 @@ func pruneState(ctx *cli.Context) error { return nil } +func pruneAllState(ctx *cli.Context) error { + stack, _ := makeConfigNode(ctx) + defer stack.Close() + + genesisPath := ctx.Args().First() + if len(genesisPath) == 0 { + utils.Fatalf("Must supply path to genesis JSON file") + } + file, err := os.Open(genesisPath) + if err != nil { + utils.Fatalf("Failed to read genesis file: %v", err) + } + defer file.Close() + + g := new(core.Genesis) + if err := json.NewDecoder(file).Decode(g); err != nil { + cfg := gethConfig{ + Eth: ethconfig.Defaults, + Node: defaultNodeConfig(), + Metrics: metrics.DefaultConfig, + } + + // Load config file. + if err := loadConfig(genesisPath, &cfg); err != nil { + utils.Fatalf("%v", err) + } + g = cfg.Eth.Genesis + } + + chaindb := utils.MakeChainDatabase(ctx, stack, false, false) + pruner, err := pruner.NewAllPruner(chaindb) + if err != nil { + log.Error("Failed to open snapshot tree", "err", err) + return err + } + if err = pruner.PruneAll(g); err != nil { + log.Error("Failed to prune state", "err", err) + return err + } + return nil +} + func verifyState(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() @@ -373,7 +445,7 @@ func verifyState(ctx *cli.Context) error { log.Error("Failed to load head block") return errors.New("no head block") } - snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, 128, headBlock.Root(), false, false, false) + snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, 128, headBlock.Root(), false, false, false, false) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return err diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index a1a0a7d0b4..6dd878f9e9 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -41,6 +41,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.NoUSBFlag, utils.DirectBroadcastFlag, utils.DisableSnapProtocolFlag, + utils.DisableDiffProtocolFlag, + utils.EnableTrustProtocolFlag, utils.RangeLimitFlag, utils.SmartCardDaemonPathFlag, utils.NetworkIdFlag, @@ -50,6 +52,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.YoloV3Flag, utils.RopstenFlag, utils.SyncModeFlag, + utils.TriesVerifyModeFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, utils.TxLookupLimitFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 218ecfcf3c..dc6ccb7e6b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -122,6 +122,14 @@ var ( Name: "disablesnapprotocol", Usage: "Disable snap protocol", } + DisableDiffProtocolFlag = cli.BoolFlag{ + Name: "disablediffprotocol", + Usage: "Disable diff protocol", + } + EnableTrustProtocolFlag = cli.BoolFlag{ + Name: "enabletrustprotocol", + Usage: "Enable trust protocol", + } DiffSyncFlag = cli.BoolFlag{ Name: "diffsync", Usage: "Enable diffy sync, Please note that enable diffsync will improve the syncing speed, " + @@ -264,6 +272,20 @@ var ( Usage: "The layer of tries trees that keep in memory", Value: 128, } + defaultVerifyMode = ethconfig.Defaults.TriesVerifyMode + TriesVerifyModeFlag = TextMarshalerFlag{ + Name: "tries-verify-mode", + Usage: `tries verify mode: + "local(default): a normal full node with complete state world(both MPT and snapshot), merkle state root will + be verified against the block header.", + "full: a fast node with only snapshot state world. Merkle state root is verified by the trustworthy remote verify node + by comparing the diffhash(an identify of difflayer generated by the block) and state root.", + "insecure: same as full mode, except that it can tolerate without verifying the diffhash when verify node does not have it.", + "none: no merkle state root verification at all, there is no need to setup or connect remote verify node at all, + it is more light comparing to full and insecure mode, but get a very small chance that the state is not consistent + with other peers."`, + Value: &defaultVerifyMode, + } OverrideBerlinFlag = cli.Uint64Flag{ Name: "override.berlin", Usage: "Manually specify Berlin fork-block, overriding the bundled setting", @@ -1644,6 +1666,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(DisableSnapProtocolFlag.Name) { cfg.DisableSnapProtocol = ctx.GlobalBool(DisableSnapProtocolFlag.Name) } + if ctx.GlobalIsSet(DisableDiffProtocolFlag.Name) { + cfg.DisableDiffProtocol = ctx.GlobalIsSet(DisableDiffProtocolFlag.Name) + } + if ctx.GlobalIsSet(EnableTrustProtocolFlag.Name) { + cfg.EnableTrustProtocol = ctx.GlobalIsSet(EnableTrustProtocolFlag.Name) + } if ctx.GlobalIsSet(DiffSyncFlag.Name) { cfg.DiffSync = ctx.GlobalBool(DiffSyncFlag.Name) } @@ -1677,6 +1705,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.GlobalIsSet(TriesInMemoryFlag.Name) { cfg.TriesInMemory = ctx.GlobalUint64(TriesInMemoryFlag.Name) } + if ctx.GlobalIsSet(TriesVerifyModeFlag.Name) { + cfg.TriesVerifyMode = *GlobalTextMarshaler(ctx, TriesVerifyModeFlag.Name).(*core.VerifyMode) + // If a node sets verify mode to full or insecure, it's a fast node and need + // to verify blocks from verify nodes, then it should enable trust protocol. + if cfg.TriesVerifyMode.NeedRemoteVerify() { + cfg.EnableTrustProtocol = true + } + } if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) { cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100 } @@ -1716,7 +1752,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCapFlag.Name) } if ctx.GlobalIsSet(NoDiscoverFlag.Name) { - cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs = []string{}, []string{} + cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs, cfg.TrustDiscoveryURLs = []string{}, []string{}, []string{} } else if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) { urls := ctx.GlobalString(DNSDiscoveryFlag.Name) if urls == "" { @@ -1822,6 +1858,7 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) { if url := params.KnownDNSNetwork(genesis, protocol); url != "" { cfg.EthDiscoveryURLs = []string{url} cfg.SnapDiscoveryURLs = cfg.EthDiscoveryURLs + cfg.TrustDiscoveryURLs = cfg.EthDiscoveryURLs } } diff --git a/core/block_validator.go b/core/block_validator.go index 4cf53a6cdc..8963fd32fa 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -30,23 +30,38 @@ import ( const badBlockCacheExpire = 30 * time.Second +type BlockValidatorOption func(*BlockValidator) *BlockValidator + +func EnableRemoteVerifyManager(remoteValidator *remoteVerifyManager) BlockValidatorOption { + return func(bv *BlockValidator) *BlockValidator { + bv.remoteValidator = remoteValidator + return bv + } +} + // BlockValidator is responsible for validating block headers, uncles and // processed state. // // BlockValidator implements Validator. type BlockValidator struct { - config *params.ChainConfig // Chain configuration options - bc *BlockChain // Canonical block chain - engine consensus.Engine // Consensus engine used for validating + config *params.ChainConfig // Chain configuration options + bc *BlockChain // Canonical block chain + engine consensus.Engine // Consensus engine used for validating + remoteValidator *remoteVerifyManager } // NewBlockValidator returns a new block validator which is safe for re-use -func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator { +func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine, opts ...BlockValidatorOption) *BlockValidator { validator := &BlockValidator{ config: config, engine: engine, bc: blockchain, } + + for _, opt := range opts { + validator = opt(validator) + } + return validator } @@ -92,6 +107,12 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { } return nil }, + func() error { + if v.remoteValidator != nil && !v.remoteValidator.AncestorVerified(block.Header()) { + return fmt.Errorf("%w, number: %s, hash: %s", ErrAncestorHasNotBeenVerified, block.Number(), block.Hash()) + } + return nil + }, } validateRes := make(chan error, len(validateFuns)) for _, f := range validateFuns { @@ -171,6 +192,10 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return err } +func (v *BlockValidator) RemoteVerifyManager() *remoteVerifyManager { + return v.remoteValidator +} + // CalcGasLimit computes the gas limit of the next block after parent. It aims // to keep the baseline gas above the provided floor, and increase it towards the // ceil if the blocks are full. If the ceil is exceeded, it will always decrease diff --git a/core/blockchain.go b/core/blockchain.go index 9eb3154cbe..1555d19e78 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -29,6 +29,7 @@ import ( "time" lru "github.com/hashicorp/golang-lru" + "golang.org/x/crypto/sha3" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" @@ -141,6 +142,7 @@ 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 TriesInMemory uint64 // How many tries keeps in memory + NoTries bool // Insecure settings. Do not have any tries in databases if enabled. SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } @@ -161,7 +163,7 @@ var defaultCacheConfig = &CacheConfig{ SnapshotWait: true, } -type BlockChainOption func(*BlockChain) *BlockChain +type BlockChainOption func(*BlockChain) (*BlockChain, error) // BlockChain represents the canonical chain given a database with a genesis // block. The Blockchain manages chain imports, reverts, chain reorganisations. @@ -195,15 +197,16 @@ type BlockChain struct { txLookupLimit uint64 triesInMemory uint64 - hc *HeaderChain - rmLogsFeed event.Feed - chainFeed event.Feed - chainSideFeed event.Feed - chainHeadFeed event.Feed - logsFeed event.Feed - blockProcFeed event.Feed - scope event.SubscriptionScope - genesisBlock *types.Block + hc *HeaderChain + rmLogsFeed event.Feed + chainFeed event.Feed + chainSideFeed event.Feed + chainHeadFeed event.Feed + chainBlockFeed event.Feed + logsFeed event.Feed + blockProcFeed event.Feed + scope event.SubscriptionScope + genesisBlock *types.Block chainmu sync.RWMutex // blockchain insertion lock @@ -223,6 +226,7 @@ type BlockChain struct { // trusted diff layers diffLayerCache *lru.Cache // Cache for the diffLayers diffLayerRLPCache *lru.Cache // Cache for the rlp encoded diffLayers + diffLayerChanCache *lru.Cache // Cache for the difflayer channel diffQueue *prque.Prque // A Priority queue to store recent diff layer diffQueueBuffer chan *types.DiffLayer diffLayerFreezerBlockLimit uint64 @@ -274,6 +278,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par futureBlocks, _ := lru.New(maxFutureBlocks) diffLayerCache, _ := lru.New(diffLayerCacheLimit) diffLayerRLPCache, _ := lru.New(diffLayerRLPCacheLimit) + diffLayerChanCache, _ := lru.New(diffLayerCacheLimit) bc := &BlockChain{ chainConfig: chainConfig, @@ -284,6 +289,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par Cache: cacheConfig.TrieCleanLimit, Journal: cacheConfig.TrieCleanJournal, Preimages: cacheConfig.Preimages, + NoTries: cacheConfig.NoTries, }), triesInMemory: cacheConfig.TriesInMemory, quit: make(chan struct{}), @@ -295,6 +301,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par badBlockCache: badBlockCache, diffLayerCache: diffLayerCache, diffLayerRLPCache: diffLayerRLPCache, + diffLayerChanCache: diffLayerChanCache, txLookupCache: txLookupCache, futureBlocks: futureBlocks, engine: engine, @@ -307,6 +314,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par diffNumToBlockHashes: make(map[uint64]map[common.Hash]struct{}), diffPeersToDiffHashes: make(map[string]map[common.Hash]struct{}), } + bc.prefetcher = NewStatePrefetcher(chainConfig, bc, engine) bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.processor = NewStateProcessor(chainConfig, bc, engine) @@ -439,13 +447,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par log.Warn("Enabling snapshot recovery", "chainhead", head.NumberU64(), "diskbase", *layer) recover = true } - bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, int(bc.cacheConfig.TriesInMemory), head.Root(), !bc.cacheConfig.SnapshotWait, true, recover) + bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, int(bc.cacheConfig.TriesInMemory), head.Root(), !bc.cacheConfig.SnapshotWait, true, recover, bc.stateCache.NoTries()) } // write safe point block number rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().NumberU64()) // do options before start any routine for _, option := range options { - bc = option(bc) + bc, err = option(bc) + if err != nil { + return nil, err + } } // Take ownership of this particular state go bc.update() @@ -499,11 +510,35 @@ func (bc *BlockChain) cacheReceipts(hash common.Hash, receipts types.Receipts) { bc.receiptsCache.Add(hash, receipts) } -func (bc *BlockChain) cacheDiffLayer(diffLayer *types.DiffLayer) { +func (bc *BlockChain) cacheDiffLayer(diffLayer *types.DiffLayer, diffLayerCh chan struct{}) { + // The difflayer in the system is stored by the map structure, + // so it will be out of order. + // It must be sorted first and then cached, + // otherwise the DiffHash calculated by different nodes will be inconsistent + sort.SliceStable(diffLayer.Codes, func(i, j int) bool { + return diffLayer.Codes[i].Hash.Hex() < diffLayer.Codes[j].Hash.Hex() + }) + sort.SliceStable(diffLayer.Destructs, func(i, j int) bool { + return diffLayer.Destructs[i].Hex() < (diffLayer.Destructs[j].Hex()) + }) + sort.SliceStable(diffLayer.Accounts, func(i, j int) bool { + return diffLayer.Accounts[i].Account.Hex() < diffLayer.Accounts[j].Account.Hex() + }) + sort.SliceStable(diffLayer.Storages, func(i, j int) bool { + return diffLayer.Storages[i].Account.Hex() < diffLayer.Storages[j].Account.Hex() + }) + for index := range diffLayer.Storages { + // Sort keys and vals by key. + sort.Sort(&diffLayer.Storages[index]) + } + if bc.diffLayerCache.Len() >= diffLayerCacheLimit { bc.diffLayerCache.RemoveOldest() } + bc.diffLayerCache.Add(diffLayer.BlockHash, diffLayer) + close(diffLayerCh) + if bc.db.DiffStore() != nil { // push to priority queue before persisting bc.diffQueueBuffer <- diffLayer @@ -1106,6 +1141,9 @@ func (bc *BlockChain) HasState(hash common.Hash) bool { return true } } + if bc.stateCache.NoTries() { + return bc.snaps != nil && bc.snaps.Snapshot(hash) != nil + } _, err := bc.stateCache.OpenTrie(hash) return err == nil } @@ -1118,6 +1156,9 @@ func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool { if block == nil { return false } + if bc.stateCache.NoTries() { + return bc.snaps != nil && bc.snaps.Snapshot(block.Root()) != nil + } return bc.HasState(block.Root()) } @@ -1804,7 +1845,14 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. diffLayer.Receipts = receipts diffLayer.BlockHash = block.Hash() diffLayer.Number = block.NumberU64() - bc.cacheDiffLayer(diffLayer) + + diffLayerCh := make(chan struct{}) + if bc.diffLayerChanCache.Len() >= diffLayerCacheLimit { + bc.diffLayerChanCache.RemoveOldest() + } + bc.diffLayerChanCache.Add(diffLayer.BlockHash, diffLayerCh) + + go bc.cacheDiffLayer(diffLayer, diffLayerCh) } wg.Wait() @@ -2215,6 +2263,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er stats.processed++ stats.usedGas += usedGas + bc.chainBlockFeed.Send(ChainHeadEvent{block}) dirty, _ := bc.stateCache.TrieDB().Size() stats.report(chain, it.index, dirty) } @@ -2795,9 +2844,14 @@ func (bc *BlockChain) HandleDiffLayer(diffLayer *types.DiffLayer, pid string, fu return nil } + if diffLayer.DiffHash.Load() == nil { + return fmt.Errorf("unexpected difflayer which diffHash is nil from peeer %s", pid) + } + diffHash := diffLayer.DiffHash.Load().(common.Hash) + bc.diffMux.Lock() defer bc.diffMux.Unlock() - if blockHash, exist := bc.diffHashToBlockHash[diffLayer.DiffHash]; exist && blockHash == diffLayer.BlockHash { + if blockHash, exist := bc.diffHashToBlockHash[diffHash]; exist && blockHash == diffLayer.BlockHash { return nil } @@ -2811,28 +2865,28 @@ func (bc *BlockChain) HandleDiffLayer(diffLayer *types.DiffLayer, pid string, fu return nil } if _, exist := bc.diffPeersToDiffHashes[pid]; exist { - if _, alreadyHas := bc.diffPeersToDiffHashes[pid][diffLayer.DiffHash]; alreadyHas { + if _, alreadyHas := bc.diffPeersToDiffHashes[pid][diffHash]; alreadyHas { return nil } } else { bc.diffPeersToDiffHashes[pid] = make(map[common.Hash]struct{}) } - bc.diffPeersToDiffHashes[pid][diffLayer.DiffHash] = struct{}{} + bc.diffPeersToDiffHashes[pid][diffHash] = struct{}{} if _, exist := bc.diffNumToBlockHashes[diffLayer.Number]; !exist { bc.diffNumToBlockHashes[diffLayer.Number] = make(map[common.Hash]struct{}) } bc.diffNumToBlockHashes[diffLayer.Number][diffLayer.BlockHash] = struct{}{} - if _, exist := bc.diffHashToPeers[diffLayer.DiffHash]; !exist { - bc.diffHashToPeers[diffLayer.DiffHash] = make(map[string]struct{}) + if _, exist := bc.diffHashToPeers[diffHash]; !exist { + bc.diffHashToPeers[diffHash] = make(map[string]struct{}) } - bc.diffHashToPeers[diffLayer.DiffHash][pid] = struct{}{} + bc.diffHashToPeers[diffHash][pid] = struct{}{} if _, exist := bc.blockHashToDiffLayers[diffLayer.BlockHash]; !exist { bc.blockHashToDiffLayers[diffLayer.BlockHash] = make(map[common.Hash]*types.DiffLayer) } - bc.blockHashToDiffLayers[diffLayer.BlockHash][diffLayer.DiffHash] = diffLayer - bc.diffHashToBlockHash[diffLayer.DiffHash] = diffLayer.BlockHash + bc.blockHashToDiffLayers[diffLayer.BlockHash][diffHash] = diffLayer + bc.diffHashToBlockHash[diffHash] = diffLayer.BlockHash return nil } @@ -3083,6 +3137,10 @@ func (bc *BlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Su return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch)) } +func (bc *BlockChain) SubscribeChainBlockEvent(ch chan<- ChainHeadEvent) event.Subscription { + return bc.scope.Track(bc.chainBlockFeed.Subscribe(ch)) +} + // SubscribeChainSideEvent registers a subscription of ChainSideEvent. func (bc *BlockChain) SubscribeChainSideEvent(ch chan<- ChainSideEvent) event.Subscription { return bc.scope.Track(bc.chainSideFeed.Subscribe(ch)) @@ -3100,19 +3158,138 @@ func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscr } // Options -func EnableLightProcessor(bc *BlockChain) *BlockChain { +func EnableLightProcessor(bc *BlockChain) (*BlockChain, error) { bc.processor = NewLightStateProcessor(bc.Config(), bc, bc.engine) - return bc + return bc, nil } -func EnablePipelineCommit(bc *BlockChain) *BlockChain { +func EnablePipelineCommit(bc *BlockChain) (*BlockChain, error) { bc.pipeCommit = true - return bc + return bc, nil } func EnablePersistDiff(limit uint64) BlockChainOption { - return func(chain *BlockChain) *BlockChain { + return func(chain *BlockChain) (*BlockChain, error) { chain.diffLayerFreezerBlockLimit = limit - return chain + return chain, nil + } +} + +func EnableBlockValidator(chainConfig *params.ChainConfig, engine consensus.Engine, mode VerifyMode, peers verifyPeers) BlockChainOption { + return func(bc *BlockChain) (*BlockChain, error) { + if mode.NeedRemoteVerify() { + vm, err := NewVerifyManager(bc, peers, mode == InsecureVerify) + if err != nil { + return nil, err + } + go vm.mainLoop() + bc.validator = NewBlockValidator(chainConfig, bc, engine, EnableRemoteVerifyManager(vm)) + } + return bc, nil + } +} + +func (bc *BlockChain) GetVerifyResult(blockNumber uint64, blockHash common.Hash, diffHash common.Hash) *VerifyResult { + var res VerifyResult + res.BlockNumber = blockNumber + res.BlockHash = blockHash + + if blockNumber > bc.CurrentHeader().Number.Uint64()+maxDiffForkDist { + res.Status = types.StatusBlockTooNew + return &res + } else if blockNumber > bc.CurrentHeader().Number.Uint64() { + res.Status = types.StatusBlockNewer + return &res + } + + header := bc.GetHeaderByHash(blockHash) + if header == nil { + if blockNumber > bc.CurrentHeader().Number.Uint64()-maxDiffForkDist { + res.Status = types.StatusPossibleFork + return &res + } + + res.Status = types.StatusImpossibleFork + return &res } + + diff := bc.GetTrustedDiffLayer(blockHash) + if diff != nil { + if diff.DiffHash.Load() == nil { + hash, err := CalculateDiffHash(diff) + if err != nil { + res.Status = types.StatusUnexpectedError + return &res + } + + diff.DiffHash.Store(hash) + } + + if diffHash != diff.DiffHash.Load().(common.Hash) { + res.Status = types.StatusDiffHashMismatch + return &res + } + + res.Status = types.StatusFullVerified + res.Root = header.Root + return &res + } + + res.Status = types.StatusPartiallyVerified + res.Root = header.Root + return &res +} + +func (bc *BlockChain) GetTrustedDiffLayer(blockHash common.Hash) *types.DiffLayer { + var diff *types.DiffLayer + if cached, ok := bc.diffLayerCache.Get(blockHash); ok { + diff = cached.(*types.DiffLayer) + return diff + } + + diffStore := bc.db.DiffStore() + if diffStore != nil { + diff = rawdb.ReadDiffLayer(diffStore, blockHash) + } + return diff +} + +func CalculateDiffHash(d *types.DiffLayer) (common.Hash, error) { + if d == nil { + return common.Hash{}, fmt.Errorf("nil diff layer") + } + + diff := &types.ExtDiffLayer{ + BlockHash: d.BlockHash, + Receipts: make([]*types.ReceiptForStorage, 0), + Number: d.Number, + Codes: d.Codes, + Destructs: d.Destructs, + Accounts: d.Accounts, + Storages: d.Storages, + } + + for index, account := range diff.Accounts { + full, err := snapshot.FullAccount(account.Blob) + if err != nil { + return common.Hash{}, fmt.Errorf("decode full account error: %v", err) + } + // set account root to empty root + diff.Accounts[index].Blob = snapshot.SlimAccountRLP(full.Nonce, full.Balance, common.Hash{}, full.CodeHash) + } + + rawData, err := rlp.EncodeToBytes(diff) + if err != nil { + return common.Hash{}, fmt.Errorf("encode new diff error: %v", err) + } + + hasher := sha3.NewLegacyKeccak256() + _, err = hasher.Write(rawData) + if err != nil { + return common.Hash{}, fmt.Errorf("hasher write error: %v", err) + } + + var hash common.Hash + hasher.Sum(hash[:0]) + return hash, nil } diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index 2575843a92..7e65ac6d79 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -286,7 +286,7 @@ func rawDataToDiffLayer(data rlp.RawValue) (*types.DiffLayer, error) { hasher.Write(data) var diffHash common.Hash hasher.Sum(diffHash[:0]) - diff.DiffHash = diffHash + diff.DiffHash.Store(diffHash) hasher.Reset() return &diff, nil } @@ -484,3 +484,164 @@ func TestGetDiffAccounts(t *testing.T) { } } } + +// newTwoForkedBlockchains returns two blockchains, these two chains are generated by different +// generators, they have some same parent blocks, the number of same blocks are determined by +// testBlocks, once chain1 inserted a non-default block, chain1 and chain2 get forked. +func newTwoForkedBlockchains(len1, len2 int) (chain1 *BlockChain, chain2 *BlockChain) { + signer := types.HomesteadSigner{} + // Create a database pre-initialize with a genesis block + db1 := rawdb.NewMemoryDatabase() + db1.SetDiffStore(memorydb.New()) + (&Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db1) + engine1 := ethash.NewFaker() + chain1, _ = NewBlockChain(db1, nil, params.TestChainConfig, engine1, vm.Config{}, nil, nil, EnablePersistDiff(860000), EnableBlockValidator(params.TestChainConfig, engine1, 0, nil)) + generator1 := func(i int, block *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.SetCoinbase(testAddr) + + for idx, testBlock := range testBlocks { + // Specific block setting, the index in this generator has 1 diff from specified blockNr. + if i+1 == testBlock.blockNr { + for _, testTransaction := range testBlock.txs { + var transaction *types.Transaction + if testTransaction.to == nil { + transaction = types.NewContractCreation(block.TxNonce(testAddr), + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data) + } else { + transaction = types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data) + } + tx, err := types.SignTx(transaction, signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain1, tx) + } + break + } + + // Default block setting. + if idx == len(testBlocks)-1 { + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + for _, testTransaction := range testBlocks[0].txs { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain1, tx) + } + } + } + + } + bs1, _ := GenerateChain(params.TestChainConfig, chain1.Genesis(), ethash.NewFaker(), db1, len1, generator1) + if _, err := chain1.InsertChain(bs1); err != nil { + panic(err) + } + + // Create a database pre-initialize with a genesis block + db2 := rawdb.NewMemoryDatabase() + db2.SetDiffStore(memorydb.New()) + (&Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db2) + engine2 := ethash.NewFaker() + chain2, _ = NewBlockChain(db2, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, EnablePersistDiff(860000), EnableBlockValidator(params.TestChainConfig, engine2, 0, nil)) + generator2 := func(i int, block *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.SetCoinbase(testAddr) + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + for _, testTransaction := range testBlocks[0].txs { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain1, tx) + } + } + bs2, _ := GenerateChain(params.TestChainConfig, chain2.Genesis(), ethash.NewFaker(), db2, len2, generator2) + if _, err := chain2.InsertChain(bs2); err != nil { + panic(err) + } + + return chain1, chain2 +} + +func testGetRootByDiffHash(t *testing.T, chain1, chain2 *BlockChain, blockNumber uint64, status types.VerifyStatus) { + block2 := chain2.GetBlockByNumber(blockNumber) + if block2 == nil { + t.Fatalf("failed to find block, number: %v", blockNumber) + } + expect := VerifyResult{ + Status: status, + BlockNumber: blockNumber, + BlockHash: block2.Hash(), + } + if status.Code&0xff00 == types.StatusVerified.Code { + expect.Root = block2.Root() + } + + diffLayer2 := chain2.GetTrustedDiffLayer(block2.Hash()) + if diffLayer2 == nil { + t.Fatal("failed to find diff layer") + } + diffHash2 := types.EmptyRootHash + if status != types.StatusDiffHashMismatch { + var err error + diffHash2, err = CalculateDiffHash(diffLayer2) + if err != nil { + t.Fatalf("failed to compute diff hash: %v", err) + } + } + + if status == types.StatusPartiallyVerified { + block1 := chain1.GetBlockByNumber(blockNumber) + if block1 == nil { + t.Fatalf("failed to find block, number: %v", blockNumber) + } + chain1.diffLayerCache.Remove(block1.Hash()) + } + + result := chain1.GetVerifyResult(blockNumber, block2.Hash(), diffHash2) + if result.Status != expect.Status { + t.Fatalf("failed to verify block, number: %v, expect status: %v, real status: %v", blockNumber, expect.Status, result.Status) + } + if result.Root != expect.Root { + t.Fatalf("failed to verify block, number: %v, expect root: %v, real root: %v", blockNumber, expect.Root, result.Root) + } +} + +func TestGetRootByDiffHash(t *testing.T) { + len1 := 23 // length of blockchain1 + len2 := 35 // length of blockchain2 + plen := 11 // length of same parent blocks, which determined by testBlocks. + + chain1, chain2 := newTwoForkedBlockchains(len1, len2) + defer chain1.Stop() + defer chain2.Stop() + + hash1 := chain1.GetBlockByNumber(uint64(plen)).Hash() + hash2 := chain2.GetBlockByNumber(uint64(plen)).Hash() + if hash1 != hash2 { + t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", plen, hash2, hash1) + } + + testGetRootByDiffHash(t, chain1, chain2, 10, types.StatusFullVerified) + testGetRootByDiffHash(t, chain1, chain2, 2, types.StatusPartiallyVerified) + testGetRootByDiffHash(t, chain1, chain2, 10, types.StatusDiffHashMismatch) + testGetRootByDiffHash(t, chain1, chain2, 12, types.StatusImpossibleFork) + testGetRootByDiffHash(t, chain1, chain2, 20, types.StatusPossibleFork) + testGetRootByDiffHash(t, chain1, chain2, 24, types.StatusBlockNewer) + testGetRootByDiffHash(t, chain1, chain2, 35, types.StatusBlockTooNew) +} diff --git a/core/blockchain_notries_test.go b/core/blockchain_notries_test.go new file mode 100644 index 0000000000..7b7a977971 --- /dev/null +++ b/core/blockchain_notries_test.go @@ -0,0 +1,226 @@ +// 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 . + +// Tests that abnormal program termination (i.e.crash) and restart doesn't leave +// the database in some strange state with gaps in the chain, nor with block data +// dangling in the future. + +package core + +import ( + "math/big" + "testing" + + "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/core/vm" + "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/params" +) + +func newMockVerifyPeer() *mockVerifyPeer { + return &mockVerifyPeer{} +} + +type requestRoot struct { + blockNumber uint64 + blockHash common.Hash + diffHash common.Hash +} + +type verifFailedStatus struct { + status types.VerifyStatus + blockNumber uint64 +} + +// mockVerifyPeer is a mocking struct that simulates p2p signals for verification tasks. +type mockVerifyPeer struct { + callback func(*requestRoot) +} + +func (peer *mockVerifyPeer) setCallBack(callback func(*requestRoot)) { + peer.callback = callback +} + +func (peer *mockVerifyPeer) RequestRoot(blockNumber uint64, blockHash common.Hash, diffHash common.Hash) error { + if peer.callback != nil { + peer.callback(&requestRoot{blockNumber, blockHash, diffHash}) + } + return nil +} + +func (peer *mockVerifyPeer) ID() string { + return "mock_peer" +} + +type mockVerifyPeers struct { + peers []VerifyPeer +} + +func (peers *mockVerifyPeers) GetVerifyPeers() []VerifyPeer { + return peers.peers +} + +func newMockRemoteVerifyPeer(peers []VerifyPeer) *mockVerifyPeers { + return &mockVerifyPeers{peers} +} + +func makeTestBackendWithRemoteValidator(blocks int, mode VerifyMode, failed *verifFailedStatus) (*testBackend, *testBackend, []*types.Block, error) { + signer := types.HomesteadSigner{} + + // Create a database pre-initialize with a genesis block + db := rawdb.NewMemoryDatabase() + db.SetDiffStore(memorydb.New()) + (&Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db) + engine := ethash.NewFaker() + + db2 := rawdb.NewMemoryDatabase() + db2.SetDiffStore(memorydb.New()) + (&Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + }).MustCommit(db2) + engine2 := ethash.NewFaker() + + peer := newMockVerifyPeer() + peers := []VerifyPeer{peer} + + verifier, err := NewBlockChain(db, nil, params.TestChainConfig, engine, vm.Config{}, + nil, nil, EnablePersistDiff(100000), EnableBlockValidator(params.TestChainConfig, engine2, LocalVerify, nil)) + if err != nil { + return nil, nil, nil, err + } + + fastnode, err := NewBlockChain(db2, nil, params.TestChainConfig, engine2, vm.Config{}, + nil, nil, EnableBlockValidator(params.TestChainConfig, engine2, mode, newMockRemoteVerifyPeer(peers))) + if err != nil { + return nil, nil, nil, err + } + + generator := func(i int, block *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.SetCoinbase(testAddr) + + for idx, testBlock := range testBlocks { + // Specific block setting, the index in this generator has 1 diff from specified blockNr. + if i+1 == testBlock.blockNr { + for _, testTransaction := range testBlock.txs { + var transaction *types.Transaction + if testTransaction.to == nil { + transaction = types.NewContractCreation(block.TxNonce(testAddr), + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data) + } else { + transaction = types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data) + } + tx, err := types.SignTx(transaction, signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(verifier, tx) + } + break + } + + // Default block setting. + if idx == len(testBlocks)-1 { + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + for _, testTransaction := range testBlocks[0].txs { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, + testTransaction.value, uint64(commonGas), testTransaction.gasPrice, testTransaction.data), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(verifier, tx) + } + } + } + } + + bs, _ := GenerateChain(params.TestChainConfig, verifier.Genesis(), ethash.NewFaker(), db, blocks, generator) + + peer.setCallBack(func(req *requestRoot) { + if fastnode.validator != nil && fastnode.validator.RemoteVerifyManager() != nil { + resp := verifier.GetVerifyResult(req.blockNumber, req.blockHash, req.diffHash) + if failed != nil && req.blockNumber == failed.blockNumber { + resp.Status = failed.status + } + fastnode.validator.RemoteVerifyManager(). + HandleRootResponse( + resp, peer.ID()) + } + }) + if _, err := verifier.InsertChain(bs); err != nil { + return nil, nil, nil, err + } + + return &testBackend{ + db: db, + chain: verifier, + }, + &testBackend{ + db: db2, + chain: fastnode, + }, bs, nil +} + +func TestFastNode(t *testing.T) { + // test full mode and succeed + _, fastnode, blocks, err := makeTestBackendWithRemoteValidator(10240, FullVerify, nil) + if err != nil { + t.Fatalf(err.Error()) + } + _, err = fastnode.chain.InsertChain(blocks) + if err != nil { + t.Fatalf(err.Error()) + } + // test full mode and failed + failed := &verifFailedStatus{status: types.StatusDiffHashMismatch, blockNumber: 2048} + _, fastnode, blocks, err = makeTestBackendWithRemoteValidator(10240, FullVerify, failed) + if err != nil { + t.Fatalf(err.Error()) + } + _, err = fastnode.chain.InsertChain(blocks) + if err == nil || fastnode.chain.CurrentBlock().NumberU64() != failed.blockNumber+10 { + t.Fatalf("blocks insert should be failed at height %d", failed.blockNumber+11) + } + // test insecure mode and succeed + _, fastnode, blocks, err = makeTestBackendWithRemoteValidator(10240, InsecureVerify, nil) + if err != nil { + t.Fatalf(err.Error()) + } + _, err = fastnode.chain.InsertChain(blocks) + if err != nil { + t.Fatalf(err.Error()) + } + // test insecure mode and failed + failed = &verifFailedStatus{status: types.StatusImpossibleFork, blockNumber: 2048} + _, fastnode, blocks, err = makeTestBackendWithRemoteValidator(10240, FullVerify, failed) + if err != nil { + t.Fatalf(err.Error()) + } + _, err = fastnode.chain.InsertChain(blocks) + if err == nil || fastnode.chain.CurrentBlock().NumberU64() != failed.blockNumber+10 { + t.Fatalf("blocks insert should be failed at height %d", failed.blockNumber+11) + } +} diff --git a/core/blockchain_test.go b/core/blockchain_test.go index f7a4ff53f1..35ac5ce426 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -252,7 +252,7 @@ func TestBlockImportVerification(t *testing.T) { } defer processor.Stop() // Start fork from current height - processor = EnablePipelineCommit(processor) + processor, _ = EnablePipelineCommit(processor) testInvalidStateRootBlockImport(t, processor, length, 10, true) } diff --git a/core/error.go b/core/error.go index 0830a699fe..8934ef719c 100644 --- a/core/error.go +++ b/core/error.go @@ -35,6 +35,12 @@ var ( // ErrDiffLayerNotFound is returned when diff layer not found. ErrDiffLayerNotFound = errors.New("diff layer not found") + // ErrDiffLayerNotFound is returned when block - 11 has not been verified by the remote verifier. + ErrAncestorHasNotBeenVerified = errors.New("block ancestor has not been verified") + + // ErrCurrentBlockNotFound is returned when current block not found. + ErrCurrentBlockNotFound = errors.New("current block not found") + // ErrKnownBadBlock is return when the block is a known bad block ErrKnownBadBlock = errors.New("already known bad block") ) diff --git a/core/remote_state_verifier.go b/core/remote_state_verifier.go new file mode 100644 index 0000000000..cb8d2366bb --- /dev/null +++ b/core/remote_state_verifier.go @@ -0,0 +1,446 @@ +package core + +import ( + "fmt" + "math/big" + "math/rand" + "sync" + "time" + + lru "github.com/hashicorp/golang-lru" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +const ( + verifiedCacheSize = 256 + maxForkHeight = 11 + + // defaultPeerNumber is default number of verify peers + defaultPeerNumber = 3 + // pruneHeightDiff indicates that if the height difference between current block and task's + // corresponding block is larger than it, the task should be pruned. + pruneHeightDiff = 15 + pruneInterval = 5 * time.Second + resendInterval = 2 * time.Second + // tryAllPeersTime is the time that a block has not been verified and then try all the valid verify peers. + tryAllPeersTime = 15 * time.Second + // maxWaitVerifyResultTime is the max time of waiting for ancestor's verify result. + maxWaitVerifyResultTime = 30 * time.Second +) + +var ( + verifyTaskCounter = metrics.NewRegisteredCounter("verifymanager/task/total", nil) + verifyTaskSucceedMeter = metrics.NewRegisteredMeter("verifymanager/task/result/succeed", nil) + verifyTaskFailedMeter = metrics.NewRegisteredMeter("verifymanager/task/result/failed", nil) + + verifyTaskExecutionTimer = metrics.NewRegisteredTimer("verifymanager/task/execution", nil) +) + +type remoteVerifyManager struct { + bc *BlockChain + taskLock sync.RWMutex + tasks map[common.Hash]*verifyTask + peers verifyPeers + verifiedCache *lru.Cache + allowInsecure bool + + // Subscription + chainBlockCh chan ChainHeadEvent + chainHeadSub event.Subscription + + // Channels + verifyCh chan common.Hash + messageCh chan verifyMessage +} + +func NewVerifyManager(blockchain *BlockChain, peers verifyPeers, allowInsecure bool) (*remoteVerifyManager, error) { + verifiedCache, _ := lru.New(verifiedCacheSize) + block := blockchain.CurrentBlock() + if block == nil { + return nil, ErrCurrentBlockNotFound + } + + // rewind to last non verified block + number := new(big.Int).Sub(block.Number(), big.NewInt(int64(maxForkHeight))) + if number.Cmp(common.Big0) < 0 { + blockchain.SetHead(0) + } else { + numberU64 := number.Uint64() + blockchain.SetHead(numberU64) + block := blockchain.GetBlockByNumber(numberU64) + for i := 0; i < maxForkHeight && block.NumberU64() > 0; i++ { + // When inserting a block, + // the block before 11 blocks will be verified, + // so the parent block of 11-22 will directly write the verification information. + verifiedCache.Add(block.Hash(), true) + block = blockchain.GetBlockByHash(block.ParentHash()) + if block == nil { + return nil, fmt.Errorf("block is nil, number: %d", number) + } + } + } + + vm := &remoteVerifyManager{ + bc: blockchain, + tasks: make(map[common.Hash]*verifyTask), + peers: peers, + verifiedCache: verifiedCache, + allowInsecure: allowInsecure, + + chainBlockCh: make(chan ChainHeadEvent, chainHeadChanSize), + verifyCh: make(chan common.Hash, maxForkHeight), + messageCh: make(chan verifyMessage), + } + vm.chainHeadSub = blockchain.SubscribeChainBlockEvent(vm.chainBlockCh) + return vm, nil +} + +func (vm *remoteVerifyManager) mainLoop() { + defer vm.chainHeadSub.Unsubscribe() + + pruneTicker := time.NewTicker(pruneInterval) + defer pruneTicker.Stop() + for { + select { + case h := <-vm.chainBlockCh: + vm.NewBlockVerifyTask(h.Block.Header()) + case hash := <-vm.verifyCh: + vm.cacheBlockVerified(hash) + vm.taskLock.Lock() + if task, ok := vm.tasks[hash]; ok { + vm.CloseTask(task) + verifyTaskSucceedMeter.Mark(1) + verifyTaskExecutionTimer.Update(time.Since(task.startAt)) + } + vm.taskLock.Unlock() + case <-pruneTicker.C: + vm.taskLock.Lock() + for _, task := range vm.tasks { + if vm.bc.insertStopped() || (vm.bc.CurrentHeader().Number.Cmp(task.blockHeader.Number) == 1 && + vm.bc.CurrentHeader().Number.Uint64()-task.blockHeader.Number.Uint64() > pruneHeightDiff) { + vm.CloseTask(task) + verifyTaskFailedMeter.Mark(1) + } + } + vm.taskLock.Unlock() + case message := <-vm.messageCh: + vm.taskLock.RLock() + if vt, ok := vm.tasks[message.verifyResult.BlockHash]; ok { + vt.messageCh <- message + } + vm.taskLock.RUnlock() + // System stopped + case <-vm.bc.quit: + vm.taskLock.RLock() + for _, task := range vm.tasks { + task.Close() + } + vm.taskLock.RUnlock() + return + case <-vm.chainHeadSub.Err(): + return + } + } +} + +func (vm *remoteVerifyManager) NewBlockVerifyTask(header *types.Header) { + for i := 0; header != nil && i <= maxForkHeight; i++ { + // if is genesis block, mark it as verified and break. + if header.Number.Uint64() == 0 { + vm.cacheBlockVerified(header.Hash()) + break + } + func(hash common.Hash) { + // if verified cache record that this block has been verified, skip. + if _, ok := vm.verifiedCache.Get(hash); ok { + return + } + // if there already has a verify task for this block, skip. + vm.taskLock.RLock() + _, ok := vm.tasks[hash] + vm.taskLock.RUnlock() + if ok { + return + } + + if header.TxHash == types.EmptyRootHash { + log.Debug("this is an empty block:", "block", hash, "number", header.Number) + vm.cacheBlockVerified(hash) + return + } + + var diffLayer *types.DiffLayer + if cached, ok := vm.bc.diffLayerChanCache.Get(hash); ok { + diffLayerCh := cached.(chan struct{}) + <-diffLayerCh + diffLayer = vm.bc.GetTrustedDiffLayer(hash) + } + // if this block has no diff, there is no need to verify it. + if diffLayer == nil { + log.Info("block's trusted diffLayer is nil", "hash", hash, "number", header.Number) + return + } + diffHash, err := CalculateDiffHash(diffLayer) + if err != nil { + log.Error("failed to get diff hash", "block", hash, "number", header.Number, "error", err) + return + } + verifyTask := NewVerifyTask(diffHash, header, vm.peers, vm.verifyCh, vm.allowInsecure) + vm.taskLock.Lock() + vm.tasks[hash] = verifyTask + vm.taskLock.Unlock() + verifyTaskCounter.Inc(1) + }(header.Hash()) + header = vm.bc.GetHeaderByHash(header.ParentHash) + } +} + +func (vm *remoteVerifyManager) cacheBlockVerified(hash common.Hash) { + if vm.verifiedCache.Len() >= verifiedCacheSize { + vm.verifiedCache.RemoveOldest() + } + vm.verifiedCache.Add(hash, true) +} + +// AncestorVerified function check block has been verified or it's a empty block. +func (vm *remoteVerifyManager) AncestorVerified(header *types.Header) bool { + // find header of H-11 block. + header = vm.bc.GetHeaderByNumber(header.Number.Uint64() - maxForkHeight) + // If start from genesis block, there has not a H-11 block. + if header == nil { + return true + } + + hash := header.Hash() + + // Check if the task is complete + vm.taskLock.RLock() + task, exist := vm.tasks[hash] + vm.taskLock.RUnlock() + timeout := time.NewTimer(maxWaitVerifyResultTime) + defer timeout.Stop() + if exist { + select { + case <-task.terminalCh: + case <-timeout.C: + return false + } + } + + _, exist = vm.verifiedCache.Get(hash) + return exist +} + +func (vm *remoteVerifyManager) HandleRootResponse(vr *VerifyResult, pid string) error { + vm.messageCh <- verifyMessage{verifyResult: vr, peerId: pid} + return nil +} + +func (vm *remoteVerifyManager) CloseTask(task *verifyTask) { + delete(vm.tasks, task.blockHeader.Hash()) + task.Close() + verifyTaskCounter.Dec(1) +} + +type VerifyResult struct { + Status types.VerifyStatus + BlockNumber uint64 + BlockHash common.Hash + Root common.Hash +} + +type verifyMessage struct { + verifyResult *VerifyResult + peerId string +} + +type verifyTask struct { + diffhash common.Hash + blockHeader *types.Header + candidatePeers verifyPeers + badPeers map[string]struct{} + startAt time.Time + allowInsecure bool + + messageCh chan verifyMessage + terminalCh chan struct{} +} + +func NewVerifyTask(diffhash common.Hash, header *types.Header, peers verifyPeers, verifyCh chan common.Hash, allowInsecure bool) *verifyTask { + vt := &verifyTask{ + diffhash: diffhash, + blockHeader: header, + candidatePeers: peers, + badPeers: make(map[string]struct{}), + allowInsecure: allowInsecure, + messageCh: make(chan verifyMessage), + terminalCh: make(chan struct{}), + } + go vt.Start(verifyCh) + return vt +} + +func (vt *verifyTask) Close() { + // It is safe to call close multiple + select { + case <-vt.terminalCh: + default: + close(vt.terminalCh) + } +} + +func (vt *verifyTask) Start(verifyCh chan common.Hash) { + vt.startAt = time.Now() + + vt.sendVerifyRequest(defaultPeerNumber) + resend := time.NewTicker(resendInterval) + defer resend.Stop() + for { + select { + case msg := <-vt.messageCh: + switch msg.verifyResult.Status { + case types.StatusFullVerified: + vt.compareRootHashAndMark(msg, verifyCh) + case types.StatusPartiallyVerified: + log.Warn("block is insecure verified", "hash", msg.verifyResult.BlockHash, "number", msg.verifyResult.BlockNumber) + if vt.allowInsecure { + vt.compareRootHashAndMark(msg, verifyCh) + } + case types.StatusDiffHashMismatch, types.StatusImpossibleFork, types.StatusUnexpectedError: + vt.badPeers[msg.peerId] = struct{}{} + log.Info("peer is not available", "hash", msg.verifyResult.BlockHash, "number", msg.verifyResult.BlockNumber, "peer", msg.peerId, "reason", msg.verifyResult.Status.Msg) + case types.StatusBlockTooNew, types.StatusBlockNewer, types.StatusPossibleFork: + log.Info("return msg from peer", "peerId", msg.peerId, "hash", msg.verifyResult.BlockHash, "msg", msg.verifyResult.Status.Msg) + } + newVerifyMsgTypeGauge(msg.verifyResult.Status.Code, msg.peerId).Inc(1) + case <-resend.C: + // if a task has run over 15s, try all the vaild peers to verify. + if time.Since(vt.startAt) < tryAllPeersTime { + vt.sendVerifyRequest(1) + } else { + vt.sendVerifyRequest(-1) + } + case <-vt.terminalCh: + return + } + } +} + +// sendVerifyRequest func select at most n peers from (candidatePeers-badPeers) randomly and send verify request. +// when n<0, send to all the peers exclude badPeers. +func (vt *verifyTask) sendVerifyRequest(n int) { + var validPeers []VerifyPeer + candidatePeers := vt.candidatePeers.GetVerifyPeers() + for _, p := range candidatePeers { + if _, ok := vt.badPeers[p.ID()]; !ok { + validPeers = append(validPeers, p) + } + } + // if has not valid peer, log warning. + if len(validPeers) == 0 { + log.Warn("there is no valid peer for block", "number", vt.blockHeader.Number) + return + } + + if n < len(validPeers) && n > 0 { + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(validPeers), func(i, j int) { validPeers[i], validPeers[j] = validPeers[j], validPeers[i] }) + } else { + n = len(validPeers) + } + for i := 0; i < n; i++ { + p := validPeers[i] + p.RequestRoot(vt.blockHeader.Number.Uint64(), vt.blockHeader.Hash(), vt.diffhash) + } +} + +func (vt *verifyTask) compareRootHashAndMark(msg verifyMessage, verifyCh chan common.Hash) { + if msg.verifyResult.Root == vt.blockHeader.Root { + // write back to manager so that manager can cache the result and delete this task. + verifyCh <- msg.verifyResult.BlockHash + } else { + vt.badPeers[msg.peerId] = struct{}{} + } +} + +type VerifyPeer interface { + RequestRoot(blockNumber uint64, blockHash common.Hash, diffHash common.Hash) error + ID() string +} + +type verifyPeers interface { + GetVerifyPeers() []VerifyPeer +} + +type VerifyMode uint32 + +const ( + LocalVerify VerifyMode = iota + FullVerify + InsecureVerify + NoneVerify +) + +func (mode VerifyMode) IsValid() bool { + return mode >= LocalVerify && mode <= NoneVerify +} + +func (mode VerifyMode) String() string { + switch mode { + case LocalVerify: + return "local" + case FullVerify: + return "full" + case InsecureVerify: + return "insecure" + case NoneVerify: + return "none" + default: + return "unknown" + } +} + +func (mode VerifyMode) MarshalText() ([]byte, error) { + switch mode { + case LocalVerify: + return []byte("local"), nil + case FullVerify: + return []byte("full"), nil + case InsecureVerify: + return []byte("insecure"), nil + case NoneVerify: + return []byte("none"), nil + default: + return nil, fmt.Errorf("unknown verify mode %d", mode) + } +} + +func (mode *VerifyMode) UnmarshalText(text []byte) error { + switch string(text) { + case "local": + *mode = LocalVerify + case "full": + *mode = FullVerify + case "insecure": + *mode = InsecureVerify + case "none": + *mode = NoneVerify + default: + return fmt.Errorf(`unknown sync mode %q, want "full", "light" or "insecure"`, text) + } + return nil +} + +func (mode VerifyMode) NeedRemoteVerify() bool { + return mode == FullVerify || mode == InsecureVerify +} + +func newVerifyMsgTypeGauge(msgType uint16, peerId string) metrics.Gauge { + m := fmt.Sprintf("verifymanager/message/%d/peer/%s", msgType, peerId) + return metrics.GetOrRegisterGauge(m, nil) +} diff --git a/core/state/database.go b/core/state/database.go index 487589324c..dd114dc6ad 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -74,6 +74,9 @@ type Database interface { // Purge cache Purge() + + // NoTries returns whether the database has tries storage. + NoTries() bool } // Trie is a Ethereum Merkle Patricia trie. @@ -134,10 +137,12 @@ func NewDatabase(db ethdb.Database) Database { func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { csc, _ := lru.New(codeSizeCacheSize) cc, _ := lru.New(codeCacheSize) + noTries := config != nil && config.NoTries return &cachingDB{ db: trie.NewDatabaseWithConfig(db, config), codeSizeCache: csc, codeCache: cc, + noTries: noTries, } } @@ -146,6 +151,7 @@ func NewDatabaseWithConfigAndCache(db ethdb.Database, config *trie.Config) Datab cc, _ := lru.New(codeCacheSize) atc, _ := lru.New(accountTrieCacheSize) stc, _ := lru.New(storageTrieCacheSize) + noTries := config != nil && config.NoTries database := &cachingDB{ db: trie.NewDatabaseWithConfig(db, config), @@ -153,8 +159,11 @@ func NewDatabaseWithConfigAndCache(db ethdb.Database, config *trie.Config) Datab codeCache: cc, accountTrieCache: atc, storageTrieCache: stc, + noTries: noTries, + } + if !noTries { + go database.purgeLoop() } - go database.purgeLoop() return database } @@ -164,6 +173,7 @@ type cachingDB struct { codeCache *lru.Cache accountTrieCache *lru.Cache storageTrieCache *lru.Cache + noTries bool } type triePair struct { @@ -187,6 +197,9 @@ func (db *cachingDB) purgeLoop() { // OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { + if db.noTries { + return trie.NewEmptyTrie(), nil + } if db.accountTrieCache != nil { if tr, exist := db.accountTrieCache.Get(root); exist { return tr.(Trie).(*trie.SecureTrie).Copy(), nil @@ -201,6 +214,9 @@ 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) { + if db.noTries { + return trie.NewEmptyTrie(), nil + } if db.storageTrieCache != nil { if tries, exist := db.storageTrieCache.Get(addrHash); exist { triesPairs := tries.([3]*triePair) @@ -246,6 +262,10 @@ func (db *cachingDB) CacheStorage(addrHash common.Hash, root common.Hash, t Trie } } +func (db *cachingDB) NoTries() bool { + return db.noTries +} + func (db *cachingDB) Purge() { if db.storageTrieCache != nil { db.storageTrieCache.Purge() @@ -263,6 +283,8 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { switch t := t.(type) { case *trie.SecureTrie: return t.Copy() + case *trie.EmptyTrie: + 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 b222bb97bb..42808394d5 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -31,6 +31,7 @@ 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/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" @@ -103,7 +104,7 @@ func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize, trie if headBlock == nil { return nil, errors.New("Failed to load head block") } - snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, int(triesInMemory), headBlock.Root(), false, false, false) + snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, int(triesInMemory), headBlock.Root(), false, false, false, false) if err != nil { return nil, err // The relevant snapshot(s) might not exist } @@ -138,6 +139,105 @@ func NewBlockPruner(db ethdb.Database, n *node.Node, oldAncientPath, newAncientP } } +func NewAllPruner(db ethdb.Database) (*Pruner, error) { + headBlock := rawdb.ReadHeadBlock(db) + if headBlock == nil { + return nil, errors.New("Failed to load head block") + } + return &Pruner{ + db: db, + }, nil +} + +func (p *Pruner) PruneAll(genesis *core.Genesis) error { + deleteCleanTrieCache(p.trieCachePath) + return pruneAll(p.db, genesis) +} + +func pruneAll(maindb ethdb.Database, g *core.Genesis) error { + var ( + count int + size common.StorageSize + pstart = time.Now() + logged = time.Now() + batch = maindb.NewBatch() + iter = maindb.NewIterator(nil, nil) + ) + start := time.Now() + for iter.Next() { + key := iter.Key() + if len(key) == common.HashLength { + count += 1 + size += common.StorageSize(len(key) + len(iter.Value())) + batch.Delete(key) + + var eta time.Duration // Realistically will never remain uninited + if done := binary.BigEndian.Uint64(key[:8]); done > 0 { + var ( + left = math.MaxUint64 - binary.BigEndian.Uint64(key[:8]) + speed = done/uint64(time.Since(pstart)/time.Millisecond+1) + 1 // +1s to avoid division by zero + ) + eta = time.Duration(left/speed) * time.Millisecond + } + if time.Since(logged) > 8*time.Second { + log.Info("Pruning state data", "nodes", count, "size", size, + "elapsed", common.PrettyDuration(time.Since(pstart)), "eta", common.PrettyDuration(eta)) + logged = time.Now() + } + // Recreate the iterator after every batch commit in order + // to allow the underlying compactor to delete the entries. + if batch.ValueSize() >= ethdb.IdealBatchSize { + batch.Write() + batch.Reset() + + iter.Release() + iter = maindb.NewIterator(nil, key) + } + } + } + if batch.ValueSize() > 0 { + batch.Write() + batch.Reset() + } + iter.Release() + log.Info("Pruned state data", "nodes", count, "size", size, "elapsed", common.PrettyDuration(time.Since(pstart))) + + // Start compactions, will remove the deleted data from the disk immediately. + // Note for small pruning, the compaction is skipped. + if count >= rangeCompactionThreshold { + cstart := time.Now() + for b := 0x00; b <= 0xf0; b += 0x10 { + var ( + start = []byte{byte(b)} + end = []byte{byte(b + 0x10)} + ) + if b == 0xf0 { + end = nil + } + log.Info("Compacting database", "range", fmt.Sprintf("%#x-%#x", start, end), "elapsed", common.PrettyDuration(time.Since(cstart))) + if err := maindb.Compact(start, end); err != nil { + log.Error("Database compaction failed", "error", err) + return err + } + } + log.Info("Database compaction finished", "elapsed", common.PrettyDuration(time.Since(cstart))) + } + statedb, _ := state.New(common.Hash{}, state.NewDatabase(maindb), nil) + for addr, account := range g.Alloc { + 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 := statedb.IntermediateRoot(false) + statedb.Commit(nil) + statedb.Database().TrieDB().Commit(root, true, nil) + log.Info("State pruning successful", "pruned", size, "elapsed", common.PrettyDuration(time.Since(start))) + return nil +} + func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, stateBloom *stateBloom, bloomPath string, middleStateRoots map[common.Hash]struct{}, start time.Time) error { // Delete all stale trie nodes in the disk. With the help of state bloom // the trie nodes(and codes) belong to the active state will be filtered @@ -585,7 +685,7 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string, tri // - 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, int(triesInMemory), headBlock.Root(), false, false, true) + snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, int(triesInMemory), headBlock.Root(), false, false, true, false) 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 587f78a474..aabbfd7e1b 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -126,7 +126,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, cache int, root common.Hash, recovery, withoutTrie 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) { @@ -145,6 +145,7 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, root: baseRoot, } snapshot, generator, err := loadAndParseJournal(diskdb, base) + if err != nil { log.Warn("Failed to load new-format journal", "error", err) return nil, false, err @@ -158,6 +159,11 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, // which is below the snapshot. In this case the snapshot can be recovered // by re-executing blocks but right now it's unavailable. if head := snapshot.Root(); head != root { + log.Warn("Snapshot is not continuous with chain", "snaproot", head, "chainroot", root) + + if withoutTrie { + return snapshot, false, nil + } // If it's legacy snapshot, or it's new-format snapshot but // it's not in recovery mode, returns the error here for // rebuilding the entire snapshot forcibly. @@ -168,7 +174,6 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, // the disk layer is always higher than chain head. It can // be eventually recovered when the chain head beyonds the // disk layer. - log.Warn("Snapshot is not continuous with chain", "snaproot", head, "chainroot", root) } // Everything loaded correctly, resume any suspended operations if !generator.Done { diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 7ad4bcc91b..d28d2e295e 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -194,7 +194,7 @@ type Tree struct { // store, on a background thread. If the memory layers from the journal is not // continuous with disk layer or the journal is missing, all diffs will be discarded // iff it's in "recovery" mode, otherwise rebuild is mandatory. -func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache, cap int, root common.Hash, async bool, rebuild bool, recovery bool) (*Tree, error) { +func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache, cap int, root common.Hash, async bool, rebuild bool, recovery, withoutTrie bool) (*Tree, error) { // Create a new, empty snapshot tree snap := &Tree{ diskdb: diskdb, @@ -207,7 +207,7 @@ func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache, cap int, root 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, cache, root, recovery, withoutTrie) if disabled { log.Warn("Snapshot maintenance disabled (syncing)") return snap, nil diff --git a/core/state/state_object.go b/core/state/state_object.go index ad6fbf5f89..e3e0fe29a3 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -18,6 +18,7 @@ package state import ( "bytes" + "errors" "fmt" "io" "math/big" @@ -25,11 +26,14 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" ) +const snapshotStaleRetryInterval = time.Millisecond * 10 + var emptyCodeHash = crypto.Keccak256(nil) type Code []byte @@ -274,6 +278,18 @@ func (s *StateObject) GetCommittedState(db Database, key common.Hash) common.Has } enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) } + // ErrSnapshotStale may occur due to diff layers in the update, so we should try again in noTrie mode. + if s.db.NoTrie() && err != nil && errors.Is(err, snapshot.ErrSnapshotStale) { + // This error occurs when statedb.snaps.Cap changes the state of the merged difflayer + // to stale during the refresh of the difflayer, indicating that it is about to be discarded. + // Since the difflayer is refreshed in parallel, + // there is a small chance that the difflayer of the stale will be read while reading, + // resulting in an empty array being returned here. + // Therefore, noTrie mode must retry here, + // and add a time interval when retrying to avoid stacking too much and causing stack overflow. + time.Sleep(snapshotStaleRetryInterval) + return s.GetCommittedState(db, key) + } // If snapshot unavailable or reading from it failed, load from the database if s.db.snap == nil || err != nil { if meter != nil { @@ -452,6 +468,13 @@ func (s *StateObject) updateTrie(db Database) Trie { // UpdateRoot sets the trie root to the current root hash of func (s *StateObject) updateRoot(db Database) { + // If node runs in no trie mode, set root to empty. + defer func() { + if db.NoTries() { + s.data.Root = common.Hash{} + } + }() + // If nothing changed, don't bother with hashing anything if s.updateTrie(db) == nil { return diff --git a/core/state/statedb.go b/core/state/statedb.go index d4d02ad039..6ef45c2861 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -82,6 +82,7 @@ type StateDB struct { stateRoot common.Hash // The calculation result of IntermediateRoot trie Trie + noTrie bool hasher crypto.KeccakState diffLayer *types.DiffLayer diffTries map[common.Address]Trie @@ -174,6 +175,7 @@ func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, journal: newJournal(), hasher: crypto.NewKeccakState(), } + if sdb.snaps != nil { if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil { sdb.snapDestructs = make(map[common.Address]struct{}) @@ -188,6 +190,7 @@ func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, if err != nil && (sdb.snap == nil || snapVerified) { return nil, err } + _, sdb.noTrie = tr.(*trie.EmptyTrie) sdb.trie = tr return sdb, nil } @@ -200,6 +203,9 @@ func (s *StateDB) EnableWriteOnSharedStorage() { // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. func (s *StateDB) StartPrefetcher(namespace string) { + if s.noTrie { + return + } s.prefetcherLock.Lock() defer s.prefetcherLock.Unlock() if s.prefetcher != nil { @@ -214,6 +220,9 @@ func (s *StateDB) StartPrefetcher(namespace string) { // StopPrefetcher terminates a running prefetcher and reports any leftover stats // from the gathered metrics. func (s *StateDB) StopPrefetcher() { + if s.noTrie { + return + } s.prefetcherLock.Lock() defer s.prefetcherLock.Unlock() if s.prefetcher != nil { @@ -260,6 +269,10 @@ func (s *StateDB) setError(err error) { } } +func (s *StateDB) NoTrie() bool { + return s.noTrie +} + func (s *StateDB) Error() error { return s.dbErr } @@ -572,6 +585,9 @@ func (s *StateDB) Suicide(addr common.Address) bool { // updateStateObject writes the given object to the trie. func (s *StateDB) updateStateObject(obj *StateObject) { + if s.noTrie { + return + } // Track the amount of time wasted on updating the account from the trie if metrics.EnabledExpensive { defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) @@ -593,6 +609,9 @@ func (s *StateDB) updateStateObject(obj *StateObject) { // deleteStateObject removes the given object from the state trie. func (s *StateDB) deleteStateObject(obj *StateObject) { + if s.noTrie { + return + } // Track the amount of time wasted on deleting the account from the trie if metrics.EnabledExpensive { defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) @@ -651,6 +670,20 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *StateObject { } } } + + // ErrSnapshotStale may occur due to diff layers in the update, so we should try again in noTrie mode. + if s.NoTrie() && err != nil && errors.Is(err, snapshot.ErrSnapshotStale) { + // This error occurs when statedb.snaps.Cap changes the state of the merged difflayer + // to stale during the refresh of the difflayer, indicating that it is about to be discarded. + // Since the difflayer is refreshed in parallel, + // there is a small chance that the difflayer of the stale will be read while reading, + // resulting in an empty array being returned here. + // Therefore, noTrie mode must retry here, + // and add a time interval when retrying to avoid stacking too much and causing OOM. + time.Sleep(snapshotStaleRetryInterval) + return s.getDeletedStateObject(addr) + } + // If snapshot unavailable or reading from it failed, load from the database if s.snap == nil || err != nil { if s.trie == nil { @@ -965,6 +998,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // It is called in between transactions to get the root hash that // goes into transaction receipts. func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { + // light process is not allowed when there is no trie if s.lightProcessed { s.StopPrefetcher() return s.trie.Hash() @@ -1132,16 +1166,18 @@ func (s *StateDB) StateIntermediateRoot() common.Hash { } usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) - for addr := range s.stateObjectsPending { - if obj := s.stateObjects[addr]; obj.deleted { - s.deleteStateObject(obj) - } else { - s.updateStateObject(obj) + if !s.noTrie { + for addr := range s.stateObjectsPending { + if obj := s.stateObjects[addr]; obj.deleted { + s.deleteStateObject(obj) + } else { + s.updateStateObject(obj) + } + usedAddrs = append(usedAddrs, common.CopyBytes(addr[:])) // Copy needed for closure + } + if prefetcher != nil { + prefetcher.used(s.originalRoot, usedAddrs) } - usedAddrs = append(usedAddrs, common.CopyBytes(addr[:])) // Copy needed for closure - } - if prefetcher != nil { - prefetcher.used(s.originalRoot, usedAddrs) } if len(s.stateObjectsPending) > 0 { @@ -1151,8 +1187,11 @@ func (s *StateDB) StateIntermediateRoot() common.Hash { if metrics.EnabledExpensive { defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) } - root := s.trie.Hash() - return root + if s.noTrie { + return s.expectedRoot + } else { + return s.trie.Hash() + } } // Prepare sets the current transaction hash and index and block hash which is @@ -1378,8 +1417,13 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er // Write any contract code associated with the state object tasks <- func() { // Write any storage changes in the state object to its storage trie - err := obj.CommitTrie(s.db) - taskResults <- err + if !s.noTrie { + if err := obj.CommitTrie(s.db); err != nil { + taskResults <- err + return + } + } + taskResults <- nil } tasksNum++ } @@ -1396,24 +1440,27 @@ func (s *StateDB) Commit(failPostCommitFunc func(), postCommitFuncs ...func() er // The onleaf func is called _serially_, so we can reuse the same account // for unmarshalling every time. - var account Account - root, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash) error { - if err := rlp.DecodeBytes(leaf, &account); err != nil { + if !s.noTrie { + var account Account + root, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash) error { + if err := rlp.DecodeBytes(leaf, &account); err != nil { + return nil + } + if account.Root != emptyRoot { + s.db.TrieDB().Reference(account.Root, parent) + } return nil + }) + if err != nil { + return err } - if account.Root != emptyRoot { - s.db.TrieDB().Reference(account.Root, parent) + if root != emptyRoot { + s.db.CacheAccount(root, s.trie) } - return nil - }) - if err != nil { - return err - } - if root != emptyRoot { - s.db.CacheAccount(root, s.trie) } + for _, postFunc := range postCommitFuncs { - err = postFunc() + err := postFunc() if err != nil { return err } diff --git a/core/state_processor.go b/core/state_processor.go index cdaaf1e643..6b9586f8d3 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -118,7 +118,7 @@ func (p *LightStateProcessor) Process(block *types.Block, statedb *state.StateDB return statedb, receipts, logs, gasUsed, nil } log.Error("do light process err at block", "num", block.NumberU64(), "err", err) - p.bc.removeDiffLayers(diffLayer.DiffHash) + p.bc.removeDiffLayers(diffLayer.DiffHash.Load().(common.Hash)) // prepare new statedb statedb.StopPrefetcher() parent := p.bc.GetHeader(block.ParentHash(), block.NumberU64()-1) @@ -407,6 +407,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // usually do have two tx, one for validator set contract, another for system reward contract. systemTxs := make([]*types.Transaction, 0, 2) + for i, tx := range block.Transactions() { if isPoSA { if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { @@ -424,12 +425,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return statedb, nil, nil, 0, err } statedb.Prepare(tx.Hash(), block.Hash(), i) + receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv, bloomProcessors) if err != nil { bloomProcessors.Close() return statedb, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } - commonTxs = append(commonTxs, tx) receipts = append(receipts, receipt) } diff --git a/core/types.go b/core/types.go index 7736ebacd1..d0469dfcb6 100644 --- a/core/types.go +++ b/core/types.go @@ -32,6 +32,8 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error + // RemoteVerifyManager return remoteVerifyManager of validator. + RemoteVerifyManager() *remoteVerifyManager } // Prefetcher is an interface for pre-caching transaction signatures and state. diff --git a/core/types/block.go b/core/types/block.go index bee5d80cdd..7be5b2a3ed 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -40,6 +40,32 @@ var ( EmptyUncleHash = rlpHash([]*Header(nil)) ) +type VerifyStatus struct { + Code uint16 + Msg string +} + +var ( + // StatusVerified means the processing of request going as expected and found the root correctly. + StatusVerified = VerifyStatus{Code: 0x100} + StatusFullVerified = VerifyStatus{Code: 0x101, Msg: "state root full verified"} + StatusPartiallyVerified = VerifyStatus{Code: 0x102, Msg: "state root partially verified, because of difflayer not found"} + + // StatusFailed means the request has something wrong. + StatusFailed = VerifyStatus{Code: 0x200} + StatusDiffHashMismatch = VerifyStatus{Code: 0x201, Msg: "verify failed because of blockhash mismatch with diffhash"} + StatusImpossibleFork = VerifyStatus{Code: 0x202, Msg: "verify failed because of impossible fork detected"} + + // StatusUncertain means verify node can't give a certain result of the request. + StatusUncertain = VerifyStatus{Code: 0x300} + StatusBlockTooNew = VerifyStatus{Code: 0x301, Msg: "can’t verify because of block number larger than current height more than 11"} + StatusBlockNewer = VerifyStatus{Code: 0x302, Msg: "can’t verify because of block number larger than current height"} + StatusPossibleFork = VerifyStatus{Code: 0x303, Msg: "can’t verify because of possible fork detected"} + + // StatusUnexpectedError is unexpected internal error. + StatusUnexpectedError = VerifyStatus{Code: 0x400, Msg: "can’t verify because of unexpected internal error"} +) + // 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. @@ -380,10 +406,10 @@ type DiffLayer struct { Accounts []DiffAccount Storages []DiffStorage - DiffHash common.Hash + DiffHash atomic.Value } -type extDiffLayer struct { +type ExtDiffLayer struct { BlockHash common.Hash Number uint64 Receipts []*ReceiptForStorage // Receipts are duplicated stored to simplify the logic @@ -395,7 +421,7 @@ type extDiffLayer struct { // DecodeRLP decodes the Ethereum func (d *DiffLayer) DecodeRLP(s *rlp.Stream) error { - var ed extDiffLayer + var ed ExtDiffLayer if err := s.Decode(&ed); err != nil { return err } @@ -415,7 +441,7 @@ func (d *DiffLayer) EncodeRLP(w io.Writer) error { for i, receipt := range d.Receipts { storageReceipts[i] = (*ReceiptForStorage)(receipt) } - return rlp.Encode(w, extDiffLayer{ + return rlp.Encode(w, ExtDiffLayer{ BlockHash: d.BlockHash, Number: d.Number, Receipts: storageReceipts, @@ -454,6 +480,13 @@ type DiffStorage struct { Vals [][]byte } +func (storage *DiffStorage) Len() int { return len(storage.Keys) } +func (storage *DiffStorage) Swap(i, j int) { + storage.Keys[i], storage.Keys[j] = storage.Keys[j], storage.Keys[i] + storage.Vals[i], storage.Vals[j] = storage.Vals[j], storage.Vals[i] +} +func (storage *DiffStorage) Less(i, j int) bool { return storage.Keys[i] < storage.Keys[j] } + type DiffAccountsInTx struct { TxHash common.Hash Accounts map[common.Address]*big.Int diff --git a/eth/backend.go b/eth/backend.go index b9c9f9a2cb..70abc35f98 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -45,6 +45,7 @@ import ( "github.com/ethereum/go-ethereum/eth/protocols/diff" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" + "github.com/ethereum/go-ethereum/eth/protocols/trust" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -68,11 +69,12 @@ type Ethereum struct { config *ethconfig.Config // Handlers - txPool *core.TxPool - blockchain *core.BlockChain - handler *handler - ethDialCandidates enode.Iterator - snapDialCandidates enode.Iterator + txPool *core.TxPool + blockchain *core.BlockChain + handler *handler + ethDialCandidates enode.Iterator + snapDialCandidates enode.Iterator + trustDialCandidates enode.Iterator // DB interfaces chainDb ethdb.Database // Block chain database @@ -109,6 +111,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if !config.SyncMode.IsValid() { return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) } + if !config.TriesVerifyMode.IsValid() { + return nil, fmt.Errorf("invalid tries verify mode %d", config.TriesVerifyMode) + } if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 { log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) @@ -194,14 +199,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { TrieDirtyLimit: config.TrieDirtyCache, TrieDirtyDisabled: config.NoPruning, TrieTimeLimit: config.TrieTimeout, + NoTries: config.TriesVerifyMode != core.LocalVerify, SnapshotLimit: config.SnapshotCache, TriesInMemory: config.TriesInMemory, Preimages: config.Preimages, } ) bcOps := make([]core.BlockChainOption, 0) - // TODO diffsync performance is not as expected, disable it when pipecommit is enabled for now - if config.DiffSync && !config.PipeCommit { + if config.DiffSync && !config.PipeCommit && config.TriesVerifyMode == core.LocalVerify { bcOps = append(bcOps, core.EnableLightProcessor) } if config.PipeCommit { @@ -210,6 +215,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.PersistDiff { bcOps = append(bcOps, core.EnablePersistDiff(config.DiffBlock)) } + + peers := newPeerSet() + bcOps = append(bcOps, core.EnableBlockValidator(chainConfig, eth.engine, config.TriesVerifyMode, peers)) eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit, bcOps...) if err != nil { return nil, err @@ -247,6 +255,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { DirectBroadcast: config.DirectBroadcast, DiffSync: config.DiffSync, DisablePeerTxBroadcast: config.DisablePeerTxBroadcast, + PeerSet: peers, }); err != nil { return nil, err } @@ -270,6 +279,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } + eth.trustDialCandidates, err = dnsclient.NewIterator(eth.config.TrustDiscoveryURLs...) + if err != nil { + return nil, err + } // Start the RPC service eth.netRPCService = ethapi.NewPublicNetAPI(eth.p2pServer, config.NetworkId) @@ -553,7 +566,12 @@ func (s *Ethereum) Protocols() []p2p.Protocol { protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) } // diff protocol can still open without snap protocol - protos = append(protos, diff.MakeProtocols((*diffHandler)(s.handler), s.snapDialCandidates)...) + if !s.config.DisableDiffProtocol { + protos = append(protos, diff.MakeProtocols((*diffHandler)(s.handler), s.snapDialCandidates)...) + } + if s.config.EnableTrustProtocol { + protos = append(protos, trust.MakeProtocols((*trustHandler)(s.handler), s.snapDialCandidates)...) + } return protos } @@ -584,6 +602,7 @@ func (s *Ethereum) Stop() error { // Stop all the peer-related stuff first. s.ethDialCandidates.Close() s.snapDialCandidates.Close() + s.trustDialCandidates.Close() s.handler.Stop() // Then stop everything else. diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index e1225e7a1c..dcbeb1eea7 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum" "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/snapshot" "github.com/ethereum/go-ethereum/core/types" @@ -1812,6 +1813,9 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { // of the blocks delivered from the downloader, and the indexing will be off. log.Debug("Downloaded item processing failed on sidechain import", "index", index, "err", err) } + if errors.Is(err, core.ErrAncestorHasNotBeenVerified) { + return err + } return fmt.Errorf("%w: %v", errInvalidChain, err) } return nil diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index e25b55186e..1c1310686d 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -79,6 +79,7 @@ var Defaults = Config{ TrieDirtyCache: 256, TrieTimeout: 60 * time.Minute, TriesInMemory: 128, + TriesVerifyMode: core.LocalVerify, SnapshotCache: 102, DiffBlock: uint64(86400), Miner: miner.Config{ @@ -130,12 +131,15 @@ type Config struct { // This can be set to list of enrtree:// URLs which will be queried for // for nodes to connect to. - EthDiscoveryURLs []string - SnapDiscoveryURLs []string + EthDiscoveryURLs []string + SnapDiscoveryURLs []string + TrustDiscoveryURLs []string NoPruning bool // Whether to disable pruning and flush everything to disk DirectBroadcast bool DisableSnapProtocol bool //Whether disable snap protocol + DisableDiffProtocol bool //Whether disable diff protocol + EnableTrustProtocol bool //Whether enable trust protocol DiffSync bool // Whether support diff sync PipeCommit bool RangeLimit bool @@ -176,6 +180,7 @@ type Config struct { TrieTimeout time.Duration SnapshotCache int TriesInMemory uint64 + TriesVerifyMode core.VerifyMode Preimages bool // Mining options diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index b3af010714..c5c19cac75 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -3,6 +3,7 @@ package ethconfig import ( + "math/big" "time" "github.com/ethereum/go-ethereum/common" @@ -23,8 +24,15 @@ func (c Config) MarshalTOML() (interface{}, error) { DisablePeerTxBroadcast bool EthDiscoveryURLs []string SnapDiscoveryURLs []string + TrustDiscoveryURLs []string NoPruning bool NoPrefetch bool + DirectBroadcast bool + DisableSnapProtocol bool + DisableDiffProtocol bool + EnableTrustProtocol bool + DiffSync bool + RangeLimit bool TxLookupLimit uint64 `toml:",omitempty"` Whitelist map[uint64]common.Hash `toml:"-"` LightServ int `toml:",omitempty"` @@ -47,24 +55,26 @@ func (c Config) MarshalTOML() (interface{}, error) { TrieCleanCacheRejournal time.Duration `toml:",omitempty"` TrieDirtyCache int TrieTimeout time.Duration - TriesInMemory uint64 `toml:",omitempty"` SnapshotCache int + TriesInMemory uint64 + TriesVerifyMode core.VerifyMode Preimages bool PersistDiff bool DiffBlock uint64 `toml:",omitempty"` PruneAncientData bool Miner miner.Config - Ethash ethash.Config + Ethash ethash.Config `toml:",omitempty"` TxPool core.TxPoolConfig GPO gasprice.Config EnablePreimageRecording bool DocRoot string `toml:"-"` EWASMInterpreter string EVMInterpreter string - RPCGasCap uint64 `toml:",omitempty"` - RPCTxFeeCap float64 `toml:",omitempty"` + RPCGasCap uint64 + RPCTxFeeCap float64 Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` + OverrideBerlin *big.Int `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -73,7 +83,14 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.DisablePeerTxBroadcast = c.DisablePeerTxBroadcast enc.EthDiscoveryURLs = c.EthDiscoveryURLs enc.SnapDiscoveryURLs = c.SnapDiscoveryURLs + enc.TrustDiscoveryURLs = c.TrustDiscoveryURLs enc.NoPruning = c.NoPruning + enc.DirectBroadcast = c.DirectBroadcast + enc.DisableSnapProtocol = c.DisableSnapProtocol + enc.DisableDiffProtocol = c.DisableDiffProtocol + enc.EnableTrustProtocol = c.EnableTrustProtocol + enc.DiffSync = c.DiffSync + enc.RangeLimit = c.RangeLimit enc.TxLookupLimit = c.TxLookupLimit enc.Whitelist = c.Whitelist enc.LightServ = c.LightServ @@ -91,13 +108,16 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.DatabaseCache = c.DatabaseCache enc.DatabaseFreezer = c.DatabaseFreezer enc.DatabaseDiff = c.DatabaseDiff + enc.PersistDiff = c.PersistDiff + enc.DiffBlock = c.DiffBlock enc.TrieCleanCache = c.TrieCleanCache enc.TrieCleanCacheJournal = c.TrieCleanCacheJournal enc.TrieCleanCacheRejournal = c.TrieCleanCacheRejournal enc.TrieDirtyCache = c.TrieDirtyCache enc.TrieTimeout = c.TrieTimeout - enc.TriesInMemory = c.TriesInMemory enc.SnapshotCache = c.SnapshotCache + enc.TriesInMemory = c.TriesInMemory + enc.TriesVerifyMode = c.TriesVerifyMode enc.Preimages = c.Preimages enc.PersistDiff = c.PersistDiff enc.DiffBlock = c.DiffBlock @@ -114,6 +134,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCTxFeeCap = c.RPCTxFeeCap enc.Checkpoint = c.Checkpoint enc.CheckpointOracle = c.CheckpointOracle + enc.OverrideBerlin = c.OverrideBerlin return &enc, nil } @@ -126,8 +147,15 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { DisablePeerTxBroadcast *bool EthDiscoveryURLs []string SnapDiscoveryURLs []string + TrustDiscoveryURLs []string NoPruning *bool NoPrefetch *bool + DirectBroadcast *bool + DisableSnapProtocol *bool + DisableDiffProtocol *bool + EnableTrustProtocol *bool + DiffSync *bool + RangeLimit *bool TxLookupLimit *uint64 `toml:",omitempty"` Whitelist map[uint64]common.Hash `toml:"-"` LightServ *int `toml:",omitempty"` @@ -153,21 +181,23 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` TrieDirtyCache *int TrieTimeout *time.Duration - TriesInMemory *uint64 `toml:",omitempty"` SnapshotCache *int + TriesInMemory *uint64 + TriesVerifyMode *core.VerifyMode Preimages *bool Miner *miner.Config - Ethash *ethash.Config + Ethash *ethash.Config `toml:",omitempty"` TxPool *core.TxPoolConfig GPO *gasprice.Config EnablePreimageRecording *bool DocRoot *string `toml:"-"` EWASMInterpreter *string EVMInterpreter *string - RPCGasCap *uint64 `toml:",omitempty"` - RPCTxFeeCap *float64 `toml:",omitempty"` + RPCGasCap *uint64 + RPCTxFeeCap *float64 Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` + OverrideBerlin *big.Int `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -191,9 +221,30 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.SnapDiscoveryURLs != nil { c.SnapDiscoveryURLs = dec.SnapDiscoveryURLs } + if dec.TrustDiscoveryURLs != nil { + c.TrustDiscoveryURLs = dec.TrustDiscoveryURLs + } if dec.NoPruning != nil { c.NoPruning = *dec.NoPruning } + if dec.DirectBroadcast != nil { + c.DirectBroadcast = *dec.DirectBroadcast + } + if dec.DisableSnapProtocol != nil { + c.DisableSnapProtocol = *dec.DisableSnapProtocol + } + if dec.DisableDiffProtocol != nil { + c.DisableDiffProtocol = *dec.DisableDiffProtocol + } + if dec.EnableTrustProtocol != nil { + c.EnableTrustProtocol = *dec.EnableTrustProtocol + } + if dec.DiffSync != nil { + c.DiffSync = *dec.DiffSync + } + if dec.RangeLimit != nil { + c.RangeLimit = *dec.RangeLimit + } if dec.TxLookupLimit != nil { c.TxLookupLimit = *dec.TxLookupLimit } @@ -269,11 +320,14 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.TrieTimeout != nil { c.TrieTimeout = *dec.TrieTimeout } + if dec.SnapshotCache != nil { + c.SnapshotCache = *dec.SnapshotCache + } if dec.TriesInMemory != nil { c.TriesInMemory = *dec.TriesInMemory } - if dec.SnapshotCache != nil { - c.SnapshotCache = *dec.SnapshotCache + if dec.TriesVerifyMode != nil { + c.TriesVerifyMode = *dec.TriesVerifyMode } if dec.Preimages != nil { c.Preimages = *dec.Preimages @@ -314,5 +368,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.CheckpointOracle != nil { c.CheckpointOracle = dec.CheckpointOracle } + if dec.OverrideBerlin != nil { + c.OverrideBerlin = dec.OverrideBerlin + } return nil } diff --git a/eth/handler.go b/eth/handler.go index acf2000293..065bd1d8e5 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/eth/protocols/diff" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" + "github.com/ethereum/go-ethereum/eth/protocols/trust" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -95,6 +96,7 @@ type handlerConfig struct { Whitelist map[uint64]common.Hash // Hard coded whitelist for sync challenged DirectBroadcast bool DisablePeerTxBroadcast bool + PeerSet *peerSet } type handler struct { @@ -146,6 +148,9 @@ func newHandler(config *handlerConfig) (*handler, error) { if config.EventMux == nil { config.EventMux = new(event.TypeMux) // Nicety initialization for tests } + if config.PeerSet == nil { + config.PeerSet = newPeerSet() // Nicety initialization for tests + } h := &handler{ networkID: config.Network, forkFilter: forkid.NewFilter(config.Chain), @@ -154,7 +159,7 @@ func newHandler(config *handlerConfig) (*handler, error) { database: config.Database, txpool: config.TxPool, chain: config.Chain, - peers: newPeerSet(), + peers: config.PeerSet, whitelist: config.Whitelist, directBroadcast: config.DirectBroadcast, diffSync: config.DiffSync, @@ -273,6 +278,11 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Error("Diff extension barrier failed", "err", err) return err } + trust, err := h.peers.waitTrustExtension(peer) + if err != nil { + peer.Log().Error("Trust extension barrier failed", "err", err) + return err + } // TODO(karalabe): Not sure why this is needed if !h.chainSync.handlePeerEvent(peer) { return p2p.DiscQuitting @@ -313,7 +323,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Debug("Ethereum peer connected", "name", peer.Name()) // Register the peer locally - if err := h.peers.registerPeer(peer, snap, diff); err != nil { + if err := h.peers.registerPeer(peer, snap, diff, trust); err != nil { peer.Log().Error("Ethereum peer registration failed", "err", err) return err } @@ -399,6 +409,21 @@ func (h *handler) runDiffExtension(peer *diff.Peer, handler diff.Handler) error return handler(peer) } +// runTrustExtension registers a `trust` peer into the joint eth/trust peerset and +// starts handling inbound messages. As `trust` is only a satellite protocol to +// `eth`, all subsystem registrations and lifecycle management will be done by +// the main `eth` handler to prevent strange races. +func (h *handler) runTrustExtension(peer *trust.Peer, handler trust.Handler) error { + h.peerWG.Add(1) + defer h.peerWG.Done() + + if err := h.peers.registerTrustExtension(peer); err != nil { + peer.Log().Error("Trust extension registration failed", "err", err) + return err + } + return handler(peer) +} + // removePeer requests disconnection of a peer. func (h *handler) removePeer(id string) { peer := h.peers.peer(id) diff --git a/eth/handler_trust.go b/eth/handler_trust.go new file mode 100644 index 0000000000..0b116b9255 --- /dev/null +++ b/eth/handler_trust.go @@ -0,0 +1,52 @@ +package eth + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/eth/protocols/trust" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +// trustHandler implements the trust.Backend interface to handle the various network +// packets that are sent as replies or broadcasts. +type trustHandler handler + +func (h *trustHandler) Chain() *core.BlockChain { return h.chain } + +// RunPeer is invoked when a peer joins on the `snap` protocol. +func (h *trustHandler) RunPeer(peer *trust.Peer, hand trust.Handler) error { + return (*handler)(h).runTrustExtension(peer, hand) +} + +// PeerInfo retrieves all known `trust` information about a peer. +func (h *trustHandler) PeerInfo(id enode.ID) interface{} { + if p := h.peers.peer(id.String()); p != nil { + if p.trustExt != nil { + return p.trustExt.info() + } + } + return nil +} + +// Handle is invoked from a peer's message handler when it receives a new remote +// message that the handler couldn't consume and serve itself. +func (h *trustHandler) Handle(peer *trust.Peer, packet trust.Packet) error { + switch packet := packet.(type) { + case *trust.RootResponsePacket: + verifyResult := &core.VerifyResult{ + Status: packet.Status, + BlockNumber: packet.BlockNumber, + BlockHash: packet.BlockHash, + Root: packet.Root, + } + if vm := h.Chain().Validator().RemoteVerifyManager(); vm != nil { + vm.HandleRootResponse(verifyResult, peer.ID()) + return nil + } + return fmt.Errorf("verify manager is nil which is unexpected") + + default: + return fmt.Errorf("unexpected trust packet type: %T", packet) + } +} diff --git a/eth/peer.go b/eth/peer.go index 2fb6fabf26..4d92f4e78f 100644 --- a/eth/peer.go +++ b/eth/peer.go @@ -21,6 +21,8 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/eth/protocols/trust" + "github.com/ethereum/go-ethereum/eth/protocols/diff" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" @@ -37,8 +39,9 @@ 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 - diffExt *diffPeer + snapExt *snapPeer // Satellite `snap` connection + diffExt *diffPeer + trustExt *trustPeer syncDrop *time.Timer // Connection dropper if `eth` sync progress isn't validated in time snapWait chan struct{} // Notification channel for snap connections @@ -69,6 +72,12 @@ type diffPeerInfo struct { DiffSync bool `json:"diff_sync"` } +// trustPeerInfo represents a short summary of the `trust` sub-protocol metadata known +// about a connected peer. +type trustPeerInfo struct { + Version uint `json:"version"` // Trust protocol version negotiated +} + // snapPeer is a wrapper around snap.Peer to maintain a few extra metadata. type snapPeer struct { *snap.Peer @@ -79,6 +88,11 @@ type diffPeer struct { *diff.Peer } +// trustPeer is a wrapper around trust.Peer to maintain a few extra metadata. +type trustPeer struct { + *trust.Peer +} + // info gathers and returns some `diff` protocol metadata known about a peer. func (p *diffPeer) info() *diffPeerInfo { return &diffPeerInfo{ @@ -93,3 +107,10 @@ func (p *snapPeer) info() *snapPeerInfo { Version: p.Version(), } } + +// info gathers and returns some `trust` protocol metadata known about a peer. +func (p *trustPeer) info() *trustPeerInfo { + return &trustPeerInfo{ + Version: p.Version(), + } +} diff --git a/eth/peerset.go b/eth/peerset.go index 0f5245a05e..b68d0e7783 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -23,10 +23,12 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/protocols/diff" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" + "github.com/ethereum/go-ethereum/eth/protocols/trust" "github.com/ethereum/go-ethereum/p2p" ) @@ -53,6 +55,10 @@ var ( // errDiffWithoutEth is returned if a peer attempts to connect only on the // diff protocol without advertising the eth main protocol. errDiffWithoutEth = errors.New("peer connected on diff without compatible eth support") + + // errTrustWithoutEth is returned if a peer attempts to connect only on the + // trust protocol without advertising the eth main protocol. + errTrustWithoutEth = errors.New("peer connected on trust without compatible eth support") ) const ( @@ -73,6 +79,9 @@ type peerSet struct { diffWait map[string]chan *diff.Peer // Peers connected on `eth` waiting for their diff extension diffPend map[string]*diff.Peer // Peers connected on the `diff` protocol, but not yet on `eth` + trustWait map[string]chan *trust.Peer // Peers connected on `eth` waiting for their trust extension + trustPend map[string]*trust.Peer // Peers connected on the `trust` protocol, but not yet on `eth` + lock sync.RWMutex closed bool } @@ -80,11 +89,13 @@ type peerSet struct { // newPeerSet creates a new peer set to track the active participants. func newPeerSet() *peerSet { return &peerSet{ - peers: make(map[string]*ethPeer), - snapWait: make(map[string]chan *snap.Peer), - snapPend: make(map[string]*snap.Peer), - diffWait: make(map[string]chan *diff.Peer), - diffPend: make(map[string]*diff.Peer), + peers: make(map[string]*ethPeer), + snapWait: make(map[string]chan *snap.Peer), + snapPend: make(map[string]*snap.Peer), + diffWait: make(map[string]chan *diff.Peer), + diffPend: make(map[string]*diff.Peer), + trustWait: make(map[string]chan *trust.Peer), + trustPend: make(map[string]*trust.Peer), } } @@ -148,6 +159,40 @@ func (ps *peerSet) registerDiffExtension(peer *diff.Peer) error { return nil } +// registerTrustExtension unblocks an already connected `eth` peer waiting for its +// `trust` extension, or if no such peer exists, tracks the extension for the time +// being until the `eth` main protocol starts looking for it. +func (ps *peerSet) registerTrustExtension(peer *trust.Peer) error { + // Reject the peer if it advertises `trust` without `eth` as `trust` is only a + // satellite protocol meaningful with the chain selection of `eth` + if !peer.RunningCap(eth.ProtocolName, eth.ProtocolVersions) { + return errTrustWithoutEth + } + // If the peer isn't verify node, don't register trust extension into eth protocol. + if !peer.VerifyNode() { + return nil + } + // Ensure nobody can double connect + ps.lock.Lock() + defer ps.lock.Unlock() + + id := peer.ID() + if _, ok := ps.peers[id]; ok { + return errPeerAlreadyRegistered // avoid connections with the same id as existing ones + } + if _, ok := ps.trustPend[id]; ok { + return errPeerAlreadyRegistered // avoid connections with the same id as pending ones + } + // Inject the peer into an `eth` counterpart is available, otherwise save for later + if wait, ok := ps.trustWait[id]; ok { + delete(ps.trustWait, id) + wait <- peer + return nil + } + ps.trustPend[id] = peer + return nil +} + // waitExtensions blocks until all satellite protocols are connected and tracked // by the peerset. func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { @@ -234,6 +279,53 @@ func (ps *peerSet) waitDiffExtension(peer *eth.Peer) (*diff.Peer, error) { } } +// waitTrustExtension blocks until all satellite protocols are connected and tracked +// by the peerset. +func (ps *peerSet) waitTrustExtension(peer *eth.Peer) (*trust.Peer, error) { + // If the peer does not support a compatible `trust`, don't wait + if !peer.RunningCap(trust.ProtocolName, trust.ProtocolVersions) { + return nil, nil + } + // If the peer isn't verify node, don't register trust extension into eth protocol. + if !peer.VerifyNode() { + return nil, nil + } + // Ensure nobody can double connect + ps.lock.Lock() + + id := peer.ID() + if _, ok := ps.peers[id]; ok { + ps.lock.Unlock() + return nil, errPeerAlreadyRegistered // avoid connections with the same id as existing ones + } + if _, ok := ps.trustWait[id]; ok { + ps.lock.Unlock() + return nil, errPeerAlreadyRegistered // avoid connections with the same id as pending ones + } + // If `trust` already connected, retrieve the peer from the pending set + if trust, ok := ps.trustPend[id]; ok { + delete(ps.trustPend, id) + + ps.lock.Unlock() + return trust, nil + } + // Otherwise wait for `trust` to connect concurrently + wait := make(chan *trust.Peer) + ps.trustWait[id] = wait + ps.lock.Unlock() + + select { + case peer := <-wait: + return peer, nil + + case <-time.After(extensionWaitTimeout): + ps.lock.Lock() + delete(ps.trustWait, id) + ps.lock.Unlock() + return nil, errPeerWaitTimeout + } +} + func (ps *peerSet) GetDiffPeer(pid string) downloader.IDiffPeer { if p := ps.peer(pid); p != nil && p.diffExt != nil { return p.diffExt @@ -241,9 +333,23 @@ func (ps *peerSet) GetDiffPeer(pid string) downloader.IDiffPeer { return nil } +// GetVerifyPeers returns an array of verify nodes. +func (ps *peerSet) GetVerifyPeers() []core.VerifyPeer { + ps.lock.RLock() + defer ps.lock.RUnlock() + + res := make([]core.VerifyPeer, 0) + for _, p := range ps.peers { + if p.trustExt != nil && p.trustExt.Peer != nil { + res = append(res, p.trustExt.Peer) + } + } + return res +} + // registerPeer injects a new `eth` peer into the working set, or returns an error // if the peer is already known. -func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer, diffExt *diff.Peer) error { +func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer, diffExt *diff.Peer, trustExt *trust.Peer) error { // Start tracking the new peer ps.lock.Lock() defer ps.lock.Unlock() @@ -265,6 +371,9 @@ func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer, diffExt *diff.Pe if diffExt != nil { eth.diffExt = &diffPeer{diffExt} } + if trustExt != nil { + eth.trustExt = &trustPeer{trustExt} + } ps.peers[id] = eth return nil } diff --git a/eth/protocols/diff/protocol.go b/eth/protocols/diff/protocol.go index 4467d0b327..e6bf5b3e14 100644 --- a/eth/protocols/diff/protocol.go +++ b/eth/protocols/diff/protocol.go @@ -92,7 +92,7 @@ func (p *DiffLayersPacket) Unpack() ([]*types.DiffLayer, error) { var diffHash common.Hash hasher.Sum(diffHash[:0]) hasher.Reset() - diff.DiffHash = diffHash + diff.DiffHash.Store(diffHash) } return diffLayers, nil } diff --git a/eth/protocols/trust/discovery.go b/eth/protocols/trust/discovery.go new file mode 100644 index 0000000000..ce38ec5ed9 --- /dev/null +++ b/eth/protocols/trust/discovery.go @@ -0,0 +1,14 @@ +package trust + +import "github.com/ethereum/go-ethereum/rlp" + +// enrEntry is the ENR entry which advertises `trust` protocol on the discovery. +type enrEntry struct { + // Ignore additional fields (for forward compatibility). + Rest []rlp.RawValue `rlp:"tail"` +} + +// ENRKey implements enr.Entry. +func (e enrEntry) ENRKey() string { + return "trust" +} diff --git a/eth/protocols/trust/handler.go b/eth/protocols/trust/handler.go new file mode 100644 index 0000000000..f10aff5178 --- /dev/null +++ b/eth/protocols/trust/handler.go @@ -0,0 +1,157 @@ +package trust + +import ( + "fmt" + "time" + + "github.com/ethereum/go-ethereum/core" + "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" +) + +// Handler is a callback to invoke from an outside runner after the boilerplate +// exchanges have passed. +type Handler func(peer *Peer) error + +type Backend interface { + // Chain retrieves the blockchain object to serve data. + Chain() *core.BlockChain + + // RunPeer is invoked when a peer joins on the `eth` protocol. The handler + // should do any peer maintenance work, handshakes and validations. If all + // is passed, control should be given back to the `handler` to process the + // inbound messages going forward. + RunPeer(peer *Peer, handler Handler) error + + PeerInfo(id enode.ID) interface{} + + Handle(peer *Peer, packet Packet) error +} + +// MakeProtocols constructs the P2P protocol definitions for `trust`. +func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { + // Filter the discovery iterator for nodes advertising trust support. + dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool { + var trust enrEntry + return n.Load(&trust) == nil + }) + + protocols := make([]p2p.Protocol, len(ProtocolVersions)) + for i, version := range ProtocolVersions { + version := version // Closure + + protocols[i] = p2p.Protocol{ + Name: ProtocolName, + Version: version, + Length: protocolLengths[version], + Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + return backend.RunPeer(NewPeer(version, p, rw), func(peer *Peer) error { + defer peer.Close() + return Handle(backend, peer) + }) + }, + NodeInfo: func() interface{} { + return nodeInfo(backend.Chain()) + }, + PeerInfo: func(id enode.ID) interface{} { + return backend.PeerInfo(id) + }, + Attributes: []enr.Entry{&enrEntry{}}, + DialCandidates: dnsdisc, + } + } + return protocols +} + +// Handle is the callback invoked to manage the life cycle of a `trust` peer. +// When this function terminates, the peer is disconnected. +func Handle(backend Backend, peer *Peer) error { + for { + if err := handleMessage(backend, peer); err != nil { + peer.Log().Debug("Message handling failed in `trust`", "err", err) + return err + } + } +} + +// handleMessage is invoked whenever an inbound message is received from a +// remote peer on the `diff` protocol. The remote connection is torn down upon +// returning any error. +func handleMessage(backend Backend, peer *Peer) error { + // Read the next message from the remote peer, and ensure it's fully consumed + msg, err := peer.rw.ReadMsg() + if err != nil { + return err + } + if msg.Size > maxMessageSize { + return fmt.Errorf("%w: %v > %v", errMsgTooLarge, msg.Size, maxMessageSize) + } + defer msg.Discard() + + // 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) { + sampler := func() metrics.Sample { + return metrics.ResettingSample( + metrics.NewExpDecaySample(1028, 0.015), + ) + } + metrics.GetOrRegisterHistogramLazy(h, nil, sampler).Update(time.Since(start).Microseconds()) + }(time.Now()) + } + // Handle the message depending on its contents + switch { + case msg.Code == RequestRootMsg: + return handleRootRequest(backend, msg, peer) + + case msg.Code == RespondRootMsg: + return handleRootResponse(backend, msg, peer) + + default: + return fmt.Errorf("%w: %v", errInvalidMsgCode, msg.Code) + } +} + +type Decoder interface { + Decode(val interface{}) error + Time() time.Time +} + +func handleRootRequest(backend Backend, msg Decoder, peer *Peer) error { + req := new(RootRequestPacket) + if err := msg.Decode(req); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + + res := backend.Chain().GetVerifyResult(req.BlockNumber, req.BlockHash, req.DiffHash) + return p2p.Send(peer.rw, RespondRootMsg, RootResponsePacket{ + RequestId: req.RequestId, + Status: res.Status, + BlockNumber: req.BlockNumber, + BlockHash: req.BlockHash, + Root: res.Root, + Extra: defaultExtra, + }) +} + +func handleRootResponse(backend Backend, msg Decoder, peer *Peer) error { + res := new(RootResponsePacket) + if err := msg.Decode(res); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + + requestTracker.Fulfil(peer.id, peer.version, RespondRootMsg, res.RequestId) + return backend.Handle(peer, res) +} + +// NodeInfo represents a short summary of the `trust` sub-protocol metadata +// known about the host peer. +type NodeInfo struct{} + +// nodeInfo retrieves some `trust` protocol metadata about the running host node. +func nodeInfo(chain *core.BlockChain) *NodeInfo { + return &NodeInfo{} +} diff --git a/eth/protocols/trust/handler_test.go b/eth/protocols/trust/handler_test.go new file mode 100644 index 0000000000..e594401a2c --- /dev/null +++ b/eth/protocols/trust/handler_test.go @@ -0,0 +1,270 @@ +package trust + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/clique" + "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/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/params" +) + +var ( + // testKey is a private key to use for funding a tester account. + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + + // testAddr is the Ethereum address of the tester account. + testAddr = crypto.PubkeyToAddress(testKey.PublicKey) +) + +// 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. +type testBackend struct { + db ethdb.Database + chain *core.BlockChain + txpool *core.TxPool +} + +// newTestBackend creates an empty chain and wraps it into a mock backend. +func newTestBackend(blocks int) *testBackend { + return newTestBackendWithGenerator(blocks) +} + +// newTestBackend creates a chain with a number of explicitly defined blocks and +// wraps it into a mock backend. +func newTestBackendWithGenerator(blocks int) *testBackend { + signer := types.HomesteadSigner{} + db := rawdb.NewMemoryDatabase() + engine := clique.New(params.AllCliqueProtocolChanges.Clique, db) + genspec := &core.Genesis{ + //Config: params.TestChainConfig, + ExtraData: make([]byte, 32+common.AddressLength+65), + Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, + } + copy(genspec.ExtraData[32:], testAddr[:]) + genesis := genspec.MustCommit(db) + + chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + generator := 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.SetCoinbase(testAddr) + block.SetDifficulty(big.NewInt(2)) + + // We want to simulate an empty middle block, having the same state as the + // first one. The last is needs a state change again to force a reorg. + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), common.Address{0x01}, big.NewInt(1), params.TxGas, nil, nil), signer, testKey) + if err != nil { + panic(err) + } + block.AddTxWithChain(chain, tx) + } + + bs, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, blocks, generator) + for i, block := range bs { + header := block.Header() + if i > 0 { + header.ParentHash = bs[i-1].Hash() + } + header.Extra = make([]byte, 32+65) + header.Difficulty = big.NewInt(2) + + sig, _ := crypto.Sign(clique.SealHash(header).Bytes(), testKey) + copy(header.Extra[len(header.Extra)-65:], sig) + bs[i] = block.WithSeal(header) + } + + if _, err := chain.InsertChain(bs); err != nil { + panic(err) + } + + txconfig := core.DefaultTxPoolConfig + txconfig.Journal = "" // Don't litter the disk with test journals + + return &testBackend{ + db: db, + chain: chain, + txpool: core.NewTxPool(txconfig, params.AllCliqueProtocolChanges, chain), + } +} + +// close tears down the transaction pool and chain behind the mock backend. +func (b *testBackend) close() { + b.txpool.Stop() + b.chain.Stop() +} + +func (b *testBackend) Chain() *core.BlockChain { return b.chain } + +func (b *testBackend) RunPeer(peer *Peer, handler Handler) error { + // Normally the backend would do peer mainentance and handshakes. All that + // is omitted and we will just give control back to the handler. + return handler(peer) +} +func (b *testBackend) PeerInfo(enode.ID) interface{} { panic("not implemented") } + +func (b *testBackend) Handle(*Peer, Packet) error { + panic("data processing tests should be done in the handler package") +} + +func TestRequestRoot(t *testing.T) { testRequestRoot(t, Trust1) } + +func testRequestRoot(t *testing.T, protocol uint) { + t.Parallel() + + blockNum := 1032 // The latest 1024 blocks' DiffLayer will be cached. + backend := newTestBackend(blockNum) + defer backend.close() + + peer, _ := newTestPeer("peer", protocol, backend) + defer peer.close() + + pairs := []struct { + req RootRequestPacket + res RootResponsePacket + }{ + { + req: RootRequestPacket{ + RequestId: 1, + BlockNumber: 1, + }, + res: RootResponsePacket{ + RequestId: 1, + Status: types.StatusPartiallyVerified, + BlockNumber: 1, + Extra: defaultExtra, + }, + }, + { + req: RootRequestPacket{ + RequestId: 2, + BlockNumber: 128, + }, + res: RootResponsePacket{ + RequestId: 2, + Status: types.StatusFullVerified, + BlockNumber: 128, + Extra: defaultExtra, + }, + }, + { + req: RootRequestPacket{ + RequestId: 3, + BlockNumber: 128, + BlockHash: types.EmptyRootHash, + DiffHash: types.EmptyRootHash, + }, + res: RootResponsePacket{ + RequestId: 3, + Status: types.StatusImpossibleFork, + BlockNumber: 128, + BlockHash: types.EmptyRootHash, + Root: common.Hash{}, + Extra: defaultExtra, + }, + }, + { + req: RootRequestPacket{ + RequestId: 4, + BlockNumber: 128, + DiffHash: types.EmptyRootHash, + }, + res: RootResponsePacket{ + RequestId: 4, + Status: types.StatusDiffHashMismatch, + BlockNumber: 128, + Root: common.Hash{}, + Extra: defaultExtra, + }, + }, + { + req: RootRequestPacket{ + RequestId: 5, + BlockNumber: 1024, + }, + res: RootResponsePacket{ + RequestId: 5, + Status: types.StatusFullVerified, + BlockNumber: 1024, + Extra: defaultExtra, + }, + }, + { + req: RootRequestPacket{ + RequestId: 6, + BlockNumber: 1024, + BlockHash: types.EmptyRootHash, + DiffHash: types.EmptyRootHash, + }, + res: RootResponsePacket{ + RequestId: 6, + Status: types.StatusPossibleFork, + BlockNumber: 1024, + BlockHash: types.EmptyRootHash, + Root: common.Hash{}, + Extra: defaultExtra, + }, + }, + { + req: RootRequestPacket{ + RequestId: 7, + BlockNumber: 1033, + BlockHash: types.EmptyRootHash, + DiffHash: types.EmptyRootHash, + }, + res: RootResponsePacket{ + RequestId: 7, + Status: types.StatusBlockNewer, + BlockNumber: 1033, + BlockHash: types.EmptyRootHash, + Root: common.Hash{}, + Extra: defaultExtra, + }, + }, + { + req: RootRequestPacket{ + RequestId: 8, + BlockNumber: 1044, + BlockHash: types.EmptyRootHash, + DiffHash: types.EmptyRootHash, + }, + res: RootResponsePacket{ + RequestId: 8, + Status: types.StatusBlockTooNew, + BlockNumber: 1044, + BlockHash: types.EmptyRootHash, + Root: common.Hash{}, + Extra: defaultExtra, + }, + }, + } + + for idx, pair := range pairs { + header := backend.Chain().GetHeaderByNumber(pair.req.BlockNumber) + if header != nil { + if pair.res.Status.Code&0xFF00 == types.StatusVerified.Code { + pair.req.BlockHash = header.Hash() + pair.req.DiffHash, _ = core.CalculateDiffHash(backend.Chain().GetTrustedDiffLayer(header.Hash())) + pair.res.BlockHash = pair.req.BlockHash + pair.res.Root = header.Root + } else if pair.res.Status.Code == types.StatusDiffHashMismatch.Code { + pair.req.BlockHash = header.Hash() + pair.res.BlockHash = pair.req.BlockHash + } + } + + p2p.Send(peer.app, RequestRootMsg, pair.req) + if err := p2p.ExpectMsg(peer.app, RespondRootMsg, pair.res); err != nil { + t.Errorf("test %d: root response not expected: %v", idx, err) + } + } +} diff --git a/eth/protocols/trust/peer.go b/eth/protocols/trust/peer.go new file mode 100644 index 0000000000..18ba229914 --- /dev/null +++ b/eth/protocols/trust/peer.go @@ -0,0 +1,66 @@ +package trust + +import ( + "math/rand" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p" +) + +// Peer is a collection of relevant information we have about a `trust` peer. +type Peer struct { + id string // Unique ID for the peer, cached + + *p2p.Peer // The embedded P2P package peer + rw p2p.MsgReadWriter // Input/output streams for diff + version uint // Protocol version negotiated + logger log.Logger // Contextual logger with the peer id injected +} + +// NewPeer create a wrapper for a network connection and negotiated protocol +// version. +func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) *Peer { + id := p.ID().String() + peer := &Peer{ + id: id, + Peer: p, + rw: rw, + version: version, + logger: log.New("peer", id[:8]), + } + return peer +} + +// ID retrieves the peer's unique identifier. +func (p *Peer) ID() string { + return p.id +} + +// Version retrieves the peer's negoatiated `diff` protocol version. +func (p *Peer) Version() uint { + return p.version +} + +// Log overrides the P2P logget with the higher level one containing only the id. +func (p *Peer) Log() log.Logger { + return p.logger +} + +// Close signals the broadcast goroutine to terminate. Only ever call this if +// you created the peer yourself via NewPeer. Otherwise let whoever created it +// clean it up! +func (p *Peer) Close() { +} + +func (p *Peer) RequestRoot(blockNumber uint64, blockHash common.Hash, diffHash common.Hash) error { + id := rand.Uint64() + + requestTracker.Track(p.id, p.version, RequestRootMsg, RespondRootMsg, id) + return p2p.Send(p.rw, RequestRootMsg, RootRequestPacket{ + RequestId: id, + BlockNumber: blockNumber, + BlockHash: blockHash, + DiffHash: diffHash, + }) +} diff --git a/eth/protocols/trust/peer_test.go b/eth/protocols/trust/peer_test.go new file mode 100644 index 0000000000..ab229a1b32 --- /dev/null +++ b/eth/protocols/trust/peer_test.go @@ -0,0 +1,42 @@ +package trust + +import ( + "math/rand" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +// testPeer is a simulated peer to allow testing direct network calls. +type testPeer struct { + *Peer + + net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging + app *p2p.MsgPipeRW // Application layer reader/writer to simulate the local side +} + +// newTestPeer creates a new peer registered at the given data backend. +func newTestPeer(name string, version uint, backend Backend) (*testPeer, <-chan error) { + // Create a message pipe to communicate through + app, net := p2p.MsgPipe() + + // Start the peer on a new thread + var id enode.ID + rand.Read(id[:]) + + peer := NewPeer(version, p2p.NewPeer(id, name, nil), net) + errc := make(chan error, 1) + go func() { + errc <- backend.RunPeer(peer, func(peer *Peer) error { + return Handle(backend, peer) + }) + }() + return &testPeer{app: app, net: net, Peer: peer}, errc +} + +// close terminates the local side of the peer, notifying the remote protocol +// manager of termination. +func (p *testPeer) close() { + p.Peer.Close() + p.app.Close() +} diff --git a/eth/protocols/trust/protocol.go b/eth/protocols/trust/protocol.go new file mode 100644 index 0000000000..e4f98dd324 --- /dev/null +++ b/eth/protocols/trust/protocol.go @@ -0,0 +1,71 @@ +package trust + +import ( + "errors" + + "github.com/ethereum/go-ethereum/core/types" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" +) + +// Constants to match up protocol versions and messages +const ( + Trust1 = 1 +) + +// ProtocolName is the official short name of the `trust` protocol used during +// devp2p capability negotiation. +const ProtocolName = "trust" + +// ProtocolVersions are the supported versions of the `trust` protocol (first +// is primary). +var ProtocolVersions = []uint{Trust1} + +// protocolLengths are the number of implemented message corresponding to +// different protocol versions. +var protocolLengths = map[uint]uint64{Trust1: 2} + +// maxMessageSize is the maximum cap on the size of a protocol message. +const maxMessageSize = 10 * 1024 * 1024 + +const ( + RequestRootMsg = 0x00 + RespondRootMsg = 0x01 +) + +var defaultExtra = []byte{0x00} + +var ( + errMsgTooLarge = errors.New("message too long") + errDecode = errors.New("invalid message") + errInvalidMsgCode = errors.New("invalid message code") +) + +// Packet represents a p2p message in the `trust` protocol. +type Packet interface { + Name() string // Name returns a string corresponding to the message type. + Kind() byte // Kind returns the message type. +} + +type RootRequestPacket struct { + RequestId uint64 + BlockNumber uint64 + BlockHash common.Hash + DiffHash common.Hash +} + +type RootResponsePacket struct { + RequestId uint64 + Status types.VerifyStatus + BlockNumber uint64 + BlockHash common.Hash + Root common.Hash + Extra rlp.RawValue // for extension +} + +func (*RootRequestPacket) Name() string { return "RequestRoot" } +func (*RootRequestPacket) Kind() byte { return RequestRootMsg } + +func (*RootResponsePacket) Name() string { return "RootResponse" } +func (*RootResponsePacket) Kind() byte { return RespondRootMsg } diff --git a/eth/protocols/trust/tracker.go b/eth/protocols/trust/tracker.go new file mode 100644 index 0000000000..ab492b3fb8 --- /dev/null +++ b/eth/protocols/trust/tracker.go @@ -0,0 +1,10 @@ +package trust + +import ( + "time" + + "github.com/ethereum/go-ethereum/p2p/tracker" +) + +// requestTracker is a singleton tracker for request times. +var requestTracker = tracker.New(ProtocolName, time.Minute) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 578b10f09a..d4d19ff5f0 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum" "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/types" "github.com/ethereum/go-ethereum/rpc" ) @@ -200,6 +201,12 @@ func (ec *Client) GetDiffAccountsWithScope(ctx context.Context, number *big.Int, return &result, err } +func (ec *Client) GetRootByDiffHash(ctx context.Context, blockNr *big.Int, blockHash common.Hash, diffHash common.Hash) (*core.VerifyResult, error) { + var result core.VerifyResult + err := ec.c.CallContext(ctx, &result, "eth_getRootByDiffHash", toBlockNumArg(blockNr), blockHash, diffHash) + return &result, err +} + type rpcTransaction struct { tx *types.Transaction txExtraInfo diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7a3f0ad8bd..3309542581 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1287,6 +1287,10 @@ func (s *PublicBlockChainAPI) GetDiffAccountsWithScope(ctx context.Context, bloc return result, err } +func (s *PublicBlockChainAPI) GetVerifyResult(ctx context.Context, blockNr rpc.BlockNumber, blockHash common.Hash, diffHash common.Hash) *core.VerifyResult { + return s.b.Chain().GetVerifyResult(uint64(blockNr), blockHash, diffHash) +} + // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value diff --git a/light/trie.go b/light/trie.go index 3896b73c4d..3f942f3607 100644 --- a/light/trie.go +++ b/light/trie.go @@ -49,6 +49,10 @@ type odrDatabase struct { backend OdrBackend } +func (db *odrDatabase) NoTries() bool { + return false +} + func (db *odrDatabase) OpenTrie(root common.Hash) (state.Trie, error) { return &odrTrie{db: db, id: db.id}, nil } @@ -178,6 +182,10 @@ func (t *odrTrie) do(key []byte, fn func() error) error { } } +func (db *odrTrie) NoTries() bool { + return false +} + type nodeIterator struct { trie.NodeIterator t *odrTrie diff --git a/p2p/peer.go b/p2p/peer.go index 5e6ef0732e..8c1f743a25 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -227,6 +227,11 @@ func (p *Peer) Inbound() bool { return p.rw.is(inboundConn) } +// VerifyNode returns true if the peer is a verification connection +func (p *Peer) VerifyNode() bool { + return p.rw.is(verifyConn) +} + func newPeer(log log.Logger, conn *conn, protocols []Protocol) *Peer { protomap := matchProtocols(protocols, conn.caps, conn) p := &Peer{ diff --git a/p2p/server.go b/p2p/server.go index 2a38550abf..01e56936ab 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -114,6 +114,10 @@ type Config struct { // maintained and re-connected on disconnects. StaticNodes []*enode.Node + // Verify nodes are used as pre-configured connections which are always + // maintained and re-connected on disconnects. + VerifyNodes []*enode.Node + // Trusted nodes are used as pre-configured connections which are always // allowed to connect, even above the peer limit. TrustedNodes []*enode.Node @@ -218,6 +222,7 @@ const ( staticDialedConn inboundConn trustedConn + verifyConn ) // conn wraps a network connection with information gathered @@ -269,6 +274,9 @@ func (f connFlag) String() string { if f&inboundConn != 0 { s += "-inbound" } + if f&verifyConn != 0 { + s += "-verify" + } if s != "" { s = s[1:] } @@ -649,6 +657,9 @@ func (srv *Server) setupDialScheduler() { for _, n := range srv.StaticNodes { srv.dialsched.addStatic(n) } + for _, n := range srv.VerifyNodes { + srv.dialsched.addStatic(n) + } } func (srv *Server) maxInboundConns() int { @@ -934,6 +945,13 @@ func (srv *Server) checkInboundConn(remoteIP net.IP) error { // as a peer. It returns when the connection has been added as a peer // or the handshakes have failed. func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *enode.Node) error { + // If dialDest is verify node, set verifyConn flags. + for _, n := range srv.VerifyNodes { + if dialDest == n { + flags |= verifyConn + } + } + c := &conn{fd: fd, flags: flags, cont: make(chan error)} if dialDest == nil { c.transport = srv.newTransport(fd, nil) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index a688254a20..1de4a787dd 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -234,7 +234,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo var snaps *snapshot.Tree if snapshotter { - snaps, _ = snapshot.New(db, sdb.TrieDB(), 1, 128, root, false, true, false) + snaps, _ = snapshot.New(db, sdb.TrieDB(), 1, 128, root, false, true, false, false) } statedb, _ = state.New(root, sdb, snaps) return snaps, statedb diff --git a/trie/database.go b/trie/database.go index 649af6dbf9..85797cc2e4 100644 --- a/trie/database.go +++ b/trie/database.go @@ -282,6 +282,7 @@ type Config struct { Cache int // Memory allowance (MB) to use for caching trie nodes in memory Journal string // Journal of clean cache to survive node restarts Preimages bool // Flag whether the preimage of trie key is recorded + NoTries bool } // NewDatabase creates a new trie database to store ephemeral trie content before diff --git a/trie/dummy_trie.go b/trie/dummy_trie.go new file mode 100644 index 0000000000..99eb79fbd4 --- /dev/null +++ b/trie/dummy_trie.go @@ -0,0 +1,96 @@ +// 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 trie + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/ethdb" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" +) + +type EmptyTrie struct{} + +func (t *EmptyTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error { + return nil +} + +// NewSecure creates a dummy trie +func NewEmptyTrie() *EmptyTrie { + return &EmptyTrie{} +} + +func (t *EmptyTrie) Get(key []byte) []byte { + return nil +} + +func (t *EmptyTrie) TryGet(key []byte) ([]byte, error) { + return nil, nil +} + +func (t *EmptyTrie) TryGetNode(path []byte) ([]byte, int, error) { + return nil, 0, nil +} +func (t *EmptyTrie) Update(key, value []byte) {} + +func (t *EmptyTrie) TryUpdate(key, value []byte) error { + return nil +} + +// Delete removes any existing value for key from the trie. +func (t *EmptyTrie) Delete(key []byte) { + if err := t.TryDelete(key); err != nil { + log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + } +} + +func (t *EmptyTrie) TryDelete(key []byte) error { + + return nil +} + +func (t *EmptyTrie) GetKey(shaKey []byte) []byte { + return nil +} + +func (t *EmptyTrie) Commit(onleaf LeafCallback) (root common.Hash, err error) { + + return common.Hash{}, nil +} + +func (t *EmptyTrie) Hash() common.Hash { + return common.Hash{} +} + +// Copy returns a copy of SecureTrie. +func (t *EmptyTrie) Copy() *EmptyTrie { + cpy := *t + return &cpy +} + +func (t *EmptyTrie) ResetCopy() *EmptyTrie { + cpy := *t + return &cpy +} + +// NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration +// starts at the key after the given start key. +func (t *EmptyTrie) NodeIterator(start []byte) NodeIterator { + return nil +}