mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 06:06:44 +00:00
core: integrated fork procedure
This commit is contained in:
parent
888b5c706e
commit
064a78507e
7 changed files with 150 additions and 60 deletions
|
|
@ -66,19 +66,23 @@ func NewBlockValidator(config *ChainConfig, blockchain *BlockChain, pow pow.PoW)
|
||||||
// state that might or might not be present is checked to make sure that fast
|
// state that might or might not be present is checked to make sure that fast
|
||||||
// sync has done it's job proper. This prevents the block validator form accepting
|
// sync has done it's job proper. This prevents the block validator form accepting
|
||||||
// false positives where a header is present but the state is not.
|
// false positives where a header is present but the state is not.
|
||||||
func (v *BlockValidator) ValidateBlock(block *types.Block) error {
|
func (v *BlockValidator) ValidateBlock(reader BlockReader, block *types.Block) error {
|
||||||
if v.bc.HasBlock(block.Hash()) {
|
/* wtf?
|
||||||
if _, err := state.New(block.Root(), v.bc.chainDb); err == nil {
|
if reader.GetBlock(block.Hash()) != nil {
|
||||||
|
if _, err := state.New(block.Root(), v.chainDb); err == nil {
|
||||||
return &KnownBlockError{block.Number(), block.Hash()}
|
return &KnownBlockError{block.Number(), block.Hash()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parent := v.bc.GetBlock(block.ParentHash())
|
*/
|
||||||
|
parent := reader.GetBlock(block.ParentHash())
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return ParentError(block.ParentHash())
|
return ParentError(block.ParentHash())
|
||||||
}
|
}
|
||||||
|
/* wtf?
|
||||||
if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil {
|
if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil {
|
||||||
return ParentError(block.ParentHash())
|
return ParentError(block.ParentHash())
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
header := block.Header()
|
header := block.Header()
|
||||||
// validate the block header
|
// validate the block header
|
||||||
|
|
@ -86,7 +90,7 @@ func (v *BlockValidator) ValidateBlock(block *types.Block) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// verify the uncles are correctly rewarded
|
// verify the uncles are correctly rewarded
|
||||||
if err := v.VerifyUncles(block, parent); err != nil {
|
if err := v.VerifyUncles(reader, block, parent); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,15 +142,20 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
|
||||||
// consensus rules to the various block headers included; it will return an
|
// consensus rules to the various block headers included; it will return an
|
||||||
// error if any of the included uncle headers were invalid. It returns an error
|
// error if any of the included uncle headers were invalid. It returns an error
|
||||||
// if the validation failed.
|
// if the validation failed.
|
||||||
func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error {
|
func (v *BlockValidator) VerifyUncles(reader BlockReader, block, parent *types.Block) error {
|
||||||
|
usize := len(block.Uncles())
|
||||||
|
if usize == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// validate that there at most 2 uncles included in this block
|
// validate that there at most 2 uncles included in this block
|
||||||
if len(block.Uncles()) > 2 {
|
if usize > 2 {
|
||||||
return ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles()))
|
return ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles()))
|
||||||
}
|
}
|
||||||
|
|
||||||
uncles := set.New()
|
uncles := set.New()
|
||||||
ancestors := make(map[common.Hash]*types.Block)
|
ancestors := make(map[common.Hash]*types.Block)
|
||||||
for _, ancestor := range v.bc.GetBlocksFromHash(block.ParentHash(), 7) {
|
for _, ancestor := range reader.GetBlocksFromHash(block.ParentHash(), 7) {
|
||||||
ancestors[ancestor.Hash()] = ancestor
|
ancestors[ancestor.Hash()] = ancestor
|
||||||
// Include ancestors uncles in the uncle set. Uncles must be unique.
|
// Include ancestors uncles in the uncle set. Uncles must be unique.
|
||||||
for _, uncle := range ancestor.Uncles() {
|
for _, uncle := range ancestor.Uncles() {
|
||||||
|
|
@ -193,10 +202,12 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return ParentError(header.ParentHash)
|
return ParentError(header.ParentHash)
|
||||||
}
|
}
|
||||||
|
/* XXX i really don't like this here
|
||||||
// Short circuit if the header's already known or its parent missing
|
// Short circuit if the header's already known or its parent missing
|
||||||
if v.bc.HasHeader(header.Hash()) {
|
if v.bc.HasHeader(header.Hash()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return ValidateHeader(v.config, v.Pow, header, parent, checkPow, false)
|
return ValidateHeader(v.config, v.Pow, header, parent, checkPow, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -826,6 +826,10 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
nonceChecked = make([]bool, len(chain))
|
nonceChecked = make([]bool, len(chain))
|
||||||
statedb *state.StateDB
|
statedb *state.StateDB
|
||||||
)
|
)
|
||||||
|
fork, err := Fork(self.chainDb, self.Config(), self, chain[0].ParentHash(), len(chain))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
// Start the parallel nonce verifier.
|
// Start the parallel nonce verifier.
|
||||||
nonceAbort, nonceResults := verifyNoncesFromBlocks(self.pow, chain)
|
nonceAbort, nonceResults := verifyNoncesFromBlocks(self.pow, chain)
|
||||||
|
|
@ -838,7 +842,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
bstart := time.Now()
|
//bstart := time.Now()
|
||||||
// Wait for block i's nonce to be verified before processing
|
// Wait for block i's nonce to be verified before processing
|
||||||
// its state transition.
|
// its state transition.
|
||||||
for !nonceChecked[i] {
|
for !nonceChecked[i] {
|
||||||
|
|
@ -857,7 +861,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
}
|
}
|
||||||
// Stage 1 validation of the block using the chain's validator
|
// Stage 1 validation of the block using the chain's validator
|
||||||
// interface.
|
// interface.
|
||||||
err := self.Validator().ValidateBlock(block)
|
err := self.Validator().ValidateBlock(fork, block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsKnownBlockErr(err) {
|
if IsKnownBlockErr(err) {
|
||||||
stats.ignored++
|
stats.ignored++
|
||||||
|
|
@ -892,6 +896,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
// Create a new statedb using the parent block and report an
|
// Create a new statedb using the parent block and report an
|
||||||
// error if it fails.
|
// error if it fails.
|
||||||
if statedb == nil {
|
if statedb == nil {
|
||||||
|
//statedb = fork.State()
|
||||||
statedb, err = state.New(self.GetBlock(block.ParentHash()).Root(), self.chainDb)
|
statedb, err = state.New(self.GetBlock(block.ParentHash()).Root(), self.chainDb)
|
||||||
} else {
|
} else {
|
||||||
err = statedb.Reset(chain[i-1].Root())
|
err = statedb.Reset(chain[i-1].Root())
|
||||||
|
|
@ -901,13 +906,13 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Process block using the parent state as reference point.
|
// Process block using the parent state as reference point.
|
||||||
receipts, logs, usedGas, err := self.processor.Process(GetHashFn(block.ParentHash(), self), block, statedb, self.config.VmConfig)
|
receipts, _, usedGas, err := self.processor.Process(fork.GetNumHash, block, statedb, self.config.VmConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reportBlock(block, err)
|
reportBlock(block, err)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Validate the state using the default validator
|
// Validate the state using the default validator
|
||||||
err = self.Validator().ValidateState(block, self.GetBlock(block.ParentHash()), statedb, receipts, usedGas)
|
err = self.Validator().ValidateState(block, fork.GetBlock(block.ParentHash()), statedb, receipts, usedGas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reportBlock(block, err)
|
reportBlock(block, err)
|
||||||
return i, err
|
return i, err
|
||||||
|
|
@ -918,50 +923,61 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// coalesce logs for later processing
|
err = fork.CommitBlock(new(big.Int).Add(fork.GetTd(block.ParentHash()), block.Difficulty()), block, receipts)
|
||||||
coalescedLogs = append(coalescedLogs, logs...)
|
|
||||||
|
|
||||||
if err := WriteBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil {
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
txcount += len(block.Transactions())
|
|
||||||
// write the block to the chain and get the status
|
|
||||||
status, err := self.WriteBlock(block)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch status {
|
/*
|
||||||
case CanonStatTy:
|
// coalesce logs for later processing
|
||||||
if glog.V(logger.Debug) {
|
coalescedLogs = append(coalescedLogs, logs...)
|
||||||
glog.Infof("[%v] inserted block #%d (%d TXs %v G %d UNCs) (%x...). Took %v\n", time.Now().UnixNano(), block.Number(), len(block.Transactions()), block.GasUsed(), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
|
|
||||||
}
|
|
||||||
events = append(events, ChainEvent{block, block.Hash(), logs})
|
|
||||||
|
|
||||||
// This puts transactions in a extra db for rpc
|
if err := WriteBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil {
|
||||||
if err := WriteTransactions(self.chainDb, block); err != nil {
|
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// store the receipts
|
|
||||||
if err := WriteReceipts(self.chainDb, receipts); err != nil {
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
// Write map map bloom filters
|
|
||||||
if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil {
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
case SideStatTy:
|
|
||||||
if glog.V(logger.Detail) {
|
|
||||||
glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
|
|
||||||
}
|
|
||||||
events = append(events, ChainSideEvent{block, logs})
|
|
||||||
|
|
||||||
case SplitStatTy:
|
txcount += len(block.Transactions())
|
||||||
events = append(events, ChainSplitEvent{block, logs})
|
// write the block to the chain and get the status
|
||||||
}
|
status, err := self.WriteBlock(block)
|
||||||
|
if err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch status {
|
||||||
|
case CanonStatTy:
|
||||||
|
if glog.V(logger.Debug) {
|
||||||
|
glog.Infof("[%v] inserted block #%d (%d TXs %v G %d UNCs) (%x...). Took %v\n", time.Now().UnixNano(), block.Number(), len(block.Transactions()), block.GasUsed(), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
|
||||||
|
}
|
||||||
|
events = append(events, ChainEvent{block, block.Hash(), logs})
|
||||||
|
|
||||||
|
// This puts transactions in a extra db for rpc
|
||||||
|
if err := WriteTransactions(self.chainDb, block); err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
// store the receipts
|
||||||
|
if err := WriteReceipts(self.chainDb, receipts); err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
// Write map map bloom filters
|
||||||
|
if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
case SideStatTy:
|
||||||
|
if glog.V(logger.Detail) {
|
||||||
|
glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
|
||||||
|
}
|
||||||
|
events = append(events, ChainSideEvent{block, logs})
|
||||||
|
|
||||||
|
case SplitStatTy:
|
||||||
|
events = append(events, ChainSplitEvent{block, logs})
|
||||||
|
}
|
||||||
|
*/
|
||||||
stats.processed++
|
stats.processed++
|
||||||
}
|
}
|
||||||
|
if err := fork.CommitToDb(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
fork.ApplyTo(self)
|
||||||
|
|
||||||
if (stats.queued > 0 || stats.processed > 0 || stats.ignored > 0) && bool(glog.V(logger.Info)) {
|
if (stats.queued > 0 || stats.processed > 0 || stats.ignored > 0) && bool(glog.V(logger.Info)) {
|
||||||
tend := time.Since(tstart)
|
tend := time.Since(tstart)
|
||||||
|
|
@ -973,6 +989,21 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) Resolve(writer ethdb.Writer, changes []Changes) error {
|
||||||
|
for _, change := range changes {
|
||||||
|
block := change.block
|
||||||
|
// Add the block to the canonical chain number scheme and mark as the head
|
||||||
|
if err := WriteCanonicalHash(writer, block.Hash(), block.NumberU64()); err != nil {
|
||||||
|
return fmt.Errorf("failed to insert block number: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := WriteHeadBlockHash(writer, changes[len(changes)-1].block.Hash()); err != nil {
|
||||||
|
return fmt.Errorf("failed to insert head block hash: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them
|
// reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them
|
||||||
// to be part of the new canonical chain and accumulates potential missing transactions and post an
|
// to be part of the new canonical chain and accumulates potential missing transactions and post an
|
||||||
// event about them
|
// event about them
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ func printChain(bc *BlockChain) {
|
||||||
func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
||||||
for _, block := range chain {
|
for _, block := range chain {
|
||||||
// Try and process the block
|
// Try and process the block
|
||||||
err := blockchain.Validator().ValidateBlock(block)
|
err := blockchain.Validator().ValidateBlock(blockchain, block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsKnownBlockErr(err) {
|
if IsKnownBlockErr(err) {
|
||||||
continue
|
continue
|
||||||
|
|
@ -430,7 +430,7 @@ func TestChainMultipleInsertions(t *testing.T) {
|
||||||
|
|
||||||
type bproc struct{}
|
type bproc struct{}
|
||||||
|
|
||||||
func (bproc) ValidateBlock(*types.Block) error { return nil }
|
func (bproc) ValidateBlock(BlockReader, *types.Block) error { return nil }
|
||||||
func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return nil }
|
func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return nil }
|
||||||
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
|
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ func GetReceipt(db ethdb.ReadWriter, txHash common.Hash) *types.Receipt {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteCanonicalHash stores the canonical hash for the given block number.
|
// WriteCanonicalHash stores the canonical hash for the given block number.
|
||||||
func WriteCanonicalHash(db ethdb.ReadWriter, hash common.Hash, number uint64) error {
|
func WriteCanonicalHash(db ethdb.Writer, hash common.Hash, number uint64) error {
|
||||||
key := append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...)
|
key := append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...)
|
||||||
if err := db.Put(key, hash.Bytes()); err != nil {
|
if err := db.Put(key, hash.Bytes()); err != nil {
|
||||||
glog.Fatalf("failed to store number to hash mapping into database: %v", err)
|
glog.Fatalf("failed to store number to hash mapping into database: %v", err)
|
||||||
|
|
@ -252,7 +252,7 @@ func WriteHeadHeaderHash(db ethdb.ReadWriter, hash common.Hash) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteHeadBlockHash stores the head block's hash.
|
// WriteHeadBlockHash stores the head block's hash.
|
||||||
func WriteHeadBlockHash(db ethdb.ReadWriter, hash common.Hash) error {
|
func WriteHeadBlockHash(db ethdb.Writer, hash common.Hash) error {
|
||||||
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
|
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
|
||||||
glog.Fatalf("failed to store last block's hash into database: %v", err)
|
glog.Fatalf("failed to store last block's hash into database: %v", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
56
core/fork.go
56
core/fork.go
|
|
@ -19,6 +19,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -33,7 +34,7 @@ var errUnboundedParent = errors.New("core/fork: parent hash does not match last
|
||||||
// ChainResolver should implement chain resolving and should be capable
|
// ChainResolver should implement chain resolving and should be capable
|
||||||
// handling reorganisations.
|
// handling reorganisations.
|
||||||
type ChainResolver interface {
|
type ChainResolver interface {
|
||||||
Resolve(ethdb.ReadWriter, []Changes) error
|
Resolve(ethdb.Writer, []Changes) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes are changes that have previously been applied to the forked blockchain.
|
// Changes are changes that have previously been applied to the forked blockchain.
|
||||||
|
|
@ -46,7 +47,8 @@ type Changes struct {
|
||||||
// BlockReader is the basic chain reader interface for reading blocks of the blockchain
|
// BlockReader is the basic chain reader interface for reading blocks of the blockchain
|
||||||
type BlockReader interface {
|
type BlockReader interface {
|
||||||
GetBlock(common.Hash) *types.Block // GetBlock returns the block that corresponds to the given hash
|
GetBlock(common.Hash) *types.Block // GetBlock returns the block that corresponds to the given hash
|
||||||
Db() ethdb.Database // XXX this doesn't really belong here.
|
GetBlocksFromHash(common.Hash, int) []*types.Block
|
||||||
|
GetTd(common.Hash) *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// receipt keeps a log of changes for a specific block number which can
|
// receipt keeps a log of changes for a specific block number which can
|
||||||
|
|
@ -75,12 +77,13 @@ type ChainFork struct {
|
||||||
|
|
||||||
// Fork returns a new blockchain with the given database as backing layer
|
// Fork returns a new blockchain with the given database as backing layer
|
||||||
// for the localised blockchain transaction.
|
// for the localised blockchain transaction.
|
||||||
func Fork(config *ChainConfig, blockReader BlockReader, origin common.Hash) (*ChainFork, error) {
|
func Fork(db ethdb.Database, config *ChainConfig, blockReader BlockReader, origin common.Hash, size int) (*ChainFork, error) {
|
||||||
fork := &ChainFork{
|
fork := &ChainFork{
|
||||||
db: blockReader.Db(),
|
db: db,
|
||||||
reader: blockReader,
|
reader: blockReader,
|
||||||
config: config,
|
config: config,
|
||||||
hashToIdx: make(map[common.Hash]int),
|
hashToIdx: make(map[common.Hash]int),
|
||||||
|
changes: make([]Changes, 0, size),
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the origin block from which this fork originates
|
// get the origin block from which this fork originates
|
||||||
|
|
@ -143,6 +146,43 @@ func (fork *ChainFork) GetBlock(hash common.Hash) *types.Block {
|
||||||
return fork.changes[idx].block
|
return fork.changes[idx].block
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fork *ChainFork) GetBlocksFromHash(hash common.Hash, size int) []*types.Block {
|
||||||
|
blocks := make([]*types.Block, 0, size)
|
||||||
|
|
||||||
|
max := int(math.Min(float64(size), float64(len(fork.changes))))
|
||||||
|
for i := 0; i < max; i++ {
|
||||||
|
blocks = append(blocks, fork.changes[len(fork.changes)-(i+1)].block)
|
||||||
|
}
|
||||||
|
// fetch the rest from the blockchain
|
||||||
|
if max < size {
|
||||||
|
blocks = append(blocks, fork.origin)
|
||||||
|
hash := fork.origin.ParentHash()
|
||||||
|
for i := max + 1; i < size; i++ {
|
||||||
|
block := GetBlock(fork.db, hash)
|
||||||
|
if block == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
blocks = append(blocks, block)
|
||||||
|
hash = block.ParentHash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fork *ChainFork) GetTd(hash common.Hash) *big.Int {
|
||||||
|
if len(fork.changes) == 0 {
|
||||||
|
if fork.origin.Hash() == hash {
|
||||||
|
return fork.reader.GetTd(hash)
|
||||||
|
}
|
||||||
|
return new(big.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx, ok := fork.hashToIdx[hash]; ok {
|
||||||
|
return fork.changes[idx].td
|
||||||
|
}
|
||||||
|
return new(big.Int)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,7 +236,7 @@ func (fork *ChainFork) CommitToDb() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := change.block.Hash()
|
hash := change.block.Hash()
|
||||||
if err := WriteHeader(tx, change.block.Header()); err != nil {
|
if err := WriteBlock(tx, change.block); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := WriteTd(tx, hash, change.td); err != nil {
|
if err := WriteTd(tx, hash, change.td); err != nil {
|
||||||
|
|
@ -231,7 +271,11 @@ func (fork *ChainFork) ApplyTo(resolver ChainResolver) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return resolver.Resolve(tx, fork.changes)
|
err = resolver.Resolve(tx, fork.changes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUnsealedBlock creates a new unsealed block using the last block in the fork
|
// NewUnsealedBlock creates a new unsealed block using the last block in the fork
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,12 @@ func newFakeChain() fakeChain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c fakeChain) Db() ethdb.Database {
|
func (c fakeChain) GetTd(common.Hash) *big.Int {
|
||||||
return c.db
|
return new(big.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c fakeChain) GetBlocksFromHash(common.Hash, int) []*types.Block {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c fakeChain) GetBlock(hash common.Hash) *types.Block {
|
func (c fakeChain) GetBlock(hash common.Hash) *types.Block {
|
||||||
|
|
@ -33,7 +37,7 @@ func TestGetNumHash(t *testing.T) {
|
||||||
genesis := WriteGenesisBlockForTesting(chain.db)
|
genesis := WriteGenesisBlockForTesting(chain.db)
|
||||||
config := &ChainConfig{HomesteadBlock: new(big.Int)}
|
config := &ChainConfig{HomesteadBlock: new(big.Int)}
|
||||||
|
|
||||||
fork, err := Fork(config, chain, genesis.Hash())
|
fork, err := Fork(chain.db, config, chain, genesis.Hash(), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ import (
|
||||||
// gas used. The implementer should decide what to do with the given input.
|
// gas used. The implementer should decide what to do with the given input.
|
||||||
type Validator interface {
|
type Validator interface {
|
||||||
HeaderValidator
|
HeaderValidator
|
||||||
ValidateBlock(block *types.Block) error
|
ValidateBlock(reader BlockReader, block *types.Block) error
|
||||||
ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error
|
ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue