5
5
"context"
6
6
"database/sql"
7
7
"fmt"
8
+ "io"
8
9
"math/rand"
9
10
"net/url"
10
11
"testing"
@@ -23,6 +24,7 @@ import (
23
24
"github.com/lightninglabs/taproot-assets/tapdb"
24
25
"github.com/lightninglabs/taproot-assets/tapgarden"
25
26
"github.com/lightninglabs/taproot-assets/tapscript"
27
+ "github.com/lightninglabs/taproot-assets/universe"
26
28
"github.com/lightningnetwork/lnd/clock"
27
29
"github.com/lightningnetwork/lnd/lnrpc"
28
30
"github.com/lightningnetwork/lnd/lntest/wait"
@@ -59,9 +61,46 @@ func newAddrBookForDB(db *tapdb.BaseDB, keyRing *tapgarden.MockKeyRing,
59
61
return book , tapdbBook
60
62
}
61
63
64
+ type mockVerifier struct {
65
+ t * testing.T
66
+ }
67
+
68
+ func newMockVerifier (t * testing.T ) * mockVerifier {
69
+ return & mockVerifier {
70
+ t : t ,
71
+ }
72
+ }
73
+
74
+ func (m * mockVerifier ) Verify (_ context.Context , r io.Reader ,
75
+ headerVerifier proof.HeaderVerifier ,
76
+ groupVerifier proof.GroupVerifier ) (* proof.AssetSnapshot , error ) {
77
+
78
+ f := & proof.File {}
79
+ err := f .Decode (r )
80
+ require .NoError (m .t , err )
81
+
82
+ lastProof , err := f .LastProof ()
83
+ require .NoError (m .t , err )
84
+
85
+ ac , err := commitment .NewAssetCommitment (& lastProof .Asset )
86
+ require .NoError (m .t , err )
87
+ tc , err := commitment .NewTapCommitment (ac )
88
+ require .NoError (m .t , err )
89
+
90
+ return & proof.AssetSnapshot {
91
+ Asset : & lastProof .Asset ,
92
+ OutPoint : lastProof .OutPoint (),
93
+ OutputIndex : lastProof .InclusionProof .OutputIndex ,
94
+ AnchorBlockHash : lastProof .BlockHeader .BlockHash (),
95
+ AnchorTx : & lastProof .AnchorTx ,
96
+ InternalKey : lastProof .InclusionProof .InternalKey ,
97
+ ScriptRoot : tc ,
98
+ }, nil
99
+ }
100
+
62
101
// newProofArchive creates a new instance of the MultiArchiver.
63
102
func newProofArchiveForDB (t * testing.T , db * tapdb.BaseDB ) (* proof.MultiArchiver ,
64
- * tapdb.AssetStore ) {
103
+ * tapdb.AssetStore , * tapdb. MultiverseStore ) {
65
104
66
105
txCreator := func (tx * sql.Tx ) tapdb.ActiveAssetsStore {
67
106
return db .WithTx (tx )
@@ -78,7 +117,14 @@ func newProofArchiveForDB(t *testing.T, db *tapdb.BaseDB) (*proof.MultiArchiver,
78
117
assetStore ,
79
118
)
80
119
81
- return proofArchive , assetStore
120
+ multiverseDB := tapdb .NewTransactionExecutor (
121
+ db , func (tx * sql.Tx ) tapdb.BaseMultiverseStore {
122
+ return db .WithTx (tx )
123
+ },
124
+ )
125
+ multiverse := tapdb .NewMultiverseStore (multiverseDB )
126
+
127
+ return proofArchive , assetStore , multiverse
82
128
}
83
129
84
130
type custodianHarness struct {
@@ -93,6 +139,7 @@ type custodianHarness struct {
93
139
addrBook * address.Book
94
140
syncer * tapgarden.MockAssetSyncer
95
141
assetDB * tapdb.AssetStore
142
+ multiverse * tapdb.MultiverseStore
96
143
courier * proof.MockProofCourier
97
144
}
98
145
@@ -192,6 +239,48 @@ func (h *custodianHarness) assertAddrsRegistered(
192
239
}
193
240
}
194
241
242
+ // addProofFileToMultiverse adds the given proof to the multiverse store.
243
+ func (h * custodianHarness ) addProofFileToMultiverse (p * proof.AnnotatedProof ) {
244
+ f := & proof.File {}
245
+ err := f .Decode (bytes .NewReader (p .Blob ))
246
+ require .NoError (h .t , err )
247
+
248
+ ctx := context .Background ()
249
+ ctxt , cancel := context .WithTimeout (ctx , testTimeout )
250
+ defer cancel ()
251
+
252
+ for i := uint32 (0 ); i < uint32 (f .NumProofs ()); i ++ {
253
+ transition , err := f .ProofAt (i )
254
+ require .NoError (h .t , err )
255
+
256
+ rawTransition , err := f .RawProofAt (i )
257
+ require .NoError (h .t , err )
258
+
259
+ id := universe .NewUniIDFromAsset (transition .Asset )
260
+ key := universe.LeafKey {
261
+ OutPoint : transition .OutPoint (),
262
+ ScriptKey : fn .Ptr (asset .NewScriptKey (
263
+ transition .Asset .ScriptKey .PubKey ,
264
+ )),
265
+ }
266
+ leaf := & universe.Leaf {
267
+ GenesisWithGroup : universe.GenesisWithGroup {
268
+ Genesis : transition .Asset .Genesis ,
269
+ GroupKey : transition .Asset .GroupKey ,
270
+ },
271
+ RawProof : rawTransition ,
272
+ Asset : & transition .Asset ,
273
+ Amt : transition .Asset .Amount ,
274
+ }
275
+ h .t .Logf ("Importing proof with script key %x and outpoint %v " +
276
+ "into multiverse" ,
277
+ key .ScriptKey .PubKey .SerializeCompressed (),
278
+ key .OutPoint )
279
+ _ , err = h .multiverse .UpsertProofLeaf (ctxt , id , key , leaf , nil )
280
+ require .NoError (h .t , err )
281
+ }
282
+ }
283
+
195
284
func newHarness (t * testing.T ,
196
285
initialAddrs []* address.AddrWithKeyInfo ) * custodianHarness {
197
286
@@ -201,7 +290,10 @@ func newHarness(t *testing.T,
201
290
syncer := tapgarden .NewMockAssetSyncer ()
202
291
db := tapdb .NewTestDB (t )
203
292
addrBook , tapdbBook := newAddrBookForDB (db .BaseDB , keyRing , syncer )
204
- _ , assetDB := newProofArchiveForDB (t , db .BaseDB )
293
+
294
+ _ , assetDB , multiverse := newProofArchiveForDB (t , db .BaseDB )
295
+ notifier := proof .NewMultiArchiveNotifier (assetDB , multiverse )
296
+
205
297
courier := proof .NewMockProofCourier ()
206
298
courierDispatch := & proof.MockProofCourierDispatcher {
207
299
Courier : courier ,
@@ -214,14 +306,18 @@ func newHarness(t *testing.T,
214
306
require .NoError (t , err )
215
307
}
216
308
309
+ archive := proof .NewMultiArchiver (
310
+ newMockVerifier (t ), testTimeout , assetDB ,
311
+ )
312
+
217
313
errChan := make (chan error , 1 )
218
314
cfg := & tapgarden.CustodianConfig {
219
315
ChainParams : chainParams ,
220
316
ChainBridge : chainBridge ,
221
317
WalletAnchor : walletAnchor ,
222
318
AddrBook : addrBook ,
223
- ProofArchive : assetDB ,
224
- ProofNotifier : assetDB ,
319
+ ProofArchive : archive ,
320
+ ProofNotifier : notifier ,
225
321
ProofCourierDispatcher : courierDispatch ,
226
322
ProofWatcher : proofWatcher ,
227
323
ErrChan : errChan ,
@@ -238,6 +334,7 @@ func newHarness(t *testing.T,
238
334
addrBook : addrBook ,
239
335
syncer : syncer ,
240
336
assetDB : assetDB ,
337
+ multiverse : multiverse ,
241
338
courier : courier ,
242
339
}
243
340
}
@@ -315,6 +412,11 @@ func randProof(t *testing.T, outputIndex int, tx *wire.MsgTx,
315
412
Genesis : * genesis ,
316
413
Amount : addr .Amount ,
317
414
ScriptKey : asset .NewScriptKey (& addr .ScriptKey ),
415
+ PrevWitnesses : []asset.Witness {
416
+ {
417
+ PrevID : & asset.PrevID {},
418
+ },
419
+ },
318
420
}
319
421
if addr .GroupKey != nil {
320
422
a .GroupKey = & asset.GroupKey {
@@ -653,6 +755,49 @@ func mustMakeAddr(t *testing.T,
653
755
return addr
654
756
}
655
757
758
+ // TestProofInMultiverseOnly tests that the custodian imports a proof correctly
759
+ // into the local archive if it's only present in the multiverse.
760
+ func TestProofInMultiverseOnly (t * testing.T ) {
761
+ h := newHarness (t , nil )
762
+
763
+ // Before we start the custodian, we create a random address and a
764
+ // corresponding wallet transaction.
765
+ ctx := context .Background ()
766
+
767
+ addr , genesis := randAddr (h )
768
+ err := h .tapdbBook .InsertAddrs (ctx , * addr )
769
+ require .NoError (t , err )
770
+
771
+ // We now start the custodian and make sure it's started up correctly
772
+ // and the pending event is registered.
773
+ require .NoError (t , h .c .Start ())
774
+ h .assertStartup ()
775
+ h .assertAddrsRegistered (addr )
776
+
777
+ // Receiving a TX for it should create a pending event and cause the
778
+ // proof courier to attempt to fetch it. But the courier won't find it.
779
+ outputIdx , tx := randWalletTx (addr )
780
+ h .walletAnchor .SubscribeTx <- * tx
781
+ h .assertEventsPresent (1 , address .StatusTransactionDetected )
782
+
783
+ // We now stop the custodian again.
784
+ require .NoError (t , h .c .Stop ())
785
+
786
+ // The proof is only in the multiverse, not in the local archive. And we
787
+ // add the proof to the multiverse before starting the custodian, so the
788
+ // notification for it doesn't trigger.
789
+ mockProof := randProof (t , outputIdx , tx .Tx , genesis , addr )
790
+ h .addProofFileToMultiverse (mockProof )
791
+
792
+ // And a new start should import the proof into the local archive.
793
+ h .c = tapgarden .NewCustodian (h .cfg )
794
+ require .NoError (t , h .c .Start ())
795
+ t .Cleanup (func () {
796
+ require .NoError (t , h .c .Stop ())
797
+ })
798
+ h .assertStartup ()
799
+ }
800
+
656
801
// TestAddrMatchesAsset tests that the AddrMatchesAsset function works
657
802
// correctly.
658
803
func TestAddrMatchesAsset (t * testing.T ) {
0 commit comments