mp_payment_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. package channeldb
  2. import (
  3. "bytes"
  4. "fmt"
  5. "testing"
  6. "github.com/lightningnetwork/lnd/lntypes"
  7. "github.com/lightningnetwork/lnd/lnwire"
  8. "github.com/lightningnetwork/lnd/routing/route"
  9. "github.com/stretchr/testify/require"
  10. )
  11. // TestLazySessionKeyDeserialize tests that we can read htlc attempt session
  12. // keys that were previously serialized as a private key as raw bytes.
  13. func TestLazySessionKeyDeserialize(t *testing.T) {
  14. var b bytes.Buffer
  15. // Serialize as a private key.
  16. err := WriteElements(&b, priv)
  17. require.NoError(t, err)
  18. // Deserialize into [btcec.PrivKeyBytesLen]byte.
  19. attempt := HTLCAttemptInfo{}
  20. err = ReadElements(&b, &attempt.sessionKey)
  21. require.NoError(t, err)
  22. require.Zero(t, b.Len())
  23. sessionKey := attempt.SessionKey()
  24. require.Equal(t, priv, sessionKey)
  25. }
  26. // TestRegistrable checks the method `Registrable` behaves as expected for ALL
  27. // possible payment statuses.
  28. func TestRegistrable(t *testing.T) {
  29. t.Parallel()
  30. testCases := []struct {
  31. status PaymentStatus
  32. registryErr error
  33. hasSettledHTLC bool
  34. paymentFailed bool
  35. }{
  36. {
  37. status: StatusInitiated,
  38. registryErr: nil,
  39. },
  40. {
  41. // Test inflight status with no settled HTLC and no
  42. // failed payment.
  43. status: StatusInFlight,
  44. registryErr: nil,
  45. },
  46. {
  47. // Test inflight status with settled HTLC but no failed
  48. // payment.
  49. status: StatusInFlight,
  50. registryErr: ErrPaymentPendingSettled,
  51. hasSettledHTLC: true,
  52. },
  53. {
  54. // Test inflight status with no settled HTLC but failed
  55. // payment.
  56. status: StatusInFlight,
  57. registryErr: ErrPaymentPendingFailed,
  58. paymentFailed: true,
  59. },
  60. {
  61. // Test error state with settled HTLC and failed
  62. // payment.
  63. status: 0,
  64. registryErr: ErrUnknownPaymentStatus,
  65. hasSettledHTLC: true,
  66. paymentFailed: true,
  67. },
  68. {
  69. status: StatusSucceeded,
  70. registryErr: ErrPaymentAlreadySucceeded,
  71. },
  72. {
  73. status: StatusFailed,
  74. registryErr: ErrPaymentAlreadyFailed,
  75. },
  76. {
  77. status: 0,
  78. registryErr: ErrUnknownPaymentStatus,
  79. },
  80. }
  81. for i, tc := range testCases {
  82. i, tc := i, tc
  83. p := &MPPayment{
  84. Status: tc.status,
  85. State: &MPPaymentState{
  86. HasSettledHTLC: tc.hasSettledHTLC,
  87. PaymentFailed: tc.paymentFailed,
  88. },
  89. }
  90. name := fmt.Sprintf("test_%d_%s", i, p.Status.String())
  91. t.Run(name, func(t *testing.T) {
  92. t.Parallel()
  93. err := p.Registrable()
  94. require.ErrorIs(t, err, tc.registryErr,
  95. "registrable under state %v", tc.status)
  96. })
  97. }
  98. }
  99. // TestPaymentSetState checks that the method setState creates the
  100. // MPPaymentState as expected.
  101. func TestPaymentSetState(t *testing.T) {
  102. t.Parallel()
  103. // Create a test preimage and failure reason.
  104. preimage := lntypes.Preimage{1}
  105. failureReasonError := FailureReasonError
  106. testCases := []struct {
  107. name string
  108. payment *MPPayment
  109. totalAmt int
  110. expectedState *MPPaymentState
  111. errExpected error
  112. }{
  113. {
  114. // Test that when the sentAmt exceeds totalAmount, the
  115. // error is returned.
  116. name: "amount exceeded error",
  117. // SentAmt returns 90, 10
  118. // TerminalInfo returns non-nil, nil
  119. // InFlightHTLCs returns 0
  120. payment: &MPPayment{
  121. HTLCs: []HTLCAttempt{
  122. makeSettledAttempt(100, 10, preimage),
  123. },
  124. },
  125. totalAmt: 1,
  126. errExpected: ErrSentExceedsTotal,
  127. },
  128. {
  129. // Test that when the htlc is failed, the fee is not
  130. // used.
  131. name: "fee excluded for failed htlc",
  132. payment: &MPPayment{
  133. // SentAmt returns 90, 10
  134. // TerminalInfo returns nil, nil
  135. // InFlightHTLCs returns 1
  136. HTLCs: []HTLCAttempt{
  137. makeActiveAttempt(100, 10),
  138. makeFailedAttempt(100, 10),
  139. },
  140. },
  141. totalAmt: 1000,
  142. expectedState: &MPPaymentState{
  143. NumAttemptsInFlight: 1,
  144. RemainingAmt: 1000 - 90,
  145. FeesPaid: 10,
  146. HasSettledHTLC: false,
  147. PaymentFailed: false,
  148. },
  149. },
  150. {
  151. // Test when the payment is settled, the state should
  152. // be marked as terminated.
  153. name: "payment settled",
  154. // SentAmt returns 90, 10
  155. // TerminalInfo returns non-nil, nil
  156. // InFlightHTLCs returns 0
  157. payment: &MPPayment{
  158. HTLCs: []HTLCAttempt{
  159. makeSettledAttempt(100, 10, preimage),
  160. },
  161. },
  162. totalAmt: 1000,
  163. expectedState: &MPPaymentState{
  164. NumAttemptsInFlight: 0,
  165. RemainingAmt: 1000 - 90,
  166. FeesPaid: 10,
  167. HasSettledHTLC: true,
  168. PaymentFailed: false,
  169. },
  170. },
  171. {
  172. // Test when the payment is failed, the state should be
  173. // marked as terminated.
  174. name: "payment failed",
  175. // SentAmt returns 0, 0
  176. // TerminalInfo returns nil, non-nil
  177. // InFlightHTLCs returns 0
  178. payment: &MPPayment{
  179. FailureReason: &failureReasonError,
  180. },
  181. totalAmt: 1000,
  182. expectedState: &MPPaymentState{
  183. NumAttemptsInFlight: 0,
  184. RemainingAmt: 1000,
  185. FeesPaid: 0,
  186. HasSettledHTLC: false,
  187. PaymentFailed: true,
  188. },
  189. },
  190. }
  191. for _, tc := range testCases {
  192. tc := tc
  193. t.Run(tc.name, func(t *testing.T) {
  194. t.Parallel()
  195. // Attach the payment info.
  196. info := &PaymentCreationInfo{
  197. Value: lnwire.MilliSatoshi(tc.totalAmt),
  198. }
  199. tc.payment.Info = info
  200. // Call the method that updates the payment state.
  201. err := tc.payment.setState()
  202. require.ErrorIs(t, err, tc.errExpected)
  203. require.Equal(
  204. t, tc.expectedState, tc.payment.State,
  205. "state not updated as expected",
  206. )
  207. })
  208. }
  209. }
  210. // TestNeedWaitAttempts checks whether we need to wait for the results of the
  211. // HTLC attempts against ALL possible payment statuses.
  212. func TestNeedWaitAttempts(t *testing.T) {
  213. t.Parallel()
  214. testCases := []struct {
  215. status PaymentStatus
  216. remainingAmt lnwire.MilliSatoshi
  217. hasSettledHTLC bool
  218. hasFailureReason bool
  219. needWait bool
  220. expectedErr error
  221. }{
  222. {
  223. // For a newly created payment we don't need to wait
  224. // for results.
  225. status: StatusInitiated,
  226. remainingAmt: 1000,
  227. needWait: false,
  228. expectedErr: nil,
  229. },
  230. {
  231. // With HTLCs inflight we don't need to wait when the
  232. // remainingAmt is not zero and we have no settled
  233. // HTLCs.
  234. status: StatusInFlight,
  235. remainingAmt: 1000,
  236. needWait: false,
  237. expectedErr: nil,
  238. },
  239. {
  240. // With HTLCs inflight we need to wait when the
  241. // remainingAmt is not zero but we have settled HTLCs.
  242. status: StatusInFlight,
  243. remainingAmt: 1000,
  244. hasSettledHTLC: true,
  245. needWait: true,
  246. expectedErr: nil,
  247. },
  248. {
  249. // With HTLCs inflight we need to wait when the
  250. // remainingAmt is not zero and the payment is failed.
  251. status: StatusInFlight,
  252. remainingAmt: 1000,
  253. needWait: true,
  254. hasFailureReason: true,
  255. expectedErr: nil,
  256. },
  257. {
  258. // With the payment settled, but the remainingAmt is
  259. // not zero, we have an error state.
  260. status: StatusSucceeded,
  261. remainingAmt: 1000,
  262. needWait: false,
  263. expectedErr: ErrPaymentInternal,
  264. },
  265. {
  266. // Payment is in terminal state, no need to wait.
  267. status: StatusFailed,
  268. remainingAmt: 1000,
  269. needWait: false,
  270. expectedErr: nil,
  271. },
  272. {
  273. // A newly created payment with zero remainingAmt
  274. // indicates an error.
  275. status: StatusInitiated,
  276. remainingAmt: 0,
  277. needWait: false,
  278. expectedErr: ErrPaymentInternal,
  279. },
  280. {
  281. // With zero remainingAmt we must wait for the results.
  282. status: StatusInFlight,
  283. remainingAmt: 0,
  284. needWait: true,
  285. expectedErr: nil,
  286. },
  287. {
  288. // Payment is terminated, no need to wait for results.
  289. status: StatusSucceeded,
  290. remainingAmt: 0,
  291. needWait: false,
  292. expectedErr: nil,
  293. },
  294. {
  295. // Payment is terminated, no need to wait for results.
  296. status: StatusFailed,
  297. remainingAmt: 0,
  298. needWait: false,
  299. expectedErr: ErrPaymentInternal,
  300. },
  301. {
  302. // Payment is in an unknown status, return an error.
  303. status: 0,
  304. remainingAmt: 0,
  305. needWait: false,
  306. expectedErr: ErrUnknownPaymentStatus,
  307. },
  308. {
  309. // Payment is in an unknown status, return an error.
  310. status: 0,
  311. remainingAmt: 1000,
  312. needWait: false,
  313. expectedErr: ErrUnknownPaymentStatus,
  314. },
  315. }
  316. for _, tc := range testCases {
  317. tc := tc
  318. p := &MPPayment{
  319. Info: &PaymentCreationInfo{
  320. PaymentIdentifier: [32]byte{1, 2, 3},
  321. },
  322. Status: tc.status,
  323. State: &MPPaymentState{
  324. RemainingAmt: tc.remainingAmt,
  325. HasSettledHTLC: tc.hasSettledHTLC,
  326. PaymentFailed: tc.hasFailureReason,
  327. },
  328. }
  329. name := fmt.Sprintf("status=%s|remainingAmt=%v|"+
  330. "settledHTLC=%v|failureReason=%v", tc.status,
  331. tc.remainingAmt, tc.hasSettledHTLC, tc.hasFailureReason)
  332. t.Run(name, func(t *testing.T) {
  333. t.Parallel()
  334. result, err := p.NeedWaitAttempts()
  335. require.ErrorIs(t, err, tc.expectedErr)
  336. require.Equalf(t, tc.needWait, result, "status=%v, "+
  337. "remainingAmt=%v", tc.status, tc.remainingAmt)
  338. })
  339. }
  340. }
  341. // TestAllowMoreAttempts checks whether more attempts can be created against
  342. // ALL possible payment statuses.
  343. func TestAllowMoreAttempts(t *testing.T) {
  344. t.Parallel()
  345. testCases := []struct {
  346. status PaymentStatus
  347. remainingAmt lnwire.MilliSatoshi
  348. hasSettledHTLC bool
  349. paymentFailed bool
  350. allowMore bool
  351. expectedErr error
  352. }{
  353. {
  354. // A newly created payment with zero remainingAmt
  355. // indicates an error.
  356. status: StatusInitiated,
  357. remainingAmt: 0,
  358. allowMore: false,
  359. expectedErr: ErrPaymentInternal,
  360. },
  361. {
  362. // With zero remainingAmt we don't allow more HTLC
  363. // attempts.
  364. status: StatusInFlight,
  365. remainingAmt: 0,
  366. allowMore: false,
  367. expectedErr: nil,
  368. },
  369. {
  370. // With zero remainingAmt we don't allow more HTLC
  371. // attempts.
  372. status: StatusSucceeded,
  373. remainingAmt: 0,
  374. allowMore: false,
  375. expectedErr: nil,
  376. },
  377. {
  378. // With zero remainingAmt we don't allow more HTLC
  379. // attempts.
  380. status: StatusFailed,
  381. remainingAmt: 0,
  382. allowMore: false,
  383. expectedErr: nil,
  384. },
  385. {
  386. // With zero remainingAmt and settled HTLCs we don't
  387. // allow more HTLC attempts.
  388. status: StatusInFlight,
  389. remainingAmt: 0,
  390. hasSettledHTLC: true,
  391. allowMore: false,
  392. expectedErr: nil,
  393. },
  394. {
  395. // With zero remainingAmt and failed payment we don't
  396. // allow more HTLC attempts.
  397. status: StatusInFlight,
  398. remainingAmt: 0,
  399. paymentFailed: true,
  400. allowMore: false,
  401. expectedErr: nil,
  402. },
  403. {
  404. // With zero remainingAmt and both settled HTLCs and
  405. // failed payment, we don't allow more HTLC attempts.
  406. status: StatusInFlight,
  407. remainingAmt: 0,
  408. hasSettledHTLC: true,
  409. paymentFailed: true,
  410. allowMore: false,
  411. expectedErr: nil,
  412. },
  413. {
  414. // A newly created payment can have more attempts.
  415. status: StatusInitiated,
  416. remainingAmt: 1000,
  417. allowMore: true,
  418. expectedErr: nil,
  419. },
  420. {
  421. // With HTLCs inflight we can have more attempts when
  422. // the remainingAmt is not zero and we have neither
  423. // failed payment or settled HTLCs.
  424. status: StatusInFlight,
  425. remainingAmt: 1000,
  426. allowMore: true,
  427. expectedErr: nil,
  428. },
  429. {
  430. // With HTLCs inflight we cannot have more attempts
  431. // though the remainingAmt is not zero but we have
  432. // settled HTLCs.
  433. status: StatusInFlight,
  434. remainingAmt: 1000,
  435. hasSettledHTLC: true,
  436. allowMore: false,
  437. expectedErr: nil,
  438. },
  439. {
  440. // With HTLCs inflight we cannot have more attempts
  441. // though the remainingAmt is not zero but we have
  442. // failed payment.
  443. status: StatusInFlight,
  444. remainingAmt: 1000,
  445. paymentFailed: true,
  446. allowMore: false,
  447. expectedErr: nil,
  448. },
  449. {
  450. // With HTLCs inflight we cannot have more attempts
  451. // though the remainingAmt is not zero but we have
  452. // settled HTLCs and failed payment.
  453. status: StatusInFlight,
  454. remainingAmt: 1000,
  455. hasSettledHTLC: true,
  456. paymentFailed: true,
  457. allowMore: false,
  458. expectedErr: nil,
  459. },
  460. {
  461. // With the payment settled, but the remainingAmt is
  462. // not zero, we have an error state.
  463. status: StatusSucceeded,
  464. remainingAmt: 1000,
  465. hasSettledHTLC: true,
  466. allowMore: false,
  467. expectedErr: ErrPaymentInternal,
  468. },
  469. {
  470. // With the payment failed with no inflight HTLCs, we
  471. // don't allow more attempts to be made.
  472. status: StatusFailed,
  473. remainingAmt: 1000,
  474. paymentFailed: true,
  475. allowMore: false,
  476. expectedErr: nil,
  477. },
  478. {
  479. // With the payment in an unknown state, we don't allow
  480. // more attempts to be made.
  481. status: 0,
  482. remainingAmt: 1000,
  483. allowMore: false,
  484. expectedErr: nil,
  485. },
  486. }
  487. for i, tc := range testCases {
  488. tc := tc
  489. p := &MPPayment{
  490. Info: &PaymentCreationInfo{
  491. PaymentIdentifier: [32]byte{1, 2, 3},
  492. },
  493. Status: tc.status,
  494. State: &MPPaymentState{
  495. RemainingAmt: tc.remainingAmt,
  496. HasSettledHTLC: tc.hasSettledHTLC,
  497. PaymentFailed: tc.paymentFailed,
  498. },
  499. }
  500. name := fmt.Sprintf("test_%d|status=%s|remainingAmt=%v", i,
  501. tc.status, tc.remainingAmt)
  502. t.Run(name, func(t *testing.T) {
  503. t.Parallel()
  504. result, err := p.AllowMoreAttempts()
  505. require.ErrorIs(t, err, tc.expectedErr)
  506. require.Equalf(t, tc.allowMore, result, "status=%v, "+
  507. "remainingAmt=%v", tc.status, tc.remainingAmt)
  508. })
  509. }
  510. }
  511. func makeActiveAttempt(total, fee int) HTLCAttempt {
  512. return HTLCAttempt{
  513. HTLCAttemptInfo: makeAttemptInfo(total, total-fee),
  514. }
  515. }
  516. func makeSettledAttempt(total, fee int,
  517. preimage lntypes.Preimage) HTLCAttempt {
  518. return HTLCAttempt{
  519. HTLCAttemptInfo: makeAttemptInfo(total, total-fee),
  520. Settle: &HTLCSettleInfo{Preimage: preimage},
  521. }
  522. }
  523. func makeFailedAttempt(total, fee int) HTLCAttempt {
  524. return HTLCAttempt{
  525. HTLCAttemptInfo: makeAttemptInfo(total, total-fee),
  526. Failure: &HTLCFailInfo{
  527. Reason: HTLCFailInternal,
  528. },
  529. }
  530. }
  531. func makeAttemptInfo(total, amtForwarded int) HTLCAttemptInfo {
  532. hop := &route.Hop{AmtToForward: lnwire.MilliSatoshi(amtForwarded)}
  533. return HTLCAttemptInfo{
  534. Route: route.Route{
  535. TotalAmount: lnwire.MilliSatoshi(total),
  536. Hops: []*route.Hop{hop},
  537. },
  538. }
  539. }