244 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			244 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2014 The go-ethereum Authors
							 | 
						||
| 
								 | 
							
								// This file is part of the go-ethereum library.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The go-ethereum library is free software: you can redistribute it and/or modify
							 | 
						||
| 
								 | 
							
								// it under the terms of the GNU Lesser General Public License as published by
							 | 
						||
| 
								 | 
							
								// the Free Software Foundation, either version 3 of the License, or
							 | 
						||
| 
								 | 
							
								// (at your option) any later version.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The go-ethereum library is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								// but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
							 | 
						||
| 
								 | 
							
								// GNU Lesser General Public License for more details.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// You should have received a copy of the GNU Lesser General Public License
							 | 
						||
| 
								 | 
							
								// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package core
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"math/big"
							 | 
						||
| 
								 | 
							
									"time"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"github.com/ethereum/go-ethereum/common"
							 | 
						||
| 
								 | 
							
									"github.com/ethereum/go-ethereum/core/state"
							 | 
						||
| 
								 | 
							
									"github.com/ethereum/go-ethereum/core/types"
							 | 
						||
| 
								 | 
							
									"github.com/ethereum/go-ethereum/logger/glog"
							 | 
						||
| 
								 | 
							
									"github.com/ethereum/go-ethereum/params"
							 | 
						||
| 
								 | 
							
									"github.com/ethereum/go-ethereum/pow"
							 | 
						||
| 
								 | 
							
									"gopkg.in/fatih/set.v0"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// BlockValidator is responsible for validating block headers, uncles and
							 | 
						||
| 
								 | 
							
								// processed state.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// BlockValidator implements Validator.
							 | 
						||
| 
								 | 
							
								type BlockValidator struct {
							 | 
						||
| 
								 | 
							
									bc  *BlockChain // Canonical block chain
							 | 
						||
| 
								 | 
							
									Pow pow.PoW     // Proof of work used for validating
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// NewBlockValidator returns a new block validator which is safe for re-use
							 | 
						||
| 
								 | 
							
								func NewBlockValidator(blockchain *BlockChain, pow pow.PoW) *BlockValidator {
							 | 
						||
| 
								 | 
							
									validator := &BlockValidator{
							 | 
						||
| 
								 | 
							
										Pow: pow,
							 | 
						||
| 
								 | 
							
										bc:  blockchain,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return validator
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ValidateBlock validates the given block's header and uncles and verifies the
							 | 
						||
| 
								 | 
							
								// the block header's transaction and uncle roots.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// ValidateBlock does not validate the header's pow. The pow work validated
							 | 
						||
| 
								 | 
							
								// seperately so we can process them in paralel.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// ValidateBlock also validates and makes sure that any previous state (or present)
							 | 
						||
| 
								 | 
							
								// 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
							 | 
						||
| 
								 | 
							
								// false positives where a header is present but the state is not.
							 | 
						||
| 
								 | 
							
								func (v *BlockValidator) ValidateBlock(block *types.Block) error {
							 | 
						||
| 
								 | 
							
									if v.bc.HasBlock(block.Hash()) {
							 | 
						||
| 
								 | 
							
										if _, err := state.New(block.Root(), v.bc.chainDb); err == nil {
							 | 
						||
| 
								 | 
							
											return &KnownBlockError{block.Number(), block.Hash()}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									parent := v.bc.GetBlock(block.ParentHash())
							 | 
						||
| 
								 | 
							
									if parent == nil {
							 | 
						||
| 
								 | 
							
										return ParentError(block.ParentHash())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil {
							 | 
						||
| 
								 | 
							
										return ParentError(block.ParentHash())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									header := block.Header()
							 | 
						||
| 
								 | 
							
									// validate the block header
							 | 
						||
| 
								 | 
							
									if err := ValidateHeader(v.Pow, header, parent.Header(), false, false); err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// verify the uncles are correctly rewarded
							 | 
						||
| 
								 | 
							
									if err := v.VerifyUncles(block, parent); err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Verify UncleHash before running other uncle validations
							 | 
						||
| 
								 | 
							
									unclesSha := types.CalcUncleHash(block.Uncles())
							 | 
						||
| 
								 | 
							
									if unclesSha != header.UncleHash {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
							 | 
						||
| 
								 | 
							
									// can be used by light clients to make sure they've received the correct Txs
							 | 
						||
| 
								 | 
							
									txSha := types.DeriveSha(block.Transactions())
							 | 
						||
| 
								 | 
							
									if txSha != header.TxHash {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ValidateState validates the various changes that happen after a state
							 | 
						||
| 
								 | 
							
								// transition, such as amount of used gas, the receipt roots and the state root
							 | 
						||
| 
								 | 
							
								// itself. ValidateState returns a database batch if the validation was a succes
							 | 
						||
| 
								 | 
							
								// 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) {
							 | 
						||
| 
								 | 
							
									header := block.Header()
							 | 
						||
| 
								 | 
							
									if block.GasUsed().Cmp(usedGas) != 0 {
							 | 
						||
| 
								 | 
							
										return ValidationError(fmt.Sprintf("gas used error (%v / %v)", block.GasUsed(), usedGas))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Validate the received block's bloom with the one derived from the generated receipts.
							 | 
						||
| 
								 | 
							
									// For valid blocks this should always validate to true.
							 | 
						||
| 
								 | 
							
									rbloom := types.CreateBloom(receipts)
							 | 
						||
| 
								 | 
							
									if rbloom != header.Bloom {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
							 | 
						||
| 
								 | 
							
									receiptSha := types.DeriveSha(receipts)
							 | 
						||
| 
								 | 
							
									if receiptSha != header.ReceiptHash {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("invalid receipt root hash. received=%x calculated=%x", header.ReceiptHash, receiptSha)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Validate the state root against the received state root and throw
							 | 
						||
| 
								 | 
							
									// an error if they don't match.
							 | 
						||
| 
								 | 
							
									if root := statedb.IntermediateRoot(); header.Root != root {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// VerifyUncles verifies the given block's uncles and applies the Ethereum
							 | 
						||
| 
								 | 
							
								// 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 {
							 | 
						||
| 
								 | 
							
									// 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()))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									uncles := set.New()
							 | 
						||
| 
								 | 
							
									ancestors := make(map[common.Hash]*types.Block)
							 | 
						||
| 
								 | 
							
									for _, ancestor := range v.bc.GetBlocksFromHash(block.ParentHash(), 7) {
							 | 
						||
| 
								 | 
							
										ancestors[ancestor.Hash()] = ancestor
							 | 
						||
| 
								 | 
							
										// Include ancestors uncles in the uncle set. Uncles must be unique.
							 | 
						||
| 
								 | 
							
										for _, uncle := range ancestor.Uncles() {
							 | 
						||
| 
								 | 
							
											uncles.Add(uncle.Hash())
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									ancestors[block.Hash()] = block
							 | 
						||
| 
								 | 
							
									uncles.Add(block.Hash())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for i, uncle := range block.Uncles() {
							 | 
						||
| 
								 | 
							
										hash := uncle.Hash()
							 | 
						||
| 
								 | 
							
										if uncles.Has(hash) {
							 | 
						||
| 
								 | 
							
											// Error not unique
							 | 
						||
| 
								 | 
							
											return UncleError("uncle[%d](%x) not unique", i, hash[:4])
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										uncles.Add(hash)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ancestors[hash] != nil {
							 | 
						||
| 
								 | 
							
											branch := fmt.Sprintf("  O - %x\n  |\n", block.Hash())
							 | 
						||
| 
								 | 
							
											for h := range ancestors {
							 | 
						||
| 
								 | 
							
												branch += fmt.Sprintf("  O - %x\n  |\n", h)
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											glog.Infoln(branch)
							 | 
						||
| 
								 | 
							
											return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == parent.Hash() {
							 | 
						||
| 
								 | 
							
											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 {
							 | 
						||
| 
								 | 
							
											return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ValidateHeader validates the given header and, depending on the pow arg,
							 | 
						||
| 
								 | 
							
								// checks the proof of work of the given header. Returns an error if the
							 | 
						||
| 
								 | 
							
								// validation failed.
							 | 
						||
| 
								 | 
							
								func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow bool) error {
							 | 
						||
| 
								 | 
							
									// Short circuit if the parent is missing.
							 | 
						||
| 
								 | 
							
									if parent == nil {
							 | 
						||
| 
								 | 
							
										return ParentError(header.ParentHash)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Short circuit if the header's already known or its parent missing
							 | 
						||
| 
								 | 
							
									if v.bc.HasHeader(header.Hash()) {
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return ValidateHeader(v.Pow, header, parent, checkPow, false)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Validates a header. Returns an error if the header is invalid.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// See YP section 4.3.4. "Block Header Validity"
							 | 
						||
| 
								 | 
							
								func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
							 | 
						||
| 
								 | 
							
									if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if uncle {
							 | 
						||
| 
								 | 
							
										if header.Time.Cmp(common.MaxBig) == 1 {
							 | 
						||
| 
								 | 
							
											return BlockTSTooBigErr
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										if header.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 {
							 | 
						||
| 
								 | 
							
											return BlockFutureErr
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if header.Time.Cmp(parent.Time) != 1 {
							 | 
						||
| 
								 | 
							
										return BlockEqualTSErr
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									expd := CalcDifficulty(header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty)
							 | 
						||
| 
								 | 
							
									if expd.Cmp(header.Difficulty) != 0 {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("Difficulty check failed for header %v, %v", header.Difficulty, expd)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									a := new(big.Int).Set(parent.GasLimit)
							 | 
						||
| 
								 | 
							
									a = a.Sub(a, header.GasLimit)
							 | 
						||
| 
								 | 
							
									a.Abs(a)
							 | 
						||
| 
								 | 
							
									b := new(big.Int).Set(parent.GasLimit)
							 | 
						||
| 
								 | 
							
									b = b.Div(b, params.GasLimitBoundDivisor)
							 | 
						||
| 
								 | 
							
									if !(a.Cmp(b) < 0) || (header.GasLimit.Cmp(params.MinGasLimit) == -1) {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("GasLimit check failed for header %v (%v > %v)", header.GasLimit, a, b)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									num := new(big.Int).Set(parent.Number)
							 | 
						||
| 
								 | 
							
									num.Sub(header.Number, num)
							 | 
						||
| 
								 | 
							
									if num.Cmp(big.NewInt(1)) != 0 {
							 | 
						||
| 
								 | 
							
										return BlockNumberErr
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if checkPow {
							 | 
						||
| 
								 | 
							
										// Verify the nonce of the header. Return an error if it's not valid
							 | 
						||
| 
								 | 
							
										if !pow.Verify(types.NewBlockWithHeader(header)) {
							 | 
						||
| 
								 | 
							
											return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 |