@@ -17,6 +17,7 @@ import (
17
17
"github.com/lightninglabs/taproot-assets/commitment"
18
18
"github.com/lightninglabs/taproot-assets/fn"
19
19
"github.com/lightninglabs/taproot-assets/vm"
20
+ lfn "github.com/lightningnetwork/lnd/fn"
20
21
"golang.org/x/exp/maps"
21
22
"golang.org/x/sync/errgroup"
22
23
)
@@ -33,6 +34,21 @@ type ChainLookupGenerator interface {
33
34
GenProofChainLookup (p * Proof ) (asset.ChainLookup , error )
34
35
}
35
36
37
+ // AssetPoint is similar to PrevID but is meant to be used for created asset
38
+ // outputs rather than those that are spent. This is similar to the concept of
39
+ // an outpoint in normal Bitcoin.
40
+ type AssetPoint = asset.PrevID
41
+
42
+ // IgnoreChecker is used during proof validation to optionally fail validation
43
+ // if a proof is known to be invalid. This can be used as a caching mechanism to
44
+ // avoid expensive validation for already known invalid proofs.
45
+ type IgnoreChecker interface {
46
+ // IsIgnored returns true if the given prevID is known to be invalid. A
47
+ // prevID is used here, but the check should be tested against a proof
48
+ // result, or produced output.
49
+ IsIgnored (prevID AssetPoint ) bool
50
+ }
51
+
36
52
// VerifierCtx is a context struct that is used to pass in various interfaces
37
53
// needed during proof verification.
38
54
type VerifierCtx struct {
@@ -45,6 +61,8 @@ type VerifierCtx struct {
45
61
GroupAnchorVerifier GroupAnchorVerifier
46
62
47
63
ChainLookupGen ChainLookupGenerator
64
+
65
+ IgnoreChecker lfn.Option [IgnoreChecker ]
48
66
}
49
67
50
68
// Verifier abstracts away from the task of verifying a proof file blob.
@@ -559,6 +577,23 @@ func (p *Proof) Verify(ctx context.Context, prev *AssetSnapshot,
559
577
"%w" , err )
560
578
}
561
579
580
+ assetPoint := AssetPoint {
581
+ OutPoint : p .OutPoint (),
582
+ ID : p .Asset .ID (),
583
+ ScriptKey : asset .ToSerialized (p .Asset .ScriptKey .PubKey ),
584
+ }
585
+
586
+ // Before we do any other validation, we'll check to see if we can halt
587
+ // validation here, as the proof is already known to be invalid. This
588
+ // can be used as a rejection caching mechanism.
589
+ fail := lfn .MapOptionZ (vCtx .IgnoreChecker , func (c IgnoreChecker ) bool {
590
+ return c .IsIgnored (assetPoint )
591
+ })
592
+ if fail {
593
+ return prev , fmt .Errorf ("%w: asset_point=%v is ignored" ,
594
+ ErrProofInvalid , assetPoint )
595
+ }
596
+
562
597
// 1. A transaction that spends the previous asset output has a valid
563
598
// merkle proof within a block in the chain.
564
599
if prev != nil && p .PrevOut != prev .OutPoint {
@@ -683,11 +718,8 @@ func (p *Proof) Verify(ctx context.Context, prev *AssetSnapshot,
683
718
// TODO(roasbeef): need tx index as well
684
719
685
720
return & AssetSnapshot {
686
- Asset : & p .Asset ,
687
- OutPoint : wire.OutPoint {
688
- Hash : p .AnchorTx .TxHash (),
689
- Index : p .InclusionProof .OutputIndex ,
690
- },
721
+ Asset : & p .Asset ,
722
+ OutPoint : p .OutPoint (),
691
723
AnchorBlockHash : p .BlockHeader .BlockHash (),
692
724
AnchorBlockHeight : p .BlockHeight ,
693
725
AnchorTx : & p .AnchorTx ,
@@ -790,6 +822,27 @@ func (f *File) Verify(ctx context.Context,
790
822
if err != nil {
791
823
return nil , err
792
824
}
825
+
826
+ // At this point, we'll check to see if we can halt validation
827
+ // here, as the proof is already known to be invalid. This can
828
+ // be used as a rejection caching mechanism.
829
+ fail := lfn .MapOptionZ (
830
+ vCtx .IgnoreChecker , func (checker IgnoreChecker ) bool {
831
+ assetPoint := AssetPoint {
832
+ OutPoint : result .OutPoint ,
833
+ ID : result .Asset .ID (),
834
+ ScriptKey : asset .ToSerialized (
835
+ result .Asset .ScriptKey .PubKey ,
836
+ ),
837
+ }
838
+
839
+ return checker .IsIgnored (assetPoint )
840
+ },
841
+ )
842
+ if fail {
843
+ return prev , ErrProofFileInvalid
844
+ }
845
+
793
846
prev = result
794
847
}
795
848
0 commit comments