Skip to content

Commit

Permalink
fix: retry when block not found
Browse files Browse the repository at this point in the history
  • Loading branch information
jrwbabylonlab committed Nov 8, 2024
1 parent 789b438 commit e32848c
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 15 deletions.
58 changes: 46 additions & 12 deletions internal/clients/bbnclient/bbnclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"strings"
"time"

"github.com/babylonlabs-io/babylon-staking-indexer/internal/types"
"github.com/babylonlabs-io/babylon/client/config"
Expand All @@ -14,6 +15,13 @@ import (
"github.com/rs/zerolog/log"
)

const (
// Backoff parameters for retries for getting BBN block result
initialBackoff = 500 * time.Millisecond // Start with 500ms
backoffFactor = 2 // Exponential backoff factor
maxRetries = 10 // 8 minutes in worst case
)

type BbnClient struct {
queryClient *query.QueryClient
}
Expand All @@ -38,18 +46,6 @@ func (c *BbnClient) GetLatestBlockNumber(ctx context.Context) (int64, *types.Err
return status.SyncInfo.LatestBlockHeight, nil
}

func (c *BbnClient) GetBlockResults(ctx context.Context, blockHeight int64) (*ctypes.ResultBlockResults, *types.Error) {
resp, err := c.queryClient.RPCClient.BlockResults(ctx, &blockHeight)
if err != nil {
return nil, types.NewErrorWithMsg(
http.StatusInternalServerError,
types.InternalServiceError,
fmt.Sprintf("failed to get block results for block %d: %s", blockHeight, err.Error()),
)
}
return resp, nil
}

func (c *BbnClient) GetCheckpointParams(ctx context.Context) (*CheckpointParams, *types.Error) {
params, err := c.queryClient.BTCCheckpointParams()
if err != nil {
Expand Down Expand Up @@ -107,6 +103,44 @@ func (c *BbnClient) GetAllStakingParams(ctx context.Context) (map[uint32]*Stakin
return allParams, nil
}

// GetBlockResultsWithRetry retries the `getBlockResults` method with exponential backoff
// when the block is not yet available.
func (c *BbnClient) GetBlockResultsWithRetry(
ctx context.Context, blockHeight *int64,
) (*ctypes.ResultBlockResults, *types.Error) {
backoff := initialBackoff
var resp *ctypes.ResultBlockResults
var err *types.Error

for i := 0; i < maxRetries; i++ {
resp, err = c.getBlockResults(ctx, blockHeight)
if err == nil {
return resp, nil
}

if strings.Contains(
err.Err.Error(),
"must be less than or equal to the current blockchain height",
) {
log.Debug().
Str("block_height", fmt.Sprintf("%d", *blockHeight)).
Str("backoff", backoff.String()).
Msg("Block not yet available, retrying...")
time.Sleep(backoff)
backoff *= backoffFactor
continue
}
return nil, err
}

// If we exhaust retries, return a not found error
return nil, types.NewErrorWithMsg(
http.StatusNotFound,
types.NotFound,
fmt.Sprintf("Block height %d not found after retries", *blockHeight),
)
}

func (c *BbnClient) Subscribe(subscriber, query string, outCapacity ...int) (out <-chan ctypes.ResultEvent, err error) {
return c.queryClient.RPCClient.Subscribe(context.Background(), subscriber, query, outCapacity...)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/clients/bbnclient/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ type BbnInterface interface {
GetCheckpointParams(ctx context.Context) (*CheckpointParams, *types.Error)
GetAllStakingParams(ctx context.Context) (map[uint32]*StakingParams, *types.Error)
GetLatestBlockNumber(ctx context.Context) (int64, *types.Error)
GetBlockResults(
ctx context.Context, blockHeight int64,
GetBlockResultsWithRetry(
ctx context.Context, blockHeight *int64,
) (*ctypes.ResultBlockResults, *types.Error)
Subscribe(subscriber, query string, outCapacity ...int) (out <-chan ctypes.ResultEvent, err error)
UnsubscribeAll(subscriber string) error
Expand Down
2 changes: 1 addition & 1 deletion internal/services/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (s *Service) getEventsFromBlock(
ctx context.Context, blockHeight int64,
) ([]BbnEvent, *types.Error) {
events := make([]BbnEvent, 0)
blockResult, err := s.bbn.GetBlockResults(ctx, blockHeight)
blockResult, err := s.bbn.GetBlockResultsWithRetry(ctx, &blockHeight)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit e32848c

Please sign in to comment.