mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
- Update vm dependency to v1.0.18 - Remove internal log package in favor of luxfi/log - Migrate prometheus to gatherer package
128 lines
4.8 KiB
Go
128 lines
4.8 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package core
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/evm/params"
|
|
"github.com/luxfi/evm/params/extras"
|
|
"github.com/luxfi/evm/precompile/precompileconfig"
|
|
"github.com/luxfi/evm/predicate"
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/luxfi/geth/core/types"
|
|
log "github.com/luxfi/log"
|
|
"github.com/luxfi/math/set"
|
|
)
|
|
|
|
var ErrMissingPredicateContext = errors.New("missing predicate context")
|
|
|
|
// CheckPredicates verifies the predicates of [tx] and returns the result. Returning an error invalidates the block.
|
|
func CheckPredicates(rules params.Rules, predicateContext *precompileconfig.PredicateContext, tx *types.Transaction) (map[common.Address][]byte, error) {
|
|
// Check that the transaction can cover its IntrinsicGas (including the gas required by the predicate) before
|
|
// verifying the predicate.
|
|
intrinsicGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, rules)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if tx.Gas() < intrinsicGas {
|
|
return nil, fmt.Errorf("%w for predicate verification (%d) < intrinsic gas (%d)", ErrIntrinsicGas, tx.Gas(), intrinsicGas)
|
|
}
|
|
|
|
predicateResults := make(map[common.Address][]byte)
|
|
|
|
// Get the RulesExtra which contains Predicaters
|
|
rulesExtra := params.GetRulesExtra(rules)
|
|
|
|
// Short circuit early if there are no precompile predicates to verify
|
|
if !rulesExtra.PredicatersExist {
|
|
return predicateResults, nil
|
|
}
|
|
|
|
// Build extrasRules for PreparePredicateStorageSlots
|
|
extrasRules := &extras.Rules{
|
|
Predicaters: rulesExtra.Predicaters,
|
|
LuxRules: rulesExtra.LuxRules,
|
|
}
|
|
|
|
// Prepare the predicate storage slots from the transaction's access list
|
|
predicateArguments := predicate.PreparePredicateStorageSlots(extrasRules, tx.AccessList())
|
|
|
|
// If there are no predicates to verify, return early and skip requiring the proposervm block
|
|
// context to be populated.
|
|
if len(predicateArguments) == 0 {
|
|
return predicateResults, nil
|
|
}
|
|
|
|
if predicateContext == nil || predicateContext.ProposerVMBlockCtx == nil {
|
|
return nil, ErrMissingPredicateContext
|
|
}
|
|
|
|
for address, predicates := range predicateArguments {
|
|
// Since [address] is only added to [predicateArguments] when there's a valid predicate in the ruleset
|
|
// there's no need to check if the predicate exists here.
|
|
predicaterContract := rulesExtra.Predicaters[address]
|
|
bitset := set.NewBits()
|
|
for i, pred := range predicates {
|
|
if err := predicaterContract.VerifyPredicate(predicateContext, pred); err != nil {
|
|
log.Debug("predicate verification failed", "tx", tx.Hash(), "address", address, "index", i, "err", err)
|
|
bitset.Add(i)
|
|
}
|
|
}
|
|
res := bitset.Bytes()
|
|
log.Debug("predicate verify", "tx", tx.Hash(), "address", address, "res", res)
|
|
predicateResults[address] = res
|
|
}
|
|
return predicateResults, nil
|
|
}
|
|
|
|
// CheckPredicatesWithRules verifies the predicates of [tx] with full extras.Rules support
|
|
func CheckPredicatesWithRules(rules params.Rules, extrasRules *extras.Rules, predicateContext *precompileconfig.PredicateContext, tx *types.Transaction) (map[common.Address][]byte, error) {
|
|
// Check that the transaction can cover its IntrinsicGas (including the gas required by the predicate) before
|
|
// verifying the predicate.
|
|
intrinsicGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, rules)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if tx.Gas() < intrinsicGas {
|
|
return nil, fmt.Errorf("%w for predicate verification (%d) < intrinsic gas (%d)", ErrIntrinsicGas, tx.Gas(), intrinsicGas)
|
|
}
|
|
|
|
predicateResults := make(map[common.Address][]byte)
|
|
// Short circuit early if there are no precompile predicates to verify
|
|
if !extrasRules.PredicatersExist() {
|
|
return predicateResults, nil
|
|
}
|
|
|
|
// Prepare the predicate storage slots from the transaction's access list
|
|
predicateArguments := predicate.PreparePredicateStorageSlots(extrasRules, tx.AccessList())
|
|
|
|
// If there are no predicates to verify, return early and skip requiring the proposervm block
|
|
// context to be populated.
|
|
if len(predicateArguments) == 0 {
|
|
return predicateResults, nil
|
|
}
|
|
|
|
if predicateContext == nil || predicateContext.ProposerVMBlockCtx == nil {
|
|
return nil, ErrMissingPredicateContext
|
|
}
|
|
|
|
for address, predicates := range predicateArguments {
|
|
// Since [address] is only added to [predicateArguments] when there's a valid predicate in the ruleset
|
|
// there's no need to check if the predicate exists here.
|
|
predicaterContract := extrasRules.Predicaters[address]
|
|
bitset := set.NewBits()
|
|
for i, predicate := range predicates {
|
|
if err := predicaterContract.VerifyPredicate(predicateContext, predicate); err != nil {
|
|
bitset.Add(i)
|
|
}
|
|
}
|
|
res := bitset.Bytes()
|
|
log.Debug("predicate verify", "tx", tx.Hash(), "address", address, "res", res)
|
|
predicateResults[address] = res
|
|
}
|
|
return predicateResults, nil
|
|
}
|