execution

package
v0.1.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2026 License: GPL-3.0 Imports: 5 Imported by: 0

Documentation

Index

Constants

View Source
const (
	LegacyTxType     = 0
	AccessListTxType = 1
	DynamicFeeTxType = 2
	BlobTxType       = 3
)

Transaction type constants matching go-ethereum values.

Variables

This section is empty.

Functions

func SanitizeGasCost added in v0.1.5

func SanitizeGasCost(log *StructLog)

SanitizeGasCost detects and corrects corrupted gasCost values from Erigon's debug_traceTransaction RPC.

Bug: Erigon has an unsigned integer underflow bug in gas.go:callGas() where `availableGas - base` underflows when availableGas < base, producing huge corrupted values (e.g., 18158513697557845033).

Detection: gasCost can never legitimately exceed the available gas at that opcode. If gasCost > Gas, the value is corrupted.

Correction: Set gasCost = Gas (all available gas consumed), matching Reth's behavior for failed CALL opcodes.

func SanitizeStructLogs added in v0.1.5

func SanitizeStructLogs(logs []StructLog)

SanitizeStructLogs applies gas cost sanitization to all structlogs. This corrects corrupted values from Erigon's unsigned integer underflow bug.

Types

type Address added in v0.1.5

type Address [20]byte

Address represents a 20-byte Ethereum address.

func (Address) Hex added in v0.1.5

func (a Address) Hex() string

Hex returns the hex string representation of the address with checksum.

func (Address) String added in v0.1.5

func (a Address) String() string

String returns the hex string representation of the address.

type Block added in v0.1.5

type Block interface {
	// Number returns the block number.
	Number() *big.Int

	// Hash returns the block hash.
	Hash() Hash

	// ParentHash returns the parent block hash.
	ParentHash() Hash

	// BaseFee returns the base fee per gas (EIP-1559), or nil for pre-London blocks.
	BaseFee() *big.Int

	// Transactions returns all transactions in the block.
	Transactions() []Transaction
}

Block interface defines methods for accessing block data. Implementations are provided by data sources (RPC, embedded clients).

type Config

type Config struct {
	// The address of the Execution node to connect to
	NodeAddress string `yaml:"nodeAddress"`
	// NodeHeaders is a map of headers to send to the execution node.
	NodeHeaders map[string]string `yaml:"nodeHeaders"`
	// Name is the name of the execution node
	Name string `yaml:"name"`
}

func (*Config) Validate

func (c *Config) Validate() error

type DataSource added in v0.1.5

type DataSource interface {
	// BlockNumber returns the current block number.
	BlockNumber(ctx context.Context) (*uint64, error)

	// BlockByNumber returns the block at the given number.
	BlockByNumber(ctx context.Context, number *big.Int) (Block, error)

	// BlocksByNumbers returns blocks at the given numbers.
	// Returns blocks up to the first not-found (contiguous only).
	BlocksByNumbers(ctx context.Context, numbers []*big.Int) ([]Block, error)

	// BlockReceipts returns all receipts for the block at the given number.
	BlockReceipts(ctx context.Context, number *big.Int) ([]Receipt, error)

	// TransactionReceipt returns the receipt for the transaction with the given hash.
	TransactionReceipt(ctx context.Context, hash string) (Receipt, error)

	// DebugTraceTransaction returns the execution trace for the transaction.
	DebugTraceTransaction(ctx context.Context, hash string, blockNumber *big.Int, opts TraceOptions) (*TraceTransaction, error)

	// ChainID returns the chain ID.
	ChainID() int64

	// ClientType returns the client type/version string.
	ClientType() string

	// IsSynced returns true if the data source is fully synced.
	IsSynced() bool
}

DataSource is the interface host applications implement to provide execution data directly without JSON-RPC. This enables embedding execution-processor as a library within an execution client.

All methods must be safe for concurrent calls from multiple goroutines. Context cancellation should be respected for all I/O operations.

The interface uses abstract types (Block, Transaction, Receipt) instead of go-ethereum types to avoid CGO dependencies. Host applications should implement these interfaces with their own types.

Example implementation:

type MyDataSource struct {
    client *MyExecutionClient
}

func (ds *MyDataSource) BlockNumber(ctx context.Context) (*uint64, error) {
    num := ds.client.CurrentBlock()
    return &num, nil
}

type EmbeddedNode added in v0.1.5

type EmbeddedNode struct {
	// contains filtered or unexported fields
}

EmbeddedNode implements Node by delegating to a DataSource. This allows host applications to provide execution data directly without going through JSON-RPC, eliminating serialization overhead.

Lifecycle:

  1. Create with NewEmbeddedNode(log, name, dataSource)
  2. Register OnReady callbacks (optional)
  3. Pool calls Start() (no-op for embedded)
  4. Host calls MarkReady() when DataSource is ready to serve data
  5. Callbacks execute in registration order, node becomes healthy in pool
  6. Pool calls Stop() on shutdown (no-op for embedded)

Thread-safety: All methods are safe for concurrent use.

func NewEmbeddedNode added in v0.1.5

func NewEmbeddedNode(log logrus.FieldLogger, name string, source DataSource) *EmbeddedNode

NewEmbeddedNode creates a new EmbeddedNode with the given DataSource.

Parameters:

  • log: Logger for node operations
  • name: Human-readable name for this node (used in logs and metrics)
  • source: DataSource implementation providing execution data

The returned node is not yet ready. Call MarkReady() when the DataSource is ready to serve data.

func (*EmbeddedNode) BlockByNumber added in v0.1.5

func (n *EmbeddedNode) BlockByNumber(ctx context.Context, number *big.Int) (Block, error)

BlockByNumber delegates to the DataSource.

func (*EmbeddedNode) BlockNumber added in v0.1.5

func (n *EmbeddedNode) BlockNumber(ctx context.Context) (*uint64, error)

BlockNumber delegates to the DataSource.

func (*EmbeddedNode) BlockReceipts added in v0.1.5

func (n *EmbeddedNode) BlockReceipts(ctx context.Context, number *big.Int) ([]Receipt, error)

BlockReceipts delegates to the DataSource.

func (*EmbeddedNode) BlocksByNumbers added in v0.1.5

func (n *EmbeddedNode) BlocksByNumbers(ctx context.Context, numbers []*big.Int) ([]Block, error)

BlocksByNumbers delegates to the DataSource.

func (*EmbeddedNode) ChainID added in v0.1.5

func (n *EmbeddedNode) ChainID() int64

ChainID delegates to the DataSource.

func (*EmbeddedNode) ClientType added in v0.1.5

func (n *EmbeddedNode) ClientType() string

ClientType delegates to the DataSource.

func (*EmbeddedNode) DebugTraceTransaction added in v0.1.5

func (n *EmbeddedNode) DebugTraceTransaction(
	ctx context.Context,
	hash string,
	blockNumber *big.Int,
	opts TraceOptions,
) (*TraceTransaction, error)

DebugTraceTransaction delegates to the DataSource.

OPTIMIZATION: In embedded mode, the tracer extracts CallToAddress directly for CALL-family opcodes instead of capturing the full stack. We explicitly set DisableStack: true to signal this intent, even though the tracer ignores this setting (it always uses the optimized path).

func (*EmbeddedNode) IsReady added in v0.1.5

func (n *EmbeddedNode) IsReady() bool

IsReady returns true if the node has been marked as ready.

func (*EmbeddedNode) IsSynced added in v0.1.5

func (n *EmbeddedNode) IsSynced() bool

IsSynced delegates to the DataSource.

func (*EmbeddedNode) MarkReady added in v0.1.5

func (n *EmbeddedNode) MarkReady(ctx context.Context) error

MarkReady is called by the host application when the DataSource is ready. This triggers all registered OnReady callbacks.

func (*EmbeddedNode) Name added in v0.1.5

func (n *EmbeddedNode) Name() string

Name returns the configured name for this node.

func (*EmbeddedNode) OnReady added in v0.1.5

func (n *EmbeddedNode) OnReady(_ context.Context, callback func(ctx context.Context) error)

OnReady registers a callback to be called when the node becomes ready.

func (*EmbeddedNode) Start added in v0.1.5

func (n *EmbeddedNode) Start(_ context.Context) error

Start is a no-op for EmbeddedNode. The host controls readiness via MarkReady().

func (*EmbeddedNode) Stop added in v0.1.5

func (n *EmbeddedNode) Stop(_ context.Context) error

Stop is a no-op for EmbeddedNode. The host manages the DataSource lifecycle.

func (*EmbeddedNode) TransactionReceipt added in v0.1.5

func (n *EmbeddedNode) TransactionReceipt(ctx context.Context, hash string) (Receipt, error)

TransactionReceipt delegates to the DataSource.

type ErigonResult

type ErigonResult struct {
	Gas         uint64  `json:"gas"`
	Failed      bool    `json:"failed"`
	ReturnValue *string `json:"returnValue"`
	// empty array on transfer
	StructLogs []ErigonStructLog `json:"structLogs"`
}

type ErigonStructLog

type ErigonStructLog struct {
	PC         uint32    `json:"pc"`
	Op         string    `json:"op"`
	Gas        uint64    `json:"gas"`
	GasCost    uint64    `json:"gasCost"`
	Depth      uint64    `json:"depth"`
	ReturnData []byte    `json:"returnData"`
	Refund     *uint64   `json:"refund,omitempty"`
	Error      *string   `json:"error,omitempty"`
	Stack      *[]string `json:"stack,omitempty"`
}

type Hash added in v0.1.5

type Hash [32]byte

Hash represents a 32-byte hash.

func (Hash) Hex added in v0.1.5

func (h Hash) Hex() string

Hex returns the hex string representation of the hash.

func (Hash) String added in v0.1.5

func (h Hash) String() string

String returns the hex string representation of the hash.

type Node

type Node interface {
	// Start initializes the node and begins any background operations.
	// For RPCNode, this establishes the RPC connection and starts health monitoring.
	// For EmbeddedNode, this is a no-op as the host controls the DataSource lifecycle.
	Start(ctx context.Context) error

	// Stop gracefully shuts down the node and releases resources.
	// Should be called when the node is no longer needed.
	Stop(ctx context.Context) error

	// OnReady registers a callback to be invoked when the node becomes ready.
	// For RPCNode, callbacks execute when the RPC connection is healthy.
	// For EmbeddedNode, callbacks execute when MarkReady is called by the host.
	// Multiple callbacks can be registered and will execute in registration order.
	OnReady(ctx context.Context, callback func(ctx context.Context) error)

	// BlockNumber returns the current block number from the execution client.
	BlockNumber(ctx context.Context) (*uint64, error)

	// BlockByNumber returns the block at the given number.
	BlockByNumber(ctx context.Context, number *big.Int) (Block, error)

	// BlocksByNumbers returns blocks at the given numbers using batch RPC.
	// Returns blocks up to the first not-found (contiguous only).
	// If a block is not found, the returned slice contains all blocks before that point.
	BlocksByNumbers(ctx context.Context, numbers []*big.Int) ([]Block, error)

	// BlockReceipts returns all receipts for the block at the given number.
	BlockReceipts(ctx context.Context, number *big.Int) ([]Receipt, error)

	// TransactionReceipt returns the receipt for the transaction with the given hash.
	TransactionReceipt(ctx context.Context, hash string) (Receipt, error)

	// DebugTraceTransaction returns the execution trace for the transaction.
	DebugTraceTransaction(ctx context.Context, hash string, blockNumber *big.Int, opts TraceOptions) (*TraceTransaction, error)

	// ChainID returns the chain ID reported by the execution client.
	ChainID() int64

	// ClientType returns the client type/version string (e.g., "geth/1.10.0").
	ClientType() string

	// IsSynced returns true if the execution client is fully synced.
	IsSynced() bool

	// Name returns the configured name for this node.
	Name() string
}

Node defines the interface for execution data providers.

Implementations include:

  • geth.RPCNode: connects to execution clients via JSON-RPC over HTTP
  • EmbeddedNode: receives data directly from host application via DataSource

All methods must be safe for concurrent use by multiple goroutines.

Lifecycle:

  1. Create node with appropriate constructor (geth.NewRPCNode or NewEmbeddedNode)
  2. Register OnReady callbacks before calling Start
  3. Call Start to begin initialization
  4. Node signals readiness by executing OnReady callbacks
  5. Call Stop for graceful shutdown

type Receipt added in v0.1.5

type Receipt interface {
	// Status returns the transaction status (1=success, 0=failure).
	Status() uint64

	// TxHash returns the transaction hash.
	TxHash() Hash

	// GasUsed returns the post-refund gas used by the transaction (what the user pays).
	//
	// EIP-7778 context: This remains post-refund. The EIP-7778 split between receipt gas
	// and block gas only affects ExecutionResult at the EVM layer; the Receipt's GasUsed
	// field and its derivation from CumulativeGasUsed are unchanged.
	GasUsed() uint64
}

Receipt interface defines methods for accessing transaction receipt data.

type StructLog

type StructLog struct {
	// PC is the program counter. Kept for RPC backward compatibility but not
	// populated in embedded mode (always 0).
	PC uint32 `json:"pc"`

	// Op is the opcode name (e.g., "PUSH1", "CALL", "SSTORE").
	Op string `json:"op"`

	// Gas is the remaining gas before this opcode executes.
	Gas uint64 `json:"gas"`

	// GasCost is the static gas cost of the opcode (may differ from actual GasUsed).
	GasCost uint64 `json:"gasCost"`

	// GasUsed is the actual gas consumed by this opcode.
	// In embedded mode: pre-computed by tracer using gas difference to next opcode.
	// In RPC mode: computed post-hoc by ComputeGasUsed(), this field will be 0.
	GasUsed uint64 `json:"gasUsed,omitempty"`

	// Depth is the call stack depth (1 = top-level, increases with CALL/CREATE).
	Depth uint64 `json:"depth"`

	// ReturnData contains the return data from the last CALL/STATICCALL/etc.
	ReturnData *string `json:"returnData"`

	// Refund is the gas refund counter value.
	Refund *uint64 `json:"refund,omitempty"`

	// Error contains any error message if the opcode failed.
	Error *string `json:"error,omitempty"`

	// Stack contains the EVM stack state (RPC mode only).
	// In embedded mode this is nil - use CallToAddress instead.
	Stack *[]string `json:"stack,omitempty"`

	// CallToAddress is the target address for CALL/STATICCALL/DELEGATECALL/CALLCODE.
	// In embedded mode: pre-extracted by tracer from stack[len-2].
	// In RPC mode: nil, extracted post-hoc from Stack by extractCallAddress().
	CallToAddress *string `json:"callToAddress,omitempty"`

	// MemorySize is the EVM memory size in bytes at the time this opcode executes.
	// Used to compute memory expansion gas between consecutive opcodes.
	// In embedded mode: captured by tracer from scope.MemoryData().
	// In RPC mode: 0 (not available).
	MemorySize uint32 `json:"memSize,omitempty"`

	// CallTransfersValue indicates whether a CALL/CALLCODE transfers non-zero ETH value.
	// True only for CALL/CALLCODE with value > 0 on the stack.
	// Used to normalize CALL gas for cold access detection.
	CallTransfersValue bool `json:"callTransfersValue,omitempty"`

	// ExtCodeCopySize is the size parameter for EXTCODECOPY opcodes.
	// Used to compute the copy cost component for cold access detection.
	ExtCodeCopySize uint32 `json:"extCodeCopySize,omitempty"`
}

StructLog represents a single EVM opcode execution trace entry.

This struct supports two operation modes:

  • RPC mode: Stack is populated for CALL opcodes, CallToAddress/GasUsed computed post-hoc
  • Embedded mode: CallToAddress/GasUsed pre-computed by tracer, Stack remains nil

The embedded mode optimizations eliminate ~99% of stack-related allocations and remove the post-processing GasUsed computation pass.

type TraceOptions added in v0.0.11

type TraceOptions struct {
	DisableStorage   bool
	DisableStack     bool
	DisableMemory    bool
	EnableReturnData bool
}

TraceOptions configures debug_traceTransaction parameters.

func DefaultTraceOptions added in v0.0.11

func DefaultTraceOptions() TraceOptions

DefaultTraceOptions returns standard options.

func StackTraceOptions added in v0.0.11

func StackTraceOptions() TraceOptions

StackTraceOptions returns options with stack enabled.

type TraceTransaction

type TraceTransaction struct {
	// Gas is the post-refund gas used by this transaction (what the user pays).
	// Set by the data source from the execution result or receipt's GasUsed.
	//
	// EIP-7778 context: After EIP-7778, Ethereum splits gas accounting into:
	//   - ReceiptGasUsed (post-refund): what the user pays, stored in receipts
	//   - BlockGasUsed (pre-refund): used for block gas limit accounting
	// This field carries the receipt (post-refund) value. The computeIntrinsicGas()
	// formula in structlog_agg depends on this being post-refund.
	Gas         uint64  `json:"gas"`
	Failed      bool    `json:"failed"`
	ReturnValue *string `json:"returnValue"`

	Structlogs []StructLog
}

TraceTransaction holds the result of a debug_traceTransaction call.

type Transaction added in v0.1.5

type Transaction interface {
	// Hash returns the transaction hash.
	Hash() Hash

	// Type returns the transaction type (0=legacy, 1=access list, 2=dynamic fee, 3=blob).
	Type() uint8

	// To returns the recipient address, or nil for contract creation.
	To() *Address

	// From returns the sender address.
	// This is computed by the data source using types.Sender() or equivalent.
	From() Address

	// Nonce returns the sender account nonce.
	Nonce() uint64

	// Gas returns the gas limit.
	Gas() uint64

	// GasPrice returns the gas price (for legacy transactions).
	GasPrice() *big.Int

	// GasTipCap returns the max priority fee per gas (EIP-1559).
	GasTipCap() *big.Int

	// GasFeeCap returns the max fee per gas (EIP-1559).
	GasFeeCap() *big.Int

	// Value returns the value transferred in wei.
	Value() *big.Int

	// Data returns the input data (calldata).
	Data() []byte

	// Size returns the encoded transaction size in bytes.
	Size() uint64

	// ChainId returns the chain ID, or nil for legacy transactions.
	ChainId() *big.Int

	// BlobGas returns the blob gas used (for blob transactions).
	BlobGas() uint64

	// BlobGasFeeCap returns the max blob fee per gas (for blob transactions).
	BlobGasFeeCap() *big.Int

	// BlobHashes returns the versioned hashes (for blob transactions).
	BlobHashes() []Hash
}

Transaction interface defines methods for accessing transaction data. The From() method returns the sender address, computed by the data source using its own crypto implementation (avoiding go-ethereum crypto imports).

Directories

Path Synopsis
Package geth provides go-ethereum adapters for the execution interfaces.
Package geth provides go-ethereum adapters for the execution interfaces.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL