Skip to content

Commit e0f6208

Browse files
adg-flaretilenflare
authored andcommitted
fix: use heuristics for block-by-timestamp search
1 parent 449c097 commit e0f6208

1 file changed

Lines changed: 56 additions & 31 deletions

File tree

database/history_drop.go

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66
"flare-ftso-indexer/chain"
77
"flare-ftso-indexer/config"
88
"flare-ftso-indexer/logger"
9+
"math"
910
"math/big"
10-
"sort"
1111
"time"
1212

1313
"github.com/pkg/errors"
@@ -17,6 +17,7 @@ import (
1717
const (
1818
deleteBatchesPauseAfter = 10
1919
deleteBatchesPauseDuration = 100 * time.Millisecond
20+
searchWindowBlocks = uint64(5 * 24 * 3600) // Heuristic: 5 days of blocks, assuming 1 sec per block
2021
)
2122

2223
func DropHistory(
@@ -226,42 +227,66 @@ func getNearestBlockByTimestampFromChain(
226227
startBlockNumber uint64,
227228
endBlockNumber uint64,
228229
) (uint64, error) {
229-
// We search over the entire range of blocks from the configured
230-
// startBlockNumber to the most recent block number.
231-
//
232-
// This could potentially be optimized further using some estimate
233-
// of the block time to reduce the search range, but for now this should
234-
// be good enough.
235-
//
236-
// Once the indexer is running for a while it should be possible to
237-
// read the required block number from the database instead of using
238-
// this search process.
239-
240-
var err error
241-
i := sort.Search(int(endBlockNumber-startBlockNumber+1), func(i int) bool {
242-
// The err variable comes from the enclosing function. If it has been
243-
// set to a non-nil value by a previous iteration of the binary search,
244-
// we should not overwrite it. Ideally we would exit the binary search
245-
// early, but the sort.Search function does not provide a way to do
246-
// that. So instead, we just return false for all future iterations.
247-
// The results of the search are meaningless in this case.
248-
if err != nil {
249-
return false
230+
logger.Debug("Getting nearest block by timestamp from chain: search timestamp: %d, start block: %d, end block: %d", searchTimestamp, startBlockNumber, endBlockNumber)
231+
232+
var searchStartBlockNumber = startBlockNumber
233+
var searchEndBlockNumber = endBlockNumber
234+
235+
if startBlockNumber == 0 {
236+
// If start block was not specified in config, try to reduce the search space by going back in steps of 5 days
237+
// until we find a block earlier than searchTimestamp.
238+
// This is to avoid querying for very old blocks during binary search - the RPC node might not have full block history.
239+
startCandidate := endBlockNumber
240+
candidateBlockTime := uint64(math.MaxUint64)
241+
242+
var err error
243+
for candidateBlockTime > searchTimestamp {
244+
startCandidate = startCandidate - searchWindowBlocks
245+
candidateBlockTime, _, err = getBlockTimestamp(ctx, big.NewInt(int64(startCandidate)), client)
246+
if err != nil {
247+
return 0, errors.Wrap(err, "getNearestBlockByTimestampFromChain")
248+
}
250249
}
250+
searchStartBlockNumber = startCandidate
251+
searchEndBlockNumber = startCandidate + searchWindowBlocks
252+
logger.Debug("Search block window narrowed down to: %d-%d", searchStartBlockNumber, searchEndBlockNumber)
253+
}
251254

252-
blockNumber := startBlockNumber + uint64(i)
255+
blockNumber, err := binarySearchBlockByTimestamp(
256+
ctx, searchTimestamp, client, searchStartBlockNumber, searchEndBlockNumber,
257+
)
258+
if err != nil {
259+
return 0, errors.Wrap(err, "getNearestBlockByTimestampFromChain")
260+
}
261+
262+
logger.Debug("Found nearest block by timestamp from chain: block number: %d", blockNumber)
263+
return blockNumber, nil
264+
}
253265

254-
var blockTime uint64
255-
blockTime, _, err = getBlockTimestamp(ctx, big.NewInt(int64(blockNumber)), client)
266+
func binarySearchBlockByTimestamp(
267+
ctx context.Context,
268+
searchTimestamp uint64,
269+
client *chain.Client,
270+
startBlockNumber uint64,
271+
endBlockNumber uint64,
272+
) (uint64, error) {
273+
low := startBlockNumber
274+
high := endBlockNumber
275+
276+
for low < high {
277+
mid := low + (high-low)/2
278+
279+
blockTime, _, err := getBlockTimestamp(ctx, big.NewInt(int64(mid)), client)
256280
if err != nil {
257-
return false
281+
return 0, err
258282
}
259283

260-
return blockTime >= searchTimestamp
261-
})
262-
if err != nil {
263-
return 0, errors.Wrap(err, "getNearestBlockByTimestampFromChain")
284+
if blockTime >= searchTimestamp {
285+
high = mid
286+
} else {
287+
low = mid + 1
288+
}
264289
}
265290

266-
return startBlockNumber + uint64(i), nil
291+
return low, nil
267292
}

0 commit comments

Comments
 (0)