github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/core/block_validator.go (about)

     1  // Copyright 2015 The Spectrum Authors
     2  // This file is part of the Spectrum library.
     3  //
     4  // The Spectrum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The Spectrum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  
    23  	"github.com/SmartMeshFoundation/Spectrum/common/math"
    24  	"github.com/SmartMeshFoundation/Spectrum/consensus"
    25  	"github.com/SmartMeshFoundation/Spectrum/consensus/tribe"
    26  	"github.com/SmartMeshFoundation/Spectrum/core/state"
    27  	"github.com/SmartMeshFoundation/Spectrum/core/types"
    28  	"github.com/SmartMeshFoundation/Spectrum/log"
    29  	"github.com/SmartMeshFoundation/Spectrum/params"
    30  )
    31  
    32  // BlockValidator is responsible for validating block headers, uncles 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 validates the given block's uncles and verifies the the block
    53  // header's transaction and uncle roots. The headers are assumed to be already
    54  // validated at this point.
    55  func (v *BlockValidator) ValidateBody(parent, block *types.Block) error {
    56  
    57  	if t, ok := v.engine.(*tribe.Tribe); ok {
    58  		status := &tribe.TribeStatus{}
    59  		tribenew := &tribe.Tribe{
    60  			Status: status,
    61  		}
    62  		tribenew.SetConfig(t.GetConfig())
    63  		status.SetTribe(tribenew)
    64  		status.SetNodeKey(t.Status.GetNodeKey())
    65  		if err := status.ValidateBlock(parent, block, true); err != nil {
    66  			log.Error("BlockValidator.ValidateBody", "number", block.Number().Int64(), "err", err)
    67  			return err
    68  		}
    69  	}
    70  	// Check whether the block's known, and if not, that it's linkable
    71  	if v.bc.HasBlockAndState(block.Hash()) {
    72  		return ErrKnownBlock
    73  	}
    74  	if !v.bc.HasBlockAndState(block.ParentHash()) {
    75  		return consensus.ErrUnknownAncestor
    76  	}
    77  	// Header validity is known at this point, check the uncles and transactions
    78  	header := block.Header()
    79  	if err := v.engine.VerifyUncles(v.bc, block); err != nil {
    80  		return err
    81  	}
    82  	if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
    83  		return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash)
    84  	}
    85  	// add by liangc : 18-09-13 : error block : incompatible HomesteadSigner
    86  	if params.IsSIP003Block(header.Number) {
    87  		for _, tx := range block.Transactions() {
    88  			if !tx.Protected() {
    89  				return fmt.Errorf("Incompatible HomesteadSigner now num=%d tx=%s", header.Number.Int64(), tx.Hash().Hex())
    90  			}
    91  		}
    92  	}
    93  	if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash {
    94  		return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
    95  	}
    96  	return nil
    97  }
    98  
    99  // ValidateState validates the various changes that happen after a state
   100  // transition, such as amount of used gas, the receipt roots and the state root
   101  // itself. ValidateState returns a database batch if the validation was a success
   102  // otherwise nil and an error is returned.
   103  func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
   104  	// testnet 176222~192630 block receipt CumulativeGasUsed error
   105  	// skip this validation for compatibility
   106  	header := block.Header()
   107  	if block.GasUsed().Cmp(usedGas) != 0 {
   108  		return fmt.Errorf("invalid gas used (remote: %v local: %v)", block.GasUsed(), usedGas)
   109  	}
   110  	// Validate the received block's bloom with the one derived from the generated receipts.
   111  	// For valid blocks this should always validate to true.
   112  	rbloom := types.CreateBloom(receipts)
   113  	if rbloom != header.Bloom {
   114  		return fmt.Errorf("invalid bloom (remote: %x  local: %x)", header.Bloom, rbloom)
   115  	}
   116  	// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
   117  	receiptSha := types.DeriveSha(receipts)
   118  	if receiptSha != header.ReceiptHash {
   119  		return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
   120  	}
   121  	// Validate the state root against the received state root and throw
   122  	// an error if they don't match.
   123  	if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
   124  		return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
   125  	}
   126  	//if t, ok := v.engine.(*tribe.Tribe); ok {
   127  	//	log.Debug("<<ValidateState>> verify_signer =>", "num", header.Number, "coinbase", header.Coinbase.Hex())
   128  	//	//if err := tribe.VerifySignerBalance(statedb, header.Coinbase, header); err != nil {
   129  	//	if err := t.Status.VerifySignerBalance(statedb, common.HexToAddress("0x"), header); err != nil {
   130  	//		return err
   131  	//	}
   132  	//}
   133  	return nil
   134  }
   135  
   136  // CalcGasLimit computes the gas limit of the next block after parent.
   137  // The result may be modified by the caller.
   138  // This is miner strategy, not consensus protocol.
   139  func CalcGasLimit(parent *types.Block) *big.Int {
   140  	// contrib = (parentGasUsed * 3 / 2) / 1024
   141  
   142  	contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
   143  	contrib = contrib.Div(contrib, big.NewInt(2))
   144  	contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
   145  
   146  	// decay = parentGasLimit / 1024 -1
   147  	decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
   148  	decay.Sub(decay, big.NewInt(1))
   149  
   150  	/*
   151  		strategy: gasLimit of block-to-mine is set based on parent's
   152  		gasUsed value.  if parentGasUsed > parentGasLimit * (2/3) then we
   153  		increase it, otherwise lower it (or leave it unchanged if it's right
   154  		at that usage) the amount increased/decreased depends on how far away
   155  		from parentGasLimit * (2/3) parentGasUsed is.
   156  	*/
   157  	gl := new(big.Int).Sub(parent.GasLimit(), decay)
   158  	gl = gl.Add(gl, contrib)
   159  
   160  	minGasLimit := params.MinGasLimit
   161  	//sip004区块硬分叉开始,提升区块最小的gaslimit
   162  	if params.IsSIP004Block(new(big.Int).Add(parent.Number(), big.NewInt(1))) {
   163  		minGasLimit = params.Sip004GasLimit
   164  	}
   165  	/*
   166  		sip004Block := params.MainnetChainConfig.Sip004Block
   167  		if params.IsTestnet() {
   168  			sip004Block = params.TestnetChainConfig.Sip004Block
   169  		} else if params.IsDevnet() {
   170  			sip004Block = params.DevnetChainConfig.Sip004Block
   171  		}
   172  		number := parent.Number().Add(parent.Number(), big.NewInt(1))
   173  		if number.Cmp(sip004Block) >= 0 {
   174  			minGasLimit = params.Sip004GasLimit
   175  		}
   176  	*/
   177  
   178  	gl.Set(math.BigMax(gl, minGasLimit))
   179  
   180  	// however, if we're now below the target (TargetGasLimit) we increase the
   181  	// limit as much as we can (parentGasLimit / 1024 -1)
   182  	if gl.Cmp(params.TargetGasLimit) < 0 {
   183  		gl.Add(parent.GasLimit(), decay)
   184  		gl.Set(math.BigMin(gl, params.TargetGasLimit))
   185  	}
   186  	return gl
   187  }