@@ -575,6 +575,54 @@ func TestFrameAggregator_SuccessfulTransaction_HasRefundAndIntrinsic(t *testing.
575575 // Note: might be nil if computed value is 0, so we just check the logic is exercised
576576}
577577
578+ func TestFrameAggregator_RevertWithoutOpcodeError (t * testing.T ) {
579+ // Test that REVERT transactions are correctly detected as failed even when
580+ // the REVERT opcode itself has no error field set.
581+ //
582+ // REVERT is a successful opcode execution that causes transaction failure.
583+ // Unlike "out of gas" errors where the opcode has an error field, REVERT
584+ // executes successfully but reverts state changes. The failure is indicated
585+ // by trace.Failed = true, NOT by individual opcode errors.
586+ aggregator := NewFrameAggregator ()
587+
588+ // Simulate a transaction that reverts: PUSH1 -> REVERT
589+ aggregator .ProcessStructlog (& execution.StructLog {
590+ Op : "PUSH1" ,
591+ Depth : 1 ,
592+ Gas : 50000 ,
593+ }, 0 , 0 , []uint32 {0 }, 3 , 3 , nil , nil )
594+
595+ // REVERT opcode with NO error field (realistic behavior)
596+ aggregator .ProcessStructlog (& execution.StructLog {
597+ Op : "REVERT" ,
598+ Depth : 1 ,
599+ Gas : 49997 ,
600+ // Note: NO Error field set - REVERT executes successfully
601+ }, 1 , 0 , []uint32 {0 }, 0 , 0 , nil , & execution.StructLog {Op : "PUSH1" , Depth : 1 })
602+
603+ // trace.Failed is true because the transaction reverted
604+ trace := & execution.TraceTransaction {
605+ Gas : 50000 ,
606+ Failed : true , // This is how REVERT is indicated
607+ }
608+
609+ frames := aggregator .Finalize (trace , 30000 )
610+
611+ assert .Equal (t , 1 , countSummaryRows (frames ))
612+
613+ summaryRow := getSummaryRow (frames , 0 )
614+ require .NotNil (t , summaryRow )
615+
616+ // Error count MUST be 1 even though no opcode had an error field
617+ // This is the key assertion: trace.Failed should set error_count = 1
618+ assert .Equal (t , uint64 (1 ), summaryRow .ErrorCount ,
619+ "ErrorCount should be 1 for REVERT transactions even without opcode errors" )
620+
621+ // GasRefund should be nil for failed transactions
622+ assert .Nil (t , summaryRow .GasRefund ,
623+ "GasRefund should be nil for reverted transactions" )
624+ }
625+
578626func TestMapOpcodeToCallType (t * testing.T ) {
579627 tests := []struct {
580628 opcode string
0 commit comments