Skip to content

Commit

Permalink
Add getTransactions endpoint (#136)
Browse files Browse the repository at this point in the history
* Add cursor for getTransactions

* Add validation of pagination and range

* implement getTransactions handler - 1

* Add getLedgers

* Read a single ledger instead of getting all ledgers

* Add ParseCursor method for tx cursor

* Cursor changes - 1

* Cursor changes - 2

* Cursor changes - 3

* revert go-mod changes

* Use reader.Seek()

* Use reader.Seek() - 2

* Add config-options for tx pagination limits

* Fix failing cursor test

* Go mod changes

* Go mod changes - 2

* Add unittests - 1

* Update go.mod and go.sum

* Add integration tests

* Update go.mod and go.sum

* Add ledgerSeq to error string

* Add docstrings

* Change transactions limits

* add defensive check for error other than EOF

* add defensive check for error other than EOF - 2

* Change ledger sequence to uint32

* Add comments/docstrings

* Include only cursor in response

* Use toid instead of new cursor

* Revert cursor changes

* Return cursor as string in result

* Refactor reader.Seek error handling

* Small refactoring

* Remove startLedger check

* Remove endLedger

* Import fix

* Fix failing tests

* Refactor to use new transaction db

* Refactor mocks

* Refactor unittests for using the new db changes

* Refactor integration test

* Add config vars for max requests and request duration

* Fix failing test

* Use transactionInfo struct instead of db.Transactions

* Start indexing from 1 instead of 0 for toid

* Operation index from 1

* Add lines to make sure structs implement interfaces

* Remove omitempty

* rename test func

* make txInfo struct public and convert string cursor to int

* Use sendSuccessfulTransaction helper func

* Convert cursor to string in request

* Change jrpc response codes

* Change ledger close meta code to invalid-params

* Revert back to InvalidParams error for reader.Read()

* Refactor if-else statement

* Refactor if-else statement - 2
  • Loading branch information
aditya1702 authored May 13, 2024
1 parent 711df2c commit 7eaaf61
Show file tree
Hide file tree
Showing 7 changed files with 725 additions and 8 deletions.
4 changes: 4 additions & 0 deletions cmd/soroban-rpc/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Config struct {
CheckpointFrequency uint32
CoreRequestTimeout time.Duration
DefaultEventsLimit uint
DefaultTransactionsLimit uint
EventLedgerRetentionWindow uint32
FriendbotURL string
HistoryArchiveURLs []string
Expand All @@ -33,6 +34,7 @@ type Config struct {
LogFormat LogFormat
LogLevel logrus.Level
MaxEventsLimit uint
MaxTransactionsLimit uint
MaxHealthyLedgerLatency time.Duration
NetworkPassphrase string
PreflightWorkerCount uint
Expand All @@ -48,6 +50,7 @@ type Config struct {
RequestBacklogGetLatestLedgerQueueLimit uint
RequestBacklogGetLedgerEntriesQueueLimit uint
RequestBacklogGetTransactionQueueLimit uint
RequestBacklogGetTransactionsQueueLimit uint
RequestBacklogSendTransactionQueueLimit uint
RequestBacklogSimulateTransactionQueueLimit uint
RequestExecutionWarningThreshold time.Duration
Expand All @@ -59,6 +62,7 @@ type Config struct {
MaxGetLatestLedgerExecutionDuration time.Duration
MaxGetLedgerEntriesExecutionDuration time.Duration
MaxGetTransactionExecutionDuration time.Duration
MaxGetTransactionsExecutionDuration time.Duration
MaxSendTransactionExecutionDuration time.Duration
MaxSimulateTransactionExecutionDuration time.Duration

Expand Down
35 changes: 35 additions & 0 deletions cmd/soroban-rpc/internal/config/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,28 @@ func (cfg *Config) options() ConfigOptions {
return nil
},
},
{
Name: "max-transactions-limit",
Usage: "Maximum amount of transactions allowed in a single getTransactions response",
ConfigKey: &cfg.MaxTransactionsLimit,
DefaultValue: uint(200),
},
{
Name: "default-transactions-limit",
Usage: "Default cap on the amount of transactions included in a single getTransactions response",
ConfigKey: &cfg.DefaultTransactionsLimit,
DefaultValue: uint(50),
Validate: func(co *ConfigOption) error {
if cfg.DefaultTransactionsLimit > cfg.MaxTransactionsLimit {
return fmt.Errorf(
"default-transactions-limit (%v) cannot exceed max-transactions-limit (%v)",
cfg.DefaultTransactionsLimit,
cfg.MaxTransactionsLimit,
)
}
return nil
},
},
{
Name: "max-healthy-ledger-latency",
Usage: "maximum ledger latency (i.e. time elapsed since the last known ledger closing time) considered to be healthy" +
Expand Down Expand Up @@ -334,6 +356,13 @@ func (cfg *Config) options() ConfigOptions {
DefaultValue: uint(1000),
Validate: positive,
},
{
TomlKey: strutils.KebabToConstantCase("request-backlog-get-transactions-queue-limit"),
Usage: "Maximum number of outstanding GetTransactions requests",
ConfigKey: &cfg.RequestBacklogGetTransactionsQueueLimit,
DefaultValue: uint(1000),
Validate: positive,
},
{
TomlKey: strutils.KebabToConstantCase("request-backlog-send-transaction-queue-limit"),
Usage: "Maximum number of outstanding SendTransaction requests",
Expand Down Expand Up @@ -402,6 +431,12 @@ func (cfg *Config) options() ConfigOptions {
ConfigKey: &cfg.MaxGetTransactionExecutionDuration,
DefaultValue: 5 * time.Second,
},
{
TomlKey: strutils.KebabToConstantCase("max-get-transactions-execution-duration"),
Usage: "The maximum duration of time allowed for processing a getTransactions request. When that time elapses, the rpc server would return -32001 and abort the request's execution",
ConfigKey: &cfg.MaxGetTransactionsExecutionDuration,
DefaultValue: 5 * time.Second,
},
{
TomlKey: strutils.KebabToConstantCase("max-send-transaction-execution-duration"),
Usage: "The maximum duration of time allowed for processing a sendTransaction request. When that time elapses, the rpc server would return -32001 and abort the request's execution",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,24 @@ import (
type mockTransactionHandler struct {
passphrase string

ledgerRange ledgerbucketwindow.LedgerRange
txs map[string]ingest.LedgerTransaction
ledgers map[string]*xdr.LedgerCloseMeta
ledgerRange ledgerbucketwindow.LedgerRange
txs map[string]ingest.LedgerTransaction
txHashToMeta map[string]*xdr.LedgerCloseMeta
ledgerSeqToMeta map[uint32]*xdr.LedgerCloseMeta
}

func NewMockTransactionStore(passphrase string) *mockTransactionHandler {
return &mockTransactionHandler{
passphrase: passphrase,
txs: make(map[string]ingest.LedgerTransaction),
ledgers: make(map[string]*xdr.LedgerCloseMeta),
passphrase: passphrase,
txs: make(map[string]ingest.LedgerTransaction),
txHashToMeta: make(map[string]*xdr.LedgerCloseMeta),
ledgerSeqToMeta: make(map[uint32]*xdr.LedgerCloseMeta),
}
}

func (txn *mockTransactionHandler) InsertTransactions(lcm xdr.LedgerCloseMeta) error {
txn.ledgerSeqToMeta[lcm.LedgerSequence()] = &lcm

reader, err := ingest.NewLedgerTransactionReaderFromLedgerCloseMeta(txn.passphrase, lcm)
if err != nil {
return err
Expand All @@ -44,7 +48,7 @@ func (txn *mockTransactionHandler) InsertTransactions(lcm xdr.LedgerCloseMeta) e

h := tx.Result.TransactionHash.HexString()
txn.txs[h] = tx
txn.ledgers[h] = &lcm
txn.txHashToMeta[h] = &lcm
}

if lcmSeq := lcm.LedgerSequence(); lcmSeq < txn.ledgerRange.FirstLedger.Sequence ||
Expand Down Expand Up @@ -72,12 +76,35 @@ func (txn *mockTransactionHandler) GetTransaction(ctx context.Context, hash xdr.
if tx, ok := txn.txs[hash.HexString()]; !ok {
return Transaction{}, txn.ledgerRange, ErrNoTransaction
} else {
itx, err := ParseTransaction(*txn.ledgers[hash.HexString()], tx)
itx, err := ParseTransaction(*txn.txHashToMeta[hash.HexString()], tx)
return itx, txn.ledgerRange, err
}
}

func (txn *mockTransactionHandler) RegisterMetrics(_, _ prometheus.Observer) {}

type mockLedgerReader struct {
txn mockTransactionHandler
}

func NewMockLedgerReader(txn *mockTransactionHandler) *mockLedgerReader {
return &mockLedgerReader{
txn: *txn,
}
}

func (m *mockLedgerReader) GetLedger(ctx context.Context, sequence uint32) (xdr.LedgerCloseMeta, bool, error) {
lcm, ok := m.txn.ledgerSeqToMeta[sequence]
if !ok {
return xdr.LedgerCloseMeta{}, false, nil
}
return *lcm, true, nil
}

func (m *mockLedgerReader) StreamAllLedgers(ctx context.Context, f StreamLedgerFn) error {
return nil
}

var _ TransactionReader = &mockTransactionHandler{}
var _ TransactionWriter = &mockTransactionHandler{}
var _ LedgerReader = &mockLedgerReader{}
7 changes: 7 additions & 0 deletions cmd/soroban-rpc/internal/jsonrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler {
queueLimit: cfg.RequestBacklogGetTransactionQueueLimit,
requestDurationLimit: cfg.MaxGetTransactionExecutionDuration,
},
{
methodName: "getTransactions",
underlyingHandler: methods.NewGetTransactionsHandler(params.Logger, params.LedgerReader, params.TransactionReader, cfg.MaxTransactionsLimit, cfg.DefaultTransactionsLimit, cfg.NetworkPassphrase),
longName: "get_transactions",
queueLimit: cfg.RequestBacklogGetTransactionsQueueLimit,
requestDurationLimit: cfg.MaxGetTransactionsExecutionDuration,
},
{
methodName: "sendTransaction",
underlyingHandler: methods.NewSendTransactionHandler(
Expand Down
Loading

0 comments on commit 7eaaf61

Please sign in to comment.