Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

services/horizon/internal/actions: populate default cursor value for history endpoints #5410

Merged
merged 7 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion services/horizon/internal/actions/effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type GetEffectsHandler struct {
}

func (handler GetEffectsHandler) GetResourcePage(w HeaderWriter, r *http.Request) ([]hal.Pageable, error) {
pq, err := GetPageQuery(handler.LedgerState, r)
pq, err := GetPageQuery(handler.LedgerState, r, DefaultTOID)
if err != nil {
return nil, err
}
Expand Down
14 changes: 14 additions & 0 deletions services/horizon/internal/actions/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/stellar/go/services/horizon/internal/ledger"
hProblem "github.com/stellar/go/services/horizon/internal/render/problem"
"github.com/stellar/go/support/errors"
"github.com/stellar/go/support/ordered"
"github.com/stellar/go/support/render/problem"
"github.com/stellar/go/toid"
"github.com/stellar/go/xdr"
Expand All @@ -44,6 +45,8 @@ type Opt int
const (
// DisableCursorValidation disables cursor validation in GetPageQuery
DisableCursorValidation Opt = iota
// DefaultTOID sets a default cursor value in GetPageQuery based on the ledger state
DefaultTOID Opt = iota
)

// HeaderWriter is an interface for setting HTTP response headers
Expand Down Expand Up @@ -182,10 +185,14 @@ func getLimit(r *http.Request, name string, def uint64, max uint64) (uint64, err
// using the results from a call to GetPagingParams()
func GetPageQuery(ledgerState *ledger.State, r *http.Request, opts ...Opt) (db2.PageQuery, error) {
disableCursorValidation := false
defaultTOID := false
for _, opt := range opts {
if opt == DisableCursorValidation {
disableCursorValidation = true
}
if opt == DefaultTOID {
defaultTOID = true
}
}

cursor, err := getCursor(ledgerState, r, ParamCursor)
Expand Down Expand Up @@ -214,6 +221,13 @@ func GetPageQuery(ledgerState *ledger.State, r *http.Request, opts ...Opt) (db2.

return db2.PageQuery{}, err
}
if cursor == "" && defaultTOID {
tamirms marked this conversation as resolved.
Show resolved Hide resolved
if pageQuery.Order == db2.OrderAscending {
pageQuery.Cursor = toid.AfterLedger(
ordered.Max(0, ledgerState.CurrentStatus().HistoryElder-1),
).String()
}
}

return pageQuery, nil
}
Expand Down
58 changes: 58 additions & 0 deletions services/horizon/internal/actions/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/url"
"strings"
"testing"
"time"

"github.com/go-chi/chi"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -290,6 +291,63 @@ func TestGetPageQuery(t *testing.T) {
tt.Assert.Error(err)
}

func TestGetPageQueryCursorDefaultTOID(t *testing.T) {
tamirms marked this conversation as resolved.
Show resolved Hide resolved
ascReq := makeTestActionRequest("/foo-bar/blah?limit=2", testURLParams())
descReq := makeTestActionRequest("/foo-bar/blah?limit=2&order=desc", testURLParams())

ledgerState := &ledger.State{}
ledgerState.SetHorizonStatus(ledger.HorizonStatus{
HistoryLatest: 7000,
HistoryLatestClosedAt: time.Now(),
HistoryElder: 300,
ExpHistoryLatest: 7000,
})

pq, err := GetPageQuery(ledgerState, ascReq, DefaultTOID)
assert.NoError(t, err)
assert.Equal(t, toid.AfterLedger(299).String(), pq.Cursor)
assert.Equal(t, uint64(2), pq.Limit)
assert.Equal(t, "asc", pq.Order)

pq, err = GetPageQuery(ledgerState, descReq, DefaultTOID)
assert.NoError(t, err)
assert.Equal(t, "", pq.Cursor)
assert.Equal(t, uint64(2), pq.Limit)
assert.Equal(t, "desc", pq.Order)

pq, err = GetPageQuery(ledgerState, ascReq)
assert.NoError(t, err)
assert.Empty(t, pq.Cursor)
assert.Equal(t, uint64(2), pq.Limit)
assert.Equal(t, "asc", pq.Order)

pq, err = GetPageQuery(ledgerState, descReq)
assert.NoError(t, err)
assert.Empty(t, pq.Cursor)
assert.Equal(t, "", pq.Cursor)
assert.Equal(t, "desc", pq.Order)

ledgerState.SetHorizonStatus(ledger.HorizonStatus{
HistoryLatest: 7000,
HistoryLatestClosedAt: time.Now(),
HistoryElder: 0,
ExpHistoryLatest: 7000,
})

pq, err = GetPageQuery(ledgerState, ascReq, DefaultTOID)
assert.NoError(t, err)
assert.Equal(t, toid.AfterLedger(0).String(), pq.Cursor)
assert.Equal(t, uint64(2), pq.Limit)
assert.Equal(t, "asc", pq.Order)

pq, err = GetPageQuery(ledgerState, descReq, DefaultTOID)
assert.NoError(t, err)
assert.Equal(t, "", pq.Cursor)
assert.Equal(t, uint64(2), pq.Limit)
assert.Equal(t, "desc", pq.Order)

}

func TestGetString(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
Expand Down
2 changes: 1 addition & 1 deletion services/horizon/internal/actions/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type GetLedgersHandler struct {
}

func (handler GetLedgersHandler) GetResourcePage(w HeaderWriter, r *http.Request) ([]hal.Pageable, error) {
pq, err := GetPageQuery(handler.LedgerState, r)
pq, err := GetPageQuery(handler.LedgerState, r, DefaultTOID)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion services/horizon/internal/actions/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type GetOperationsHandler struct {
func (handler GetOperationsHandler) GetResourcePage(w HeaderWriter, r *http.Request) ([]hal.Pageable, error) {
ctx := r.Context()

pq, err := GetPageQuery(handler.LedgerState, r)
pq, err := GetPageQuery(handler.LedgerState, r, DefaultTOID)
if err != nil {
return nil, err
}
Expand Down
71 changes: 48 additions & 23 deletions services/horizon/internal/actions/operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"time"

"github.com/guregu/null"
"github.com/stretchr/testify/assert"

"github.com/stellar/go/ingest"
"github.com/stellar/go/protocols/horizon/operations"
"github.com/stellar/go/services/horizon/internal/db2/history"
Expand All @@ -19,7 +21,6 @@ import (
supportProblem "github.com/stellar/go/support/render/problem"
"github.com/stellar/go/toid"
"github.com/stellar/go/xdr"
"github.com/stretchr/testify/assert"
)

func TestInvokeHostFnDetailsInPaymentOperations(t *testing.T) {
Expand All @@ -28,8 +29,14 @@ func TestInvokeHostFnDetailsInPaymentOperations(t *testing.T) {
test.ResetHorizonDB(t, tt.HorizonDB)

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{OnlyPayments: true}

handler := GetOperationsHandler{OnlyPayments: true,
LedgerState: &ledger.State{},
}
handler.LedgerState.SetHorizonStatus(ledger.HorizonStatus{
HistoryLatest: 56,
HistoryElder: 56,
ExpHistoryLatest: 56,
})
txIndex := int32(1)
sequence := int32(56)
txID := toid.New(sequence, txIndex, 0).ToInt64()
Expand Down Expand Up @@ -178,10 +185,12 @@ func TestInvokeHostFnDetailsInPaymentOperations(t *testing.T) {
func TestGetOperationsWithoutFilter(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("base")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("base"))

records, err := handler.GetResourcePage(
httptest.NewRecorder(),
Expand All @@ -196,10 +205,12 @@ func TestGetOperationsWithoutFilter(t *testing.T) {
func TestGetOperationsExclusiveFilters(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("base")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("base"))

testCases := []struct {
desc string
Expand Down Expand Up @@ -255,10 +266,12 @@ func TestGetOperationsByLiquidityPool(t *testing.T) {
func TestGetOperationsFilterByAccountID(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("base")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("base"))

testCases := []struct {
accountID string
Expand Down Expand Up @@ -296,10 +309,12 @@ func TestGetOperationsFilterByAccountID(t *testing.T) {
func TestGetOperationsFilterByTxID(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("base")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("base"))

testCases := []struct {
desc string
Expand Down Expand Up @@ -370,10 +385,12 @@ func TestGetOperationsFilterByTxID(t *testing.T) {
func TestGetOperationsIncludeFailed(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("failed_transactions")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("failed_transactions"))

records, err := handler.GetResourcePage(
httptest.NewRecorder(),
Expand Down Expand Up @@ -500,10 +517,12 @@ func TestGetOperationsIncludeFailed(t *testing.T) {
func TestGetOperationsFilterByLedgerID(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("base")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("base"))

testCases := []struct {
ledgerID string
Expand Down Expand Up @@ -571,12 +590,13 @@ func TestGetOperationsFilterByLedgerID(t *testing.T) {
func TestGetOperationsOnlyPayments(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("base")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
OnlyPayments: true,
}
handler.LedgerState.SetStatus(tt.Scenario("base"))

records, err := handler.GetResourcePage(
httptest.NewRecorder(),
Expand Down Expand Up @@ -620,7 +640,7 @@ func TestGetOperationsOnlyPayments(t *testing.T) {
tt.Assert.NoError(err)
tt.Assert.Len(records, 1)

tt.Scenario("pathed_payment")
handler.LedgerState.SetStatus(tt.Scenario("pathed_payment"))

records, err = handler.GetResourcePage(
httptest.NewRecorder(),
Expand Down Expand Up @@ -651,10 +671,12 @@ func TestGetOperationsOnlyPayments(t *testing.T) {
func TestOperation_CreatedAt(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("base")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("base"))

records, err := handler.GetResourcePage(
httptest.NewRecorder(),
Expand All @@ -676,12 +698,12 @@ func TestOperation_CreatedAt(t *testing.T) {
func TestGetOperationsPagination(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("base")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("base"))

records, err := handler.GetResourcePage(
httptest.NewRecorder(),
Expand Down Expand Up @@ -735,10 +757,12 @@ func TestGetOperationsPagination(t *testing.T) {
func TestGetOperations_IncludeTransactions(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("failed_transactions")

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{}
handler := GetOperationsHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("failed_transactions"))

_, err := handler.GetResourcePage(
httptest.NewRecorder(),
Expand Down Expand Up @@ -828,11 +852,12 @@ func TestGetOperation(t *testing.T) {
func TestOperation_IncludeTransaction(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
tt.Scenario("kahuna")

handler := GetOperationByIDHandler{
LedgerState: &ledger.State{},
}
handler.LedgerState.SetStatus(tt.Scenario("kahuna"))

record, err := handler.GetResource(
httptest.NewRecorder(),
makeRequest(
Expand Down
2 changes: 1 addition & 1 deletion services/horizon/internal/actions/trade.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ type GetTradesHandler struct {
func (handler GetTradesHandler) GetResourcePage(w HeaderWriter, r *http.Request) ([]hal.Pageable, error) {
ctx := r.Context()

pq, err := GetPageQuery(handler.LedgerState, r)
pq, err := GetPageQuery(handler.LedgerState, r, DefaultTOID)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion services/horizon/internal/actions/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type GetTransactionsHandler struct {
func (handler GetTransactionsHandler) GetResourcePage(w HeaderWriter, r *http.Request) ([]hal.Pageable, error) {
ctx := r.Context()

pq, err := GetPageQuery(handler.LedgerState, r)
pq, err := GetPageQuery(handler.LedgerState, r, DefaultTOID)
if err != nil {
return nil, err
}
Expand Down
Loading
Loading