mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 22:56:43 +00:00
dev: chg: more regression changes for bor after merge
This commit is contained in:
parent
162af07d38
commit
d3f6da90e1
47 changed files with 253 additions and 1271 deletions
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package vm
|
|||
|
||||
import (
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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{}),
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
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")
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ func main() {
|
|||
if err := os.WriteFile(canonicalPath, code, 0600); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fatal(args ...interface{}) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ import (
|
|||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue