From 1b285b8c81392e968f96ab8765ac0c45eba4faa2 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 21 Feb 2025 11:31:32 -0500 Subject: [PATCH] Added tests to ensure we covers balance and gas change correctly --- eth/tracers/firehose.go | 2 +- eth/tracers/firehose_test.go | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/eth/tracers/firehose.go b/eth/tracers/firehose.go index 4038bdd1a3..4f5e68b7f7 100644 --- a/eth/tracers/firehose.go +++ b/eth/tracers/firehose.go @@ -2068,7 +2068,7 @@ var gasChangeReasonToPb = map[tracing.GasChangeReason]pbeth.GasChange_Reason{ tracing.GasChangeWitnessContractCollisionCheck: pbeth.GasChange_REASON_WITNESS_CONTRACT_COLLISION_CHECK, tracing.GasChangeTxDataFloor: pbeth.GasChange_REASON_TX_DATA_FLOOR, - // Ignored, we track them manually, newGasChange ensure that we panic if we see Unknown + // Ignored, we track them manually, [newGasChange] ensure that we panic if we see Unknown tracing.GasChangeCallOpCode: pbeth.GasChange_REASON_UNKNOWN, } diff --git a/eth/tracers/firehose_test.go b/eth/tracers/firehose_test.go index 681a33cce8..9c00ed6636 100644 --- a/eth/tracers/firehose_test.go +++ b/eth/tracers/firehose_test.go @@ -3,9 +3,11 @@ package tracers import ( "encoding/json" "fmt" + "math" "math/big" "os" "reflect" + "regexp" "slices" "testing" @@ -188,6 +190,58 @@ func Test_FirehoseAndGethHeaderFieldMatches(t *testing.T) { } } +var endsWithUnknownConstant = regexp.MustCompile(`.*\(\d+\)$`) + +func TestFirehose_BalanceChangeAllMappedCorrectly(t *testing.T) { + + for i := 0; i <= math.MaxUint8; i++ { + tracingReason := tracing.BalanceChangeReason(i) + if tracingReason == tracing.BalanceChangeUnspecified || tracingReason == tracing.BalanceChangeRevert { + // Should never happen in Firehose tracer, only if tracer is wrapped with [tracing.WrapWithJournal] + continue + } + + // Here, we leverage the fact that the `tracing.BalanceChangeReason` Stringer will render the String + // as `()` if the index is not mapped to a constant in the enum. If this happens, + // we know it's not a defined constant in the Geth tracing package. + // + // Otherwise, it's defined and we should have some mapping for it in the `balanceChangeReasonFromChain` function. + // + // There is a loophole of this technique and it's that if the code generator defining the enum Stringer is + // not run, we will think it's an undefined constant and will miss it. + if !endsWithUnknownConstant.MatchString(tracingReason.String()) { + require.NotPanics(t, func() { + balanceChangeReasonFromChain(tracingReason) + }, "BalanceChangeReason panicked for value %v", tracingReason) + } + } +} + +func TestFirehose_GasChangeAllMappedCorrectly(t *testing.T) { + for i := 0; i <= math.MaxUint8; i++ { + tracingReason := tracing.GasChangeReason(i) + + // Those are ignored and never mapped + if tracingReason == tracing.GasChangeUnspecified || tracingReason == tracing.GasChangeCallOpCode || tracingReason == tracing.GasChangeIgnored { + continue + } + + // Here, we leverage the fact that the `tracing.GasChangeReason` Stringer will render the String + // as `()` if the index is not mapped to a constant in the enum. If this happens, + // we know it's not a defined constant in the Geth tracing package. + // + // Otherwise, it's defined and we should have some mapping for it in the `gasChangeReasonFromChain` function. + // + // There is a loophole of this technique and it's that if the code generator defining the enum Stringer is + // not run, we will think it's an undefined constant and will miss it. + if !endsWithUnknownConstant.MatchString(tracingReason.String()) { + require.NotPanics(t, func() { + gasChangeReasonFromChain(tracingReason) + }, "GasChangeReason panicked for value %v", tracingReason) + } + } +} + func fillAllFieldsWithNonEmptyValues(t *testing.T, structValue reflect.Value, fields []reflect.StructField) { t.Helper()