@@ -198,7 +198,9 @@ func (a *MintingArchive) RegisterIssuance(ctx context.Context, id Identifier,
198198 // Before we can validate a non-issuance proof we need to fetch the
199199 // previous asset snapshot (which is the proof verification result for
200200 // the previous/parent proof in the proof file).
201- prevAssetSnapshot , err := a .getPrevAssetSnapshot (ctx , id , * newProof )
201+ prevAssetSnapshot , err := a .getPrevAssetSnapshot (
202+ ctx , id , * newProof , nil ,
203+ )
202204 if err != nil {
203205 return nil , fmt .Errorf ("unable to fetch previous asset " +
204206 "snapshot: %w" , err )
@@ -280,6 +282,18 @@ func (a *MintingArchive) verifyIssuanceProof(ctx context.Context, id Identifier,
280282 return assetSnapshot , nil
281283}
282284
285+ // extractBatchDeps constructs map from leaf key to asset in a batch. This is
286+ // useful for when we're validating an asset state transition in a batch, and
287+ // the input asset it depends on is created in the batch.
288+ func extractBatchDeps (batch []* IssuanceItem ) map [UniverseKey ]* asset.Asset {
289+ batchDeps := make (map [UniverseKey ]* asset.Asset )
290+ for _ , item := range batch {
291+ batchDeps [item .Key .UniverseKey ()] = & item .Leaf .Proof .Asset
292+ }
293+
294+ return batchDeps
295+ }
296+
283297// RegisterNewIssuanceBatch inserts a batch of new minting leaves within the
284298// target universe tree (based on the ID), stored at the base key(s). We assume
285299// the proofs within the batch have already been checked that they don't yet
@@ -329,13 +343,24 @@ func (a *MintingArchive) RegisterNewIssuanceBatch(ctx context.Context,
329343 }
330344 }
331345
346+ batchDeps := extractBatchDeps (items )
347+
332348 verifyBatch := func (batchItems []* IssuanceItem ) error {
333349 err := fn .ParSlice (
334350 ctx , batchItems , func (ctx context.Context ,
335351 i * IssuanceItem ) error {
336352
353+ prevAssets , err := a .getPrevAssetSnapshot (
354+ ctx , i .ID , * i .Leaf .Proof , batchDeps ,
355+ )
356+ if err != nil {
357+ return fmt .Errorf ("unable to " +
358+ "fetch previous asset " +
359+ "snapshot: %w" , err )
360+ }
361+
337362 assetSnapshot , err := a .verifyIssuanceProof (
338- ctx , i .ID , i .Key , i .Leaf , nil ,
363+ ctx , i .ID , i .Key , i .Leaf , prevAssets ,
339364 )
340365 if err != nil {
341366 return err
@@ -397,10 +422,14 @@ func (a *MintingArchive) RegisterNewIssuanceBatch(ctx context.Context,
397422 return nil
398423}
399424
425+ // UniverseKey represents the key used to locate an item within a universe.
426+ type UniverseKey [32 ]byte
427+
400428// getPrevAssetSnapshot returns the previous asset snapshot for the passed
401429// proof. If the proof is a genesis proof, then nil is returned.
402430func (a * MintingArchive ) getPrevAssetSnapshot (ctx context.Context ,
403- uniID Identifier , newProof proof.Proof ) (* proof.AssetSnapshot , error ) {
431+ uniID Identifier , newProof proof.Proof ,
432+ batchAssets map [UniverseKey ]* asset.Asset ) (* proof.AssetSnapshot , error ) {
404433
405434 // If this is a genesis proof, then there is no previous asset (and
406435 // therefore no previous asset snapshot).
@@ -433,9 +462,33 @@ func (a *MintingArchive) getPrevAssetSnapshot(ctx context.Context,
433462 ScriptKey : & prevScriptKey ,
434463 }
435464
465+ // First, we'll check if the prev asset that we need is already amongst
466+ // the batch we have, if so then we won't have it in our universe tree
467+ // yet, so we'll return it directly.
468+ if batchAssets != nil {
469+ newAsset := newProof .Asset
470+ newScriptKey := newAsset .ScriptKey .PubKey .SerializeCompressed ()
471+
472+ inputAsset , ok := batchAssets [prevLeafKey .UniverseKey ()]
473+ if ok {
474+
475+ log .Debugf ("script_key=%x spends item in batch, " +
476+ "universe_key=%x using batch input" ,
477+ newScriptKey , prevLeafKey .UniverseKey ())
478+
479+ return & proof.AssetSnapshot {
480+ Asset : inputAsset ,
481+ OutPoint : prevID .OutPoint ,
482+ }, nil
483+ }
484+ }
485+
486+ // If we can't find the previous asset in the batch, then we'll query
487+ // our local universe.
436488 prevProofs , err := a .cfg .Multiverse .FetchProofLeaf (
437489 ctx , uniID , prevLeafKey ,
438490 )
491+
439492 // If we've failed in finding the previous proof in the transfer
440493 // universe, we will try to find it in the issuance universe.
441494 if uniID .ProofType == ProofTypeTransfer &&
@@ -448,11 +501,15 @@ func (a *MintingArchive) getPrevAssetSnapshot(ctx context.Context,
448501 }
449502 if err != nil {
450503 return nil , fmt .Errorf ("unable to fetch previous " +
451- "proof: %v" , err )
504+ "proof: %v, id=%v, leaf_key=%v, new_script_key=%x" , err ,
505+ spew .Sdump (uniID ), spew .Sdump (prevLeafKey ),
506+ newProof .Asset .ScriptKey .PubKey .SerializeCompressed ())
452507 }
453508
454509 prevProof := prevProofs [0 ].Leaf .Proof
455510
511+ // TODO(roasbeef): need more than one snapshot, for inputs
512+
456513 // Construct minimal asset snapshot for previous asset.
457514 // This is a minimal the proof verification result for the
458515 // previous (input) asset. We know that it was already verified
0 commit comments