github.com/dominant-strategies/go-quai@v0.28.2/core/block_validator.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"fmt"
    21  	"time"
    22  
    23  	"github.com/dominant-strategies/go-quai/common"
    24  	"github.com/dominant-strategies/go-quai/consensus"
    25  	"github.com/dominant-strategies/go-quai/core/state"
    26  	"github.com/dominant-strategies/go-quai/core/types"
    27  	"github.com/dominant-strategies/go-quai/log"
    28  	"github.com/dominant-strategies/go-quai/params"
    29  	"github.com/dominant-strategies/go-quai/trie"
    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  	hc     *HeaderChain        // HeaderChain
    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, headerChain *HeaderChain, engine consensus.Engine) *BlockValidator {
    44  	validator := &BlockValidator{
    45  		config: config,
    46  		engine: engine,
    47  		hc:     headerChain,
    48  	}
    49  	return validator
    50  }
    51  
    52  // ValidateBody validates the given block's uncles and verifies 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(block *types.Block) error {
    56  	nodeCtx := common.NodeLocation.Context()
    57  	// Check whether the block's known, and if not, that it's linkable
    58  	if nodeCtx == common.ZONE_CTX && v.hc.ProcessingState() {
    59  		if v.hc.bc.processor.HasBlockAndState(block.Hash(), block.NumberU64()) {
    60  			return ErrKnownBlock
    61  		}
    62  	}
    63  	header := block.Header()
    64  	// Subordinate manifest must match ManifestHash in subordinate context, _iff_
    65  	// we have a subordinate (i.e. if we are not a zone)
    66  	if nodeCtx != common.ZONE_CTX {
    67  		// Region nodes should have body with zero length txs and etxs
    68  		if len(block.Transactions()) != 0 {
    69  			return fmt.Errorf("region body has non zero transactions")
    70  		}
    71  		if len(block.ExtTransactions()) != 0 {
    72  			return fmt.Errorf("region body has non zero etx transactions")
    73  		}
    74  		if len(block.Uncles()) != 0 {
    75  			return fmt.Errorf("region body has non zero uncles")
    76  		}
    77  		subManifestHash := types.DeriveSha(block.SubManifest(), trie.NewStackTrie(nil))
    78  		if subManifestHash == types.EmptyRootHash || subManifestHash != header.ManifestHash(nodeCtx+1) {
    79  			// If we have a subordinate chain, it is impossible for the subordinate manifest to be empty
    80  			return ErrBadSubManifest
    81  		}
    82  	} else {
    83  		// Header validity is known at this point, check the uncles and transactions
    84  		if err := v.engine.VerifyUncles(v.hc, block); err != nil {
    85  			return err
    86  		}
    87  		if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash() {
    88  			return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash())
    89  		}
    90  		if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash() {
    91  			return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash())
    92  		}
    93  		if hash := types.DeriveSha(block.ExtTransactions(), trie.NewStackTrie(nil)); hash != header.EtxHash() {
    94  			return fmt.Errorf("external transaction root hash mismatch: have %x, want %x", hash, header.EtxHash())
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  // ValidateState validates the various changes that happen after a state
   101  // transition, such as amount of used gas, the receipt roots and the state root
   102  // itself. ValidateState returns a database batch if the validation was a success
   103  // otherwise nil and an error is returned.
   104  func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error {
   105  	start := time.Now()
   106  	header := types.CopyHeader(block.Header())
   107  	time1 := common.PrettyDuration(time.Since(start))
   108  	if block.GasUsed() != usedGas {
   109  		return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
   110  	}
   111  	time2 := common.PrettyDuration(time.Since(start))
   112  	time3 := common.PrettyDuration(time.Since(start))
   113  	// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
   114  	receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
   115  	if receiptSha != header.ReceiptHash() {
   116  		return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash(), receiptSha)
   117  	}
   118  	time4 := common.PrettyDuration(time.Since(start))
   119  	// Validate the state root against the received state root and throw
   120  	// an error if they don't match.
   121  	if root := statedb.IntermediateRoot(true); header.Root() != root {
   122  		return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root(), root)
   123  	}
   124  	time5 := common.PrettyDuration(time.Since(start))
   125  	// Collect ETXs emitted from each successful transaction
   126  	var emittedEtxs types.Transactions
   127  	for _, receipt := range receipts {
   128  		if receipt.Status == types.ReceiptStatusSuccessful {
   129  			emittedEtxs = append(emittedEtxs, receipt.Etxs...)
   130  		}
   131  	}
   132  	time6 := common.PrettyDuration(time.Since(start))
   133  	// Confirm the ETXs emitted by the transactions in this block exactly match the
   134  	// ETXs given in the block body
   135  	if etxHash := types.DeriveSha(emittedEtxs, trie.NewStackTrie(nil)); etxHash != header.EtxHash() {
   136  		return fmt.Errorf("invalid etx hash (remote: %x local: %x)", header.EtxHash(), etxHash)
   137  	}
   138  	log.Debug("times during validate state:", "t1:", time1, "t2:", time2, "t3:", time3, "t4:", time4, "t5:", time5, "t6:", time6)
   139  	return nil
   140  }
   141  
   142  // CalcGasLimit computes the gas limit of the next block after parent. It aims
   143  // to keep the baseline gas close to the provided target, and increase it towards
   144  // the target if the baseline gas is lower.
   145  func CalcGasLimit(parent *types.Header, gasCeil uint64) uint64 {
   146  
   147  	parentGasLimit := parent.GasLimit()
   148  
   149  	delta := parentGasLimit/params.GasLimitBoundDivisor - 1
   150  	limit := parentGasLimit
   151  
   152  	var desiredLimit uint64
   153  	percentGasUsed := parent.GasUsed() * 100 / parent.GasLimit()
   154  	if percentGasUsed > params.PercentGasUsedThreshold {
   155  		desiredLimit = CalcGasCeil(parent.NumberU64(), gasCeil)
   156  		if desiredLimit > gasCeil {
   157  			desiredLimit = gasCeil
   158  		}
   159  		if limit+delta > desiredLimit {
   160  			return desiredLimit
   161  		} else {
   162  			return limit + delta
   163  		}
   164  	} else {
   165  		desiredLimit = params.MinGasLimit
   166  		if limit-delta/2 < desiredLimit {
   167  			return desiredLimit
   168  		} else {
   169  			return limit - delta/2
   170  		}
   171  	}
   172  }
   173  
   174  func CalcGasCeil(blockNumber uint64, gasCeil uint64) uint64 {
   175  	if blockNumber < params.GasLimitStepOneBlockThreshold {
   176  		return gasCeil / 4
   177  	} else if blockNumber < params.GasLimitStepTwoBlockThreshold {
   178  		return gasCeil / 2
   179  	} else if blockNumber < params.GasLimitStepThreeBlockThreshold {
   180  		return gasCeil * 3 / 4
   181  	}
   182  	return gasCeil
   183  }