@@ -23,225 +23,92 @@ import (
2323 "github.com/stretchr/testify/require"
2424)
2525
26- // TestKVStoreDeleteNonInFlight checks that calling DeletePayments only
27- // deletes payments from the database that are not in-flight.
28- //
29- // TODO(ziggie): Make this test db agnostic .
30- func TestKVStoreDeleteNonInFlight (t * testing.T ) {
26+ // TestKVStoreDeleteDuplicatePayments tests that when a payment with duplicate
27+ // payments is deleted, both the parent payment and its duplicates are properly
28+ // removed from the payment index. This is specific to the KV store's legacy
29+ // duplicate payment handling .
30+ func TestKVStoreDeleteDuplicatePayments (t * testing.T ) {
3131 t .Parallel ()
3232
3333 ctx := t .Context ()
3434
3535 paymentDB := NewKVTestDB (t )
3636
37- // Create a sequence number for duplicate payments that will not collide
38- // with the sequence numbers for the payments we create. These values
39- // start at 1, so 9999 is a safe bet for this test.
40- var duplicateSeqNr = 9999
41-
42- payments := []struct {
43- failed bool
44- success bool
45- hasDuplicate bool
46- }{
47- {
48- failed : true ,
49- success : false ,
50- hasDuplicate : false ,
51- },
52- {
53- failed : false ,
54- success : true ,
55- hasDuplicate : false ,
56- },
57- {
58- failed : false ,
59- success : false ,
60- hasDuplicate : false ,
61- },
62- {
63- failed : false ,
64- success : true ,
65- hasDuplicate : true ,
66- },
67- }
68-
69- var numSuccess , numInflight int
70-
71- for _ , p := range payments {
72- preimg , err := genPreimage (t )
73- require .NoError (t , err )
74-
75- rhash := sha256 .Sum256 (preimg [:])
76- info := genPaymentCreationInfo (t , rhash )
77- attempt , err := genAttemptWithHash (
78- t , 0 , genSessionKey (t ), rhash ,
79- )
80- require .NoError (t , err )
81-
82- // Sends base htlc message which initiate StatusInFlight.
83- err = paymentDB .InitPayment (ctx , info .PaymentIdentifier , info )
84- if err != nil {
85- t .Fatalf ("unable to send htlc message: %v" , err )
86- }
87- _ , err = paymentDB .RegisterAttempt (
88- ctx , info .PaymentIdentifier , attempt ,
89- )
90- if err != nil {
91- t .Fatalf ("unable to send htlc message: %v" , err )
92- }
93-
94- htlc := & htlcStatus {
95- HTLCAttemptInfo : attempt ,
96- }
97-
98- switch {
99- case p .failed :
100- // Fail the payment attempt.
101- htlcFailure := HTLCFailUnreadable
102- _ , err := paymentDB .FailAttempt (
103- ctx , info .PaymentIdentifier , attempt .AttemptID ,
104- & HTLCFailInfo {
105- Reason : htlcFailure ,
106- },
107- )
108- if err != nil {
109- t .Fatalf ("unable to fail htlc: %v" , err )
110- }
37+ // Create a successful payment.
38+ preimg , err := genPreimage (t )
39+ require .NoError (t , err )
11140
112- // Fail the payment, which should moved it to Failed.
113- failReason := FailureReasonNoRoute
114- _ , err = paymentDB .Fail (
115- ctx , info .PaymentIdentifier , failReason ,
116- )
117- if err != nil {
118- t .Fatalf ("unable to fail payment hash: %v" , err )
119- }
41+ rhash := sha256 .Sum256 (preimg [:])
42+ info := genPaymentCreationInfo (t , rhash )
43+ attempt , err := genAttemptWithHash (t , 0 , genSessionKey (t ), rhash )
44+ require .NoError (t , err )
12045
121- // Verify the status is indeed Failed.
122- assertDBPaymentstatus (
123- t , paymentDB , info .PaymentIdentifier ,
124- StatusFailed ,
125- )
46+ // Init and settle the payment.
47+ err = paymentDB .InitPayment (ctx , info .PaymentIdentifier , info )
48+ require .NoError (t , err , "unable to init payment" )
12649
127- htlc .failure = & htlcFailure
128- assertPaymentInfo (
129- t , paymentDB , info .PaymentIdentifier , info ,
130- & failReason , htlc ,
131- )
50+ _ , err = paymentDB .RegisterAttempt (
51+ ctx , info .PaymentIdentifier , attempt ,
52+ )
53+ require .NoError (t , err , "unable to register attempt" )
13254
133- case p .success :
134- // Verifies that status was changed to StatusSucceeded.
135- _ , err := paymentDB .SettleAttempt (
136- ctx , info .PaymentIdentifier , attempt .AttemptID ,
137- & HTLCSettleInfo {
138- Preimage : preimg ,
139- },
140- )
141- if err != nil {
142- t .Fatalf ("error shouldn't have been received," +
143- " got: %v" , err )
144- }
55+ _ , err = paymentDB .SettleAttempt (
56+ ctx , info .PaymentIdentifier , attempt .AttemptID ,
57+ & HTLCSettleInfo {
58+ Preimage : preimg ,
59+ },
60+ )
61+ require .NoError (t , err , "unable to settle attempt" )
14562
146- assertDBPaymentstatus (
147- t , paymentDB , info .PaymentIdentifier ,
148- StatusSucceeded ,
149- )
63+ assertDBPaymentstatus (
64+ t , paymentDB , info .PaymentIdentifier , StatusSucceeded ,
65+ )
15066
151- htlc .settle = & preimg
152- assertPaymentInfo (
153- t , paymentDB , info .PaymentIdentifier , info , nil ,
154- htlc ,
155- )
67+ // Fetch the payment to get its sequence number.
68+ payment , err := paymentDB .FetchPayment (ctx , info .PaymentIdentifier )
69+ require .NoError (t , err )
15670
157- numSuccess ++
71+ // Add two duplicate payments. Use high sequence numbers that won't
72+ // collide with the original payment.
73+ duplicateSeqNr1 := payment .SequenceNum + 1000
74+ duplicateSeqNr2 := payment .SequenceNum + 1001
15875
159- default :
160- assertDBPaymentstatus (
161- t , paymentDB , info .PaymentIdentifier ,
162- StatusInFlight ,
163- )
164- assertPaymentInfo (
165- t , paymentDB , info .PaymentIdentifier , info , nil ,
166- htlc ,
167- )
76+ appendDuplicatePayment (
77+ t , paymentDB .db , info .PaymentIdentifier , duplicateSeqNr1 ,
78+ preimg ,
79+ )
80+ appendDuplicatePayment (
81+ t , paymentDB .db , info .PaymentIdentifier , duplicateSeqNr2 ,
82+ preimg ,
83+ )
16884
169- numInflight ++
170- }
85+ // Verify we now have 3 index entries: original + 2 duplicates.
86+ var indexCount int
87+ err = kvdb .View (paymentDB .db , func (tx walletdb.ReadTx ) error {
88+ index := tx .ReadBucket (paymentsIndexBucket )
17189
172- // If the payment is intended to have a duplicate payment, we
173- // add one.
174- if p .hasDuplicate {
175- appendDuplicatePayment (
176- t , paymentDB .db , info .PaymentIdentifier ,
177- uint64 (duplicateSeqNr ), preimg ,
178- )
179- duplicateSeqNr ++
180- numSuccess ++
181- }
182- }
90+ return index .ForEach (func (k , v []byte ) error {
91+ indexCount ++
92+ return nil
93+ })
94+ }, func () { indexCount = 0 })
95+ require .NoError (t , err )
96+ require .Equal (t , 3 , indexCount , "expected 3 index entries " +
97+ "(parent + 2 duplicates)" )
18398
184- // Delete all failed payments.
185- numPayments , err := paymentDB .DeletePayments (ctx , true , false )
99+ // Delete all successful payments.
100+ numPayments , err := paymentDB .DeletePayments (ctx , false , false )
186101 require .NoError (t , err )
187- require .EqualValues (t , 1 , numPayments )
102+ require .EqualValues (t , 1 , numPayments , "should delete 1 payment" )
188103
189- // This should leave the succeeded and in-flight payments .
104+ // Verify all payments are deleted .
190105 dbPayments , err := paymentDB .FetchPayments ()
191- if err != nil {
192- t .Fatal (err )
193- }
194-
195- if len (dbPayments ) != numSuccess + numInflight {
196- t .Fatalf ("expected %d payments, got %d" ,
197- numSuccess + numInflight , len (dbPayments ))
198- }
199-
200- var s , i int
201- for _ , p := range dbPayments {
202- t .Log ("fetch payment has status" , p .Status )
203- switch p .Status {
204- case StatusSucceeded :
205- s ++
206- case StatusInFlight :
207- i ++
208- }
209- }
210-
211- if s != numSuccess {
212- t .Fatalf ("expected %d succeeded payments , got %d" ,
213- numSuccess , s )
214- }
215- if i != numInflight {
216- t .Fatalf ("expected %d in-flight payments, got %d" ,
217- numInflight , i )
218- }
219-
220- // Now delete all payments except in-flight.
221- numPayments , err = paymentDB .DeletePayments (ctx , false , false )
222106 require .NoError (t , err )
223- require .EqualValues (t , 2 , numPayments )
107+ require .Empty (t , dbPayments , "all payments should be deleted" )
224108
225- // This should leave the in-flight payment.
226- dbPayments , err = paymentDB .FetchPayments ()
227- if err != nil {
228- t .Fatal (err )
229- }
230-
231- if len (dbPayments ) != numInflight {
232- t .Fatalf ("expected %d payments, got %d" , numInflight ,
233- len (dbPayments ))
234- }
235-
236- for _ , p := range dbPayments {
237- if p .Status != StatusInFlight {
238- t .Fatalf ("expected in-fligth status, got %v" , p .Status )
239- }
240- }
241-
242- // Finally, check that we only have a single index left in the payment
243- // index bucket.
244- var indexCount int
109+ // Verify the payment index is now empty - all 3 entries (parent +
110+ // duplicates) should be removed.
111+ indexCount = 0
245112 err = kvdb .View (paymentDB .db , func (tx walletdb.ReadTx ) error {
246113 index := tx .ReadBucket (paymentsIndexBucket )
247114
@@ -251,8 +118,8 @@ func TestKVStoreDeleteNonInFlight(t *testing.T) {
251118 })
252119 }, func () { indexCount = 0 })
253120 require .NoError (t , err )
254-
255- require . Equal ( t , 1 , indexCount )
121+ require . Equal ( t , 0 , indexCount , "payment index should be empty " +
122+ "after deleting payment with duplicates" )
256123}
257124
258125func makeFakeInfo (t * testing.T ) (* PaymentCreationInfo ,
0 commit comments