diff --git a/lnd_test.go b/lnd_test.go index 43b567e8..7cba968a 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -14,6 +14,9 @@ import ( "sync/atomic" + "encoding/hex" + "reflect" + "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/lnrpc" @@ -24,8 +27,6 @@ import ( "github.com/roasbeef/btcutil" "golang.org/x/net/context" "google.golang.org/grpc" - "reflect" - "encoding/hex" ) // harnessTest wraps a regular testing.T providing enhanced error detection @@ -495,21 +496,18 @@ func testSingleHopInvoice(net *networkHarness, t *harnessTest) { func testListPayments(net *networkHarness, t *harnessTest) { ctxb := context.Background() - timeout := time.Duration(time.Second * 2) + timeout := time.Duration(time.Second * 5) - // Delete all payments from Alice. DB should have no payments - deleteAllPaymentsInitialReq := &lnrpc.DeleteAllPaymentsRequest{} - deleteAllPaymentsInitialCtxt, _ := context.WithTimeout(ctxb, timeout) - _, err := net.Alice.DeleteAllPayments(deleteAllPaymentsInitialCtxt, - deleteAllPaymentsInitialReq) - if err != nil { - t.Fatalf("Can't delete payments at the begining: %v", err) + // First start by deleting all payments that Alice knows of. This will + // allow us to execute the test with a clean state for Alice. + delPaymentsReq := &lnrpc.DeleteAllPaymentsRequest{} + if _, err := net.Alice.DeleteAllPayments(ctxb, delPaymentsReq); err != nil { + t.Fatalf("unable to delete payments: %v", err) } // Check that there are no payments before test. reqInit := &lnrpc.ListPaymentsRequest{} - reqInitCtxt, _ := context.WithTimeout(ctxb, timeout) - paymentsRespInit, err := net.Alice.ListPayments(reqInitCtxt, reqInit) + paymentsRespInit, err := net.Alice.ListPayments(ctxb, reqInit) if err != nil { t.Fatalf("error when obtaining Alice payments: %v", err) } @@ -518,18 +516,16 @@ func testListPayments(net *networkHarness, t *harnessTest) { len(paymentsRespInit.Payments), 0) } - // Open a channel with 100k satoshis - // between Alice and Bob with Alice being - // the sole funder of the channel. - + // Open a channel with 100k satoshis between Alice and Bob with Alice + // being the sole funder of the channel. chanAmt := btcutil.Amount(100000) - openChannelCtxt, _ := context.WithTimeout(ctxb, timeout) - chanPoint := openChannelAndAssert(t, net, openChannelCtxt, - net.Alice, net.Bob, chanAmt) + ctxt, _ := context.WithTimeout(ctxb, timeout) + chanPoint := openChannelAndAssert(t, net, ctxt, net.Alice, net.Bob, + chanAmt) // Now that the channel is open, create an invoice for Bob which - // expects a payment of 1000 satoshis from Alice - // paid via a particular pre-image. + // expects a payment of 1000 satoshis from Alice paid via a particular + // pre-image. const paymentAmt = 1000 preimage := bytes.Repeat([]byte("B"), 32) invoice := &lnrpc.Invoice{ @@ -545,8 +541,7 @@ func testListPayments(net *networkHarness, t *harnessTest) { // With the invoice for Bob added, send a payment towards Alice paying // to the above generated invoice. - sendPaymentCtxt, _ := context.WithTimeout(ctxb, timeout) - sendStream, err := net.Alice.SendPayment(sendPaymentCtxt) + sendStream, err := net.Alice.SendPayment(ctxb) if err != nil { t.Fatalf("unable to create alice payment stream: %v", err) } @@ -562,12 +557,10 @@ func testListPayments(net *networkHarness, t *harnessTest) { t.Fatalf("error when attempting recv: %v", err) } - // We doesn't check different states of parties - // like balance here because it is already checked in - // testSingleHopInvoice + // Grab Alice's list of payments, she should show the existence of + // exactly one payment. req := &lnrpc.ListPaymentsRequest{} - listPaymentsCtxt, _ := context.WithTimeout(ctxb, timeout) - paymentsResp, err := net.Alice.ListPayments(listPaymentsCtxt, req) + paymentsResp, err := net.Alice.ListPayments(ctxb, req) if err != nil { t.Fatalf("error when obtaining Alice payments: %v", err) } @@ -577,9 +570,9 @@ func testListPayments(net *networkHarness, t *harnessTest) { } p := paymentsResp.Payments[0] - // Check path. + // Ensure that the stored path shows a direct payment to Bob with no + // other nodes in-between. expectedPath := []string{ - net.Alice.PubKeyStr, net.Bob.PubKeyStr, } if !reflect.DeepEqual(p.Path, expectedPath) { @@ -587,52 +580,47 @@ func testListPayments(net *networkHarness, t *harnessTest) { p.Path, expectedPath) } - // Check amount. + // The payment amount should also match our previous payment directly. if p.Value != paymentAmt { t.Fatalf("incorrect amount, got %v, want %v", p.Value, paymentAmt) } - // Check RHash. + // The payment hash (or r-hash) should have been stored correctly. correctRHash := hex.EncodeToString(invoiceResp.RHash) - if !reflect.DeepEqual(p.RHash, correctRHash) { + if !reflect.DeepEqual(p.PaymentHash, correctRHash) { t.Fatalf("incorrect RHash, got %v, want %v", - p.RHash, correctRHash) + p.PaymentHash, correctRHash) } - // Check Fee. - // Currently there is no fees so assume value 0 for fees. + // Finally, as we made a single-hop direct payment, there should have + // been no fee applied. if p.Fee != 0 { t.Fatalf("incorrect Fee, got %v, want %v", p.Fee, 0) } // Delete all payments from Alice. DB should have no payments. - deleteAllPaymentsEndReq := &lnrpc.DeleteAllPaymentsRequest{} - deleteAllPaymentsEndCtxt, _ := context.WithTimeout(ctxb, timeout) - _, err = net.Alice.DeleteAllPayments(deleteAllPaymentsEndCtxt, - deleteAllPaymentsEndReq) + delReq := &lnrpc.DeleteAllPaymentsRequest{} + _, err = net.Alice.DeleteAllPayments(ctxb, delReq) if err != nil { t.Fatalf("Can't delete payments at the end: %v", err) } // Check that there are no payments before test. - reqEnd := &lnrpc.ListPaymentsRequest{} - listPaymentsEndCtxt, _ := context.WithTimeout(ctxb, timeout) - _, err = net.Alice.ListPayments(listPaymentsEndCtxt, reqEnd) + listReq := &lnrpc.ListPaymentsRequest{} + paymentsResp, err = net.Alice.ListPayments(ctxb, listReq) if err != nil { t.Fatalf("error when obtaining Alice payments: %v", err) } - if len(paymentsRespInit.Payments) != 0 { + if len(paymentsResp.Payments) != 0 { t.Fatalf("incorrect number of payments, got %v, want %v", len(paymentsRespInit.Payments), 0) } - closeChannelCtxt, _ := context.WithTimeout(ctxb, timeout) - closeChannelAndAssert(t, net, closeChannelCtxt, - net.Alice, chanPoint, false) + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(t, net, ctxt, net.Alice, chanPoint, false) } - func testMultiHopPayments(net *networkHarness, t *harnessTest) { const chanAmt = btcutil.Amount(100000) ctxb := context.Background() @@ -1071,11 +1059,11 @@ func testMaxPendingChannels(net *networkHarness, t *harnessTest) { chanPoints[i] = fundingChanPoint } - // Finally close the channel between Alice and Carol, asserting that the - // channel has been properly closed on-chain. + // Finally close the channel between Alice and Carol, asserting that + // the channel has been properly closed on-chain. for _, chanPoint := range chanPoints { - ctx, _ = context.WithTimeout(context.Background(), timeout) - closeChannelAndAssert(t, net, ctx, net.Alice, chanPoint, false) + ctxt, _ := context.WithTimeout(context.Background(), timeout) + closeChannelAndAssert(t, net, ctxt, net.Alice, chanPoint, false) } } diff --git a/routing/router.go b/routing/router.go index 93cbc1fe..d9c65b88 100644 --- a/routing/router.go +++ b/routing/router.go @@ -535,7 +535,7 @@ func (r *ChannelRouter) processNetworkAnnouncement(msg lnwire.Message) bool { } // As edges are directional edge node has a unique policy for - // the direction of th edge they control. Therefore we first + // the direction of the edge they control. Therefore we first // check if we already have the most up to date information for // that edge. If so, then we can exit early. updateTimestamp := time.Unix(int64(msg.Timestamp), 0) diff --git a/rpcserver.go b/rpcserver.go index e820b90d..97958142 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -610,26 +610,31 @@ func (r *rpcServer) ListChannels(ctx context.Context, return resp, nil } -func constructPayment(route *routing.Route, amount btcutil.Amount, - rHash []byte) *channeldb.OutgoingPayment { +// savePayment saves a successfully completed payment to the database for +// historical record keeping. +func (r *rpcServer) savePayment(route *routing.Route, amount btcutil.Amount, + rHash []byte) error { - payment := &channeldb.OutgoingPayment{} - - // When we create payment we do not know preImage. - // So we need to save rHash - copy(payment.RHash[:], rHash) - - payment.Invoice.Terms.Value = btcutil.Amount(amount) - payment.Invoice.CreationDate = time.Now() - payment.Timestamp = time.Now() - - pathBytes33 := make([][33]byte, len(route.Hops)) + paymentPath := make([][33]byte, len(route.Hops)) for i, hop := range route.Hops { hopPub := hop.Channel.Node.PubKey.SerializeCompressed() - copy(pathBytes33[i][:], hopPub) + copy(paymentPath[i][:], hopPub) } - payment.Path = pathBytes33 - return payment + + payment := &channeldb.OutgoingPayment{ + Invoice: channeldb.Invoice{ + Terms: channeldb.ContractTerm{ + Value: btcutil.Amount(amount), + }, + CreationDate: time.Now(), + }, + Path: paymentPath, + Fee: route.TotalFees, + TimeLockLength: route.TotalTimeLock, + } + copy(payment.PaymentHash[:], rHash) + + return r.server.chanDB.AddPayment(payment) } // SendPayment dispatches a bi-directional streaming RPC for sending payments @@ -719,8 +724,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer) // Save the completed payment to the database // for record keeping purposes. - payment := constructPayment(route, amt, rHash[:]) - if err := r.server.chanDB.AddPayment(payment); err != nil { + if err := r.savePayment(route, amt, rHash[:]); err != nil { errChan <- err return } @@ -779,14 +783,15 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context, return nil, err } - // Finally, send this next packet to the routing layer in order to + // Next, send this next packet to the routing layer in order to // complete the next payment. if err := r.server.htlcSwitch.SendHTLC(htlcPkt); err != nil { return nil, err } - payment := constructPayment(route, amt, rHash[:]) - if err := r.server.chanDB.AddPayment(payment); err != nil { + // With the payment completed successfully, we now ave the details of + // the completed payment to the databse for historical record keeping. + if err := r.savePayment(route, amt, rHash[:]); err != nil { return nil, err } @@ -1448,17 +1453,18 @@ func (r *rpcServer) ListPayments(context.Context, paymentsResp := &lnrpc.ListPaymentsResponse{ Payments: make([]*lnrpc.Payment, len(payments)), } - for i := 0; i < len(payments); i++ { - p := &lnrpc.Payment{} - p.CreationDate = payments[i].CreationDate.Unix() - p.Value = int64(payments[i].Terms.Value) - p.RHash = hex.EncodeToString(payments[i].RHash[:]) - path := make([]string, len(payments[i].Path)) - for j := 0; j < len(path); j++ { - path[j] = hex.EncodeToString(payments[i].Path[j][:]) + for i, payment := range payments { + path := make([]string, len(payment.Path)) + for i, hop := range payment.Path { + path[i] = hex.EncodeToString(hop[:]) + } + + paymentsResp.Payments[i] = &lnrpc.Payment{ + PaymentHash: hex.EncodeToString(payment.PaymentHash[:]), + Value: int64(payment.Terms.Value), + CreationDate: payment.CreationDate.Unix(), + Path: path, } - p.Path = path - paymentsResp.Payments[i] = p } return paymentsResp, nil @@ -1470,9 +1476,11 @@ func (r *rpcServer) DeleteAllPayments(context.Context, rpcsLog.Debugf("[DeleteAllPayments]") - err := r.server.chanDB.DeleteAllPayments() - resp := &lnrpc.DeleteAllPaymentsResponse{} - return resp, err + if err := r.server.chanDB.DeleteAllPayments(); err != nil { + return nil, err + } + + return &lnrpc.DeleteAllPaymentsResponse{}, nil } // SetAlias...