Skip to content

Commit 9ffd05a

Browse files
committed
accounts: start writing to the new request ID scoped cache
For all payment request handlers, start using the new ReqIDToPaymentHash store to store some state (just payment hash for now).
1 parent 18c819b commit 9ffd05a

File tree

2 files changed

+91
-20
lines changed

2 files changed

+91
-20
lines changed

accounts/checkers.go

Lines changed: 83 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ var (
6363
ListPeersEmptyRewriter = mid.NewResponseEmptier[
6464
*lnrpc.ListPeersRequest, *lnrpc.ListPeersResponse,
6565
]()
66+
67+
emptyHash lntypes.Hash
6668
)
6769

6870
// CheckerMap is a type alias that maps gRPC request URIs to their
@@ -181,7 +183,8 @@ func NewAccountChecker(service Service,
181183
func(ctx context.Context, r *lnrpc.SendRequest) error {
182184
return checkSend(
183185
ctx, chainParams, service, r.Amt,
184-
r.AmtMsat, r.PaymentRequest, r.FeeLimit,
186+
r.AmtMsat, r.PaymentRequest,
187+
r.PaymentHash, r.FeeLimit,
185188
)
186189
}, sendResponseHandler, mid.PassThroughErrorHandler,
187190
),
@@ -191,7 +194,8 @@ func NewAccountChecker(service Service,
191194
func(ctx context.Context, r *lnrpc.SendRequest) error {
192195
return checkSend(
193196
ctx, chainParams, service, r.Amt,
194-
r.AmtMsat, r.PaymentRequest, r.FeeLimit,
197+
r.AmtMsat, r.PaymentRequest,
198+
r.PaymentHash, r.FeeLimit,
195199
)
196200
}, sendResponseHandler, mid.PassThroughErrorHandler,
197201
),
@@ -210,6 +214,7 @@ func NewAccountChecker(service Service,
210214
return checkSend(
211215
ctx, chainParams, service, r.Amt,
212216
r.AmtMsat, r.PaymentRequest,
217+
r.PaymentHash,
213218
&lnrpc.FeeLimit{
214219
Limit: &lnrpc.FeeLimit_FixedMsat{
215220
FixedMsat: feeLimitMsat,
@@ -240,7 +245,9 @@ func NewAccountChecker(service Service,
240245
func(ctx context.Context,
241246
r *lnrpc.SendToRouteRequest) error {
242247

243-
return checkSendToRoute(ctx, service, r.Route)
248+
return checkSendToRoute(
249+
ctx, service, r.PaymentHash, r.Route,
250+
)
244251
}, sendResponseHandler, mid.PassThroughErrorHandler,
245252
),
246253
"/lnrpc.Lightning/SendToRouteSync": mid.NewFullChecker(
@@ -249,7 +256,9 @@ func NewAccountChecker(service Service,
249256
func(ctx context.Context,
250257
r *lnrpc.SendToRouteRequest) error {
251258

252-
return checkSendToRoute(ctx, service, r.Route)
259+
return checkSendToRoute(
260+
ctx, service, r.PaymentHash, r.Route,
261+
)
253262
}, sendResponseHandler, mid.PassThroughErrorHandler,
254263
),
255264
// routerrpc.Router/SendToRoute is deprecated.
@@ -259,7 +268,9 @@ func NewAccountChecker(service Service,
259268
func(ctx context.Context,
260269
r *routerrpc.SendToRouteRequest) error {
261270

262-
return checkSendToRoute(ctx, service, r.Route)
271+
return checkSendToRoute(
272+
ctx, service, r.PaymentHash, r.Route,
273+
)
263274
},
264275
// We don't get the payment hash in the response to this
265276
// call. So we can't optimize things and need to rely on
@@ -509,20 +520,29 @@ func filterPayments(ctx context.Context,
509520
// the context has enough balance to pay for it.
510521
func checkSend(ctx context.Context, chainParams *chaincfg.Params,
511522
service Service, amt, amtMsat int64, invoice string,
512-
feeLimit *lnrpc.FeeLimit) error {
523+
paymentHash []byte, feeLimit *lnrpc.FeeLimit) error {
513524

514525
acct, err := AccountFromContext(ctx)
515526
if err != nil {
516527
return err
517528
}
518529

530+
reqID, err := RequestIDFromContext(ctx)
531+
if err != nil {
532+
return err
533+
}
534+
519535
sendAmt := lnwire.NewMSatFromSatoshis(btcutil.Amount(amt))
520536
if lnwire.MilliSatoshi(amtMsat) > sendAmt {
521537
sendAmt = lnwire.MilliSatoshi(amtMsat)
522538
}
523539

524-
// The invoice is optional.
525-
var paymentHash lntypes.Hash
540+
// We require that a payment hash is set, which we either read from the
541+
// payment hash from the invoice or from the request.
542+
var pHash lntypes.Hash
543+
544+
// Check if an invoice was provided. If so, glean the payment hash from
545+
// that.
526546
if len(invoice) > 0 {
527547
payReq, err := zpay32.Decode(invoice, chainParams)
528548
if err != nil {
@@ -534,10 +554,36 @@ func checkSend(ctx context.Context, chainParams *chaincfg.Params,
534554
}
535555

536556
if payReq.PaymentHash != nil {
537-
paymentHash = *payReq.PaymentHash
557+
pHash = *payReq.PaymentHash
538558
}
539559
}
540560

561+
// If a payment hash was separately provided in the request, then glean
562+
// derive the hash from there. If the invoice was set then the two
563+
// payment hashes must match.
564+
if len(paymentHash) != 0 {
565+
hash, err := lntypes.MakeHash(paymentHash)
566+
if err != nil {
567+
return err
568+
}
569+
570+
if pHash != emptyHash && hash != pHash {
571+
return fmt.Errorf("two conflicting hashes provided")
572+
}
573+
574+
pHash = hash
575+
}
576+
577+
// If at this point we still have no payment hash, then we error out
578+
// for now.
579+
// TODO(elle): support key sends by:
580+
// 1) allowing the user to set a pre-image
581+
// 2) deriving a pre-image here.
582+
// Then glean the payment hash from that.
583+
if pHash == emptyHash {
584+
return fmt.Errorf("a payment hash is required")
585+
}
586+
541587
// We also add the max fee to the amount to check. This might mean that
542588
// not every single satoshi of an account can be used up. But it
543589
// prevents an account from going into a negative balance if we only
@@ -554,15 +600,15 @@ func checkSend(ctx context.Context, chainParams *chaincfg.Params,
554600
return fmt.Errorf("error validating account balance: %w", err)
555601
}
556602

557-
emptyHash := lntypes.Hash{}
558-
if paymentHash != emptyHash {
559-
err = service.AssociatePayment(acct.ID, paymentHash, sendAmt)
560-
if err != nil {
561-
return fmt.Errorf("error associating payment: %w", err)
562-
}
603+
err = service.AssociatePayment(acct.ID, pHash, sendAmt)
604+
if err != nil {
605+
return fmt.Errorf("error associating payment: %w", err)
563606
}
564607

565-
return nil
608+
return service.RegisterValues(reqID, &RequestValues{
609+
PaymentHash: pHash,
610+
PaymentAmount: sendAmt,
611+
})
566612
}
567613

568614
// checkSendResponse makes sure that a payment that is in flight is tracked
@@ -593,14 +639,24 @@ func checkSendResponse(ctx context.Context, service Service,
593639

594640
// checkSendToRoute checks if a payment can be sent to the route by making sure
595641
// the account in the context has enough balance to pay for it.
596-
func checkSendToRoute(ctx context.Context, service Service,
642+
func checkSendToRoute(ctx context.Context, service Service, paymentHash []byte,
597643
route *lnrpc.Route) error {
598644

599645
acct, err := AccountFromContext(ctx)
600646
if err != nil {
601647
return err
602648
}
603649

650+
hash, err := lntypes.MakeHash(paymentHash)
651+
if err != nil {
652+
return err
653+
}
654+
655+
reqID, err := RequestIDFromContext(ctx)
656+
if err != nil {
657+
return err
658+
}
659+
604660
if route == nil {
605661
return fmt.Errorf("invalid route")
606662
}
@@ -625,5 +681,14 @@ func checkSendToRoute(ctx context.Context, service Service,
625681
return fmt.Errorf("error validating account balance: %w", err)
626682
}
627683

628-
return nil
684+
err = service.AssociatePayment(acct.ID, hash, sendAmt)
685+
if err != nil {
686+
return fmt.Errorf("error associating payment with hash %s: %w",
687+
hash, err)
688+
}
689+
690+
return service.RegisterValues(reqID, &RequestValues{
691+
PaymentHash: hash,
692+
PaymentAmount: sendAmt,
693+
})
629694
}

accounts/checkers_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ var (
2525
}
2626

2727
testID = AccountID{77, 88, 99}
28-
testHash = lntypes.Hash{1, 2, 3, 4, 5}
28+
testHash = lntypes.Hash{
29+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
30+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
31+
}
2932

3033
testAmount = &lnrpc.Amount{
3134
Sat: 456,
@@ -207,7 +210,8 @@ func TestAccountCheckers(t *testing.T) {
207210
name: "send payment, not enough balance",
208211
fullURI: "/lnrpc.Lightning/SendPaymentSync",
209212
originalRequest: &lnrpc.SendRequest{
210-
AmtMsat: 5000,
213+
AmtMsat: 5000,
214+
PaymentHash: testHash[:],
211215
},
212216
requestErr: "error validating account balance: invalid balance",
213217
}, {
@@ -223,6 +227,7 @@ func TestAccountCheckers(t *testing.T) {
223227
Percent: 1,
224228
},
225229
},
230+
PaymentHash: testHash[:],
226231
},
227232
requestErr: "error validating account balance: invalid balance",
228233
}, {
@@ -238,6 +243,7 @@ func TestAccountCheckers(t *testing.T) {
238243
FixedMsat: 123,
239244
},
240245
},
246+
PaymentHash: testHash[:],
241247
},
242248
originalResponse: &lnrpc.SendResponse{
243249
PaymentHash: testHash[:],

0 commit comments

Comments
 (0)