-
Notifications
You must be signed in to change notification settings - Fork 56
feat(kotlin-sdk): tx-label & asset-lock-kind DAO resolver queries #4251
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -74,6 +74,22 @@ interface AssetLockDao { | |||||||||||||||||||||||||||
| @Query("SELECT * FROM asset_locks WHERE outPointHex = :outPointHex") | ||||||||||||||||||||||||||||
| suspend fun getByOutPointHex(outPointHex: String): AssetLockEntity? | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||
| * Transaction-label resolver probe: the `fundingTypeRaw` of the asset | ||||||||||||||||||||||||||||
| * lock whose outpoint belongs to [txidHex]. [txidHex] is the explorer | ||||||||||||||||||||||||||||
| * DISPLAY txid hex (64 lowercase chars, wire order reversed) — the | ||||||||||||||||||||||||||||
| * prefix of the `outPointHex` PK (`<txidDisplayHex>:<vout>`), matched | ||||||||||||||||||||||||||||
| * via `LIKE '<txidHex>:%'`. A txid is a pure-hex string (no `%`/`_`), | ||||||||||||||||||||||||||||
| * so the LIKE pattern carries no wildcards of its own. Returns null | ||||||||||||||||||||||||||||
| * when no asset lock funds this tx (e.g. plain send, or an | ||||||||||||||||||||||||||||
| * AssetUnlock/unshield — see [TransactionDao.transactionKindForTxid]). | ||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||
| @Query( | ||||||||||||||||||||||||||||
| "SELECT fundingTypeRaw FROM asset_locks " + | ||||||||||||||||||||||||||||
| "WHERE outPointHex LIKE :txidHex || ':%' LIMIT 1" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
| suspend fun fundingTypeForTxid(txidHex: String): Int? | ||||||||||||||||||||||||||||
|
Comment on lines
+96
to
+103
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: fundingTypeForTxid doesn't enforce its own hex-only contract before using input as a LIKE pattern fundingTypeForTxid binds txidHex directly into
Suggested change
source: ['claude', 'codex']
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 176f8ed — adopted the suggested query shape: the SQL now enforces the 64-hex contract itself (
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved in Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread. |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| @Upsert | ||||||||||||||||||||||||||||
| suspend fun upsert(assetLock: AssetLockEntity) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -27,6 +27,35 @@ interface TransactionDao { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Query("SELECT * FROM transactions WHERE txid = :txid") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| suspend fun getByTxid(txid: ByteArray): TransactionEntity? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Transaction-label resolver probe for the withdraw/unshield case, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * which has NO `asset_locks` row and is identified solely by | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * `transactionTypeKind == 7` (AssetUnlock). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * [txidWire] is the raw little-endian WIRE txid — the exact | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * [TransactionEntity.txid] PK form (a BLOB), i.e. the explorer display | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * hex reversed then hex-decoded. When the caller holds the display hex | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * (as the resolver does), prefer [transactionKindForDisplayTxid], which | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * does the reversal. Returns null when no such tx is stored; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * `transactionTypeKind == 0xFF` (255) means "not yet populated". | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Query("SELECT transactionTypeKind FROM transactions WHERE txid = :txidWire LIMIT 1") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| suspend fun transactionKindForTxid(txidWire: ByteArray): Int? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Convenience over [transactionKindForTxid] keyed by the explorer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * DISPLAY txid hex (64 lowercase chars, wire order reversed) the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * resolver already holds — the same display form used by | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * [AssetLockDao.fundingTypeForTxid]. Reverses to wire order before the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * BLOB PK match. Returns null for malformed hex (not 64 hex chars) or | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * when no such tx is stored. Not a Room query — a plain default method | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * delegating to [transactionKindForTxid]. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| suspend fun transactionKindForDisplayTxid(txidDisplayHex: String): Int? { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val wire = displayHexToWireTxid(txidDisplayHex) ?: return null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return transactionKindForTxid(wire) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+42
to
+56
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: Add Room tests for the new resolver contracts No SDK test invokes source: ['codex']
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved in this update — Add Room tests for the new resolver contracts no longer present. Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.
Comment on lines
+42
to
+56
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: No test coverage for the three new resolver methods Nothing in the repo invokes transactionKindForTxid, transactionKindForDisplayTxid, or fundingTypeForTxid. The hand-written byte-reversal in displayHexToWireTxid (TransactionDao.kt:129-141) has no pinned regression test — deleting the reversal loop entirely would not fail CI, silently mislabeling every withdraw/unshield transaction on-device. The in-memory Room harness already used by WalletDeletionTest is available for this. Add cases with a non-palindromic txid (to catch endian regressions a symmetric fixture like "ab".repeat(32) would miss), uppercase input, malformed/short hex, no-match, and — for fundingTypeForTxid — multiple asset-lock rows sharing a txid prefix to pin down the LIMIT 1 selection behavior. source: ['claude', 'codex']
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in 176f8ed:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved in this update — No test coverage for the three new resolver methods no longer present. Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Timeline join helper — parents of a wallet's TXO set. */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Query("SELECT * FROM transactions WHERE txid IN (:txids) ORDER BY firstSeen DESC") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun observeByTxids(txids: List<ByteArray>): Flow<List<TransactionEntity>> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -89,4 +118,26 @@ interface TransactionDao { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** StorageExplorer row count. */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Query("SELECT COUNT(*) FROM transactions") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun count(): Flow<Long> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Explorer DISPLAY txid hex (wire order reversed, 64 lowercase | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * chars) → raw little-endian WIRE txid, the [TransactionEntity.txid] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * PK form. Mirrors the txid half of [decodeOutPointHex]. Returns | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * null for any non-64-char or non-hex input. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private fun displayHexToWireTxid(displayHex: String): ByteArray? { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (displayHex.length != 64) return null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val display = ByteArray(32) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (i in 0 until 32) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val hi = Character.digit(displayHex[i * 2], 16) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val lo = Character.digit(displayHex[i * 2 + 1], 16) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (hi < 0 || lo < 0) return null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| display[i] = ((hi shl 4) or lo).toByte() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val wire = ByteArray(32) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (i in 0 until 32) wire[i] = display[31 - i] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return wire | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+129
to
+141
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: displayHexToWireTxid accepts non-ASCII Unicode hex digits via Character.digit Java's
Suggested change
source: ['claude', 'codex'] |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Suggestion: Validate txids before using them as a LIKE pattern
Unlike
transactionKindForDisplayTxid, this resolver does not enforce its documented 64-character hexadecimal input contract. SQLite interprets%and_in the bound value as wildcards, so malformed inputs such as%or 64 underscores match unrelated asset-lock rows andLIMIT 1returns one row's funding type rather than null. Validate and canonicalize the input in SQL, then compare the exact 64-character outpoint prefix; generatedoutPointHexvalues are lowercase, whilelower(:txidHex)preserves support for uppercase canonical txids.source: ['codex']
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in this update — Validate txids before using them as a LIKE pattern no longer present.
Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.