From f877183cbb38d9212d25bc33650926e0aadcf9c7 Mon Sep 17 00:00:00 2001 From: Shane Bammel Date: Tue, 26 Aug 2025 08:44:16 -0500 Subject: [PATCH] eth/tracers: fix supply tracer uncle accounting (#31882) Uncle rewards were being omitted in the supply tracer due to a bug. This PR fixes that. --------- Co-authored-by: Sina Mahmoodi --- eth/tracers/internal/tracetest/supply_test.go | 68 ++++++++++++++++--- eth/tracers/live/supply.go | 3 +- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 8aedc9d564..2b5a8212aa 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -77,7 +77,7 @@ func TestSupplyOmittedFields(t *testing.T) { out, _, err := testSupplyTracer(t, gspec, func(b *core.BlockGen) { b.SetPoS() - }) + }, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -120,7 +120,7 @@ func TestSupplyGenesisAlloc(t *testing.T) { ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), } - out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) + out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -148,7 +148,55 @@ func TestSupplyRewards(t *testing.T) { ParentHash: common.HexToHash("0xadeda0a83e337b6c073e3f0e9a17531a04009b397a9588c093b628f21b8bc5a3"), } - out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) + out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc, 1) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + actual := out[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func TestSupplyRewardsWithUncle(t *testing.T) { + var ( + config = *params.AllEthashProtocolChanges + + gspec = &core.Genesis{ + Config: &config, + } + ) + + // Base reward for the miner + baseReward := ethash.ConstantinopleBlockReward.ToBig() + // Miner reward for uncle inclusion is 1/32 of the base reward + uncleInclusionReward := new(big.Int).Rsh(baseReward, 5) + // Uncle miner reward for an uncle that is 1 block behind is 7/8 of the base reward + uncleReward := big.NewInt(7) + uncleReward.Mul(uncleReward, baseReward).Rsh(uncleReward, 3) + + totalReward := baseReward.Add(baseReward, uncleInclusionReward).Add(baseReward, uncleReward) + + expected := supplyInfo{ + Issuance: &supplyInfoIssuance{ + Reward: (*hexutil.Big)(totalReward), + }, + Number: 3, + Hash: common.HexToHash("0x0737d31f8671c18d32b5143833cfa600e4264df62324c9de569668c6de9eed6d"), + ParentHash: common.HexToHash("0x45af6557df87719cb3c7e6f8a98b61508ea74a797733191aececb4c2ec802447"), + } + + // Generate a new chain where block 3 includes an uncle + uncleGenerationFunc := func(b *core.BlockGen) { + if b.Number().Uint64() == 3 { + prevBlock := b.PrevBlock(1) // Block 2 + uncle := types.CopyHeader(prevBlock.Header()) + uncle.Extra = []byte("uncle!") + b.AddUncle(uncle) + } + } + + out, _, err := testSupplyTracer(t, gspec, uncleGenerationFunc, 3) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -195,7 +243,7 @@ func TestSupplyEip1559Burn(t *testing.T) { b.AddTx(tx) } - out, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc) + out, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -238,7 +286,7 @@ func TestSupplyWithdrawals(t *testing.T) { }) } - out, chain, err := testSupplyTracer(t, gspec, withdrawalsBlockGenerationFunc) + out, chain, err := testSupplyTracer(t, gspec, withdrawalsBlockGenerationFunc, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -318,7 +366,7 @@ func TestSupplySelfdestruct(t *testing.T) { } // 1. Test pre Cancun - preCancunOutput, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + preCancunOutput, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc, 1) if err != nil { t.Fatalf("Pre-cancun failed to test supply tracer: %v", err) } @@ -360,7 +408,7 @@ func TestSupplySelfdestruct(t *testing.T) { gspec.Config.CancunTime = &cancunTime gspec.Config.BlobScheduleConfig = params.DefaultBlobSchedule - postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc, 1) if err != nil { t.Fatalf("Post-cancun failed to test supply tracer: %v", err) } @@ -500,7 +548,7 @@ func TestSupplySelfdestructItselfAndRevert(t *testing.T) { b.AddTx(tx) } - output, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + output, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc, 1) if err != nil { t.Fatalf("failed to test supply tracer: %v", err) } @@ -542,7 +590,7 @@ func TestSupplySelfdestructItselfAndRevert(t *testing.T) { compareAsJSON(t, expected, actual) } -func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, *core.BlockChain, error) { +func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(b *core.BlockGen), numBlocks int) ([]supplyInfo, *core.BlockChain, error) { engine := beacon.New(ethash.NewFaker()) traceOutputPath := filepath.ToSlash(t.TempDir()) @@ -562,7 +610,7 @@ func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockG } defer chain.Stop() - _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, 1, func(i int, b *core.BlockGen) { + _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, numBlocks, func(i int, b *core.BlockGen) { b.SetCoinbase(common.Address{1}) gen(b) }) diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go index bae7445cb4..ad3b9cbae3 100644 --- a/eth/tracers/live/supply.go +++ b/eth/tracers/live/supply.go @@ -199,8 +199,7 @@ func (s *supplyTracer) onBalanceChange(a common.Address, prevBalance, newBalance // NOTE: don't handle "BalanceIncreaseGenesisBalance" because it is handled in OnGenesisBlock switch reason { - case tracing.BalanceIncreaseRewardMineUncle: - case tracing.BalanceIncreaseRewardMineBlock: + case tracing.BalanceIncreaseRewardMineBlock, tracing.BalanceIncreaseRewardMineUncle: s.delta.Issuance.Reward.Add(s.delta.Issuance.Reward, diff) case tracing.BalanceIncreaseWithdrawal: s.delta.Issuance.Withdrawals.Add(s.delta.Issuance.Withdrawals, diff)