github.com/klaytn/klaytn@v1.12.1/blockchain/block_validator.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/block_validator.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package blockchain 22 23 import ( 24 "fmt" 25 26 "github.com/klaytn/klaytn/blockchain/state" 27 "github.com/klaytn/klaytn/blockchain/types" 28 "github.com/klaytn/klaytn/consensus" 29 "github.com/klaytn/klaytn/params" 30 ) 31 32 // BlockValidator is responsible for validating block headers and 33 // processed state. 34 // 35 // BlockValidator implements Validator. 36 type BlockValidator struct { 37 config *params.ChainConfig // Chain configuration options 38 bc *BlockChain // Canonical block chain 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, blockchain *BlockChain, engine consensus.Engine) *BlockValidator { 44 validator := &BlockValidator{ 45 config: config, 46 engine: engine, 47 bc: blockchain, 48 } 49 return validator 50 } 51 52 // ValidateBody verifies the block 53 // header's transaction. The headers are assumed to be already 54 // validated at this point. 55 func (v *BlockValidator) ValidateBody(block *types.Block) error { 56 // Check whether the block's known, and if not, that it's linkable 57 if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { 58 return ErrKnownBlock 59 } 60 if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { 61 if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { 62 logger.Error("unknown ancestor (ValidateBody)", "num", block.NumberU64(), 63 "hash", block.Hash(), "parentHash", block.ParentHash()) 64 return consensus.ErrUnknownAncestor 65 } 66 return consensus.ErrPrunedAncestor 67 } 68 // Header validity is known at this point, check the transactions 69 header := block.Header() 70 if hash := types.DeriveSha(block.Transactions(), block.Number()); hash != header.TxHash { 71 return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) 72 } 73 baseFee := block.Header().BaseFee 74 if baseFee != nil { 75 for _, tx := range block.Transactions() { 76 if baseFee.Cmp(tx.GasPrice()) > 0 { 77 return fmt.Errorf("Invalid GasPrice: txHash %x, GasPrice %d, BaseFee %d", tx.Hash(), tx.GasPrice(), baseFee) 78 } 79 } 80 } 81 return nil 82 } 83 84 // ValidateState validates the various changes that happen after a state 85 // transition, such as amount of used gas, the receipt roots and the state root 86 // itself. ValidateState returns a database batch if the validation was a success 87 // otherwise nil and an error is returned. 88 func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { 89 header := block.Header() 90 if block.GasUsed() != usedGas { 91 return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) 92 } 93 // Validate the received block's bloom with the one derived from the generated receipts. 94 // For valid blocks this should always validate to true. 95 rbloom := types.CreateBloom(receipts) 96 if rbloom != header.Bloom { 97 return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) 98 } 99 // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) 100 receiptSha := types.DeriveSha(receipts, block.Number()) 101 if receiptSha != header.ReceiptHash { 102 return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) 103 } 104 // Validate the state root against the received state root and throw 105 // an error if they don't match. 106 if root := statedb.IntermediateRoot(true); header.Root != root { 107 return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) 108 } 109 return nil 110 }