@@ -1409,30 +1409,9 @@ func (a *AssetStore) FetchProof(ctx context.Context,
14091409
14101410 readOpts := NewAssetStoreReadTx ()
14111411 dbErr := a .db .ExecTx (ctx , & readOpts , func (q ActiveAssetsStore ) error {
1412- assetProofs , err := q .FetchAssetProof (ctx , args )
1413- if err != nil {
1414- return fmt .Errorf ("unable to fetch asset proof: %w" ,
1415- err )
1416- }
1417-
1418- switch {
1419- // We have no proof for this script key.
1420- case len (assetProofs ) == 0 :
1421- return proof .ErrProofNotFound
1422-
1423- // If the query without the outpoint returns exactly one proof
1424- // then we're fine. If there actually are multiple proofs, we
1425- // require the user to specify the outpoint as well.
1426- case len (assetProofs ) == 1 :
1427- diskProof = assetProofs [0 ].ProofFile
1428-
1429- return nil
1430-
1431- // User needs to specify the outpoint as well, since we have
1432- // multiple proofs for this script key.
1433- default :
1434- return proof .ErrMultipleProofs
1435- }
1412+ var err error
1413+ diskProof , err = fetchProof (ctx , q , args )
1414+ return err
14361415 })
14371416 switch {
14381417 case errors .Is (dbErr , sql .ErrNoRows ):
@@ -1444,6 +1423,34 @@ func (a *AssetStore) FetchProof(ctx context.Context,
14441423 return diskProof , nil
14451424}
14461425
1426+ // fetchProof is a wrapper around the FetchAssetProof query that enforces that
1427+ // a proof is only returned if exactly one matching proof was found.
1428+ func fetchProof (ctx context.Context , q ActiveAssetsStore ,
1429+ args sqlc.FetchAssetProofParams ) (proof.Blob , error ) {
1430+
1431+ assetProofs , err := q .FetchAssetProof (ctx , args )
1432+ if err != nil {
1433+ return nil , fmt .Errorf ("unable to fetch asset proof: %w" , err )
1434+ }
1435+
1436+ switch {
1437+ // We have no proof for this script key.
1438+ case len (assetProofs ) == 0 :
1439+ return nil , proof .ErrProofNotFound
1440+
1441+ // If the query without the outpoint returns exactly one proof
1442+ // then we're fine. If there actually are multiple proofs, we
1443+ // require the user to specify the outpoint as well.
1444+ case len (assetProofs ) == 1 :
1445+ return assetProofs [0 ].ProofFile , nil
1446+
1447+ // User needs to specify the outpoint as well, since we have
1448+ // multiple proofs for this script key.
1449+ default :
1450+ return nil , proof .ErrMultipleProofs
1451+ }
1452+ }
1453+
14471454// locatorToProofQuery turns a proof locator into a FetchAssetProof query
14481455// struct.
14491456func locatorToProofQuery (locator proof.Locator ) (FetchAssetProof , error ) {
@@ -2084,8 +2091,12 @@ func (a *AssetStore) queryCommitments(ctx context.Context,
20842091 chainAnchorToAssets = make (
20852092 map [wire.OutPoint ][]* asset.ChainAsset ,
20862093 )
2087- anchorPoints = make (map [wire.OutPoint ]AnchorPoint )
2088- err error
2094+ anchorPoints = make (map [wire.OutPoint ]AnchorPoint )
2095+ anchorAltLeaves = make (
2096+ map [wire.OutPoint ][]asset.AltLeaf [asset.Asset ],
2097+ )
2098+ matchingAssetProofs = make (map [wire.OutPoint ]proof.Blob )
2099+ err error
20892100 )
20902101
20912102 readOpts := NewAssetStoreReadTx ()
@@ -2145,6 +2156,31 @@ func (a *AssetStore) queryCommitments(ctx context.Context,
21452156 }
21462157
21472158 anchorPoints [anchorPoint ] = anchorUTXO
2159+
2160+ // TODO(jhb): replace full proof fetch with
2161+ // outpoint -> alt leaf table / index
2162+ // We also need to fetch the input proof here, in order
2163+ // to fetch any committed alt leaves.
2164+ assetLoc := proof.Locator {
2165+ AssetID : fn .Ptr (matchingAsset .ID ()),
2166+ ScriptKey : * matchingAsset .ScriptKey .PubKey ,
2167+ OutPoint : & matchingAsset .AnchorOutpoint ,
2168+ }
2169+ proofArgs , err := locatorToProofQuery (assetLoc )
2170+ if err != nil {
2171+ return err
2172+ }
2173+
2174+ var assetProof proof.Blob
2175+ assetProof , err = fetchProof (ctx , q , proofArgs )
2176+ switch {
2177+ case errors .Is (err , sql .ErrNoRows ):
2178+ return proof .ErrProofNotFound
2179+ case err != nil :
2180+ return err
2181+ }
2182+
2183+ matchingAssetProofs [anchorPoint ] = assetProof
21482184 }
21492185
21502186 return nil
@@ -2153,6 +2189,17 @@ func (a *AssetStore) queryCommitments(ctx context.Context,
21532189 return nil , dbErr
21542190 }
21552191
2192+ for anchorPoint , rawProof := range matchingAssetProofs {
2193+ lastProof , err := rawProof .AsSingleProof ()
2194+ if err != nil {
2195+ return nil , err
2196+ }
2197+
2198+ anchorAltLeaves [anchorPoint ] = append (
2199+ anchorAltLeaves [anchorPoint ], lastProof .AltLeaves ... ,
2200+ )
2201+ }
2202+
21562203 // Our final query wants the complete Taproot Asset commitment for each
21572204 // of the managed UTXOs. Some of the assets that match our query might
21582205 // actually be in the same Taproot Asset commitment, so we'll collect
@@ -2164,6 +2211,7 @@ func (a *AssetStore) queryCommitments(ctx context.Context,
21642211 anchorPoint := anchorPoint
21652212 anchorUTXO := anchorPoints [anchorPoint ]
21662213 anchoredAssets := chainAnchorToAssets [anchorPoint ]
2214+ anchoredAltLeaves := anchorAltLeaves [anchorPoint ]
21672215
21682216 // Fetch the asset leaves from each chain asset, and then
21692217 // build a Taproot Asset commitment from this set of assets.
@@ -2199,6 +2247,13 @@ func (a *AssetStore) queryCommitments(ctx context.Context,
21992247 return nil , err
22002248 }
22012249
2250+ // The reconstructed commitment must also include any alt leaves
2251+ // included in the original commitment.
2252+ err = tapCommitment .MergeAltLeaves (anchoredAltLeaves )
2253+ if err != nil {
2254+ return nil , err
2255+ }
2256+
22022257 // Verify that the constructed Taproot Asset commitment matches
22032258 // the commitment root stored in the managed UTXO.
22042259 commitmentRoot := tapCommitment .TapscriptRoot (nil )
0 commit comments