github.com/MetalBlockchain/subnet-evm@v0.4.9/plugin/evm/block_verification.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package evm 5 6 import ( 7 "fmt" 8 "math/big" 9 10 "github.com/ethereum/go-ethereum/common" 11 12 "github.com/MetalBlockchain/subnet-evm/core/types" 13 "github.com/MetalBlockchain/subnet-evm/params" 14 "github.com/MetalBlockchain/subnet-evm/trie" 15 ) 16 17 var legacyMinGasPrice = big.NewInt(params.MinGasPrice) 18 19 type BlockValidator interface { 20 SyntacticVerify(b *Block, rules params.Rules) error 21 } 22 23 type blockValidator struct{} 24 25 func NewBlockValidator() BlockValidator { 26 return &blockValidator{} 27 } 28 29 func (v blockValidator) SyntacticVerify(b *Block, rules params.Rules) error { 30 if b == nil || b.ethBlock == nil { 31 return errInvalidBlock 32 } 33 34 // Skip verification of the genesis block since it 35 // should already be marked as accepted 36 if b.ethBlock.Hash() == b.vm.genesisHash { 37 return nil 38 } 39 40 // Perform block and header sanity checks 41 ethHeader := b.ethBlock.Header() 42 if ethHeader.Number == nil || !ethHeader.Number.IsUint64() { 43 return errInvalidBlock 44 } 45 if ethHeader.Difficulty == nil || !ethHeader.Difficulty.IsUint64() || 46 ethHeader.Difficulty.Uint64() != 1 { 47 return fmt.Errorf("invalid difficulty: %d", ethHeader.Difficulty) 48 } 49 if ethHeader.Nonce.Uint64() != 0 { 50 return fmt.Errorf( 51 "expected nonce to be 0 but got %d: %w", 52 ethHeader.Nonce.Uint64(), errInvalidNonce, 53 ) 54 } 55 56 if ethHeader.MixDigest != (common.Hash{}) { 57 return fmt.Errorf("invalid mix digest: %v", ethHeader.MixDigest) 58 } 59 60 if rules.IsSubnetEVM { 61 expectedExtraDataSize := params.ExtraDataSize 62 if headerExtraDataSize := len(ethHeader.Extra); headerExtraDataSize != expectedExtraDataSize { 63 return fmt.Errorf( 64 "expected header ExtraData to be %d but got %d", 65 expectedExtraDataSize, headerExtraDataSize, 66 ) 67 } 68 } else { 69 headerExtraDataSize := uint64(len(ethHeader.Extra)) 70 if headerExtraDataSize > params.MaximumExtraDataSize { 71 return fmt.Errorf( 72 "expected header ExtraData to be <= %d but got %d", 73 params.MaximumExtraDataSize, headerExtraDataSize, 74 ) 75 } 76 } 77 78 if rules.IsSubnetEVM { 79 if ethHeader.BaseFee == nil { 80 return errNilBaseFeeSubnetEVM 81 } 82 if bfLen := ethHeader.BaseFee.BitLen(); bfLen > 256 { 83 return fmt.Errorf("too large base fee: bitlen %d", bfLen) 84 } 85 } 86 87 // Check that the tx hash in the header matches the body 88 txsHash := types.DeriveSha(b.ethBlock.Transactions(), new(trie.Trie)) 89 if txsHash != ethHeader.TxHash { 90 return fmt.Errorf("invalid txs hash %v does not match calculated txs hash %v", ethHeader.TxHash, txsHash) 91 } 92 // Check that the uncle hash in the header matches the body 93 uncleHash := types.CalcUncleHash(b.ethBlock.Uncles()) 94 if uncleHash != ethHeader.UncleHash { 95 return fmt.Errorf("invalid uncle hash %v does not match calculated uncle hash %v", ethHeader.UncleHash, uncleHash) 96 } 97 98 // Block must not have any uncles 99 if len(b.ethBlock.Uncles()) > 0 { 100 return errUnclesUnsupported 101 } 102 // Block must not be empty 103 txs := b.ethBlock.Transactions() 104 if len(txs) == 0 { 105 return errEmptyBlock 106 } 107 108 if !rules.IsSubnetEVM { 109 // Make sure that all the txs have the correct fee set. 110 for _, tx := range txs { 111 if tx.GasPrice().Cmp(legacyMinGasPrice) < 0 { 112 return fmt.Errorf("block contains tx %s with gas price too low (%d < %d)", tx.Hash(), tx.GasPrice(), legacyMinGasPrice) 113 } 114 } 115 } 116 117 // Make sure the block isn't too far in the future 118 blockTimestamp := b.ethBlock.Time() 119 if maxBlockTime := uint64(b.vm.clock.Time().Add(maxFutureBlockTime).Unix()); blockTimestamp > maxBlockTime { 120 return fmt.Errorf("block timestamp is too far in the future: %d > allowed %d", blockTimestamp, maxBlockTime) 121 } 122 123 if rules.IsSubnetEVM { 124 switch { 125 // Make sure BlockGasCost is not nil 126 // NOTE: ethHeader.BlockGasCost correctness is checked in header verification 127 case ethHeader.BlockGasCost == nil: 128 return errNilBlockGasCostSubnetEVM 129 case !ethHeader.BlockGasCost.IsUint64(): 130 return fmt.Errorf("too large blockGasCost: %d", ethHeader.BlockGasCost) 131 } 132 } 133 return nil 134 }