Skip to content

Commit 5683924

Browse files
authored
fix(logpoller): replay lower boundary revalidation (#603)
* fix: replay lower boundary revalidation * chore: clean up * fix: check BlockIDExt * chore: lint
1 parent f9026ec commit 5683924

3 files changed

Lines changed: 24 additions & 12 deletions

File tree

pkg/logpoller/o11y_log_provider.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package logpoller
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"strconv"
78

@@ -30,6 +31,10 @@ func NewTonO11yLogProvider(client ton.APIClientWrapped, loader TxLoader) RawLogP
3031

3132
// GetLogs retrieves all ExternalMsgOutLogs for an address between fromBlockSeqNo (exclusive) and toBlock (inclusive).
3233
func (tlp *tonO11yLogProvider) GetLogs(ctx context.Context, addr *address.Address, from uint32, to *ton.BlockIDExt) ([]models.RawLog, error) {
34+
if to == nil {
35+
return nil, errors.New("to block must not be nil")
36+
}
37+
3338
// validate that the provided block belongs to the masterchain
3439
if to.Workchain != address.MasterchainID {
3540
return nil, fmt.Errorf("expected masterchain block (workchain %d), got workchain %d", address.MasterchainID, to.Workchain)

pkg/logpoller/replay.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,14 @@ func (lp *service) applyReplayOverride(ctx context.Context, blockRange *models.B
133133
return blockRange, 0 // No replay request
134134
}
135135

136-
// re-validate that the replay target block still exists
137-
_, err := lp.lookupRequestedReplayBlock(ctx, fromBlock, currentMasterchainBlock)
136+
// re-validate prevBlock (fromBlock-1) to handle the edge case where it gets pruned between
137+
// request and override time. Validate fromBlock-1 since it's the block used by
138+
// GetTransactionLTBounds for startLT.
139+
blockToValidate := fromBlock // fromBlock == 1: no block 0 on TON (localnet edge case)
140+
if fromBlock > 1 {
141+
blockToValidate = fromBlock - 1
142+
}
143+
_, err := lp.lookupRequestedReplayBlock(ctx, blockToValidate, currentMasterchainBlock)
138144
if err != nil {
139145
lp.lggr.Warnw("replay rejected", "error", err, "fromBlock", fromBlock)
140146
lp.clearReplayRequest()

pkg/logpoller/replay_test.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ func TestApplyReplayOverride(t *testing.T) {
4848
lp := &service{
4949
lggr: logger.Sugared(logger.Nop()),
5050
clientProvider: func(_ context.Context) (ton.APIClientWrapped, error) {
51-
// Validation looks up replayFromBlock (51)
52-
return &mockAPIClient{lookupBlockResult: &ton.BlockIDExt{SeqNo: 51}}, nil
51+
// Validation looks up prevBlock (50)
52+
return &mockAPIClient{lookupBlockResult: &ton.BlockIDExt{SeqNo: 50}}, nil
5353
},
5454
}
5555
lp.replay.status = models.ReplayStatusRequested
@@ -77,8 +77,8 @@ func TestApplyReplayOverride(t *testing.T) {
7777
lp := &service{
7878
lggr: logger.Sugared(logger.Nop()),
7979
clientProvider: func(_ context.Context) (ton.APIClientWrapped, error) {
80-
// Validation looks up replayFromBlock (51)
81-
return &mockAPIClient{lookupBlockResult: &ton.BlockIDExt{SeqNo: 51}}, nil
80+
// Validation looks up prevBlock (50)
81+
return &mockAPIClient{lookupBlockResult: &ton.BlockIDExt{SeqNo: 50}}, nil
8282
},
8383
}
8484
lp.replay.status = models.ReplayStatusRequested
@@ -94,7 +94,7 @@ func TestApplyReplayOverride(t *testing.T) {
9494
t.Run("replay rejected and status reset when block beyond current", func(t *testing.T) {
9595
t.Parallel()
9696
currentMasterchainBlock := &ton.BlockIDExt{Workchain: address.MasterchainID, SeqNo: 100, Shard: 1}
97-
// Replay from block 151 stores fromBlock=151, prevBlock=150, validation checks 151 >= 100
97+
// Replay from block 151 stores fromBlock=151, prevBlock=150, validation checks 150 >= 100
9898
prevBlock := &ton.BlockIDExt{Workchain: address.MasterchainID, SeqNo: 150, Shard: 1}
9999

100100
lp := &service{
@@ -115,25 +115,26 @@ func TestApplyReplayOverride(t *testing.T) {
115115
require.Nil(t, lp.replay.prevBlock)
116116
})
117117

118-
t.Run("replay rejected and status reset when block pruned", func(t *testing.T) {
118+
t.Run("replay rejected when prevBlock pruned between request and override", func(t *testing.T) {
119119
t.Parallel()
120120
currentMasterchainBlock := &ton.BlockIDExt{Workchain: address.MasterchainID, SeqNo: 100, Shard: 1}
121-
// Replay from block 51 stores fromBlock=51, prevBlock=50, validation looks up block 51
121+
// Replay from block 51 stores fromBlock=51, prevBlock=50, validation looks up prevBlock (50)
122122
prevBlock := &ton.BlockIDExt{Workchain: address.MasterchainID, SeqNo: 50, Shard: 1}
123123

124124
lp := &service{
125125
lggr: logger.Sugared(logger.Nop()),
126126
clientProvider: func(_ context.Context) (ton.APIClientWrapped, error) {
127+
// prevBlock (50) was pruned since the original Replay() request
127128
return &mockAPIClient{lookupBlockErr: ton.ErrBlockNotFound}, nil
128129
},
129130
}
130131
lp.replay.status = models.ReplayStatusRequested
131132
lp.replay.fromBlock = 51
132133
lp.replay.prevBlock = prevBlock
133134

134-
result, _ := lp.applyReplayOverride(context.Background(), nil, currentMasterchainBlock)
135+
result, replayFrom := lp.applyReplayOverride(context.Background(), nil, currentMasterchainBlock)
135136
require.Nil(t, result)
136-
// Status should be NoRequest after clearReplayRequest() is called (rejection resets to initial state)
137+
require.Equal(t, uint32(0), replayFrom)
137138
require.Equal(t, models.ReplayStatusNoRequest, lp.replay.status)
138139
require.Equal(t, uint32(0), lp.replay.fromBlock)
139140
require.Nil(t, lp.replay.prevBlock)
@@ -146,7 +147,7 @@ func TestApplyReplayOverride(t *testing.T) {
146147
lp := &service{
147148
lggr: logger.Sugared(logger.Nop()),
148149
clientProvider: func(_ context.Context) (ton.APIClientWrapped, error) {
149-
// Validation looks up fromBlock (1)
150+
// fromBlock == 1: no block 0 on TON, so validation falls back to block 1
150151
return &mockAPIClient{lookupBlockResult: &ton.BlockIDExt{SeqNo: 1}}, nil
151152
},
152153
}

0 commit comments

Comments
 (0)