github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/block_validator.go (about) 1 package core 2 3 import ( 4 "fmt" 5 6 "github.com/quickchainproject/quickchain/consensus" 7 "github.com/quickchainproject/quickchain/core/state" 8 "github.com/quickchainproject/quickchain/core/types" 9 "github.com/quickchainproject/quickchain/params" 10 ) 11 12 // BlockValidator is responsible for validating block headers, uncles and 13 // processed state. 14 // 15 // BlockValidator implements Validator. 16 type BlockValidator struct { 17 config *params.ChainConfig // Chain configuration options 18 bc *BlockChain // Canonical block chain 19 engine consensus.Engine // Consensus engine used for validating 20 } 21 22 // NewBlockValidator returns a new block validator which is safe for re-use 23 func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator { 24 validator := &BlockValidator{ 25 config: config, 26 engine: engine, 27 bc: blockchain, 28 } 29 return validator 30 } 31 32 // ValidateBody validates the given block's uncles and verifies the the block 33 // header's transaction and uncle roots. The headers are assumed to be already 34 // validated at this point. 35 func (v *BlockValidator) ValidateBody(block *types.Block) error { 36 // Check whether the block's known, and if not, that it's linkable 37 if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { 38 return ErrKnownBlock 39 } 40 if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { 41 if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { 42 return consensus.ErrUnknownAncestor 43 } 44 return consensus.ErrPrunedAncestor 45 } 46 // Header validity is known at this point, check the uncles and transactions 47 header := block.Header() 48 if err := v.engine.VerifyUncles(v.bc, block); err != nil { 49 return err 50 } 51 if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash { 52 return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash) 53 } 54 if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash { 55 return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) 56 } 57 return nil 58 } 59 60 // ValidateState validates the various changes that happen after a state 61 // transition, such as amount of used gas, the receipt roots and the state root 62 // itself. ValidateState returns a database batch if the validation was a success 63 // otherwise nil and an error is returned. 64 func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { 65 header := block.Header() 66 if block.GasUsed() != usedGas { 67 return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) 68 } 69 // Validate the received block's bloom with the one derived from the generated receipts. 70 // For valid blocks this should always validate to true. 71 rbloom := types.CreateBloom(receipts) 72 if rbloom != header.Bloom { 73 return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) 74 } 75 // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) 76 receiptSha := types.DeriveSha(receipts) 77 if receiptSha != header.ReceiptHash { 78 return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) 79 } 80 // Validate the state root against the received state root and throw 81 // an error if they don't match. 82 if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { 83 return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) 84 } 85 return nil 86 } 87 88 func (v *BlockValidator) ValidateDposState(block *types.Block) error { 89 header := block.Header() 90 localRoot := block.DposCtx().Root() 91 remoteRoot := header.DposContext.Root() 92 if remoteRoot != localRoot { 93 return fmt.Errorf("invalid dpos root (remote: %x local: %x)", remoteRoot, localRoot) 94 } 95 return nil 96 } 97 98 // CalcGasLimit computes the gas limit of the next block after parent. 99 // This is miner strategy, not consensus protocol. 100 func CalcGasLimit(parent *types.Block) uint64 { 101 // contrib = (parentGasUsed * 3 / 2) / 1024 102 contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor 103 104 // decay = parentGasLimit / 1024 -1 105 decay := parent.GasLimit()/params.GasLimitBoundDivisor - 1 106 107 /* 108 strategy: gasLimit of block-to-mine is set based on parent's 109 gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we 110 increase it, otherwise lower it (or leave it unchanged if it's right 111 at that usage) the amount increased/decreased depends on how far away 112 from parentGasLimit * (2/3) parentGasUsed is. 113 */ 114 limit := parent.GasLimit() - decay + contrib 115 if limit < params.MinGasLimit { 116 limit = params.MinGasLimit 117 } 118 // however, if we're now below the target (TargetGasLimit) we increase the 119 // limit as much as we can (parentGasLimit / 1024 -1) 120 if limit < params.TargetGasLimit { 121 limit = parent.GasLimit() + decay 122 if limit > params.TargetGasLimit { 123 limit = params.TargetGasLimit 124 } 125 } 126 return limit 127 }