mirror of
https://github.com/luxfi/evmgpu.git
synced 2026-10-30 16:57:11 +00:00
135 lines
4.1 KiB
Go
135 lines
4.1 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package evm
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/luxfi/geth/common"
|
|
|
|
"github.com/luxfi/evmgpu/params"
|
|
"github.com/luxfi/evmgpu/plugin/evm/customtypes"
|
|
"github.com/luxfi/evmgpu/plugin/evm/header"
|
|
"github.com/luxfi/evmgpu/plugin/evm/upgrade/legacy"
|
|
"github.com/luxfi/geth/core/types"
|
|
"github.com/luxfi/geth/trie"
|
|
)
|
|
|
|
var legacyMinGasPrice = big.NewInt(legacy.BaseFee)
|
|
|
|
type BlockValidator interface {
|
|
SyntacticVerify(b *Block, rules params.Rules) error
|
|
}
|
|
|
|
type blockValidator struct{}
|
|
|
|
func NewBlockValidator() BlockValidator {
|
|
return &blockValidator{}
|
|
}
|
|
|
|
func (v blockValidator) SyntacticVerify(b *Block, rules params.Rules) error {
|
|
rulesExtra := params.GetRulesExtra(rules)
|
|
if b == nil || b.ethBlock == nil {
|
|
return errInvalidBlock
|
|
}
|
|
ethHeader := b.ethBlock.Header()
|
|
blockHash := b.ethBlock.Hash()
|
|
|
|
// Skip verification of the genesis block since it should already be marked as accepted.
|
|
if blockHash == b.vm.genesisHash {
|
|
return nil
|
|
}
|
|
|
|
// Perform block and header sanity checks
|
|
if ethHeader.Number == nil || !ethHeader.Number.IsUint64() {
|
|
return errInvalidBlock
|
|
}
|
|
if ethHeader.Difficulty == nil || !ethHeader.Difficulty.IsUint64() ||
|
|
ethHeader.Difficulty.Uint64() != 1 {
|
|
return fmt.Errorf("invalid difficulty: %d", ethHeader.Difficulty)
|
|
}
|
|
if ethHeader.Nonce.Uint64() != 0 {
|
|
return fmt.Errorf(
|
|
"expected nonce to be 0 but got %d: %w",
|
|
ethHeader.Nonce.Uint64(), errInvalidNonce,
|
|
)
|
|
}
|
|
|
|
if ethHeader.MixDigest != (common.Hash{}) {
|
|
return fmt.Errorf("invalid mix digest: %v", ethHeader.MixDigest)
|
|
}
|
|
|
|
// Verify the extra data is well-formed.
|
|
if err := header.VerifyExtra(rulesExtra.LuxRules, ethHeader.Extra); err != nil {
|
|
return err
|
|
}
|
|
|
|
if rulesExtra.IsEVM {
|
|
if ethHeader.BaseFee == nil {
|
|
return errNilBaseFeeEVM
|
|
}
|
|
if bfLen := ethHeader.BaseFee.BitLen(); bfLen > 256 {
|
|
return fmt.Errorf("too large base fee: bitlen %d", bfLen)
|
|
}
|
|
}
|
|
|
|
// Check that the tx hash in the header matches the body
|
|
txsHash := types.DeriveSha(b.ethBlock.Transactions(), trie.NewStackTrie(nil))
|
|
if txsHash != ethHeader.TxHash {
|
|
return fmt.Errorf("invalid txs hash %v does not match calculated txs hash %v", ethHeader.TxHash, txsHash)
|
|
}
|
|
// Check that the uncle hash in the header matches the body
|
|
uncleHash := types.CalcUncleHash(b.ethBlock.Uncles())
|
|
if uncleHash != ethHeader.UncleHash {
|
|
return fmt.Errorf("invalid uncle hash %v does not match calculated uncle hash %v", ethHeader.UncleHash, uncleHash)
|
|
}
|
|
|
|
// Block must not have any uncles
|
|
if len(b.ethBlock.Uncles()) > 0 {
|
|
return errUnclesUnsupported
|
|
}
|
|
|
|
// Block must not be empty (unless automining/dev mode is enabled)
|
|
txs := b.ethBlock.Transactions()
|
|
if len(txs) == 0 && !b.vm.config.EnableAutomining {
|
|
return errEmptyBlock
|
|
}
|
|
|
|
if !rulesExtra.IsEVM {
|
|
// Make sure that all the txs have the correct fee set.
|
|
for _, tx := range txs {
|
|
if tx.GasPrice().Cmp(legacyMinGasPrice) < 0 {
|
|
return fmt.Errorf("block contains tx %s with gas price too low (%d < %d)", tx.Hash(), tx.GasPrice(), legacyMinGasPrice)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make sure the block isn't too far in the future
|
|
blockTimestamp := b.ethBlock.Time()
|
|
if maxBlockTime := uint64(b.vm.clock.Time().Add(maxFutureBlockTime).Unix()); blockTimestamp > maxBlockTime {
|
|
return fmt.Errorf("block timestamp is too far in the future: %d > allowed %d", blockTimestamp, maxBlockTime)
|
|
}
|
|
|
|
if rulesExtra.IsEVM {
|
|
blockGasCost := customtypes.GetHeaderExtra(ethHeader).BlockGasCost
|
|
switch {
|
|
// Make sure BlockGasCost is not nil
|
|
// NOTE: ethHeader.BlockGasCost correctness is checked in header verification
|
|
case blockGasCost == nil:
|
|
return errNilBlockGasCostEVM
|
|
case !blockGasCost.IsUint64():
|
|
return fmt.Errorf("too large blockGasCost: %d", blockGasCost)
|
|
}
|
|
}
|
|
|
|
// Lux does NOT use Ethereum beacon chain or blob transactions
|
|
// Skip Cancun-specific field requirements for pre-Cancun blocks
|
|
// Only reject if blob gas was actually used (which shouldn't happen on Lux)
|
|
if ethHeader.BlobGasUsed != nil && *ethHeader.BlobGasUsed > 0 {
|
|
return fmt.Errorf("blobs not enabled on lux networks: used %d blob gas", *ethHeader.BlobGasUsed)
|
|
}
|
|
return nil
|
|
}
|