core: extend TxContext to have all data related to TXPARAM* family

This commit is contained in:
lightclient 2026-01-05 06:55:18 -07:00
parent c051a69bfb
commit 4e1fc9bc25
No known key found for this signature in database
GPG key ID: 657913021EF45A6A
5 changed files with 143 additions and 23 deletions

View file

@ -25,6 +25,8 @@ import (
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
@ -82,13 +84,55 @@ func NewEVMTxContext(msg *Message) vm.TxContext {
Origin: msg.From, Origin: msg.From,
GasPrice: new(big.Int).Set(msg.GasPrice), GasPrice: new(big.Int).Set(msg.GasPrice),
BlobHashes: msg.BlobHashes, BlobHashes: msg.BlobHashes,
// EIP-7701 fields
TxType: msg.TxType,
Nonce: msg.Nonce,
Sender: msg.Sender,
Deployer: msg.Deployer,
Paymaster: msg.Paymaster,
SenderExecutionData: msg.Data,
SenderExecutionGas: msg.GasLimit,
} }
if msg.BlobGasFeeCap != nil { if msg.BlobGasFeeCap != nil {
ctx.BlobFeeCap = new(big.Int).Set(msg.BlobGasFeeCap) ctx.BlobFeeCap = new(big.Int).Set(msg.BlobGasFeeCap)
} }
if msg.GasTipCap != nil {
ctx.MaxPriorityFeePerGas = new(big.Int).Set(msg.GasTipCap)
}
if msg.GasFeeCap != nil {
ctx.MaxFeePerGas = new(big.Int).Set(msg.GasFeeCap)
}
// Compute AccessListHash
if len(msg.AccessList) > 0 {
ctx.AccessListHash = rlpHash(msg.AccessList)
}
// Compute AuthorizationListHash
if len(msg.SetCodeAuthorizations) > 0 {
ctx.AuthorizationListHash = rlpHash(msg.SetCodeAuthorizations)
}
// TxHashForSignature is nil for AA transactions
// For non-AA transactions, we leave it nil as we don't have access to the
// original transaction here. If needed, this should be set by the caller.
if !msg.Abstract {
// TODO: compute TxHashForSignature for non-AA transactions if needed
}
return ctx return ctx
} }
// rlpHash computes the keccak256 hash of the RLP encoding of x.
func rlpHash(x interface{}) common.Hash {
encoded, err := rlp.EncodeToBytes(x)
if err != nil {
return common.Hash{}
}
return crypto.Keccak256Hash(encoded)
}
// GetHashFn returns a GetHashFunc which retrieves header hashes by number // GetHashFn returns a GetHashFunc which retrieves header hashes by number
func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash {
// Cache will initially contain [refHash.parent], // Cache will initially contain [refHash.parent],

View file

@ -146,6 +146,7 @@ func toWordSize(size uint64) uint64 {
// A Message contains the data derived from a single transaction that is relevant to state // A Message contains the data derived from a single transaction that is relevant to state
// processing. // processing.
type Message struct { type Message struct {
TxType uint8
To *common.Address To *common.Address
From common.Address From common.Address
Nonce uint64 Nonce uint64
@ -187,6 +188,7 @@ type Message struct {
// TransactionToMessage converts a transaction into a Message. // TransactionToMessage converts a transaction into a Message.
func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) { func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) {
msg := &Message{ msg := &Message{
TxType: tx.Type(),
Nonce: tx.Nonce(), Nonce: tx.Nonce(),
GasLimit: tx.Gas(), GasLimit: tx.Gas(),
GasPrice: new(big.Int).Set(tx.GasPrice()), GasPrice: new(big.Int).Set(tx.GasPrice()),

View file

@ -599,82 +599,128 @@ func opAcceptRole(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
type paramLoader func(*EVM, uint64) []byte type paramLoader func(*EVM, uint64) []byte
// uint64ToBytes32 converts a uint64 to a 32-byte big-endian slice.
func uint64ToBytes32(v uint64) []byte {
return common.LeftPadBytes(new(uint256.Int).SetUint64(v).Bytes(), 32)
}
func loadType(evm *EVM, id uint64) []byte { func loadType(evm *EVM, id uint64) []byte {
// TODO: plumb in type to TxContext return uint64ToBytes32(uint64(evm.TxContext.TxType))
return nil
} }
func loadNonce(evm *EVM, id uint64) []byte { func loadNonce(evm *EVM, id uint64) []byte {
// TODO: plumb in nonce to TxContext return uint64ToBytes32(evm.TxContext.Nonce)
return nil
} }
func loadSender(evm *EVM, id uint64) []byte { func loadSender(evm *EVM, id uint64) []byte {
return nil return common.LeftPadBytes(evm.TxContext.Origin.Bytes(), 32)
} }
func loadSenderValidationData(evm *EVM, id uint64) []byte { func loadSenderValidationData(evm *EVM, id uint64) []byte {
return nil if evm.TxContext.Sender == nil {
return nil
}
return evm.TxContext.Sender.Data
} }
func loadDeployer(evm *EVM, id uint64) []byte { func loadDeployer(evm *EVM, id uint64) []byte {
return nil // 0 or 32 bytes: return nil when not set
if evm.TxContext.Deployer == nil {
return nil
}
return common.LeftPadBytes(evm.TxContext.Deployer.Target.Bytes(), 32)
} }
func loadDeployerData(evm *EVM, id uint64) []byte { func loadDeployerData(evm *EVM, id uint64) []byte {
return nil // dynamic, default empty array
if evm.TxContext.Deployer == nil {
return nil
}
return evm.TxContext.Deployer.Data
} }
func loadPaymaster(evm *EVM, id uint64) []byte { func loadPaymaster(evm *EVM, id uint64) []byte {
return nil // 0 or 32 bytes: return nil when not set
if evm.TxContext.Paymaster == nil {
return nil
}
return common.LeftPadBytes(evm.TxContext.Paymaster.Target.Bytes(), 32)
} }
func loadPaymasterData(evm *EVM, id uint64) []byte { func loadPaymasterData(evm *EVM, id uint64) []byte {
return nil // dynamic, default empty array
if evm.TxContext.Paymaster == nil {
return nil
}
return evm.TxContext.Paymaster.Data
} }
func loadSenderExecutionData(evm *EVM, id uint64) []byte { func loadSenderExecutionData(evm *EVM, id uint64) []byte {
return nil return evm.TxContext.SenderExecutionData
} }
func loadMaxPriorityFeePerGas(evm *EVM, id uint64) []byte { func loadMaxPriorityFeePerGas(evm *EVM, id uint64) []byte {
return nil if evm.TxContext.MaxPriorityFeePerGas == nil {
return make([]byte, 32)
}
return common.LeftPadBytes(evm.TxContext.MaxPriorityFeePerGas.Bytes(), 32)
} }
func loadMaxFeePerGas(evm *EVM, id uint64) []byte { func loadMaxFeePerGas(evm *EVM, id uint64) []byte {
return nil if evm.TxContext.MaxFeePerGas == nil {
return make([]byte, 32)
}
return common.LeftPadBytes(evm.TxContext.MaxFeePerGas.Bytes(), 32)
}
func loadSenderValidationGas(evm *EVM, id uint64) []byte {
if evm.TxContext.Sender == nil {
return uint64ToBytes32(0)
}
return uint64ToBytes32(evm.TxContext.Sender.Gas)
} }
func loadPaymasterValidationGas(evm *EVM, id uint64) []byte { func loadPaymasterValidationGas(evm *EVM, id uint64) []byte {
return nil // 32 bytes, default 0
if evm.TxContext.Paymaster == nil {
return uint64ToBytes32(0)
}
return uint64ToBytes32(evm.TxContext.Paymaster.Gas)
} }
func loadSenderExecutionGas(evm *EVM, id uint64) []byte { func loadSenderExecutionGas(evm *EVM, id uint64) []byte {
return nil return uint64ToBytes32(evm.TxContext.SenderExecutionGas)
} }
func loadPaymasterPostOpGas(evm *EVM, id uint64) []byte { func loadPaymasterPostOpGas(evm *EVM, id uint64) []byte {
return nil // 32 bytes, default 0
if evm.TxContext.Paymaster == nil {
return uint64ToBytes32(0)
}
return uint64ToBytes32(evm.TxContext.Paymaster.PostOpGas)
} }
func loadAccessListHash(evm *EVM, id uint64) []byte { func loadAccessListHash(evm *EVM, id uint64) []byte {
return nil return evm.TxContext.AccessListHash[:]
} }
func loadAuthorizationListHash(evm *EVM, id uint64) []byte { func loadAuthorizationListHash(evm *EVM, id uint64) []byte {
return nil return evm.TxContext.AuthorizationListHash[:]
} }
func loadExecutionStatus(evm *EVM, id uint64) []byte { func loadExecutionStatus(evm *EVM, id uint64) []byte {
return nil return uint64ToBytes32(evm.TxContext.ExecutionStatus)
} }
func loadExecutionGasUsed(evm *EVM, id uint64) []byte { func loadExecutionGasUsed(evm *EVM, id uint64) []byte {
return nil return uint64ToBytes32(evm.TxContext.ExecutionGasUsed)
} }
func loadTxHashForSignature(evm *EVM, id uint64) []byte { func loadTxHashForSignature(evm *EVM, id uint64) []byte {
return nil if evm.TxContext.TxHashForSignature == nil {
return nil
}
return evm.TxContext.TxHashForSignature[:]
} }
// idToParam is a map of identifier to transaction parameter loader. // idToParam is a map of identifier to transaction parameter loader.
@ -690,7 +736,7 @@ var idToParam = map[uint64]paramLoader{
0x08: loadSenderExecutionData, 0x08: loadSenderExecutionData,
0x0B: loadMaxPriorityFeePerGas, 0x0B: loadMaxPriorityFeePerGas,
0x0C: loadMaxFeePerGas, 0x0C: loadMaxFeePerGas,
0x0D: loadSenderValidationData, 0x0D: loadSenderValidationGas,
0x0E: loadPaymasterValidationGas, 0x0E: loadPaymasterValidationGas,
0x0F: loadSenderExecutionGas, 0x0F: loadSenderExecutionGas,
0x10: loadPaymasterPostOpGas, 0x10: loadPaymasterPostOpGas,

View file

@ -80,7 +80,29 @@ type TxContext struct {
BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set
AccessEvents *state.AccessEvents // Capture all state accesses for this tx AccessEvents *state.AccessEvents // Capture all state accesses for this tx
// TODO: add EIP-7701 fields // EIP-7701: Transaction parameters for TXPARAM* opcodes
TxType uint8 // 0x00: transaction type
Nonce uint64 // 0x01: transaction nonce
// Origin is sender (0x02)
// AA authorization structs (nil for non-AA txs)
Sender *types.AbstractAuthorization // 0x03: Data, 0x0D: Gas
Deployer *types.AbstractAuthorization // 0x04: Target, 0x05: Data
Paymaster *types.PaymasterAuthorization // 0x06: Target, 0x07: Data, 0x0E: Gas, 0x10: PostOpGas
SenderExecutionData []byte // 0x08: execution calldata
SenderExecutionGas uint64 // 0x0F: execution gas limit
MaxPriorityFeePerGas *big.Int // 0x0B: max priority fee per gas
MaxFeePerGas *big.Int // 0x0C: max fee per gas
// Hashes (computed when creating TxContext)
AccessListHash common.Hash // 0x11: hash of access list
AuthorizationListHash common.Hash // 0x12: hash of authorization list
TxHashForSignature *common.Hash // 0xff: hash for signature (nil for AA txs)
// Mutable execution state (set during AA tx processing)
ExecutionStatus uint64 // 0xf1: execution result status
ExecutionGasUsed uint64 // 0xf2: gas used during execution
} }
// EVM is the Ethereum Virtual Machine base object and provides // EVM is the Ethereum Virtual Machine base object and provides

View file

@ -27,6 +27,12 @@ func NewEnv(cfg *Config) *vm.EVM {
GasPrice: cfg.GasPrice, GasPrice: cfg.GasPrice,
BlobHashes: cfg.BlobHashes, BlobHashes: cfg.BlobHashes,
BlobFeeCap: cfg.BlobFeeCap, BlobFeeCap: cfg.BlobFeeCap,
// EIP-7701: Set basic fields for non-AA transactions
// AA-specific fields (Sender, Deployer, Paymaster) remain nil
MaxPriorityFeePerGas: cfg.GasPrice,
MaxFeePerGas: cfg.GasPrice,
SenderExecutionGas: cfg.GasLimit,
} }
blockContext := vm.BlockContext{ blockContext := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,