github.com/amazechain/amc@v0.1.3/internal/block_validator.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package internal 18 19 import ( 20 "fmt" 21 "github.com/amazechain/amc/common/block" 22 "github.com/amazechain/amc/common/crypto/bls" 23 "github.com/amazechain/amc/common/hexutil" 24 "github.com/amazechain/amc/common/transaction" 25 "github.com/amazechain/amc/common/types" 26 "github.com/amazechain/amc/internal/consensus" 27 "github.com/amazechain/amc/log" 28 "github.com/amazechain/amc/modules/state" 29 "github.com/amazechain/amc/params" 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 bc *BlockChain // Canonical block chain 38 engine consensus.Engine // Consensus engine used for validating 39 config *params.ChainConfig 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 engine: engine, 46 bc: blockchain, 47 config: config, 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(b block.IBlock) error { 56 // Check Signature valid 57 vfs := b.Body().Verifier() 58 addrs := make([]types.Address, len(vfs)) 59 ss := make([]bls.PublicKey, len(vfs)) 60 for i, p := range vfs { 61 addrs[i] = p.Address 62 blsP, err := bls.PublicKeyFromBytes(p.PublicKey[:]) 63 if nil != err { 64 return err 65 } 66 ss[i] = blsP 67 } 68 69 if v.config.IsBeijing(b.Number64().Uint64()) { 70 header := b.Header().(*block.Header) 71 sig, err := bls.SignatureFromBytes(header.Signature[:]) 72 if nil != err { 73 return err 74 } 75 if !sig.FastAggregateVerify(ss, header.Root) { 76 log.Warn("AggSignature verify falied", "blockNr", b.Number64().Uint64(), "Signature", hexutil.Encode(header.Signature[:]), "Root", hexutil.Encode(header.Root[:])) 77 for i, addr := range addrs { 78 log.Warn("", "address", addr.String(), "publicKey", hexutil.Encode(ss[i].Marshal())) 79 } 80 return fmt.Errorf("AggSignature verify falied") 81 } 82 } 83 84 // Check whether the block's known, and if not, that it's linkable 85 if v.bc.HasBlockAndState(b.Hash(), b.Number64().Uint64()) { 86 return ErrKnownBlock 87 } 88 89 if hash := DeriveSha(transaction.Transactions(b.Transactions())); hash != b.TxHash() { 90 return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, b.TxHash()) 91 } 92 93 if !v.bc.HasBlockAndState(b.ParentHash(), b.Number64().Uint64()-1) { 94 if !v.bc.HasBlock(b.ParentHash(), b.Number64().Uint64()-1) { 95 return ErrUnknownAncestor 96 } 97 return ErrPrunedAncestor 98 } 99 return nil 100 } 101 102 // ValidateState validates the various changes that happen after a state 103 // transition, such as amount of used gas, the receipt roots and the state root 104 // itself. ValidateState returns a database batch if the validation was a success 105 // otherwise nil and an error is returned. 106 func (v *BlockValidator) ValidateState(iBlock block.IBlock, statedb *state.IntraBlockState, receipts block.Receipts, usedGas uint64) error { 107 header := iBlock.Header().(*block.Header) 108 if header.GasUsed != usedGas { 109 return fmt.Errorf("invalid gas used (remote: %d local: %d)", header.GasUsed, usedGas) 110 } 111 112 rbloom := block.CreateBloom(receipts) 113 if rbloom != header.Bloom { 114 return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) 115 } 116 117 receiptSha := DeriveSha(receipts) 118 if receiptSha != header.ReceiptHash { 119 for i, tx := range iBlock.Body().Transactions() { 120 log.Warn("tx", "index", i, "from", tx.From(), "GasUsed", receipts[i].GasUsed) 121 for index2, l := range receipts[i].Logs { 122 log.Warn("tx logs", "index", index2, "address", l.Address, "topic", l.Topics[0], "data", hexutil.Encode(l.Data)) 123 } 124 125 } 126 return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) 127 } 128 // Validate the state root against the received state root and throw 129 // an error if they don't match. 130 // TODO 替换 emptyroot 131 if root := statedb.IntermediateRoot(); header.StateRoot() != root { 132 return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) 133 } 134 return nil 135 }