From d3f6da90e1d49504f51c11b67fc6d44bb0603c86 Mon Sep 17 00:00:00 2001 From: marcello33 Date: Mon, 12 Jun 2023 19:35:40 +0200 Subject: [PATCH] dev: chg: more regression changes for bor after merge --- cmd/geth/snapshot.go | 2 +- core/block_validator_test.go | 2 +- core/blockchain.go | 10 +- core/blockchain_bor_test.go | 2 +- core/bor_blockchain.go | 2 +- core/chain_makers_test.go | 2 +- core/forkchoice_test.go | 44 +- core/state_processor_test.go | 4 +- .../txpool2_test_BOR.go} | 10 +- core/txpool/txpool_test.go | 2 + core/types/legacy.go | 53 -- core/types/transaction.go | 17 +- core/vm/gas_table_test.go | 2 +- core/vm/logger.go | 1 - eth/filters/bor_filter_system.go | 3 +- eth/filters/bor_filter_test.go | 1 + eth/filters/filter_system_test.go | 6 + eth/tracers/api_bor.go | 13 +- eth/tracers/js/tracer.go | 880 ------------------ eth/tracers/native/tracer.go | 79 -- ethclient/ethclient.go | 32 + ethclient/gethclient/gethclient_test.go | 2 +- ethdb/memorydb/memorydb.go | 56 -- internal/cli/server/chains/mainnet.go | 1 - internal/cli/server/chains/mumbai.go | 1 - internal/cli/server/config.go | 8 +- internal/cli/server/server.go | 14 +- internal/cli/server/server_test.go | 4 +- internal/cli/server/service.go | 2 +- internal/cli/snapshot.go | 8 +- internal/debug/flags.go | 2 +- internal/ethapi/transaction_args_test.go | 40 + light/lightchain.go | 20 +- light/odr_test.go | 2 +- light/trie_test.go | 2 +- light/txpool_test.go | 2 +- miner/worker_test.go | 86 +- node/config.go | 65 ++ node/rpcstack.go | 2 +- node/rpcstack_test.go | 2 +- rlp/rlpgen/main.go | 1 + rpc/http.go | 7 +- rpc/json.go | 5 - signer/core/apitypes/types.go | 2 - tests/bor/bor_sprint_length_change_test.go | 5 +- tests/init.go | 9 +- trie/trie.go | 9 - 47 files changed, 253 insertions(+), 1271 deletions(-) rename core/{txpool2_test.go => txpool/txpool2_test_BOR.go} (97%) delete mode 100644 core/types/legacy.go delete mode 100644 eth/tracers/js/tracer.go delete mode 100644 eth/tracers/native/tracer.go diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 0759341fd9..36519a9300 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -35,7 +35,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - cli "github.com/urfave/cli/v2" + "github.com/urfave/cli/v2" ) var ( diff --git a/core/block_validator_test.go b/core/block_validator_test.go index fc4d3593f0..3245a1e886 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -159,7 +159,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { t.Logf("Post-merge header: %d", block.NumberU64()) } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() // Verify the blocks before the merging diff --git a/core/blockchain.go b/core/blockchain.go index 13a779549a..dd71db0b23 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -238,10 +238,10 @@ type BlockChain struct { vmConfig vm.Config // Bor related changes - borReceiptsCache *lru.Cache[common.Hash, []*types.Receipt] // Cache for the most recent bor receipt receipts per block - stateSyncData []*types.StateSyncData // State sync data - stateSyncFeed event.Feed // State sync feed - chain2HeadFeed event.Feed // Reorg/NewHead/Fork data feed + borReceiptsCache *lru.Cache[common.Hash, *types.Receipt] // Cache for the most recent bor receipt receipts per block + stateSyncData []*types.StateSyncData // State sync data + stateSyncFeed event.Feed // State sync feed + chain2HeadFeed event.Feed // Reorg/NewHead/Fork data feed } // NewBlockChain returns a fully initialised block chain using information @@ -295,7 +295,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis engine: engine, vmConfig: vmConfig, - borReceiptsCache: lru.NewCache[common.Hash, []*types.Receipt](receiptsCacheLimit), + borReceiptsCache: lru.NewCache[common.Hash, *types.Receipt](receiptsCacheLimit), } bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.forker = NewForkChoice(bc, shouldPreserve, checker) diff --git a/core/blockchain_bor_test.go b/core/blockchain_bor_test.go index 6bc38ec4ab..9063a49d0c 100644 --- a/core/blockchain_bor_test.go +++ b/core/blockchain_bor_test.go @@ -27,7 +27,7 @@ func TestChain2HeadEvent(t *testing.T) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() chain2HeadCh := make(chan Chain2HeadEvent, 64) diff --git a/core/bor_blockchain.go b/core/bor_blockchain.go index 49973421bd..80a4b3ce28 100644 --- a/core/bor_blockchain.go +++ b/core/bor_blockchain.go @@ -9,7 +9,7 @@ import ( // GetBorReceiptByHash retrieves the bor block receipt in a given block. func (bc *BlockChain) GetBorReceiptByHash(hash common.Hash) *types.Receipt { if receipt, ok := bc.borReceiptsCache.Get(hash); ok { - return receipt.(*types.Receipt) + return receipt } // read header from hash diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index f0b8f64caa..73e485b292 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -107,7 +107,7 @@ func TestGenerateWithdrawalChain(t *testing.T) { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/forkchoice_test.go b/core/forkchoice_test.go index 2493d4701f..be78488cca 100644 --- a/core/forkchoice_test.go +++ b/core/forkchoice_test.go @@ -1,6 +1,7 @@ package core import ( + "github.com/ethereum/go-ethereum/trie" "math/big" "testing" @@ -33,11 +34,12 @@ func TestPastChainInsert(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + db = rawdb.NewMemoryDatabase() + gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false }) + gspec.Commit(db, trie.NewDatabase(db)) + hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) } @@ -48,11 +50,11 @@ func TestPastChainInsert(t *testing.T) { } validate := func(currentHeader *types.Header, chain []*types.Header) (bool, error) { // Put all explicit conditions here - // If canonical chain is empty and we're importing a chain of 64 blocks + // If canonical chain is empty, and we're importing a chain of 64 blocks if currentHeader.Number.Uint64() == uint64(0) && len(chain) == 64 { return true, nil } - // If canonical chain is of len 64 and we're importing a past chain from 54-64, then accept it + // If canonical chain is of len 64, and we're importing a past chain from 54-64, then accept it if currentHeader.Number.Uint64() == uint64(64) && chain[0].Number.Uint64() == 55 && len(chain) == 10 { return true, nil } @@ -64,7 +66,7 @@ func TestPastChainInsert(t *testing.T) { mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator) // chain A: G->A1->A2...A64 - chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10) + genDb, chainA := makeHeaderChainWithGenesis(gspec, 64, ethash.NewFaker(), 10) // Inserting 64 headers on an empty chain // expecting 1 write status with no error @@ -72,11 +74,11 @@ func TestPastChainInsert(t *testing.T) { // The current chain is: G->A1->A2...A64 // chain B: G->A1->A2...A44->B45->B46...B64 - chainB := makeHeaderChain(chainA[43], 20, ethash.NewFaker(), db, 10) + chainB := makeHeaderChain(gspec.Config, chainA[43], 20, ethash.NewFaker(), genDb, 10) // The current chain is: G->A1->A2...A64 // chain C: G->A1->A2...A54->C55->C56...C64 - chainC := makeHeaderChain(chainA[53], 10, ethash.NewFaker(), db, 10) + chainC := makeHeaderChain(gspec.Config, chainA[53], 10, ethash.NewFaker(), genDb, 10) // Update the function to consider chainC with higher difficulty getTd = func(hash common.Hash, number uint64) *big.Int { @@ -103,11 +105,12 @@ func TestFutureChainInsert(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + db = rawdb.NewMemoryDatabase() + gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false }) + gspec.Commit(db, trie.NewDatabase(db)) + hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) } @@ -134,7 +137,7 @@ func TestFutureChainInsert(t *testing.T) { mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator) // chain A: G->A1->A2...A64 - chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10) + genDb, chainA := makeHeaderChainWithGenesis(gspec, 64, ethash.NewFaker(), 10) // Inserting 64 headers on an empty chain // expecting 1 write status with no error @@ -142,7 +145,7 @@ func TestFutureChainInsert(t *testing.T) { // The current chain is: G->A1->A2...A64 // chain B: G->A1->A2...A64->B65->B66...B84 - chainB := makeHeaderChain(chainA[63], 20, ethash.NewFaker(), db, 10) + chainB := makeHeaderChain(gspec.Config, chainA[63], 20, ethash.NewFaker(), genDb, 10) // Inserting 20 headers on the canonical chain // expecting 0 write status with no error @@ -150,7 +153,7 @@ func TestFutureChainInsert(t *testing.T) { // The current chain is: G->A1->A2...A64 // chain C: G->A1->A2...A64->C65->C66...C74 - chainC := makeHeaderChain(chainA[63], 10, ethash.NewFaker(), db, 10) + chainC := makeHeaderChain(gspec.Config, chainA[63], 10, ethash.NewFaker(), genDb, 10) // Inserting 10 headers on the canonical chain // expecting 0 write status with no error @@ -161,11 +164,12 @@ func TestOverlappingChainInsert(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + db = rawdb.NewMemoryDatabase() + gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false }) + gspec.Commit(db, trie.NewDatabase(db)) + hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) } @@ -192,7 +196,7 @@ func TestOverlappingChainInsert(t *testing.T) { mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator) // chain A: G->A1->A2...A64 - chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10) + genDb, chainA := makeHeaderChainWithGenesis(gspec, 64, ethash.NewFaker(), 10) // Inserting 64 headers on an empty chain // expecting 1 write status with no error @@ -200,7 +204,7 @@ func TestOverlappingChainInsert(t *testing.T) { // The current chain is: G->A1->A2...A64 // chain B: G->A1->A2...A54->B55->B56...B84 - chainB := makeHeaderChain(chainA[53], 30, ethash.NewFaker(), db, 10) + chainB := makeHeaderChain(gspec.Config, chainA[53], 30, ethash.NewFaker(), genDb, 10) // Inserting 20 blocks on canonical chain // expecting 2 write status with no error @@ -208,7 +212,7 @@ func TestOverlappingChainInsert(t *testing.T) { // The current chain is: G->A1->A2...A64 // chain C: G->A1->A2...A54->C55->C56...C74 - chainC := makeHeaderChain(chainA[53], 20, ethash.NewFaker(), db, 10) + chainC := makeHeaderChain(gspec.Config, chainA[53], 20, ethash.NewFaker(), genDb, 10) // Inserting 10 blocks on canonical chain // expecting 1 write status with no error diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 872171d29e..5a2589fb85 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -345,7 +345,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil, nil) tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} smallInitCode = [320]byte{} ) @@ -386,7 +386,7 @@ func TestStateProcessorErrors(t *testing.T) { func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block { difficulty := big.NewInt(0) if !config.TerminalTotalDifficultyPassed { - difficulty = engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{ + difficulty = engine.CalcDifficulty(&fakeChainReader{config: config}, parent.Time()+10, &types.Header{ Number: parent.Number(), Time: parent.Time(), Difficulty: parent.Difficulty(), diff --git a/core/txpool2_test.go b/core/txpool/txpool2_test_BOR.go similarity index 97% rename from core/txpool2_test.go rename to core/txpool/txpool2_test_BOR.go index 45f784f343..5e2298a5a3 100644 --- a/core/txpool2_test.go +++ b/core/txpool/txpool2_test_BOR.go @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +package txpool import ( "crypto/ecdsa" @@ -28,6 +28,8 @@ import ( "github.com/ethereum/go-ethereum/event" ) +// TODO marcello merge this file with txpool2_test.go + func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(value), gaslimit, gasprice, nil), types.HomesteadSigner{}, key) return tx @@ -36,9 +38,9 @@ func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gaspric func count(t *testing.T, pool *TxPool) (pending int, queued int) { t.Helper() - pending, queued = pool.stats() + pending, queued = pool.Stats() - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -55,7 +57,7 @@ func fillPool(t *testing.T, pool *TxPool) { key, _ := crypto.GenerateKey() pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000)) // Add executable ones - for j := 0; j < int(pool.config.AccountSlots); j++ { + for j := 0; j < int(pool.config().AccountSlots); j++ { executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) } } diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index 8e63dec21a..b1a32e359b 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -53,6 +53,8 @@ import ( "github.com/JekaMas/crand" ) +// TODO marcello merge this file with txpool2_test_BOR.go + var ( // testTxPoolConfig is a transaction pool configuration without stateful disk // sideeffects used during testing. diff --git a/core/types/legacy.go b/core/types/legacy.go deleted file mode 100644 index 9254381b1e..0000000000 --- a/core/types/legacy.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2021 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package types - -import ( - "errors" - - "github.com/ethereum/go-ethereum/rlp" -) - -// IsLegacyStoredReceipts tries to parse the RLP-encoded blob -// first as an array of v3 stored receipt, then v4 stored receipt and -// returns true if successful. -func IsLegacyStoredReceipts(raw []byte) (bool, error) { - var v3 []v3StoredReceiptRLP - if err := rlp.DecodeBytes(raw, &v3); err == nil { - return true, nil - } - var v4 []v4StoredReceiptRLP - if err := rlp.DecodeBytes(raw, &v4); err == nil { - return true, nil - } - var v5 []storedReceiptRLP - // Check to see valid fresh stored receipt - if err := rlp.DecodeBytes(raw, &v5); err == nil { - return false, nil - } - return false, errors.New("value is not a valid receipt encoding") -} - -// ConvertLegacyStoredReceipts takes the RLP encoding of an array of legacy -// stored receipts and returns a fresh RLP-encoded stored receipt. -func ConvertLegacyStoredReceipts(raw []byte) ([]byte, error) { - var receipts []ReceiptForStorage - if err := rlp.DecodeBytes(raw, &receipts); err != nil { - return nil, err - } - return rlp.EncodeToBytes(&receipts) -} diff --git a/core/types/transaction.go b/core/types/transaction.go index 2f93ab949b..9eb18f4412 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -56,7 +56,7 @@ type Transaction struct { // caches hash atomic.Pointer[common.Hash] - size atomic.Pointer[common.StorageSize] + size atomic.Pointer[uint64] from atomic.Pointer[sigCache] } @@ -207,8 +207,7 @@ func (tx *Transaction) setDecoded(inner TxData, size uint64) { tx.inner = inner tx.time = time.Now() if size > 0 { - v := float64(size) - tx.size.Store((*common.StorageSize)(&v)) + tx.size.Store(&size) } } @@ -486,17 +485,19 @@ func (tx *Transaction) Hash() common.Hash { // Size returns the true encoded storage size of the transaction, either by encoding // and returning it, or returning a previously cached value. -func (tx *Transaction) Size() common.StorageSize { +func (tx *Transaction) Size() uint64 { if size := tx.size.Load(); size != nil { return *size } - c := writeCounter(0) - rlp.Encode(&c, &tx.inner) - tx.size.Store((*common.StorageSize)(&c)) - return common.StorageSize(c) + size := uint64(c) + if tx.Type() != LegacyTxType { + size += 1 // type byte + } + tx.size.Store(&size) + return size } // WithSignature returns a new transaction with the given signature. diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 466638e01e..564bfff562 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -151,7 +151,7 @@ func TestCreateGas(t *testing.T) { vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, config) var startGas = uint64(testGas) - ret, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, startGas, new(big.Int)) + ret, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, startGas, new(big.Int), nil) if err != nil { return false } diff --git a/core/vm/logger.go b/core/vm/logger.go index 405e425fc8..8b5b81d60d 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -18,7 +18,6 @@ package vm import ( "math/big" - "time" "github.com/ethereum/go-ethereum/common" ) diff --git a/eth/filters/bor_filter_system.go b/eth/filters/bor_filter_system.go index c3308de27b..904d99bf23 100644 --- a/eth/filters/bor_filter_system.go +++ b/eth/filters/bor_filter_system.go @@ -3,7 +3,6 @@ package filters import ( "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" @@ -22,7 +21,7 @@ func (es *EventSystem) SubscribeNewDeposits(data chan *types.StateSyncData) *Sub typ: StateSyncSubscription, created: time.Now(), logs: make(chan []*types.Log), - hashes: make(chan []common.Hash), + txs: make(chan []*types.Transaction), headers: make(chan *types.Header), stateSyncData: data, installed: make(chan struct{}), diff --git a/eth/filters/bor_filter_test.go b/eth/filters/bor_filter_test.go index 1848648beb..3c7b0583b7 100644 --- a/eth/filters/bor_filter_test.go +++ b/eth/filters/bor_filter_test.go @@ -74,6 +74,7 @@ func TestBorFilters(t *testing.T) { // Block 1 backend.expectBorReceiptsFromMock([]*common.Hash{nil, &hash1, &hash2, &hash3, &hash4}) + // TODO marcello regenerate ctrls for gomock to include the new methods filter := NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 18, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) logs, err := filter.Logs(context.Background()) diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 51908bdfe5..c8fdc8006c 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -50,6 +50,12 @@ type testBackend struct { rmLogsFeed event.Feed pendingLogsFeed event.Feed chainFeed event.Feed + + stateSyncFeed event.Feed +} + +func (b *testBackend) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription { + return b.stateSyncFeed.Subscribe(ch) } func (b *testBackend) ChainConfig() *params.ChainConfig { diff --git a/eth/tracers/api_bor.go b/eth/tracers/api_bor.go index 2351aed2a9..ffebd2e7d9 100644 --- a/eth/tracers/api_bor.go +++ b/eth/tracers/api_bor.go @@ -62,10 +62,11 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T } // TODO: discuss consequences of setting preferDisk false. - statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) + statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, err } + defer release() // Execute all the transaction contained within the block concurrently var ( @@ -77,25 +78,25 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) traceTxn := func(indx int, tx *types.Transaction, borTx bool) *TxTraceResult { - message, _ := tx.AsMessage(signer, block.BaseFee()) + message, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) txContext := core.NewEVMTxContext(message) tracer := logger.NewStructLogger(config.Config) // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(blockCtx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) + vmenv := vm.NewEVM(blockCtx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true}) // Call Prepare to clear out the statedb access list // Not sure if we need to do this - statedb.Prepare(tx.Hash(), indx) + statedb.SetTxContext(tx.Hash(), indx) var execRes *core.ExecutionResult if borTx { - callmsg := prepareCallMessage(message) + callmsg := prepareCallMessage(*message) execRes, err = statefull.ApplyBorMessage(*vmenv, callmsg) } else { - execRes, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), nil) + execRes, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit), nil) } if err != nil { diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go deleted file mode 100644 index 30c5c2cf14..0000000000 --- a/eth/tracers/js/tracer.go +++ /dev/null @@ -1,880 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// package 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, env.Context.Random != nil) - 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/native/tracer.go b/eth/tracers/native/tracer.go deleted file mode 100644 index 3158654f33..0000000000 --- a/eth/tracers/native/tracer.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2021 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -/* -Package native is a collection of tracers written in go. - -In order to add a native tracer and have it compiled into the binary, a new -file needs to be added to this folder, containing an implementation of the -`eth.tracers.Tracer` interface. - -Aside from implementing the tracer, it also needs to register itself, using the -`register` method -- and this needs to be done in the package initialization. - -Example: - -```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/ethclient/ethclient.go b/ethclient/ethclient.go index 13a2e46d25..8158359995 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -504,6 +504,38 @@ func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { return (*big.Int)(&hex), nil } +type feeHistoryResultMarshaling struct { + OldestBlock *hexutil.Big `json:"oldestBlock"` + Reward [][]*hexutil.Big `json:"reward,omitempty"` + BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` + GasUsedRatio []float64 `json:"gasUsedRatio"` +} + +// FeeHistory retrieves the fee market history. +func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*ethereum.FeeHistory, error) { + var res feeHistoryResultMarshaling + if err := ec.c.CallContext(ctx, &res, "eth_feeHistory", hexutil.Uint(blockCount), toBlockNumArg(lastBlock), rewardPercentiles); err != nil { + return nil, err + } + reward := make([][]*big.Int, len(res.Reward)) + for i, r := range res.Reward { + reward[i] = make([]*big.Int, len(r)) + for j, r := range r { + reward[i][j] = (*big.Int)(r) + } + } + baseFee := make([]*big.Int, len(res.BaseFee)) + for i, b := range res.BaseFee { + baseFee[i] = (*big.Int)(b) + } + return ðereum.FeeHistory{ + OldestBlock: (*big.Int)(res.OldestBlock), + Reward: reward, + BaseFee: baseFee, + GasUsedRatio: res.GasUsedRatio, + }, nil +} + // EstimateGas tries to estimate the gas needed to execute a specific transaction based on // the current pending state of the backend blockchain. There is no guarantee that this is // the true gas limit requirement as other transactions may be added or removed by miners, diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index ed836b56d7..bcb980b981 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -64,7 +64,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { filterSystem := filters.NewFilterSystem(ethservice.APIBackend, filters.Config{}) n.RegisterAPIs([]rpc.API{{ Namespace: "eth", - Service: filters.NewFilterAPI(filterSystem, false), + Service: filters.NewFilterAPI(filterSystem, false, config.BorLogs), }}) // Import the test chain. diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 60e4085975..7e4fd7e5e7 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -385,59 +385,3 @@ func (snap *snapshot) Release() { snap.db = nil } - -// snapshot wraps a batch of key-value entries deep copied from the in-memory -// database for implementing the Snapshot interface. -type snapshot struct { - db map[string][]byte - lock sync.RWMutex -} - -// newSnapshot initializes the snapshot with the given database instance. -func newSnapshot(db *Database) *snapshot { - db.lock.RLock() - defer db.lock.RUnlock() - - copied := make(map[string][]byte) - for key, val := range db.db { - copied[key] = common.CopyBytes(val) - } - return &snapshot{db: copied} -} - -// Has retrieves if a key is present in the snapshot backing by a key-value -// data store. -func (snap *snapshot) Has(key []byte) (bool, error) { - snap.lock.RLock() - defer snap.lock.RUnlock() - - if snap.db == nil { - return false, errSnapshotReleased - } - _, ok := snap.db[string(key)] - return ok, nil -} - -// Get retrieves the given key if it's present in the snapshot backing by -// key-value data store. -func (snap *snapshot) Get(key []byte) ([]byte, error) { - snap.lock.RLock() - defer snap.lock.RUnlock() - - if snap.db == nil { - return nil, errSnapshotReleased - } - if entry, ok := snap.db[string(key)]; ok { - return common.CopyBytes(entry), nil - } - return nil, errMemorydbNotFound -} - -// Release releases associated resources. Release should always succeed and can -// be called multiple times without causing error. -func (snap *snapshot) Release() { - snap.lock.Lock() - defer snap.lock.Unlock() - - snap.db = nil -} diff --git a/internal/cli/server/chains/mainnet.go b/internal/cli/server/chains/mainnet.go index b2570e9b2f..9f224692b3 100644 --- a/internal/cli/server/chains/mainnet.go +++ b/internal/cli/server/chains/mainnet.go @@ -17,7 +17,6 @@ var mainnetBor = &Chain{ HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: true, - EIP150Hash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), diff --git a/internal/cli/server/chains/mumbai.go b/internal/cli/server/chains/mumbai.go index 64a5b80060..b66b46a86f 100644 --- a/internal/cli/server/chains/mumbai.go +++ b/internal/cli/server/chains/mumbai.go @@ -17,7 +17,6 @@ var mumbaiTestnet = &Chain{ HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: true, - EIP150Hash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index 5ca9d4eb15..50a3a41743 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -897,8 +897,8 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (* { n.GPO.Blocks = int(c.Gpo.Blocks) n.GPO.Percentile = int(c.Gpo.Percentile) - n.GPO.MaxHeaderHistory = c.Gpo.MaxHeaderHistory - n.GPO.MaxBlockHistory = c.Gpo.MaxBlockHistory + n.GPO.MaxHeaderHistory = uint64(c.Gpo.MaxHeaderHistory) + n.GPO.MaxBlockHistory = uint64(c.Gpo.MaxBlockHistory) n.GPO.MaxPrice = c.Gpo.MaxPrice n.GPO.IgnorePrice = c.Gpo.IgnorePrice } @@ -1022,7 +1022,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (* // RequiredBlocks { - n.PeerRequiredBlocks = map[uint64]common.Hash{} + n.RequiredBlocks = map[uint64]common.Hash{} for k, v := range c.RequiredBlocks { number, err := strconv.ParseUint(k, 0, 64) if err != nil { @@ -1034,7 +1034,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (* return nil, fmt.Errorf("invalid required block hash %s: %v", v, err) } - n.PeerRequiredBlocks[number] = hash + n.RequiredBlocks[number] = hash } } diff --git a/internal/cli/server/server.go b/internal/cli/server/server.go index 90586b9283..6d8f64d6d8 100644 --- a/internal/cli/server/server.go +++ b/internal/cli/server/server.go @@ -3,6 +3,8 @@ package server import ( "context" "fmt" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/eth/ethconfig" "io" "math/big" "net" @@ -165,6 +167,8 @@ func NewServer(config *Config, opts ...serverOption) (*Server, error) { // flag to set if we're authorizing consensus here authorized := false + var ethCfg *ethconfig.Config + // check if personal wallet endpoints are disabled or not // nolint:nestif if !config.Accounts.DisableBorWallet { @@ -172,7 +176,7 @@ func NewServer(config *Config, opts ...serverOption) (*Server, error) { stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p)) // register the ethereum backend - ethCfg, err := config.buildEth(stack, stack.AccountManager()) + ethCfg, err = config.buildEth(stack, stack.AccountManager()) if err != nil { return nil, err } @@ -185,7 +189,7 @@ func NewServer(config *Config, opts ...serverOption) (*Server, error) { srv.backend = backend } else { // register the ethereum backend (with temporary created account manager) - ethCfg, err := config.buildEth(stack, accountManager) + ethCfg, err = config.buildEth(stack, accountManager) if err != nil { return nil, err } @@ -244,13 +248,15 @@ func NewServer(config *Config, opts ...serverOption) (*Server, error) { // set the auth status in backend srv.backend.SetAuthorized(authorized) + filterSystem := utils.RegisterFilterAPI(stack, srv.backend.APIBackend, ethCfg) + // debug tracing is enabled by default stack.RegisterAPIs(tracers.APIs(srv.backend.APIBackend)) srv.tracerAPI = tracers.NewAPI(srv.backend.APIBackend) // graphql is started from another place if config.JsonRPC.Graphql.Enabled { - if err := graphql.New(stack, srv.backend.APIBackend, config.JsonRPC.Graphql.Cors, config.JsonRPC.Graphql.VHost); err != nil { + if err := graphql.New(stack, srv.backend.APIBackend, filterSystem, config.JsonRPC.Graphql.Cors, config.JsonRPC.Graphql.VHost); err != nil { return nil, fmt.Errorf("failed to register the GraphQL service: %v", err) } } @@ -500,7 +506,7 @@ func setupLogger(logLevel string, loggingInfo LoggingConfig) { } func (s *Server) GetLatestBlockNumber() *big.Int { - return s.backend.BlockChain().CurrentBlock().Number() + return s.backend.BlockChain().CurrentBlock().Number } func (s *Server) GetGrpcAddr() string { diff --git a/internal/cli/server/server_test.go b/internal/cli/server/server_test.go index c88c656b10..16447af31e 100644 --- a/internal/cli/server/server_test.go +++ b/internal/cli/server/server_test.go @@ -47,13 +47,13 @@ func TestServer_DeveloperMode(t *testing.T) { defer CloseMockServer(server) // record the initial block number - blockNumber := server.backend.BlockChain().CurrentBlock().Header().Number.Int64() + blockNumber := server.backend.BlockChain().CurrentBlock().Number.Int64() var i int64 = 0 for i = 0; i < 3; i++ { // We expect the node to mine blocks every `config.Developer.Period` time period time.Sleep(time.Duration(config.Developer.Period) * time.Second) - currBlock := server.backend.BlockChain().CurrentBlock().Header().Number.Int64() + currBlock := server.backend.BlockChain().CurrentBlock().Number.Int64() expected := blockNumber + i + 1 if res := assert.Equal(t, currBlock, expected); res == false { break diff --git a/internal/cli/server/service.go b/internal/cli/server/service.go index 1d530de10b..402deb7a33 100644 --- a/internal/cli/server/service.go +++ b/internal/cli/server/service.go @@ -197,7 +197,7 @@ func (s *Server) Status(ctx context.Context, in *proto.StatusRequest) (*proto.St resp := &proto.StatusResponse{ CurrentHeader: headerToProtoHeader(apiBackend.CurrentHeader()), - CurrentBlock: headerToProtoHeader(apiBackend.CurrentBlock().Header()), + CurrentBlock: headerToProtoHeader(apiBackend.CurrentBlock()), NumPeers: int64(len(s.node.Server().PeersInfo())), SyncMode: s.config.SyncMode, Syncing: &proto.StatusResponse_Syncing{ diff --git a/internal/cli/snapshot.go b/internal/cli/snapshot.go index 9f4a0795bc..7257cde4b7 100644 --- a/internal/cli/snapshot.go +++ b/internal/cli/snapshot.go @@ -168,7 +168,13 @@ func (c *PruneStateCommand) Run(args []string) int { return 1 } - pruner, err := pruner.NewPruner(chaindb, node.ResolvePath(""), node.ResolvePath(c.cacheTrieJournal), c.bloomfilterSize) + prunerconfig := pruner.Config{ + Datadir: node.ResolvePath(""), + Cachedir: node.ResolvePath(c.cacheTrieJournal), + BloomSize: c.bloomfilterSize, + } + + pruner, err := pruner.NewPruner(chaindb, prunerconfig) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return 1 diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 77af8932a3..0b3c2904e3 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -312,7 +312,7 @@ func Setup(ctx *cli.Context) error { // This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name. // It cannot be imported because it will cause a cyclical dependency. StartPProf(address, !ctx.IsSet("metrics.addr")) - } else if ctx.GlobalIsSet("bor-mumbai") || ctx.GlobalIsSet("bor-mainnet") { + } else if ctx.IsSet("bor-mumbai") || ctx.IsSet("bor-mainnet") { address := fmt.Sprintf("%s:%d", "0.0.0.0", 7071) StartPProf(address, !ctx.IsSet("metrics.addr")) } diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 24c15b7775..5f4dfc0ad5 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -343,3 +343,43 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) } func (b *backendMock) Engine() consensus.Engine { return nil } + +func (b *backendMock) RPCRpcReturnDataLimit() uint64 { + return b.RPCRpcReturnDataLimit() +} + +func (b *backendMock) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription { + return b.SubscribeStateSyncEvent(ch) +} + +func (b *backendMock) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) { + return b.GetRootHash(ctx, starBlockNr, endBlockNr) +} + +func (b *backendMock) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { + return b.GetBorBlockReceipt(ctx, hash) +} + +func (b *backendMock) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { + return b.GetBorBlockLogs(ctx, hash) +} + +func (b *backendMock) GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { + return b.GetBorBlockTransaction(ctx, txHash) +} + +func (b *backendMock) GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { + return b.GetBorBlockTransactionWithBlockHash(ctx, txHash, blockHash) +} + +func (b *backendMock) SubscribeChain2HeadEvent(ch chan<- core.Chain2HeadEvent) event.Subscription { + return b.SubscribeChain2HeadEvent(ch) +} + +func (b *backendMock) GetCheckpointWhitelist() map[uint64]common.Hash { + return b.GetCheckpointWhitelist() +} + +func (b *backendMock) PurgeCheckpointWhitelist() { + b.PurgeCheckpointWhitelist() +} diff --git a/light/lightchain.go b/light/lightchain.go index 22b1bd5880..567a28b800 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -93,7 +93,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit), engine: engine, } - bc.forker = core.NewForkChoice(bc, nil) + bc.forker = core.NewForkChoice(bc, nil, checker) var err error bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt) if err != nil { @@ -401,24 +401,6 @@ func (lc *LightChain) SetCanonical(header *types.Header) error { return nil } -func (lc *LightChain) InsertHeader(header *types.Header) error { - // Verify the header first before obtaining the lock - headers := []*types.Header{header} - if _, err := lc.hc.ValidateHeaderChain(headers, 100); err != nil { - return err - } - // Make sure only one thread manipulates the chain at once - lc.chainmu.Lock() - defer lc.chainmu.Unlock() - - lc.wg.Add(1) - defer lc.wg.Done() - - _, err := lc.hc.WriteHeaders(headers) - log.Info("Inserted header", "number", header.Number, "hash", header.Hash()) - return err -} - func (lc *LightChain) SetChainHead(header *types.Header) error { lc.chainmu.Lock() defer lc.chainmu.Unlock() diff --git a/light/odr_test.go b/light/odr_test.go index b0be271c69..76d5384c5f 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -276,7 +276,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { } ) // Assemble the test environment - blockchain, _ := core.NewBlockChain(sdb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(sdb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) _, gchain, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { t.Fatal(err) diff --git a/light/trie_test.go b/light/trie_test.go index 0ab3eb02a0..477883b886 100644 --- a/light/trie_test.go +++ b/light/trie_test.go @@ -43,7 +43,7 @@ func TestNodeIterator(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), } ) - blockchain, _ := core.NewBlockChain(fulldb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(fulldb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) _, gchain, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) diff --git a/light/txpool_test.go b/light/txpool_test.go index 249fa14ffc..d815435ff8 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -90,7 +90,7 @@ func TestTxPool(t *testing.T) { } ) // Assemble the test environment - blockchain, _ := core.NewBlockChain(sdb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(sdb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) _, gchain, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), poolTestBlocks, txPoolTestChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) diff --git a/miner/worker_test.go b/miner/worker_test.go index ae0cce6384..dbce0d01c1 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -19,7 +19,6 @@ package miner import ( "crypto/rand" "errors" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -50,15 +49,6 @@ import ( "github.com/ethereum/go-ethereum/tests/bor/mocks" ) -const ( - // testCode is the testing contract binary code which will initialises some - // variables in constructor - testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032" - - // testGas is the gas required for contract deployment. - testGas = 144109 -) - func init() { testTxPoolConfig = txpool.DefaultConfig testTxPoolConfig.Journal = "" @@ -92,15 +82,6 @@ func init() { newTxs = append(newTxs, tx2) } -// testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. -type testWorkerBackend struct { - db ethdb.Database - txPool *txpool.TxPool - chain *core.BlockChain - genesis *core.Genesis - uncleBlock *types.Block -} - // newTestWorker creates a new test worker with the given parameters. func newTestWorker(t TensingObject, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int, noempty bool, delay uint, opcodeDelay uint) (*worker, *testWorkerBackend, func()) { backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) @@ -124,63 +105,6 @@ func newTestWorker(t TensingObject, chainConfig *params.ChainConfig, engine cons return w, backend, w.close } -func newTestWorkerBackend(t TensingObject, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { - var gspec = &core.Genesis{ - Config: chainConfig, - Alloc: core.GenesisAlloc{TestBankAddress: {Balance: testBankFunds}}, - } - switch e := engine.(type) { - case *bor.Bor: - gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) - copy(gspec.ExtraData[32:32+common.AddressLength], TestBankAddress.Bytes()) - e.Authorize(TestBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { - return crypto.Sign(crypto.Keccak256(data), testBankKey) - }) - case *clique.Clique: - gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) - copy(gspec.ExtraData[32:32+common.AddressLength], TestBankAddress.Bytes()) - e.Authorize(TestBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { - return crypto.Sign(crypto.Keccak256(data), testBankKey) - }) - case *ethash.Ethash: - default: - t.Fatalf("unexpected consensus engine type: %T", engine) - } - chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil, nil) - if err != nil { - t.Fatalf("core.NewBlockChain failed: %v", err) - } - txpool := txpool.NewTxPool(testTxPoolConfig, chainConfig, chain) - - // Generate a small n-block chain and an uncle block for it - var uncle *types.Block - if n > 0 { - genDb, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, func(i int, gen *core.BlockGen) { - gen.SetCoinbase(TestBankAddress) - }) - if _, err := chain.InsertChain(blocks); err != nil { - t.Fatalf("failed to insert origin chain: %v", err) - } - parent := chain.GetBlockByHash(chain.CurrentBlock().ParentHash) - blocks, _ = core.GenerateChain(chainConfig, parent, engine, genDb, 1, func(i int, gen *core.BlockGen) { - gen.SetCoinbase(testUserAddress) - }) - uncle = blocks[0] - } else { - _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, 1, func(i int, gen *core.BlockGen) { - gen.SetCoinbase(testUserAddress) - }) - uncle = blocks[0] - } - return &testWorkerBackend{ - db: db, - chain: chain, - txPool: txpool, - genesis: gspec, - uncleBlock: uncle, - } -} - func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool } func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { @@ -196,7 +120,7 @@ func (b *testWorkerBackend) newRandomUncle() (*types.Block, error) { parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash) } var err error - blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) { + blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.DB, 1, func(i int, gen *core.BlockGen) { var addr = make([]byte, common.AddressLength) _, err = rand.Read(addr) if err != nil { @@ -302,7 +226,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) { defer w.close() // This test chain imports the mined blocks. - chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, b.genesis, nil, engine, vm.Config{}, nil, nil, nil) + chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, b.Genesis, nil, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() // Ignore empty commit here for less noise. @@ -962,7 +886,7 @@ func BenchmarkBorMining(b *testing.B) { w, back, _ := newTestWorker(b, chainConfig, engine, db, 0, false, 0, 0) defer w.close() - chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, back.genesis, nil, engine, vm.Config{}, nil, nil, nil) + chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, back.Genesis, nil, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() // Ignore empty commit here for less noise. @@ -978,7 +902,7 @@ func BenchmarkBorMining(b *testing.B) { var err error - txInBlock := int(back.genesis.GasLimit/totalGas) + 1 + txInBlock := int(back.Genesis.GasLimit/totalGas) + 1 // a bit risky for i := 0; i < 2*totalBlocks*txInBlock; i++ { @@ -1004,7 +928,7 @@ func BenchmarkBorMining(b *testing.B) { // Start mining! w.start() - blockPeriod, ok := back.genesis.Config.Bor.Period["0"] + blockPeriod, ok := back.Genesis.Config.Bor.Period["0"] if !ok { blockPeriod = 1 } diff --git a/node/config.go b/node/config.go index fa3e7857a1..e2eb270fd5 100644 --- a/node/config.go +++ b/node/config.go @@ -19,10 +19,12 @@ package node import ( "crypto/ecdsa" "fmt" + "github.com/ethereum/go-ethereum/p2p/enode" "os" "path/filepath" "runtime" "strings" + "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -193,6 +195,8 @@ type Config struct { // Logger is a custom logger to use with the p2p.Server. Logger log.Logger `toml:",omitempty"` + staticNodesWarning bool + trustedNodesWarning bool oldGethResourceWarning bool // AllowUnprotectedTxs allows non EIP-155 protected transactions to be send over RPC. @@ -360,6 +364,50 @@ func (c *Config) ResolvePath(path string) string { return filepath.Join(c.instanceDir(), path) } +// StaticNodes returns a list of node enode URLs configured as static nodes. +func (c *Config) StaticNodes() []*enode.Node { + return c.parsePersistentNodes(&c.staticNodesWarning, c.ResolvePath(datadirStaticNodes)) +} + +// TrustedNodes returns a list of node enode URLs configured as trusted nodes. +func (c *Config) TrustedNodes() []*enode.Node { + return c.parsePersistentNodes(&c.trustedNodesWarning, c.ResolvePath(datadirTrustedNodes)) +} + +// parsePersistentNodes parses a list of discovery node URLs loaded from a .json +// file from within the data directory. +func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node { + // Short circuit if no node config is present + if c.DataDir == "" { + return nil + } + if _, err := os.Stat(path); err != nil { + return nil + } + c.warnOnce(w, "Found deprecated node list file %s, please use the TOML config file instead.", path) + + // Load the nodes from the config file. + var nodelist []string + if err := common.LoadJSON(path, &nodelist); err != nil { + log.Error(fmt.Sprintf("Can't load node list file: %v", err)) + return nil + } + // Interpret the list as a discovery node array + var nodes []*enode.Node + for _, url := range nodelist { + if url == "" { + continue + } + node, err := enode.Parse(enode.ValidSchemes, url) + if err != nil { + log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err)) + continue + } + nodes = append(nodes, node) + } + return nodes +} + func (c *Config) instanceDir() string { if c.DataDir == "" { return "" @@ -480,3 +528,20 @@ func getKeyStoreDir(conf *Config) (string, bool, error) { return keydir, isEphemeral, nil } + +var warnLock sync.Mutex + +func (c *Config) warnOnce(w *bool, format string, args ...interface{}) { + warnLock.Lock() + defer warnLock.Unlock() + + if *w { + return + } + l := c.Logger + if l == nil { + l = log.Root() + } + l.Warn(fmt.Sprintf(format, args...)) + *w = true +} diff --git a/node/rpcstack.go b/node/rpcstack.go index 49e10968d9..3da357330a 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -308,7 +308,7 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error { // Create RPC server and handler. srv := rpc.NewServer(config.executionPoolSize, config.executionPoolRequestTimeout) srv.SetRPCBatchLimit(h.RPCBatchLimit) - if err := RegisterApis(apis, config.Modules, srv, false); err != nil { + if err := RegisterApis(apis, config.Modules, srv); err != nil { return err } h.httpConfig = config diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 0790dddec4..6eeb609395 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -241,7 +241,7 @@ func createAndStartServer(t *testing.T, conf *httpConfig, ws bool, wsConf *wsCon if timeouts == nil { timeouts = &rpc.DefaultHTTPTimeouts } - srv := newHTTPServer(testlog.Logger(t, log.LvlDebug), *timeouts) + srv := newHTTPServer(testlog.Logger(t, log.LvlDebug), *timeouts, 100) assert.NoError(t, srv.enableRPC(apis(), *conf)) if ws { assert.NoError(t, srv.enableWS(nil, *wsConf)) diff --git a/rlp/rlpgen/main.go b/rlp/rlpgen/main.go index 0b3c08936b..655eea2689 100644 --- a/rlp/rlpgen/main.go +++ b/rlp/rlpgen/main.go @@ -62,6 +62,7 @@ func main() { if err := os.WriteFile(canonicalPath, code, 0600); err != nil { fatal(err) } + } } func fatal(args ...interface{}) { diff --git a/rpc/http.go b/rpc/http.go index ffd5505327..810da3fa9c 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -114,10 +114,10 @@ type HTTPTimeouts struct { // DefaultHTTPTimeouts represents the default timeout values used if further // configuration is not provided. var DefaultHTTPTimeouts = HTTPTimeouts{ - ReadTimeout: 10 * time.Second, + ReadTimeout: 10 * time.Second, ReadHeaderTimeout: 30 * time.Second, - WriteTimeout: 30 * time.Second, - IdleTimeout: 120 * time.Second, + WriteTimeout: 30 * time.Second, + IdleTimeout: 120 * time.Second, } // DialHTTP creates a new RPC client that connects to an RPC server over HTTP. @@ -165,7 +165,6 @@ func newClientTransportHTTP(endpoint string, cfg *clientConfig) reconnectFunc { return func(ctx context.Context) (ServerCodec, error) { return hc, nil -} } } diff --git a/rpc/json.go b/rpc/json.go index a394f8bf35..8a3b162cab 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -214,11 +214,6 @@ func (c *jsonCodec) peerInfo() PeerInfo { return PeerInfo{Transport: "ipc", RemoteAddr: c.remote} } -func (c *jsonCodec) peerInfo() PeerInfo { - // This returns "ipc" because all other built-in transports have a separate codec type. - return PeerInfo{Transport: "ipc", RemoteAddr: c.remote} -} - func (c *jsonCodec) remoteAddr() string { return c.remote } diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 8fb1182377..8218e754d3 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -27,8 +27,6 @@ import ( "sort" "strconv" "strings" - "unicode" - "unicode/utf8" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" diff --git a/tests/bor/bor_sprint_length_change_test.go b/tests/bor/bor_sprint_length_change_test.go index fed05751d4..5aef2ade1c 100644 --- a/tests/bor/bor_sprint_length_change_test.go +++ b/tests/bor/bor_sprint_length_change_test.go @@ -5,6 +5,7 @@ import ( "encoding/csv" "encoding/json" "fmt" + "github.com/ethereum/go-ethereum/core/txpool" "io/ioutil" // nolint: staticcheck _log "log" "math/big" @@ -16,7 +17,6 @@ import ( "gotest.tools/assert" "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" @@ -778,7 +778,6 @@ func InitGenesisSprintLength(t *testing.T, faucets []*ecdsa.PrivateKey, fileLoca } genesis.Config.ChainID = big.NewInt(15001) - genesis.Config.EIP150Hash = common.Hash{} genesis.Config.Bor.Sprint["0"] = sprintSize return genesis @@ -811,7 +810,7 @@ func InitMinerSprintLength(genesis *core.Genesis, privKey *ecdsa.PrivateKey, wit SyncMode: downloader.FullSync, DatabaseCache: 256, DatabaseHandles: 256, - TxPool: core.DefaultTxPoolConfig, + TxPool: txpool.DefaultConfig, GPO: ethconfig.Defaults.GPO, Ethash: ethconfig.Defaults.Ethash, Miner: miner.Config{ diff --git a/tests/init.go b/tests/init.go index eb76b2aa95..a8800b8ce2 100644 --- a/tests/init.go +++ b/tests/init.go @@ -231,7 +231,6 @@ var Forks = map[string]*params.ChainConfig{ LondonBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0), Bor: params.BorUnittestChainConfig.Bor, - ArrowGlacierBlock: big.NewInt(0), }, "ArrowGlacierToMergeAtDiffC0000": { ChainID: big.NewInt(1), @@ -250,7 +249,7 @@ var Forks = map[string]*params.ChainConfig{ GrayGlacierBlock: big.NewInt(0), MergeNetsplitBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0xC0000), - Bor: params.BorUnittestChainConfig.Bor, + Bor: params.BorUnittestChainConfig.Bor, }, "GrayGlacier": { ChainID: big.NewInt(1), @@ -285,7 +284,7 @@ var Forks = map[string]*params.ChainConfig{ ArrowGlacierBlock: big.NewInt(0), MergeNetsplitBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0), - Bor: params.BorUnittestChainConfig.Bor, + Bor: params.BorUnittestChainConfig.Bor, }, "Shanghai": { ChainID: big.NewInt(1), @@ -304,7 +303,7 @@ var Forks = map[string]*params.ChainConfig{ MergeNetsplitBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: u64(0), - Bor: params.BorUnittestChainConfig.Bor, + Bor: params.BorUnittestChainConfig.Bor, }, "MergeToShanghaiAtTime15k": { ChainID: big.NewInt(1), @@ -323,7 +322,7 @@ var Forks = map[string]*params.ChainConfig{ MergeNetsplitBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: u64(15_000), - Bor: params.BorUnittestChainConfig.Bor, + Bor: params.BorUnittestChainConfig.Bor, }, } diff --git a/trie/trie.go b/trie/trie.go index aaecee15a0..4b6f6a55bb 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -557,15 +557,6 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { return mustDecodeNode(n, blob), nil } -func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) { - hash := common.BytesToHash(n) - blob, _ := t.db.Node(hash) - if len(blob) != 0 { - return blob, nil - } - return nil, &MissingNodeError{NodeHash: hash, Path: prefix} -} - // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. func (t *Trie) Hash() common.Hash {