channeldb+routing: expose HTLCs in payment subscriptions
This commit modifies the FetchPayment method to return MPPayment structs converted from the legacy on-disk format. This allows us to attach the HTLCs to the events given to clients subscribing to the outcome of an HTLC. This commit also bubbles up to the routerrpc/router_server, by populating HTLCAttempts in the response and extracting the legacy route field from the HTLCAttempts.
This commit is contained in:
parent
68916eb4b7
commit
063f24f2ed
@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/coreos/bbolt"
|
"github.com/coreos/bbolt"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -192,16 +191,17 @@ func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
// duplicate payments to the same payment hash. The provided preimage is
|
// duplicate payments to the same payment hash. The provided preimage is
|
||||||
// atomically saved to the DB for record keeping.
|
// atomically saved to the DB for record keeping.
|
||||||
func (p *PaymentControl) Success(paymentHash lntypes.Hash,
|
func (p *PaymentControl) Success(paymentHash lntypes.Hash,
|
||||||
preimage lntypes.Preimage) (*route.Route, error) {
|
preimage lntypes.Preimage) (*MPPayment, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
updateErr error
|
updateErr error
|
||||||
route *route.Route
|
payment *MPPayment
|
||||||
)
|
)
|
||||||
err := p.db.Batch(func(tx *bbolt.Tx) error {
|
err := p.db.Batch(func(tx *bbolt.Tx) error {
|
||||||
// Reset the update error, to avoid carrying over an error
|
// Reset the update error, to avoid carrying over an error
|
||||||
// from a previous execution of the batched db transaction.
|
// from a previous execution of the batched db transaction.
|
||||||
updateErr = nil
|
updateErr = nil
|
||||||
|
payment = nil
|
||||||
|
|
||||||
bucket, err := fetchPaymentBucket(tx, paymentHash)
|
bucket, err := fetchPaymentBucket(tx, paymentHash)
|
||||||
if err == ErrPaymentNotInitiated {
|
if err == ErrPaymentNotInitiated {
|
||||||
@ -225,20 +225,14 @@ func (p *PaymentControl) Success(paymentHash lntypes.Hash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve attempt info for the notification.
|
// Retrieve attempt info for the notification.
|
||||||
attempt, err := fetchPaymentAttempt(bucket)
|
payment, err = fetchPayment(bucket)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
route = &attempt.Route
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return route, updateErr
|
return payment, updateErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail transitions a payment into the Failed state, and records the reason the
|
// Fail transitions a payment into the Failed state, and records the reason the
|
||||||
@ -246,16 +240,17 @@ func (p *PaymentControl) Success(paymentHash lntypes.Hash,
|
|||||||
// its next call for this payment hash, allowing the switch to make a
|
// its next call for this payment hash, allowing the switch to make a
|
||||||
// subsequent payment.
|
// subsequent payment.
|
||||||
func (p *PaymentControl) Fail(paymentHash lntypes.Hash,
|
func (p *PaymentControl) Fail(paymentHash lntypes.Hash,
|
||||||
reason FailureReason) (*route.Route, error) {
|
reason FailureReason) (*MPPayment, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
updateErr error
|
updateErr error
|
||||||
route *route.Route
|
payment *MPPayment
|
||||||
)
|
)
|
||||||
err := p.db.Batch(func(tx *bbolt.Tx) error {
|
err := p.db.Batch(func(tx *bbolt.Tx) error {
|
||||||
// Reset the update error, to avoid carrying over an error
|
// Reset the update error, to avoid carrying over an error
|
||||||
// from a previous execution of the batched db transaction.
|
// from a previous execution of the batched db transaction.
|
||||||
updateErr = nil
|
updateErr = nil
|
||||||
|
payment = nil
|
||||||
|
|
||||||
bucket, err := fetchPaymentBucket(tx, paymentHash)
|
bucket, err := fetchPaymentBucket(tx, paymentHash)
|
||||||
if err == ErrPaymentNotInitiated {
|
if err == ErrPaymentNotInitiated {
|
||||||
@ -279,28 +274,21 @@ func (p *PaymentControl) Fail(paymentHash lntypes.Hash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve attempt info for the notification, if available.
|
// Retrieve attempt info for the notification, if available.
|
||||||
attempt, err := fetchPaymentAttempt(bucket)
|
payment, err = fetchPayment(bucket)
|
||||||
if err != nil && err != errNoAttemptInfo {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err != errNoAttemptInfo {
|
|
||||||
route = &attempt.Route
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return route, updateErr
|
return payment, updateErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchPayment returns information about a payment from the database.
|
// FetchPayment returns information about a payment from the database.
|
||||||
func (p *PaymentControl) FetchPayment(paymentHash lntypes.Hash) (
|
func (p *PaymentControl) FetchPayment(paymentHash lntypes.Hash) (
|
||||||
*Payment, error) {
|
*MPPayment, error) {
|
||||||
|
|
||||||
var payment *Payment
|
var payment *MPPayment
|
||||||
err := p.db.View(func(tx *bbolt.Tx) error {
|
err := p.db.View(func(tx *bbolt.Tx) error {
|
||||||
bucket, err := fetchPaymentBucket(tx, paymentHash)
|
bucket, err := fetchPaymentBucket(tx, paymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/coreos/bbolt"
|
"github.com/coreos/bbolt"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func initDB() (*DB, error) {
|
func initDB() (*DB, error) {
|
||||||
@ -132,16 +131,22 @@ func TestPaymentControlSwitchFail(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Verifies that status was changed to StatusSucceeded.
|
// Verifies that status was changed to StatusSucceeded.
|
||||||
var route *route.Route
|
var payment *MPPayment
|
||||||
route, err = pControl.Success(info.PaymentHash, preimg)
|
payment, err = pControl.Success(info.PaymentHash, preimg)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = assertRouteEqual(route, &attempt.Route)
|
if len(payment.HTLCs) != 1 {
|
||||||
|
t.Fatalf("payment should have one htlc, got: %d",
|
||||||
|
len(payment.HTLCs))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = assertRouteEqual(&payment.HTLCs[0].Route, &attempt.Route)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected route returned: %v vs %v: %v",
|
t.Fatalf("unexpected route returned: %v vs %v: %v",
|
||||||
spew.Sdump(attempt.Route), spew.Sdump(*route), err)
|
spew.Sdump(attempt.Route),
|
||||||
|
spew.Sdump(payment.HTLCs[0].Route), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assertPaymentStatus(t, db, info.PaymentHash, StatusSucceeded)
|
assertPaymentStatus(t, db, info.PaymentHash, StatusSucceeded)
|
||||||
|
@ -337,7 +337,7 @@ func (db *DB) FetchPayments() ([]*MPPayment, error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
payments = append(payments, p.ToMPPayment())
|
payments = append(payments, p)
|
||||||
|
|
||||||
// For older versions of lnd, duplicate payments to a
|
// For older versions of lnd, duplicate payments to a
|
||||||
// payment has was possible. These will be found in a
|
// payment has was possible. These will be found in a
|
||||||
@ -362,7 +362,7 @@ func (db *DB) FetchPayments() ([]*MPPayment, error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
payments = append(payments, p.ToMPPayment())
|
payments = append(payments, p)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -379,7 +379,7 @@ func (db *DB) FetchPayments() ([]*MPPayment, error) {
|
|||||||
return payments, nil
|
return payments, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchPayment(bucket *bbolt.Bucket) (*Payment, error) {
|
func fetchPayment(bucket *bbolt.Bucket) (*MPPayment, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
p = &Payment{}
|
p = &Payment{}
|
||||||
@ -434,7 +434,7 @@ func fetchPayment(bucket *bbolt.Bucket) (*Payment, error) {
|
|||||||
p.Failure = &reason
|
p.Failure = &reason
|
||||||
}
|
}
|
||||||
|
|
||||||
return p, nil
|
return p.ToMPPayment(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePayments deletes all completed and failed payments from the DB.
|
// DeletePayments deletes all completed and failed payments from the DB.
|
||||||
|
@ -584,19 +584,12 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
|
|||||||
case result := <-resultChan:
|
case result := <-resultChan:
|
||||||
// Marshall result to rpc type.
|
// Marshall result to rpc type.
|
||||||
var status PaymentStatus
|
var status PaymentStatus
|
||||||
|
|
||||||
if result.Success {
|
if result.Success {
|
||||||
log.Debugf("Payment %v successfully completed",
|
log.Debugf("Payment %v successfully completed",
|
||||||
paymentHash)
|
paymentHash)
|
||||||
|
|
||||||
status.State = PaymentState_SUCCEEDED
|
status.State = PaymentState_SUCCEEDED
|
||||||
status.Preimage = result.Preimage[:]
|
status.Preimage = result.Preimage[:]
|
||||||
status.Route, err = router.MarshallRoute(
|
|
||||||
result.Route,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
state, err := marshallFailureReason(
|
state, err := marshallFailureReason(
|
||||||
result.FailureReason,
|
result.FailureReason,
|
||||||
@ -605,15 +598,49 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
status.State = state
|
status.State = state
|
||||||
if result.Route != nil {
|
}
|
||||||
status.Route, err = router.MarshallRoute(
|
|
||||||
result.Route,
|
// Extract the last route from the given list of HTLCs. This
|
||||||
)
|
// will populate the legacy route field for backwards
|
||||||
if err != nil {
|
// compatibility.
|
||||||
return err
|
//
|
||||||
}
|
// NOTE: For now there will be at most one HTLC, this code
|
||||||
|
// should be revisted or the field removed when multiple HTLCs
|
||||||
|
// are permitted.
|
||||||
|
var legacyRoute *route.Route
|
||||||
|
for _, htlc := range result.HTLCs {
|
||||||
|
switch {
|
||||||
|
case htlc.Settle != nil:
|
||||||
|
legacyRoute = &htlc.Route
|
||||||
|
|
||||||
|
// Only display the route for failed payments if we got
|
||||||
|
// an incorrect payment details error, so that it can be
|
||||||
|
// used for probing or fee estimation.
|
||||||
|
case htlc.Failure != nil && result.FailureReason ==
|
||||||
|
channeldb.FailureReasonPaymentDetails:
|
||||||
|
|
||||||
|
legacyRoute = &htlc.Route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if legacyRoute != nil {
|
||||||
|
status.Route, err = router.MarshallRoute(legacyRoute)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal our list of HTLCs that have been tried for this
|
||||||
|
// payment.
|
||||||
|
htlcs := make([]*lnrpc.HTLCAttempt, 0, len(result.HTLCs))
|
||||||
|
for _, dbHtlc := range result.HTLCs {
|
||||||
|
htlc, err := router.MarshalHTLCAttempt(dbHtlc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
htlcs = append(htlcs, htlc)
|
||||||
|
}
|
||||||
|
status.Htlcs = htlcs
|
||||||
|
|
||||||
// Send event to the client.
|
// Send event to the client.
|
||||||
err = stream.Send(&status)
|
err = stream.Send(&status)
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ControlTower tracks all outgoing payments made, whose primary purpose is to
|
// ControlTower tracks all outgoing payments made, whose primary purpose is to
|
||||||
@ -52,10 +51,6 @@ type PaymentResult struct {
|
|||||||
// Success indicates whether the payment was successful.
|
// Success indicates whether the payment was successful.
|
||||||
Success bool
|
Success bool
|
||||||
|
|
||||||
// Route is the (last) route attempted to send the HTLC. It is only set
|
|
||||||
// for successful payments.
|
|
||||||
Route *route.Route
|
|
||||||
|
|
||||||
// Preimage is the preimage of a successful payment. This serves as a
|
// Preimage is the preimage of a successful payment. This serves as a
|
||||||
// proof of payment. It is only set for successful payments.
|
// proof of payment. It is only set for successful payments.
|
||||||
Preimage lntypes.Preimage
|
Preimage lntypes.Preimage
|
||||||
@ -63,6 +58,10 @@ type PaymentResult struct {
|
|||||||
// FailureReason is a failure reason code indicating the reason the
|
// FailureReason is a failure reason code indicating the reason the
|
||||||
// payment failed. It is only set for failed payments.
|
// payment failed. It is only set for failed payments.
|
||||||
FailureReason channeldb.FailureReason
|
FailureReason channeldb.FailureReason
|
||||||
|
|
||||||
|
// HTLCs is a list of HTLCs that have been attempted in order to settle
|
||||||
|
// the payment.
|
||||||
|
HTLCs []channeldb.HTLCAttempt
|
||||||
}
|
}
|
||||||
|
|
||||||
// controlTower is persistent implementation of ControlTower to restrict
|
// controlTower is persistent implementation of ControlTower to restrict
|
||||||
@ -107,46 +106,46 @@ func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
func (p *controlTower) Success(paymentHash lntypes.Hash,
|
func (p *controlTower) Success(paymentHash lntypes.Hash,
|
||||||
preimage lntypes.Preimage) error {
|
preimage lntypes.Preimage) error {
|
||||||
|
|
||||||
route, err := p.db.Success(paymentHash, preimage)
|
payment, err := p.db.Success(paymentHash, preimage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify subscribers of success event.
|
// Notify subscribers of success event.
|
||||||
p.notifyFinalEvent(
|
p.notifyFinalEvent(
|
||||||
paymentHash, createSuccessResult(route, preimage),
|
paymentHash, createSuccessResult(payment.HTLCs),
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createSuccessResult creates a success result to send to subscribers.
|
// createSuccessResult creates a success result to send to subscribers.
|
||||||
func createSuccessResult(rt *route.Route,
|
func createSuccessResult(htlcs []channeldb.HTLCAttempt) *PaymentResult {
|
||||||
preimage lntypes.Preimage) *PaymentResult {
|
// Extract any preimage from the list of HTLCs.
|
||||||
|
var preimage lntypes.Preimage
|
||||||
|
for _, htlc := range htlcs {
|
||||||
|
if htlc.Settle != nil {
|
||||||
|
preimage = htlc.Settle.Preimage
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &PaymentResult{
|
return &PaymentResult{
|
||||||
Success: true,
|
Success: true,
|
||||||
Preimage: preimage,
|
Preimage: preimage,
|
||||||
Route: rt,
|
HTLCs: htlcs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// createFailResult creates a failed result to send to subscribers.
|
// createFailResult creates a failed result to send to subscribers.
|
||||||
func createFailedResult(rt *route.Route,
|
func createFailedResult(htlcs []channeldb.HTLCAttempt,
|
||||||
reason channeldb.FailureReason) *PaymentResult {
|
reason channeldb.FailureReason) *PaymentResult {
|
||||||
|
|
||||||
result := &PaymentResult{
|
return &PaymentResult{
|
||||||
Success: false,
|
Success: false,
|
||||||
FailureReason: reason,
|
FailureReason: reason,
|
||||||
|
HTLCs: htlcs,
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case of incorrect payment details, set the route. This can be used
|
|
||||||
// for probing and to extract a fee estimate from the route.
|
|
||||||
if reason == channeldb.FailureReasonPaymentDetails {
|
|
||||||
result.Route = rt
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail transitions a payment into the Failed state, and records the reason the
|
// Fail transitions a payment into the Failed state, and records the reason the
|
||||||
@ -156,14 +155,16 @@ func createFailedResult(rt *route.Route,
|
|||||||
func (p *controlTower) Fail(paymentHash lntypes.Hash,
|
func (p *controlTower) Fail(paymentHash lntypes.Hash,
|
||||||
reason channeldb.FailureReason) error {
|
reason channeldb.FailureReason) error {
|
||||||
|
|
||||||
route, err := p.db.Fail(paymentHash, reason)
|
payment, err := p.db.Fail(paymentHash, reason)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify subscribers of fail event.
|
// Notify subscribers of fail event.
|
||||||
p.notifyFinalEvent(
|
p.notifyFinalEvent(
|
||||||
paymentHash, createFailedResult(route, reason),
|
paymentHash, createFailedResult(
|
||||||
|
payment.HTLCs, reason,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -213,20 +214,14 @@ func (p *controlTower) SubscribePayment(paymentHash lntypes.Hash) (
|
|||||||
// a subscriber, because we can send the result on the channel
|
// a subscriber, because we can send the result on the channel
|
||||||
// immediately.
|
// immediately.
|
||||||
case channeldb.StatusSucceeded:
|
case channeldb.StatusSucceeded:
|
||||||
event = *createSuccessResult(
|
event = *createSuccessResult(payment.HTLCs)
|
||||||
&payment.Attempt.Route, *payment.Preimage,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Payment already failed. It is not necessary to register as a
|
// Payment already failed. It is not necessary to register as a
|
||||||
// subscriber, because we can send the result on the channel
|
// subscriber, because we can send the result on the channel
|
||||||
// immediately.
|
// immediately.
|
||||||
case channeldb.StatusFailed:
|
case channeldb.StatusFailed:
|
||||||
var route *route.Route
|
|
||||||
if payment.Attempt != nil {
|
|
||||||
route = &payment.Attempt.Route
|
|
||||||
}
|
|
||||||
event = *createFailedResult(
|
event = *createFailedResult(
|
||||||
route, *payment.Failure,
|
payment.HTLCs, *payment.FailureReason,
|
||||||
)
|
)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -144,10 +144,13 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||||||
if result.Preimage != preimg {
|
if result.Preimage != preimg {
|
||||||
t.Fatal("unexpected preimage")
|
t.Fatal("unexpected preimage")
|
||||||
}
|
}
|
||||||
|
if len(result.HTLCs) != 1 {
|
||||||
if !reflect.DeepEqual(result.Route, &attempt.Route) {
|
t.Fatalf("expected one htlc, got %d", len(result.HTLCs))
|
||||||
t.Fatalf("unexpected route: %v vs %v",
|
}
|
||||||
spew.Sdump(result.Route),
|
htlc := result.HTLCs[0]
|
||||||
|
if !reflect.DeepEqual(htlc.Route, attempt.Route) {
|
||||||
|
t.Fatalf("unexpected htlc route: %v vs %v",
|
||||||
|
spew.Sdump(htlc.Route),
|
||||||
spew.Sdump(attempt.Route))
|
spew.Sdump(attempt.Route))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +171,15 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||||||
func TestPaymentControlSubscribeFail(t *testing.T) {
|
func TestPaymentControlSubscribeFail(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("register attempt", func(t *testing.T) {
|
||||||
|
testPaymentControlSubscribeFail(t, true)
|
||||||
|
})
|
||||||
|
t.Run("no register attempt", func(t *testing.T) {
|
||||||
|
testPaymentControlSubscribeFail(t, false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
|
||||||
db, err := initDB()
|
db, err := initDB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to init db: %v", err)
|
t.Fatalf("unable to init db: %v", err)
|
||||||
@ -176,7 +188,7 @@ func TestPaymentControlSubscribeFail(t *testing.T) {
|
|||||||
pControl := NewControlTower(channeldb.NewPaymentControl(db))
|
pControl := NewControlTower(channeldb.NewPaymentControl(db))
|
||||||
|
|
||||||
// Initiate a payment.
|
// Initiate a payment.
|
||||||
info, _, _, err := genInfo()
|
info, attempt, _, err := genInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -192,6 +204,17 @@ func TestPaymentControlSubscribeFail(t *testing.T) {
|
|||||||
t.Fatalf("expected subscribe to succeed, but got: %v", err)
|
t.Fatalf("expected subscribe to succeed, but got: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Conditionally register the attempt based on the test type. This
|
||||||
|
// allows us to simulate failing after attempting with an htlc or before
|
||||||
|
// making any attempts at all.
|
||||||
|
if registerAttempt {
|
||||||
|
// Register an attempt.
|
||||||
|
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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.PaymentHash, channeldb.FailureReasonTimeout); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -223,9 +246,28 @@ func TestPaymentControlSubscribeFail(t *testing.T) {
|
|||||||
if result.Success {
|
if result.Success {
|
||||||
t.Fatal("unexpected payment state")
|
t.Fatal("unexpected payment state")
|
||||||
}
|
}
|
||||||
if result.Route != nil {
|
|
||||||
t.Fatal("expected no route")
|
// There will either be one or zero htlcs depending on whether
|
||||||
|
// or not the attempt was registered. Assert the correct number
|
||||||
|
// is present, and the route taken if the attempt was
|
||||||
|
// registered.
|
||||||
|
if registerAttempt {
|
||||||
|
if len(result.HTLCs) != 1 {
|
||||||
|
t.Fatalf("expected 1 htlc, got: %d",
|
||||||
|
len(result.HTLCs))
|
||||||
|
}
|
||||||
|
|
||||||
|
htlc := result.HTLCs[0]
|
||||||
|
if !reflect.DeepEqual(htlc.Route, testRoute) {
|
||||||
|
t.Fatalf("unexpected htlc route: %v vs %v",
|
||||||
|
spew.Sdump(htlc.Route),
|
||||||
|
spew.Sdump(testRoute))
|
||||||
|
}
|
||||||
|
} else if len(result.HTLCs) != 0 {
|
||||||
|
t.Fatalf("expected 0 htlcs, got: %d",
|
||||||
|
len(result.HTLCs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.FailureReason != channeldb.FailureReasonTimeout {
|
if result.FailureReason != channeldb.FailureReasonTimeout {
|
||||||
t.Fatal("unexpected failure reason")
|
t.Fatal("unexpected failure reason")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user