@@ -10,6 +10,7 @@ import (
1010 "time"
1111
1212 "github.com/btcsuite/btcd/btcec/v2"
13+ "github.com/btcsuite/btcd/btcec/v2/schnorr"
1314 "github.com/btcsuite/btcd/chaincfg/chainhash"
1415 "github.com/btcsuite/btcd/wire"
1516 "github.com/lightninglabs/taproot-assets/asset"
@@ -20,14 +21,21 @@ import (
2021 "github.com/lightninglabs/taproot-assets/universe/supplycommit"
2122 "github.com/lightninglabs/taproot-assets/universe/supplyverifier"
2223 lfn "github.com/lightningnetwork/lnd/fn/v2"
24+ "github.com/lightningnetwork/lnd/keychain"
2325 "github.com/lightningnetwork/lnd/lnutils"
2426)
2527
2628type (
2729 // UnspentMintPreCommits is an alias for the sqlc type representing an
28- // unspent supply pre-commitment row.
30+ // unspent supply pre-commitment row where the local node was the
31+ // issuer.
2932 UnspentMintPreCommits = sqlc.FetchUnspentMintSupplyPreCommitsRow
3033
34+ // UnspentPreCommits is an alias for the sqlc type representing an
35+ // unspent supply pre-commitment row where a remote node was the
36+ // issuer.
37+ UnspentPreCommits = sqlc.FetchUnspentSupplyPreCommitsRow
38+
3139 // SupplyCommit is an alias for the sqlc type.
3240 SupplyCommit = sqlc.FetchSupplyCommitRow
3341
@@ -109,6 +117,12 @@ type SupplyCommitStore interface {
109117 FetchUnspentMintSupplyPreCommits (ctx context.Context ,
110118 groupKey []byte ) ([]UnspentMintPreCommits , error )
111119
120+ // FetchUnspentSupplyPreCommits fetches all unspent supply
121+ // pre-commitments for the specified asset group key where a remote
122+ // node was the issuer.
123+ FetchUnspentSupplyPreCommits (ctx context.Context ,
124+ groupKey []byte ) ([]UnspentPreCommits , error )
125+
112126 // FetchSupplyCommit fetches the latest confirmed supply commitment for
113127 // a given group key.
114128 FetchSupplyCommit (ctx context.Context ,
@@ -267,7 +281,8 @@ func NewSupplyCommitMachine(db BatchedSupplyCommitStore) *SupplyCommitMachine {
267281// asset spec. The asset spec will only specify a group key, and not also an
268282// asset ID.
269283func (s * SupplyCommitMachine ) UnspentPrecommits (ctx context.Context ,
270- assetSpec asset.Specifier ) lfn.Result [supplycommit.PreCommits ] {
284+ assetSpec asset.Specifier ,
285+ localIssuerOnly bool ) lfn.Result [supplycommit.PreCommits ] {
271286
272287 groupKey := assetSpec .UnwrapGroupKeyToPtr ()
273288 if groupKey == nil {
@@ -278,23 +293,25 @@ func (s *SupplyCommitMachine) UnspentPrecommits(ctx context.Context,
278293 var preCommits supplycommit.PreCommits
279294 readTx := ReadTxOption ()
280295 dbErr := s .db .ExecTx (ctx , readTx , func (db SupplyCommitStore ) error {
281- rows , err := db .FetchUnspentMintSupplyPreCommits (
296+ mintRows , err := db .FetchUnspentMintSupplyPreCommits (
282297 ctx , groupKeyBytes ,
283298 )
284- if err != nil {
285- // It's okay if there are no unspent pre-commits.
286- if errors .Is (err , sql .ErrNoRows ) {
287- return nil
288- }
289- return fmt .Errorf ("error fetching unspent " +
290- "precommits: %w" , err )
299+ switch {
300+ case errors .Is (err , sql .ErrNoRows ):
301+ // No unspent pre-commits minted by this local node
302+ // exist for this group key. Proceed to query for
303+ // pre-commits from other issuers.
304+
305+ case err != nil :
306+ return fmt .Errorf ("failed to fetch unspent local node " +
307+ "issued pre-commit outputs: %w" , err )
291308 }
292309
293310 // For each pre-commitment, parse the internal key and group
294311 // key, and assemble the final struct as needed by the
295312 // interface.
296- preCommits = make (supplycommit.PreCommits , 0 , len (rows ))
297- for _ , row := range rows {
313+ preCommits = make (supplycommit.PreCommits , 0 , len (mintRows ))
314+ for _ , row := range mintRows {
298315 internalKey , err := parseInternalKey (row .InternalKey )
299316 if err != nil {
300317 return fmt .Errorf ("failed to parse " +
@@ -326,6 +343,76 @@ func (s *SupplyCommitMachine) UnspentPrecommits(ctx context.Context,
326343 preCommits = append (preCommits , preCommit )
327344 }
328345
346+ // If any pre-commits were found where we acted as the issuer,
347+ // return early and skip querying for pre-commits from other
348+ // issuers. Also return early if the caller explicitly requested
349+ // only pre-commits issued by the local node.
350+ if len (preCommits ) > 0 || localIssuerOnly {
351+ return nil
352+ }
353+
354+ // No pre-commits found where we were the issuer. So now
355+ // we'll query for pre-commits from other issuers.
356+ rows , err := db .FetchUnspentSupplyPreCommits (
357+ ctx , schnorr .SerializePubKey (groupKey ),
358+ )
359+ switch {
360+ case errors .Is (err , sql .ErrNoRows ):
361+ // No unspent pre-commits minted by peer issuer nodes
362+ // exist for this group key. Return early.
363+ return nil
364+
365+ case err != nil :
366+ return fmt .Errorf ("failed to fetch unspent remote " +
367+ "node issued pre-commit outputs: %w" , err )
368+ }
369+
370+ // Parse rows into pre-commitment structs.
371+ for _ , row := range rows {
372+ pubKey , err := btcec .ParsePubKey (row .TaprootInternalKey )
373+ if err != nil {
374+ return fmt .Errorf ("failed to parse internal " +
375+ "raw key: %w" , err )
376+ }
377+
378+ internalKey := keychain.KeyDescriptor {
379+ PubKey : pubKey ,
380+ }
381+
382+ groupPubKey , err := schnorr .ParsePubKey (row .GroupKey )
383+ if err != nil {
384+ return fmt .Errorf ("error parsing group key: %w" ,
385+ err )
386+ }
387+
388+ var mintingTx wire.MsgTx
389+ err = mintingTx .Deserialize (bytes .NewReader (row .RawTx ))
390+ if err != nil {
391+ return fmt .Errorf ("error deserializing " +
392+ "minting tx: %w" , err )
393+ }
394+
395+ var outpoint wire.OutPoint
396+ err = readOutPoint (
397+ bytes .NewReader (row .Outpoint ), 0 , 0 , & outpoint ,
398+ )
399+ if err != nil {
400+ return fmt .Errorf ("%w: %w" , ErrReadOutpoint ,
401+ err )
402+ }
403+
404+ preCommit := supplycommit.PreCommitment {
405+ BlockHeight : uint32 (
406+ row .BlockHeight .Int32 ,
407+ ),
408+ MintingTxn : & mintingTx ,
409+ OutIdx : outpoint .Index ,
410+ InternalKey : internalKey ,
411+ GroupPubKey : * groupPubKey ,
412+ }
413+ preCommits = append (preCommits , preCommit )
414+ }
415+
329416 return nil
330417 })
331418 if dbErr != nil {
0 commit comments