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 }