routing: use Identifier in place of PaymentHash

Since we want to support AMP payment using a different unique payment
identifier (AMP payments don't go to one specific hash), we change the
nomenclature to be Identifier instead of PaymentHash.
This commit is contained in:
Johan T. Halseth 2021-03-31 12:23:08 +02:00
parent 6104d12cf8
commit f07c9d002c
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
17 changed files with 296 additions and 245 deletions

@ -99,7 +99,7 @@ func deserializeDuplicatePaymentCreationInfo(r io.Reader) (
c := &PaymentCreationInfo{} c := &PaymentCreationInfo{}
if _, err := io.ReadFull(r, c.PaymentHash[:]); err != nil { if _, err := io.ReadFull(r, c.PaymentIdentifier[:]); err != nil {
return nil, err return nil, err
} }

@ -173,8 +173,10 @@ func (p *PaymentControl) InitPayment(paymentHash lntypes.Hash,
// Once we have obtained a sequence number, we add an entry // Once we have obtained a sequence number, we add an entry
// to our index bucket which will map the sequence number to // to our index bucket which will map the sequence number to
// our payment hash. // our payment identifier.
err = createPaymentIndexEntry(tx, sequenceNum, info.PaymentHash) err = createPaymentIndexEntry(
tx, sequenceNum, info.PaymentIdentifier,
)
if err != nil { if err != nil {
return err return err
} }
@ -220,12 +222,12 @@ const paymentIndexTypeHash paymentIndexType = 0
// createPaymentIndexEntry creates a payment hash typed index for a payment. The // createPaymentIndexEntry creates a payment hash typed index for a payment. The
// index produced contains a payment index type (which can be used in future to // index produced contains a payment index type (which can be used in future to
// signal different payment index types) and the payment hash. // signal different payment index types) and the payment identifier.
func createPaymentIndexEntry(tx kvdb.RwTx, sequenceNumber []byte, func createPaymentIndexEntry(tx kvdb.RwTx, sequenceNumber []byte,
hash lntypes.Hash) error { id lntypes.Hash) error {
var b bytes.Buffer var b bytes.Buffer
if err := WriteElements(&b, paymentIndexTypeHash, hash[:]); err != nil { if err := WriteElements(&b, paymentIndexTypeHash, id[:]); err != nil {
return err return err
} }

@ -38,10 +38,10 @@ func genInfo() (*PaymentCreationInfo, *HTLCAttemptInfo,
rhash := sha256.Sum256(preimage[:]) rhash := sha256.Sum256(preimage[:])
return &PaymentCreationInfo{ return &PaymentCreationInfo{
PaymentHash: rhash, PaymentIdentifier: rhash,
Value: testRoute.ReceiverAmt(), Value: testRoute.ReceiverAmt(),
CreationTime: time.Unix(time.Now().Unix(), 0), CreationTime: time.Unix(time.Now().Unix(), 0),
PaymentRequest: []byte("hola"), PaymentRequest: []byte("hola"),
}, },
&HTLCAttemptInfo{ &HTLCAttemptInfo{
AttemptID: 0, AttemptID: 0,
@ -70,63 +70,63 @@ func TestPaymentControlSwitchFail(t *testing.T) {
} }
// Sends base htlc message which initiate StatusInFlight. // Sends base htlc message which initiate StatusInFlight.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
assertPaymentIndex(t, pControl, info.PaymentHash) assertPaymentIndex(t, pControl, info.PaymentIdentifier)
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, nil, t, pControl, info.PaymentIdentifier, info, nil, nil,
) )
// Fail the payment, which should moved it to Failed. // Fail the payment, which should moved it to Failed.
failReason := FailureReasonNoRoute failReason := FailureReasonNoRoute
_, err = pControl.Fail(info.PaymentHash, failReason) _, err = pControl.Fail(info.PaymentIdentifier, failReason)
if err != nil { if err != nil {
t.Fatalf("unable to fail payment hash: %v", err) t.Fatalf("unable to fail payment hash: %v", err)
} }
// Verify the status is indeed Failed. // Verify the status is indeed Failed.
assertPaymentStatus(t, pControl, info.PaymentHash, StatusFailed) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusFailed)
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, &failReason, nil, t, pControl, info.PaymentIdentifier, info, &failReason, nil,
) )
// Lookup the payment so we can get its old sequence number before it is // Lookup the payment so we can get its old sequence number before it is
// overwritten. // overwritten.
payment, err := pControl.FetchPayment(info.PaymentHash) payment, err := pControl.FetchPayment(info.PaymentIdentifier)
assert.NoError(t, err) assert.NoError(t, err)
// Sends the htlc again, which should succeed since the prior payment // Sends the htlc again, which should succeed since the prior payment
// failed. // failed.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
// Check that our index has been updated, and the old index has been // Check that our index has been updated, and the old index has been
// removed. // removed.
assertPaymentIndex(t, pControl, info.PaymentHash) assertPaymentIndex(t, pControl, info.PaymentIdentifier)
assertNoIndex(t, pControl, payment.SequenceNum) assertNoIndex(t, pControl, payment.SequenceNum)
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, nil, t, pControl, info.PaymentIdentifier, info, nil, nil,
) )
// Record a new attempt. In this test scenario, the attempt fails. // Record a new attempt. In this test scenario, the attempt fails.
// However, this is not communicated to control tower in the current // However, this is not communicated to control tower in the current
// implementation. It only registers the initiation of the attempt. // implementation. It only registers the initiation of the attempt.
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatalf("unable to register attempt: %v", err) t.Fatalf("unable to register attempt: %v", err)
} }
htlcReason := HTLCFailUnreadable htlcReason := HTLCFailUnreadable
_, err = pControl.FailAttempt( _, err = pControl.FailAttempt(
info.PaymentHash, attempt.AttemptID, info.PaymentIdentifier, attempt.AttemptID,
&HTLCFailInfo{ &HTLCFailInfo{
Reason: htlcReason, Reason: htlcReason,
}, },
@ -134,35 +134,35 @@ func TestPaymentControlSwitchFail(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
htlc := &htlcStatus{ htlc := &htlcStatus{
HTLCAttemptInfo: attempt, HTLCAttemptInfo: attempt,
failure: &htlcReason, failure: &htlcReason,
} }
assertPaymentInfo(t, pControl, info.PaymentHash, info, nil, htlc) assertPaymentInfo(t, pControl, info.PaymentIdentifier, info, nil, htlc)
// Record another attempt. // Record another attempt.
attempt.AttemptID = 1 attempt.AttemptID = 1
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
htlc = &htlcStatus{ htlc = &htlcStatus{
HTLCAttemptInfo: attempt, HTLCAttemptInfo: attempt,
} }
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
// Settle the attempt and verify that status was changed to // Settle the attempt and verify that status was changed to
// StatusSucceeded. // StatusSucceeded.
payment, err = pControl.SettleAttempt( payment, err = pControl.SettleAttempt(
info.PaymentHash, attempt.AttemptID, info.PaymentIdentifier, attempt.AttemptID,
&HTLCSettleInfo{ &HTLCSettleInfo{
Preimage: preimg, Preimage: preimg,
}, },
@ -183,16 +183,16 @@ func TestPaymentControlSwitchFail(t *testing.T) {
spew.Sdump(payment.HTLCs[0].Route), err) spew.Sdump(payment.HTLCs[0].Route), err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusSucceeded) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded)
htlc.settle = &preimg htlc.settle = &preimg
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
// Attempt a final payment, which should now fail since the prior // Attempt a final payment, which should now fail since the prior
// payment succeed. // payment succeed.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != ErrAlreadyPaid { if err != ErrAlreadyPaid {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
@ -219,42 +219,42 @@ func TestPaymentControlSwitchDoubleSend(t *testing.T) {
// Sends base htlc message which initiate base status and move it to // Sends base htlc message which initiate base status and move it to
// StatusInFlight and verifies that it was changed. // StatusInFlight and verifies that it was changed.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
assertPaymentIndex(t, pControl, info.PaymentHash) assertPaymentIndex(t, pControl, info.PaymentIdentifier)
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, nil, t, pControl, info.PaymentIdentifier, info, nil, nil,
) )
// Try to initiate double sending of htlc message with the same // Try to initiate double sending of htlc message with the same
// payment hash, should result in error indicating that payment has // payment hash, should result in error indicating that payment has
// already been sent. // already been sent.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != ErrPaymentInFlight { if err != ErrPaymentInFlight {
t.Fatalf("payment control wrong behaviour: " + t.Fatalf("payment control wrong behaviour: " +
"double sending must trigger ErrPaymentInFlight error") "double sending must trigger ErrPaymentInFlight error")
} }
// Record an attempt. // Record an attempt.
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
htlc := &htlcStatus{ htlc := &htlcStatus{
HTLCAttemptInfo: attempt, HTLCAttemptInfo: attempt,
} }
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
// Sends base htlc message which initiate StatusInFlight. // Sends base htlc message which initiate StatusInFlight.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != ErrPaymentInFlight { if err != ErrPaymentInFlight {
t.Fatalf("payment control wrong behaviour: " + t.Fatalf("payment control wrong behaviour: " +
"double sending must trigger ErrPaymentInFlight error") "double sending must trigger ErrPaymentInFlight error")
@ -262,7 +262,7 @@ func TestPaymentControlSwitchDoubleSend(t *testing.T) {
// After settling, the error should be ErrAlreadyPaid. // After settling, the error should be ErrAlreadyPaid.
_, err = pControl.SettleAttempt( _, err = pControl.SettleAttempt(
info.PaymentHash, attempt.AttemptID, info.PaymentIdentifier, attempt.AttemptID,
&HTLCSettleInfo{ &HTLCSettleInfo{
Preimage: preimg, Preimage: preimg,
}, },
@ -270,12 +270,12 @@ func TestPaymentControlSwitchDoubleSend(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("error shouldn't have been received, got: %v", err) t.Fatalf("error shouldn't have been received, got: %v", err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusSucceeded) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded)
htlc.settle = &preimg htlc.settle = &preimg
assertPaymentInfo(t, pControl, info.PaymentHash, info, nil, htlc) assertPaymentInfo(t, pControl, info.PaymentIdentifier, info, nil, htlc)
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != ErrAlreadyPaid { if err != ErrAlreadyPaid {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
@ -302,7 +302,7 @@ func TestPaymentControlSuccessesWithoutInFlight(t *testing.T) {
// Attempt to complete the payment should fail. // Attempt to complete the payment should fail.
_, err = pControl.SettleAttempt( _, err = pControl.SettleAttempt(
info.PaymentHash, 0, info.PaymentIdentifier, 0,
&HTLCSettleInfo{ &HTLCSettleInfo{
Preimage: preimg, Preimage: preimg,
}, },
@ -311,7 +311,7 @@ func TestPaymentControlSuccessesWithoutInFlight(t *testing.T) {
t.Fatalf("expected ErrPaymentNotInitiated, got %v", err) t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusUnknown) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusUnknown)
} }
// TestPaymentControlFailsWithoutInFlight checks that a strict payment // TestPaymentControlFailsWithoutInFlight checks that a strict payment
@ -334,12 +334,12 @@ func TestPaymentControlFailsWithoutInFlight(t *testing.T) {
} }
// Calling Fail should return an error. // Calling Fail should return an error.
_, err = pControl.Fail(info.PaymentHash, FailureReasonNoRoute) _, err = pControl.Fail(info.PaymentIdentifier, FailureReasonNoRoute)
if err != ErrPaymentNotInitiated { if err != ErrPaymentNotInitiated {
t.Fatalf("expected ErrPaymentNotInitiated, got %v", err) t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusUnknown) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusUnknown)
} }
// TestPaymentControlDeleteNonInFlight checks that calling DeletePayments only // TestPaymentControlDeleteNonInFlight checks that calling DeletePayments only
@ -397,11 +397,11 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
} }
// Sends base htlc message which initiate StatusInFlight. // Sends base htlc message which initiate StatusInFlight.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
@ -414,7 +414,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
// Fail the payment attempt. // Fail the payment attempt.
htlcFailure := HTLCFailUnreadable htlcFailure := HTLCFailUnreadable
_, err := pControl.FailAttempt( _, err := pControl.FailAttempt(
info.PaymentHash, attempt.AttemptID, info.PaymentIdentifier, attempt.AttemptID,
&HTLCFailInfo{ &HTLCFailInfo{
Reason: htlcFailure, Reason: htlcFailure,
}, },
@ -425,23 +425,23 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
// Fail the payment, which should moved it to Failed. // Fail the payment, which should moved it to Failed.
failReason := FailureReasonNoRoute failReason := FailureReasonNoRoute
_, err = pControl.Fail(info.PaymentHash, failReason) _, err = pControl.Fail(info.PaymentIdentifier, failReason)
if err != nil { if err != nil {
t.Fatalf("unable to fail payment hash: %v", err) t.Fatalf("unable to fail payment hash: %v", err)
} }
// Verify the status is indeed Failed. // Verify the status is indeed Failed.
assertPaymentStatus(t, pControl, info.PaymentHash, StatusFailed) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusFailed)
htlc.failure = &htlcFailure htlc.failure = &htlcFailure
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, t, pControl, info.PaymentIdentifier, info,
&failReason, htlc, &failReason, htlc,
) )
} else if p.success { } else if p.success {
// Verifies that status was changed to StatusSucceeded. // Verifies that status was changed to StatusSucceeded.
_, err := pControl.SettleAttempt( _, err := pControl.SettleAttempt(
info.PaymentHash, attempt.AttemptID, info.PaymentIdentifier, attempt.AttemptID,
&HTLCSettleInfo{ &HTLCSettleInfo{
Preimage: preimg, Preimage: preimg,
}, },
@ -450,18 +450,18 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
t.Fatalf("error shouldn't have been received, got: %v", err) t.Fatalf("error shouldn't have been received, got: %v", err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusSucceeded) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded)
htlc.settle = &preimg htlc.settle = &preimg
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
numSuccess++ numSuccess++
} else { } else {
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
numInflight++ numInflight++
@ -471,7 +471,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
// add one. // add one.
if p.hasDuplicate { if p.hasDuplicate {
appendDuplicatePayment( appendDuplicatePayment(
t, pControl.db, info.PaymentHash, t, pControl.db, info.PaymentIdentifier,
uint64(duplicateSeqNr), preimg, uint64(duplicateSeqNr), preimg,
) )
duplicateSeqNr++ duplicateSeqNr++
@ -582,20 +582,20 @@ func TestPaymentControlDeletePayments(t *testing.T) {
attemptID++ attemptID++
// Init the payment. // Init the payment.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
// Register and fail the first attempt for all three payments. // Register and fail the first attempt for all three payments.
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
htlcFailure := HTLCFailUnreadable htlcFailure := HTLCFailUnreadable
_, err = pControl.FailAttempt( _, err = pControl.FailAttempt(
info.PaymentHash, attempt.AttemptID, info.PaymentIdentifier, attempt.AttemptID,
&HTLCFailInfo{ &HTLCFailInfo{
Reason: htlcFailure, Reason: htlcFailure,
}, },
@ -609,7 +609,7 @@ func TestPaymentControlDeletePayments(t *testing.T) {
attempt.AttemptID = attemptID attempt.AttemptID = attemptID
attemptID++ attemptID++
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
@ -620,7 +620,7 @@ func TestPaymentControlDeletePayments(t *testing.T) {
case 0: case 0:
htlcFailure := HTLCFailUnreadable htlcFailure := HTLCFailUnreadable
_, err = pControl.FailAttempt( _, err = pControl.FailAttempt(
info.PaymentHash, attempt.AttemptID, info.PaymentIdentifier, attempt.AttemptID,
&HTLCFailInfo{ &HTLCFailInfo{
Reason: htlcFailure, Reason: htlcFailure,
}, },
@ -630,7 +630,7 @@ func TestPaymentControlDeletePayments(t *testing.T) {
} }
failReason := FailureReasonNoRoute failReason := FailureReasonNoRoute
_, err = pControl.Fail(info.PaymentHash, failReason) _, err = pControl.Fail(info.PaymentIdentifier, failReason)
if err != nil { if err != nil {
t.Fatalf("unable to fail payment hash: %v", err) t.Fatalf("unable to fail payment hash: %v", err)
} }
@ -638,7 +638,7 @@ func TestPaymentControlDeletePayments(t *testing.T) {
// Settle the attempt // Settle the attempt
case 1: case 1:
_, err := pControl.SettleAttempt( _, err := pControl.SettleAttempt(
info.PaymentHash, attempt.AttemptID, info.PaymentIdentifier, attempt.AttemptID,
&HTLCSettleInfo{ &HTLCSettleInfo{
Preimage: preimg, Preimage: preimg,
}, },
@ -807,15 +807,15 @@ func TestPaymentControlMultiShard(t *testing.T) {
} }
// Init the payment, moving it to the StatusInFlight state. // Init the payment, moving it to the StatusInFlight state.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
assertPaymentIndex(t, pControl, info.PaymentHash) assertPaymentIndex(t, pControl, info.PaymentIdentifier)
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, nil, t, pControl, info.PaymentIdentifier, info, nil, nil,
) )
// Create three unique attempts we'll use for the test, and // Create three unique attempts we'll use for the test, and
@ -834,19 +834,19 @@ func TestPaymentControlMultiShard(t *testing.T) {
a.AttemptID = i a.AttemptID = i
attempts = append(attempts, &a) attempts = append(attempts, &a)
_, err = pControl.RegisterAttempt(info.PaymentHash, &a) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &a)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
assertPaymentStatus( assertPaymentStatus(
t, pControl, info.PaymentHash, StatusInFlight, t, pControl, info.PaymentIdentifier, StatusInFlight,
) )
htlc := &htlcStatus{ htlc := &htlcStatus{
HTLCAttemptInfo: &a, HTLCAttemptInfo: &a,
} }
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
} }
@ -855,7 +855,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
// will be too large. // will be too large.
b := *attempt b := *attempt
b.AttemptID = 3 b.AttemptID = 3
_, err = pControl.RegisterAttempt(info.PaymentHash, &b) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
if err != ErrValueExceedsAmt { if err != ErrValueExceedsAmt {
t.Fatalf("expected ErrValueExceedsAmt, got: %v", t.Fatalf("expected ErrValueExceedsAmt, got: %v",
err) err)
@ -865,7 +865,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
a := attempts[1] a := attempts[1]
htlcFail := HTLCFailUnreadable htlcFail := HTLCFailUnreadable
_, err = pControl.FailAttempt( _, err = pControl.FailAttempt(
info.PaymentHash, a.AttemptID, info.PaymentIdentifier, a.AttemptID,
&HTLCFailInfo{ &HTLCFailInfo{
Reason: htlcFail, Reason: htlcFail,
}, },
@ -879,11 +879,11 @@ func TestPaymentControlMultiShard(t *testing.T) {
failure: &htlcFail, failure: &htlcFail,
} }
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
// Payment should still be in-flight. // Payment should still be in-flight.
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
// Depending on the test case, settle or fail the first attempt. // Depending on the test case, settle or fail the first attempt.
a = attempts[0] a = attempts[0]
@ -894,7 +894,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
var firstFailReason *FailureReason var firstFailReason *FailureReason
if test.settleFirst { if test.settleFirst {
_, err := pControl.SettleAttempt( _, err := pControl.SettleAttempt(
info.PaymentHash, a.AttemptID, info.PaymentIdentifier, a.AttemptID,
&HTLCSettleInfo{ &HTLCSettleInfo{
Preimage: preimg, Preimage: preimg,
}, },
@ -907,11 +907,11 @@ func TestPaymentControlMultiShard(t *testing.T) {
// Assert that the HTLC has had the preimage recorded. // Assert that the HTLC has had the preimage recorded.
htlc.settle = &preimg htlc.settle = &preimg
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
} else { } else {
_, err := pControl.FailAttempt( _, err := pControl.FailAttempt(
info.PaymentHash, a.AttemptID, info.PaymentIdentifier, a.AttemptID,
&HTLCFailInfo{ &HTLCFailInfo{
Reason: htlcFail, Reason: htlcFail,
}, },
@ -924,13 +924,13 @@ func TestPaymentControlMultiShard(t *testing.T) {
// Assert the failure was recorded. // Assert the failure was recorded.
htlc.failure = &htlcFail htlc.failure = &htlcFail
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, nil, htlc, t, pControl, info.PaymentIdentifier, info, nil, htlc,
) )
// We also record a payment level fail, to move it into // We also record a payment level fail, to move it into
// a terminal state. // a terminal state.
failReason := FailureReasonNoRoute failReason := FailureReasonNoRoute
_, err = pControl.Fail(info.PaymentHash, failReason) _, err = pControl.Fail(info.PaymentIdentifier, failReason)
if err != nil { if err != nil {
t.Fatalf("unable to fail payment hash: %v", err) t.Fatalf("unable to fail payment hash: %v", err)
} }
@ -942,18 +942,18 @@ func TestPaymentControlMultiShard(t *testing.T) {
// The payment should still be considered in-flight, since there // The payment should still be considered in-flight, since there
// is still an active HTLC. // is still an active HTLC.
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
// Try to register yet another attempt. This should fail now // Try to register yet another attempt. This should fail now
// that the payment has reached a terminal condition. // that the payment has reached a terminal condition.
b = *attempt b = *attempt
b.AttemptID = 3 b.AttemptID = 3
_, err = pControl.RegisterAttempt(info.PaymentHash, &b) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
if err != ErrPaymentTerminal { if err != ErrPaymentTerminal {
t.Fatalf("expected ErrPaymentTerminal, got: %v", err) t.Fatalf("expected ErrPaymentTerminal, got: %v", err)
} }
assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
// Settle or fail the remaining attempt based on the testcase. // Settle or fail the remaining attempt based on the testcase.
a = attempts[2] a = attempts[2]
@ -963,7 +963,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
if test.settleLast { if test.settleLast {
// Settle the last outstanding attempt. // Settle the last outstanding attempt.
_, err = pControl.SettleAttempt( _, err = pControl.SettleAttempt(
info.PaymentHash, a.AttemptID, info.PaymentIdentifier, a.AttemptID,
&HTLCSettleInfo{ &HTLCSettleInfo{
Preimage: preimg, Preimage: preimg,
}, },
@ -975,13 +975,13 @@ func TestPaymentControlMultiShard(t *testing.T) {
htlc.settle = &preimg htlc.settle = &preimg
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, t, pControl, info.PaymentIdentifier, info,
firstFailReason, htlc, firstFailReason, htlc,
) )
} else { } else {
// Fail the attempt. // Fail the attempt.
_, err := pControl.FailAttempt( _, err := pControl.FailAttempt(
info.PaymentHash, a.AttemptID, info.PaymentIdentifier, a.AttemptID,
&HTLCFailInfo{ &HTLCFailInfo{
Reason: htlcFail, Reason: htlcFail,
}, },
@ -994,7 +994,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
// Assert the failure was recorded. // Assert the failure was recorded.
htlc.failure = &htlcFail htlc.failure = &htlcFail
assertPaymentInfo( assertPaymentInfo(
t, pControl, info.PaymentHash, info, t, pControl, info.PaymentIdentifier, info,
firstFailReason, htlc, firstFailReason, htlc,
) )
@ -1003,7 +1003,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
// write a terminal failure to the database without // write a terminal failure to the database without
// syncing. // syncing.
failReason := FailureReasonPaymentDetails failReason := FailureReasonPaymentDetails
_, err = pControl.Fail(info.PaymentHash, failReason) _, err = pControl.Fail(info.PaymentIdentifier, failReason)
if err != nil { if err != nil {
t.Fatalf("unable to fail payment hash: %v", err) t.Fatalf("unable to fail payment hash: %v", err)
} }
@ -1017,10 +1017,10 @@ func TestPaymentControlMultiShard(t *testing.T) {
finalStatus = StatusSucceeded finalStatus = StatusSucceeded
} }
assertPaymentStatus(t, pControl, info.PaymentHash, finalStatus) assertPaymentStatus(t, pControl, info.PaymentIdentifier, finalStatus)
// Finally assert we cannot register more attempts. // Finally assert we cannot register more attempts.
_, err = pControl.RegisterAttempt(info.PaymentHash, &b) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
require.Equal(t, ErrPaymentTerminal, err) require.Equal(t, ErrPaymentTerminal, err)
} }
@ -1053,7 +1053,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
} }
// Init the payment. // Init the payment.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
@ -1068,7 +1068,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
info.Value, [32]byte{1}, info.Value, [32]byte{1},
) )
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
@ -1077,7 +1077,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
b := *attempt b := *attempt
b.AttemptID = 1 b.AttemptID = 1
b.Route.FinalHop().MPP = nil b.Route.FinalHop().MPP = nil
_, err = pControl.RegisterAttempt(info.PaymentHash, &b) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
if err != ErrMPPayment { if err != ErrMPPayment {
t.Fatalf("expected ErrMPPayment, got: %v", err) t.Fatalf("expected ErrMPPayment, got: %v", err)
} }
@ -1086,7 +1086,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
b.Route.FinalHop().MPP = record.NewMPP( b.Route.FinalHop().MPP = record.NewMPP(
info.Value, [32]byte{2}, info.Value, [32]byte{2},
) )
_, err = pControl.RegisterAttempt(info.PaymentHash, &b) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
if err != ErrMPPPaymentAddrMismatch { if err != ErrMPPPaymentAddrMismatch {
t.Fatalf("expected ErrMPPPaymentAddrMismatch, got: %v", err) t.Fatalf("expected ErrMPPPaymentAddrMismatch, got: %v", err)
} }
@ -1095,7 +1095,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
b.Route.FinalHop().MPP = record.NewMPP( b.Route.FinalHop().MPP = record.NewMPP(
info.Value/2, [32]byte{1}, info.Value/2, [32]byte{1},
) )
_, err = pControl.RegisterAttempt(info.PaymentHash, &b) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
if err != ErrMPPTotalAmountMismatch { if err != ErrMPPTotalAmountMismatch {
t.Fatalf("expected ErrMPPTotalAmountMismatch, got: %v", err) t.Fatalf("expected ErrMPPTotalAmountMismatch, got: %v", err)
} }
@ -1107,13 +1107,13 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
t.Fatalf("unable to generate htlc message: %v", err) t.Fatalf("unable to generate htlc message: %v", err)
} }
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
attempt.Route.FinalHop().MPP = nil attempt.Route.FinalHop().MPP = nil
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatalf("unable to send htlc message: %v", err) t.Fatalf("unable to send htlc message: %v", err)
} }
@ -1125,7 +1125,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
info.Value, [32]byte{1}, info.Value, [32]byte{1},
) )
_, err = pControl.RegisterAttempt(info.PaymentHash, &b) _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
if err != ErrNonMPPayment { if err != ErrNonMPPayment {
t.Fatalf("expected ErrNonMPPayment, got: %v", err) t.Fatalf("expected ErrNonMPPayment, got: %v", err)
} }

@ -216,8 +216,9 @@ func (ps PaymentStatus) String() string {
// PaymentCreationInfo is the information necessary to have ready when // PaymentCreationInfo is the information necessary to have ready when
// initiating a payment, moving it into state InFlight. // initiating a payment, moving it into state InFlight.
type PaymentCreationInfo struct { type PaymentCreationInfo struct {
// PaymentHash is the hash this payment is paying to. // PaymentIdentifier is the hash this payment is paying to in case of
PaymentHash lntypes.Hash // non-AMP payments, and the SetID for AMP payments.
PaymentIdentifier lntypes.Hash
// Value is the amount we are paying. // Value is the amount we are paying.
Value lnwire.MilliSatoshi Value lnwire.MilliSatoshi
@ -856,7 +857,7 @@ func fetchSequenceNumbers(paymentBucket kvdb.RBucket) ([][]byte, error) {
func serializePaymentCreationInfo(w io.Writer, c *PaymentCreationInfo) error { func serializePaymentCreationInfo(w io.Writer, c *PaymentCreationInfo) error {
var scratch [8]byte var scratch [8]byte
if _, err := w.Write(c.PaymentHash[:]); err != nil { if _, err := w.Write(c.PaymentIdentifier[:]); err != nil {
return err return err
} }
@ -886,7 +887,7 @@ func deserializePaymentCreationInfo(r io.Reader) (*PaymentCreationInfo, error) {
c := &PaymentCreationInfo{} c := &PaymentCreationInfo{}
if _, err := io.ReadFull(r, c.PaymentHash[:]); err != nil { if _, err := io.ReadFull(r, c.PaymentIdentifier[:]); err != nil {
return nil, err return nil, err
} }

@ -60,8 +60,8 @@ func makeFakeInfo() (*PaymentCreationInfo, *HTLCAttemptInfo) {
hash := preimg.Hash() hash := preimg.Hash()
c := &PaymentCreationInfo{ c := &PaymentCreationInfo{
PaymentHash: hash, PaymentIdentifier: hash,
Value: 1000, Value: 1000,
// Use single second precision to avoid false positive test // Use single second precision to avoid false positive test
// failures due to the monotonic time component. // failures due to the monotonic time component.
CreationTime: time.Unix(time.Now().Unix(), 0), CreationTime: time.Unix(time.Now().Unix(), 0),
@ -433,7 +433,7 @@ func TestQueryPayments(t *testing.T) {
} }
// Create a new payment entry in the database. // Create a new payment entry in the database.
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatalf("unable to initialize "+ t.Fatalf("unable to initialize "+
"payment in database: %v", err) "payment in database: %v", err)
@ -442,11 +442,11 @@ func TestQueryPayments(t *testing.T) {
// Immediately delete the payment with index 2. // Immediately delete the payment with index 2.
if i == 1 { if i == 1 {
pmt, err := pControl.FetchPayment( pmt, err := pControl.FetchPayment(
info.PaymentHash, info.PaymentIdentifier,
) )
require.NoError(t, err) require.NoError(t, err)
deletePayment(t, db, info.PaymentHash, deletePayment(t, db, info.PaymentIdentifier,
pmt.SequenceNum) pmt.SequenceNum)
} }
@ -456,13 +456,13 @@ func TestQueryPayments(t *testing.T) {
// duplicate payments will always be succeeded. // duplicate payments will always be succeeded.
if i == (nonDuplicatePayments - 1) { if i == (nonDuplicatePayments - 1) {
pmt, err := pControl.FetchPayment( pmt, err := pControl.FetchPayment(
info.PaymentHash, info.PaymentIdentifier,
) )
require.NoError(t, err) require.NoError(t, err)
appendDuplicatePayment( appendDuplicatePayment(
t, pControl.db, t, pControl.db,
info.PaymentHash, info.PaymentIdentifier,
pmt.SequenceNum+1, pmt.SequenceNum+1,
preimg, preimg,
) )
@ -529,12 +529,12 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// Create a new payment entry in the database. // Create a new payment entry in the database.
err = pControl.InitPayment(noDuplicates.PaymentHash, noDuplicates) err = pControl.InitPayment(noDuplicates.PaymentIdentifier, noDuplicates)
require.NoError(t, err) require.NoError(t, err)
// Fetch the payment so we can get its sequence nr. // Fetch the payment so we can get its sequence nr.
noDuplicatesPayment, err := pControl.FetchPayment( noDuplicatesPayment, err := pControl.FetchPayment(
noDuplicates.PaymentHash, noDuplicates.PaymentIdentifier,
) )
require.NoError(t, err) require.NoError(t, err)
@ -543,12 +543,12 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// Create a new payment entry in the database. // Create a new payment entry in the database.
err = pControl.InitPayment(hasDuplicates.PaymentHash, hasDuplicates) err = pControl.InitPayment(hasDuplicates.PaymentIdentifier, hasDuplicates)
require.NoError(t, err) require.NoError(t, err)
// Fetch the payment so we can get its sequence nr. // Fetch the payment so we can get its sequence nr.
hasDuplicatesPayment, err := pControl.FetchPayment( hasDuplicatesPayment, err := pControl.FetchPayment(
hasDuplicates.PaymentHash, hasDuplicates.PaymentIdentifier,
) )
require.NoError(t, err) require.NoError(t, err)
@ -561,10 +561,10 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
// Add two duplicates to our second payment. // Add two duplicates to our second payment.
appendDuplicatePayment( appendDuplicatePayment(
t, db, hasDuplicates.PaymentHash, duplicateOneSeqNr, preimg, t, db, hasDuplicates.PaymentIdentifier, duplicateOneSeqNr, preimg,
) )
appendDuplicatePayment( appendDuplicatePayment(
t, db, hasDuplicates.PaymentHash, duplicateTwoSeqNr, preimg, t, db, hasDuplicates.PaymentIdentifier, duplicateTwoSeqNr, preimg,
) )
tests := []struct { tests := []struct {
@ -575,37 +575,37 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
}{ }{
{ {
name: "lookup payment without duplicates", name: "lookup payment without duplicates",
paymentHash: noDuplicates.PaymentHash, paymentHash: noDuplicates.PaymentIdentifier,
sequenceNumber: noDuplicatesPayment.SequenceNum, sequenceNumber: noDuplicatesPayment.SequenceNum,
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "lookup payment with duplicates", name: "lookup payment with duplicates",
paymentHash: hasDuplicates.PaymentHash, paymentHash: hasDuplicates.PaymentIdentifier,
sequenceNumber: hasDuplicatesPayment.SequenceNum, sequenceNumber: hasDuplicatesPayment.SequenceNum,
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "lookup first duplicate", name: "lookup first duplicate",
paymentHash: hasDuplicates.PaymentHash, paymentHash: hasDuplicates.PaymentIdentifier,
sequenceNumber: duplicateOneSeqNr, sequenceNumber: duplicateOneSeqNr,
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "lookup second duplicate", name: "lookup second duplicate",
paymentHash: hasDuplicates.PaymentHash, paymentHash: hasDuplicates.PaymentIdentifier,
sequenceNumber: duplicateTwoSeqNr, sequenceNumber: duplicateTwoSeqNr,
expectedErr: nil, expectedErr: nil,
}, },
{ {
name: "lookup non-existent duplicate", name: "lookup non-existent duplicate",
paymentHash: hasDuplicates.PaymentHash, paymentHash: hasDuplicates.PaymentIdentifier,
sequenceNumber: 999999, sequenceNumber: 999999,
expectedErr: ErrDuplicateNotFound, expectedErr: ErrDuplicateNotFound,
}, },
{ {
name: "lookup duplicate, no duplicates bucket", name: "lookup duplicate, no duplicates bucket",
paymentHash: noDuplicates.PaymentHash, paymentHash: noDuplicates.PaymentIdentifier,
sequenceNumber: duplicateTwoSeqNr, sequenceNumber: duplicateTwoSeqNr,
expectedErr: ErrNoDuplicateBucket, expectedErr: ErrNoDuplicateBucket,
}, },

@ -698,7 +698,11 @@ func (r *RouterBackend) extractIntentFromSendRequest(
payIntent.MaxParts = 1 payIntent.MaxParts = 1
} }
copy(payIntent.PaymentHash[:], payReq.PaymentHash[:]) err = payIntent.SetPaymentHash(*payReq.PaymentHash)
if err != nil {
return nil, err
}
destKey := payReq.Destination.SerializeCompressed() destKey := payReq.Destination.SerializeCompressed()
copy(payIntent.Target[:], destKey) copy(payIntent.Target[:], destKey)
@ -737,7 +741,15 @@ func (r *RouterBackend) extractIntentFromSendRequest(
payIntent.Amount = reqAmt payIntent.Amount = reqAmt
// Payment hash. // Payment hash.
copy(payIntent.PaymentHash[:], rpcPayReq.PaymentHash) paymentHash, err := lntypes.MakeHash(rpcPayReq.PaymentHash)
if err != nil {
return nil, err
}
err = payIntent.SetPaymentHash(paymentHash)
if err != nil {
return nil, err
}
// Parse destination feature bits. // Parse destination feature bits.
features, err := UnmarshalFeatures(rpcPayReq.DestFeatures) features, err := UnmarshalFeatures(rpcPayReq.DestFeatures)
@ -1217,7 +1229,7 @@ func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
htlcs = append(htlcs, htlc) htlcs = append(htlcs, htlc)
} }
paymentHash := payment.Info.PaymentHash paymentID := payment.Info.PaymentIdentifier
creationTimeNS := MarshalTimeNano(payment.Info.CreationTime) creationTimeNS := MarshalTimeNano(payment.Info.CreationTime)
failureReason, err := marshallPaymentFailureReason( failureReason, err := marshallPaymentFailureReason(
@ -1228,7 +1240,8 @@ func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
} }
return &lnrpc.Payment{ return &lnrpc.Payment{
PaymentHash: hex.EncodeToString(paymentHash[:]), // TODO: set this to setID for AMP-payments?
PaymentHash: hex.EncodeToString(paymentID[:]),
Value: satValue, Value: satValue,
ValueMsat: msatValue, ValueMsat: msatValue,
ValueSat: satValue, ValueSat: satValue,

@ -316,21 +316,21 @@ func (s *Server) SendPaymentV2(req *SendPaymentRequest,
if err == channeldb.ErrPaymentInFlight || if err == channeldb.ErrPaymentInFlight ||
err == channeldb.ErrAlreadyPaid { err == channeldb.ErrAlreadyPaid {
log.Debugf("SendPayment async result for hash %x: %v", log.Debugf("SendPayment async result for payment %x: %v",
payment.PaymentHash, err) payment.Identifier(), err)
return status.Error( return status.Error(
codes.AlreadyExists, err.Error(), codes.AlreadyExists, err.Error(),
) )
} }
log.Errorf("SendPayment async error for hash %x: %v", log.Errorf("SendPayment async error for payment %x: %v",
payment.PaymentHash, err) payment.Identifier(), err)
return err return err
} }
return s.trackPayment(payment.PaymentHash, stream, req.NoInflightUpdates) return s.trackPayment(payment.Identifier(), stream, req.NoInflightUpdates)
} }
// EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it // EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
@ -719,14 +719,14 @@ func (s *Server) TrackPaymentV2(request *TrackPaymentRequest,
} }
// trackPayment writes payment status updates to the provided stream. // trackPayment writes payment status updates to the provided stream.
func (s *Server) trackPayment(paymentHash lntypes.Hash, func (s *Server) trackPayment(identifier lntypes.Hash,
stream Router_TrackPaymentV2Server, noInflightUpdates bool) error { stream Router_TrackPaymentV2Server, noInflightUpdates bool) error {
router := s.cfg.RouterBackend router := s.cfg.RouterBackend
// Subscribe to the outcome of this payment. // Subscribe to the outcome of this payment.
subscription, err := router.Tower.SubscribePayment( subscription, err := router.Tower.SubscribePayment(
paymentHash, identifier,
) )
switch { switch {
case err == channeldb.ErrPaymentNotInitiated: case err == channeldb.ErrPaymentNotInitiated:
@ -769,7 +769,7 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
return errServerShuttingDown return errServerShuttingDown
case <-stream.Context().Done(): case <-stream.Context().Done():
log.Debugf("Payment status stream %v canceled", paymentHash) log.Debugf("Payment status stream %v canceled", identifier)
return stream.Context().Err() return stream.Context().Err()
} }
} }

@ -36,16 +36,16 @@
<time> [ERR] CRTR: Failed sending attempt <number> for payment <hex> to switch: insufficient bandwidth to route htlc <time> [ERR] CRTR: Failed sending attempt <number> for payment <hex> to switch: insufficient bandwidth to route htlc
<time> [ERR] CRTR: Failed sending attempt <number> for payment <hex> to switch: UnknownNextPeer <time> [ERR] CRTR: Failed sending attempt <number> for payment <hex> to switch: UnknownNextPeer
<time> [ERR] CRTR: out of order block: expecting height=<height>, got height=<height> <time> [ERR] CRTR: out of order block: expecting height=<height>, got height=<height>
<time> [ERR] CRTR: Payment with hash <hex> failed: error <time> [ERR] CRTR: Payment <hex> failed: error
<time> [ERR] CRTR: Payment with hash <hex> failed: incorrect_payment_details <time> [ERR] CRTR: Payment <hex> failed: incorrect_payment_details
<time> [ERR] CRTR: Payment with hash <hex> failed: insufficient_balance <time> [ERR] CRTR: Payment <hex> failed: insufficient_balance
<time> [ERR] CRTR: Payment with hash <hex> failed: no_route <time> [ERR] CRTR: Payment <hex> failed: no_route
<time> [ERR] CRTR: Payment with hash <hex> failed: router shutting down <time> [ERR] CRTR: Payment <hex> failed: router shutting down
<time> [ERR] CRTR: Payment with hash <hex> failed: timeout <time> [ERR] CRTR: Payment <hex> failed: timeout
<time> [ERR] CRTR: Resuming payment with hash <hex> failed: error. <time> [ERR] CRTR: Resuming payment <hex> failed: error.
<time> [ERR] CRTR: Resuming payment with hash <hex> failed: incorrect_payment_details. <time> [ERR] CRTR: Resuming payment <hex> failed: incorrect_payment_details.
<time> [ERR] CRTR: Resuming payment with hash <hex> failed: no_route. <time> [ERR] CRTR: Resuming payment <hex> failed: no_route.
<time> [ERR] CRTR: Resuming payment with hash <hex> failed: router shutting down. <time> [ERR] CRTR: Resuming payment <hex> failed: router shutting down.
<time> [ERR] CRTR: unable to add channel: edge not found <time> [ERR] CRTR: unable to add channel: edge not found
<time> [ERR] CRTR: Unable to retrieve channel by id: edge not found <time> [ERR] CRTR: Unable to retrieve channel by id: edge not found
<time> [ERR] DISC: channel announcement proof for short_chan_id=<cid> isn't valid: can't verify first bitcoin signature <time> [ERR] DISC: channel announcement proof for short_chan_id=<cid> isn't valid: can't verify first bitcoin signature

@ -79,26 +79,26 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Subscription should succeed and immediately report the InFlight // Subscription should succeed and immediately report the InFlight
// status. // status.
subscriber1, err := pControl.SubscribePayment(info.PaymentHash) subscriber1, err := pControl.SubscribePayment(info.PaymentIdentifier)
if err != nil { if err != nil {
t.Fatalf("expected subscribe to succeed, but got: %v", err) t.Fatalf("expected subscribe to succeed, but got: %v", err)
} }
// Register an attempt. // Register an attempt.
err = pControl.RegisterAttempt(info.PaymentHash, attempt) err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Register a second subscriber after the first attempt has started. // Register a second subscriber after the first attempt has started.
subscriber2, err := pControl.SubscribePayment(info.PaymentHash) subscriber2, err := pControl.SubscribePayment(info.PaymentIdentifier)
if err != nil { if err != nil {
t.Fatalf("expected subscribe to succeed, but got: %v", err) t.Fatalf("expected subscribe to succeed, but got: %v", err)
} }
@ -108,7 +108,7 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
Preimage: preimg, Preimage: preimg,
} }
htlcAttempt, err := pControl.SettleAttempt( htlcAttempt, err := pControl.SettleAttempt(
info.PaymentHash, attempt.AttemptID, &settleInfo, info.PaymentIdentifier, attempt.AttemptID, &settleInfo,
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -118,7 +118,7 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
} }
// Register a third subscriber after the payment succeeded. // Register a third subscriber after the payment succeeded.
subscriber3, err := pControl.SubscribePayment(info.PaymentHash) subscriber3, err := pControl.SubscribePayment(info.PaymentIdentifier)
if err != nil { if err != nil {
t.Fatalf("expected subscribe to succeed, but got: %v", err) t.Fatalf("expected subscribe to succeed, but got: %v", err)
} }
@ -196,13 +196,13 @@ func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
t.Fatal(err) t.Fatal(err)
} }
err = pControl.InitPayment(info.PaymentHash, info) err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Subscription should succeed. // Subscription should succeed.
subscriber1, err := pControl.SubscribePayment(info.PaymentHash) subscriber1, err := pControl.SubscribePayment(info.PaymentIdentifier)
if err != nil { if err != nil {
t.Fatalf("expected subscribe to succeed, but got: %v", err) t.Fatalf("expected subscribe to succeed, but got: %v", err)
} }
@ -212,7 +212,7 @@ func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
// making any attempts at all. // making any attempts at all.
if registerAttempt { if registerAttempt {
// Register an attempt. // Register an attempt.
err = pControl.RegisterAttempt(info.PaymentHash, attempt) err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -222,7 +222,7 @@ func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
Reason: channeldb.HTLCFailInternal, Reason: channeldb.HTLCFailInternal,
} }
htlcAttempt, err := pControl.FailAttempt( htlcAttempt, err := pControl.FailAttempt(
info.PaymentHash, attempt.AttemptID, &failInfo, info.PaymentIdentifier, attempt.AttemptID, &failInfo,
) )
if err != nil { if err != nil {
t.Fatalf("unable to fail htlc: %v", err) t.Fatalf("unable to fail htlc: %v", err)
@ -233,12 +233,12 @@ func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
} }
// Mark the payment as failed. // Mark the payment as failed.
if err := pControl.Fail(info.PaymentHash, channeldb.FailureReasonTimeout); err != nil { if err := pControl.Fail(info.PaymentIdentifier, channeldb.FailureReasonTimeout); err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Register a second subscriber after the payment failed. // Register a second subscriber after the payment failed.
subscriber2, err := pControl.SubscribePayment(info.PaymentHash) subscriber2, err := pControl.SubscribePayment(info.PaymentIdentifier)
if err != nil { if err != nil {
t.Fatalf("expected subscribe to succeed, but got: %v", err) t.Fatalf("expected subscribe to succeed, but got: %v", err)
} }
@ -326,10 +326,10 @@ func genInfo() (*channeldb.PaymentCreationInfo, *channeldb.HTLCAttemptInfo,
rhash := sha256.Sum256(preimage[:]) rhash := sha256.Sum256(preimage[:])
return &channeldb.PaymentCreationInfo{ return &channeldb.PaymentCreationInfo{
PaymentHash: rhash, PaymentIdentifier: rhash,
Value: testRoute.ReceiverAmt(), Value: testRoute.ReceiverAmt(),
CreationTime: time.Unix(time.Now().Unix(), 0), CreationTime: time.Unix(time.Now().Unix(), 0),
PaymentRequest: []byte("hola"), PaymentRequest: []byte("hola"),
}, },
&channeldb.HTLCAttemptInfo{ &channeldb.HTLCAttemptInfo{
AttemptID: 1, AttemptID: 1,

@ -152,6 +152,11 @@ func (c *integratedRoutingContext) testPayment(maxParts uint32,
MaxParts: maxParts, MaxParts: maxParts,
} }
var paymentHash [32]byte
if err := payment.SetPaymentHash(paymentHash); err != nil {
return nil, err
}
if c.maxShardAmt != nil { if c.maxShardAmt != nil {
payment.MaxShardAmt = c.maxShardAmt payment.MaxShardAmt = c.maxShardAmt
} }

@ -24,7 +24,7 @@ type paymentLifecycle struct {
router *ChannelRouter router *ChannelRouter
totalAmount lnwire.MilliSatoshi totalAmount lnwire.MilliSatoshi
feeLimit lnwire.MilliSatoshi feeLimit lnwire.MilliSatoshi
paymentHash lntypes.Hash identifier lntypes.Hash
paySession PaymentSession paySession PaymentSession
shardTracker shards.ShardTracker shardTracker shards.ShardTracker
timeoutChan <-chan time.Time timeoutChan <-chan time.Time
@ -86,7 +86,7 @@ func (p *paymentLifecycle) paymentState(payment *channeldb.MPPayment) (
func (p *paymentLifecycle) resumePayment() ([32]byte, *route.Route, error) { func (p *paymentLifecycle) resumePayment() ([32]byte, *route.Route, error) {
shardHandler := &shardHandler{ shardHandler := &shardHandler{
router: p.router, router: p.router,
paymentHash: p.paymentHash, identifier: p.identifier,
shardTracker: p.shardTracker, shardTracker: p.shardTracker,
shardErrors: make(chan error), shardErrors: make(chan error),
quit: make(chan struct{}), quit: make(chan struct{}),
@ -101,7 +101,7 @@ func (p *paymentLifecycle) resumePayment() ([32]byte, *route.Route, error) {
// up goroutines that'll collect their results and deliver them to the // up goroutines that'll collect their results and deliver them to the
// lifecycle loop below. // lifecycle loop below.
payment, err := p.router.cfg.Control.FetchPayment( payment, err := p.router.cfg.Control.FetchPayment(
p.paymentHash, p.identifier,
) )
if err != nil { if err != nil {
return [32]byte{}, nil, err return [32]byte{}, nil, err
@ -110,8 +110,8 @@ func (p *paymentLifecycle) resumePayment() ([32]byte, *route.Route, error) {
for _, a := range payment.InFlightHTLCs() { for _, a := range payment.InFlightHTLCs() {
a := a a := a
log.Infof("Resuming payment shard %v for hash %v", log.Infof("Resuming payment shard %v for payment %v",
a.AttemptID, p.paymentHash) a.AttemptID, p.identifier)
shardHandler.collectResultAsync(&a.HTLCAttemptInfo) shardHandler.collectResultAsync(&a.HTLCAttemptInfo)
} }
@ -131,7 +131,7 @@ lifecycle:
// act on the latest available information, whether we are // act on the latest available information, whether we are
// resuming an existing payment or just sent a new attempt. // resuming an existing payment or just sent a new attempt.
payment, err := p.router.cfg.Control.FetchPayment( payment, err := p.router.cfg.Control.FetchPayment(
p.paymentHash, p.identifier,
) )
if err != nil { if err != nil {
return [32]byte{}, nil, err return [32]byte{}, nil, err
@ -146,7 +146,7 @@ lifecycle:
log.Debugf("Payment %v in state terminate=%v, "+ log.Debugf("Payment %v in state terminate=%v, "+
"active_shards=%v, rem_value=%v, fee_limit=%v", "active_shards=%v, rem_value=%v, fee_limit=%v",
p.paymentHash, state.terminate, state.numShardsInFlight, p.identifier, state.terminate, state.numShardsInFlight,
state.remainingAmt, state.remainingFees) state.remainingAmt, state.remainingFees)
switch { switch {
@ -193,7 +193,7 @@ lifecycle:
// return with an error the moment all active shards // return with an error the moment all active shards
// have finished. // have finished.
saveErr := p.router.cfg.Control.Fail( saveErr := p.router.cfg.Control.Fail(
p.paymentHash, channeldb.FailureReasonTimeout, p.identifier, channeldb.FailureReasonTimeout,
) )
if saveErr != nil { if saveErr != nil {
return [32]byte{}, nil, saveErr return [32]byte{}, nil, saveErr
@ -215,7 +215,7 @@ lifecycle:
) )
if err != nil { if err != nil {
log.Warnf("Failed to find route for payment %v: %v", log.Warnf("Failed to find route for payment %v: %v",
p.paymentHash, err) p.identifier, err)
routeErr, ok := err.(noRouteError) routeErr, ok := err.(noRouteError)
if !ok { if !ok {
@ -229,10 +229,10 @@ lifecycle:
failureCode := routeErr.FailureReason() failureCode := routeErr.FailureReason()
log.Debugf("Marking payment %v permanently "+ log.Debugf("Marking payment %v permanently "+
"failed with no route: %v", "failed with no route: %v",
p.paymentHash, failureCode) p.identifier, failureCode)
saveErr := p.router.cfg.Control.Fail( saveErr := p.router.cfg.Control.Fail(
p.paymentHash, failureCode, p.identifier, failureCode,
) )
if saveErr != nil { if saveErr != nil {
return [32]byte{}, nil, saveErr return [32]byte{}, nil, saveErr
@ -261,8 +261,8 @@ lifecycle:
// were pathfinding. We know we're in a terminal state here, // were pathfinding. We know we're in a terminal state here,
// so we can continue and wait for our last shards to return. // so we can continue and wait for our last shards to return.
case err == channeldb.ErrPaymentTerminal: case err == channeldb.ErrPaymentTerminal:
log.Infof("Payment: %v in terminal state, abandoning "+ log.Infof("Payment %v in terminal state, abandoning "+
"shard", p.paymentHash) "shard", p.identifier)
continue lifecycle continue lifecycle
@ -275,7 +275,7 @@ lifecycle:
if outcome.err != nil { if outcome.err != nil {
log.Warnf("Failed to launch shard %v for "+ log.Warnf("Failed to launch shard %v for "+
"payment %v: %v", attempt.AttemptID, "payment %v: %v", attempt.AttemptID,
p.paymentHash, outcome.err) p.identifier, outcome.err)
// We must inspect the error to know whether it was // We must inspect the error to know whether it was
// critical or not, to decide whether we should // critical or not, to decide whether we should
@ -301,7 +301,7 @@ lifecycle:
// shardHandler holds what is necessary to send and collect the result of // shardHandler holds what is necessary to send and collect the result of
// shards. // shards.
type shardHandler struct { type shardHandler struct {
paymentHash lntypes.Hash identifier lntypes.Hash
router *ChannelRouter router *ChannelRouter
shardTracker shards.ShardTracker shardTracker shards.ShardTracker
@ -398,7 +398,7 @@ func (p *shardHandler) launchShard(rt *route.Route,
// of the payment that we attempted to send, such that we can query the // of the payment that we attempted to send, such that we can query the
// Switch for its whereabouts. The route is needed to handle the result // Switch for its whereabouts. The route is needed to handle the result
// when it eventually comes back. // when it eventually comes back.
err = p.router.cfg.Control.RegisterAttempt(p.paymentHash, attempt) err = p.router.cfg.Control.RegisterAttempt(p.identifier, attempt)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -450,7 +450,7 @@ func (p *shardHandler) collectResultAsync(attempt *channeldb.HTLCAttemptInfo) {
log.Errorf("Error collecting result for "+ log.Errorf("Error collecting result for "+
"shard %v for payment %v: %v", "shard %v for payment %v: %v",
attempt.AttemptID, p.paymentHash, err) attempt.AttemptID, p.identifier, err)
} }
select { select {
@ -515,7 +515,7 @@ func (p *shardHandler) collectResult(attempt *channeldb.HTLCAttemptInfo) (
// Now ask the switch to return the result of the payment when // Now ask the switch to return the result of the payment when
// available. // available.
resultChan, err := p.router.cfg.Payer.GetPaymentResult( resultChan, err := p.router.cfg.Payer.GetPaymentResult(
attempt.AttemptID, p.paymentHash, errorDecryptor, attempt.AttemptID, p.identifier, errorDecryptor,
) )
switch { switch {
@ -524,9 +524,9 @@ func (p *shardHandler) collectResult(attempt *channeldb.HTLCAttemptInfo) (
// case we can safely send a new payment attempt, and wait for its // case we can safely send a new payment attempt, and wait for its
// result to be available. // result to be available.
case err == htlcswitch.ErrPaymentIDNotFound: case err == htlcswitch.ErrPaymentIDNotFound:
log.Debugf("Payment ID %v for hash %v not found in "+ log.Debugf("Attempt ID %v for payment %v not found in "+
"the Switch, retrying.", attempt.AttemptID, "the Switch, retrying.", attempt.AttemptID,
p.paymentHash) p.identifier)
attempt, cErr := p.failAttempt(attempt, err) attempt, cErr := p.failAttempt(attempt, err)
if cErr != nil { if cErr != nil {
@ -582,7 +582,7 @@ func (p *shardHandler) collectResult(attempt *channeldb.HTLCAttemptInfo) (
// We successfully got a payment result back from the switch. // We successfully got a payment result back from the switch.
log.Debugf("Payment %v succeeded with pid=%v", log.Debugf("Payment %v succeeded with pid=%v",
p.paymentHash, attempt.AttemptID) p.identifier, attempt.AttemptID)
// Report success to mission control. // Report success to mission control.
err = p.router.cfg.MissionControl.ReportPaymentSuccess( err = p.router.cfg.MissionControl.ReportPaymentSuccess(
@ -596,7 +596,7 @@ func (p *shardHandler) collectResult(attempt *channeldb.HTLCAttemptInfo) (
// In case of success we atomically store settle result to the DB move // In case of success we atomically store settle result to the DB move
// the shard to the settled state. // the shard to the settled state.
htlcAttempt, err := p.router.cfg.Control.SettleAttempt( htlcAttempt, err := p.router.cfg.Control.SettleAttempt(
p.paymentHash, attempt.AttemptID, p.identifier, attempt.AttemptID,
&channeldb.HTLCSettleInfo{ &channeldb.HTLCSettleInfo{
Preimage: result.Preimage, Preimage: result.Preimage,
SettleTime: p.router.cfg.Clock.Now(), SettleTime: p.router.cfg.Clock.Now(),
@ -696,7 +696,7 @@ func (p *shardHandler) sendPaymentAttempt(
htlcAdd *lnwire.UpdateAddHTLC) error { htlcAdd *lnwire.UpdateAddHTLC) error {
log.Tracef("Attempting to send payment %v (pid=%v), "+ log.Tracef("Attempting to send payment %v (pid=%v), "+
"using route: %v", p.paymentHash, attempt.AttemptID, "using route: %v", p.identifier, attempt.AttemptID,
newLogClosure(func() string { newLogClosure(func() string {
return spew.Sdump(attempt.Route) return spew.Sdump(attempt.Route)
}), }),
@ -712,12 +712,12 @@ func (p *shardHandler) sendPaymentAttempt(
if err != nil { if err != nil {
log.Errorf("Failed sending attempt %d for payment "+ log.Errorf("Failed sending attempt %d for payment "+
"%v to switch: %v", attempt.AttemptID, "%v to switch: %v", attempt.AttemptID,
p.paymentHash, err) p.identifier, err)
return err return err
} }
log.Debugf("Payment %v (pid=%v) successfully sent to switch, route: %v", log.Debugf("Payment %v (pid=%v) successfully sent to switch, route: %v",
p.paymentHash, attempt.AttemptID, &attempt.Route) p.identifier, attempt.AttemptID, &attempt.Route)
return nil return nil
} }
@ -737,9 +737,9 @@ func (p *shardHandler) handleSendError(attempt *channeldb.HTLCAttemptInfo,
} }
log.Infof("Payment %v failed: final_outcome=%v, raw_err=%v", log.Infof("Payment %v failed: final_outcome=%v, raw_err=%v",
p.paymentHash, *reason, sendErr) p.identifier, *reason, sendErr)
err := p.router.cfg.Control.Fail(p.paymentHash, *reason) err := p.router.cfg.Control.Fail(p.identifier, *reason)
if err != nil { if err != nil {
return err return err
} }
@ -752,7 +752,7 @@ func (p *shardHandler) failAttempt(attempt *channeldb.HTLCAttemptInfo,
sendError error) (*channeldb.HTLCAttempt, error) { sendError error) (*channeldb.HTLCAttempt, error) {
log.Warnf("Attempt %v for payment %v failed: %v", attempt.AttemptID, log.Warnf("Attempt %v for payment %v failed: %v", attempt.AttemptID,
p.paymentHash, sendError) p.identifier, sendError)
failInfo := marshallError( failInfo := marshallError(
sendError, sendError,
@ -767,7 +767,7 @@ func (p *shardHandler) failAttempt(attempt *channeldb.HTLCAttemptInfo,
} }
return p.router.cfg.Control.FailAttempt( return p.router.cfg.Control.FailAttempt(
p.paymentHash, attempt.AttemptID, p.identifier, attempt.AttemptID,
failInfo, failInfo,
) )
} }

@ -815,7 +815,7 @@ func testPaymentLifecycle(t *testing.T, test paymentLifecycleTestCase,
Target: testGraph.aliasMap["c"], Target: testGraph.aliasMap["c"],
Amount: paymentAmt, Amount: paymentAmt,
FeeLimit: noFeeLimit, FeeLimit: noFeeLimit,
PaymentHash: payHash, paymentHash: &payHash,
} }
// Setup our payment session source to block on release of // Setup our payment session source to block on release of

@ -171,7 +171,7 @@ func newPaymentSession(p *LightningPayment,
return nil, err return nil, err
} }
logPrefix := fmt.Sprintf("PaymentSession(%x):", p.PaymentHash) logPrefix := fmt.Sprintf("PaymentSession(%x):", p.Identifier())
return &paymentSession{ return &paymentSession{
additionalEdges: edges, additionalEdges: edges,

@ -23,6 +23,11 @@ func TestRequestRoute(t *testing.T) {
FeeLimit: 1000, FeeLimit: 1000,
} }
var paymentHash [32]byte
if err := payment.SetPaymentHash(paymentHash); err != nil {
t.Fatal(err)
}
session, err := newPaymentSession( session, err := newPaymentSession(
payment, payment,
func() (map[uint64]lnwire.MilliSatoshi, func() (map[uint64]lnwire.MilliSatoshi,

@ -600,7 +600,7 @@ func (r *ChannelRouter) Start() error {
} }
for _, payment := range payments { for _, payment := range payments {
log.Infof("Resuming payment with hash %v", payment.Info.PaymentHash) log.Infof("Resuming payment %v", payment.Info.PaymentIdentifier)
r.wg.Add(1) r.wg.Add(1)
go func(payment *channeldb.MPPayment) { go func(payment *channeldb.MPPayment) {
defer r.wg.Done() defer r.wg.Done()
@ -613,7 +613,7 @@ func (r *ChannelRouter) Start() error {
// We check whether the individual attempts // We check whether the individual attempts
// have their HTLC hash set, if not we'll fall // have their HTLC hash set, if not we'll fall
// back to the overall payment hash. // back to the overall payment hash.
hash := payment.Info.PaymentHash hash := payment.Info.PaymentIdentifier
if a.Hash != nil { if a.Hash != nil {
hash = *a.Hash hash = *a.Hash
} }
@ -631,30 +631,32 @@ func (r *ChannelRouter) Start() error {
// we don't currently persist the root share necessary // we don't currently persist the root share necessary
// to re-derive them. // to re-derive them.
shardTracker := shards.NewSimpleShardTracker( shardTracker := shards.NewSimpleShardTracker(
payment.Info.PaymentHash, htlcs, payment.Info.PaymentIdentifier, htlcs,
) )
// We create a dummy, empty payment session such that // We create a dummy, empty payment session such that
// we won't make another payment attempt when the // we won't make another payment attempt when the
// result for the in-flight attempt is received. // result for the in-flight attempt is received.
paySession := r.cfg.SessionSource.NewPaymentSessionEmpty() paySession := r.cfg.SessionSource.NewPaymentSessionEmpty()
// We pass in a zero timeout value, to indicate we // We pass in a zero timeout value, to indicate we
// don't need it to timeout. It will stop immediately // don't need it to timeout. It will stop immediately
// after the existing attempt has finished anyway. We // after the existing attempt has finished anyway. We
// also set a zero fee limit, as no more routes should // also set a zero fee limit, as no more routes should
// be tried. // be tried.
_, _, err := r.sendPayment( _, _, err := r.sendPayment(
payment.Info.Value, 0, payment.Info.PaymentHash, payment.Info.Value, 0,
0, paySession, shardTracker, payment.Info.PaymentIdentifier, 0, paySession,
shardTracker,
) )
if err != nil { if err != nil {
log.Errorf("Resuming payment with hash %v "+ log.Errorf("Resuming payment %v failed: %v.",
"failed: %v.", payment.Info.PaymentHash, err) payment.Info.PaymentIdentifier, err)
return return
} }
log.Infof("Resumed payment with hash %v completed.", log.Infof("Resumed payment %v completed.",
payment.Info.PaymentHash) payment.Info.PaymentIdentifier)
}(payment) }(payment)
} }
@ -1719,9 +1721,9 @@ type LightningPayment struct {
// complete this payment. // complete this payment.
CltvLimit uint32 CltvLimit uint32
// PaymentHash is the r-hash value to use within the HTLC extended to // paymentHash is the r-hash value to use within the HTLC extended to
// the first hop. // the first hop. This won't be set for AMP payments.
PaymentHash [32]byte paymentHash *lntypes.Hash
// amp is an optional field that is set if and only if this is am AMP // amp is an optional field that is set if and only if this is am AMP
// payment. // payment.
@ -1801,6 +1803,20 @@ type AMPOptions struct {
RootShare [32]byte RootShare [32]byte
} }
// SetPaymentHash sets the given hash as the payment's overall hash. This
// should only be used for non-AMP payments.
func (l *LightningPayment) SetPaymentHash(hash lntypes.Hash) error {
l.paymentHash = &hash
return nil
}
// Identifier returns a 32-byte slice that uniquely identifies this single
// payment. For non-AMP payments this will be the payment hash, for AMP
// payments this will be the used SetID.
func (l *LightningPayment) Identifier() [32]byte {
return *l.paymentHash
}
// SendPayment attempts to send a payment as described within the passed // SendPayment attempts to send a payment as described within the passed
// LightningPayment. This function is blocking and will return either: when the // LightningPayment. This function is blocking and will return either: when the
// payment is successful, or all candidates routes have been attempted and // payment is successful, or all candidates routes have been attempted and
@ -1822,7 +1838,7 @@ func (r *ChannelRouter) SendPayment(payment *LightningPayment) ([32]byte,
// Since this is the first time this payment is being made, we pass nil // Since this is the first time this payment is being made, we pass nil
// for the existing attempt. // for the existing attempt.
return r.sendPayment( return r.sendPayment(
payment.Amount, payment.FeeLimit, payment.PaymentHash, payment.Amount, payment.FeeLimit, payment.Identifier(),
payment.PayAttemptTimeout, paySession, shardTracker, payment.PayAttemptTimeout, paySession, shardTracker,
) )
} }
@ -1845,12 +1861,12 @@ func (r *ChannelRouter) SendPaymentAsync(payment *LightningPayment) error {
spewPayment(payment)) spewPayment(payment))
_, _, err := r.sendPayment( _, _, err := r.sendPayment(
payment.Amount, payment.FeeLimit, payment.PaymentHash, payment.Amount, payment.FeeLimit, payment.Identifier(),
payment.PayAttemptTimeout, paySession, shardTracker, payment.PayAttemptTimeout, paySession, shardTracker,
) )
if err != nil { if err != nil {
log.Errorf("Payment with hash %x failed: %v", log.Errorf("Payment %x failed: %v",
payment.PaymentHash, err) payment.Identifier(), err)
} }
}() }()
@ -1897,10 +1913,10 @@ func (r *ChannelRouter) preparePayment(payment *LightningPayment) (
// //
// TODO(roasbeef): store records as part of creation info? // TODO(roasbeef): store records as part of creation info?
info := &channeldb.PaymentCreationInfo{ info := &channeldb.PaymentCreationInfo{
PaymentHash: payment.PaymentHash, PaymentIdentifier: payment.Identifier(),
Value: payment.Amount, Value: payment.Amount,
CreationTime: r.cfg.Clock.Now(), CreationTime: r.cfg.Clock.Now(),
PaymentRequest: payment.PaymentRequest, PaymentRequest: payment.PaymentRequest,
} }
// Create a new ShardTracker that we'll use during the life cycle of // Create a new ShardTracker that we'll use during the life cycle of
@ -1919,11 +1935,11 @@ func (r *ChannelRouter) preparePayment(payment *LightningPayment) (
// the same payment hash. // the same payment hash.
default: default:
shardTracker = shards.NewSimpleShardTracker( shardTracker = shards.NewSimpleShardTracker(
payment.PaymentHash, nil, payment.Identifier(), nil,
) )
} }
err = r.cfg.Control.InitPayment(payment.PaymentHash, info) err = r.cfg.Control.InitPayment(payment.Identifier(), info)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -1936,7 +1952,7 @@ func (r *ChannelRouter) preparePayment(payment *LightningPayment) (
// information as it is stored in the database. For a successful htlc, this // information as it is stored in the database. For a successful htlc, this
// information will contain the preimage. If an error occurs after the attempt // information will contain the preimage. If an error occurs after the attempt
// was initiated, both return values will be non-nil. // was initiated, both return values will be non-nil.
func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, rt *route.Route) ( func (r *ChannelRouter) SendToRoute(htlcHash lntypes.Hash, rt *route.Route) (
*channeldb.HTLCAttempt, error) { *channeldb.HTLCAttempt, error) {
// Calculate amount paid to receiver. // Calculate amount paid to receiver.
@ -1950,16 +1966,20 @@ func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, rt *route.Route) (
amt = mpp.TotalMsat() amt = mpp.TotalMsat()
} }
// For non-AMP payments the overall payment identifier will be the same
// hash as used for this HTLC.
paymentIdentifier := htlcHash
// Record this payment hash with the ControlTower, ensuring it is not // Record this payment hash with the ControlTower, ensuring it is not
// already in-flight. // already in-flight.
info := &channeldb.PaymentCreationInfo{ info := &channeldb.PaymentCreationInfo{
PaymentHash: hash, PaymentIdentifier: paymentIdentifier,
Value: amt, Value: amt,
CreationTime: r.cfg.Clock.Now(), CreationTime: r.cfg.Clock.Now(),
PaymentRequest: nil, PaymentRequest: nil,
} }
err := r.cfg.Control.InitPayment(hash, info) err := r.cfg.Control.InitPayment(paymentIdentifier, info)
switch { switch {
// If this is an MPP attempt and the hash is already registered with // If this is an MPP attempt and the hash is already registered with
// the database, we can go on to launch the shard. // the database, we can go on to launch the shard.
@ -1970,8 +1990,8 @@ func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, rt *route.Route) (
return nil, err return nil, err
} }
log.Tracef("Dispatching SendToRoute for hash %v: %v", log.Tracef("Dispatching SendToRoute for HTLC hash %v: %v",
hash, newLogClosure(func() string { htlcHash, newLogClosure(func() string {
return spew.Sdump(rt) return spew.Sdump(rt)
}), }),
) )
@ -1981,12 +2001,12 @@ func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, rt *route.Route) (
// a ShardTracker that can generate hashes for AMP payments. Instead we // a ShardTracker that can generate hashes for AMP payments. Instead we
// create a simple tracker that can just return the hash for the single // create a simple tracker that can just return the hash for the single
// shard we'll now launch. // shard we'll now launch.
shardTracker := shards.NewSimpleShardTracker(hash, nil) shardTracker := shards.NewSimpleShardTracker(htlcHash, nil)
// Launch a shard along the given route. // Launch a shard along the given route.
sh := &shardHandler{ sh := &shardHandler{
router: r, router: r,
paymentHash: hash, identifier: paymentIdentifier,
shardTracker: shardTracker, shardTracker: shardTracker,
} }
@ -1999,10 +2019,10 @@ func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, rt *route.Route) (
err == sphinx.ErrMaxRoutingInfoSizeExceeded { err == sphinx.ErrMaxRoutingInfoSizeExceeded {
log.Debugf("Invalid route provided for payment %x: %v", log.Debugf("Invalid route provided for payment %x: %v",
hash, err) paymentIdentifier, err)
controlErr := r.cfg.Control.Fail( controlErr := r.cfg.Control.Fail(
hash, channeldb.FailureReasonError, paymentIdentifier, channeldb.FailureReasonError,
) )
if controlErr != nil { if controlErr != nil {
return nil, controlErr return nil, controlErr
@ -2050,7 +2070,7 @@ func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, rt *route.Route) (
reason = &r reason = &r
} }
err = r.cfg.Control.Fail(hash, *reason) err = r.cfg.Control.Fail(paymentIdentifier, *reason)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -2075,7 +2095,7 @@ func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, rt *route.Route) (
// router will call this method for every payment still in-flight according to // router will call this method for every payment still in-flight according to
// the ControlTower. // the ControlTower.
func (r *ChannelRouter) sendPayment( func (r *ChannelRouter) sendPayment(
totalAmt, feeLimit lnwire.MilliSatoshi, paymentHash lntypes.Hash, totalAmt, feeLimit lnwire.MilliSatoshi, identifier lntypes.Hash,
timeout time.Duration, paySession PaymentSession, timeout time.Duration, paySession PaymentSession,
shardTracker shards.ShardTracker) ([32]byte, *route.Route, error) { shardTracker shards.ShardTracker) ([32]byte, *route.Route, error) {
@ -2092,7 +2112,7 @@ func (r *ChannelRouter) sendPayment(
router: r, router: r,
totalAmount: totalAmt, totalAmount: totalAmt,
feeLimit: feeLimit, feeLimit: feeLimit,
paymentHash: paymentHash, identifier: identifier,
paySession: paySession, paySession: paySession,
shardTracker: shardTracker, shardTracker: shardTracker,
currentHeight: currentHeight, currentHeight: currentHeight,

@ -275,13 +275,13 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) {
// Craft a LightningPayment struct that'll send a payment from roasbeef // Craft a LightningPayment struct that'll send a payment from roasbeef
// to luo ji for 1000 satoshis, with a maximum of 1000 satoshis in fees. // to luo ji for 1000 satoshis, with a maximum of 1000 satoshis in fees.
var payHash [32]byte var payHash lntypes.Hash
paymentAmt := lnwire.NewMSatFromSatoshis(1000) paymentAmt := lnwire.NewMSatFromSatoshis(1000)
payment := LightningPayment{ payment := LightningPayment{
Target: ctx.aliases["sophon"], Target: ctx.aliases["sophon"],
Amount: paymentAmt, Amount: paymentAmt,
FeeLimit: noFeeLimit, FeeLimit: noFeeLimit,
PaymentHash: payHash, paymentHash: &payHash,
} }
var preImage [32]byte var preImage [32]byte
@ -510,13 +510,13 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) {
// Craft a LightningPayment struct that'll send a payment from roasbeef // Craft a LightningPayment struct that'll send a payment from roasbeef
// to luo ji for 100 satoshis. // to luo ji for 100 satoshis.
var payHash [32]byte var payHash lntypes.Hash
amt := lnwire.NewMSatFromSatoshis(1000) amt := lnwire.NewMSatFromSatoshis(1000)
payment := LightningPayment{ payment := LightningPayment{
Target: ctx.aliases["sophon"], Target: ctx.aliases["sophon"],
Amount: amt, Amount: amt,
FeeLimit: noFeeLimit, FeeLimit: noFeeLimit,
PaymentHash: payHash, paymentHash: &payHash,
} }
var preImage [32]byte var preImage [32]byte
@ -611,13 +611,13 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
// Craft a LightningPayment struct that'll send a payment from roasbeef // Craft a LightningPayment struct that'll send a payment from roasbeef
// to sophon for 1k satoshis. // to sophon for 1k satoshis.
var payHash [32]byte var payHash lntypes.Hash
amt := lnwire.NewMSatFromSatoshis(1000) amt := lnwire.NewMSatFromSatoshis(1000)
payment := LightningPayment{ payment := LightningPayment{
Target: ctx.aliases["sophon"], Target: ctx.aliases["sophon"],
Amount: amt, Amount: amt,
FeeLimit: noFeeLimit, FeeLimit: noFeeLimit,
PaymentHash: payHash, paymentHash: &payHash,
} }
var preImage [32]byte var preImage [32]byte
@ -720,7 +720,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
// Once again, Roasbeef should route around Goku since they disagree // Once again, Roasbeef should route around Goku since they disagree
// w.r.t to the block height, and instead go through Pham Nuwen. We // w.r.t to the block height, and instead go through Pham Nuwen. We
// flip a bit in the payment hash to allow resending this payment. // flip a bit in the payment hash to allow resending this payment.
payment.PaymentHash[1] ^= 1 payment.paymentHash[1] ^= 1
paymentPreImage, rt, err = ctx.router.SendPayment(&payment) paymentPreImage, rt, err = ctx.router.SendPayment(&payment)
if err != nil { if err != nil {
t.Fatalf("unable to send payment: %v", err) t.Fatalf("unable to send payment: %v", err)
@ -744,13 +744,13 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
// Craft a LightningPayment struct that'll send a payment from roasbeef // Craft a LightningPayment struct that'll send a payment from roasbeef
// to luo ji for 1000 satoshis, with a maximum of 1000 satoshis in fees. // to luo ji for 1000 satoshis, with a maximum of 1000 satoshis in fees.
var payHash [32]byte var payHash lntypes.Hash
paymentAmt := lnwire.NewMSatFromSatoshis(1000) paymentAmt := lnwire.NewMSatFromSatoshis(1000)
payment := LightningPayment{ payment := LightningPayment{
Target: ctx.aliases["sophon"], Target: ctx.aliases["sophon"],
Amount: paymentAmt, Amount: paymentAmt,
FeeLimit: noFeeLimit, FeeLimit: noFeeLimit,
PaymentHash: payHash, paymentHash: &payHash,
} }
var preImage [32]byte var preImage [32]byte
@ -887,7 +887,7 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
}) })
// We flip a bit in the payment hash to allow resending this payment. // We flip a bit in the payment hash to allow resending this payment.
payment.PaymentHash[1] ^= 1 payment.paymentHash[1] ^= 1
paymentPreImage, rt, err = ctx.router.SendPayment(&payment) paymentPreImage, rt, err = ctx.router.SendPayment(&payment)
if err != nil { if err != nil {
t.Fatalf("unable to send payment: %v", err) t.Fatalf("unable to send payment: %v", err)
@ -2565,11 +2565,12 @@ func TestUnknownErrorSource(t *testing.T) {
} }
// Create a payment to node c. // Create a payment to node c.
var payHash lntypes.Hash
payment := LightningPayment{ payment := LightningPayment{
Target: ctx.aliases["c"], Target: ctx.aliases["c"],
Amount: lnwire.NewMSatFromSatoshis(1000), Amount: lnwire.NewMSatFromSatoshis(1000),
FeeLimit: noFeeLimit, FeeLimit: noFeeLimit,
PaymentHash: lntypes.Hash{}, paymentHash: &payHash,
} }
// We'll modify the SendToSwitch method so that it simulates hop b as a // We'll modify the SendToSwitch method so that it simulates hop b as a
@ -2616,7 +2617,8 @@ func TestUnknownErrorSource(t *testing.T) {
// Send off the payment request to the router. We expect the payment to // Send off the payment request to the router. We expect the payment to
// fail because both routes have been pruned. // fail because both routes have been pruned.
payment.PaymentHash = lntypes.Hash{1} payHash = lntypes.Hash{1}
payment.paymentHash = &payHash
_, _, err = ctx.router.SendPayment(&payment) _, _, err = ctx.router.SendPayment(&payment)
if err == nil { if err == nil {
t.Fatalf("expected payment to fail") t.Fatalf("expected payment to fail")

@ -4419,7 +4419,6 @@ func (r *rpcServer) dispatchPaymentIntent(
FinalCLTVDelta: payIntent.cltvDelta, FinalCLTVDelta: payIntent.cltvDelta,
FeeLimit: payIntent.feeLimit, FeeLimit: payIntent.feeLimit,
CltvLimit: payIntent.cltvLimit, CltvLimit: payIntent.cltvLimit,
PaymentHash: payIntent.rHash,
RouteHints: payIntent.routeHints, RouteHints: payIntent.routeHints,
OutgoingChannelIDs: payIntent.outgoingChannelIDs, OutgoingChannelIDs: payIntent.outgoingChannelIDs,
LastHop: payIntent.lastHop, LastHop: payIntent.lastHop,
@ -4433,6 +4432,10 @@ func (r *rpcServer) dispatchPaymentIntent(
// Users need to use routerrpc for that. // Users need to use routerrpc for that.
MaxParts: 1, MaxParts: 1,
} }
err := payment.SetPaymentHash(payIntent.rHash)
if err != nil {
return nil, err
}
preImage, route, routerErr = r.server.chanRouter.SendPayment( preImage, route, routerErr = r.server.chanRouter.SendPayment(
payment, payment,