Skip to content

Paginate the unspent-coin read: control.wallet.coins and dign wallet coins #381

Description

@MichaelTaylor3d

Task

Paginate the unspent-coin read: control.wallet.coins and the dign wallet coins CLI that fronts it.

Parent epic: https://github.com/DIG-Network/dig_ecosystem/issues/3170

User directive, verbatim: "the dig-node cli also needs a command in its wallet to list available
coins, paginated"

What already exists — do NOT rebuild it

  • control.wallet.coins — shipped, per-address, unspent-only (crates/dig-node-service/src/control.rs:148)
  • dign wallet coins <ADDRESS> --asset xch|dig [--json] — shipped, unpaginated
  • The persisted coins table with idx_coins_unspent … WHERE spent_height IS NULL, and
    WalletDb::unspent_coins(asset_id) (crates/dig-wallet/src/sage/db.rs)

The gap is only pagination. An address with thousands of coins currently returns everything in one
response.

The shape — reuse the repo's own Sage-parity idiom, do not invent one

crates/dig-wallet/src/sage/rpc.rs:358-366 already implements this correctly for coinsByParent.
Match it:

  • ASCENDING by coin_id — a stable total order, so a page boundary is well-defined.
  • Cursor, not offset. Return the last coin_id of the page; the caller resumes from it. An offset
    re-reads a shifting table and silently skips or repeats rows when a coin is spent between pages —
    and on a money surface a skipped coin reads as missing funds.
  • has_more derived from rows remaining BEYOND the page, never from whether the page filled. The
    repo's own comment says why: the two differ exactly when the count is a multiple of the page size.
  • An empty page is an answer, not an error (rpc.rs:1853).
  • A short page is never marked complete to salvage a partial read (rpc.rs:1859).

Note the existing query's scope, and decide deliberately

unspent_coins(asset_id) filters by asset_id only — it does not filter by puzzle_hash. Check
what the RPC layer does with that before adding a page on top: if the address filter is applied above
the query, paginating the unfiltered query and then filtering would produce short pages and a wrong
has_more. Filter and paginate at the same level, in SQL, or the two disagree.

Also

  • Keep --json machine output (§6.2) and make the cursor/has_more fields part of it — a scripted
    caller must be able to page without parsing prose.
  • control.wallet.coins is a published contract in dig-node-control-interface; adding optional
    paging params is additive, but the catalog must be updated in the same family (§4.1 release-first).
    State the SemVer judgement.
  • Update SPEC.md (§4.2) and the CLI parity test (#426 guards drift between the RPC and the CLI).
  • §2.4b: bring dig-*/chia-* deps to latest in the PR; index checks need a User-Agent header.

Acceptance

dign wallet coins <address> --asset dig pages through a real funded address, --json carries the
cursor, and the last page reports has_more: false without a spurious extra request. Evidence is a
real run (§2.6).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions