forked from cerc-io/plugeth
automated merge
This commit is contained in:
+4
-8
@@ -24,7 +24,6 @@ import (
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -86,11 +85,8 @@ func NewMinerAPI(e *Ethereum) *MinerAPI {
|
||||
// usable by this process. If mining is already running, this method adjust the
|
||||
// number of threads allowed to use and updates the minimum price required by the
|
||||
// transaction pool.
|
||||
func (api *MinerAPI) Start(threads *int) error {
|
||||
if threads == nil {
|
||||
return api.e.StartMining(runtime.NumCPU())
|
||||
}
|
||||
return api.e.StartMining(*threads)
|
||||
func (api *MinerAPI) Start() error {
|
||||
return api.e.StartMining()
|
||||
}
|
||||
|
||||
// Stop terminates the miner, both at the consensus engine level as well as at
|
||||
@@ -558,7 +554,7 @@ func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error
|
||||
if num.Int64() < 0 {
|
||||
block := api.eth.blockchain.CurrentBlock()
|
||||
if block == nil {
|
||||
return 0, fmt.Errorf("current block missing")
|
||||
return 0, errors.New("current block missing")
|
||||
}
|
||||
return block.Number.Uint64(), nil
|
||||
}
|
||||
@@ -578,7 +574,7 @@ func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error
|
||||
return 0, err
|
||||
}
|
||||
if start == end {
|
||||
return 0, fmt.Errorf("from and to needs to be different")
|
||||
return 0, errors.New("from and to needs to be different")
|
||||
}
|
||||
if start > end {
|
||||
delta = -1
|
||||
|
||||
+16
-5
@@ -134,6 +134,9 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
|
||||
return nil, errors.New("'finalized' tag not supported on pre-merge network")
|
||||
}
|
||||
header := b.eth.blockchain.CurrentFinalBlock()
|
||||
if header == nil {
|
||||
return nil, errors.New("finalized block not found")
|
||||
}
|
||||
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
|
||||
}
|
||||
if number == rpc.SafeBlockNumber {
|
||||
@@ -141,6 +144,9 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
|
||||
return nil, errors.New("'safe' tag not supported on pre-merge network")
|
||||
}
|
||||
header := b.eth.blockchain.CurrentSafeBlock()
|
||||
if header == nil {
|
||||
return nil, errors.New("safe block not found")
|
||||
}
|
||||
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
|
||||
}
|
||||
return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil
|
||||
@@ -240,13 +246,18 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) {
|
||||
if vmConfig == nil {
|
||||
vmConfig = b.eth.blockchain.GetVMConfig()
|
||||
}
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
context := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil)
|
||||
return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error, nil
|
||||
var context vm.BlockContext
|
||||
if blockCtx != nil {
|
||||
context = *blockCtx
|
||||
} else {
|
||||
context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil)
|
||||
}
|
||||
return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
|
||||
@@ -386,8 +397,8 @@ func (b *EthAPIBackend) Miner() *miner.Miner {
|
||||
return b.eth.Miner()
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) StartMining(threads int) error {
|
||||
return b.eth.StartMining(threads)
|
||||
func (b *EthAPIBackend) StartMining() error {
|
||||
return b.eth.StartMining()
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
|
||||
+4
-3
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
@@ -68,7 +69,7 @@ func TestAccountRange(t *testing.T) {
|
||||
|
||||
var (
|
||||
statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true})
|
||||
state, _ = state.New(common.Hash{}, statedb, nil)
|
||||
state, _ = state.New(types.EmptyRootHash, statedb, nil)
|
||||
addrs = [AccountRangeMaxResults * 2]common.Address{}
|
||||
m = map[common.Address]bool{}
|
||||
)
|
||||
@@ -139,7 +140,7 @@ func TestEmptyAccountRange(t *testing.T) {
|
||||
|
||||
var (
|
||||
statedb = state.NewDatabase(rawdb.NewMemoryDatabase())
|
||||
st, _ = state.New(common.Hash{}, statedb, nil)
|
||||
st, _ = state.New(types.EmptyRootHash, statedb, nil)
|
||||
)
|
||||
st.Commit(true)
|
||||
st.IntermediateRoot(true)
|
||||
@@ -162,7 +163,7 @@ func TestStorageRangeAt(t *testing.T) {
|
||||
|
||||
// Create a state where account 0x010000... has a few storage entries.
|
||||
var (
|
||||
state, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
state, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
addr = common.Address{0x01}
|
||||
keys = []common.Hash{ // hashes of Keys of storage
|
||||
common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"),
|
||||
|
||||
+12
-29
@@ -23,7 +23,6 @@ import (
|
||||
"math/big"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -135,14 +134,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
log.Error("Failed to recover state", "error", err)
|
||||
}
|
||||
// Transfer mining-related config to the ethash config.
|
||||
ethashConfig := config.Ethash
|
||||
ethashConfig.NotifyFull = config.Miner.NotifyFull
|
||||
cliqueConfig, err := core.LoadCliqueConfig(chainDb, config.Genesis)
|
||||
chainConfig, err := core.LoadChainConfig(chainDb, config.Genesis)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
engine, err := ethconfig.CreateConsensusEngine(chainConfig, chainDb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, config.Miner.Notify, config.Miner.Noverify, chainDb)
|
||||
|
||||
eth := &Ethereum{
|
||||
config: config,
|
||||
merger: consensus.NewMerger(chainDb),
|
||||
@@ -195,8 +194,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
)
|
||||
// Override the chain config with provided settings.
|
||||
var overrides core.ChainOverrides
|
||||
if config.OverrideShanghai != nil {
|
||||
overrides.OverrideShanghai = config.OverrideShanghai
|
||||
if config.OverrideCancun != nil {
|
||||
overrides.OverrideCancun = config.OverrideCancun
|
||||
}
|
||||
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit)
|
||||
if err != nil {
|
||||
@@ -211,10 +210,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
|
||||
// Permit the downloader to use the trie cache allowance during fast sync
|
||||
cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit
|
||||
checkpoint := config.Checkpoint
|
||||
if checkpoint == nil {
|
||||
checkpoint = params.TrustedCheckpoints[eth.blockchain.Genesis().Hash()]
|
||||
}
|
||||
if eth.handler, err = newHandler(&handlerConfig{
|
||||
Database: chainDb,
|
||||
Chain: eth.blockchain,
|
||||
@@ -224,7 +219,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
Sync: config.SyncMode,
|
||||
BloomCache: uint64(cacheLimit),
|
||||
EventMux: eth.eventMux,
|
||||
Checkpoint: checkpoint,
|
||||
RequiredBlocks: config.RequiredBlocks,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
@@ -329,7 +323,7 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) {
|
||||
if etherbase != (common.Address{}) {
|
||||
return etherbase, nil
|
||||
}
|
||||
return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
|
||||
return common.Address{}, errors.New("etherbase must be explicitly specified")
|
||||
}
|
||||
|
||||
// isLocalBlock checks whether the specified block is mined
|
||||
@@ -398,18 +392,7 @@ func (s *Ethereum) SetEtherbase(etherbase common.Address) {
|
||||
// StartMining starts the miner with the given number of CPU threads. If mining
|
||||
// is already running, this method adjust the number of threads allowed to use
|
||||
// and updates the minimum price required by the transaction pool.
|
||||
func (s *Ethereum) StartMining(threads int) error {
|
||||
// Update the thread count within the consensus engine
|
||||
type threaded interface {
|
||||
SetThreads(threads int)
|
||||
}
|
||||
if th, ok := s.engine.(threaded); ok {
|
||||
log.Info("Updated mining threads", "threads", threads)
|
||||
if threads == 0 {
|
||||
threads = -1 // Disable the miner from within
|
||||
}
|
||||
th.SetThreads(threads)
|
||||
}
|
||||
func (s *Ethereum) StartMining() error {
|
||||
// If the miner was not running, initialize it
|
||||
if !s.IsMining() {
|
||||
// Propagate the initial price point to the transaction pool
|
||||
@@ -442,7 +425,7 @@ func (s *Ethereum) StartMining(threads int) error {
|
||||
}
|
||||
// If mining is started, we can disable the transaction rejection mechanism
|
||||
// introduced to speed sync times.
|
||||
atomic.StoreUint32(&s.handler.acceptTxs, 1)
|
||||
s.handler.acceptTxs.Store(true)
|
||||
|
||||
go s.miner.Start()
|
||||
}
|
||||
@@ -474,8 +457,8 @@ func (s *Ethereum) Engine() consensus.Engine { return s.engine }
|
||||
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
|
||||
func (s *Ethereum) IsListening() bool { return true } // Always listening
|
||||
func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader }
|
||||
func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.handler.acceptTxs) == 1 }
|
||||
func (s *Ethereum) SetSynced() { atomic.StoreUint32(&s.handler.acceptTxs, 1) }
|
||||
func (s *Ethereum) Synced() bool { return s.handler.acceptTxs.Load() }
|
||||
func (s *Ethereum) SetSynced() { s.handler.acceptTxs.Store(true) }
|
||||
func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning }
|
||||
func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer }
|
||||
func (s *Ethereum) Merger() *consensus.Merger { return s.merger }
|
||||
|
||||
+10
-9
@@ -20,6 +20,7 @@ package catalyst
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -165,10 +166,10 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI {
|
||||
func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||
if payloadAttributes != nil {
|
||||
if payloadAttributes.Withdrawals != nil {
|
||||
return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1"))
|
||||
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("withdrawals not supported in V1"))
|
||||
}
|
||||
if api.eth.BlockChain().Config().IsShanghai(payloadAttributes.Timestamp) {
|
||||
return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("forkChoiceUpdateV1 called post-shanghai"))
|
||||
if api.eth.BlockChain().Config().IsShanghai(api.eth.BlockChain().Config().LondonBlock, payloadAttributes.Timestamp) {
|
||||
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai"))
|
||||
}
|
||||
}
|
||||
return api.forkchoiceUpdated(update, payloadAttributes)
|
||||
@@ -185,7 +186,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa
|
||||
}
|
||||
|
||||
func (api *ConsensusAPI) verifyPayloadAttributes(attr *engine.PayloadAttributes) error {
|
||||
if !api.eth.BlockChain().Config().IsShanghai(attr.Timestamp) {
|
||||
if !api.eth.BlockChain().Config().IsShanghai(api.eth.BlockChain().Config().LondonBlock, attr.Timestamp) {
|
||||
// Reject payload attributes with withdrawals before shanghai
|
||||
if attr.Withdrawals != nil {
|
||||
return errors.New("withdrawals before shanghai")
|
||||
@@ -385,7 +386,7 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config engine.Transit
|
||||
TerminalBlockNumber: config.TerminalBlockNumber,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid terminal block hash")
|
||||
return nil, errors.New("invalid terminal block hash")
|
||||
}
|
||||
return &engine.TransitionConfigurationV1{TerminalTotalDifficulty: (*hexutil.Big)(ttd)}, nil
|
||||
}
|
||||
@@ -416,19 +417,19 @@ func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID) (*engine.Executi
|
||||
// NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||
func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.PayloadStatusV1, error) {
|
||||
if params.Withdrawals != nil {
|
||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1"))
|
||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("withdrawals not supported in V1"))
|
||||
}
|
||||
return api.newPayload(params)
|
||||
}
|
||||
|
||||
// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||
func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) {
|
||||
if api.eth.BlockChain().Config().IsShanghai(params.Timestamp) {
|
||||
if api.eth.BlockChain().Config().IsShanghai(new(big.Int).SetUint64(params.Number), params.Timestamp) {
|
||||
if params.Withdrawals == nil {
|
||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("nil withdrawals post-shanghai"))
|
||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai"))
|
||||
}
|
||||
} else if params.Withdrawals != nil {
|
||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("non-nil withdrawals pre-shanghai"))
|
||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil withdrawals pre-shanghai"))
|
||||
}
|
||||
return api.newPayload(params)
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block)
|
||||
t.Fatal("can't create node:", err)
|
||||
}
|
||||
|
||||
ethcfg := ðconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
|
||||
ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
|
||||
ethservice, err := eth.New(n, ethcfg)
|
||||
if err != nil {
|
||||
t.Fatal("can't create eth service:", err)
|
||||
|
||||
@@ -53,11 +53,9 @@ var (
|
||||
reorgProtThreshold = 48 // Threshold number of recent blocks to disable mini reorg protection
|
||||
reorgProtHeaderDelay = 2 // Number of headers to delay delivering to cover mini reorgs
|
||||
|
||||
fsHeaderCheckFrequency = 100 // Verification frequency of the downloaded headers during snap sync
|
||||
fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected
|
||||
fsHeaderForceVerify = 24 // Number of headers to verify before and after the pivot to accept it
|
||||
fsHeaderContCheck = 3 * time.Second // Time interval to check for header continuations during state download
|
||||
fsMinFullBlocks = 64 // Number of blocks to retrieve fully even in snap sync
|
||||
fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected
|
||||
fsHeaderContCheck = 3 * time.Second // Time interval to check for header continuations during state download
|
||||
fsMinFullBlocks = 64 // Number of blocks to retrieve fully even in snap sync
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -101,10 +99,9 @@ type Downloader struct {
|
||||
mode atomic.Uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode
|
||||
mux *event.TypeMux // Event multiplexer to announce sync operation events
|
||||
|
||||
checkpoint uint64 // Checkpoint block number to enforce head against (e.g. snap sync)
|
||||
genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT)
|
||||
queue *queue // Scheduler for selecting the hashes to download
|
||||
peers *peerSet // Set of active peers from which download can proceed
|
||||
genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT)
|
||||
queue *queue // Scheduler for selecting the hashes to download
|
||||
peers *peerSet // Set of active peers from which download can proceed
|
||||
|
||||
stateDB ethdb.Database // Database to state sync into (and deduplicate via)
|
||||
|
||||
@@ -176,7 +173,7 @@ type LightChain interface {
|
||||
GetTd(common.Hash, uint64) *big.Int
|
||||
|
||||
// InsertHeaderChain inserts a batch of headers into the local chain.
|
||||
InsertHeaderChain([]*types.Header, int) (int, error)
|
||||
InsertHeaderChain([]*types.Header) (int, error)
|
||||
|
||||
// SetHead rewinds the local chain to a new head.
|
||||
SetHead(uint64) error
|
||||
@@ -219,14 +216,13 @@ type BlockChain interface {
|
||||
}
|
||||
|
||||
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
||||
func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func()) *Downloader {
|
||||
func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func()) *Downloader {
|
||||
if lightchain == nil {
|
||||
lightchain = chain
|
||||
}
|
||||
dl := &Downloader{
|
||||
stateDB: stateDb,
|
||||
mux: mux,
|
||||
checkpoint: checkpoint,
|
||||
queue: newQueue(blockCacheMaxItems, blockCacheInitialItems),
|
||||
peers: newPeerSet(),
|
||||
blockchain: chain,
|
||||
@@ -593,11 +589,9 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
|
||||
d.ancientLimit = 0
|
||||
}
|
||||
} else {
|
||||
// Legacy sync, use any hardcoded checkpoints or the best announcement
|
||||
// we have from the remote peer. TODO(karalabe): Drop this pathway.
|
||||
if d.checkpoint != 0 && d.checkpoint > fullMaxForkAncestry+1 {
|
||||
d.ancientLimit = d.checkpoint
|
||||
} else if height > fullMaxForkAncestry+1 {
|
||||
// Legacy sync, use the best announcement we have from the remote peer.
|
||||
// TODO(karalabe): Drop this pathway.
|
||||
if height > fullMaxForkAncestry+1 {
|
||||
d.ancientLimit = height - fullMaxForkAncestry - 1
|
||||
} else {
|
||||
d.ancientLimit = 0
|
||||
@@ -669,8 +663,11 @@ func (d *Downloader) spawnSync(fetchers []func() error) error {
|
||||
// it has processed the queue.
|
||||
d.queue.Close()
|
||||
}
|
||||
if err = <-errc; err != nil && err != errCanceled {
|
||||
break
|
||||
if got := <-errc; got != nil {
|
||||
err = got
|
||||
if got != errCanceled {
|
||||
break // receive a meaningful error, bubble it up
|
||||
}
|
||||
}
|
||||
}
|
||||
d.queue.Close()
|
||||
@@ -742,13 +739,10 @@ func (d *Downloader) fetchHead(p *peerConnection) (head *types.Header, pivot *ty
|
||||
if len(headers) == 0 || len(headers) > fetch {
|
||||
return nil, nil, fmt.Errorf("%w: returned headers %d != requested %d", errBadPeer, len(headers), fetch)
|
||||
}
|
||||
// The first header needs to be the head, validate against the checkpoint
|
||||
// and request. If only 1 header was returned, make sure there's no pivot
|
||||
// or there was not one requested.
|
||||
// The first header needs to be the head, validate against the request. If
|
||||
// only 1 header was returned, make sure there's no pivot or there was not
|
||||
// one requested.
|
||||
head = headers[0]
|
||||
if (mode == SnapSync || mode == LightSync) && head.Number.Uint64() < d.checkpoint {
|
||||
return nil, nil, fmt.Errorf("%w: remote head %d below checkpoint %d", errUnsyncedPeer, head.Number, d.checkpoint)
|
||||
}
|
||||
if len(headers) == 1 {
|
||||
if mode == SnapSync && head.Number.Uint64() > uint64(fsMinFullBlocks) {
|
||||
return nil, nil, fmt.Errorf("%w: no pivot included along head header", errBadPeer)
|
||||
@@ -1388,19 +1382,6 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||
|
||||
// In case of header only syncing, validate the chunk immediately
|
||||
if mode == SnapSync || mode == LightSync {
|
||||
// If we're importing pure headers, verify based on their recentness
|
||||
var pivot uint64
|
||||
|
||||
d.pivotLock.RLock()
|
||||
if d.pivotHeader != nil {
|
||||
pivot = d.pivotHeader.Number.Uint64()
|
||||
}
|
||||
d.pivotLock.RUnlock()
|
||||
|
||||
frequency := fsHeaderCheckFrequency
|
||||
if chunkHeaders[len(chunkHeaders)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot {
|
||||
frequency = 1
|
||||
}
|
||||
// Although the received headers might be all valid, a legacy
|
||||
// PoW/PoA sync must not accept post-merge headers. Make sure
|
||||
// that any transition is rejected at this point.
|
||||
@@ -1433,11 +1414,11 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||
}
|
||||
}
|
||||
if len(chunkHeaders) > 0 {
|
||||
if n, err := d.lightchain.InsertHeaderChain(chunkHeaders, frequency); err != nil {
|
||||
if n, err := d.lightchain.InsertHeaderChain(chunkHeaders); err != nil {
|
||||
rollbackErr = err
|
||||
|
||||
// If some headers were inserted, track them as uncertain
|
||||
if (mode == SnapSync || frequency > 1) && n > 0 && rollback == 0 {
|
||||
if mode == SnapSync && n > 0 && rollback == 0 {
|
||||
rollback = chunkHeaders[0].Number.Uint64()
|
||||
}
|
||||
log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package downloader
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
@@ -82,7 +81,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
|
||||
chain: chain,
|
||||
peers: make(map[string]*downloadTesterPeer),
|
||||
}
|
||||
tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success)
|
||||
tester.downloader = New(db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success)
|
||||
return tester
|
||||
}
|
||||
|
||||
@@ -1409,44 +1408,6 @@ func TestRemoteHeaderRequestSpan(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that peers below a pre-configured checkpoint block are prevented from
|
||||
// being fast-synced from, avoiding potential cheap eclipse attacks.
|
||||
func TestCheckpointEnforcement66Full(t *testing.T) { testCheckpointEnforcement(t, eth.ETH66, FullSync) }
|
||||
func TestCheckpointEnforcement66Snap(t *testing.T) { testCheckpointEnforcement(t, eth.ETH66, SnapSync) }
|
||||
func TestCheckpointEnforcement66Light(t *testing.T) {
|
||||
testCheckpointEnforcement(t, eth.ETH66, LightSync)
|
||||
}
|
||||
func TestCheckpointEnforcement67Full(t *testing.T) { testCheckpointEnforcement(t, eth.ETH67, FullSync) }
|
||||
func TestCheckpointEnforcement67Snap(t *testing.T) { testCheckpointEnforcement(t, eth.ETH67, SnapSync) }
|
||||
func TestCheckpointEnforcement67Light(t *testing.T) {
|
||||
testCheckpointEnforcement(t, eth.ETH67, LightSync)
|
||||
}
|
||||
|
||||
func testCheckpointEnforcement(t *testing.T, protocol uint, mode SyncMode) {
|
||||
// Create a new tester with a particular hard coded checkpoint block
|
||||
tester := newTester(t)
|
||||
defer tester.terminate()
|
||||
|
||||
tester.downloader.checkpoint = uint64(fsMinFullBlocks) + 256
|
||||
chain := testChainBase.shorten(int(tester.downloader.checkpoint) - 1)
|
||||
|
||||
// Attempt to sync with the peer and validate the result
|
||||
tester.newPeer("peer", protocol, chain.blocks[1:])
|
||||
|
||||
var expect error
|
||||
if mode == SnapSync || mode == LightSync {
|
||||
expect = errUnsyncedPeer
|
||||
}
|
||||
if err := tester.sync("peer", nil, mode); !errors.Is(err, expect) {
|
||||
t.Fatalf("block sync error mismatch: have %v, want %v", err, expect)
|
||||
}
|
||||
if mode == SnapSync || mode == LightSync {
|
||||
assertOwnChain(t, tester, 1)
|
||||
} else {
|
||||
assertOwnChain(t, tester, len(chain.blocks))
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that peers below a pre-configured checkpoint block are prevented from
|
||||
// being fast-synced from, avoiding potential cheap eclipse attacks.
|
||||
func TestBeaconSync66Full(t *testing.T) { testBeaconSync(t, eth.ETH66, FullSync) }
|
||||
|
||||
@@ -42,7 +42,7 @@ func makeChain(n int, seed byte, parent *types.Block, empty bool) ([]*types.Bloc
|
||||
block.SetCoinbase(common.Address{seed})
|
||||
// Add one tx to every secondblock
|
||||
if !empty && i%2 == 0 {
|
||||
signer := types.MakeSigner(params.TestChainConfig, block.Number())
|
||||
signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -168,7 +168,7 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool)
|
||||
}
|
||||
// Include transactions to the miner to make blocks more interesting.
|
||||
if parent == tc.blocks[0] && i%22 == 0 {
|
||||
signer := types.MakeSigner(params.TestChainConfig, block.Number())
|
||||
signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
+23
-83
@@ -18,10 +18,7 @@
|
||||
package ethconfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -34,9 +31,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/miner"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
@@ -62,16 +57,7 @@ var LightClientGPO = gasprice.Config{
|
||||
|
||||
// Defaults contains default settings for use on the Ethereum main net.
|
||||
var Defaults = Config{
|
||||
SyncMode: downloader.SnapSync,
|
||||
Ethash: ethash.Config{
|
||||
CacheDir: "ethash",
|
||||
CachesInMem: 2,
|
||||
CachesOnDisk: 3,
|
||||
CachesLockMmap: false,
|
||||
DatasetsInMem: 1,
|
||||
DatasetsOnDisk: 2,
|
||||
DatasetsLockMmap: false,
|
||||
},
|
||||
SyncMode: downloader.SnapSync,
|
||||
NetworkId: 1,
|
||||
TxLookupLimit: 2350000,
|
||||
LightPeers: 100,
|
||||
@@ -92,27 +78,6 @@ var Defaults = Config{
|
||||
RPCTxFeeCap: 1, // 1 ether
|
||||
}
|
||||
|
||||
func init() {
|
||||
home := os.Getenv("HOME")
|
||||
if home == "" {
|
||||
if user, err := user.Current(); err == nil {
|
||||
home = user.HomeDir
|
||||
}
|
||||
}
|
||||
if runtime.GOOS == "darwin" {
|
||||
Defaults.Ethash.DatasetDir = filepath.Join(home, "Library", "Ethash")
|
||||
} else if runtime.GOOS == "windows" {
|
||||
localappdata := os.Getenv("LOCALAPPDATA")
|
||||
if localappdata != "" {
|
||||
Defaults.Ethash.DatasetDir = filepath.Join(localappdata, "Ethash")
|
||||
} else {
|
||||
Defaults.Ethash.DatasetDir = filepath.Join(home, "AppData", "Local", "Ethash")
|
||||
}
|
||||
} else {
|
||||
Defaults.Ethash.DatasetDir = filepath.Join(home, ".ethash")
|
||||
}
|
||||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type Config -formats toml -out gen_config.go
|
||||
|
||||
// Config contains configuration options for of the ETH and LES protocols.
|
||||
@@ -141,13 +106,12 @@ type Config struct {
|
||||
RequiredBlocks map[uint64]common.Hash `toml:"-"`
|
||||
|
||||
// Light client options
|
||||
LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests
|
||||
LightIngress int `toml:",omitempty"` // Incoming bandwidth limit for light servers
|
||||
LightEgress int `toml:",omitempty"` // Outgoing bandwidth limit for light servers
|
||||
LightPeers int `toml:",omitempty"` // Maximum number of LES client peers
|
||||
LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning
|
||||
LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing
|
||||
SyncFromCheckpoint bool `toml:",omitempty"` // Whether to sync the header chain from the configured checkpoint
|
||||
LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests
|
||||
LightIngress int `toml:",omitempty"` // Incoming bandwidth limit for light servers
|
||||
LightEgress int `toml:",omitempty"` // Outgoing bandwidth limit for light servers
|
||||
LightPeers int `toml:",omitempty"` // Maximum number of LES client peers
|
||||
LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning
|
||||
LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing
|
||||
|
||||
// Ultra Light client options
|
||||
UltraLightServers []string `toml:",omitempty"` // List of trusted ultra light servers
|
||||
@@ -174,9 +138,6 @@ type Config struct {
|
||||
// Mining options
|
||||
Miner miner.Config
|
||||
|
||||
// Ethash options
|
||||
Ethash ethash.Config
|
||||
|
||||
// Transaction pool options
|
||||
TxPool txpool.Config
|
||||
|
||||
@@ -199,18 +160,14 @@ type Config struct {
|
||||
// send-transaction variants. The unit is ether.
|
||||
RPCTxFeeCap float64
|
||||
|
||||
// Checkpoint is a hardcoded checkpoint which can be nil.
|
||||
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
|
||||
|
||||
// CheckpointOracle is the configuration for checkpoint oracle.
|
||||
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
|
||||
|
||||
// OverrideShanghai (TODO: remove after the fork)
|
||||
OverrideShanghai *uint64 `toml:",omitempty"`
|
||||
// OverrideCancun (TODO: remove after the fork)
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
}
|
||||
|
||||
// CreateConsensusEngine creates a consensus engine for the given chain configuration.
|
||||
func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, cliqueConfig *params.CliqueConfig, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
|
||||
// CreateConsensusEngine creates a consensus engine for the given chain config.
|
||||
// Clique is allowed for now to live standalone, but ethash is forbidden and can
|
||||
// only exist on already merged networks.
|
||||
func CreateConsensusEngine(config *params.ChainConfig, db ethdb.Database) (consensus.Engine, error) {
|
||||
// If proof-of-authority is requested, set it up
|
||||
//begin PluGeth code injection
|
||||
if engine := pluginGetEngine(stack, notify, noverify, db); engine != nil {
|
||||
@@ -218,31 +175,14 @@ func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, clique
|
||||
return engine
|
||||
}
|
||||
//end PluGeth code injection
|
||||
var engine consensus.Engine
|
||||
if cliqueConfig != nil {
|
||||
engine = clique.New(cliqueConfig, db)
|
||||
} else {
|
||||
switch ethashConfig.PowMode {
|
||||
case ethash.ModeFake:
|
||||
log.Warn("Ethash used in fake mode")
|
||||
case ethash.ModeTest:
|
||||
log.Warn("Ethash used in test mode")
|
||||
case ethash.ModeShared:
|
||||
log.Warn("Ethash used in shared mode")
|
||||
}
|
||||
engine = ethash.New(ethash.Config{
|
||||
PowMode: ethashConfig.PowMode,
|
||||
CacheDir: stack.ResolvePath(ethashConfig.CacheDir),
|
||||
CachesInMem: ethashConfig.CachesInMem,
|
||||
CachesOnDisk: ethashConfig.CachesOnDisk,
|
||||
CachesLockMmap: ethashConfig.CachesLockMmap,
|
||||
DatasetDir: ethashConfig.DatasetDir,
|
||||
DatasetsInMem: ethashConfig.DatasetsInMem,
|
||||
DatasetsOnDisk: ethashConfig.DatasetsOnDisk,
|
||||
DatasetsLockMmap: ethashConfig.DatasetsLockMmap,
|
||||
NotifyFull: ethashConfig.NotifyFull,
|
||||
}, notify, noverify)
|
||||
engine.(*ethash.Ethash).SetThreads(-1) // Disable CPU mining
|
||||
if config.Clique != nil {
|
||||
return beacon.New(clique.New(config.Clique, db)), nil
|
||||
}
|
||||
return beacon.New(engine)
|
||||
// If defaulting to proof-of-work, enforce an already merged network since
|
||||
// we cannot run PoW algorithms and more, so we cannot even follow a chain
|
||||
// not coordinated by a beacon node.
|
||||
if !config.TerminalTotalDifficultyPassed {
|
||||
return nil, errors.New("ethash is only supported as a historical component of already merged networks")
|
||||
}
|
||||
return beacon.New(ethash.NewFaker()), nil
|
||||
}
|
||||
|
||||
@@ -6,13 +6,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||
"github.com/ethereum/go-ethereum/miner"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// MarshalTOML marshals as TOML.
|
||||
@@ -33,7 +31,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
LightPeers int `toml:",omitempty"`
|
||||
LightNoPrune bool `toml:",omitempty"`
|
||||
LightNoSyncServe bool `toml:",omitempty"`
|
||||
SyncFromCheckpoint bool `toml:",omitempty"`
|
||||
UltraLightServers []string `toml:",omitempty"`
|
||||
UltraLightFraction int `toml:",omitempty"`
|
||||
UltraLightOnlyAnnounce bool `toml:",omitempty"`
|
||||
@@ -50,7 +47,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
Preimages bool
|
||||
FilterLogCacheSize int
|
||||
Miner miner.Config
|
||||
Ethash ethash.Config
|
||||
TxPool txpool.Config
|
||||
GPO gasprice.Config
|
||||
EnablePreimageRecording bool
|
||||
@@ -58,9 +54,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
RPCGasCap uint64
|
||||
RPCEVMTimeout time.Duration
|
||||
RPCTxFeeCap float64
|
||||
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
|
||||
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
|
||||
OverrideShanghai *uint64 `toml:",omitempty"`
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
}
|
||||
var enc Config
|
||||
enc.Genesis = c.Genesis
|
||||
@@ -78,7 +72,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
enc.LightPeers = c.LightPeers
|
||||
enc.LightNoPrune = c.LightNoPrune
|
||||
enc.LightNoSyncServe = c.LightNoSyncServe
|
||||
enc.SyncFromCheckpoint = c.SyncFromCheckpoint
|
||||
enc.UltraLightServers = c.UltraLightServers
|
||||
enc.UltraLightFraction = c.UltraLightFraction
|
||||
enc.UltraLightOnlyAnnounce = c.UltraLightOnlyAnnounce
|
||||
@@ -95,7 +88,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
enc.Preimages = c.Preimages
|
||||
enc.FilterLogCacheSize = c.FilterLogCacheSize
|
||||
enc.Miner = c.Miner
|
||||
enc.Ethash = c.Ethash
|
||||
enc.TxPool = c.TxPool
|
||||
enc.GPO = c.GPO
|
||||
enc.EnablePreimageRecording = c.EnablePreimageRecording
|
||||
@@ -103,9 +95,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
enc.RPCGasCap = c.RPCGasCap
|
||||
enc.RPCEVMTimeout = c.RPCEVMTimeout
|
||||
enc.RPCTxFeeCap = c.RPCTxFeeCap
|
||||
enc.Checkpoint = c.Checkpoint
|
||||
enc.CheckpointOracle = c.CheckpointOracle
|
||||
enc.OverrideShanghai = c.OverrideShanghai
|
||||
enc.OverrideCancun = c.OverrideCancun
|
||||
return &enc, nil
|
||||
}
|
||||
|
||||
@@ -127,7 +117,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
LightPeers *int `toml:",omitempty"`
|
||||
LightNoPrune *bool `toml:",omitempty"`
|
||||
LightNoSyncServe *bool `toml:",omitempty"`
|
||||
SyncFromCheckpoint *bool `toml:",omitempty"`
|
||||
UltraLightServers []string `toml:",omitempty"`
|
||||
UltraLightFraction *int `toml:",omitempty"`
|
||||
UltraLightOnlyAnnounce *bool `toml:",omitempty"`
|
||||
@@ -144,7 +133,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
Preimages *bool
|
||||
FilterLogCacheSize *int
|
||||
Miner *miner.Config
|
||||
Ethash *ethash.Config
|
||||
TxPool *txpool.Config
|
||||
GPO *gasprice.Config
|
||||
EnablePreimageRecording *bool
|
||||
@@ -152,9 +140,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
RPCGasCap *uint64
|
||||
RPCEVMTimeout *time.Duration
|
||||
RPCTxFeeCap *float64
|
||||
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
|
||||
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
|
||||
OverrideShanghai *uint64 `toml:",omitempty"`
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
}
|
||||
var dec Config
|
||||
if err := unmarshal(&dec); err != nil {
|
||||
@@ -205,9 +191,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
if dec.LightNoSyncServe != nil {
|
||||
c.LightNoSyncServe = *dec.LightNoSyncServe
|
||||
}
|
||||
if dec.SyncFromCheckpoint != nil {
|
||||
c.SyncFromCheckpoint = *dec.SyncFromCheckpoint
|
||||
}
|
||||
if dec.UltraLightServers != nil {
|
||||
c.UltraLightServers = dec.UltraLightServers
|
||||
}
|
||||
@@ -256,9 +239,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
if dec.Miner != nil {
|
||||
c.Miner = *dec.Miner
|
||||
}
|
||||
if dec.Ethash != nil {
|
||||
c.Ethash = *dec.Ethash
|
||||
}
|
||||
if dec.TxPool != nil {
|
||||
c.TxPool = *dec.TxPool
|
||||
}
|
||||
@@ -280,14 +260,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
if dec.RPCTxFeeCap != nil {
|
||||
c.RPCTxFeeCap = *dec.RPCTxFeeCap
|
||||
}
|
||||
if dec.Checkpoint != nil {
|
||||
c.Checkpoint = dec.Checkpoint
|
||||
}
|
||||
if dec.CheckpointOracle != nil {
|
||||
c.CheckpointOracle = dec.CheckpointOracle
|
||||
}
|
||||
if dec.OverrideShanghai != nil {
|
||||
c.OverrideShanghai = dec.OverrideShanghai
|
||||
if dec.OverrideCancun != nil {
|
||||
c.OverrideCancun = dec.OverrideCancun
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ var (
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
genesis = gspec.MustCommit(testdb)
|
||||
unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil))
|
||||
unknownBlock = types.NewBlock(&types.Header{Root: types.EmptyRootHash, GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil))
|
||||
)
|
||||
|
||||
// makeChain creates a chain of n blocks starting at and including parent.
|
||||
@@ -58,7 +58,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common
|
||||
|
||||
// If the block number is multiple of 3, send a bonus transaction to the miner
|
||||
if parent == genesis && i%3 == 0 {
|
||||
signer := types.MakeSigner(params.TestChainConfig, block.Number())
|
||||
signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -413,13 +413,13 @@ func testConcurrentAnnouncements(t *testing.T, light bool) {
|
||||
secondHeaderFetcher := tester.makeHeaderFetcher("second", blocks, -gatherSlack)
|
||||
secondBodyFetcher := tester.makeBodyFetcher("second", blocks, 0)
|
||||
|
||||
counter := uint32(0)
|
||||
var counter atomic.Uint32
|
||||
firstHeaderWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) {
|
||||
atomic.AddUint32(&counter, 1)
|
||||
counter.Add(1)
|
||||
return firstHeaderFetcher(hash, sink)
|
||||
}
|
||||
secondHeaderWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) {
|
||||
atomic.AddUint32(&counter, 1)
|
||||
counter.Add(1)
|
||||
return secondHeaderFetcher(hash, sink)
|
||||
}
|
||||
// Iteratively announce blocks until all are imported
|
||||
@@ -446,8 +446,8 @@ func testConcurrentAnnouncements(t *testing.T, light bool) {
|
||||
verifyImportDone(t, imported)
|
||||
|
||||
// Make sure no blocks were retrieved twice
|
||||
if int(counter) != targetBlocks {
|
||||
t.Fatalf("retrieval count mismatch: have %v, want %v", counter, targetBlocks)
|
||||
if c := int(counter.Load()); c != targetBlocks {
|
||||
t.Fatalf("retrieval count mismatch: have %v, want %v", c, targetBlocks)
|
||||
}
|
||||
verifyChainHeight(t, tester, uint64(len(hashes)-1))
|
||||
}
|
||||
@@ -513,9 +513,9 @@ func testPendingDeduplication(t *testing.T, light bool) {
|
||||
bodyFetcher := tester.makeBodyFetcher("repeater", blocks, 0)
|
||||
|
||||
delay := 50 * time.Millisecond
|
||||
counter := uint32(0)
|
||||
var counter atomic.Uint32
|
||||
headerWrapper := func(hash common.Hash, sink chan *eth.Response) (*eth.Request, error) {
|
||||
atomic.AddUint32(&counter, 1)
|
||||
counter.Add(1)
|
||||
|
||||
// Simulate a long running fetch
|
||||
resink := make(chan *eth.Response)
|
||||
@@ -545,8 +545,8 @@ func testPendingDeduplication(t *testing.T, light bool) {
|
||||
time.Sleep(delay)
|
||||
|
||||
// Check that all blocks were imported and none fetched twice
|
||||
if int(counter) != 1 {
|
||||
t.Fatalf("retrieval count mismatch: have %v, want %v", counter, 1)
|
||||
if c := counter.Load(); c != 1 {
|
||||
t.Fatalf("retrieval count mismatch: have %v, want %v", c, 1)
|
||||
}
|
||||
verifyChainHeight(t, tester, 1)
|
||||
}
|
||||
@@ -632,9 +632,9 @@ func TestImportDeduplication(t *testing.T) {
|
||||
headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
|
||||
bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
|
||||
|
||||
counter := uint32(0)
|
||||
var counter atomic.Uint32
|
||||
tester.fetcher.insertChain = func(blocks types.Blocks) (int, error) {
|
||||
atomic.AddUint32(&counter, uint32(len(blocks)))
|
||||
counter.Add(uint32(len(blocks)))
|
||||
return tester.insertChain(blocks)
|
||||
}
|
||||
// Instrument the fetching and imported events
|
||||
@@ -655,8 +655,8 @@ func TestImportDeduplication(t *testing.T) {
|
||||
tester.fetcher.Enqueue("valid", blocks[hashes[1]])
|
||||
verifyImportCount(t, imported, 2)
|
||||
|
||||
if counter != 2 {
|
||||
t.Fatalf("import invocation count mismatch: have %v, want %v", counter, 2)
|
||||
if c := counter.Load(); c != 2 {
|
||||
t.Fatalf("import invocation count mismatch: have %v, want %v", c, 2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,13 +853,13 @@ func TestHashMemoryExhaustionAttack(t *testing.T) {
|
||||
// Create a tester with instrumented import hooks
|
||||
tester := newTester(false)
|
||||
|
||||
imported, announces := make(chan interface{}), int32(0)
|
||||
imported, announces := make(chan interface{}), atomic.Int32{}
|
||||
tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block }
|
||||
tester.fetcher.announceChangeHook = func(hash common.Hash, added bool) {
|
||||
if added {
|
||||
atomic.AddInt32(&announces, 1)
|
||||
announces.Add(1)
|
||||
} else {
|
||||
atomic.AddInt32(&announces, -1)
|
||||
announces.Add(-1)
|
||||
}
|
||||
}
|
||||
// Create a valid chain and an infinite junk chain
|
||||
@@ -879,7 +879,7 @@ func TestHashMemoryExhaustionAttack(t *testing.T) {
|
||||
}
|
||||
tester.fetcher.Notify("attacker", attack[i], 1 /* don't distance drop */, time.Now(), attackerHeaderFetcher, attackerBodyFetcher)
|
||||
}
|
||||
if count := atomic.LoadInt32(&announces); count != hashLimit+maxQueueDist {
|
||||
if count := announces.Load(); count != hashLimit+maxQueueDist {
|
||||
t.Fatalf("queued announce count mismatch: have %d, want %d", count, hashLimit+maxQueueDist)
|
||||
}
|
||||
// Wait for fetches to complete
|
||||
@@ -900,13 +900,13 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) {
|
||||
// Create a tester with instrumented import hooks
|
||||
tester := newTester(false)
|
||||
|
||||
imported, enqueued := make(chan interface{}), int32(0)
|
||||
imported, enqueued := make(chan interface{}), atomic.Int32{}
|
||||
tester.fetcher.importedHook = func(header *types.Header, block *types.Block) { imported <- block }
|
||||
tester.fetcher.queueChangeHook = func(hash common.Hash, added bool) {
|
||||
if added {
|
||||
atomic.AddInt32(&enqueued, 1)
|
||||
enqueued.Add(1)
|
||||
} else {
|
||||
atomic.AddInt32(&enqueued, -1)
|
||||
enqueued.Add(-1)
|
||||
}
|
||||
}
|
||||
// Create a valid chain and a batch of dangling (but in range) blocks
|
||||
@@ -924,7 +924,7 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) {
|
||||
tester.fetcher.Enqueue("attacker", block)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
if queued := atomic.LoadInt32(&enqueued); queued != blockLimit {
|
||||
if queued := enqueued.Load(); queued != blockLimit {
|
||||
t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit)
|
||||
}
|
||||
// Queue up a batch of valid blocks, and check that a new peer is allowed to do so
|
||||
@@ -932,7 +932,7 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) {
|
||||
tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-3-i]])
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if queued := atomic.LoadInt32(&enqueued); queued != blockLimit+maxQueueDist-1 {
|
||||
if queued := enqueued.Load(); queued != blockLimit+maxQueueDist-1 {
|
||||
t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit+maxQueueDist-1)
|
||||
}
|
||||
// Insert the missing piece (and sanity check the import)
|
||||
|
||||
+10
-5
@@ -33,6 +33,11 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidTopic = errors.New("invalid topic(s)")
|
||||
errFilterNotFound = errors.New("filter not found")
|
||||
)
|
||||
|
||||
// filter is a helper struct that holds meta information over the filter type
|
||||
// and associated subscription in the event system.
|
||||
type filter struct {
|
||||
@@ -376,7 +381,7 @@ func (api *FilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Lo
|
||||
api.filtersMu.Unlock()
|
||||
|
||||
if !found || f.typ != LogsSubscription {
|
||||
return nil, fmt.Errorf("filter not found")
|
||||
return nil, errFilterNotFound
|
||||
}
|
||||
|
||||
var filter *Filter
|
||||
@@ -452,7 +457,7 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return []interface{}{}, fmt.Errorf("filter not found")
|
||||
return []interface{}{}, errFilterNotFound
|
||||
}
|
||||
|
||||
// returnHashes is a helper that will return an empty hash array case the given hash array is nil,
|
||||
@@ -491,7 +496,7 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
||||
if raw.BlockHash != nil {
|
||||
if raw.FromBlock != nil || raw.ToBlock != nil {
|
||||
// BlockHash is mutually exclusive with FromBlock/ToBlock criteria
|
||||
return fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other")
|
||||
return errors.New("cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other")
|
||||
}
|
||||
args.BlockHash = raw.BlockHash
|
||||
} else {
|
||||
@@ -564,11 +569,11 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
||||
}
|
||||
args.Topics[i] = append(args.Topics[i], parsed)
|
||||
} else {
|
||||
return fmt.Errorf("invalid topic(s)")
|
||||
return errInvalidTopic
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("invalid topic(s)")
|
||||
return errInvalidTopic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestUnmarshalJSONNewFilterArgs(t *testing.T) {
|
||||
|
||||
// from, to block number
|
||||
var test1 FilterCriteria
|
||||
vector := fmt.Sprintf(`{"fromBlock":"%#x","toBlock":"%#x"}`, fromBlock, toBlock)
|
||||
vector := fmt.Sprintf(`{"fromBlock":"%v","toBlock":"%v"}`, fromBlock, toBlock)
|
||||
if err := json.Unmarshal([]byte(vector), &test1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -296,6 +296,9 @@ func (f *Filter) checkMatches(ctx context.Context, header *types.Header) ([]*typ
|
||||
// pendingLogs returns the logs matching the filter criteria within the pending block.
|
||||
func (f *Filter) pendingLogs() ([]*types.Log, error) {
|
||||
block, receipts := f.sys.backend.PendingBlockAndReceipts()
|
||||
if block == nil {
|
||||
return nil, errors.New("pending state not available")
|
||||
}
|
||||
if bloomFilter(block.Bloom(), f.addresses, f.topics) {
|
||||
var unfiltered []*types.Log
|
||||
for _, r := range receipts {
|
||||
|
||||
@@ -20,6 +20,7 @@ package filters
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -331,7 +332,7 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ
|
||||
if from >= 0 && to == rpc.LatestBlockNumber {
|
||||
return es.subscribeLogs(crit, logs), nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid from and to block combination: from > to")
|
||||
return nil, errors.New("invalid from and to block combination: from > to")
|
||||
}
|
||||
|
||||
// subscribeMinedPendingLogs creates a subscription that returned mined and
|
||||
|
||||
@@ -111,7 +111,9 @@ func (b *testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.
|
||||
|
||||
func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
||||
if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil {
|
||||
return rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig), nil
|
||||
if header := rawdb.ReadHeader(b.db, hash, *number); header != nil {
|
||||
return rawdb.ReadReceipts(b.db, hash, *number, header.Time, params.TestChainConfig), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
+15
-12
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
func makeReceipt(addr common.Address) *types.Receipt {
|
||||
@@ -179,7 +180,7 @@ func TestFilters(t *testing.T) {
|
||||
// Set block 998 as Finalized (-3)
|
||||
rawdb.WriteFinalizedBlockHash(db, chain[998].Hash())
|
||||
|
||||
filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
|
||||
filter := sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
|
||||
logs, _ := filter.Logs(context.Background())
|
||||
if len(logs) != 4 {
|
||||
t.Error("expected 4 log, got", len(logs))
|
||||
@@ -193,34 +194,36 @@ func TestFilters(t *testing.T) {
|
||||
sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}),
|
||||
[]common.Hash{hash3},
|
||||
}, {
|
||||
sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}),
|
||||
sys.NewRangeFilter(990, int64(rpc.LatestBlockNumber), []common.Address{addr}, [][]common.Hash{{hash3}}),
|
||||
[]common.Hash{hash3},
|
||||
}, {
|
||||
sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}),
|
||||
[]common.Hash{hash1, hash2},
|
||||
}, {
|
||||
sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}),
|
||||
sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}),
|
||||
nil,
|
||||
}, {
|
||||
sys.NewRangeFilter(0, -1, []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil),
|
||||
sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil),
|
||||
nil,
|
||||
}, {
|
||||
sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}),
|
||||
sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}),
|
||||
nil,
|
||||
}, {
|
||||
sys.NewRangeFilter(-1, -1, nil, nil), []common.Hash{hash4},
|
||||
sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash4},
|
||||
}, {
|
||||
sys.NewRangeFilter(-3, -1, nil, nil), []common.Hash{hash3, hash4},
|
||||
sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash3, hash4},
|
||||
}, {
|
||||
sys.NewRangeFilter(-3, -3, nil, nil), []common.Hash{hash3},
|
||||
sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), []common.Hash{hash3},
|
||||
}, {
|
||||
sys.NewRangeFilter(-1, -3, nil, nil), nil,
|
||||
sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), nil,
|
||||
}, {
|
||||
sys.NewRangeFilter(-4, -1, nil, nil), nil,
|
||||
sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), nil,
|
||||
}, {
|
||||
sys.NewRangeFilter(-4, -4, nil, nil), nil,
|
||||
sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.SafeBlockNumber), nil, nil), nil,
|
||||
}, {
|
||||
sys.NewRangeFilter(-1, -4, nil, nil), nil,
|
||||
sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.SafeBlockNumber), nil, nil), nil,
|
||||
}, {
|
||||
sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), nil,
|
||||
},
|
||||
} {
|
||||
logs, _ := tc.f.Logs(context.Background())
|
||||
|
||||
@@ -251,10 +251,10 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL
|
||||
}
|
||||
oldestBlock := lastBlock + 1 - blocks
|
||||
|
||||
var (
|
||||
next = oldestBlock
|
||||
results = make(chan *blockFees, blocks)
|
||||
)
|
||||
var next atomic.Uint64
|
||||
next.Store(oldestBlock)
|
||||
results := make(chan *blockFees, blocks)
|
||||
|
||||
percentileKey := make([]byte, 8*len(rewardPercentiles))
|
||||
for i, p := range rewardPercentiles {
|
||||
binary.LittleEndian.PutUint64(percentileKey[i*8:(i+1)*8], math.Float64bits(p))
|
||||
@@ -263,7 +263,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL
|
||||
go func() {
|
||||
for {
|
||||
// Retrieve the next block number to fetch with this goroutine
|
||||
blockNumber := atomic.AddUint64(&next, 1) - 1
|
||||
blockNumber := next.Add(1) - 1
|
||||
if blockNumber > lastBlock {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
|
||||
results []*big.Int
|
||||
)
|
||||
for sent < oracle.checkBlocks && number > 0 {
|
||||
go oracle.getBlockValues(ctx, types.MakeSigner(oracle.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, oracle.ignorePrice, result, quit)
|
||||
go oracle.getBlockValues(ctx, number, sampleNumber, oracle.ignorePrice, result, quit)
|
||||
sent++
|
||||
exp++
|
||||
number--
|
||||
@@ -199,7 +199,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
|
||||
// meaningful returned, try to query more blocks. But the maximum
|
||||
// is 2*checkBlocks.
|
||||
if len(res.values) == 1 && len(results)+1+exp < oracle.checkBlocks*2 && number > 0 {
|
||||
go oracle.getBlockValues(ctx, types.MakeSigner(oracle.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, oracle.ignorePrice, result, quit)
|
||||
go oracle.getBlockValues(ctx, number, sampleNumber, oracle.ignorePrice, result, quit)
|
||||
sent++
|
||||
exp++
|
||||
number--
|
||||
@@ -251,11 +251,11 @@ func (s *txSorter) Less(i, j int) bool {
|
||||
return tip1.Cmp(tip2) < 0
|
||||
}
|
||||
|
||||
// getBlockPrices calculates the lowest transaction gas price in a given block
|
||||
// getBlockValues calculates the lowest transaction gas price in a given block
|
||||
// and sends it to the result channel. If the block is empty or all transactions
|
||||
// are sent by the miner itself(it doesn't make any sense to include this kind of
|
||||
// transaction prices for sampling), nil gasprice is returned.
|
||||
func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) {
|
||||
func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) {
|
||||
block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
|
||||
if block == nil {
|
||||
select {
|
||||
@@ -264,6 +264,8 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b
|
||||
}
|
||||
return
|
||||
}
|
||||
signer := types.MakeSigner(oracle.backend.ChainConfig(), block.Number(), block.Time())
|
||||
|
||||
// Sort the transaction by effective tip in ascending sort.
|
||||
txs := make([]*types.Transaction, len(block.Transactions()))
|
||||
copy(txs, block.Transactions())
|
||||
|
||||
+23
-102
@@ -38,7 +38,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -77,27 +76,23 @@ type txPool interface {
|
||||
// handlerConfig is the collection of initialization parameters to create a full
|
||||
// node network handler.
|
||||
type handlerConfig struct {
|
||||
Database ethdb.Database // Database for direct sync insertions
|
||||
Chain *core.BlockChain // Blockchain to serve data from
|
||||
TxPool txPool // Transaction pool to propagate from
|
||||
Merger *consensus.Merger // The manager for eth1/2 transition
|
||||
Network uint64 // Network identifier to adfvertise
|
||||
Sync downloader.SyncMode // Whether to snap or full sync
|
||||
BloomCache uint64 // Megabytes to alloc for snap sync bloom
|
||||
EventMux *event.TypeMux // Legacy event mux, deprecate for `feed`
|
||||
Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges
|
||||
RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges
|
||||
Database ethdb.Database // Database for direct sync insertions
|
||||
Chain *core.BlockChain // Blockchain to serve data from
|
||||
TxPool txPool // Transaction pool to propagate from
|
||||
Merger *consensus.Merger // The manager for eth1/2 transition
|
||||
Network uint64 // Network identifier to adfvertise
|
||||
Sync downloader.SyncMode // Whether to snap or full sync
|
||||
BloomCache uint64 // Megabytes to alloc for snap sync bloom
|
||||
EventMux *event.TypeMux // Legacy event mux, deprecate for `feed`
|
||||
RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
networkID uint64
|
||||
forkFilter forkid.Filter // Fork ID filter, constant across the lifetime of the node
|
||||
|
||||
snapSync uint32 // Flag whether snap sync is enabled (gets disabled if we already have blocks)
|
||||
acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing)
|
||||
|
||||
checkpointNumber uint64 // Block number for the sync progress validator to cross reference
|
||||
checkpointHash common.Hash // Block hash for the sync progress validator to cross reference
|
||||
snapSync atomic.Bool // Flag whether snap sync is enabled (gets disabled if we already have blocks)
|
||||
acceptTxs atomic.Bool // Flag whether we're considered synchronised (enables transaction processing)
|
||||
|
||||
database ethdb.Database
|
||||
txpool txPool
|
||||
@@ -154,7 +149,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||
// In these cases however it's safe to reenable snap sync.
|
||||
fullBlock, snapBlock := h.chain.CurrentBlock(), h.chain.CurrentSnapBlock()
|
||||
if fullBlock.Number.Uint64() == 0 && snapBlock.Number.Uint64() > 0 {
|
||||
h.snapSync = uint32(1)
|
||||
h.snapSync.Store(true)
|
||||
log.Warn("Switch sync mode from full sync to snap sync")
|
||||
}
|
||||
} else {
|
||||
@@ -163,36 +158,24 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||
log.Warn("Switch sync mode from snap sync to full sync")
|
||||
} else {
|
||||
// If snap sync was requested and our database is empty, grant it
|
||||
h.snapSync = uint32(1)
|
||||
h.snapSync.Store(true)
|
||||
}
|
||||
}
|
||||
// If we have trusted checkpoints, enforce them on the chain
|
||||
if config.Checkpoint != nil {
|
||||
h.checkpointNumber = (config.Checkpoint.SectionIndex+1)*params.CHTFrequency - 1
|
||||
h.checkpointHash = config.Checkpoint.SectionHead
|
||||
}
|
||||
// If sync succeeds, pass a callback to potentially disable snap sync mode
|
||||
// and enable transaction propagation.
|
||||
success := func() {
|
||||
// If we were running snap sync and it finished, disable doing another
|
||||
// round on next sync cycle
|
||||
if atomic.LoadUint32(&h.snapSync) == 1 {
|
||||
if h.snapSync.Load() {
|
||||
log.Info("Snap sync complete, auto disabling")
|
||||
atomic.StoreUint32(&h.snapSync, 0)
|
||||
}
|
||||
// If we've successfully finished a sync cycle and passed any required
|
||||
// checkpoint, enable accepting transactions from the network
|
||||
head := h.chain.CurrentBlock()
|
||||
if head.Number.Uint64() >= h.checkpointNumber {
|
||||
// Checkpoint passed, sanity check the timestamp to have a fallback mechanism
|
||||
// for non-checkpointed (number = 0) private networks.
|
||||
if head.Time >= uint64(time.Now().AddDate(0, -1, 0).Unix()) {
|
||||
atomic.StoreUint32(&h.acceptTxs, 1)
|
||||
}
|
||||
h.snapSync.Store(false)
|
||||
}
|
||||
// If we've successfully finished a sync cycle, accept transactions from
|
||||
// the network
|
||||
h.acceptTxs.Store(true)
|
||||
}
|
||||
// Construct the downloader (long sync)
|
||||
h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success)
|
||||
h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, success)
|
||||
if ttd := h.chain.Config().TerminalTotalDifficulty; ttd != nil {
|
||||
if h.chain.Config().TerminalTotalDifficultyPassed {
|
||||
log.Info("Chain post-merge, sync via beacon client")
|
||||
@@ -224,7 +207,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||
return errors.New("unexpected post-merge header")
|
||||
}
|
||||
}
|
||||
return h.chain.Engine().VerifyHeader(h.chain, header, true)
|
||||
return h.chain.Engine().VerifyHeader(h.chain, header)
|
||||
}
|
||||
heighter := func() uint64 {
|
||||
return h.chain.CurrentBlock().Number.Uint64()
|
||||
@@ -244,22 +227,12 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||
log.Warn("Unexpected insertion activity", ctx...)
|
||||
return 0, errors.New("unexpected behavior after transition")
|
||||
}
|
||||
// If sync hasn't reached the checkpoint yet, deny importing weird blocks.
|
||||
//
|
||||
// Ideally we would also compare the head block's timestamp and similarly reject
|
||||
// the propagated block if the head is too old. Unfortunately there is a corner
|
||||
// case when starting new networks, where the genesis might be ancient (0 unix)
|
||||
// which would prevent full nodes from accepting it.
|
||||
if h.chain.CurrentBlock().Number.Uint64() < h.checkpointNumber {
|
||||
log.Warn("Unsynced yet, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash())
|
||||
return 0, nil
|
||||
}
|
||||
// If snap sync is running, deny importing weird blocks. This is a problematic
|
||||
// clause when starting up a new network, because snap-syncing miners might not
|
||||
// accept each others' blocks until a restart. Unfortunately we haven't figured
|
||||
// out a way yet where nodes can decide unilaterally whether the network is new
|
||||
// or not. This should be fixed if we figure out a solution.
|
||||
if atomic.LoadUint32(&h.snapSync) == 1 {
|
||||
if h.snapSync.Load() {
|
||||
log.Warn("Snap syncing, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash())
|
||||
return 0, nil
|
||||
}
|
||||
@@ -288,7 +261,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||
}
|
||||
n, err := h.chain.InsertChain(blocks)
|
||||
if err == nil {
|
||||
atomic.StoreUint32(&h.acceptTxs, 1) // Mark initial sync done on any fetcher import
|
||||
h.acceptTxs.Store(true) // Mark initial sync done on any fetcher import
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
@@ -337,7 +310,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error {
|
||||
return err
|
||||
}
|
||||
reject := false // reserved peer slots
|
||||
if atomic.LoadUint32(&h.snapSync) == 1 {
|
||||
if h.snapSync.Load() {
|
||||
if snap == nil {
|
||||
// If we are running snap-sync, we want to reserve roughly half the peer
|
||||
// slots for peers supporting the snap protocol.
|
||||
@@ -387,58 +360,6 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error {
|
||||
dead := make(chan struct{})
|
||||
defer close(dead)
|
||||
|
||||
// If we have a trusted CHT, reject all peers below that (avoid fast sync eclipse)
|
||||
if h.checkpointHash != (common.Hash{}) {
|
||||
// Request the peer's checkpoint header for chain height/weight validation
|
||||
resCh := make(chan *eth.Response)
|
||||
|
||||
req, err := peer.RequestHeadersByNumber(h.checkpointNumber, 1, 0, false, resCh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Start a timer to disconnect if the peer doesn't reply in time
|
||||
go func() {
|
||||
// Ensure the request gets cancelled in case of error/drop
|
||||
defer req.Close()
|
||||
|
||||
timeout := time.NewTimer(syncChallengeTimeout)
|
||||
defer timeout.Stop()
|
||||
|
||||
select {
|
||||
case res := <-resCh:
|
||||
headers := ([]*types.Header)(*res.Res.(*eth.BlockHeadersPacket))
|
||||
if len(headers) == 0 {
|
||||
// If we're doing a snap sync, we must enforce the checkpoint
|
||||
// block to avoid eclipse attacks. Unsynced nodes are welcome
|
||||
// to connect after we're done joining the network.
|
||||
if atomic.LoadUint32(&h.snapSync) == 1 {
|
||||
peer.Log().Warn("Dropping unsynced node during sync", "addr", peer.RemoteAddr(), "type", peer.Name())
|
||||
res.Done <- errors.New("unsynced node cannot serve sync")
|
||||
return
|
||||
}
|
||||
res.Done <- nil
|
||||
return
|
||||
}
|
||||
// Validate the header and either drop the peer or continue
|
||||
if len(headers) > 1 {
|
||||
res.Done <- errors.New("too many headers in checkpoint response")
|
||||
return
|
||||
}
|
||||
if headers[0].Hash() != h.checkpointHash {
|
||||
res.Done <- errors.New("checkpoint hash mismatch")
|
||||
return
|
||||
}
|
||||
res.Done <- nil
|
||||
|
||||
case <-timeout.C:
|
||||
peer.Log().Warn("Checkpoint challenge timed out, dropping", "addr", peer.RemoteAddr(), "type", peer.Name())
|
||||
h.removePeer(peer.ID())
|
||||
|
||||
case <-dead:
|
||||
// Peer handler terminated, abort all goroutines
|
||||
}
|
||||
}()
|
||||
}
|
||||
// If we have any explicit peer required block hashes, request them
|
||||
for number, hash := range h.requiredBlocks {
|
||||
resCh := make(chan *eth.Response)
|
||||
|
||||
+1
-2
@@ -19,7 +19,6 @@ package eth
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -52,7 +51,7 @@ func (h *ethHandler) PeerInfo(id enode.ID) interface{} {
|
||||
// AcceptTxs retrieves whether transaction processing is enabled on the node
|
||||
// or if inbound transactions should simply be dropped.
|
||||
func (h *ethHandler) AcceptTxs() bool {
|
||||
return atomic.LoadUint32(&h.acceptTxs) == 1
|
||||
return h.acceptTxs.Load()
|
||||
}
|
||||
|
||||
// Handle is invoked from a peer's message handler when it receives a new remote
|
||||
|
||||
+3
-148
@@ -19,8 +19,6 @@ package eth
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -38,7 +36,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// testEthHandler is a mock event handler to listen for inbound network requests
|
||||
@@ -251,7 +248,7 @@ func testRecvTransactions(t *testing.T, protocol uint) {
|
||||
handler := newTestHandler()
|
||||
defer handler.close()
|
||||
|
||||
handler.handler.acceptTxs = 1 // mark synced to accept transactions
|
||||
handler.handler.acceptTxs.Store(true) // mark synced to accept transactions
|
||||
|
||||
txs := make(chan core.NewTxsEvent)
|
||||
sub := handler.txpool.SubscribeNewTxsEvent(txs)
|
||||
@@ -397,7 +394,7 @@ func testTransactionPropagation(t *testing.T, protocol uint) {
|
||||
// to receive them. We need multiple sinks since a one-to-one peering would
|
||||
// broadcast all transactions without announcement.
|
||||
source := newTestHandler()
|
||||
source.handler.snapSync = 0 // Avoid requiring snap, otherwise some will be dropped below
|
||||
source.handler.snapSync.Store(false) // Avoid requiring snap, otherwise some will be dropped below
|
||||
defer source.close()
|
||||
|
||||
sinks := make([]*testHandler, 10)
|
||||
@@ -405,7 +402,7 @@ func testTransactionPropagation(t *testing.T, protocol uint) {
|
||||
sinks[i] = newTestHandler()
|
||||
defer sinks[i].close()
|
||||
|
||||
sinks[i].handler.acceptTxs = 1 // mark synced to accept transactions
|
||||
sinks[i].handler.acceptTxs.Store(true) // mark synced to accept transactions
|
||||
}
|
||||
// Interconnect all the sink handlers with the source handler
|
||||
for i, sink := range sinks {
|
||||
@@ -459,148 +456,6 @@ func testTransactionPropagation(t *testing.T, protocol uint) {
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that post eth protocol handshake, clients perform a mutual checkpoint
|
||||
// challenge to validate each other's chains. Hash mismatches, or missing ones
|
||||
// during a fast sync should lead to the peer getting dropped.
|
||||
func TestCheckpointChallenge(t *testing.T) {
|
||||
tests := []struct {
|
||||
syncmode downloader.SyncMode
|
||||
checkpoint bool
|
||||
timeout bool
|
||||
empty bool
|
||||
match bool
|
||||
drop bool
|
||||
}{
|
||||
// If checkpointing is not enabled locally, don't challenge and don't drop
|
||||
{downloader.FullSync, false, false, false, false, false},
|
||||
{downloader.SnapSync, false, false, false, false, false},
|
||||
|
||||
// If checkpointing is enabled locally and remote response is empty, only drop during fast sync
|
||||
{downloader.FullSync, true, false, true, false, false},
|
||||
{downloader.SnapSync, true, false, true, false, true}, // Special case, fast sync, unsynced peer
|
||||
|
||||
// If checkpointing is enabled locally and remote response mismatches, always drop
|
||||
{downloader.FullSync, true, false, false, false, true},
|
||||
{downloader.SnapSync, true, false, false, false, true},
|
||||
|
||||
// If checkpointing is enabled locally and remote response matches, never drop
|
||||
{downloader.FullSync, true, false, false, true, false},
|
||||
{downloader.SnapSync, true, false, false, true, false},
|
||||
|
||||
// If checkpointing is enabled locally and remote times out, always drop
|
||||
{downloader.FullSync, true, true, false, true, true},
|
||||
{downloader.SnapSync, true, true, false, true, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(fmt.Sprintf("sync %v checkpoint %v timeout %v empty %v match %v", tt.syncmode, tt.checkpoint, tt.timeout, tt.empty, tt.match), func(t *testing.T) {
|
||||
testCheckpointChallenge(t, tt.syncmode, tt.checkpoint, tt.timeout, tt.empty, tt.match, tt.drop)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpoint bool, timeout bool, empty bool, match bool, drop bool) {
|
||||
// Reduce the checkpoint handshake challenge timeout
|
||||
defer func(old time.Duration) { syncChallengeTimeout = old }(syncChallengeTimeout)
|
||||
syncChallengeTimeout = 250 * time.Millisecond
|
||||
|
||||
// Create a test handler and inject a CHT into it. The injection is a bit
|
||||
// ugly, but it beats creating everything manually just to avoid reaching
|
||||
// into the internals a bit.
|
||||
handler := newTestHandler()
|
||||
defer handler.close()
|
||||
|
||||
if syncmode == downloader.SnapSync {
|
||||
atomic.StoreUint32(&handler.handler.snapSync, 1)
|
||||
} else {
|
||||
atomic.StoreUint32(&handler.handler.snapSync, 0)
|
||||
}
|
||||
var response *types.Header
|
||||
if checkpoint {
|
||||
number := (uint64(rand.Intn(500))+1)*params.CHTFrequency - 1
|
||||
response = &types.Header{Number: big.NewInt(int64(number)), Extra: []byte("valid")}
|
||||
|
||||
handler.handler.checkpointNumber = number
|
||||
handler.handler.checkpointHash = response.Hash()
|
||||
}
|
||||
|
||||
// Create a challenger peer and a challenged one.
|
||||
p2pLocal, p2pRemote := p2p.MsgPipe()
|
||||
defer p2pLocal.Close()
|
||||
defer p2pRemote.Close()
|
||||
|
||||
local := eth.NewPeer(eth.ETH66, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pLocal), p2pLocal, handler.txpool)
|
||||
remote := eth.NewPeer(eth.ETH66, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pRemote), p2pRemote, handler.txpool)
|
||||
defer local.Close()
|
||||
defer remote.Close()
|
||||
|
||||
handlerDone := make(chan struct{})
|
||||
go func() {
|
||||
defer close(handlerDone)
|
||||
handler.handler.runEthPeer(local, func(peer *eth.Peer) error {
|
||||
return eth.Handle((*ethHandler)(handler.handler), peer)
|
||||
})
|
||||
}()
|
||||
|
||||
// Run the handshake locally to avoid spinning up a remote handler.
|
||||
var (
|
||||
genesis = handler.chain.Genesis()
|
||||
head = handler.chain.CurrentBlock()
|
||||
td = handler.chain.GetTd(head.Hash(), head.Number.Uint64())
|
||||
)
|
||||
if err := remote.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
||||
t.Fatalf("failed to run protocol handshake")
|
||||
}
|
||||
// Connect a new peer and check that we receive the checkpoint challenge.
|
||||
if checkpoint {
|
||||
msg, err := p2pRemote.ReadMsg()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read checkpoint challenge: %v", err)
|
||||
}
|
||||
request := new(eth.GetBlockHeadersPacket66)
|
||||
if err := msg.Decode(request); err != nil {
|
||||
t.Fatalf("failed to decode checkpoint challenge: %v", err)
|
||||
}
|
||||
query := request.GetBlockHeadersPacket
|
||||
if query.Origin.Number != response.Number.Uint64() || query.Amount != 1 || query.Skip != 0 || query.Reverse {
|
||||
t.Fatalf("challenge mismatch: have [%d, %d, %d, %v] want [%d, %d, %d, %v]",
|
||||
query.Origin.Number, query.Amount, query.Skip, query.Reverse,
|
||||
response.Number.Uint64(), 1, 0, false)
|
||||
}
|
||||
// Create a block to reply to the challenge if no timeout is simulated.
|
||||
if !timeout {
|
||||
if empty {
|
||||
if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{}); err != nil {
|
||||
t.Fatalf("failed to answer challenge: %v", err)
|
||||
}
|
||||
} else if match {
|
||||
responseRlp, _ := rlp.EncodeToBytes(response)
|
||||
if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{responseRlp}); err != nil {
|
||||
t.Fatalf("failed to answer challenge: %v", err)
|
||||
}
|
||||
} else {
|
||||
responseRlp, _ := rlp.EncodeToBytes(&types.Header{Number: response.Number})
|
||||
if err := remote.ReplyBlockHeadersRLP(request.RequestId, []rlp.RawValue{responseRlp}); err != nil {
|
||||
t.Fatalf("failed to answer challenge: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wait until the test timeout passes to ensure proper cleanup
|
||||
time.Sleep(syncChallengeTimeout + 300*time.Millisecond)
|
||||
|
||||
// Verify that the remote peer is maintained or dropped.
|
||||
if drop {
|
||||
<-handlerDone
|
||||
if peers := handler.handler.peers.len(); peers != 0 {
|
||||
t.Fatalf("peer count mismatch: have %d, want %d", peers, 0)
|
||||
}
|
||||
} else {
|
||||
if peers := handler.handler.peers.len(); peers != 1 {
|
||||
t.Fatalf("peer count mismatch: have %d, want %d", peers, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that blocks are broadcast to a sqrt number of peers only.
|
||||
func TestBroadcastBlock1Peer(t *testing.T) { testBroadcastBlock(t, 1, 1) }
|
||||
func TestBroadcastBlock2Peers(t *testing.T) { testBroadcastBlock(t, 2, 1) }
|
||||
|
||||
@@ -449,10 +449,10 @@ type Syncer struct {
|
||||
trienodeHealReqs map[uint64]*trienodeHealRequest // Trie node requests currently running
|
||||
bytecodeHealReqs map[uint64]*bytecodeHealRequest // Bytecode requests currently running
|
||||
|
||||
trienodeHealRate float64 // Average heal rate for processing trie node data
|
||||
trienodeHealPend uint64 // Number of trie nodes currently pending for processing
|
||||
trienodeHealThrottle float64 // Divisor for throttling the amount of trienode heal data requested
|
||||
trienodeHealThrottled time.Time // Timestamp the last time the throttle was updated
|
||||
trienodeHealRate float64 // Average heal rate for processing trie node data
|
||||
trienodeHealPend atomic.Uint64 // Number of trie nodes currently pending for processing
|
||||
trienodeHealThrottle float64 // Divisor for throttling the amount of trienode heal data requested
|
||||
trienodeHealThrottled time.Time // Timestamp the last time the throttle was updated
|
||||
|
||||
trienodeHealSynced uint64 // Number of state trie nodes downloaded
|
||||
trienodeHealBytes common.StorageSize // Number of state trie bytes persisted to disk
|
||||
@@ -2189,7 +2189,7 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) {
|
||||
// HR(N) = (1-MI)^N*(OR-NR) + NR
|
||||
s.trienodeHealRate = gomath.Pow(1-trienodeHealRateMeasurementImpact, float64(fills))*(s.trienodeHealRate-rate) + rate
|
||||
|
||||
pending := atomic.LoadUint64(&s.trienodeHealPend)
|
||||
pending := s.trienodeHealPend.Load()
|
||||
if time.Since(s.trienodeHealThrottled) > time.Second {
|
||||
// Periodically adjust the trie node throttler
|
||||
if float64(pending) > 2*s.trienodeHealRate {
|
||||
@@ -2776,9 +2776,9 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error
|
||||
return errors.New("unexpected healing trienode")
|
||||
}
|
||||
// Response validated, send it to the scheduler for filling
|
||||
atomic.AddUint64(&s.trienodeHealPend, fills)
|
||||
s.trienodeHealPend.Add(fills)
|
||||
defer func() {
|
||||
atomic.AddUint64(&s.trienodeHealPend, ^(fills - 1))
|
||||
s.trienodeHealPend.Add(^(fills - 1))
|
||||
}()
|
||||
response := &trienodeHealResponse{
|
||||
paths: req.paths,
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
@@ -1389,7 +1390,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) {
|
||||
// Commit the state changes into db and re-create the trie
|
||||
// for accessing later.
|
||||
root, nodes := accTrie.Commit(false)
|
||||
db.Update(trie.NewWithNodeSet(nodes))
|
||||
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
|
||||
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
return db.Scheme(), accTrie, entries
|
||||
@@ -1451,7 +1452,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) {
|
||||
// Commit the state changes into db and re-create the trie
|
||||
// for accessing later.
|
||||
root, nodes := accTrie.Commit(false)
|
||||
db.Update(trie.NewWithNodeSet(nodes))
|
||||
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
|
||||
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
return db.Scheme(), accTrie, entries
|
||||
@@ -1467,7 +1468,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool)
|
||||
storageRoots = make(map[common.Hash]common.Hash)
|
||||
storageTries = make(map[common.Hash]*trie.Trie)
|
||||
storageEntries = make(map[common.Hash]entrySlice)
|
||||
nodes = trie.NewMergedNodeSet()
|
||||
nodes = trienode.NewMergedNodeSet()
|
||||
)
|
||||
// Create n accounts in the trie
|
||||
for i := uint64(1); i <= uint64(accounts); i++ {
|
||||
@@ -1500,7 +1501,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool)
|
||||
nodes.Merge(set)
|
||||
|
||||
// Commit gathered dirty nodes into database
|
||||
db.Update(nodes)
|
||||
db.Update(root, types.EmptyRootHash, nodes)
|
||||
|
||||
// Re-create tries with new root
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
@@ -1522,7 +1523,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin
|
||||
storageRoots = make(map[common.Hash]common.Hash)
|
||||
storageTries = make(map[common.Hash]*trie.Trie)
|
||||
storageEntries = make(map[common.Hash]entrySlice)
|
||||
nodes = trie.NewMergedNodeSet()
|
||||
nodes = trienode.NewMergedNodeSet()
|
||||
)
|
||||
// Create n accounts in the trie
|
||||
for i := uint64(1); i <= uint64(accounts); i++ {
|
||||
@@ -1534,7 +1535,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin
|
||||
// Make a storage trie
|
||||
var (
|
||||
stRoot common.Hash
|
||||
stNodes *trie.NodeSet
|
||||
stNodes *trienode.NodeSet
|
||||
stEntries entrySlice
|
||||
)
|
||||
if boundary {
|
||||
@@ -1565,7 +1566,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin
|
||||
nodes.Merge(set)
|
||||
|
||||
// Commit gathered dirty nodes into database
|
||||
db.Update(nodes)
|
||||
db.Update(root, types.EmptyRootHash, nodes)
|
||||
|
||||
// Re-create tries with new root
|
||||
accTrie, err := trie.New(trie.StateTrieID(root), db)
|
||||
@@ -1587,8 +1588,8 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin
|
||||
// makeStorageTrieWithSeed fills a storage trie with n items, returning the
|
||||
// not-yet-committed trie and the sorted entries. The seeds can be used to ensure
|
||||
// that tries are unique.
|
||||
func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trie.NodeSet, entrySlice) {
|
||||
trie, _ := trie.New(trie.StorageTrieID(common.Hash{}, owner, common.Hash{}), db)
|
||||
func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) {
|
||||
trie, _ := trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db)
|
||||
var entries entrySlice
|
||||
for i := uint64(1); i <= n; i++ {
|
||||
// store 'x' at slot 'x'
|
||||
@@ -1610,11 +1611,11 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas
|
||||
// makeBoundaryStorageTrie constructs a storage trie. Instead of filling
|
||||
// storage slots normally, this function will fill a few slots which have
|
||||
// boundary hash.
|
||||
func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trie.NodeSet, entrySlice) {
|
||||
func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) {
|
||||
var (
|
||||
entries entrySlice
|
||||
boundaries []common.Hash
|
||||
trie, _ = trie.New(trie.StorageTrieID(common.Hash{}, owner, common.Hash{}), db)
|
||||
trie, _ = trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db)
|
||||
)
|
||||
// Initialize boundaries
|
||||
var next common.Hash
|
||||
|
||||
@@ -209,7 +209,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||
return nil, vm.BlockContext{}, statedb, release, nil
|
||||
}
|
||||
// Recompute transactions up to the target index.
|
||||
signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
|
||||
signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time())
|
||||
for idx, tx := range block.Transactions() {
|
||||
// Assemble the transaction call message and return if the requested offset
|
||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||
|
||||
+7
-13
@@ -19,7 +19,6 @@ package eth
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -205,7 +204,7 @@ func peerToSyncOp(mode downloader.SyncMode, p *eth.Peer) *chainSyncOp {
|
||||
|
||||
func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) {
|
||||
// If we're in snap sync mode, return that directly
|
||||
if atomic.LoadUint32(&cs.handler.snapSync) == 1 {
|
||||
if cs.handler.snapSync.Load() {
|
||||
block := cs.handler.chain.CurrentSnapBlock()
|
||||
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
|
||||
return downloader.SnapSync, td
|
||||
@@ -256,20 +255,15 @@ func (h *handler) doSync(op *chainSyncOp) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if atomic.LoadUint32(&h.snapSync) == 1 {
|
||||
if h.snapSync.Load() {
|
||||
log.Info("Snap sync complete, auto disabling")
|
||||
atomic.StoreUint32(&h.snapSync, 0)
|
||||
h.snapSync.Store(false)
|
||||
}
|
||||
// If we've successfully finished a sync cycle and passed any required checkpoint,
|
||||
// enable accepting transactions from the network.
|
||||
// If we've successfully finished a sync cycle, enable accepting transactions
|
||||
// from the network.
|
||||
h.acceptTxs.Store(true)
|
||||
|
||||
head := h.chain.CurrentBlock()
|
||||
if head.Number.Uint64() >= h.checkpointNumber {
|
||||
// Checkpoint passed, sanity check the timestamp to have a fallback mechanism
|
||||
// for non-checkpointed (number = 0) private networks.
|
||||
if head.Time >= uint64(time.Now().AddDate(0, -1, 0).Unix()) {
|
||||
atomic.StoreUint32(&h.acceptTxs, 1)
|
||||
}
|
||||
}
|
||||
if head.Number.Uint64() > 0 {
|
||||
// We've completed a sync cycle, notify all peers of new state. This path is
|
||||
// essential in star-topology networks where a gateway node needs to notify
|
||||
|
||||
+3
-4
@@ -17,7 +17,6 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -39,14 +38,14 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) {
|
||||
|
||||
// Create an empty handler and ensure it's in snap sync mode
|
||||
empty := newTestHandler()
|
||||
if atomic.LoadUint32(&empty.handler.snapSync) == 0 {
|
||||
if !empty.handler.snapSync.Load() {
|
||||
t.Fatalf("snap sync disabled on pristine blockchain")
|
||||
}
|
||||
defer empty.close()
|
||||
|
||||
// Create a full handler and ensure snap sync ends up disabled
|
||||
full := newTestHandlerWithBlocks(1024)
|
||||
if atomic.LoadUint32(&full.handler.snapSync) == 1 {
|
||||
if full.handler.snapSync.Load() {
|
||||
t.Fatalf("snap sync not disabled on non-empty blockchain")
|
||||
}
|
||||
defer full.close()
|
||||
@@ -91,7 +90,7 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) {
|
||||
if err := empty.handler.doSync(op); err != nil {
|
||||
t.Fatal("sync failed:", err)
|
||||
}
|
||||
if atomic.LoadUint32(&empty.handler.snapSync) == 1 {
|
||||
if empty.handler.snapSync.Load() {
|
||||
t.Fatalf("snap sync not disabled after successful synchronisation")
|
||||
}
|
||||
}
|
||||
|
||||
+12
-35
@@ -100,34 +100,10 @@ func NewAPI(backend Backend) *API {
|
||||
return &API{backend: backend}
|
||||
}
|
||||
|
||||
type chainContext struct {
|
||||
api *API
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (context *chainContext) Engine() consensus.Engine {
|
||||
return context.api.backend.Engine()
|
||||
}
|
||||
|
||||
func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||
header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if header.Hash() == hash {
|
||||
return header
|
||||
}
|
||||
header, err = context.api.backend.HeaderByHash(context.ctx, hash)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return header
|
||||
}
|
||||
|
||||
// chainContext constructs the context reader which is used by the evm for reading
|
||||
// the necessary chain context.
|
||||
func (api *API) chainContext(ctx context.Context) core.ChainContext {
|
||||
return &chainContext{api: api, ctx: ctx}
|
||||
return ethapi.NewChainContext(ctx, api.backend)
|
||||
}
|
||||
|
||||
// blockByNumber is the wrapper of the chain access function offered by the backend.
|
||||
@@ -200,6 +176,7 @@ type StdTraceConfig struct {
|
||||
|
||||
// txTraceResult is the result of a single transaction trace.
|
||||
type txTraceResult struct {
|
||||
TxHash common.Hash `json:"txHash"` // transaction hash
|
||||
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
|
||||
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
|
||||
}
|
||||
@@ -288,7 +265,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
||||
// Fetch and execute the block trace taskCh
|
||||
for task := range taskCh {
|
||||
var (
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number())
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
|
||||
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
|
||||
)
|
||||
// Trace all the transactions contained within
|
||||
@@ -302,13 +279,13 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
||||
}
|
||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
|
||||
if err != nil {
|
||||
task.results[i] = &txTraceResult{Error: err.Error()}
|
||||
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
|
||||
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
|
||||
break
|
||||
}
|
||||
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
||||
task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
|
||||
task.results[i] = &txTraceResult{Result: res}
|
||||
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res}
|
||||
}
|
||||
// Tracing state is used up, queue it for de-referencing. Note the
|
||||
// state is the parent state of trace block, use block.number-1 as
|
||||
@@ -544,7 +521,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
||||
|
||||
var (
|
||||
roots []common.Hash
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
chainConfig = api.backend.ChainConfig()
|
||||
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
|
||||
@@ -623,7 +600,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||
blockHash = block.Hash()
|
||||
is158 = api.backend.ChainConfig().IsEIP158(block.Number())
|
||||
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
results = make([]*txTraceResult, len(txs))
|
||||
)
|
||||
for i, tx := range txs {
|
||||
@@ -639,7 +616,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results[i] = &txTraceResult{Result: res}
|
||||
results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res}
|
||||
// Finalize the state so any modifications are written to the trie
|
||||
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
||||
statedb.Finalise(is158)
|
||||
@@ -656,7 +633,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
|
||||
txs = block.Transactions()
|
||||
blockHash = block.Hash()
|
||||
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
results = make([]*txTraceResult, len(txs))
|
||||
pend sync.WaitGroup
|
||||
)
|
||||
@@ -680,10 +657,10 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
|
||||
}
|
||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
|
||||
if err != nil {
|
||||
results[task.index] = &txTraceResult{Error: err.Error()}
|
||||
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
|
||||
continue
|
||||
}
|
||||
results[task.index] = &txTraceResult{Result: res}
|
||||
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Result: res}
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -765,7 +742,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||
// Execute transaction, either tracing all or just the requested one
|
||||
var (
|
||||
dumps []string
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
chainConfig = api.backend.ChainConfig()
|
||||
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
canon = true
|
||||
|
||||
+14
-11
@@ -169,7 +169,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
||||
return nil, vm.BlockContext{}, statedb, release, nil
|
||||
}
|
||||
// Recompute transactions up to the target index.
|
||||
signer := types.MakeSigner(b.chainConfig, block.Number())
|
||||
signer := types.MakeSigner(b.chainConfig, block.Number(), block.Time())
|
||||
for idx, tx := range block.Transactions() {
|
||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
@@ -384,12 +384,14 @@ func TestTraceBlock(t *testing.T) {
|
||||
}
|
||||
genBlocks := 10
|
||||
signer := types.HomesteadSigner{}
|
||||
var txHash common.Hash
|
||||
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
|
||||
// Transfer from account[0] to account[1]
|
||||
// value: 1000 wei
|
||||
// fee: 0 wei
|
||||
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
|
||||
b.AddTx(tx)
|
||||
txHash = tx.Hash()
|
||||
})
|
||||
defer backend.chain.Stop()
|
||||
api := NewAPI(backend)
|
||||
@@ -408,7 +410,7 @@ func TestTraceBlock(t *testing.T) {
|
||||
// Trace head block
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(genBlocks),
|
||||
want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
|
||||
},
|
||||
// Trace non-existent block
|
||||
{
|
||||
@@ -418,12 +420,12 @@ func TestTraceBlock(t *testing.T) {
|
||||
// Trace latest block
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
|
||||
},
|
||||
// Trace pending block
|
||||
{
|
||||
blockNumber: rpc.PendingBlockNumber,
|
||||
want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
|
||||
want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
|
||||
},
|
||||
}
|
||||
for i, tc := range testSuite {
|
||||
@@ -853,7 +855,7 @@ func TestTraceChain(t *testing.T) {
|
||||
backend.relHook = func() { rel.Add(1) }
|
||||
api := NewAPI(backend)
|
||||
|
||||
single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}`
|
||||
single := `{"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}`
|
||||
var cases = []struct {
|
||||
start uint64
|
||||
end uint64
|
||||
@@ -872,16 +874,17 @@ func TestTraceChain(t *testing.T) {
|
||||
|
||||
next := c.start + 1
|
||||
for result := range resCh {
|
||||
if next != uint64(result.Block) {
|
||||
t.Error("Unexpected tracing block")
|
||||
if have, want := uint64(result.Block), next; have != want {
|
||||
t.Fatalf("unexpected tracing block, have %d want %d", have, want)
|
||||
}
|
||||
if len(result.Traces) != int(next) {
|
||||
t.Error("Unexpected tracing result")
|
||||
if have, want := len(result.Traces), int(next); have != want {
|
||||
t.Fatalf("unexpected result length, have %d want %d", have, want)
|
||||
}
|
||||
for _, trace := range result.Traces {
|
||||
trace.TxHash = common.Hash{}
|
||||
blob, _ := json.Marshal(trace)
|
||||
if string(blob) != single {
|
||||
t.Error("Unexpected tracing result")
|
||||
if have, want := string(blob), single; have != want {
|
||||
t.Fatalf("unexpected tracing result, have\n%v\nwant:\n%v", have, want)
|
||||
}
|
||||
}
|
||||
next += 1
|
||||
|
||||
@@ -121,7 +121,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
||||
}
|
||||
// Configure a blockchain with the given prestate
|
||||
var (
|
||||
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
||||
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
|
||||
origin, _ = signer.Sender(tx)
|
||||
txContext = vm.TxContext{
|
||||
Origin: origin,
|
||||
@@ -218,7 +218,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
||||
if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil {
|
||||
b.Fatalf("failed to parse testcase input: %v", err)
|
||||
}
|
||||
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
||||
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
|
||||
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||
if err != nil {
|
||||
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
|
||||
@@ -85,7 +85,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
||||
if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil {
|
||||
return fmt.Errorf("failed to parse testcase input: %v", err)
|
||||
}
|
||||
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
||||
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
|
||||
origin, _ := signer.Sender(tx)
|
||||
txContext := vm.TxContext{
|
||||
Origin: origin,
|
||||
|
||||
@@ -92,7 +92,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
||||
}
|
||||
// Configure a blockchain with the given prestate
|
||||
var (
|
||||
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
||||
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
|
||||
origin, _ = signer.Sender(tx)
|
||||
txContext = vm.TxContext{
|
||||
Origin: origin,
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"context": {
|
||||
"difficulty": "3502894804",
|
||||
"gasLimit": "4722976",
|
||||
"miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724",
|
||||
"number": "2289806",
|
||||
"timestamp": "1513601314"
|
||||
},
|
||||
"genesis": {
|
||||
"alloc": {
|
||||
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
|
||||
"balance": "0x0",
|
||||
"code": "0x",
|
||||
"nonce": "22",
|
||||
"storage": {}
|
||||
},
|
||||
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
|
||||
"balance": "0x4d87094125a369d9bd5",
|
||||
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
|
||||
"nonce": "1",
|
||||
"storage": {
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
|
||||
}
|
||||
},
|
||||
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
|
||||
"balance": "0x1780d77678137ac1b775",
|
||||
"code": "0x",
|
||||
"nonce": "29072",
|
||||
"storage": {}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"byzantiumBlock": 1700000,
|
||||
"chainId": 3,
|
||||
"daoForkSupport": true,
|
||||
"eip150Block": 0,
|
||||
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
|
||||
"eip155Block": 10,
|
||||
"eip158Block": 10,
|
||||
"ethash": {},
|
||||
"homesteadBlock": 0
|
||||
},
|
||||
"difficulty": "3509749784",
|
||||
"extraData": "0x4554482e45544846414e532e4f52472d4641313738394444",
|
||||
"gasLimit": "4727564",
|
||||
"hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440",
|
||||
"miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3",
|
||||
"mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada",
|
||||
"nonce": "0x4eb12e19c16d43da",
|
||||
"number": "2289805",
|
||||
"stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f",
|
||||
"timestamp": "1513601261",
|
||||
"totalDifficulty": "7143276353481064"
|
||||
},
|
||||
"input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4",
|
||||
"tracerConfig": {
|
||||
"onlyTopCall": true
|
||||
},
|
||||
"result": [
|
||||
{
|
||||
"action": {
|
||||
"callType": "call",
|
||||
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
|
||||
"gas": "0x15f90",
|
||||
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
|
||||
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
|
||||
"value": "0x0"
|
||||
},
|
||||
"blockNumber": 2289806,
|
||||
"result": {
|
||||
"gasUsed": "0x9751",
|
||||
"output": "0x0000000000000000000000000000000000000000000000000000000000000001"
|
||||
},
|
||||
"subtraces": 1,
|
||||
"traceAddress": [],
|
||||
"type": "call"
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"callType": "call",
|
||||
"from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
|
||||
"gas": "0x6d05",
|
||||
"input": "0x",
|
||||
"to": "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
|
||||
"value": "0x6f05b59d3b20000"
|
||||
},
|
||||
"blockNumber": 0,
|
||||
"result": {
|
||||
"gasUsed": "0x0",
|
||||
"output": "0x"
|
||||
},
|
||||
"subtraces": 0,
|
||||
"traceAddress": [0],
|
||||
"type": "call"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b
|
||||
b := obj.Get("buffer").Export().(goja.ArrayBuffer).Bytes()
|
||||
return b, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid buffer type")
|
||||
return nil, errors.New("invalid buffer type")
|
||||
}
|
||||
|
||||
// jsTracer is an implementation of the Tracer interface which evaluates
|
||||
|
||||
@@ -18,7 +18,7 @@ package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"errors"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
@@ -85,7 +85,7 @@ func TestStructLogMarshalingOmitEmpty(t *testing.T) {
|
||||
}{
|
||||
{"empty err and no fields", &StructLog{},
|
||||
`{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memSize":0,"stack":null,"depth":0,"refund":0,"opName":"STOP"}`},
|
||||
{"with err", &StructLog{Err: fmt.Errorf("this failed")},
|
||||
{"with err", &StructLog{Err: errors.New("this failed")},
|
||||
`{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memSize":0,"stack":null,"depth":0,"refund":0,"opName":"STOP","error":"this failed"}`},
|
||||
{"with mem", &StructLog{Memory: make([]byte, 2), MemorySize: 2},
|
||||
`{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memory":"0x0000","memSize":2,"stack":null,"depth":0,"refund":0,"opName":"STOP"}`},
|
||||
|
||||
@@ -129,7 +129,9 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace
|
||||
}
|
||||
}
|
||||
|
||||
tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, cfg)
|
||||
// Create inner call tracer with default configuration, don't forward
|
||||
// the OnlyTopCall or WithLog to inner for now
|
||||
tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package tracers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
@@ -105,7 +106,7 @@ const (
|
||||
// It zero-pads the slice if it extends beyond memory bounds.
|
||||
func GetMemoryCopyPadded(m *vm.Memory, offset, size int64) ([]byte, error) {
|
||||
if offset < 0 || size < 0 {
|
||||
return nil, fmt.Errorf("offset or size must not be negative")
|
||||
return nil, errors.New("offset or size must not be negative")
|
||||
}
|
||||
if int(offset+size) < m.Len() { // slice fully inside memory
|
||||
return m.GetCopy(offset, size), nil
|
||||
|
||||
Reference in New Issue
Block a user