Skip to content
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
6 changes: 4 additions & 2 deletions integration/token/fungible/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ func GetEndorsers(network *integration.Infrastructure, sel *token3.ReplicaSelect

func CheckAuditedTransactions(network *integration.Infrastructure, auditor *token3.NodeReference, expected []TransactionRecord, start *time.Time, end *time.Time) {
txsBoxed, err := network.Client(auditor.ReplicaName()).CallView("historyAuditing", common.JSONMarshall(&views.ListAuditedTransactions{
From: start,
To: end,
From: start,
To: end,
SearchDirection: ttxdb.FromBeginning,
}))
gomega.Expect(err).NotTo(gomega.HaveOccurred())
var txs []*ttxdb.TransactionRecord
Expand Down Expand Up @@ -214,6 +215,7 @@ func CheckAcceptedTransactions(network *integration.Infrastructure, id *token3.N
To: end,
ActionTypes: actionTypes,
Statuses: statuses,
SearchDirection: ttxdb.FromBeginning,
}
txsBoxed, err := network.Client(id.ReplicaName()).CallView("acceptedTransactionHistory", common.JSONMarshall(&params))
gomega.Expect(err).NotTo(gomega.HaveOccurred())
Expand Down
9 changes: 6 additions & 3 deletions integration/token/fungible/views/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ func (i *ListIssuedTokensViewFactory) NewView(in []byte) (view.View, error) {
}

type ListAuditedTransactions struct {
From *time.Time
To *time.Time
From *time.Time
To *time.Time
SearchDirection ttxdb.SearchDirection
}

type ListAuditedTransactionsView struct {
Expand All @@ -79,7 +80,7 @@ func (p *ListAuditedTransactionsView) Call(context view.Context) (interface{}, e
return nil, errors.Wrapf(err, "failed to get auditor instance")
}

it, err := auditor.Transactions(context.Context(), ttxdb.QueryTransactionsParams{From: p.From, To: p.To}, pagination.None())
it, err := auditor.Transactions(context.Context(), ttxdb.QueryTransactionsParams{From: p.From, To: p.To, SearchDirection: p.SearchDirection}, pagination.None())
if err != nil {
return nil, errors.Wrapf(err, "failed querying transactions")
}
Expand Down Expand Up @@ -108,6 +109,7 @@ type ListAcceptedTransactions struct {
Statuses []ttxdb.TxStatus
TMSID *token.TMSID
IDs []string
SearchDirection ttxdb.SearchDirection
}

type ListAcceptedTransactionsView struct {
Expand All @@ -127,6 +129,7 @@ func (p *ListAcceptedTransactionsView) Call(context view.Context) (interface{},
ActionTypes: p.ActionTypes,
Statuses: p.Statuses,
IDs: p.IDs,
SearchDirection: p.SearchDirection,
}, pagination.None())
if err != nil {
return nil, errors.Wrapf(err, "failed querying transactions")
Expand Down
27 changes: 25 additions & 2 deletions token/services/storage/db/dbtest/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ func TTransaction(t *testing.T, db driver3.TokenTransactionStore) {

// get all except last year's
t1 := time.Now().Add(time.Second * 3)
it, err := db.QueryTransactions(ctx, driver3.QueryTransactionsParams{From: &t0, To: &t1}, nil)
it, err := db.QueryTransactions(ctx, driver3.QueryTransactionsParams{From: &t0, To: &t1, SearchDirection: driver3.FromBeginning}, nil)
require.NoError(t, err)
for _, exp := range txs {
act, err := it.Items.Next()
Expand Down Expand Up @@ -547,7 +547,8 @@ func TAllowsSameTxID(t *testing.T, db driver3.TokenTransactionStore) {
require.NoError(t, w.AddTransaction(ctx, tr2))
require.NoError(t, w.Commit())

txs := getTransactions(t, db, driver3.QueryTransactionsParams{})
// Explicit ASC: tr1 first, tr2 second
txs := getTransactions(t, db, driver3.QueryTransactionsParams{SearchDirection: driver3.FromBeginning})
assert.Len(t, txs, 2)
assertTxEqual(t, &tr1, txs[0])
assertTxEqual(t, &tr2, txs[1])
Expand Down Expand Up @@ -822,6 +823,28 @@ func TTransactionQueries(t *testing.T, db driver3.TokenTransactionStore) {
assert.Len(t, res, tc.expectedLen, fmt.Sprintf("params: %v", tc.params))
})
}

// SearchDirection: redemptions have distinct stored_at (now-1day vs now+1day)
t.Run("SearchDirection ASC", func(t *testing.T) {
res := getTransactions(t, db, driver3.QueryTransactionsParams{
ActionTypes: []driver3.ActionType{driver3.Redeem},
Statuses: []driver3.TxStatus{driver3.Confirmed},
SearchDirection: driver3.FromBeginning,
})
require.Len(t, res, 2)
assert.Equal(t, "8", res[0].TxID, "ASC: older redemption first")
assert.Equal(t, "10", res[1].TxID, "ASC: newer redemption second")
})
t.Run("SearchDirection DESC", func(t *testing.T) {
res := getTransactions(t, db, driver3.QueryTransactionsParams{
ActionTypes: []driver3.ActionType{driver3.Redeem},
Statuses: []driver3.TxStatus{driver3.Confirmed},
SearchDirection: driver3.FromLast,
})
require.Len(t, res, 2)
assert.Equal(t, "10", res[0].TxID, "DESC: newer redemption first")
assert.Equal(t, "8", res[1].TxID, "DESC: older redemption second")
})
}

func getTransactions(t *testing.T, db driver3.TokenTransactionStore, params driver3.QueryTransactionsParams) []*driver3.TransactionRecord {
Expand Down
3 changes: 3 additions & 0 deletions token/services/storage/db/driver/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ type QueryTransactionsParams struct {
// TokenTypes is the list of token types to accept
// If empty, any token type is accepted
TokenTypes []token2.Type
// SearchDirection is the direction of the search.
// Default (zero value) is FromLast (descending by stored_at).
SearchDirection SearchDirection
}

// QueryValidationRecordsParams defines the parameters for querying validation records.
Expand Down
2 changes: 1 addition & 1 deletion token/services/storage/db/sql/common/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (db *TransactionStore) QueryTransactions(ctx context.Context, params driver
cond.Cmp(transactionsTable.Field("tx_id"), "=", requestsTable.Field("tx_id"))),
).
Where(HasTransactionParams(params, transactionsTable)).
OrderBy(q.Asc(common3.FieldName("stored_at"))).
OrderBy(orderBy("stored_at", params.SearchDirection)).
Paginated(pagination).
FormatPaginated(db.ci, db.pi)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestQueryTransactions(t *testing.T, store transactionsStoreConstructor) {
mockDB.
ExpectQuery("SELECT TRANSACTIONS.tx_id, action_type, sender_eid, recipient_eid, token_type, amount, " +
"REQUESTS.status, REQUESTS.application_metadata, REQUESTS.public_metadata, stored_at " +
"FROM TRANSACTIONS LEFT JOIN REQUESTS ON TRANSACTIONS.tx_id = REQUESTS.tx_id ORDER BY stored_at ASC").
"FROM TRANSACTIONS LEFT JOIN REQUESTS ON TRANSACTIONS.tx_id = REQUESTS.tx_id ORDER BY stored_at DESC").
WillReturnRows(mockDB.NewRows([]string{"tx_id", "action_type", "sender_eid", "recipient_eid", "token_type", "amount", "status", "application_metadata", "public_metadata", "stored_at"}).AddRow(output...))

info, err := store(db).QueryTransactions(t.Context(),
Expand Down
10 changes: 10 additions & 0 deletions token/services/storage/ttxdb/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ const (
Redeem = dbdriver.Redeem
)

// SearchDirection defines the direction of a search.
type SearchDirection = dbdriver.SearchDirection

const (
// FromLast defines the direction of a search from the last key.
FromLast = dbdriver.FromLast
// FromBeginning defines the direction of a search from the first key.
FromBeginning = dbdriver.FromBeginning
)

// TransactionRecord is a more finer-grained version of a movement record.
// Given a Token Transaction, for each token action in the Token Request,
// a transaction record is created for each unique enrollment ID found in the outputs.
Expand Down
Loading