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

/exp/lighthorizon: new endpoints for tx and ops paged listing by account id #4453

Merged
merged 27 commits into from
Jul 22, 2022
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3982ea7
#4333: wip on tx/ops by account id
sreuland Jul 5, 2022
dcc8953
#4033: new endpoints for tx and ops by account id
sreuland Jul 8, 2022
ae5f81d
#4433: more verbose error message for missing ledger
sreuland Jul 8, 2022
8f370af
#4433: updated the api docs
sreuland Jul 8, 2022
09ebf0a
#4433: removed static check warnings
sreuland Jul 9, 2022
fc233f8
#4433: added interfaces for transactxion and account data access
sreuland Jul 10, 2022
6aff024
#4433: refactor domain model for operations/transactions interface
sreuland Jul 11, 2022
ec950a8
Merge remote-tracking branch 'upstream/lighthorizon' into lite_search…
sreuland Jul 11, 2022
427611d
Merge remote-tracking branch 'upstream/lighthorizon' into lite_search…
sreuland Jul 12, 2022
ad2b90a
#4433: fixes to incorporate after latest merge of metrics
sreuland Jul 12, 2022
be847d1
#4433: fixed race condition during index flush
sreuland Jul 12, 2022
f5051d8
Merge remote-tracking branch 'upstream/lighthorizon' into lite_search…
sreuland Jul 15, 2022
5c9e551
#4433: removed unnecessary /operations /transactions endpoints
sreuland Jul 15, 2022
6de7faa
#4433: refactored service tx index traversal to be less duplicate code
sreuland Jul 15, 2022
99ab856
Merge remote-tracking branch 'upstream/lighthorizon' into lite_search…
sreuland Jul 20, 2022
91fcd88
#4433: pr feedback, refactor index search interface to be on ledger s…
sreuland Jul 20, 2022
5ffcb32
#4433: pr feedback, make zero-based operations index the standard on …
sreuland Jul 20, 2022
a6b87ec
#4433: pr feedback, parameterize the index name
sreuland Jul 21, 2022
fa45ee2
#4433: pr feedback, cleanup up method docs
sreuland Jul 21, 2022
53fde55
#4433: pr feedback, perf optimize on index checkpoint reads
sreuland Jul 21, 2022
483434b
#4433: fixed static check error
sreuland Jul 21, 2022
ff5b145
#4433: fixed go fmt warning
sreuland Jul 21, 2022
223626e
Merge remote-tracking branch 'upstream/lighthorizon' into lite_search…
sreuland Jul 21, 2022
62370cf
#4433: used CheckpointManager for some of checkpoint math
sreuland Jul 22, 2022
90cd1f1
#4433: fixed index next checkpoint counter values
sreuland Jul 22, 2022
882408f
#4433: remove debugging code
sreuland Jul 22, 2022
4647710
#4433: fixed unit test failure
sreuland Jul 22, 2022
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
129 changes: 129 additions & 0 deletions exp/lighthorizon/actions/accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package actions

import (
"net/http"
"strconv"

"github.com/stellar/go/support/log"

"github.com/stellar/go/exp/lighthorizon/adapters"
"github.com/stellar/go/exp/lighthorizon/services"
hProtocol "github.com/stellar/go/protocols/horizon"
"github.com/stellar/go/protocols/horizon/operations"
"github.com/stellar/go/support/render/hal"
"github.com/stellar/go/toid"
)

const (
urlAccountId = "account_id"
)

func accountRequestParams(w http.ResponseWriter, r *http.Request) (string, pagination) {
var accountId string
var accountErr bool

if accountId, accountErr = getURLParam(r, urlAccountId); !accountErr {
sendErrorResponse(w, http.StatusBadRequest, "")
return "", pagination{}
sreuland marked this conversation as resolved.
Show resolved Hide resolved
}

paginate, err := paging(r)
if err != nil {
sendErrorResponse(w, http.StatusBadRequest, string(invalidPagingParameters))
return "", pagination{}
}

if paginate.Cursor < 1 {
paginate.Cursor = toid.New(1, 1, 1).ToInt64()
}

if paginate.Limit == 0 {
paginate.Limit = 10
sreuland marked this conversation as resolved.
Show resolved Hide resolved
}

return accountId, paginate
}

func NewTXByAccountHandler(lightHorizon services.LightHorizon) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var accountId string
var paginate pagination

if accountId, paginate = accountRequestParams(w, r); accountId == "" {
return
}

page := hal.Page{
Cursor: strconv.FormatInt(paginate.Cursor, 10),
Order: string(paginate.Order),
Limit: uint64(paginate.Limit),
}
page.Init()
page.FullURL = r.URL

txns, err := lightHorizon.Transactions.GetTransactionsByAccount(ctx, paginate.Cursor, paginate.Limit, accountId)
if err != nil {
log.Error(err)
sendErrorResponse(w, http.StatusInternalServerError, "")
return
}

for _, txn := range txns {
var response hProtocol.Transaction
response, err = adapters.PopulateTransaction(r, &txn)
if err != nil {
log.Error(err)
sendErrorResponse(w, http.StatusInternalServerError, "")
return
}

page.Add(response)
}

page.PopulateLinks()
sendPageResponse(w, page)
}
}

func NewOpsByAccountHandler(lightHorizon services.LightHorizon) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var accountId string
var paginate pagination

if accountId, paginate = accountRequestParams(w, r); accountId == "" {
return
}

page := hal.Page{
Cursor: strconv.FormatInt(paginate.Cursor, 10),
Order: string(paginate.Order),
Limit: uint64(paginate.Limit),
}
page.Init()
page.FullURL = r.URL

ops, err := lightHorizon.Operations.GetOperationsByAccount(ctx, paginate.Cursor, paginate.Limit, accountId)
if err != nil {
log.Error(err)
sendErrorResponse(w, http.StatusInternalServerError, "")
return
}

for _, op := range ops {
var response operations.Operation
response, err = adapters.PopulateOperation(r, &op)
if err != nil {
log.Error(err)
sendErrorResponse(w, http.StatusInternalServerError, "")
return
}

page.Add(response)
}

page.PopulateLinks()
sendPageResponse(w, page)
}
}
88 changes: 63 additions & 25 deletions exp/lighthorizon/actions/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,50 @@ import (
"net/url"
"strconv"

"github.com/go-chi/chi"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/stellar/go/support/log"
"github.com/stellar/go/support/render/hal"
)

var (
//go:embed static
staticFiles embed.FS
//lint:ignore U1000 temporary
requestCount = promauto.NewCounter(prometheus.CounterOpts{
Name: "horizon_lite_request_count",
Help: "How many requests have occurred?",
})
//lint:ignore U1000 temporary
requestTime = promauto.NewHistogram(prometheus.HistogramOpts{
Name: "horizon_lite_request_duration",
Help: "How long do requests take?",
Buckets: append(
prometheus.LinearBuckets(0, 50, 20),
prometheus.LinearBuckets(1000, 1000, 8)...,
),
})
)

type Order string
type ErrorMessage string
type order string
type errorMessage string

const (
OrderAsc Order = "asc"
OrderDesc Order = "desc"
orderAsc order = "asc"
orderDesc order = "desc"
)

const (
ServerError ErrorMessage = "Error: A problem occurred on the server while processing request"
InvalidPagingParameters ErrorMessage = "Error: Invalid paging parameters"
//TODO - refactor to use horizon 'problems' package
serverError errorMessage = "Error: A problem occurred on the server while processing request"
invalidPagingParameters errorMessage = "Error: Invalid paging parameters"
)

type Pagination struct {
Limit int64
type pagination struct {
Limit uint64
Cursor int64
Order
Order order
}

func sendPageResponse(w http.ResponseWriter, page hal.Page) {
Expand All @@ -49,46 +67,66 @@ func sendErrorResponse(w http.ResponseWriter, errorCode int, errorMsg string) {
if errorMsg != "" {
http.Error(w, errorMsg, errorCode)
} else {
http.Error(w, string(ServerError), errorCode)
http.Error(w, string(serverError), errorCode)
}
}

func RequestUnaryParam(r *http.Request, paramName string) (string, error) {
func requestUnaryParam(r *http.Request, paramName string) (string, error) {
query, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
return "", err
}
return query.Get(paramName), nil
}

func Paging(r *http.Request) (Pagination, error) {
paginate := Pagination{
Order: OrderAsc,
func paging(r *http.Request) (pagination, error) {
paginate := pagination{
Order: orderAsc,
}

if cursorRequested, err := RequestUnaryParam(r, "cursor"); err != nil {
return Pagination{}, err
if cursorRequested, err := requestUnaryParam(r, "cursor"); err != nil {
return pagination{}, err
} else if cursorRequested != "" {
paginate.Cursor, err = strconv.ParseInt(cursorRequested, 10, 64)
if err != nil {
return Pagination{}, err
return pagination{}, err
}
}

if limitRequested, err := RequestUnaryParam(r, "limit"); err != nil {
return Pagination{}, err
if limitRequested, err := requestUnaryParam(r, "limit"); err != nil {
return pagination{}, err
} else if limitRequested != "" {
paginate.Limit, err = strconv.ParseInt(limitRequested, 10, 64)
paginate.Limit, err = strconv.ParseUint(limitRequested, 10, 64)
if err != nil {
return Pagination{}, err
return pagination{}, err
}
}

if orderRequested, err := RequestUnaryParam(r, "order"); err != nil {
return Pagination{}, err
} else if orderRequested != "" && orderRequested == string(OrderDesc) {
paginate.Order = OrderDesc
if orderRequested, err := requestUnaryParam(r, "order"); err != nil {
return pagination{}, err
} else if orderRequested != "" && orderRequested == string(orderDesc) {
paginate.Order = orderDesc
}

return paginate, nil
}

func getURLParam(r *http.Request, key string) (string, bool) {
rctx := chi.RouteContext(r.Context())

if rctx == nil {
return "", false
}

if len(rctx.URLParams.Keys) != len(rctx.URLParams.Values) {
return "", false
}

for k := len(rctx.URLParams.Keys) - 1; k >= 0; k-- {
if rctx.URLParams.Keys[k] == key {
return rctx.URLParams.Values[k], true
}
}

return "", false
}
105 changes: 0 additions & 105 deletions exp/lighthorizon/actions/operation.go

This file was deleted.

Loading