github.com/cgcardona/r-subnet-evm@v0.1.5/core/block_validator.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2015 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package core
    28  
    29  import (
    30  	"fmt"
    31  
    32  	"github.com/cgcardona/r-subnet-evm/consensus"
    33  	"github.com/cgcardona/r-subnet-evm/core/state"
    34  	"github.com/cgcardona/r-subnet-evm/core/types"
    35  	"github.com/cgcardona/r-subnet-evm/params"
    36  	"github.com/cgcardona/r-subnet-evm/trie"
    37  )
    38  
    39  // BlockValidator is responsible for validating block headers, uncles and
    40  // processed state.
    41  //
    42  // BlockValidator implements Validator.
    43  type BlockValidator struct {
    44  	config *params.ChainConfig // Chain configuration options
    45  	bc     *BlockChain         // Canonical block chain
    46  	engine consensus.Engine    // Consensus engine used for validating
    47  }
    48  
    49  // NewBlockValidator returns a new block validator which is safe for re-use
    50  func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
    51  	validator := &BlockValidator{
    52  		config: config,
    53  		engine: engine,
    54  		bc:     blockchain,
    55  	}
    56  	return validator
    57  }
    58  
    59  // ValidateBody validates the given block's uncles and verifies the block
    60  // header's transaction and uncle roots. The headers are assumed to be already
    61  // validated at this point.
    62  func (v *BlockValidator) ValidateBody(block *types.Block) error {
    63  	// Check whether the block's known, and if not, that it's linkable
    64  	if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
    65  		return ErrKnownBlock
    66  	}
    67  	// Header validity is known at this point, check the uncles and transactions
    68  	header := block.Header()
    69  	if err := v.engine.VerifyUncles(v.bc, block); err != nil {
    70  		return err
    71  	}
    72  	if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
    73  		return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash)
    74  	}
    75  	if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
    76  		return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
    77  	}
    78  	if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
    79  		if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
    80  			return consensus.ErrUnknownAncestor
    81  		}
    82  		return consensus.ErrPrunedAncestor
    83  	}
    84  	return nil
    85  }
    86  
    87  // ValidateState validates the various changes that happen after a state
    88  // transition, such as amount of used gas, the receipt roots and the state root
    89  // itself. ValidateState returns a database batch if the validation was a success
    90  // otherwise nil and an error is returned.
    91  func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error {
    92  	header := block.Header()
    93  	if block.GasUsed() != usedGas {
    94  		return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
    95  	}
    96  	// Validate the received block's bloom with the one derived from the generated receipts.
    97  	// For valid blocks this should always validate to true.
    98  	rbloom := types.CreateBloom(receipts)
    99  	if rbloom != header.Bloom {
   100  		return fmt.Errorf("invalid bloom (remote: %x  local: %x)", header.Bloom, rbloom)
   101  	}
   102  	// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
   103  	receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
   104  	if receiptSha != header.ReceiptHash {
   105  		return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
   106  	}
   107  	// Validate the state root against the received state root and throw
   108  	// an error if they don't match.
   109  	if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
   110  		return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
   111  	}
   112  	return nil
   113  }
   114  
   115  // CalcGasLimit computes the gas limit of the next block after parent. It aims
   116  // to keep the baseline gas above the provided floor, and increase it towards the
   117  // ceil if the blocks are full. If the ceil is exceeded, it will always decrease
   118  // the gas allowance.
   119  func CalcGasLimit(parentGasUsed, parentGasLimit, gasFloor, gasCeil uint64) uint64 {
   120  	// contrib = (parentGasUsed * 3 / 2) / 1024
   121  	contrib := (parentGasUsed + parentGasUsed/2) / params.GasLimitBoundDivisor
   122  
   123  	// decay = parentGasLimit / 1024 -1
   124  	decay := parentGasLimit/params.GasLimitBoundDivisor - 1
   125  
   126  	/*
   127  		strategy: gasLimit of block-to-mine is set based on parent's
   128  		gasUsed value.  if parentGasUsed > parentGasLimit * (2/3) then we
   129  		increase it, otherwise lower it (or leave it unchanged if it's right
   130  		at that usage) the amount increased/decreased depends on how far away
   131  		from parentGasLimit * (2/3) parentGasUsed is.
   132  	*/
   133  	limit := parentGasLimit - decay + contrib
   134  	if limit < params.MinGasLimit {
   135  		limit = params.MinGasLimit
   136  	}
   137  	// If we're outside our allowed gas range, we try to hone towards them
   138  	if limit < gasFloor {
   139  		limit = parentGasLimit + decay
   140  		if limit > gasFloor {
   141  			limit = gasFloor
   142  		}
   143  	} else if limit > gasCeil {
   144  		limit = parentGasLimit - decay
   145  		if limit < gasCeil {
   146  			limit = gasCeil
   147  		}
   148  	}
   149  	return limit
   150  }