Avoid calling OnBlockEnd on panic

This avoid problem where the tracer receives `OnBlockEnd(nil)` and thus cannot know that an error happen, in which case it could flush data out.

Technically, shouldn't be a big problem as since there is a panic, the block will not be committed to geth storage and will be replayed correctly.

The other possibility would be to still call the tracer but passing the recovered error to `OnBlockEnd`, but this would require transforming the recovered `any` type into an `error`.
This commit is contained in:
Matthieu Vachon 2025-05-14 17:01:43 -04:00
parent 2f09dade9a
commit 4a4a4f6710
2 changed files with 46 additions and 1 deletions

View file

@ -1952,7 +1952,11 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
}
if bc.logger != nil && bc.logger.OnBlockEnd != nil {
defer func() {
bc.logger.OnBlockEnd(blockEndErr)
if recovered := recover(); recovered != nil {
panic(recovered)
} else {
bc.logger.OnBlockEnd(blockEndErr)
}
}()
}

View file

@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/core/history"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/core/vm/program"
@ -4390,3 +4391,43 @@ func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64,
}
}
}
func TestTracingBlockEndNotCalledOnPanic(t *testing.T) {
genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true, "path")
if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
}
defer blockchain.Stop()
blockEndCalled := false
hooks := &tracing.Hooks{
// This simulates a panic in the tracer
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
panic("panic")
},
OnBlockEnd: func(err error) {
blockEndCalled = true
},
}
blockchain.logger = hooks
blockchain.vmConfig.Tracer = hooks
blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 1, ethash.NewFullFaker(), genDb, 0)
func() {
defer func() {
if r := recover(); r == nil {
t.Fatalf("Expected panic, but got none, ensure that OnBalanceChange hook is called correctly to generate the panic")
}
}()
if _, err := blockchain.InsertChain(blocks); err != nil {
t.Fatalf("Failed to insert block: %v", err)
}
}()
if blockEndCalled {
t.Fatalf("OnBlockEnd should not be called on panic within the tracer")
}
}