diff --git a/internal/migrations/024-attestation-actions.sql b/internal/migrations/024-attestation-actions.sql index 99cf41ed5..739c565ec 100644 --- a/internal/migrations/024-attestation-actions.sql +++ b/internal/migrations/024-attestation-actions.sql @@ -271,11 +271,12 @@ CREATE OR REPLACE ACTION get_signed_attestation( /** * list_attestations: List attestations with optional filtering * - * Returns metadata for attestations, optionally filtered by requester. + * Returns metadata for attestations, optionally filtered by requester or request_tx_id. * Supports pagination with limit and offset. */ CREATE OR REPLACE ACTION list_attestations( $requester BYTEA, + $request_tx_id TEXT, $limit INT, $offset INT, $order_by TEXT @@ -306,17 +307,24 @@ CREATE OR REPLACE ACTION list_attestations( } } - -- Build query with optional requester filter - IF $requester IS NULL { + -- Build query with optional requester and request_tx_id filters + IF $request_tx_id IS NOT NULL { + -- Filter by specific request_tx_id (ignores other filters for exact match) + RETURN SELECT request_tx_id, attestation_hash, requester, + created_height, signed_height, encrypt_sig + FROM attestations + WHERE request_tx_id = $request_tx_id + LIMIT 1; + } ELSEIF $requester IS NULL { -- Show all attestations (analytics/auditing) IF $order_desc { - RETURN SELECT request_tx_id, attestation_hash, requester, + RETURN SELECT request_tx_id, attestation_hash, requester, created_height, signed_height, encrypt_sig FROM attestations ORDER BY created_height DESC, request_tx_id ASC LIMIT $limit OFFSET $offset; } ELSE { - RETURN SELECT request_tx_id, attestation_hash, requester, + RETURN SELECT request_tx_id, attestation_hash, requester, created_height, signed_height, encrypt_sig FROM attestations ORDER BY created_height ASC, request_tx_id ASC diff --git a/tests/streams/attestation/attestation_retrieval_test.go b/tests/streams/attestation/attestation_retrieval_test.go index b8e037e49..9796bd1f5 100644 --- a/tests/streams/attestation/attestation_retrieval_test.go +++ b/tests/streams/attestation/attestation_retrieval_test.go @@ -129,6 +129,10 @@ func TestListAttestations(t *testing.T) { testListFilterByRequester(helper, addrs) }) + t.Run("FilterByRequestTxID", func(t *testing.T) { + testListFilterByRequestTxID(helper, testActionName, addrs) + }) + t.Run("Pagination", func(t *testing.T) { testListPagination(helper, testActionName, addrs) }) @@ -144,7 +148,7 @@ func TestListAttestations(t *testing.T) { } func testListEmpty(h *AttestationTestHelper) { - count := h.CountRows("list_attestations", []any{nil, 10, 0, nil}) + count := h.CountRows("list_attestations", []any{nil, nil, 10, 0, nil}) require.Equal(h.t, 0, count, "should return no results when empty") } @@ -154,7 +158,7 @@ func testListNoFilter(h *AttestationTestHelper, actionName string, addrs *TestAd h.CreateAttestationForRequester(actionName, addrs.Requester2, 3) count := 0 - h.CallAction("list_attestations", []any{nil, 100, 0, nil}, func(row *common.Row) error { + h.CallAction("list_attestations", []any{nil, nil, 100, 0, nil}, func(row *common.Row) error { count++ require.Len(h.t, row.Values, 6, "should return 6 columns") return nil @@ -164,7 +168,7 @@ func testListNoFilter(h *AttestationTestHelper, actionName string, addrs *TestAd func testListFilterByRequester(h *AttestationTestHelper, addrs *TestAddresses) { count := 0 - h.CallAction("list_attestations", []any{addrs.Requester1.Bytes(), 100, 0, nil}, func(row *common.Row) error { + h.CallAction("list_attestations", []any{addrs.Requester1.Bytes(), nil, 100, 0, nil}, func(row *common.Row) error { count++ requester := row.Values[2].([]byte) require.Equal(h.t, addrs.Requester1.Bytes(), requester, "requester should match filter") @@ -173,21 +177,57 @@ func testListFilterByRequester(h *AttestationTestHelper, addrs *TestAddresses) { require.Equal(h.t, 2, count, "should return only requester1's attestations") } +func testListFilterByRequestTxID(h *AttestationTestHelper, actionName string, addrs *TestAddresses) { + // Create multiple attestations + requestTxID1, hash1 := h.RequestAttestation(actionName, 500) + requestTxID2, _ := h.RequestAttestation(actionName, 501) + h.RequestAttestation(actionName, 502) + + // Filter by specific request_tx_id + count := 0 + var returnedTxID string + var returnedHash []byte + h.CallAction("list_attestations", []any{nil, requestTxID1, nil, nil, nil}, func(row *common.Row) error { + count++ + returnedTxID = row.Values[0].(string) + returnedHash = row.Values[1].([]byte) + return nil + }) + + require.Equal(h.t, 1, count, "should return exactly 1 result for specific request_tx_id") + require.Equal(h.t, requestTxID1, returnedTxID, "returned tx_id should match filter") + require.Equal(h.t, hash1, returnedHash, "returned hash should match the attestation") + + // Verify different request_tx_id returns different result + count = 0 + h.CallAction("list_attestations", []any{nil, requestTxID2, nil, nil, nil}, func(row *common.Row) error { + count++ + returnedTxID = row.Values[0].(string) + return nil + }) + require.Equal(h.t, 1, count, "should return exactly 1 result for second request_tx_id") + require.Equal(h.t, requestTxID2, returnedTxID, "returned tx_id should match second filter") + + // Verify non-existent request_tx_id returns no results + count = h.CountRows("list_attestations", []any{nil, InvalidTxID, nil, nil, nil}) + require.Equal(h.t, 0, count, "should return 0 results for non-existent request_tx_id") +} + func testListPagination(h *AttestationTestHelper, actionName string, addrs *TestAddresses) { for i := 0; i < 5; i++ { h.CreateAttestationForRequester(actionName, addrs.Requester1, int64(100+i)) } // First page - count := h.CountRows("list_attestations", []any{addrs.Requester1.Bytes(), 3, 0, nil}) + count := h.CountRows("list_attestations", []any{addrs.Requester1.Bytes(), nil, 3, 0, nil}) require.Equal(h.t, 3, count, "first page should return 3 results") // Second page - count = h.CountRows("list_attestations", []any{addrs.Requester1.Bytes(), 3, 3, nil}) + count = h.CountRows("list_attestations", []any{addrs.Requester1.Bytes(), nil, 3, 3, nil}) require.Equal(h.t, 3, count, "second page should return 3 results") } func testListMaxLimit(h *AttestationTestHelper) { - count := h.CountRows("list_attestations", []any{nil, 99999, 0, nil}) + count := h.CountRows("list_attestations", []any{nil, nil, 99999, 0, nil}) require.Greater(h.t, count, 0, "should return results with large limit") }