diff --git a/core/block_validator.go b/core/block_validator.go index 4d710ae3f5..d4f3152cf2 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -84,7 +84,8 @@ func (v *BlockValidator) ValidateBlock(block *types.Block) error { return err } // verify the uncles are correctly rewarded - if err := v.VerifyUncles(block, parent); err != nil { + ancestors := v.bc.GetBlocksFromHash(block.ParentHash(), 7) + if err := VerifyUncles(v.Pow, block, parent, ancestors); err != nil { return err } @@ -109,6 +110,10 @@ func (v *BlockValidator) ValidateBlock(block *types.Block) error { // itself. ValidateState returns a database batch if the validation was a success // otherwise nil and an error is returned. func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas *big.Int) (err error) { + return ValidateState(block, parent, statedb, receipts, usedGas) +} + +func ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas *big.Int) (err error) { header := block.Header() if block.GasUsed().Cmp(usedGas) != 0 { return ValidationError(fmt.Sprintf("gas used error (%v / %v)", block.GasUsed(), usedGas)) @@ -136,7 +141,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat // 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 // if the validation failed. -func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error { +func VerifyUncles(pow pow.PoW, block, parent *types.Block, ancestorList []*types.Block) error { // validate that there at most 2 uncles included in this block if len(block.Uncles()) > 2 { return ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles())) @@ -144,7 +149,7 @@ func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error { uncles := set.New() ancestors := make(map[common.Hash]*types.Block) - for _, ancestor := range v.bc.GetBlocksFromHash(block.ParentHash(), 7) { + for _, ancestor := range ancestorList { ancestors[ancestor.Hash()] = ancestor // Include ancestors uncles in the uncle set. Uncles must be unique. for _, uncle := range ancestor.Uncles() { @@ -175,7 +180,7 @@ func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error { return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4]) } - if err := ValidateHeader(v.Pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil { + if err := ValidateHeader(pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil { return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err)) } } diff --git a/core/state_processor.go b/core/state_processor.go index 3ca36a43a9..562341ec94 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,10 +17,10 @@ var ( ) type StateProcessor struct { - bc *BlockChain + bc blockGetter } -func NewStateProcessor(bc *BlockChain) *StateProcessor { +func NewStateProcessor(bc blockGetter) *StateProcessor { return &StateProcessor{bc} } @@ -60,7 +60,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB) (ty // // ApplyTransactions returns the generated receipts and vm logs during the // execution of the state transition phase. -func ApplyTransaction(bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int) (*types.Receipt, vm.Logs, *big.Int, error) { +func ApplyTransaction(bc blockGetter, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int) (*types.Receipt, vm.Logs, *big.Int, error) { _, gas, err := ApplyMessage(NewEnv(statedb, bc, tx, header), tx, gp) if err != nil { return nil, nil, nil, err diff --git a/core/vm_env.go b/core/vm_env.go index 7b9a1a0f9a..174a62a47e 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -25,10 +25,14 @@ import ( "github.com/ethereum/go-ethereum/core/vm" ) +type blockGetter interface { + GetBlock(common.Hash) *types.Block +} + // GetHashFn returns a function for which the VM env can query block hashes through // up to the limit defined by the Yellow Paper and uses the given block chain // to query for information. -func GetHashFn(ref common.Hash, chain *BlockChain) func(n uint64) common.Hash { +func GetHashFn(ref common.Hash, chain blockGetter) func(n uint64) common.Hash { return func(n uint64) common.Hash { for block := chain.GetBlock(ref); block != nil; block = chain.GetBlock(block.ParentHash()) { if block.NumberU64() == n { @@ -45,7 +49,7 @@ type VMEnv struct { header *types.Header msg Message depth int - chain *BlockChain + chain blockGetter typ vm.Type getHashFn func(uint64) common.Hash @@ -53,7 +57,7 @@ type VMEnv struct { logs []vm.StructLog } -func NewEnv(state *state.StateDB, chain *BlockChain, msg Message, header *types.Header) *VMEnv { +func NewEnv(state *state.StateDB, chain blockGetter, msg Message, header *types.Header) *VMEnv { return &VMEnv{ chain: chain, state: state, diff --git a/eth/handler.go b/eth/handler.go index 2c5cae479f..1db87998d5 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -60,7 +60,7 @@ type ProtocolManager struct { fastSync bool txpool txPool - blockchain *core.BlockChain + blockchain blockChain chaindb ethdb.Database downloader *downloader.Downloader @@ -86,7 +86,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(fastSync bool, networkId int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) { +func NewProtocolManager(fastSync bool, networkId int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain blockChain, chaindb ethdb.Database) (*ProtocolManager, error) { // Figure out whether to allow fast sync or not if fastSync && blockchain.CurrentBlock().NumberU64() > 0 { glog.V(logger.Info).Infof("blockchain not empty, fast sync disabled") diff --git a/eth/protocol.go b/eth/protocol.go index 808ac06011..9b10a5245c 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -123,6 +123,30 @@ type chainManager interface { Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) } +// proxy interface to core.BlockChain +type blockChain interface { + Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) + Genesis() *types.Block + CurrentHeader() *types.Header + CurrentBlock() *types.Block + CurrentFastBlock() *types.Block + HasHeader(hash common.Hash) bool + HasBlock(hash common.Hash) bool + HasBlockAndState(hash common.Hash) bool + GetHeader(hash common.Hash) *types.Header + GetHeaderByNumber(number uint64) *types.Header + GetBlock(hash common.Hash) *types.Block + GetBlockByNumber(number uint64) *types.Block + GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash + GetBodyRLP(hash common.Hash) rlp.RawValue + FastSyncCommitHead(hash common.Hash) error + GetTd(hash common.Hash) *big.Int + InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) + InsertChain(chain types.Blocks) (int, error) + InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) + Rollback(chain []common.Hash) +} + // statusData is the network packet for the status message. type statusData struct { ProtocolVersion uint32