@@ -22,7 +22,6 @@ import (
2222 "github.com/lightningnetwork/lnd/input"
2323 "github.com/lightningnetwork/lnd/lnwallet"
2424 "github.com/lightningnetwork/lnd/lnwire"
25- "github.com/lightningnetwork/lnd/tlv"
2625 "github.com/stretchr/testify/require"
2726)
2827
@@ -40,10 +39,58 @@ var (
4039 )
4140
4241 testTimeout = time .Second
42+
43+ chanState = & channeldb.OpenChannel {
44+ ChanType : channeldb .AnchorOutputsBit |
45+ channeldb .ScidAliasChanBit | channeldb .SingleFunderBit |
46+ channeldb .SimpleTaprootFeatureBit |
47+ channeldb .TapscriptRootBit ,
48+ IsInitiator : true ,
49+ }
50+
51+ // sig job batch size when making more that one sig job.
52+ numSigJobs = int32 (10 )
53+
54+ // Threshold for trying to cancel or quit the aux leaf signer (allow
55+ // the signer to complete a third of the batch).
56+ sigJobCancelThreshold = numSigJobs / 3
4357)
4458
45- // TestAuxLeafSigner tests the AuxLeafSigner implementation.
46- func TestAuxLeafSigner (t * testing.T ) {
59+ // RandAuxSigJob generates a basic aux signer job with random key material.
60+ func RandAuxSigJob (t * testing.T , cancelChan chan struct {},
61+ commitBlob lfn.Option [[]byte ], outputIdx int32 ) lnwallet.AuxSigJob {
62+
63+ keyDesc , _ := test .RandKeyDesc (t )
64+ keyRing := test .RandCommitmentKeyRing (t )
65+
66+ return lnwallet.AuxSigJob {
67+ SignDesc : input.SignDescriptor {
68+ KeyDesc : keyDesc ,
69+ },
70+ BaseAuxJob : lnwallet.BaseAuxJob {
71+ OutputIndex : outputIdx ,
72+ KeyRing : keyRing ,
73+ HTLC : lnwallet.PaymentDescriptor {
74+ HtlcIndex : 0 ,
75+ Amount : lnwire .NewMSatFromSatoshis (
76+ 354 ,
77+ ),
78+ EntryType : lnwallet .Add ,
79+ },
80+ Incoming : false ,
81+ CommitBlob : commitBlob ,
82+ HtlcLeaf : input.AuxTapLeaf {},
83+ },
84+ Resp : make (chan lnwallet.AuxSigJobResp , 1 ),
85+ Cancel : cancelChan ,
86+ }
87+ }
88+
89+ // setupAuxLeafSigner sets up an AuxLeafSigner instance and a batch of sig jobs
90+ // to use in unit tests.
91+ func setupAuxLeafSigner (t * testing.T , numJobs int32 ) (* AuxLeafSigner ,
92+ chan struct {}, * wire.MsgTx , []lnwallet.AuxSigJob ) {
93+
4794 cfg := & LeafSignerConfig {
4895 ChainParams : testChainParams ,
4996 Signer : & mockVirtualSigner {},
@@ -52,30 +99,8 @@ func TestAuxLeafSigner(t *testing.T) {
5299 signer := NewAuxLeafSigner (cfg )
53100 require .NoError (t , signer .Start ())
54101
55- defer func () {
56- require .NoError (t , signer .Stop ())
57- }()
58-
59- chanState := & channeldb.OpenChannel {
60- ChanType : channeldb .AnchorOutputsBit |
61- channeldb .ScidAliasChanBit | channeldb .SingleFunderBit |
62- channeldb .SimpleTaprootFeatureBit |
63- channeldb .TapscriptRootBit ,
64- IsInitiator : true ,
65- }
66102 randInputProof := randProof (t )
67103 commitTx := & randInputProof .AnchorTx
68- keyRing := lnwallet.CommitmentKeyRing {
69- CommitPoint : test .RandPubKey (t ),
70- LocalCommitKeyTweak : test .RandBytes (32 ),
71- LocalHtlcKeyTweak : test .RandBytes (32 ),
72- LocalHtlcKey : test .RandPubKey (t ),
73- RemoteHtlcKey : test .RandPubKey (t ),
74- ToLocalKey : test .RandPubKey (t ),
75- ToRemoteKey : test .RandPubKey (t ),
76- RevocationKey : test .RandPubKey (t ),
77- }
78-
79104 outgoingHtlcs := make (map [input.HtlcIndex ][]* cmsg.AssetOutput )
80105 outgoingHtlcs [0 ] = []* cmsg.AssetOutput {
81106 cmsg .NewAssetOutput (
@@ -87,33 +112,28 @@ func TestAuxLeafSigner(t *testing.T) {
87112 com := cmsg .NewCommitment (
88113 nil , nil , outgoingHtlcs , nil , lnwallet.CommitAuxLeaves {},
89114 )
115+ cancelChan := make (chan struct {})
90116
91- randKeyDesc , _ := test .RandKeyDesc (t )
92-
93- jobs := []lnwallet.AuxSigJob {
94- {
95- SignDesc : input.SignDescriptor {
96- KeyDesc : randKeyDesc ,
97- },
98- BaseAuxJob : lnwallet.BaseAuxJob {
99- OutputIndex : 0 ,
100- KeyRing : keyRing ,
101- HTLC : lnwallet.PaymentDescriptor {
102- HtlcIndex : 0 ,
103- Amount : lnwire .NewMSatFromSatoshis (
104- 354 ,
105- ),
106- EntryType : lnwallet .Add ,
107- },
108- Incoming : false ,
109- CommitBlob : lfn.Some [tlv.Blob ](com .Bytes ()),
110- HtlcLeaf : input.AuxTapLeaf {},
111- },
112- Resp : make (chan lnwallet.AuxSigJobResp ),
113- Cancel : make (chan struct {}),
114- },
117+ // Constructing multiple jobs will allow us to assert that later jobs
118+ // are cancelled successfully.
119+ jobs := make ([]lnwallet.AuxSigJob , 0 , numJobs )
120+ for idx := range numJobs {
121+ newJob := RandAuxSigJob (
122+ t , cancelChan , lfn .Some (com .Bytes ()), idx ,
123+ )
124+ jobs = append (jobs , newJob )
115125 }
116126
127+ return signer , cancelChan , commitTx , jobs
128+ }
129+
130+ // TestAuxLeafSigner tests the AuxLeafSigner implementation.
131+ func TestAuxLeafSigner (t * testing.T ) {
132+ signer , _ , commitTx , jobs := setupAuxLeafSigner (t , 1 )
133+ defer func () {
134+ require .NoError (t , signer .Stop ())
135+ }()
136+
117137 err := signer .SubmitSecondLevelSigBatch (chanState , commitTx , jobs )
118138 require .NoError (t , err )
119139
@@ -131,6 +151,79 @@ func TestAuxLeafSigner(t *testing.T) {
131151 }
132152}
133153
154+ // TestAuxLeafSignerCancel tests that the AuxLeafSigner will handle a cancel
155+ // signal correctly, which involves skipping all remaining sig jobs.
156+ func TestAuxLeafSignerCancel (t * testing.T ) {
157+ // Constructing multiple jobs will allow us to assert that later jobs
158+ // are cancelled successfully.
159+ signer , cancelChan , commitTx , jobs := setupAuxLeafSigner (t , numSigJobs )
160+ defer func () {
161+ require .NoError (t , signer .Stop ())
162+ }()
163+
164+ err := signer .SubmitSecondLevelSigBatch (chanState , commitTx , jobs )
165+ require .NoError (t , err )
166+
167+ select {
168+ case <- time .After (testTimeout ):
169+ t .Fatalf ("timeout waiting for response" )
170+ case <- jobs [sigJobCancelThreshold ].Resp :
171+ // Send the cancel signal; jobs at the end of the batch should
172+ // not be processed.
173+ close (cancelChan )
174+ }
175+
176+ signer .Wg .Wait ()
177+
178+ // Once the aux signer finishes handling the batch, the last job of the
179+ // batch should have an empty response channel. Otherwise, the signer
180+ // failed to skip that job after the cancel channel was closed.
181+ select {
182+ case <- jobs [numSigJobs - 1 ].Resp :
183+ t .Fatalf ("Job cancellation failed" )
184+ default :
185+ }
186+ }
187+
188+ // TestAuxLeafSignerCancelAndQuit tests that the AuxLeafSigner will handle a
189+ // quit signal correctly, which involves ending sig job handling as soon as
190+ // possible. This test also sends a cancel signal before the quit signal, to
191+ // check that quits are handled correctly alongside other sent signals.
192+ func TestAuxLeafSignerCancelAndQuit (t * testing.T ) {
193+ // Constructing multiple jobs will allow us to assert that later jobs
194+ // are skipped successfully after sending the quit signal.
195+ signer , cancelChan , commitTx , jobs := setupAuxLeafSigner (t , numSigJobs )
196+ defer func () {
197+ require .NoError (t , signer .Stop ())
198+ }()
199+
200+ err := signer .SubmitSecondLevelSigBatch (chanState , commitTx , jobs )
201+ require .NoError (t , err )
202+
203+ select {
204+ case <- time .After (testTimeout ):
205+ t .Fatalf ("timeout waiting for response" )
206+ case <- jobs [sigJobCancelThreshold ].Resp :
207+ // Another component could have sent the cancel signal; we'll
208+ // send that before the quit signal.
209+ close (cancelChan )
210+ time .Sleep (time .Millisecond )
211+
212+ // Send the quit signal; jobs at the end of the batch should not
213+ // be processed.
214+ require .NoError (t , signer .Stop ())
215+ }
216+
217+ // Once the aux signer stops, the last job of the batch should have an
218+ // an empty response. Otherwise, the signer failed to stop as soon as
219+ // the quit signal was sent.
220+ select {
221+ case <- jobs [numSigJobs - 1 ].Resp :
222+ t .Fatalf ("Aux signer quitting failed" )
223+ default :
224+ }
225+ }
226+
134227// mockVirtualSigner is a mock implementation of the VirtualSigner interface.
135228type mockVirtualSigner struct {
136229}
0 commit comments