github.com/klaytn/klaytn@v1.12.1/blockchain/block_validator.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from core/block_validator.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package blockchain
    22  
    23  import (
    24  	"fmt"
    25  
    26  	"github.com/klaytn/klaytn/blockchain/state"
    27  	"github.com/klaytn/klaytn/blockchain/types"
    28  	"github.com/klaytn/klaytn/consensus"
    29  	"github.com/klaytn/klaytn/params"
    30  )
    31  
    32  // BlockValidator is responsible for validating block headers and
    33  // processed state.
    34  //
    35  // BlockValidator implements Validator.
    36  type BlockValidator struct {
    37  	config *params.ChainConfig // Chain configuration options
    38  	bc     *BlockChain         // Canonical block chain
    39  	engine consensus.Engine    // Consensus engine used for validating
    40  }
    41  
    42  // NewBlockValidator returns a new block validator which is safe for re-use
    43  func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
    44  	validator := &BlockValidator{
    45  		config: config,
    46  		engine: engine,
    47  		bc:     blockchain,
    48  	}
    49  	return validator
    50  }
    51  
    52  // ValidateBody verifies the block
    53  // header's transaction. The headers are assumed to be already
    54  // validated at this point.
    55  func (v *BlockValidator) ValidateBody(block *types.Block) error {
    56  	// Check whether the block's known, and if not, that it's linkable
    57  	if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
    58  		return ErrKnownBlock
    59  	}
    60  	if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
    61  		if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
    62  			logger.Error("unknown ancestor (ValidateBody)", "num", block.NumberU64(),
    63  				"hash", block.Hash(), "parentHash", block.ParentHash())
    64  			return consensus.ErrUnknownAncestor
    65  		}
    66  		return consensus.ErrPrunedAncestor
    67  	}
    68  	// Header validity is known at this point, check the transactions
    69  	header := block.Header()
    70  	if hash := types.DeriveSha(block.Transactions(), block.Number()); hash != header.TxHash {
    71  		return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
    72  	}
    73  	baseFee := block.Header().BaseFee
    74  	if baseFee != nil {
    75  		for _, tx := range block.Transactions() {
    76  			if baseFee.Cmp(tx.GasPrice()) > 0 {
    77  				return fmt.Errorf("Invalid GasPrice: txHash %x, GasPrice %d, BaseFee %d", tx.Hash(), tx.GasPrice(), baseFee)
    78  			}
    79  		}
    80  	}
    81  	return nil
    82  }
    83  
    84  // ValidateState validates the various changes that happen after a state
    85  // transition, such as amount of used gas, the receipt roots and the state root
    86  // itself. ValidateState returns a database batch if the validation was a success
    87  // otherwise nil and an error is returned.
    88  func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error {
    89  	header := block.Header()
    90  	if block.GasUsed() != usedGas {
    91  		return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
    92  	}
    93  	// Validate the received block's bloom with the one derived from the generated receipts.
    94  	// For valid blocks this should always validate to true.
    95  	rbloom := types.CreateBloom(receipts)
    96  	if rbloom != header.Bloom {
    97  		return fmt.Errorf("invalid bloom (remote: %x  local: %x)", header.Bloom, rbloom)
    98  	}
    99  	// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
   100  	receiptSha := types.DeriveSha(receipts, block.Number())
   101  	if receiptSha != header.ReceiptHash {
   102  		return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
   103  	}
   104  	// Validate the state root against the received state root and throw
   105  	// an error if they don't match.
   106  	if root := statedb.IntermediateRoot(true); header.Root != root {
   107  		return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
   108  	}
   109  	return nil
   110  }