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  }