From 1a74baa2614004b882e5e5f54f6bb665ca85c4f7 Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 11 Apr 2024 19:55:56 +0200 Subject: [PATCH 1/3] Add ledger range to getHealth endpoint --- cmd/soroban-rpc/internal/events/events.go | 7 +++ cmd/soroban-rpc/internal/jsonrpc.go | 2 +- .../ledgerbucketwindow/ledgerbucketwindow.go | 29 ++++++++++++ cmd/soroban-rpc/internal/methods/health.go | 29 +++++++++--- .../internal/transactions/transactions.go | 45 +++---------------- .../transactions/transactions_test.go | 11 ++--- 6 files changed, 73 insertions(+), 50 deletions(-) diff --git a/cmd/soroban-rpc/internal/events/events.go b/cmd/soroban-rpc/internal/events/events.go index 39fdc4ce..12e8e765 100644 --- a/cmd/soroban-rpc/internal/events/events.go +++ b/cmd/soroban-rpc/internal/events/events.go @@ -264,3 +264,10 @@ func readEvents(networkPassphrase string, ledgerCloseMeta xdr.LedgerCloseMeta) ( } return events, err } + +// GetLedgerRange returns the first and latest ledger available in the store. +func (m *MemoryStore) GetLedgerRange() ledgerbucketwindow.LedgerRange { + m.lock.RLock() + defer m.lock.RUnlock() + return m.eventsByLedger.GetLedgerRange() +} diff --git a/cmd/soroban-rpc/internal/jsonrpc.go b/cmd/soroban-rpc/internal/jsonrpc.go index d122b9a0..7b7096f7 100644 --- a/cmd/soroban-rpc/internal/jsonrpc.go +++ b/cmd/soroban-rpc/internal/jsonrpc.go @@ -143,7 +143,7 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler { }{ { methodName: "getHealth", - underlyingHandler: methods.NewHealthCheck(params.TransactionStore, cfg.MaxHealthyLedgerLatency), + underlyingHandler: methods.NewHealthCheck(params.TransactionStore, params.EventStore, cfg.MaxHealthyLedgerLatency), longName: "get_health", queueLimit: cfg.RequestBacklogGetHealthQueueLimit, requestDurationLimit: cfg.MaxGetHealthExecutionDuration, diff --git a/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go b/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go index 8234b607..7225a6b3 100644 --- a/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go +++ b/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go @@ -65,6 +65,35 @@ func (w *LedgerBucketWindow[T]) Len() uint32 { return uint32(len(w.buckets)) } +type LedgerInfo struct { + Sequence uint32 + CloseTime int64 +} + +type LedgerRange struct { + FirstLedger LedgerInfo + LastLedger LedgerInfo +} + +func (w *LedgerBucketWindow[T]) GetLedgerRange() LedgerRange { + length := w.Len() + if length == 0 { + return LedgerRange{} + } + firstBucket := w.Get(0) + lastBucket := w.Get(length - 1) + return LedgerRange{ + FirstLedger: LedgerInfo{ + Sequence: firstBucket.LedgerSeq, + CloseTime: firstBucket.LedgerCloseTimestamp, + }, + LastLedger: LedgerInfo{ + Sequence: lastBucket.LedgerSeq, + CloseTime: lastBucket.LedgerCloseTimestamp, + }, + } +} + // Get obtains a bucket from the window func (w *LedgerBucketWindow[T]) Get(i uint32) *LedgerBucket[T] { length := w.Len() diff --git a/cmd/soroban-rpc/internal/methods/health.go b/cmd/soroban-rpc/internal/methods/health.go index ab46d62a..db577f54 100644 --- a/cmd/soroban-rpc/internal/methods/health.go +++ b/cmd/soroban-rpc/internal/methods/health.go @@ -8,24 +8,36 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/events" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/transactions" ) type HealthCheckResult struct { - Status string `json:"status"` + Status string `json:"status"` + LatestLedger uint32 `json:"latestLedger"` + FirstLedger uint32 `json:"firstLedger"` } // NewHealthCheck returns a health check json rpc handler -func NewHealthCheck(txStore *transactions.MemoryStore, maxHealthyLedgerLatency time.Duration) jrpc2.Handler { +func NewHealthCheck(txStore *transactions.MemoryStore, evStore *events.MemoryStore, maxHealthyLedgerLatency time.Duration) jrpc2.Handler { return handler.New(func(ctx context.Context) (HealthCheckResult, error) { - ledgerInfo := txStore.GetLatestLedger() - if ledgerInfo.Sequence < 1 { + txLedgerRange := txStore.GetLedgerRange() + evLedgerRange := evStore.GetLedgerRange() + if txLedgerRange.FirstLedger.Sequence < 1 || evLedgerRange.FirstLedger.Sequence < 1 { return HealthCheckResult{}, jrpc2.Error{ Code: jrpc2.InternalError, Message: "data stores are not initialized", } } - lastKnownLedgerCloseTime := time.Unix(ledgerInfo.CloseTime, 0) + mergedRange := evLedgerRange + if txLedgerRange.FirstLedger.Sequence < mergedRange.FirstLedger.Sequence { + mergedRange.FirstLedger = txLedgerRange.FirstLedger + } + if txLedgerRange.LastLedger.Sequence > mergedRange.LastLedger.Sequence { + mergedRange.LastLedger = txLedgerRange.LastLedger + } + + lastKnownLedgerCloseTime := time.Unix(mergedRange.LastLedger.CloseTime, 0) lastKnownLedgerLatency := time.Since(lastKnownLedgerCloseTime) if lastKnownLedgerLatency > maxHealthyLedgerLatency { roundedLatency := lastKnownLedgerLatency.Round(time.Second) @@ -35,6 +47,11 @@ func NewHealthCheck(txStore *transactions.MemoryStore, maxHealthyLedgerLatency t Message: msg, } } - return HealthCheckResult{Status: "healthy"}, nil + result := HealthCheckResult{ + Status: "healthy", + LatestLedger: mergedRange.LastLedger.Sequence, + FirstLedger: mergedRange.FirstLedger.Sequence, + } + return result, nil }) } diff --git a/cmd/soroban-rpc/internal/transactions/transactions.go b/cmd/soroban-rpc/internal/transactions/transactions.go index 6b24f429..e5abe55c 100644 --- a/cmd/soroban-rpc/internal/transactions/transactions.go +++ b/cmd/soroban-rpc/internal/transactions/transactions.go @@ -140,11 +140,6 @@ func (m *MemoryStore) IngestTransactions(ledgerCloseMeta xdr.LedgerCloseMeta) er return nil } -type LedgerInfo struct { - Sequence uint32 - CloseTime int64 -} - type Transaction struct { Result []byte // XDR encoded xdr.TransactionResult Meta []byte // XDR encoded xdr.TransactionMeta @@ -153,48 +148,22 @@ type Transaction struct { FeeBump bool ApplicationOrder int32 Successful bool - Ledger LedgerInfo -} - -type StoreRange struct { - FirstLedger LedgerInfo - LastLedger LedgerInfo + Ledger ledgerbucketwindow.LedgerInfo } -// GetLatestLedger returns the latest ledger available in the store. -func (m *MemoryStore) GetLatestLedger() LedgerInfo { +// GetLedgerRange returns the first and latest ledger available in the store. +func (m *MemoryStore) GetLedgerRange() ledgerbucketwindow.LedgerRange { m.lock.RLock() defer m.lock.RUnlock() - if m.transactionsByLedger.Len() > 0 { - lastBucket := m.transactionsByLedger.Get(m.transactionsByLedger.Len() - 1) - return LedgerInfo{ - Sequence: lastBucket.LedgerSeq, - CloseTime: lastBucket.LedgerCloseTimestamp, - } - } - return LedgerInfo{} + return m.transactionsByLedger.GetLedgerRange() } // GetTransaction obtains a transaction from the store and whether it's present and the current store range -func (m *MemoryStore) GetTransaction(hash xdr.Hash) (Transaction, bool, StoreRange) { +func (m *MemoryStore) GetTransaction(hash xdr.Hash) (Transaction, bool, ledgerbucketwindow.LedgerRange) { startTime := time.Now() m.lock.RLock() defer m.lock.RUnlock() - var storeRange StoreRange - if m.transactionsByLedger.Len() > 0 { - firstBucket := m.transactionsByLedger.Get(0) - lastBucket := m.transactionsByLedger.Get(m.transactionsByLedger.Len() - 1) - storeRange = StoreRange{ - FirstLedger: LedgerInfo{ - Sequence: firstBucket.LedgerSeq, - CloseTime: firstBucket.LedgerCloseTimestamp, - }, - LastLedger: LedgerInfo{ - Sequence: lastBucket.LedgerSeq, - CloseTime: lastBucket.LedgerCloseTimestamp, - }, - } - } + storeRange := m.transactionsByLedger.GetLedgerRange() internalTx, ok := m.transactions[hash] if !ok { return Transaction{}, false, storeRange @@ -229,7 +198,7 @@ func (m *MemoryStore) GetTransaction(hash xdr.Hash) (Transaction, bool, StoreRan FeeBump: internalTx.feeBump, Successful: internalTx.successful, ApplicationOrder: internalTx.applicationOrder, - Ledger: LedgerInfo{ + Ledger: ledgerbucketwindow.LedgerInfo{ Sequence: internalTx.bucket.LedgerSeq, CloseTime: internalTx.bucket.LedgerCloseTimestamp, }, diff --git a/cmd/soroban-rpc/internal/transactions/transactions_test.go b/cmd/soroban-rpc/internal/transactions/transactions_test.go index 73ddbaa6..4b801835 100644 --- a/cmd/soroban-rpc/internal/transactions/transactions_test.go +++ b/cmd/soroban-rpc/internal/transactions/transactions_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" ) func expectedTransaction(t *testing.T, ledger uint32, feeBump bool) Transaction { @@ -36,16 +37,16 @@ func expectedTransaction(t *testing.T, ledger uint32, feeBump bool) Transaction return tx } -func expectedLedgerInfo(ledgerSequence uint32) LedgerInfo { - return LedgerInfo{ +func expectedLedgerInfo(ledgerSequence uint32) ledgerbucketwindow.LedgerInfo { + return ledgerbucketwindow.LedgerInfo{ Sequence: ledgerSequence, CloseTime: ledgerCloseTime(ledgerSequence), } } -func expectedStoreRange(startLedger uint32, endLedger uint32) StoreRange { - return StoreRange{ +func expectedStoreRange(startLedger uint32, endLedger uint32) ledgerbucketwindow.LedgerRange { + return ledgerbucketwindow.LedgerRange{ FirstLedger: expectedLedgerInfo(startLedger), LastLedger: expectedLedgerInfo(endLedger), } @@ -295,7 +296,7 @@ func TestIngestTransactions(t *testing.T) { _, ok, storeRange := store.GetTransaction(txHash(1, false)) require.False(t, ok) - require.Equal(t, StoreRange{}, storeRange) + require.Equal(t, ledgerbucketwindow.LedgerRange{}, storeRange) // Insert ledger 1 require.NoError(t, store.IngestTransactions(txMeta(1, false))) From e9dda7349cb6702cccdbbd16fc61f88496f3cb7b Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 11 Apr 2024 21:29:49 +0200 Subject: [PATCH 2/3] Decide biggest range and startup and address feedback --- cmd/soroban-rpc/internal/jsonrpc.go | 9 +++++- .../internal/methods/get_transaction.go | 3 +- cmd/soroban-rpc/internal/methods/health.go | 29 ++++++++----------- .../internal/methods/send_transaction.go | 19 ++++-------- cmd/soroban-rpc/internal/test/health_test.go | 8 +++-- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/cmd/soroban-rpc/internal/jsonrpc.go b/cmd/soroban-rpc/internal/jsonrpc.go index 7b7096f7..688e9331 100644 --- a/cmd/soroban-rpc/internal/jsonrpc.go +++ b/cmd/soroban-rpc/internal/jsonrpc.go @@ -134,6 +134,13 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler { Logger: func(text string) { params.Logger.Debug(text) }, }, } + + // Get the largest history window + var ledgerRangeGetter methods.LedgerRangeGetter = params.EventStore + if cfg.TransactionLedgerRetentionWindow > cfg.EventLedgerRetentionWindow { + ledgerRangeGetter = params.TransactionStore + } + handlers := []struct { methodName string underlyingHandler jrpc2.Handler @@ -143,7 +150,7 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler { }{ { methodName: "getHealth", - underlyingHandler: methods.NewHealthCheck(params.TransactionStore, params.EventStore, cfg.MaxHealthyLedgerLatency), + underlyingHandler: methods.NewHealthCheck(ledgerRangeGetter, cfg.MaxHealthyLedgerLatency), longName: "get_health", queueLimit: cfg.RequestBacklogGetHealthQueueLimit, requestDurationLimit: cfg.MaxGetHealthExecutionDuration, diff --git a/cmd/soroban-rpc/internal/methods/get_transaction.go b/cmd/soroban-rpc/internal/methods/get_transaction.go index 8b1846f8..1e6ef610 100644 --- a/cmd/soroban-rpc/internal/methods/get_transaction.go +++ b/cmd/soroban-rpc/internal/methods/get_transaction.go @@ -10,6 +10,7 @@ import ( "github.com/creachadair/jrpc2/handler" "github.com/stellar/go/xdr" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/transactions" ) @@ -67,7 +68,7 @@ type GetTransactionRequest struct { } type transactionGetter interface { - GetTransaction(hash xdr.Hash) (transactions.Transaction, bool, transactions.StoreRange) + GetTransaction(hash xdr.Hash) (transactions.Transaction, bool, ledgerbucketwindow.LedgerRange) } func GetTransaction(getter transactionGetter, request GetTransactionRequest) (GetTransactionResponse, error) { diff --git a/cmd/soroban-rpc/internal/methods/health.go b/cmd/soroban-rpc/internal/methods/health.go index db577f54..7aabe707 100644 --- a/cmd/soroban-rpc/internal/methods/health.go +++ b/cmd/soroban-rpc/internal/methods/health.go @@ -8,36 +8,31 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/events" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/transactions" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" ) type HealthCheckResult struct { Status string `json:"status"` LatestLedger uint32 `json:"latestLedger"` - FirstLedger uint32 `json:"firstLedger"` + OldestLedger uint32 `json:"oldestLedger"` +} + +type LedgerRangeGetter interface { + GetLedgerRange() ledgerbucketwindow.LedgerRange } // NewHealthCheck returns a health check json rpc handler -func NewHealthCheck(txStore *transactions.MemoryStore, evStore *events.MemoryStore, maxHealthyLedgerLatency time.Duration) jrpc2.Handler { +func NewHealthCheck(ledgerRangeGetter LedgerRangeGetter, maxHealthyLedgerLatency time.Duration) jrpc2.Handler { return handler.New(func(ctx context.Context) (HealthCheckResult, error) { - txLedgerRange := txStore.GetLedgerRange() - evLedgerRange := evStore.GetLedgerRange() - if txLedgerRange.FirstLedger.Sequence < 1 || evLedgerRange.FirstLedger.Sequence < 1 { + ledgerRange := ledgerRangeGetter.GetLedgerRange() + if ledgerRange.LastLedger.Sequence < 1 { return HealthCheckResult{}, jrpc2.Error{ Code: jrpc2.InternalError, Message: "data stores are not initialized", } } - mergedRange := evLedgerRange - if txLedgerRange.FirstLedger.Sequence < mergedRange.FirstLedger.Sequence { - mergedRange.FirstLedger = txLedgerRange.FirstLedger - } - if txLedgerRange.LastLedger.Sequence > mergedRange.LastLedger.Sequence { - mergedRange.LastLedger = txLedgerRange.LastLedger - } - lastKnownLedgerCloseTime := time.Unix(mergedRange.LastLedger.CloseTime, 0) + lastKnownLedgerCloseTime := time.Unix(ledgerRange.LastLedger.CloseTime, 0) lastKnownLedgerLatency := time.Since(lastKnownLedgerCloseTime) if lastKnownLedgerLatency > maxHealthyLedgerLatency { roundedLatency := lastKnownLedgerLatency.Round(time.Second) @@ -49,8 +44,8 @@ func NewHealthCheck(txStore *transactions.MemoryStore, evStore *events.MemorySto } result := HealthCheckResult{ Status: "healthy", - LatestLedger: mergedRange.LastLedger.Sequence, - FirstLedger: mergedRange.FirstLedger.Sequence, + LatestLedger: ledgerRange.LastLedger.Sequence, + OldestLedger: ledgerRange.FirstLedger.Sequence, } return result, nil }) diff --git a/cmd/soroban-rpc/internal/methods/send_transaction.go b/cmd/soroban-rpc/internal/methods/send_transaction.go index c8404c69..215e2998 100644 --- a/cmd/soroban-rpc/internal/methods/send_transaction.go +++ b/cmd/soroban-rpc/internal/methods/send_transaction.go @@ -12,7 +12,6 @@ import ( "github.com/stellar/go/xdr" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/transactions" ) // SendTransactionResponse represents the transaction submission response returned Soroban-RPC @@ -45,14 +44,8 @@ type SendTransactionRequest struct { Transaction string `json:"transaction"` } -// LatestLedgerStore is a store which returns the latest ingested ledger. -type LatestLedgerStore interface { - // GetLatestLedger returns the latest ingested ledger. - GetLatestLedger() transactions.LedgerInfo -} - // NewSendTransactionHandler returns a submit transaction json rpc handler -func NewSendTransactionHandler(daemon interfaces.Daemon, logger *log.Entry, store LatestLedgerStore, passphrase string) jrpc2.Handler { +func NewSendTransactionHandler(daemon interfaces.Daemon, logger *log.Entry, ledgerRangeGetter LedgerRangeGetter, passphrase string) jrpc2.Handler { submitter := daemon.CoreClient() return handler.New(func(ctx context.Context, request SendTransactionRequest) (SendTransactionResponse, error) { var envelope xdr.TransactionEnvelope @@ -74,7 +67,7 @@ func NewSendTransactionHandler(daemon interfaces.Daemon, logger *log.Entry, stor } txHash := hex.EncodeToString(hash[:]) - ledgerInfo := store.GetLatestLedger() + latestLedgerInfo := ledgerRangeGetter.GetLedgerRange().LastLedger resp, err := submitter.SubmitTransaction(ctx, request.Transaction) if err != nil { logger.WithError(err). @@ -110,15 +103,15 @@ func NewSendTransactionHandler(daemon interfaces.Daemon, logger *log.Entry, stor DiagnosticEventsXDR: events, Status: resp.Status, Hash: txHash, - LatestLedger: ledgerInfo.Sequence, - LatestLedgerCloseTime: ledgerInfo.CloseTime, + LatestLedger: latestLedgerInfo.Sequence, + LatestLedgerCloseTime: latestLedgerInfo.CloseTime, }, nil case proto.TXStatusPending, proto.TXStatusDuplicate, proto.TXStatusTryAgainLater: return SendTransactionResponse{ Status: resp.Status, Hash: txHash, - LatestLedger: ledgerInfo.Sequence, - LatestLedgerCloseTime: ledgerInfo.CloseTime, + LatestLedger: latestLedgerInfo.Sequence, + LatestLedgerCloseTime: latestLedgerInfo.CloseTime, }, nil default: logger.WithField("status", resp.Status). diff --git a/cmd/soroban-rpc/internal/test/health_test.go b/cmd/soroban-rpc/internal/test/health_test.go index 46a327fd..3f39c62c 100644 --- a/cmd/soroban-rpc/internal/test/health_test.go +++ b/cmd/soroban-rpc/internal/test/health_test.go @@ -6,8 +6,9 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/jhttp" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" "github.com/stretchr/testify/assert" + + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" ) func TestHealth(t *testing.T) { @@ -20,5 +21,8 @@ func TestHealth(t *testing.T) { if err := client.CallResult(context.Background(), "getHealth", nil, &result); err != nil { t.Fatalf("rpc call failed: %v", err) } - assert.Equal(t, methods.HealthCheckResult{Status: "healthy"}, result) + assert.Equal(t, "healthy", result.Status) + assert.Greater(t, result.OldestLedger, uint32(0)) + assert.Greater(t, result.LatestLedger, uint32(0)) + assert.GreaterOrEqual(t, result.LatestLedger, result.OldestLedger) } From 2ba572099038cc6a45c1ef0826d2aae2d5032105 Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 11 Apr 2024 22:21:57 +0200 Subject: [PATCH 3/3] Expose the maximum ledger retention window --- cmd/soroban-rpc/internal/jsonrpc.go | 4 +++- cmd/soroban-rpc/internal/methods/health.go | 16 +++++++++------- cmd/soroban-rpc/internal/test/health_test.go | 2 ++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/soroban-rpc/internal/jsonrpc.go b/cmd/soroban-rpc/internal/jsonrpc.go index 688e9331..b0ceb372 100644 --- a/cmd/soroban-rpc/internal/jsonrpc.go +++ b/cmd/soroban-rpc/internal/jsonrpc.go @@ -137,7 +137,9 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler { // Get the largest history window var ledgerRangeGetter methods.LedgerRangeGetter = params.EventStore + var retentionWindow = cfg.EventLedgerRetentionWindow if cfg.TransactionLedgerRetentionWindow > cfg.EventLedgerRetentionWindow { + retentionWindow = cfg.TransactionLedgerRetentionWindow ledgerRangeGetter = params.TransactionStore } @@ -150,7 +152,7 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler { }{ { methodName: "getHealth", - underlyingHandler: methods.NewHealthCheck(ledgerRangeGetter, cfg.MaxHealthyLedgerLatency), + underlyingHandler: methods.NewHealthCheck(retentionWindow, ledgerRangeGetter, cfg.MaxHealthyLedgerLatency), longName: "get_health", queueLimit: cfg.RequestBacklogGetHealthQueueLimit, requestDurationLimit: cfg.MaxGetHealthExecutionDuration, diff --git a/cmd/soroban-rpc/internal/methods/health.go b/cmd/soroban-rpc/internal/methods/health.go index 7aabe707..b8f684af 100644 --- a/cmd/soroban-rpc/internal/methods/health.go +++ b/cmd/soroban-rpc/internal/methods/health.go @@ -12,9 +12,10 @@ import ( ) type HealthCheckResult struct { - Status string `json:"status"` - LatestLedger uint32 `json:"latestLedger"` - OldestLedger uint32 `json:"oldestLedger"` + Status string `json:"status"` + LatestLedger uint32 `json:"latestLedger"` + OldestLedger uint32 `json:"oldestLedger"` + LedgerRetentionWindow uint32 `json:"ledgerRetentionWindow"` } type LedgerRangeGetter interface { @@ -22,7 +23,7 @@ type LedgerRangeGetter interface { } // NewHealthCheck returns a health check json rpc handler -func NewHealthCheck(ledgerRangeGetter LedgerRangeGetter, maxHealthyLedgerLatency time.Duration) jrpc2.Handler { +func NewHealthCheck(retentionWindow uint32, ledgerRangeGetter LedgerRangeGetter, maxHealthyLedgerLatency time.Duration) jrpc2.Handler { return handler.New(func(ctx context.Context) (HealthCheckResult, error) { ledgerRange := ledgerRangeGetter.GetLedgerRange() if ledgerRange.LastLedger.Sequence < 1 { @@ -43,9 +44,10 @@ func NewHealthCheck(ledgerRangeGetter LedgerRangeGetter, maxHealthyLedgerLatency } } result := HealthCheckResult{ - Status: "healthy", - LatestLedger: ledgerRange.LastLedger.Sequence, - OldestLedger: ledgerRange.FirstLedger.Sequence, + Status: "healthy", + LatestLedger: ledgerRange.LastLedger.Sequence, + OldestLedger: ledgerRange.FirstLedger.Sequence, + LedgerRetentionWindow: retentionWindow, } return result, nil }) diff --git a/cmd/soroban-rpc/internal/test/health_test.go b/cmd/soroban-rpc/internal/test/health_test.go index 3f39c62c..75e097d4 100644 --- a/cmd/soroban-rpc/internal/test/health_test.go +++ b/cmd/soroban-rpc/internal/test/health_test.go @@ -8,6 +8,7 @@ import ( "github.com/creachadair/jrpc2/jhttp" "github.com/stretchr/testify/assert" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" ) @@ -22,6 +23,7 @@ func TestHealth(t *testing.T) { t.Fatalf("rpc call failed: %v", err) } assert.Equal(t, "healthy", result.Status) + assert.Equal(t, uint32(ledgerbucketwindow.DefaultEventLedgerRetentionWindow), result.LedgerRetentionWindow) assert.Greater(t, result.OldestLedger, uint32(0)) assert.Greater(t, result.LatestLedger, uint32(0)) assert.GreaterOrEqual(t, result.LatestLedger, result.OldestLedger)