Summary
#2252 bounded input selection so that funding a send lists coins in pages of
descending amounts and stops once the target is covered. Sends that pin their
inputs are excluded from that: they still list every eligible coin the node
holds. On a node with 2461 assets, coin selection for a pinned-input send takes
1.53s against 68ms for the bounded path.
Where
The prev-ID filter is applied in Go, after the query has already built an
AnchoredCommitment for every eligible coin:
// tapdb/assets_store.go, ListEligibleCoins
selectedCommitments, err := a.queryCommitments(ctx, assetFilter)
if err != nil {
return nil, fmt.Errorf("unable to query commitments: %w", err)
}
// If we want to restrict on specific inputs, we do the filtering now.
if len(constraints.PrevIDs) > 0 {
selectedCommitments = filterCommitmentsByPrevIDs(
selectedCommitments, constraints.PrevIDs,
)
So a bounded page could contain none of the pinned inputs, and #2252 rejects
the combination rather than returning a wrong answer:
if constraints.CoinLimit > 0 && len(constraints.PrevIDs) > 0 {
return nil, fmt.Errorf("coin limit cannot be combined with " +
"specific prev IDs")
}
CoinSelect.listCoins correspondingly sets the page size to zero when
PrevIDs is set, which is what makes the listing unbounded.
Pinned inputs reach coin selection from FundVirtualPsbt and the other funding
RPCs, via FundingDescriptor.PrevIDs.
Measurement
Same node and harness used for #2249 and #2250: a copy of a real regtest node,
sqlite, 2461 assets, dominant asset group holding 621 coins.
operation before #2251/#2252 on current main
SelectCoins, pinned prev IDs 16.66s 1.53s
SelectCoins, 1-unit group send 16.57s 68ms
The pinned path is 10x better than it was, purely from the query batching in
#2251, but it is still linear in total holdings where the bounded path is not.
Possible direction
Push the prev-ID set into the SQL filter, so the query returns only the pinned
coins instead of everything followed by a Go-side filter. Each prev ID is an
(anchor outpoint, asset ID, script key) triple, all of which the query already
joins on.
A keyset cursor over (amount, assets.asset_id) in place of LIMIT/OFFSET would
also let pinned listings be paged, and would additionally remove the unbounded
retry #2252 needs when a multi-page listing falls short. See the discussion on
#2252 for that variant.
Environment
Summary
#2252 bounded input selection so that funding a send lists coins in pages of
descending amounts and stops once the target is covered. Sends that pin their
inputs are excluded from that: they still list every eligible coin the node
holds. On a node with 2461 assets, coin selection for a pinned-input send takes
1.53s against 68ms for the bounded path.
Where
The prev-ID filter is applied in Go, after the query has already built an
AnchoredCommitmentfor every eligible coin:So a bounded page could contain none of the pinned inputs, and #2252 rejects
the combination rather than returning a wrong answer:
CoinSelect.listCoinscorrespondingly sets the page size to zero whenPrevIDsis set, which is what makes the listing unbounded.Pinned inputs reach coin selection from
FundVirtualPsbtand the other fundingRPCs, via
FundingDescriptor.PrevIDs.Measurement
Same node and harness used for #2249 and #2250: a copy of a real regtest node,
sqlite, 2461 assets, dominant asset group holding 621 coins.
The pinned path is 10x better than it was, purely from the query batching in
#2251, but it is still linear in total holdings where the bounded path is not.
Possible direction
Push the prev-ID set into the SQL filter, so the query returns only the pinned
coins instead of everything followed by a Go-side filter. Each prev ID is an
(anchor outpoint, asset ID, script key) triple, all of which the query already
joins on.
A keyset cursor over
(amount, assets.asset_id)in place of LIMIT/OFFSET wouldalso let pinned listings be paged, and would additionally remove the unbounded
retry #2252 needs when a multi-page listing falls short. See the discussion on
#2252 for that variant.
Environment
020de0a1(main, with tapdb: batch per-asset witness and proof queries #2251 and tapfreighter: bound input selection instead of loading every eligible coin #2252 merged), sqlitebackend, regtest
sends