Skip to content

Commit 87b70c0

Browse files
Safe block support in HeadTracker (#51)
* Safe block support ni HeadTracker * Safe block support ni HeadTracker * lint * method rename
1 parent 65c5466 commit 87b70c0

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

chains/heads/client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ type Client[H chains.Head[BLOCK_HASH], S chains.Subscription, ID chains.ID, BLOC
1515
// SubscribeToHeads is the method in which the client receives new Head.
1616
// It can be implemented differently for each chain i.e websocket, polling, etc
1717
SubscribeToHeads(ctx context.Context) (<-chan H, S, error)
18+
// LatestSafeBlock - returns the latest block that was marked as safe
19+
LatestSafeBlock(ctx context.Context) (safe H, err error)
1820
// LatestFinalizedBlock - returns the latest block that was marked as finalized
1921
LatestFinalizedBlock(ctx context.Context) (head H, err error)
2022
}

chains/heads/tracker.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ type Tracker[H chains.Head[BLOCK_HASH], BLOCK_HASH chains.Hashable] interface {
3939
// Backfill given a head will fill in any missing heads up to latestFinalized
4040
Backfill(ctx context.Context, headWithChain H, prevHeadWithChain H) (err error)
4141
LatestChain() H
42+
// LatestSafeBlock returns the latest block that is considered safe to use.
43+
LatestSafeBlock(ctx context.Context) (safe H, err error)
4244
// LatestAndFinalizedBlock - returns latest and latest finalized blocks.
4345
// NOTE: Returns latest finalized block as is, ignoring the FinalityTagBypass feature flag.
4446
LatestAndFinalizedBlock(ctx context.Context) (latest, finalized H, err error)
@@ -47,6 +49,7 @@ type Tracker[H chains.Head[BLOCK_HASH], BLOCK_HASH chains.Hashable] interface {
4749
type ChainConfig interface {
4850
BlockEmissionIdleWarningThreshold() time.Duration
4951
FinalityDepth() uint32
52+
SafeDepth() uint32
5053
FinalityTagEnabled() bool
5154
FinalizedBlockOffset() uint32
5255
}
@@ -396,6 +399,42 @@ func (t *tracker[HTH, S, ID, BHASH]) backfillLoop(ctx context.Context) {
396399
}
397400
}
398401

402+
func (t *tracker[HTH, S, ID, BHASH]) LatestSafeBlock(ctx context.Context) (safe HTH, err error) {
403+
if t.config.FinalityTagEnabled() {
404+
latestSafe, err2 := t.client.LatestSafeBlock(ctx)
405+
if err2 != nil {
406+
return latestSafe, fmt.Errorf("failed to get latest finalized block: %w", err2)
407+
}
408+
409+
if !latestSafe.IsValid() {
410+
return latestSafe, fmt.Errorf("failed to get valid latest finalized block")
411+
}
412+
return latestSafe, nil
413+
}
414+
latest, err := t.client.HeadByNumber(ctx, nil)
415+
if err != nil {
416+
err = fmt.Errorf("failed to get latest block: %w", err)
417+
return
418+
}
419+
420+
if !latest.IsValid() {
421+
err = fmt.Errorf("expected latest block to be valid")
422+
return
423+
}
424+
if t.instantFinality() {
425+
return latest, nil
426+
}
427+
safeDepth := int64(t.config.SafeDepth())
428+
if safeDepth <= 0 {
429+
safeDepth = int64(t.config.FinalityDepth())
430+
}
431+
safeBlockNumber := latest.BlockNumber() - safeDepth
432+
if safeBlockNumber <= 0 {
433+
safeBlockNumber = 0
434+
}
435+
return t.getHeadAtHeight(ctx, latest.BlockHash(), safeBlockNumber)
436+
}
437+
399438
// LatestAndFinalizedBlock - returns latest and latest finalized blocks.
400439
// NOTE: Returns latest finalized block as is, ignoring the FinalityTagBypass feature flag.
401440
// TODO: BCI-3321 use cached values instead of making RPC requests

0 commit comments

Comments
 (0)