Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions pkg/processor/transaction/structlog/columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ type Columns struct {
TransactionFailed proto.ColBool
TransactionReturnValue *proto.ColNullable[string]
Index proto.ColUInt32
ProgramCounter proto.ColUInt32
Operation proto.ColStr
Gas proto.ColUInt64
GasCost proto.ColUInt64
Expand Down Expand Up @@ -67,7 +66,6 @@ func (c *Columns) Append(
txFailed bool,
txReturnValue *string,
index uint32,
pc uint32,
op string,
gas uint64,
gasCost uint64,
Expand All @@ -90,7 +88,6 @@ func (c *Columns) Append(
c.TransactionFailed.Append(txFailed)
c.TransactionReturnValue.Append(nullableStr(txReturnValue))
c.Index.Append(index)
c.ProgramCounter.Append(pc)
c.Operation.Append(op)
c.Gas.Append(gas)
c.GasCost.Append(gasCost)
Expand All @@ -116,7 +113,6 @@ func (c *Columns) Reset() {
c.TransactionFailed.Reset()
c.TransactionReturnValue.Reset()
c.Index.Reset()
c.ProgramCounter.Reset()
c.Operation.Reset()
c.Gas.Reset()
c.GasCost.Reset()
Expand All @@ -143,7 +139,6 @@ func (c *Columns) Input() proto.Input {
{Name: "transaction_failed", Data: &c.TransactionFailed},
{Name: "transaction_return_value", Data: c.TransactionReturnValue},
{Name: "index", Data: &c.Index},
{Name: "program_counter", Data: &c.ProgramCounter},
{Name: "operation", Data: &c.Operation},
{Name: "gas", Data: &c.Gas},
{Name: "gas_cost", Data: &c.GasCost},
Expand Down
20 changes: 20 additions & 0 deletions pkg/processor/transaction/structlog/gas_cost.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,26 @@ func hasPrecomputedGasUsed(structlogs []execution.StructLog) bool {
return structlogs[0].GasUsed > 0
}

// hasPrecomputedCreateAddresses detects whether CREATE/CREATE2 addresses are pre-computed.
//
// In embedded mode, the tracer resolves CREATE addresses inline when the constructor
// returns, populating CallToAddress. In RPC mode, CallToAddress is nil for CREATE
// opcodes and must be computed post-hoc using ComputeCreateAddresses().
//
// Returns true if any CREATE/CREATE2 opcode has CallToAddress pre-populated.
func hasPrecomputedCreateAddresses(structlogs []execution.StructLog) bool {
for i := range structlogs {
op := structlogs[i].Op
if op == OpcodeCREATE || op == OpcodeCREATE2 {
// If any CREATE has CallToAddress populated, tracer pre-computed.
return structlogs[i].CallToAddress != nil
}
}

// No CREATE/CREATE2 opcodes found - doesn't matter, return false to use standard path.
return false
}

// ComputeGasUsed calculates the actual gas consumed for each structlog using
// the difference between consecutive gas values at the same depth level.
//
Expand Down
42 changes: 42 additions & 0 deletions pkg/processor/transaction/structlog/gas_cost_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,48 @@ func TestHasPrecomputedGasUsed_WithoutGasUsed(t *testing.T) {
assert.False(t, hasPrecomputedGasUsed(structlogs))
}

// =============================================================================
// hasPrecomputedCreateAddresses Tests
// =============================================================================

func TestHasPrecomputedCreateAddresses_Empty(t *testing.T) {
assert.False(t, hasPrecomputedCreateAddresses(nil))
assert.False(t, hasPrecomputedCreateAddresses([]execution.StructLog{}))
}

func TestHasPrecomputedCreateAddresses_NoCreate(t *testing.T) {
structlogs := []execution.StructLog{
{Op: "PUSH1"},
{Op: "CALL"},
}
assert.False(t, hasPrecomputedCreateAddresses(structlogs))
}

func TestHasPrecomputedCreateAddresses_CreateWithAddress(t *testing.T) {
addr := "0x1234567890123456789012345678901234567890"
structlogs := []execution.StructLog{
{Op: "PUSH1"},
{Op: "CREATE", CallToAddress: &addr},
}
assert.True(t, hasPrecomputedCreateAddresses(structlogs))
}

func TestHasPrecomputedCreateAddresses_CreateWithoutAddress(t *testing.T) {
structlogs := []execution.StructLog{
{Op: "PUSH1"},
{Op: "CREATE", CallToAddress: nil},
}
assert.False(t, hasPrecomputedCreateAddresses(structlogs))
}

func TestHasPrecomputedCreateAddresses_Create2WithAddress(t *testing.T) {
addr := "0x1234567890123456789012345678901234567890"
structlogs := []execution.StructLog{
{Op: "CREATE2", CallToAddress: &addr},
}
assert.True(t, hasPrecomputedCreateAddresses(structlogs))
}

// =============================================================================
// ComputeGasUsed Tests
// =============================================================================
Expand Down
1 change: 0 additions & 1 deletion pkg/processor/transaction/structlog/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ func (p *Processor) insertStructlogs(ctx context.Context, structlogs []Structlog
sl.TransactionFailed,
sl.TransactionReturnValue,
sl.Index,
sl.ProgramCounter,
sl.Operation,
sl.Gas,
sl.GasCost,
Expand Down
14 changes: 6 additions & 8 deletions pkg/processor/transaction/structlog/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ func TestStructlogCountReturn(t *testing.T) {
mockTrace.Failed, // txFailed
mockTrace.ReturnValue, // txReturnValue
uint32(i), // index
structLog.PC, // pc
structLog.Op, // op
structLog.Gas, // gas
structLog.GasCost, // gasCost
Expand Down Expand Up @@ -235,7 +234,6 @@ func TestMemoryManagement(t *testing.T) {
false, // txFailed
nil, // txReturnValue
uint32(i), // index
uint32(i*2), // pc
"SSTORE", // op
uint64(21000-i), // gas
uint64(5000), // gasCost
Expand Down Expand Up @@ -347,7 +345,7 @@ func TestChunkProcessing(t *testing.T) {
for i := 0; i < tt.inputSize; i++ {
cols.Append(
now, uint64(i), "0xtest", uint32(0), uint64(21000), false, nil,
uint32(i), uint32(i), "PUSH1", uint64(20000), uint64(3), uint64(3), uint64(3), uint64(1),
uint32(i), "PUSH1", uint64(20000), uint64(3), uint64(3), uint64(3), uint64(1),
nil, nil, nil, nil, uint32(0), []uint32{}, "test",
)
}
Expand Down Expand Up @@ -397,7 +395,7 @@ func TestColumnsAppendAndReset(t *testing.T) {

cols.Append(
now, uint64(100), "0xabc", uint32(0), uint64(21000), false, &str,
uint32(0), uint32(100), "PUSH1", uint64(20000), uint64(3), uint64(3), uint64(3), uint64(1),
uint32(0), "PUSH1", uint64(20000), uint64(3), uint64(3), uint64(3), uint64(1),
nil, &num, nil, nil, uint32(0), []uint32{}, "mainnet",
)

Expand All @@ -407,7 +405,7 @@ func TestColumnsAppendAndReset(t *testing.T) {
for i := 0; i < 99; i++ {
cols.Append(
now, uint64(100), "0xabc", uint32(0), uint64(21000), false, nil,
uint32(i+1), uint32(100), "PUSH1", uint64(20000), uint64(3), uint64(3), uint64(3), uint64(1),
uint32(i+1), "PUSH1", uint64(20000), uint64(3), uint64(3), uint64(3), uint64(1),
nil, nil, nil, nil, uint32(0), []uint32{}, "mainnet",
)
}
Expand All @@ -423,10 +421,10 @@ func TestColumnsInput(t *testing.T) {
cols := transaction_structlog.NewColumns()
input := cols.Input()

// Verify all 22 columns are present
assert.Len(t, input, 22)
// Verify all 21 columns are present
assert.Len(t, input, 21)
assert.Equal(t, "updated_date_time", input[0].Name)
assert.Equal(t, "meta_network_name", input[21].Name)
assert.Equal(t, "meta_network_name", input[20].Name)
}

// Tests from tasks_test.go
Expand Down
26 changes: 17 additions & 9 deletions pkg/processor/transaction/structlog/transaction_processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ type Structlog struct {
TransactionFailed bool `json:"transaction_failed"`
TransactionReturnValue *string `json:"transaction_return_value"`
Index uint32 `json:"index"`
ProgramCounter uint32 `json:"program_counter"`
Operation string `json:"operation"`

// Gas is the remaining gas before this opcode executes.
Expand Down Expand Up @@ -183,8 +182,15 @@ func (p *Processor) ProcessTransaction(ctx context.Context, block execution.Bloc
// Initialize call frame tracker
callTracker := NewCallTracker()

// Pre-compute CREATE/CREATE2 addresses from trace stack
createAddresses := ComputeCreateAddresses(trace.Structlogs)
// Check if CREATE/CREATE2 addresses are pre-computed by the tracer (embedded mode).
// In embedded mode, skip the multi-pass ComputeCreateAddresses scan.
precomputedCreateAddresses := hasPrecomputedCreateAddresses(trace.Structlogs)

var createAddresses map[int]*string
if !precomputedCreateAddresses {
// Pre-compute CREATE/CREATE2 addresses from trace stack (RPC mode)
createAddresses = ComputeCreateAddresses(trace.Structlogs)
}

chunkSize := p.config.ChunkSize
if chunkSize == 0 {
Expand Down Expand Up @@ -235,7 +241,6 @@ func (p *Processor) ProcessTransaction(ctx context.Context, block execution.Bloc
trace.Failed,
trace.ReturnValue,
uint32(i), //nolint:gosec // index is bounded by structlogs length
sl.PC,
sl.Op,
sl.Gas,
sl.GasCost,
Expand Down Expand Up @@ -277,7 +282,6 @@ func (p *Processor) ProcessTransaction(ctx context.Context, block execution.Bloc
trace.Failed,
trace.ReturnValue,
uint32(i), //nolint:gosec // Same index as parent CALL
uint32(0), // No PC for EOA
"", // Empty = synthetic EOA frame
uint64(0), // Gas
uint64(0), // GasCost
Expand Down Expand Up @@ -542,8 +546,14 @@ func (p *Processor) ExtractStructlogs(ctx context.Context, block execution.Block
// Initialize call frame tracker
callTracker := NewCallTracker()

// Pre-compute CREATE/CREATE2 addresses from trace stack
createAddresses := ComputeCreateAddresses(trace.Structlogs)
// Check if CREATE/CREATE2 addresses are pre-computed by the tracer (embedded mode).
precomputedCreateAddresses := hasPrecomputedCreateAddresses(trace.Structlogs)

var createAddresses map[int]*string
if !precomputedCreateAddresses {
// Pre-compute CREATE/CREATE2 addresses from trace stack (RPC mode)
createAddresses = ComputeCreateAddresses(trace.Structlogs)
}

// Pre-allocate slice for better memory efficiency
structlogs = make([]Structlog, 0, len(trace.Structlogs))
Expand Down Expand Up @@ -571,7 +581,6 @@ func (p *Processor) ExtractStructlogs(ctx context.Context, block execution.Block
TransactionFailed: trace.Failed,
TransactionReturnValue: trace.ReturnValue,
Index: uint32(i), //nolint:gosec // index is bounded by structlogs length
ProgramCounter: structLog.PC,
Operation: structLog.Op,
Gas: structLog.Gas,
GasCost: structLog.GasCost,
Expand Down Expand Up @@ -621,7 +630,6 @@ func (p *Processor) ExtractStructlogs(ctx context.Context, block execution.Block
TransactionFailed: trace.Failed,
TransactionReturnValue: trace.ReturnValue,
Index: uint32(i), //nolint:gosec // Same index as parent CALL
ProgramCounter: 0, // No PC for EOA
Operation: "", // Empty = synthetic EOA frame
Gas: 0,
GasCost: 0,
Expand Down