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 }