Skip to content

Commit

Permalink
Handle edge cases involving blocks not being found in the db
Browse files Browse the repository at this point in the history
One case is where there is a backfill followed by an error, so that
logs get written to the db but no blocks. This will make the logpoller
(or backup log poller) rely on the chain next time instead of the db
to determine lastFinalizedBlock, which could result in a gap in logs
processed. Fixing this by writing the last block in the backfil to the db
along with the logs. Its lastFinalizedBlock field will be set to its
own block number + 1, so if the db crashes it should start by pulling
the logs from that one.

The second case is even more rare, and could only happen in a situation
where the log poller just recently started on a new chain, and there is a
re-org of depth R which happens N blocks into the chain (after N blocks
have been pulled and saved to the db), where 1 < N < R < finalizationDepth.
So this would have to be a re-org of at least depth 2 that happens at
exactly the wrong moment.
  • Loading branch information
reductionista committed Nov 16, 2023
1 parent 3a38e90 commit 1f40807
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 6 deletions.
10 changes: 8 additions & 2 deletions core/chains/evm/logpoller/log_poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error {
}

lp.lggr.Debugw("Backfill found logs", "from", from, "to", to, "logs", len(gethLogs), "blocks", blocks)
err = lp.orm.InsertLogs(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), pg.WithParentCtx(ctx))
err = lp.orm.InsertLogsWithBlock(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), blocks[len(blocks)-1], pg.WithParentCtx(ctx))
if err != nil {
lp.lggr.Warnw("Unable to insert logs, retrying", "err", err, "from", from, "to", to)
return err
Expand Down Expand Up @@ -903,7 +903,13 @@ func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.He
// This can happen only if finalityTag is not enabled and fixed finalityDepth is provided via config.
for parent.Number >= latestFinalizedBlockNumber {
ourParentBlockHash, err := lp.orm.SelectBlockByNumber(parent.Number, pg.WithParentCtx(ctx))
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
// This can happen if we're on a new chain or the node is starting for the first time, due to
// the blocks table not having enough history yet. Since there is nothing
// before this to delete there is no reason to worry about re-orgs any deeper.
lp.lggr.Infow("Unable to find parent of current block in db", "parentBlockNumber", parent.Number, parent.Hash, "currentBlockNumber", current.Number, "currentBlockHash", current.Hash)
return &blockAfterLCA, nil
} else if err != nil {
return nil, err
}
if parent.Hash == ourParentBlockHash.BlockHash {
Expand Down
8 changes: 4 additions & 4 deletions core/chains/evm/logpoller/log_poller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -965,8 +965,8 @@ func TestLogPoller_PollAndSaveLogs(t *testing.T) {
lgs, err = th.ORM.SelectLogsByBlockRange(11, 17)
require.NoError(t, err)
assert.Equal(t, 7, len(lgs))
th.assertHaveCanonical(t, 15, 16)
th.assertDontHave(t, 11, 14) // Do not expect to save backfilled blocks.
th.assertHaveCanonical(t, 14, 16) // Should have last finalized block plus unfinalized blocks
th.assertDontHave(t, 11, 13) // Should not have older finalized blocks

// Verify that a custom block timestamp will get written to db correctly also
b, err = th.Client.BlockByNumber(testutils.Context(t), nil)
Expand Down Expand Up @@ -1057,8 +1057,8 @@ func TestLogPoller_PollAndSaveLogsDeepReorg(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000002`), lgs[0].Data)
th.assertHaveCanonical(t, 1, 1)
th.assertDontHave(t, 2, 5) // These blocks are backfilled
th.assertHaveCanonical(t, 6, 10)
th.assertDontHave(t, 2, 3) // These blocks are backfilled
th.assertHaveCanonical(t, 5, 10)
})
}
}
Expand Down

0 comments on commit 1f40807

Please sign in to comment.