Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 .github/workflows/test-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
GITHUB_REF_NAME: ${{ github.ref_name }}
run: |
# Default fallback commit
DEFAULT_COMMIT="a51bdc9833d1a4641c2d7969414dbe23a4fa345e"
DEFAULT_COMMIT="c87b8c55ace0d48112a65e8a0659d3af4ef2f1cf"
REF="$DEFAULT_COMMIT"
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
# For pull_request events, we only look at the PR's base branch
Expand Down
16 changes: 9 additions & 7 deletions api/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ import (
type Events struct {
repo *chain.Repository
db *logdb.LogDB
limit uint64
maxLimit uint64
maxOffset uint64
maxCriteriaCount int
}

func New(repo *chain.Repository, db *logdb.LogDB, logsLimit uint64, maxCriteriaCount int) *Events {
func New(repo *chain.Repository, db *logdb.LogDB, maxLimit uint64, maxOffset uint64, maxCriteriaCount int) *Events {
return &Events{
repo,
db,
logsLimit,
maxLimit,
maxOffset,
maxCriteriaCount,
}
}
Expand Down Expand Up @@ -58,7 +60,7 @@ func (e *Events) handleFilter(w http.ResponseWriter, req *http.Request) error {
if err := restutil.ParseJSON(req.Body, &filter); err != nil {
return restutil.BadRequest(errors.WithMessage(err, "body"))
}
if err := filter.Options.Validate(e.limit); err != nil {
if err := filter.Options.Validate(e.maxLimit, e.maxOffset); err != nil {
return restutil.Forbidden(err)
}
if err := filter.Range.Validate(); err != nil {
Expand All @@ -83,7 +85,7 @@ func (e *Events) handleFilter(w http.ResponseWriter, req *http.Request) error {
if filter.Options.Limit == nil {
// if filter.Options.Limit is nil, set to the default limit +1
// to detect whether there are more logs than the default limit
limit := e.limit + 1
limit := e.maxLimit + 1
filter.Options.Limit = &limit
}

Expand All @@ -93,8 +95,8 @@ func (e *Events) handleFilter(w http.ResponseWriter, req *http.Request) error {
}

// ensure the result size is less than the configured limit
if len(fes) > int(e.limit) {
return restutil.Forbidden(fmt.Errorf("the number of filtered logs exceeds the maximum allowed value of %d, please use pagination", e.limit))
if len(fes) > int(e.maxLimit) {
return restutil.Forbidden(fmt.Errorf("the number of filtered logs exceeds the maximum allowed value of %d, please use pagination", e.maxLimit))
}

return restutil.WriteJSON(w, fes)
Expand Down
40 changes: 30 additions & 10 deletions api/events/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@ import (
"github.com/vechain/thor/v2/tx"
)

const defaultLogLimit uint64 = 1000
const (
defaultLogLimit uint64 = 1000
defaultLogOffset uint64 = 100
)

var (
ts *httptest.Server
tclient *thorclient.Client
)

func TestEmptyEvents(t *testing.T) {
initEventServer(t, defaultLogLimit)
initEventServer(t, defaultLogLimit, defaultLogOffset)
defer ts.Close()

tclient = thorclient.New(ts.URL)
Expand All @@ -49,7 +52,7 @@ func TestEmptyEvents(t *testing.T) {
}

func TestEvents(t *testing.T) {
thorChain := initEventServer(t, defaultLogLimit)
thorChain := initEventServer(t, defaultLogLimit, defaultLogOffset)
defer ts.Close()

blocksToInsert := 5
Expand All @@ -59,7 +62,7 @@ func TestEvents(t *testing.T) {
}

func TestOptionalIndexes(t *testing.T) {
thorChain := initEventServer(t, defaultLogLimit)
thorChain := initEventServer(t, defaultLogLimit, defaultLogOffset)
defer ts.Close()
insertBlocks(t, thorChain, 5)
tclient = thorclient.New(ts.URL)
Expand Down Expand Up @@ -109,7 +112,7 @@ func TestOptionalIndexes(t *testing.T) {
}

func TestEvents_WithOptionsNoLimit(t *testing.T) {
thorChain := initEventServer(t, defaultLogLimit)
thorChain := initEventServer(t, defaultLogLimit, defaultLogOffset)
defer ts.Close()
insertBlocks(t, thorChain, 5)

Expand All @@ -133,7 +136,7 @@ func TestEvents_WithOptionsNoLimit(t *testing.T) {
}

func TestOption(t *testing.T) {
thorChain := initEventServer(t, 5)
thorChain := initEventServer(t, 5, defaultLogOffset)
defer ts.Close()
insertBlocks(t, thorChain, 5)

Expand Down Expand Up @@ -197,10 +200,27 @@ func TestOption(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, http.StatusBadRequest, statusCode)
assert.Equal(t, "number of criteria in criteriaSet: 11 cannot be greater than: 10\n", string(res))

filter = api.EventFilter{
CriteriaSet: make([]*api.EventCriteria, 0),
Range: nil,
Options: &api.Options{Offset: defaultLogOffset, Limit: new(uint64(0))},
Order: logdb.DESC,
}

_, statusCode, err = tclient.RawHTTPClient().RawHTTPPost("/logs/event", filter)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, statusCode)

filter.Options.Offset = defaultLogOffset * 2
res, statusCode, err = tclient.RawHTTPClient().RawHTTPPost("/logs/event", filter)
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, statusCode)
assert.Equal(t, "options.offset exceeds the maximum allowed value of 100", strings.Trim(string(res), "\n"))
}

func TestZeroFrom(t *testing.T) {
thorChain := initEventServer(t, 100)
thorChain := initEventServer(t, 100, defaultLogOffset)
defer ts.Close()
insertBlocks(t, thorChain, 5)

Expand Down Expand Up @@ -234,7 +254,7 @@ func TestZeroFrom(t *testing.T) {
}

func TestNullCriteriaSet(t *testing.T) {
initEventServer(t, defaultLogLimit)
initEventServer(t, defaultLogLimit, defaultLogOffset)
defer ts.Close()

tclient = thorclient.New(ts.URL)
Expand Down Expand Up @@ -328,12 +348,12 @@ func testEventWithBlocks(t *testing.T, expectedBlocks int) {
}

// Init functions
func initEventServer(t *testing.T, limit uint64) *testchain.Chain {
func initEventServer(t *testing.T, limit uint64, offset uint64) *testchain.Chain {
thorChain, err := testchain.NewDefault()
require.NoError(t, err)

router := mux.NewRouter()
New(thorChain.Repo(), thorChain.LogDB(), limit, 10).Mount(router, "/logs/event")
New(thorChain.Repo(), thorChain.LogDB(), limit, offset, 10).Mount(router, "/logs/event")
ts = httptest.NewServer(router)

return thorChain
Expand Down
8 changes: 4 additions & 4 deletions api/events_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package api

import (
"fmt"
"math"

"github.com/ethereum/go-ethereum/common/hexutil"

Expand Down Expand Up @@ -73,15 +72,16 @@ type Options struct {
IncludeIndexes bool `json:"includeIndexes,omitempty"`
}

func (o *Options) Validate(limit uint64) error {
func (o *Options) Validate(limit uint64, offset uint64) error {
if o == nil {
return nil
}
if o.Limit != nil && *o.Limit > limit {
return fmt.Errorf("options.limit exceeds the maximum allowed value of %d", limit)
}
if o.Offset > math.MaxInt64 {
return fmt.Errorf("options.offset exceeds the maximum allowed value of %d", math.MaxInt64)

if o.Offset > offset {
return fmt.Errorf("options.offset exceeds the maximum allowed value of %d", offset)
}

return nil
Expand Down
16 changes: 9 additions & 7 deletions api/transfers/transfers.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ import (
type Transfers struct {
repo *chain.Repository
db *logdb.LogDB
limit uint64
maxLimit uint64
maxOffset uint64
maxCriteriaCount int
}

func New(repo *chain.Repository, db *logdb.LogDB, logsLimit uint64, maxCriteriaCount int) *Transfers {
func New(repo *chain.Repository, db *logdb.LogDB, maxLimit uint64, maxOffset uint64, maxCriteriaCount int) *Transfers {
return &Transfers{
repo,
db,
logsLimit,
maxLimit,
maxOffset,
maxCriteriaCount,
}
}
Expand Down Expand Up @@ -66,7 +68,7 @@ func (t *Transfers) handleFilterTransferLogs(w http.ResponseWriter, req *http.Re
if err := restutil.ParseJSON(req.Body, &filter); err != nil {
return restutil.BadRequest(errors.WithMessage(err, "body"))
}
if err := filter.Options.Validate(t.limit); err != nil {
if err := filter.Options.Validate(t.maxLimit, t.maxOffset); err != nil {
return restutil.Forbidden(err)
}
if err := filter.Range.Validate(); err != nil {
Expand All @@ -91,7 +93,7 @@ func (t *Transfers) handleFilterTransferLogs(w http.ResponseWriter, req *http.Re
if filter.Options.Limit == nil {
// if filter.Options.Limit is nil, set to the default limit +1
// to detect whether there are more logs than the default limit
limit := t.limit + 1
limit := t.maxLimit + 1
filter.Options.Limit = &limit
}

Expand All @@ -101,8 +103,8 @@ func (t *Transfers) handleFilterTransferLogs(w http.ResponseWriter, req *http.Re
}

// ensure the result size is less than the configured limit
if len(tLogs) > int(t.limit) {
return restutil.Forbidden(fmt.Errorf("the number of filtered logs exceeds the maximum allowed value of %d, please use pagination", t.limit))
if len(tLogs) > int(t.maxLimit) {
return restutil.Forbidden(fmt.Errorf("the number of filtered logs exceeds the maximum allowed value of %d, please use pagination", t.maxLimit))
}

return restutil.WriteJSON(w, tLogs)
Expand Down
36 changes: 28 additions & 8 deletions api/transfers/transfers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ import (
"github.com/vechain/thor/v2/tx"
)

const defaultLogLimit uint64 = 1000
const (
defaultLogLimit uint64 = 1000
defaultLogOffset uint64 = 100
)

var (
ts *httptest.Server
Expand All @@ -37,7 +40,7 @@ var (

func TestEmptyTransfers(t *testing.T) {
db := createDb(t)
initTransferServer(t, db, defaultLogLimit)
initTransferServer(t, db, defaultLogLimit, defaultLogOffset)
defer ts.Close()

tclient = thorclient.New(ts.URL)
Expand All @@ -47,7 +50,7 @@ func TestEmptyTransfers(t *testing.T) {

func TestTransfers(t *testing.T) {
db := createDb(t)
initTransferServer(t, db, defaultLogLimit)
initTransferServer(t, db, defaultLogLimit, defaultLogOffset)
defer ts.Close()

tclient = thorclient.New(ts.URL)
Expand All @@ -59,7 +62,7 @@ func TestTransfers(t *testing.T) {

func TestOption(t *testing.T) {
db := createDb(t)
initTransferServer(t, db, 5)
initTransferServer(t, db, 5, 100)
defer ts.Close()
insertBlocks(t, db, 5)

Expand Down Expand Up @@ -100,11 +103,28 @@ func TestOption(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, statusCode)
assert.Equal(t, "the number of filtered logs exceeds the maximum allowed value of 5, please use pagination", strings.Trim(string(res), "\n"))

filter = api.TransferFilter{
CriteriaSet: make([]*logdb.TransferCriteria, 0),
Range: nil,
Options: &api.Options{Offset: defaultLogOffset, Limit: new(uint64(0))},
Order: logdb.DESC,
}

_, statusCode, err = tclient.RawHTTPClient().RawHTTPPost("/logs/transfer", filter)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, statusCode)

filter.Options.Offset = defaultLogOffset * 2
res, statusCode, err = tclient.RawHTTPClient().RawHTTPPost("/logs/transfer", filter)
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, statusCode)
assert.Equal(t, "options.offset exceeds the maximum allowed value of 100", strings.Trim(string(res), "\n"))
}

func TestOptionalData(t *testing.T) {
db := createDb(t)
initTransferServer(t, db, defaultLogLimit)
initTransferServer(t, db, defaultLogLimit, defaultLogOffset)
defer ts.Close()
insertBlocks(t, db, 5)
tclient = thorclient.New(ts.URL)
Expand Down Expand Up @@ -155,7 +175,7 @@ func TestOptionalData(t *testing.T) {

func TestNullCriteriaSet(t *testing.T) {
db := createDb(t)
initTransferServer(t, db, defaultLogLimit)
initTransferServer(t, db, defaultLogLimit, defaultLogOffset)
defer ts.Close()
tclient = thorclient.New(ts.URL)

Expand Down Expand Up @@ -265,12 +285,12 @@ func insertBlocks(t *testing.T, db *logdb.LogDB, n int) {
}
}

func initTransferServer(t *testing.T, logDb *logdb.LogDB, limit uint64) {
func initTransferServer(t *testing.T, logDb *logdb.LogDB, limit uint64, offset uint64) {
thorChain, err := testchain.NewDefault()
require.NoError(t, err)

router := mux.NewRouter()
New(thorChain.Repo(), logDb, limit, 10).Mount(router, "/logs/transfer")
New(thorChain.Repo(), logDb, limit, offset, 10).Mount(router, "/logs/transfer")

ts = httptest.NewServer(router)
}
Expand Down
16 changes: 16 additions & 0 deletions cmd/thor/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ var (
Usage: "limit the number of logs returned by /logs API",
Sources: envVar("API_LOGS_LIMIT"),
}
apiLogsMaxOffsetFlag = &cli.Uint64Flag{
Name: "api-logs-max-offset",
Local: true,
Hidden: true,
Value: 100_000,
Comment thread
moglu2017 marked this conversation as resolved.
Outdated
Usage: "limit the maximum offset for /logs API",
Sources: envVar("API_LOGS_MAX_OFFSET"),
}
apiEnableDeprecatedFlag = &cli.BoolFlag{
Name: "api-enable-deprecated",
Local: true,
Expand All @@ -130,6 +138,14 @@ var (
Usage: "enable creation of additional indexes on startup",
Sources: envVar("LOGDB_ADDITIONAL_INDEXES"),
}
logDbMaxReadConnsFlag = &cli.Uint64Flag{
Name: "logdb-max-read-conns",
Local: true,
Value: 64,
Comment thread
moglu2017 marked this conversation as resolved.
Usage: "maximum number of read connections for the log database",
Sources: envVar("LOGDB_MAX_READ_CONNS"),
}

// priority fees API flags
apiPriorityFeesPercentageFlag = &cli.Uint64Flag{
Name: "api-priority-fees-percentage",
Expand Down
5 changes: 3 additions & 2 deletions cmd/thor/httpserver/api_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type APIConfig struct {
Timeout int
SlowQueriesThreshold int
Log5XXErrors bool
MaxLogsOffset uint64
}

func StartAPIServer(
Expand Down Expand Up @@ -109,8 +110,8 @@ func StartAPIServer(

accounts.New(repo, stater, config.CallGasLimit, config.BatchDataMaxSize, forkConfig, bft, config.EnableDeprecated).Mount(router, "/accounts")
if !config.SkipLogs {
events.New(repo, logDB, config.LogsLimit, defaultMaxCriteriaCount).Mount(router, "/logs/event")
transfers.New(repo, logDB, config.LogsLimit, defaultMaxCriteriaCount).Mount(router, "/logs/transfer")
events.New(repo, logDB, config.LogsLimit, config.MaxLogsOffset, defaultMaxCriteriaCount).Mount(router, "/logs/event")
transfers.New(repo, logDB, config.LogsLimit, config.MaxLogsOffset, defaultMaxCriteriaCount).Mount(router, "/logs/transfer")
}
blocks.New(repo, bft).Mount(router, "/blocks")
transactions.New(repo, txPool).Mount(router, "/transactions")
Expand Down
Loading
Loading