automated merge

This commit is contained in:
philip-morlier
2023-07-11 16:01:17 -07:00
327 changed files with 15001 additions and 11151 deletions
+4 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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, &ethashConfig, 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
View File
@@ -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)
}
+1 -1
View File
@@ -440,7 +440,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block)
t.Fatal("can't create node:", err)
}
ethcfg := &ethconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
ethcfg := &ethconfig.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)
+21 -40
View File
@@ -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)
+1 -40
View File
@@ -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) }
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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
}
+5 -31
View File
@@ -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
}
+24 -24
View File
@@ -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
View File
@@ -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
}
}
}
+1 -1
View File
@@ -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)
}
+3
View File
@@ -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 {
+2 -1
View File
@@ -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
+3 -1
View File
@@ -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
View File
@@ -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())
+5 -5
View File
@@ -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
}
+6 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) }
+7 -7
View File
@@ -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,
+12 -11
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
@@ -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"
}
]
}
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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"}`},
+3 -1
View File
@@ -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
}
+2 -1
View File
@@ -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