github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/block_validator.go (about)

     1  package core
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/quickchainproject/quickchain/consensus"
     7  	"github.com/quickchainproject/quickchain/core/state"
     8  	"github.com/quickchainproject/quickchain/core/types"
     9  	"github.com/quickchainproject/quickchain/params"
    10  )
    11  
    12  // BlockValidator is responsible for validating block headers, uncles and
    13  // processed state.
    14  //
    15  // BlockValidator implements Validator.
    16  type BlockValidator struct {
    17  	config *params.ChainConfig // Chain configuration options
    18  	bc     *BlockChain         // Canonical block chain
    19  	engine consensus.Engine    // Consensus engine used for validating
    20  }
    21  
    22  // NewBlockValidator returns a new block validator which is safe for re-use
    23  func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
    24  	validator := &BlockValidator{
    25  		config: config,
    26  		engine: engine,
    27  		bc:     blockchain,
    28  	}
    29  	return validator
    30  }
    31  
    32  // ValidateBody validates the given block's uncles and verifies the the block
    33  // header's transaction and uncle roots. The headers are assumed to be already
    34  // validated at this point.
    35  func (v *BlockValidator) ValidateBody(block *types.Block) error {
    36  	// Check whether the block's known, and if not, that it's linkable
    37  	if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
    38  		return ErrKnownBlock
    39  	}
    40  	if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
    41  		if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
    42  			return consensus.ErrUnknownAncestor
    43  		}
    44  		return consensus.ErrPrunedAncestor
    45  	}
    46  	// Header validity is known at this point, check the uncles and transactions
    47  	header := block.Header()
    48  	if err := v.engine.VerifyUncles(v.bc, block); err != nil {
    49  		return err
    50  	}
    51  	if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
    52  		return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash)
    53  	}
    54  	if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash {
    55  		return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
    56  	}
    57  	return nil
    58  }
    59  
    60  // ValidateState validates the various changes that happen after a state
    61  // transition, such as amount of used gas, the receipt roots and the state root
    62  // itself. ValidateState returns a database batch if the validation was a success
    63  // otherwise nil and an error is returned.
    64  func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error {
    65  	header := block.Header()
    66  	if block.GasUsed() != usedGas {
    67  		return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
    68  	}
    69  	// Validate the received block's bloom with the one derived from the generated receipts.
    70  	// For valid blocks this should always validate to true.
    71  	rbloom := types.CreateBloom(receipts)
    72  	if rbloom != header.Bloom {
    73  		return fmt.Errorf("invalid bloom (remote: %x  local: %x)", header.Bloom, rbloom)
    74  	}
    75  	// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
    76  	receiptSha := types.DeriveSha(receipts)
    77  	if receiptSha != header.ReceiptHash {
    78  		return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
    79  	}
    80  	// Validate the state root against the received state root and throw
    81  	// an error if they don't match.
    82  	if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
    83  		return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
    84  	}
    85  	return nil
    86  }
    87  
    88  func (v *BlockValidator) ValidateDposState(block *types.Block) error {
    89  	header := block.Header()
    90  	localRoot := block.DposCtx().Root()
    91  	remoteRoot := header.DposContext.Root()
    92  	if remoteRoot != localRoot {
    93  		return fmt.Errorf("invalid dpos root (remote: %x local: %x)", remoteRoot, localRoot)
    94  	}
    95  	return nil
    96  }
    97  
    98  // CalcGasLimit computes the gas limit of the next block after parent.
    99  // This is miner strategy, not consensus protocol.
   100  func CalcGasLimit(parent *types.Block) uint64 {
   101  	// contrib = (parentGasUsed * 3 / 2) / 1024
   102  	contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor
   103  
   104  	// decay = parentGasLimit / 1024 -1
   105  	decay := parent.GasLimit()/params.GasLimitBoundDivisor - 1
   106  
   107  	/*
   108  		strategy: gasLimit of block-to-mine is set based on parent's
   109  		gasUsed value.  if parentGasUsed > parentGasLimit * (2/3) then we
   110  		increase it, otherwise lower it (or leave it unchanged if it's right
   111  		at that usage) the amount increased/decreased depends on how far away
   112  		from parentGasLimit * (2/3) parentGasUsed is.
   113  	*/
   114  	limit := parent.GasLimit() - decay + contrib
   115  	if limit < params.MinGasLimit {
   116  		limit = params.MinGasLimit
   117  	}
   118  	// however, if we're now below the target (TargetGasLimit) we increase the
   119  	// limit as much as we can (parentGasLimit / 1024 -1)
   120  	if limit < params.TargetGasLimit {
   121  		limit = parent.GasLimit() + decay
   122  		if limit > params.TargetGasLimit {
   123  			limit = params.TargetGasLimit
   124  		}
   125  	}
   126  	return limit
   127  }