forked from cerc-io/ipld-eth-server
VDB-327 Constantinople prep (#135)
* Bump geth to 1.8.20 for Constantinople * Fix conflicting import/toml source for logrus
This commit is contained in:
+3
-3
@@ -444,16 +444,16 @@ func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Bloc
|
||||
if startBlock.Number().Uint64() >= endBlock.Number().Uint64() {
|
||||
return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64())
|
||||
}
|
||||
triedb := api.eth.BlockChain().StateCache().TrieDB()
|
||||
|
||||
oldTrie, err := trie.NewSecure(startBlock.Root(), trie.NewDatabase(api.eth.chainDb), 0)
|
||||
oldTrie, err := trie.NewSecure(startBlock.Root(), triedb, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newTrie, err := trie.NewSecure(endBlock.Root(), trie.NewDatabase(api.eth.chainDb), 0)
|
||||
newTrie, err := trie.NewSecure(endBlock.Root(), triedb, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
|
||||
iter := trie.NewIterator(diff)
|
||||
|
||||
|
||||
+2
-2
@@ -125,12 +125,12 @@ func (b *EthAPIBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||
return b.eth.blockchain.GetTdByHash(blockHash)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
|
||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) {
|
||||
state.SetBalance(msg.From(), math.MaxBig256)
|
||||
vmError := func() error { return nil }
|
||||
|
||||
context := core.NewEVMContext(msg, header, b.eth.BlockChain(), nil)
|
||||
return vm.NewEVM(context, state, b.eth.chainConfig, vmCfg), vmError, nil
|
||||
return vm.NewEVM(context, state, b.eth.chainConfig, *b.eth.blockchain.GetVMConfig()), vmError, nil
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
|
||||
|
||||
+157
-20
@@ -17,11 +17,13 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -60,6 +62,13 @@ type TraceConfig struct {
|
||||
Reexec *uint64
|
||||
}
|
||||
|
||||
// StdTraceConfig holds extra parameters to standard-json trace functions.
|
||||
type StdTraceConfig struct {
|
||||
*vm.LogConfig
|
||||
Reexec *uint64
|
||||
TxHash common.Hash
|
||||
}
|
||||
|
||||
// txTraceResult is the result of a single transaction trace.
|
||||
type txTraceResult struct {
|
||||
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
|
||||
@@ -138,7 +147,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
|
||||
|
||||
// Ensure we have a valid starting state before doing any work
|
||||
origin := start.NumberU64()
|
||||
database := state.NewDatabase(api.eth.ChainDb())
|
||||
database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16) // Chain tracing will probably start at genesis
|
||||
|
||||
if number := start.NumberU64(); number > 0 {
|
||||
start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1)
|
||||
@@ -366,7 +375,7 @@ func (api *PrivateDebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.B
|
||||
func (api *PrivateDebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
block := api.eth.blockchain.GetBlockByHash(hash)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("block #%x not found", hash)
|
||||
return nil, fmt.Errorf("block %#x not found", hash)
|
||||
}
|
||||
return api.traceBlock(ctx, block, config)
|
||||
}
|
||||
@@ -391,13 +400,41 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string,
|
||||
return api.TraceBlock(ctx, blob, config)
|
||||
}
|
||||
|
||||
// TraceBadBlock returns the structured logs created during the execution of a block
|
||||
// within the blockchain 'badblocks' cache
|
||||
func (api *PrivateDebugAPI) TraceBadBlock(ctx context.Context, index int, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
if blocks := api.eth.blockchain.BadBlocks(); index < len(blocks) {
|
||||
return api.traceBlock(ctx, blocks[index], config)
|
||||
// TraceBadBlockByHash returns the structured logs created during the execution of
|
||||
// EVM against a block pulled from the pool of bad ones and returns them as a JSON
|
||||
// object.
|
||||
func (api *PrivateDebugAPI) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
blocks := api.eth.blockchain.BadBlocks()
|
||||
for _, block := range blocks {
|
||||
if block.Hash() == hash {
|
||||
return api.traceBlock(ctx, block, config)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("index out of range")
|
||||
return nil, fmt.Errorf("bad block %#x not found", hash)
|
||||
}
|
||||
|
||||
// StandardTraceBlockToFile dumps the structured logs created during the
|
||||
// execution of EVM to the local file system and returns a list of files
|
||||
// to the caller.
|
||||
func (api *PrivateDebugAPI) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
|
||||
block := api.eth.blockchain.GetBlockByHash(hash)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("block %#x not found", hash)
|
||||
}
|
||||
return api.standardTraceBlockToFile(ctx, block, config)
|
||||
}
|
||||
|
||||
// StandardTraceBadBlockToFile dumps the structured logs created during the
|
||||
// execution of EVM against a block pulled from the pool of bad ones to the
|
||||
// local file system and returns a list of files to the caller.
|
||||
func (api *PrivateDebugAPI) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) {
|
||||
blocks := api.eth.blockchain.BadBlocks()
|
||||
for _, block := range blocks {
|
||||
if block.Hash() == hash {
|
||||
return api.standardTraceBlockToFile(ctx, block, config)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("bad block %#x not found", hash)
|
||||
}
|
||||
|
||||
// traceBlock configures a new tracer according to the provided configuration, and
|
||||
@@ -410,7 +447,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
|
||||
}
|
||||
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return nil, fmt.Errorf("parent %x not found", block.ParentHash())
|
||||
return nil, fmt.Errorf("parent %#x not found", block.ParentHash())
|
||||
}
|
||||
reexec := defaultTraceReexec
|
||||
if config != nil && config.Reexec != nil {
|
||||
@@ -481,6 +518,106 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// standardTraceBlockToFile configures a new tracer which uses standard JSON output,
|
||||
// and traces either a full block or an individual transaction. The return value will
|
||||
// be one filename per transaction traced.
|
||||
func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) {
|
||||
// If we're tracing a single transaction, make sure it's present
|
||||
if config != nil && config.TxHash != (common.Hash{}) {
|
||||
var exists bool
|
||||
for _, tx := range block.Transactions() {
|
||||
if exists = (tx.Hash() == config.TxHash); exists {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash)
|
||||
}
|
||||
}
|
||||
// Create the parent state database
|
||||
if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return nil, fmt.Errorf("parent %#x not found", block.ParentHash())
|
||||
}
|
||||
reexec := defaultTraceReexec
|
||||
if config != nil && config.Reexec != nil {
|
||||
reexec = *config.Reexec
|
||||
}
|
||||
statedb, err := api.computeStateDB(parent, reexec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Retrieve the tracing configurations, or use default values
|
||||
var (
|
||||
logConfig vm.LogConfig
|
||||
txHash common.Hash
|
||||
)
|
||||
if config != nil {
|
||||
if config.LogConfig != nil {
|
||||
logConfig = *config.LogConfig
|
||||
}
|
||||
txHash = config.TxHash
|
||||
}
|
||||
logConfig.Debug = true
|
||||
|
||||
// Execute transaction, either tracing all or just the requested one
|
||||
var (
|
||||
signer = types.MakeSigner(api.config, block.Number())
|
||||
dumps []string
|
||||
)
|
||||
for i, tx := range block.Transactions() {
|
||||
// Prepare the trasaction for un-traced execution
|
||||
var (
|
||||
msg, _ = tx.AsMessage(signer)
|
||||
vmctx = core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
|
||||
|
||||
vmConf vm.Config
|
||||
dump *os.File
|
||||
err error
|
||||
)
|
||||
// If the transaction needs tracing, swap out the configs
|
||||
if tx.Hash() == txHash || txHash == (common.Hash{}) {
|
||||
// Generate a unique temporary file to dump it into
|
||||
prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4])
|
||||
|
||||
dump, err = ioutil.TempFile(os.TempDir(), prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dumps = append(dumps, dump.Name())
|
||||
|
||||
// Swap out the noop logger to the standard tracer
|
||||
vmConf = vm.Config{
|
||||
Debug: true,
|
||||
Tracer: vm.NewJSONLogger(&logConfig, bufio.NewWriter(dump)),
|
||||
EnablePreimageRecording: true,
|
||||
}
|
||||
}
|
||||
// Execute the transaction and flush any traces to disk
|
||||
vmenv := vm.NewEVM(vmctx, statedb, api.config, vmConf)
|
||||
_, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
||||
|
||||
if dump != nil {
|
||||
dump.Close()
|
||||
log.Info("Wrote standard trace", "file", dump.Name())
|
||||
}
|
||||
if err != nil {
|
||||
return dumps, err
|
||||
}
|
||||
// Finalize the state so any modifications are written to the trie
|
||||
statedb.Finalise(true)
|
||||
|
||||
// If we've traced the transaction we were looking for, abort
|
||||
if tx.Hash() == txHash {
|
||||
break
|
||||
}
|
||||
}
|
||||
return dumps, nil
|
||||
}
|
||||
|
||||
// computeStateDB retrieves the state database associated with a certain block.
|
||||
// If no state is locally available for the given block, a number of blocks are
|
||||
// attempted to be reexecuted to generate the desired state.
|
||||
@@ -492,7 +629,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
|
||||
}
|
||||
// Otherwise try to reexec blocks until we find a state or reach our limit
|
||||
origin := block.NumberU64()
|
||||
database := state.NewDatabase(api.eth.ChainDb())
|
||||
database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16)
|
||||
|
||||
for i := uint64(0); i < reexec; i++ {
|
||||
block = api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
@@ -506,7 +643,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *trie.MissingNodeError:
|
||||
return nil, errors.New("required historical state unavailable")
|
||||
return nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec)
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
@@ -520,7 +657,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
|
||||
for block.NumberU64() < origin {
|
||||
// Print progress logs if long enough time elapsed
|
||||
if time.Since(logged) > 8*time.Second {
|
||||
log.Info("Regenerating historical state", "block", block.NumberU64()+1, "target", origin, "elapsed", time.Since(start))
|
||||
log.Info("Regenerating historical state", "block", block.NumberU64()+1, "target", origin, "remaining", origin-block.NumberU64()-1, "elapsed", time.Since(start))
|
||||
logged = time.Now()
|
||||
}
|
||||
// Retrieve the next block to regenerate and process it
|
||||
@@ -529,15 +666,15 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
|
||||
}
|
||||
_, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, vm.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("processing block %d failed: %v", block.NumberU64(), err)
|
||||
}
|
||||
// Finalize the state so any modifications are written to the trie
|
||||
root, err := statedb.Commit(true)
|
||||
root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := statedb.Reset(root); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("state reset after block %d failed: %v", block.NumberU64(), err)
|
||||
}
|
||||
database.TrieDB().Reference(root, common.Hash{})
|
||||
if proot != (common.Hash{}) {
|
||||
@@ -556,7 +693,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
|
||||
// Retrieve the transaction and assemble its EVM context
|
||||
tx, blockHash, _, index := rawdb.ReadTransaction(api.eth.ChainDb(), hash)
|
||||
if tx == nil {
|
||||
return nil, fmt.Errorf("transaction %x not found", hash)
|
||||
return nil, fmt.Errorf("transaction %#x not found", hash)
|
||||
}
|
||||
reexec := defaultTraceReexec
|
||||
if config != nil && config.Reexec != nil {
|
||||
@@ -636,11 +773,11 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
|
||||
// Create the parent state database
|
||||
block := api.eth.blockchain.GetBlockByHash(blockHash)
|
||||
if block == nil {
|
||||
return nil, vm.Context{}, nil, fmt.Errorf("block %x not found", blockHash)
|
||||
return nil, vm.Context{}, nil, fmt.Errorf("block %#x not found", blockHash)
|
||||
}
|
||||
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return nil, vm.Context{}, nil, fmt.Errorf("parent %x not found", block.ParentHash())
|
||||
return nil, vm.Context{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash())
|
||||
}
|
||||
statedb, err := api.computeStateDB(parent, reexec)
|
||||
if err != nil {
|
||||
@@ -659,10 +796,10 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
|
||||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{})
|
||||
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
||||
return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
|
||||
return nil, vm.Context{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||
}
|
||||
// Ensure any modifications are committed to the state
|
||||
statedb.Finalise(true)
|
||||
}
|
||||
return nil, vm.Context{}, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash)
|
||||
return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, blockHash)
|
||||
}
|
||||
|
||||
+3
-3
@@ -118,7 +118,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
|
||||
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.ConstantinopleOverride)
|
||||
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
|
||||
return nil, genesisErr
|
||||
}
|
||||
@@ -154,7 +154,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||
EWASMInterpreter: config.EWASMInterpreter,
|
||||
EVMInterpreter: config.EVMInterpreter,
|
||||
}
|
||||
cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout}
|
||||
cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieCleanLimit: config.TrieCleanCache, TrieDirtyLimit: config.TrieDirtyCache, TrieTimeLimit: config.TrieTimeout}
|
||||
)
|
||||
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.shouldPreserve)
|
||||
if err != nil {
|
||||
@@ -173,7 +173,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||
}
|
||||
eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain)
|
||||
|
||||
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil {
|
||||
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, config.Whitelist); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
+19
-10
@@ -43,15 +43,16 @@ var DefaultConfig = Config{
|
||||
DatasetsInMem: 1,
|
||||
DatasetsOnDisk: 2,
|
||||
},
|
||||
NetworkId: 1,
|
||||
LightPeers: 100,
|
||||
DatabaseCache: 768,
|
||||
TrieCache: 256,
|
||||
TrieTimeout: 60 * time.Minute,
|
||||
MinerGasFloor: 8000000,
|
||||
MinerGasCeil: 8000000,
|
||||
MinerGasPrice: big.NewInt(params.GWei),
|
||||
MinerRecommit: 3 * time.Second,
|
||||
NetworkId: 1,
|
||||
LightPeers: 100,
|
||||
DatabaseCache: 512,
|
||||
TrieCleanCache: 256,
|
||||
TrieDirtyCache: 256,
|
||||
TrieTimeout: 60 * time.Minute,
|
||||
MinerGasFloor: 8000000,
|
||||
MinerGasCeil: 8000000,
|
||||
MinerGasPrice: big.NewInt(params.GWei),
|
||||
MinerRecommit: 3 * time.Second,
|
||||
|
||||
TxPool: core.DefaultTxPoolConfig,
|
||||
GPO: gasprice.Config{
|
||||
@@ -86,6 +87,9 @@ type Config struct {
|
||||
SyncMode downloader.SyncMode
|
||||
NoPruning bool
|
||||
|
||||
// Whitelist of required block number -> hash values to accept
|
||||
Whitelist map[uint64]common.Hash `toml:"-"`
|
||||
|
||||
// Light client options
|
||||
LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests
|
||||
LightPeers int `toml:",omitempty"` // Maximum number of LES client peers
|
||||
@@ -94,7 +98,8 @@ type Config struct {
|
||||
SkipBcVersionCheck bool `toml:"-"`
|
||||
DatabaseHandles int `toml:"-"`
|
||||
DatabaseCache int
|
||||
TrieCache int
|
||||
TrieCleanCache int
|
||||
TrieDirtyCache int
|
||||
TrieTimeout time.Duration
|
||||
|
||||
// Mining-related options
|
||||
@@ -124,8 +129,12 @@ type Config struct {
|
||||
|
||||
// Type of the EWASM interpreter ("" for default)
|
||||
EWASMInterpreter string
|
||||
|
||||
// Type of the EVM interpreter ("" for default)
|
||||
EVMInterpreter string
|
||||
|
||||
// Constantinople block override (TODO: remove after the fork)
|
||||
ConstantinopleOverride *big.Int
|
||||
}
|
||||
|
||||
type configMarshaling struct {
|
||||
|
||||
+127
-40
@@ -99,6 +99,7 @@ type Downloader struct {
|
||||
mode SyncMode // Synchronisation mode defining the strategy used (per sync cycle)
|
||||
mux *event.TypeMux // Event multiplexer to announce sync operation events
|
||||
|
||||
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
|
||||
@@ -181,6 +182,9 @@ type BlockChain interface {
|
||||
// HasBlock verifies a block's presence in the local chain.
|
||||
HasBlock(common.Hash, uint64) bool
|
||||
|
||||
// HasFastBlock verifies a fast block's presence in the local chain.
|
||||
HasFastBlock(common.Hash, uint64) bool
|
||||
|
||||
// GetBlockByHash retrieves a block from the local chain.
|
||||
GetBlockByHash(common.Hash) *types.Block
|
||||
|
||||
@@ -430,7 +434,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I
|
||||
}
|
||||
height := latest.Number.Uint64()
|
||||
|
||||
origin, err := d.findAncestor(p, height)
|
||||
origin, err := d.findAncestor(p, latest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -587,41 +591,107 @@ func (d *Downloader) fetchHeight(p *peerConnection) (*types.Header, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// calculateRequestSpan calculates what headers to request from a peer when trying to determine the
|
||||
// common ancestor.
|
||||
// It returns parameters to be used for peer.RequestHeadersByNumber:
|
||||
// from - starting block number
|
||||
// count - number of headers to request
|
||||
// skip - number of headers to skip
|
||||
// and also returns 'max', the last block which is expected to be returned by the remote peers,
|
||||
// given the (from,count,skip)
|
||||
func calculateRequestSpan(remoteHeight, localHeight uint64) (int64, int, int, uint64) {
|
||||
var (
|
||||
from int
|
||||
count int
|
||||
MaxCount = MaxHeaderFetch / 16
|
||||
)
|
||||
// requestHead is the highest block that we will ask for. If requestHead is not offset,
|
||||
// the highest block that we will get is 16 blocks back from head, which means we
|
||||
// will fetch 14 or 15 blocks unnecessarily in the case the height difference
|
||||
// between us and the peer is 1-2 blocks, which is most common
|
||||
requestHead := int(remoteHeight) - 1
|
||||
if requestHead < 0 {
|
||||
requestHead = 0
|
||||
}
|
||||
// requestBottom is the lowest block we want included in the query
|
||||
// Ideally, we want to include just below own head
|
||||
requestBottom := int(localHeight - 1)
|
||||
if requestBottom < 0 {
|
||||
requestBottom = 0
|
||||
}
|
||||
totalSpan := requestHead - requestBottom
|
||||
span := 1 + totalSpan/MaxCount
|
||||
if span < 2 {
|
||||
span = 2
|
||||
}
|
||||
if span > 16 {
|
||||
span = 16
|
||||
}
|
||||
|
||||
count = 1 + totalSpan/span
|
||||
if count > MaxCount {
|
||||
count = MaxCount
|
||||
}
|
||||
if count < 2 {
|
||||
count = 2
|
||||
}
|
||||
from = requestHead - (count-1)*span
|
||||
if from < 0 {
|
||||
from = 0
|
||||
}
|
||||
max := from + (count-1)*span
|
||||
return int64(from), count, span - 1, uint64(max)
|
||||
}
|
||||
|
||||
// findAncestor tries to locate the common ancestor link of the local chain and
|
||||
// a remote peers blockchain. In the general case when our node was in sync and
|
||||
// on the correct chain, checking the top N links should already get us a match.
|
||||
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
|
||||
// the head links match), we do a binary search to find the common ancestor.
|
||||
func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, error) {
|
||||
func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) {
|
||||
// Figure out the valid ancestor range to prevent rewrite attacks
|
||||
floor, ceil := int64(-1), d.lightchain.CurrentHeader().Number.Uint64()
|
||||
var (
|
||||
floor = int64(-1)
|
||||
localHeight uint64
|
||||
remoteHeight = remoteHeader.Number.Uint64()
|
||||
)
|
||||
switch d.mode {
|
||||
case FullSync:
|
||||
localHeight = d.blockchain.CurrentBlock().NumberU64()
|
||||
case FastSync:
|
||||
localHeight = d.blockchain.CurrentFastBlock().NumberU64()
|
||||
default:
|
||||
localHeight = d.lightchain.CurrentHeader().Number.Uint64()
|
||||
}
|
||||
p.log.Debug("Looking for common ancestor", "local", localHeight, "remote", remoteHeight)
|
||||
if localHeight >= MaxForkAncestry {
|
||||
// We're above the max reorg threshold, find the earliest fork point
|
||||
floor = int64(localHeight - MaxForkAncestry)
|
||||
|
||||
if d.mode == FullSync {
|
||||
ceil = d.blockchain.CurrentBlock().NumberU64()
|
||||
} else if d.mode == FastSync {
|
||||
ceil = d.blockchain.CurrentFastBlock().NumberU64()
|
||||
// If we're doing a light sync, ensure the floor doesn't go below the CHT, as
|
||||
// all headers before that point will be missing.
|
||||
if d.mode == LightSync {
|
||||
// If we dont know the current CHT position, find it
|
||||
if d.genesis == 0 {
|
||||
header := d.lightchain.CurrentHeader()
|
||||
for header != nil {
|
||||
d.genesis = header.Number.Uint64()
|
||||
if floor >= int64(d.genesis)-1 {
|
||||
break
|
||||
}
|
||||
header = d.lightchain.GetHeaderByHash(header.ParentHash)
|
||||
}
|
||||
}
|
||||
// We already know the "genesis" block number, cap floor to that
|
||||
if floor < int64(d.genesis)-1 {
|
||||
floor = int64(d.genesis) - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if ceil >= MaxForkAncestry {
|
||||
floor = int64(ceil - MaxForkAncestry)
|
||||
}
|
||||
p.log.Debug("Looking for common ancestor", "local", ceil, "remote", height)
|
||||
from, count, skip, max := calculateRequestSpan(remoteHeight, localHeight)
|
||||
|
||||
// Request the topmost blocks to short circuit binary ancestor lookup
|
||||
head := ceil
|
||||
if head > height {
|
||||
head = height
|
||||
}
|
||||
from := int64(head) - int64(MaxHeaderFetch)
|
||||
if from < 0 {
|
||||
from = 0
|
||||
}
|
||||
// Span out with 15 block gaps into the future to catch bad head reports
|
||||
limit := 2 * MaxHeaderFetch / 16
|
||||
count := 1 + int((int64(ceil)-from)/16)
|
||||
if count > limit {
|
||||
count = limit
|
||||
}
|
||||
go p.peer.RequestHeadersByNumber(uint64(from), count, 15, false)
|
||||
p.log.Trace("Span searching for common ancestor", "count", count, "from", from, "skip", skip)
|
||||
go p.peer.RequestHeadersByNumber(uint64(from), count, skip, false)
|
||||
|
||||
// Wait for the remote response to the head fetch
|
||||
number, hash := uint64(0), common.Hash{}
|
||||
@@ -647,9 +717,10 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
|
||||
return 0, errEmptyHeaderSet
|
||||
}
|
||||
// Make sure the peer's reply conforms to the request
|
||||
for i := 0; i < len(headers); i++ {
|
||||
if number := headers[i].Number.Int64(); number != from+int64(i)*16 {
|
||||
p.log.Warn("Head headers broke chain ordering", "index", i, "requested", from+int64(i)*16, "received", number)
|
||||
for i, header := range headers {
|
||||
expectNumber := from + int64(i)*int64((skip+1))
|
||||
if number := header.Number.Int64(); number != expectNumber {
|
||||
p.log.Warn("Head headers broke chain ordering", "index", i, "requested", expectNumber, "received", number)
|
||||
return 0, errInvalidChain
|
||||
}
|
||||
}
|
||||
@@ -657,20 +728,24 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
|
||||
finished = true
|
||||
for i := len(headers) - 1; i >= 0; i-- {
|
||||
// Skip any headers that underflow/overflow our requested set
|
||||
if headers[i].Number.Int64() < from || headers[i].Number.Uint64() > ceil {
|
||||
if headers[i].Number.Int64() < from || headers[i].Number.Uint64() > max {
|
||||
continue
|
||||
}
|
||||
// Otherwise check if we already know the header or not
|
||||
h := headers[i].Hash()
|
||||
n := headers[i].Number.Uint64()
|
||||
if (d.mode == FullSync && d.blockchain.HasBlock(h, n)) || (d.mode != FullSync && d.lightchain.HasHeader(h, n)) {
|
||||
number, hash = n, h
|
||||
|
||||
// If every header is known, even future ones, the peer straight out lied about its head
|
||||
if number > height && i == limit-1 {
|
||||
p.log.Warn("Lied about chain head", "reported", height, "found", number)
|
||||
return 0, errStallingPeer
|
||||
}
|
||||
var known bool
|
||||
switch d.mode {
|
||||
case FullSync:
|
||||
known = d.blockchain.HasBlock(h, n)
|
||||
case FastSync:
|
||||
known = d.blockchain.HasFastBlock(h, n)
|
||||
default:
|
||||
known = d.lightchain.HasHeader(h, n)
|
||||
}
|
||||
if known {
|
||||
number, hash = n, h
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -694,10 +769,12 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
|
||||
return number, nil
|
||||
}
|
||||
// Ancestor not found, we need to binary search over our chain
|
||||
start, end := uint64(0), head
|
||||
start, end := uint64(0), remoteHeight
|
||||
if floor > 0 {
|
||||
start = uint64(floor)
|
||||
}
|
||||
p.log.Trace("Binary searching for common ancestor", "start", start, "end", end)
|
||||
|
||||
for start+1 < end {
|
||||
// Split our chain interval in two, and request the hash to cross check
|
||||
check := (start + end) / 2
|
||||
@@ -730,7 +807,17 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
|
||||
// Modify the search interval based on the response
|
||||
h := headers[0].Hash()
|
||||
n := headers[0].Number.Uint64()
|
||||
if (d.mode == FullSync && !d.blockchain.HasBlock(h, n)) || (d.mode != FullSync && !d.lightchain.HasHeader(h, n)) {
|
||||
|
||||
var known bool
|
||||
switch d.mode {
|
||||
case FullSync:
|
||||
known = d.blockchain.HasBlock(h, n)
|
||||
case FastSync:
|
||||
known = d.blockchain.HasFastBlock(h, n)
|
||||
default:
|
||||
known = d.lightchain.HasHeader(h, n)
|
||||
}
|
||||
if !known {
|
||||
end = check
|
||||
break
|
||||
}
|
||||
|
||||
+97
-9
@@ -20,6 +20,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@@ -114,6 +115,15 @@ func (dl *downloadTester) HasBlock(hash common.Hash, number uint64) bool {
|
||||
return dl.GetBlockByHash(hash) != nil
|
||||
}
|
||||
|
||||
// HasFastBlock checks if a block is present in the testers canonical chain.
|
||||
func (dl *downloadTester) HasFastBlock(hash common.Hash, number uint64) bool {
|
||||
dl.lock.RLock()
|
||||
defer dl.lock.RUnlock()
|
||||
|
||||
_, ok := dl.ownReceipts[hash]
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetHeader retrieves a header from the testers canonical chain.
|
||||
func (dl *downloadTester) GetHeaderByHash(hash common.Hash) *types.Header {
|
||||
dl.lock.RLock()
|
||||
@@ -234,6 +244,7 @@ func (dl *downloadTester) InsertChain(blocks types.Blocks) (i int, err error) {
|
||||
dl.ownHeaders[block.Hash()] = block.Header()
|
||||
}
|
||||
dl.ownBlocks[block.Hash()] = block
|
||||
dl.ownReceipts[block.Hash()] = make(types.Receipts, 0)
|
||||
dl.stateDb.Put(block.Root().Bytes(), []byte{0x00})
|
||||
dl.ownChainTd[block.Hash()] = new(big.Int).Add(dl.ownChainTd[block.ParentHash()], block.Difficulty())
|
||||
}
|
||||
@@ -374,28 +385,28 @@ func (dlp *downloadTesterPeer) RequestNodeData(hashes []common.Hash) error {
|
||||
// assertOwnChain checks if the local chain contains the correct number of items
|
||||
// of the various chain components.
|
||||
func assertOwnChain(t *testing.T, tester *downloadTester, length int) {
|
||||
// Mark this method as a helper to report errors at callsite, not in here
|
||||
t.Helper()
|
||||
|
||||
assertOwnForkedChain(t, tester, 1, []int{length})
|
||||
}
|
||||
|
||||
// assertOwnForkedChain checks if the local forked chain contains the correct
|
||||
// number of items of the various chain components.
|
||||
func assertOwnForkedChain(t *testing.T, tester *downloadTester, common int, lengths []int) {
|
||||
// Mark this method as a helper to report errors at callsite, not in here
|
||||
t.Helper()
|
||||
|
||||
// Initialize the counters for the first fork
|
||||
headers, blocks, receipts := lengths[0], lengths[0], lengths[0]-fsMinFullBlocks
|
||||
headers, blocks, receipts := lengths[0], lengths[0], lengths[0]
|
||||
|
||||
if receipts < 0 {
|
||||
receipts = 1
|
||||
}
|
||||
// Update the counters for each subsequent fork
|
||||
for _, length := range lengths[1:] {
|
||||
headers += length - common
|
||||
blocks += length - common
|
||||
receipts += length - common - fsMinFullBlocks
|
||||
receipts += length - common
|
||||
}
|
||||
switch tester.downloader.mode {
|
||||
case FullSync:
|
||||
receipts = 1
|
||||
case LightSync:
|
||||
if tester.downloader.mode == LightSync {
|
||||
blocks, receipts = 1, 1
|
||||
}
|
||||
if hs := len(tester.ownHeaders); hs != headers {
|
||||
@@ -1149,7 +1160,9 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) {
|
||||
}
|
||||
|
||||
func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.SyncProgress) {
|
||||
// Mark this method as a helper to report errors at callsite, not in here
|
||||
t.Helper()
|
||||
|
||||
p := d.Progress()
|
||||
p.KnownStates, p.PulledStates = 0, 0
|
||||
want.KnownStates, want.PulledStates = 0, 0
|
||||
@@ -1479,3 +1492,78 @@ func (ftp *floodingTestPeer) RequestHeadersByNumber(from uint64, count, skip int
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRemoteHeaderRequestSpan(t *testing.T) {
|
||||
testCases := []struct {
|
||||
remoteHeight uint64
|
||||
localHeight uint64
|
||||
expected []int
|
||||
}{
|
||||
// Remote is way higher. We should ask for the remote head and go backwards
|
||||
{1500, 1000,
|
||||
[]int{1323, 1339, 1355, 1371, 1387, 1403, 1419, 1435, 1451, 1467, 1483, 1499},
|
||||
},
|
||||
{15000, 13006,
|
||||
[]int{14823, 14839, 14855, 14871, 14887, 14903, 14919, 14935, 14951, 14967, 14983, 14999},
|
||||
},
|
||||
//Remote is pretty close to us. We don't have to fetch as many
|
||||
{1200, 1150,
|
||||
[]int{1149, 1154, 1159, 1164, 1169, 1174, 1179, 1184, 1189, 1194, 1199},
|
||||
},
|
||||
// Remote is equal to us (so on a fork with higher td)
|
||||
// We should get the closest couple of ancestors
|
||||
{1500, 1500,
|
||||
[]int{1497, 1499},
|
||||
},
|
||||
// We're higher than the remote! Odd
|
||||
{1000, 1500,
|
||||
[]int{997, 999},
|
||||
},
|
||||
// Check some weird edgecases that it behaves somewhat rationally
|
||||
{0, 1500,
|
||||
[]int{0, 2},
|
||||
},
|
||||
{6000000, 0,
|
||||
[]int{5999823, 5999839, 5999855, 5999871, 5999887, 5999903, 5999919, 5999935, 5999951, 5999967, 5999983, 5999999},
|
||||
},
|
||||
{0, 0,
|
||||
[]int{0, 2},
|
||||
},
|
||||
}
|
||||
reqs := func(from, count, span int) []int {
|
||||
var r []int
|
||||
num := from
|
||||
for len(r) < count {
|
||||
r = append(r, num)
|
||||
num += span + 1
|
||||
}
|
||||
return r
|
||||
}
|
||||
for i, tt := range testCases {
|
||||
from, count, span, max := calculateRequestSpan(tt.remoteHeight, tt.localHeight)
|
||||
data := reqs(int(from), count, span)
|
||||
|
||||
if max != uint64(data[len(data)-1]) {
|
||||
t.Errorf("test %d: wrong last value %d != %d", i, data[len(data)-1], max)
|
||||
}
|
||||
failed := false
|
||||
if len(data) != len(tt.expected) {
|
||||
failed = true
|
||||
t.Errorf("test %d: length wrong, expected %d got %d", i, len(tt.expected), len(data))
|
||||
} else {
|
||||
for j, n := range data {
|
||||
if n != tt.expected[j] {
|
||||
failed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if failed {
|
||||
res := strings.Replace(fmt.Sprint(data), " ", ",", -1)
|
||||
exp := strings.Replace(fmt.Sprint(tt.expected), " ", ",", -1)
|
||||
fmt.Printf("got: %v\n", res)
|
||||
fmt.Printf("exp: %v\n", exp)
|
||||
t.Errorf("test %d: wrong values", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -325,7 +325,7 @@ func (q *queue) Schedule(headers []*types.Header, from uint64) []*types.Header {
|
||||
}
|
||||
// Make sure no duplicate requests are executed
|
||||
if _, ok := q.blockTaskPool[hash]; ok {
|
||||
log.Warn("Header already scheduled for block fetch", "number", header.Number, "hash", hash)
|
||||
log.Warn("Header already scheduled for block fetch", "number", header.Number, "hash", hash)
|
||||
continue
|
||||
}
|
||||
if _, ok := q.receiptTaskPool[hash]; ok {
|
||||
|
||||
+23
-5
@@ -28,7 +28,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
SkipBcVersionCheck bool `toml:"-"`
|
||||
DatabaseHandles int `toml:"-"`
|
||||
DatabaseCache int
|
||||
TrieCache int
|
||||
TrieCleanCache int
|
||||
TrieDirtyCache int
|
||||
TrieTimeout time.Duration
|
||||
Etherbase common.Address `toml:",omitempty"`
|
||||
MinerNotify []string `toml:",omitempty"`
|
||||
@@ -43,6 +44,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
GPO gasprice.Config
|
||||
EnablePreimageRecording bool
|
||||
DocRoot string `toml:"-"`
|
||||
EWASMInterpreter string
|
||||
EVMInterpreter string
|
||||
}
|
||||
var enc Config
|
||||
enc.Genesis = c.Genesis
|
||||
@@ -54,7 +57,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
enc.SkipBcVersionCheck = c.SkipBcVersionCheck
|
||||
enc.DatabaseHandles = c.DatabaseHandles
|
||||
enc.DatabaseCache = c.DatabaseCache
|
||||
enc.TrieCache = c.TrieCache
|
||||
enc.TrieCleanCache = c.TrieCleanCache
|
||||
enc.TrieDirtyCache = c.TrieDirtyCache
|
||||
enc.TrieTimeout = c.TrieTimeout
|
||||
enc.Etherbase = c.Etherbase
|
||||
enc.MinerNotify = c.MinerNotify
|
||||
@@ -69,6 +73,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
enc.GPO = c.GPO
|
||||
enc.EnablePreimageRecording = c.EnablePreimageRecording
|
||||
enc.DocRoot = c.DocRoot
|
||||
enc.EWASMInterpreter = c.EWASMInterpreter
|
||||
enc.EVMInterpreter = c.EVMInterpreter
|
||||
return &enc, nil
|
||||
}
|
||||
|
||||
@@ -84,7 +90,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
SkipBcVersionCheck *bool `toml:"-"`
|
||||
DatabaseHandles *int `toml:"-"`
|
||||
DatabaseCache *int
|
||||
TrieCache *int
|
||||
TrieCleanCache *int
|
||||
TrieDirtyCache *int
|
||||
TrieTimeout *time.Duration
|
||||
Etherbase *common.Address `toml:",omitempty"`
|
||||
MinerNotify []string `toml:",omitempty"`
|
||||
@@ -99,6 +106,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
GPO *gasprice.Config
|
||||
EnablePreimageRecording *bool
|
||||
DocRoot *string `toml:"-"`
|
||||
EWASMInterpreter *string
|
||||
EVMInterpreter *string
|
||||
}
|
||||
var dec Config
|
||||
if err := unmarshal(&dec); err != nil {
|
||||
@@ -131,8 +140,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
if dec.DatabaseCache != nil {
|
||||
c.DatabaseCache = *dec.DatabaseCache
|
||||
}
|
||||
if dec.TrieCache != nil {
|
||||
c.TrieCache = *dec.TrieCache
|
||||
if dec.TrieCleanCache != nil {
|
||||
c.TrieCleanCache = *dec.TrieCleanCache
|
||||
}
|
||||
if dec.TrieDirtyCache != nil {
|
||||
c.TrieDirtyCache = *dec.TrieDirtyCache
|
||||
}
|
||||
if dec.TrieTimeout != nil {
|
||||
c.TrieTimeout = *dec.TrieTimeout
|
||||
@@ -176,5 +188,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
if dec.DocRoot != nil {
|
||||
c.DocRoot = *dec.DocRoot
|
||||
}
|
||||
if dec.EWASMInterpreter != nil {
|
||||
c.EWASMInterpreter = *dec.EWASMInterpreter
|
||||
}
|
||||
if dec.EVMInterpreter != nil {
|
||||
c.EVMInterpreter = *dec.EVMInterpreter
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+20
-3
@@ -88,6 +88,8 @@ type ProtocolManager struct {
|
||||
txsSub event.Subscription
|
||||
minedBlockSub *event.TypeMuxSubscription
|
||||
|
||||
whitelist map[uint64]common.Hash
|
||||
|
||||
// channels for fetcher, syncer, txsyncLoop
|
||||
newPeerCh chan *peer
|
||||
txsyncCh chan *txsync
|
||||
@@ -101,7 +103,7 @@ type ProtocolManager struct {
|
||||
|
||||
// NewProtocolManager returns a new Ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
|
||||
// with the Ethereum network.
|
||||
func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
|
||||
func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, whitelist map[uint64]common.Hash) (*ProtocolManager, error) {
|
||||
// Create the protocol manager with the base fields
|
||||
manager := &ProtocolManager{
|
||||
networkID: networkID,
|
||||
@@ -110,6 +112,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
|
||||
blockchain: blockchain,
|
||||
chainconfig: config,
|
||||
peers: newPeerSet(),
|
||||
whitelist: whitelist,
|
||||
newPeerCh: make(chan *peer),
|
||||
noMorePeers: make(chan struct{}),
|
||||
txsyncCh: make(chan *txsync),
|
||||
@@ -307,7 +310,13 @@ func (pm *ProtocolManager) handle(p *peer) error {
|
||||
}
|
||||
}()
|
||||
}
|
||||
// main loop. handle incoming messages.
|
||||
// If we have any explicit whitelist block hashes, request them
|
||||
for number := range pm.whitelist {
|
||||
if err := p.RequestHeadersByNumber(number, 1, 0, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Handle incoming messages until the connection is torn down
|
||||
for {
|
||||
if err := pm.handleMsg(p); err != nil {
|
||||
p.Log().Debug("Ethereum message handling failed", "err", err)
|
||||
@@ -466,6 +475,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||
p.Log().Debug("Verified to be on the same side of the DAO fork")
|
||||
return nil
|
||||
}
|
||||
// Otherwise if it's a whitelisted block, validate against the set
|
||||
if want, ok := pm.whitelist[headers[0].Number.Uint64()]; ok {
|
||||
if hash := headers[0].Hash(); want != hash {
|
||||
p.Log().Info("Whitelist mismatch, dropping peer", "number", headers[0].Number.Uint64(), "hash", hash, "want", want)
|
||||
return errors.New("whitelist block mismatch")
|
||||
}
|
||||
p.Log().Debug("Whitelist block verified", "number", headers[0].Number.Uint64(), "hash", want)
|
||||
}
|
||||
// Irrelevant of the fork checks, send the header to the fetcher just in case
|
||||
headers = pm.fetcher.FilterHeaders(p.id, headers, time.Now())
|
||||
}
|
||||
@@ -658,7 +675,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||
p.SetHead(trueHead, trueTD)
|
||||
|
||||
// Schedule a sync if above ours. Note, this will not fire a sync for a gap of
|
||||
// a singe block (as the true TD is below the propagated block), however this
|
||||
// a single block (as the true TD is below the propagated block), however this
|
||||
// scenario should easily be covered by the fetcher.
|
||||
currentBlock := pm.blockchain.CurrentBlock()
|
||||
if trueTD.Cmp(pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64())) > 0 {
|
||||
|
||||
+4
-4
@@ -478,7 +478,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new blockchain: %v", err)
|
||||
}
|
||||
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db)
|
||||
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to start test protocol manager: %v", err)
|
||||
}
|
||||
@@ -559,7 +559,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new blockchain: %v", err)
|
||||
}
|
||||
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db)
|
||||
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to start test protocol manager: %v", err)
|
||||
}
|
||||
@@ -585,7 +585,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
|
||||
}
|
||||
}(peer)
|
||||
}
|
||||
timeoutCh := time.NewTimer(time.Millisecond * 100).C
|
||||
timeout := time.After(300 * time.Millisecond)
|
||||
var receivedCount int
|
||||
outer:
|
||||
for {
|
||||
@@ -597,7 +597,7 @@ outer:
|
||||
if receivedCount == totalPeers {
|
||||
break outer
|
||||
}
|
||||
case <-timeoutCh:
|
||||
case <-timeout:
|
||||
break outer
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db)
|
||||
pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
+13
-13
File diff suppressed because one or more lines are too long
Generated
Vendored
+1
-4
@@ -40,10 +40,7 @@
|
||||
var idx = toHex(key);
|
||||
|
||||
if (this.prestate[acc].storage[idx] === undefined) {
|
||||
var val = toHex(db.getState(addr, key));
|
||||
if (val != "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
||||
this.prestate[acc].storage[idx] = toHex(db.getState(addr, key));
|
||||
}
|
||||
this.prestate[acc].storage[idx] = toHex(db.getState(addr, key));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user