From 483eb84a5d74baaa81d112976027494121af10c9 Mon Sep 17 00:00:00 2001 From: habibitcoin Date: Thu, 7 Nov 2024 21:05:09 -0500 Subject: [PATCH] tapdb+tapsend+tapfreighter:add prevIds to constraints we can filter on --- tapdb/assets_store.go | 43 ++++++++++++++++++++++++++++++++++++- tapfreighter/coin_select.go | 1 + tapfreighter/interface.go | 3 +++ tapfreighter/wallet.go | 6 ++++++ tapsend/send.go | 3 +++ 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/tapdb/assets_store.go b/tapdb/assets_store.go index e408508d6..3d7c1a60a 100644 --- a/tapdb/assets_store.go +++ b/tapdb/assets_store.go @@ -1991,7 +1991,48 @@ func (a *AssetStore) ListEligibleCoins(ctx context.Context, // have a block height of 0, so we set the minimum block height to 1. assetFilter.MinAnchorHeight = sqlInt32(1) - return a.queryCommitments(ctx, assetFilter) + 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, + ) + + // If this results in an empty list, we return the same error we + // would if there were no coins found without the filter. + if len(selectedCommitments) == 0 { + return nil, tapfreighter.ErrMatchingAssetsNotFound + } + } + + return selectedCommitments, nil +} + +// filterCommitmentsByPrevIDs filters the given commitments by the previous IDs +// given. +func filterCommitmentsByPrevIDs(commitments []*tapfreighter.AnchoredCommitment, + prevIDs []asset.PrevID) []*tapfreighter.AnchoredCommitment { + + prevIDMatches := func(p asset.PrevID, + c *tapfreighter.AnchoredCommitment) bool { + + return p.OutPoint == c.AnchorPoint && p.ID == c.Asset.ID() && + p.ScriptKey == asset.ToSerialized( + c.Asset.ScriptKey.PubKey, + ) + } + + commitmentInList := func(c *tapfreighter.AnchoredCommitment) bool { + return fn.Any(prevIDs, func(p asset.PrevID) bool { + return prevIDMatches(p, c) + }) + } + + return fn.Filter(commitments, commitmentInList) } // LeaseCoins leases/locks/reserves coins for the given lease owner until the diff --git a/tapfreighter/coin_select.go b/tapfreighter/coin_select.go index 2e5408ba5..2dcca14c8 100644 --- a/tapfreighter/coin_select.go +++ b/tapfreighter/coin_select.go @@ -55,6 +55,7 @@ func (s *CoinSelect) SelectCoins(ctx context.Context, AssetSpecifier: constraints.AssetSpecifier, MinAmt: 1, CoinSelectType: constraints.CoinSelectType, + PrevIDs: constraints.PrevIDs, } eligibleCommitments, err := s.coinLister.ListEligibleCoins( ctx, listConstraints, diff --git a/tapfreighter/interface.go b/tapfreighter/interface.go index 59fb6016a..28f27888e 100644 --- a/tapfreighter/interface.go +++ b/tapfreighter/interface.go @@ -35,6 +35,9 @@ type CommitmentConstraints struct { // to satisfy the constraints. MinAmt uint64 + // PrevIDs are the set of inputs allowed to be used + PrevIDs []asset.PrevID + // CoinSelectType is the type of coins that should be selected. CoinSelectType tapsend.CoinSelectType } diff --git a/tapfreighter/wallet.go b/tapfreighter/wallet.go index a05edf745..7b2472ab9 100644 --- a/tapfreighter/wallet.go +++ b/tapfreighter/wallet.go @@ -255,6 +255,11 @@ func (f *AssetWallet) FundAddressSend(ctx context.Context, return nil, fmt.Errorf("unable to describe recipients: %w", err) } + // We need to constrain the prevIDs if they are provided. + if len(prevIDs) > 0 { + fundDesc.PrevIDs = prevIDs + } + fundDesc.CoinSelectType = coinSelectType fundedVPkt, err := f.FundPacket(ctx, fundDesc, vPkt) if err != nil { @@ -373,6 +378,7 @@ func (f *AssetWallet) FundPacket(ctx context.Context, AssetSpecifier: fundDesc.AssetSpecifier, MinAmt: fundDesc.Amount, CoinSelectType: fundDesc.CoinSelectType, + PrevIDs: fundDesc.PrevIDs, } anchorVersion, err := tappsbt.CommitmentVersion(vPkt.Version) diff --git a/tapsend/send.go b/tapsend/send.go index 87bb67a11..6a6b1e692 100644 --- a/tapsend/send.go +++ b/tapsend/send.go @@ -193,6 +193,9 @@ type FundingDescriptor struct { // Amount is the amount of the asset to transfer. Amount uint64 + // PrevIDs is the set of inputs that can be used to fund the transfer. + PrevIDs []asset.PrevID + // CoinSelectType specifies the type of coins that should be selected. CoinSelectType CoinSelectType }