mirror of
https://github.com/luxfi/geth.git
synced 2026-10-30 15:05:39 +00:00
PrecompileEnvironment.CallIndex() exposes each precompile invocation's ordinal within the current tx (evm.precompileCallIndex, reset to 0 at tx start, incremented once per NewPrecompileEnvironment — for every invocation, including reverted sub-frames and STATICCALLs). It is a pure function of (tx, ordinal), so it is identical across deterministic re-execution and distinct between two invocations in one tx. The DEX 0x9999 seam binds CallIndex into DeriveIntentID so two same-params swaps in one tx get distinct, collision-free cross-chain object ids while replaying byte-identically network-wide.
194 lines
5.2 KiB
Go
194 lines
5.2 KiB
Go
// Copyright (C) 2020-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package vm
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
|
|
"github.com/holiman/uint256"
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/luxfi/geth/core/types"
|
|
"github.com/luxfi/geth/params"
|
|
)
|
|
|
|
// PrecompileEnvironment is the interface for precompile execution environment.
|
|
// This is a Lux extension for stateful precompiles that need access to
|
|
// the execution context.
|
|
type PrecompileEnvironment interface {
|
|
// BlockHeader returns the block header
|
|
BlockHeader() (*types.Header, error)
|
|
// Rules returns the chain rules
|
|
Rules() params.Rules
|
|
// BlockNumber returns the current block number
|
|
BlockNumber() *big.Int
|
|
// BlockTime returns the current block timestamp
|
|
BlockTime() uint64
|
|
// Addresses returns the caller and contract addresses
|
|
Addresses() PrecompileAddresses
|
|
// ReadOnly returns whether the environment is read-only
|
|
ReadOnly() bool
|
|
// ChainConfig returns the chain config
|
|
ChainConfig() *params.ChainConfig
|
|
// StateDB returns the state database
|
|
StateDB() StateDB
|
|
// ReadOnlyState returns a read-only state view
|
|
ReadOnlyState() StateDB
|
|
// UseGas deducts gas from the available gas
|
|
UseGas(gas uint64) bool
|
|
// Gas returns the available gas
|
|
Gas() uint64
|
|
// Call executes a call to another contract
|
|
Call(addr common.Address, input []byte, gas uint64, value *big.Int, opts ...CallOption) ([]byte, uint64, error)
|
|
// ConsensusContext returns the consensus context with chain ID/network ID for warp
|
|
ConsensusContext() context.Context
|
|
// CallIndex returns this precompile invocation's index within the current
|
|
// transaction (0-based, monotonic per tx). A stateful precompile uses it to
|
|
// derive a per-invocation content-addressed identity that is unique even when
|
|
// the same precompile is called multiple times in one transaction.
|
|
CallIndex() uint32
|
|
}
|
|
|
|
// CallOption is an option for Call
|
|
type CallOption func(*CallConfig)
|
|
|
|
// CallConfig holds call configuration
|
|
type CallConfig struct {
|
|
ProxyCaller bool
|
|
}
|
|
|
|
// WithUNSAFECallerAddressProxying returns an option to proxy caller address
|
|
func WithUNSAFECallerAddressProxying() CallOption {
|
|
return func(c *CallConfig) {
|
|
c.ProxyCaller = true
|
|
}
|
|
}
|
|
|
|
// PrecompileAddresses holds the caller and self addresses for a precompile call
|
|
type PrecompileAddresses struct {
|
|
Caller common.Address
|
|
Self common.Address
|
|
}
|
|
|
|
// evmPrecompileEnv implements PrecompileEnvironment using the EVM
|
|
type evmPrecompileEnv struct {
|
|
evm *EVM
|
|
caller common.Address
|
|
self common.Address
|
|
gas uint64
|
|
readOnly bool
|
|
// callIndex is this invocation's ordinal within the current tx, captured at
|
|
// construction (one increment of evm.precompileCallIndex per invocation).
|
|
callIndex uint32
|
|
}
|
|
|
|
// NewPrecompileEnvironment creates a PrecompileEnvironment from EVM context. It
|
|
// captures and advances the per-tx precompile call index so each invocation gets
|
|
// a distinct, monotonically increasing CallIndex() within the transaction.
|
|
func NewPrecompileEnvironment(evm *EVM, caller, self common.Address, gas uint64, readOnly bool) PrecompileEnvironment {
|
|
idx := evm.precompileCallIndex
|
|
evm.precompileCallIndex++
|
|
return &evmPrecompileEnv{
|
|
evm: evm,
|
|
caller: caller,
|
|
self: self,
|
|
gas: gas,
|
|
readOnly: readOnly,
|
|
callIndex: idx,
|
|
}
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) BlockHeader() (*types.Header, error) {
|
|
return &types.Header{
|
|
Number: e.evm.Context.BlockNumber,
|
|
Time: e.evm.Context.Time,
|
|
Coinbase: e.evm.Context.Coinbase,
|
|
GasLimit: e.evm.Context.GasLimit,
|
|
BaseFee: e.evm.Context.BaseFee,
|
|
}, nil
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) Rules() params.Rules {
|
|
return e.evm.chainRules
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) BlockNumber() *big.Int {
|
|
return new(big.Int).Set(e.evm.Context.BlockNumber)
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) BlockTime() uint64 {
|
|
return e.evm.Context.Time
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) Addresses() PrecompileAddresses {
|
|
return PrecompileAddresses{
|
|
Caller: e.caller,
|
|
Self: e.self,
|
|
}
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) ReadOnly() bool {
|
|
return e.readOnly
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) ChainConfig() *params.ChainConfig {
|
|
return e.evm.chainConfig
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) StateDB() StateDB {
|
|
return e.evm.StateDB
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) ReadOnlyState() StateDB {
|
|
return e.evm.StateDB
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) UseGas(gas uint64) bool {
|
|
if e.gas < gas {
|
|
return false
|
|
}
|
|
e.gas -= gas
|
|
return true
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) Gas() uint64 {
|
|
return e.gas
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) Call(addr common.Address, input []byte, gas uint64, value *big.Int, opts ...CallOption) ([]byte, uint64, error) {
|
|
// Handle call options
|
|
cfg := &CallConfig{}
|
|
for _, opt := range opts {
|
|
opt(cfg)
|
|
}
|
|
|
|
caller := e.self
|
|
if cfg.ProxyCaller {
|
|
caller = e.caller
|
|
}
|
|
|
|
// Convert *big.Int to *uint256.Int
|
|
var val *uint256.Int
|
|
if value != nil {
|
|
val = new(uint256.Int)
|
|
val.SetFromBig(value)
|
|
} else {
|
|
val = new(uint256.Int)
|
|
}
|
|
|
|
ret, remainingGas, err := e.evm.Call(caller, addr, input, gas, val)
|
|
return ret, remainingGas, err
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) ConsensusContext() context.Context {
|
|
if e.evm.Context.ConsensusContext != nil {
|
|
return e.evm.Context.ConsensusContext
|
|
}
|
|
return context.Background()
|
|
}
|
|
|
|
func (e *evmPrecompileEnv) CallIndex() uint32 {
|
|
return e.callIndex
|
|
}
|