From 922130c80e9d5e77a829fa5e3de85a6bcd3ba464 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 14 Nov 2023 17:46:20 +0800 Subject: [PATCH 1/6] routerrpc: skip initiated payment in `trackPaymentStream` --- lnrpc/routerrpc/router_server.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lnrpc/routerrpc/router_server.go b/lnrpc/routerrpc/router_server.go index 2d48e675bb..595eb1ea0a 100644 --- a/lnrpc/routerrpc/router_server.go +++ b/lnrpc/routerrpc/router_server.go @@ -941,10 +941,13 @@ func (s *Server) trackPaymentStream(context context.Context, result := item.(*channeldb.MPPayment) // Skip in-flight updates unless requested. - if noInflightUpdates && - result.Status == channeldb.StatusInFlight { - - continue + if noInflightUpdates { + if result.Status == channeldb.StatusInitiated { + continue + } + if result.Status == channeldb.StatusInFlight { + continue + } } rpcPayment, err := s.cfg.RouterBackend.MarshallPayment( From c58454effe8ec05ccad4e1791f8a2246a6843648 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 14 Nov 2023 20:26:13 +0800 Subject: [PATCH 2/6] routerrpc: modify field orders based on their assigned number This commit is a pure refactoring which sorts the fields in `SendPaymentRequest` so it's easier to see what number to use when adding a new field. --- lnrpc/routerrpc/router.pb.go | 198 ++++++++++++++-------------- lnrpc/routerrpc/router.proto | 68 +++++----- lnrpc/routerrpc/router.swagger.json | 58 ++++---- 3 files changed, 162 insertions(+), 162 deletions(-) diff --git a/lnrpc/routerrpc/router.pb.go b/lnrpc/routerrpc/router.pb.go index 2e0875df9a..f56414cf44 100644 --- a/lnrpc/routerrpc/router.pb.go +++ b/lnrpc/routerrpc/router.pb.go @@ -407,17 +407,11 @@ type SendPaymentRequest struct { // // The fields amt and amt_msat are mutually exclusive. Amt int64 `protobuf:"varint,2,opt,name=amt,proto3" json:"amt,omitempty"` - // Number of millisatoshis to send. - // - // The fields amt and amt_msat are mutually exclusive. - AmtMsat int64 `protobuf:"varint,12,opt,name=amt_msat,json=amtMsat,proto3" json:"amt_msat,omitempty"` // The hash to use within the payment's HTLC PaymentHash []byte `protobuf:"bytes,3,opt,name=payment_hash,json=paymentHash,proto3" json:"payment_hash,omitempty"` // The CLTV delta from the current height that should be used to set the // timelock for the final hop. FinalCltvDelta int32 `protobuf:"varint,4,opt,name=final_cltv_delta,json=finalCltvDelta,proto3" json:"final_cltv_delta,omitempty"` - // An optional payment addr to be included within the last hop of the route. - PaymentAddr []byte `protobuf:"bytes,20,opt,name=payment_addr,json=paymentAddr,proto3" json:"payment_addr,omitempty"` // A bare-bones invoice for a payment within the Lightning Network. With the // details of the invoice, the sender has all the data necessary to send a // payment to the recipient. The amount in the payment request may be zero. In @@ -436,27 +430,14 @@ type SendPaymentRequest struct { // // The fields fee_limit_sat and fee_limit_msat are mutually exclusive. FeeLimitSat int64 `protobuf:"varint,7,opt,name=fee_limit_sat,json=feeLimitSat,proto3" json:"fee_limit_sat,omitempty"` - // The maximum number of millisatoshis that will be paid as a fee of the - // payment. If this field is left to the default value of 0, only zero-fee - // routes will be considered. This usually means single hop routes connecting - // directly to the destination. To send the payment without a fee limit, use - // max int here. - // - // The fields fee_limit_sat and fee_limit_msat are mutually exclusive. - FeeLimitMsat int64 `protobuf:"varint,13,opt,name=fee_limit_msat,json=feeLimitMsat,proto3" json:"fee_limit_msat,omitempty"` // Deprecated, use outgoing_chan_ids. The channel id of the channel that must // be taken to the first hop. If zero, any channel may be used (unless // outgoing_chan_ids are set). // // Deprecated: Marked as deprecated in routerrpc/router.proto. OutgoingChanId uint64 `protobuf:"varint,8,opt,name=outgoing_chan_id,json=outgoingChanId,proto3" json:"outgoing_chan_id,omitempty"` - // The channel ids of the channels are allowed for the first hop. If empty, - // any channel may be used. - OutgoingChanIds []uint64 `protobuf:"varint,19,rep,packed,name=outgoing_chan_ids,json=outgoingChanIds,proto3" json:"outgoing_chan_ids,omitempty"` - // The pubkey of the last hop of the route. If empty, any hop may be used. - LastHopPubkey []byte `protobuf:"bytes,14,opt,name=last_hop_pubkey,json=lastHopPubkey,proto3" json:"last_hop_pubkey,omitempty"` - // An optional maximum total time lock for the route. This should not exceed - // lnd's `--max-cltv-expiry` setting. If zero, then the value of + // An optional maximum total time lock for the route. This should not + // exceed lnd's `--max-cltv-expiry` setting. If zero, then the value of // `--max-cltv-expiry` is enforced. CltvLimit int32 `protobuf:"varint,9,opt,name=cltv_limit,json=cltvLimit,proto3" json:"cltv_limit,omitempty"` // Optional route hints to reach the destination through private channels. @@ -467,6 +448,20 @@ type SendPaymentRequest struct { // required to be in the custom range >= 65536. When using REST, the values // must be encoded as base64. DestCustomRecords map[uint64][]byte `protobuf:"bytes,11,rep,name=dest_custom_records,json=destCustomRecords,proto3" json:"dest_custom_records,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Number of millisatoshis to send. + // + // The fields amt and amt_msat are mutually exclusive. + AmtMsat int64 `protobuf:"varint,12,opt,name=amt_msat,json=amtMsat,proto3" json:"amt_msat,omitempty"` + // The maximum number of millisatoshis that will be paid as a fee of the + // payment. If this field is left to the default value of 0, only zero-fee + // routes will be considered. This usually means single hop routes connecting + // directly to the destination. To send the payment without a fee limit, use + // max int here. + // + // The fields fee_limit_sat and fee_limit_msat are mutually exclusive. + FeeLimitMsat int64 `protobuf:"varint,13,opt,name=fee_limit_msat,json=feeLimitMsat,proto3" json:"fee_limit_msat,omitempty"` + // The pubkey of the last hop of the route. If empty, any hop may be used. + LastHopPubkey []byte `protobuf:"bytes,14,opt,name=last_hop_pubkey,json=lastHopPubkey,proto3" json:"last_hop_pubkey,omitempty"` // If set, circular payments to self are permitted. AllowSelfPayment bool `protobuf:"varint,15,opt,name=allow_self_payment,json=allowSelfPayment,proto3" json:"allow_self_payment,omitempty"` // Features assumed to be supported by the final node. All transitive feature @@ -481,6 +476,11 @@ type SendPaymentRequest struct { // If set, only the final payment update is streamed back. Intermediate updates // that show which htlcs are still in flight are suppressed. NoInflightUpdates bool `protobuf:"varint,18,opt,name=no_inflight_updates,json=noInflightUpdates,proto3" json:"no_inflight_updates,omitempty"` + // The channel ids of the channels are allowed for the first hop. If empty, + // any channel may be used. + OutgoingChanIds []uint64 `protobuf:"varint,19,rep,packed,name=outgoing_chan_ids,json=outgoingChanIds,proto3" json:"outgoing_chan_ids,omitempty"` + // An optional payment addr to be included within the last hop of the route. + PaymentAddr []byte `protobuf:"bytes,20,opt,name=payment_addr,json=paymentAddr,proto3" json:"payment_addr,omitempty"` // The largest payment split that should be attempted when making a payment if // splitting is necessary. Setting this value will effectively cause lnd to // split more aggressively, vs only when it thinks it needs to. Note that this @@ -539,13 +539,6 @@ func (x *SendPaymentRequest) GetAmt() int64 { return 0 } -func (x *SendPaymentRequest) GetAmtMsat() int64 { - if x != nil { - return x.AmtMsat - } - return 0 -} - func (x *SendPaymentRequest) GetPaymentHash() []byte { if x != nil { return x.PaymentHash @@ -560,13 +553,6 @@ func (x *SendPaymentRequest) GetFinalCltvDelta() int32 { return 0 } -func (x *SendPaymentRequest) GetPaymentAddr() []byte { - if x != nil { - return x.PaymentAddr - } - return nil -} - func (x *SendPaymentRequest) GetPaymentRequest() string { if x != nil { return x.PaymentRequest @@ -588,52 +574,52 @@ func (x *SendPaymentRequest) GetFeeLimitSat() int64 { return 0 } -func (x *SendPaymentRequest) GetFeeLimitMsat() int64 { +// Deprecated: Marked as deprecated in routerrpc/router.proto. +func (x *SendPaymentRequest) GetOutgoingChanId() uint64 { if x != nil { - return x.FeeLimitMsat + return x.OutgoingChanId } return 0 } -// Deprecated: Marked as deprecated in routerrpc/router.proto. -func (x *SendPaymentRequest) GetOutgoingChanId() uint64 { +func (x *SendPaymentRequest) GetCltvLimit() int32 { if x != nil { - return x.OutgoingChanId + return x.CltvLimit } return 0 } -func (x *SendPaymentRequest) GetOutgoingChanIds() []uint64 { +func (x *SendPaymentRequest) GetRouteHints() []*lnrpc.RouteHint { if x != nil { - return x.OutgoingChanIds + return x.RouteHints } return nil } -func (x *SendPaymentRequest) GetLastHopPubkey() []byte { +func (x *SendPaymentRequest) GetDestCustomRecords() map[uint64][]byte { if x != nil { - return x.LastHopPubkey + return x.DestCustomRecords } return nil } -func (x *SendPaymentRequest) GetCltvLimit() int32 { +func (x *SendPaymentRequest) GetAmtMsat() int64 { if x != nil { - return x.CltvLimit + return x.AmtMsat } return 0 } -func (x *SendPaymentRequest) GetRouteHints() []*lnrpc.RouteHint { +func (x *SendPaymentRequest) GetFeeLimitMsat() int64 { if x != nil { - return x.RouteHints + return x.FeeLimitMsat } - return nil + return 0 } -func (x *SendPaymentRequest) GetDestCustomRecords() map[uint64][]byte { +func (x *SendPaymentRequest) GetLastHopPubkey() []byte { if x != nil { - return x.DestCustomRecords + return x.LastHopPubkey } return nil } @@ -666,6 +652,20 @@ func (x *SendPaymentRequest) GetNoInflightUpdates() bool { return false } +func (x *SendPaymentRequest) GetOutgoingChanIds() []uint64 { + if x != nil { + return x.OutgoingChanIds + } + return nil +} + +func (x *SendPaymentRequest) GetPaymentAddr() []byte { + if x != nil { + return x.PaymentAddr + } + return nil +} + func (x *SendPaymentRequest) GetMaxShardSizeMsat() uint64 { if x != nil { return x.MaxShardSizeMsat @@ -3298,56 +3298,56 @@ var file_routerrpc_router_proto_rawDesc = []byte{ 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x6d, - 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x21, 0x0a, 0x0c, - 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x28, 0x0a, 0x10, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, - 0x6c, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x66, 0x69, 0x6e, 0x61, 0x6c, - 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x27, 0x0a, 0x0f, - 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, - 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x22, - 0x0a, 0x0d, 0x66, 0x65, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x61, 0x74, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x65, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, - 0x61, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x65, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, - 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x66, 0x65, 0x65, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2e, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x67, - 0x6f, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x04, 0x42, 0x04, 0x18, 0x01, 0x30, 0x01, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, - 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x67, + 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x63, 0x6c, + 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, + 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x27, + 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x12, 0x22, 0x0a, 0x0d, 0x66, 0x65, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x61, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x65, 0x65, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x53, 0x61, 0x74, 0x12, 0x2e, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, + 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x42, 0x04, + 0x18, 0x01, 0x30, 0x01, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x43, 0x68, + 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, 0x6c, 0x74, 0x76, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x12, 0x31, 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, + 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, + 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x64, 0x0a, 0x13, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x63, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x0b, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x43, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x19, 0x0a, 0x08, + 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, + 0x61, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x65, 0x65, 0x5f, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0c, 0x66, 0x65, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x26, 0x0a, + 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x50, + 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x73, + 0x65, 0x6c, 0x66, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x10, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x53, 0x65, 0x6c, 0x66, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x0d, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x66, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x52, 0x0c, 0x64, + 0x65, 0x73, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, + 0x61, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, + 0x6d, 0x61, 0x78, 0x50, 0x61, 0x72, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6e, 0x6f, 0x5f, 0x69, + 0x6e, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, + 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x6e, 0x6f, 0x49, 0x6e, 0x66, 0x6c, 0x69, 0x67, 0x68, + 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0f, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, - 0x6e, 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, - 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, - 0x61, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, - 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x09, 0x63, 0x6c, 0x74, 0x76, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x31, 0x0a, 0x0b, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, - 0x6e, 0x74, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x64, - 0x0a, 0x13, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x72, 0x6f, - 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x43, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x73, 0x65, - 0x6c, 0x66, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x10, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x53, 0x65, 0x6c, 0x66, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x0d, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x52, 0x0c, 0x64, 0x65, - 0x73, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, - 0x78, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, - 0x61, 0x78, 0x50, 0x61, 0x72, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6e, 0x6f, 0x5f, 0x69, 0x6e, - 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x12, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x6e, 0x6f, 0x49, 0x6e, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x73, + 0x6e, 0x49, 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2d, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x70, 0x18, 0x16, 0x20, diff --git a/lnrpc/routerrpc/router.proto b/lnrpc/routerrpc/router.proto index d591cc485c..1282709325 100644 --- a/lnrpc/routerrpc/router.proto +++ b/lnrpc/routerrpc/router.proto @@ -164,13 +164,6 @@ message SendPaymentRequest { */ int64 amt = 2; - /* - Number of millisatoshis to send. - - The fields amt and amt_msat are mutually exclusive. - */ - int64 amt_msat = 12; - // The hash to use within the payment's HTLC bytes payment_hash = 3; @@ -180,9 +173,6 @@ message SendPaymentRequest { */ int32 final_cltv_delta = 4; - // An optional payment addr to be included within the last hop of the route. - bytes payment_addr = 20; - /* A bare-bones invoice for a payment within the Lightning Network. With the details of the invoice, the sender has all the data necessary to send a @@ -210,17 +200,6 @@ message SendPaymentRequest { */ int64 fee_limit_sat = 7; - /* - The maximum number of millisatoshis that will be paid as a fee of the - payment. If this field is left to the default value of 0, only zero-fee - routes will be considered. This usually means single hop routes connecting - directly to the destination. To send the payment without a fee limit, use - max int here. - - The fields fee_limit_sat and fee_limit_msat are mutually exclusive. - */ - int64 fee_limit_msat = 13; - /* Deprecated, use outgoing_chan_ids. The channel id of the channel that must be taken to the first hop. If zero, any channel may be used (unless @@ -229,19 +208,8 @@ message SendPaymentRequest { uint64 outgoing_chan_id = 8 [jstype = JS_STRING, deprecated = true]; /* - The channel ids of the channels are allowed for the first hop. If empty, - any channel may be used. - */ - repeated uint64 outgoing_chan_ids = 19; - - /* - The pubkey of the last hop of the route. If empty, any hop may be used. - */ - bytes last_hop_pubkey = 14; - - /* - An optional maximum total time lock for the route. This should not exceed - lnd's `--max-cltv-expiry` setting. If zero, then the value of + An optional maximum total time lock for the route. This should not + exceed lnd's `--max-cltv-expiry` setting. If zero, then the value of `--max-cltv-expiry` is enforced. */ int32 cltv_limit = 9; @@ -260,6 +228,29 @@ message SendPaymentRequest { */ map dest_custom_records = 11; + /* + Number of millisatoshis to send. + + The fields amt and amt_msat are mutually exclusive. + */ + int64 amt_msat = 12; + + /* + The maximum number of millisatoshis that will be paid as a fee of the + payment. If this field is left to the default value of 0, only zero-fee + routes will be considered. This usually means single hop routes connecting + directly to the destination. To send the payment without a fee limit, use + max int here. + + The fields fee_limit_sat and fee_limit_msat are mutually exclusive. + */ + int64 fee_limit_msat = 13; + + /* + The pubkey of the last hop of the route. If empty, any hop may be used. + */ + bytes last_hop_pubkey = 14; + // If set, circular payments to self are permitted. bool allow_self_payment = 15; @@ -284,6 +275,15 @@ message SendPaymentRequest { */ bool no_inflight_updates = 18; + /* + The channel ids of the channels are allowed for the first hop. If empty, + any channel may be used. + */ + repeated uint64 outgoing_chan_ids = 19; + + // An optional payment addr to be included within the last hop of the route. + bytes payment_addr = 20; + /* The largest payment split that should be attempted when making a payment if splitting is necessary. Setting this value will effectively cause lnd to diff --git a/lnrpc/routerrpc/router.swagger.json b/lnrpc/routerrpc/router.swagger.json index ff0cfb1cd5..33b1824d8a 100644 --- a/lnrpc/routerrpc/router.swagger.json +++ b/lnrpc/routerrpc/router.swagger.json @@ -1678,11 +1678,6 @@ "format": "int64", "description": "Number of satoshis to send.\n\nThe fields amt and amt_msat are mutually exclusive." }, - "amt_msat": { - "type": "string", - "format": "int64", - "description": "Number of millisatoshis to send.\n\nThe fields amt and amt_msat are mutually exclusive." - }, "payment_hash": { "type": "string", "format": "byte", @@ -1693,11 +1688,6 @@ "format": "int32", "description": "The CLTV delta from the current height that should be used to set the\ntimelock for the final hop." }, - "payment_addr": { - "type": "string", - "format": "byte", - "description": "An optional payment addr to be included within the last hop of the route." - }, "payment_request": { "type": "string", "description": "A bare-bones invoice for a payment within the Lightning Network. With the\ndetails of the invoice, the sender has all the data necessary to send a\npayment to the recipient. The amount in the payment request may be zero. In\nthat case it is required to set the amt field as well. If no payment request\nis specified, the following fields are required: dest, amt and payment_hash." @@ -1712,33 +1702,15 @@ "format": "int64", "description": "The maximum number of satoshis that will be paid as a fee of the payment.\nIf this field is left to the default value of 0, only zero-fee routes will\nbe considered. This usually means single hop routes connecting directly to\nthe destination. To send the payment without a fee limit, use max int here.\n\nThe fields fee_limit_sat and fee_limit_msat are mutually exclusive." }, - "fee_limit_msat": { - "type": "string", - "format": "int64", - "description": "The maximum number of millisatoshis that will be paid as a fee of the\npayment. If this field is left to the default value of 0, only zero-fee\nroutes will be considered. This usually means single hop routes connecting\ndirectly to the destination. To send the payment without a fee limit, use\nmax int here.\n\nThe fields fee_limit_sat and fee_limit_msat are mutually exclusive." - }, "outgoing_chan_id": { "type": "string", "format": "uint64", "description": "Deprecated, use outgoing_chan_ids. The channel id of the channel that must\nbe taken to the first hop. If zero, any channel may be used (unless\noutgoing_chan_ids are set)." }, - "outgoing_chan_ids": { - "type": "array", - "items": { - "type": "string", - "format": "uint64" - }, - "description": "The channel ids of the channels are allowed for the first hop. If empty,\nany channel may be used." - }, - "last_hop_pubkey": { - "type": "string", - "format": "byte", - "description": "The pubkey of the last hop of the route. If empty, any hop may be used." - }, "cltv_limit": { "type": "integer", "format": "int32", - "description": "An optional maximum total time lock for the route. This should not exceed\nlnd's `--max-cltv-expiry` setting. If zero, then the value of\n`--max-cltv-expiry` is enforced." + "description": "An optional maximum total time lock for the route. This should not\nexceed lnd's `--max-cltv-expiry` setting. If zero, then the value of\n`--max-cltv-expiry` is enforced." }, "route_hints": { "type": "array", @@ -1755,6 +1727,21 @@ }, "description": "An optional field that can be used to pass an arbitrary set of TLV records\nto a peer which understands the new records. This can be used to pass\napplication specific data during the payment attempt. Record types are\nrequired to be in the custom range \u003e= 65536. When using REST, the values\nmust be encoded as base64." }, + "amt_msat": { + "type": "string", + "format": "int64", + "description": "Number of millisatoshis to send.\n\nThe fields amt and amt_msat are mutually exclusive." + }, + "fee_limit_msat": { + "type": "string", + "format": "int64", + "description": "The maximum number of millisatoshis that will be paid as a fee of the\npayment. If this field is left to the default value of 0, only zero-fee\nroutes will be considered. This usually means single hop routes connecting\ndirectly to the destination. To send the payment without a fee limit, use\nmax int here.\n\nThe fields fee_limit_sat and fee_limit_msat are mutually exclusive." + }, + "last_hop_pubkey": { + "type": "string", + "format": "byte", + "description": "The pubkey of the last hop of the route. If empty, any hop may be used." + }, "allow_self_payment": { "type": "boolean", "description": "If set, circular payments to self are permitted." @@ -1775,6 +1762,19 @@ "type": "boolean", "description": "If set, only the final payment update is streamed back. Intermediate updates\nthat show which htlcs are still in flight are suppressed." }, + "outgoing_chan_ids": { + "type": "array", + "items": { + "type": "string", + "format": "uint64" + }, + "description": "The channel ids of the channels are allowed for the first hop. If empty,\nany channel may be used." + }, + "payment_addr": { + "type": "string", + "format": "byte", + "description": "An optional payment addr to be included within the last hop of the route." + }, "max_shard_size_msat": { "type": "string", "format": "uint64", From 816a70e08c46d0f584a4e567c3aa33bc0a3b2a49 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 14 Nov 2023 20:29:52 +0800 Subject: [PATCH 3/6] multi: add new config `usestatusinitiated` for the new payment status This commit adds a new config value to signal that the user understands the new payment status `StatusInitiated`. --- itest/lnd_max_htlcs_test.go | 11 +++++++++++ lnrpc/routerrpc/config.go | 9 +++++++++ lnrpc/routerrpc/router_backend.go | 21 ++++++++++++++++++--- rpcserver.go | 3 ++- sample-lnd.conf | 4 ++++ 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/itest/lnd_max_htlcs_test.go b/itest/lnd_max_htlcs_test.go index a9bee5ae4a..971537adf4 100644 --- a/itest/lnd_max_htlcs_test.go +++ b/itest/lnd_max_htlcs_test.go @@ -20,6 +20,17 @@ func testMaxHtlcPathfind(ht *lntest.HarnessTest) { maxHtlcs := 5 alice, bob := ht.Alice, ht.Bob + + // Restart nodes with the new flag so they understand the new payment + // status. + ht.RestartNodeWithExtraArgs(alice, []string{ + "--routerrpc.usestatusinitiated", + }) + ht.RestartNodeWithExtraArgs(bob, []string{ + "--routerrpc.usestatusinitiated", + }) + + ht.EnsureConnected(alice, bob) chanPoint := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{ Amt: 1000000, diff --git a/lnrpc/routerrpc/config.go b/lnrpc/routerrpc/config.go index adcc84e800..ec70b6d465 100644 --- a/lnrpc/routerrpc/config.go +++ b/lnrpc/routerrpc/config.go @@ -10,9 +10,18 @@ import ( // The fields with struct tags are meant to be parsed as normal configuration // options, while if able to be populated, the latter fields MUST also be // specified. +// +//nolint:lll type Config struct { RoutingConfig + // UseStatusInitiated is a boolean that indicates whether the router + // should use the new status code `Payment_INITIATED`. + // + // TODO(yy): remove this config after the new status code is fully + // deployed to the network(v0.20.0). + UseStatusInitiated bool `long:"usestatusinitiated" description:"If true, the router will send Payment_INITIATED for new payments, otherwise Payment_In_FLIGHT will be sent for compatibility concerns."` + // RouterMacPath is the path for the router macaroon. If unspecified // then we assume that the macaroon will be found under the network // directory, named DefaultRouterMacFilename. diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go index 549443f0fe..49d080a320 100644 --- a/lnrpc/routerrpc/router_backend.go +++ b/lnrpc/routerrpc/router_backend.go @@ -98,6 +98,13 @@ type RouterBackend struct { // SetChannelAuto exposes the ability to restore automatic channel state // management after manually setting channel status. SetChannelAuto func(wire.OutPoint) error + + // UseStatusInitiated is a boolean that indicates whether the router + // should use the new status code `Payment_INITIATED`. + // + // TODO(yy): remove this config after the new status code is fully + // deployed to the network(v0.20.0). + UseStatusInitiated bool } // MissionControl defines the mission control dependencies of routerrpc. @@ -1542,7 +1549,9 @@ func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) ( msatValue := int64(payment.Info.Value) satValue := int64(payment.Info.Value.ToSatoshis()) - status, err := convertPaymentStatus(payment.Status) + status, err := convertPaymentStatus( + payment.Status, r.UseStatusInitiated, + ) if err != nil { return nil, err } @@ -1589,12 +1598,18 @@ func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) ( // convertPaymentStatus converts a channeldb.PaymentStatus to the type expected // by the RPC. -func convertPaymentStatus(dbStatus channeldb.PaymentStatus) ( +func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) ( lnrpc.Payment_PaymentStatus, error) { switch dbStatus { case channeldb.StatusInitiated: - return lnrpc.Payment_INITIATED, nil + // If the client understands the new status, return it. + if useInit { + return lnrpc.Payment_INITIATED, nil + } + + // Otherwise remain the old behavior. + return lnrpc.Payment_IN_FLIGHT, nil case channeldb.StatusInFlight: return lnrpc.Payment_IN_FLIGHT, nil diff --git a/rpcserver.go b/rpcserver.go index fa23f04852..27921e5d77 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -715,7 +715,8 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service, SetChannelDisabled: func(outpoint wire.OutPoint) error { return s.chanStatusMgr.RequestDisable(outpoint, true) }, - SetChannelAuto: s.chanStatusMgr.RequestAuto, + SetChannelAuto: s.chanStatusMgr.RequestAuto, + UseStatusInitiated: subServerCgs.RouterRPC.UseStatusInitiated, } genInvoiceFeatures := func() *lnwire.FeatureVector { diff --git a/sample-lnd.conf b/sample-lnd.conf index 9bc1a2a840..0b7531e66a 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -1201,6 +1201,10 @@ ; failures in channels. ; routerrpc.bimodal.decaytime=168h +; If set, the router will send `Payment_INITIATED` for new payments, otherwise +; `Payment_In_FLIGHT` will be sent for compatibility concerns. +; routerrpc.usestatusinitiated=false + [workers] From 9e00799188e0930e5581f6b4ec91cd6b63b64acd Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 14 Nov 2023 20:37:23 +0800 Subject: [PATCH 4/6] docs: update release notes --- docs/release-notes/release-notes-0.18.0.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/release-notes/release-notes-0.18.0.md b/docs/release-notes/release-notes-0.18.0.md index b146861df8..2f5315fd3e 100644 --- a/docs/release-notes/release-notes-0.18.0.md +++ b/docs/release-notes/release-notes-0.18.0.md @@ -63,6 +63,11 @@ * A new config value, [http-header-timeout](https://github.com/lightningnetwork/lnd/pull/7715), is added so users can specify the amount of time the http server will wait for a request to complete before closing the connection. The default value is 5 seconds. +* [`routerrpc.usestatusinitiated` is + introduced](https://github.com/lightningnetwork/lnd/pull/8177) to signal that + the new payment status `Payment_INITIATED` should be used for payment-related + RPCs. It's recommended to use it to provide granular controls over payments. + ## RPC Additions * [Deprecated](https://github.com/lightningnetwork/lnd/pull/7175) From 9acbbf0ec7274d58250080e5e3a2abb5d5347610 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 15 Nov 2023 19:45:20 +0800 Subject: [PATCH 5/6] routing: make sure `StatusInitiated` is notified when creating payments This commit fixes `InitPayment` method to make sure the subscribers get notified when new payments are created. --- routing/control_tower.go | 23 ++++++++++++++++++++--- routing/control_tower_test.go | 32 ++++++++++++++------------------ 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/routing/control_tower.go b/routing/control_tower.go index c064a5b4f2..274c4190bd 100644 --- a/routing/control_tower.go +++ b/routing/control_tower.go @@ -181,12 +181,29 @@ func NewControlTower(db *channeldb.PaymentControl) ControlTower { // InitPayment checks or records the given PaymentCreationInfo with the DB, // making sure it does not already exist as an in-flight payment. Then this -// method returns successfully, the payment is guaranteed to be in the InFlight -// state. +// method returns successfully, the payment is guaranteed to be in the +// Initiated state. func (p *controlTower) InitPayment(paymentHash lntypes.Hash, info *channeldb.PaymentCreationInfo) error { - return p.db.InitPayment(paymentHash, info) + err := p.db.InitPayment(paymentHash, info) + if err != nil { + return err + } + + // Take lock before querying the db to prevent missing or duplicating + // an update. + p.paymentsMtx.Lock(paymentHash) + defer p.paymentsMtx.Unlock(paymentHash) + + payment, err := p.db.FetchPayment(paymentHash) + if err != nil { + return err + } + + p.notifySubscribers(paymentHash, payment) + + return nil } // DeleteFailedAttempts deletes all failed htlcs if the payment was diff --git a/routing/control_tower_test.go b/routing/control_tower_test.go index 42303dc556..2baad92f1e 100644 --- a/routing/control_tower_test.go +++ b/routing/control_tower_test.go @@ -196,7 +196,7 @@ func TestPaymentControlSubscribeAllSuccess(t *testing.T) { err = pControl.InitPayment(info1.PaymentIdentifier, info1) require.NoError(t, err) - // Subscription should succeed and immediately report the InFlight + // Subscription should succeed and immediately report the Initiated // status. subscription, err := pControl.SubscribeAllPayments() require.NoError(t, err, "expected subscribe to succeed, but got: %v") @@ -246,8 +246,8 @@ func TestPaymentControlSubscribeAllSuccess(t *testing.T) { // for each payment. results := make(map[lntypes.Hash]*channeldb.MPPayment) - // After exactly 5 updates both payments will/should have completed. - for i := 0; i < 5; i++ { + // After exactly 6 updates both payments will/should have completed. + for i := 0; i < 6; i++ { select { case item := <-subscription.Updates(): id := item.(*channeldb.MPPayment).Info.PaymentIdentifier @@ -354,10 +354,6 @@ func TestPaymentControlUnsubscribeSuccess(t *testing.T) { err = pControl.InitPayment(info.PaymentIdentifier, info) require.NoError(t, err) - // Register a payment update. - err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) - require.NoError(t, err) - // Assert all subscriptions receive the update. select { case update1 := <-subscription1.Updates(): @@ -376,14 +372,9 @@ func TestPaymentControlUnsubscribeSuccess(t *testing.T) { // Close the first subscription. subscription1.Close() - // Register another update. - failInfo := channeldb.HTLCFailInfo{ - Reason: channeldb.HTLCFailInternal, - } - _, err = pControl.FailAttempt( - info.PaymentIdentifier, attempt.AttemptID, &failInfo, - ) - require.NoError(t, err, "unable to fail htlc") + // Register a payment update. + err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) + require.NoError(t, err) // Assert only subscription 2 receives the update. select { @@ -398,9 +389,14 @@ func TestPaymentControlUnsubscribeSuccess(t *testing.T) { // Close the second subscription. subscription2.Close() - // Register a last update. - err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) - require.NoError(t, err) + // Register another update. + failInfo := channeldb.HTLCFailInfo{ + Reason: channeldb.HTLCFailInternal, + } + _, err = pControl.FailAttempt( + info.PaymentIdentifier, attempt.AttemptID, &failInfo, + ) + require.NoError(t, err, "unable to fail htlc") // Assert no subscriptions receive the update. require.Len(t, subscription1.Updates(), 0) From 99354313d5e83d0f86e271d505e0de1403e9c24a Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 15 Nov 2023 19:58:52 +0800 Subject: [PATCH 6/6] routerrpc+itest: make sure `TrackPayments` is compatible This commit adds an itest case to make sure when the flag `routerrpc.usestatusinitiated` is not set, the new status is not sent. --- itest/list_on_test.go | 4 + itest/lnd_trackpayments_test.go | 125 ++++++++++++++++++++++++++----- lnrpc/routerrpc/router_server.go | 3 + 3 files changed, 113 insertions(+), 19 deletions(-) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 9b1499bd80..3370e3fe61 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -490,6 +490,10 @@ var allTestCases = []*lntest.TestCase{ Name: "trackpayments", TestFunc: testTrackPayments, }, + { + Name: "trackpayments compatible", + TestFunc: testTrackPaymentsCompatible, + }, { Name: "open channel fee policy", TestFunc: testOpenChannelUpdateFeePolicy, diff --git a/itest/lnd_trackpayments_test.go b/itest/lnd_trackpayments_test.go index 55224b87bb..b942cd4c72 100644 --- a/itest/lnd_trackpayments_test.go +++ b/itest/lnd_trackpayments_test.go @@ -14,8 +14,16 @@ import ( // testTrackPayments tests whether a client that calls the TrackPayments api // receives payment updates. func testTrackPayments(ht *lntest.HarnessTest) { - // Open a channel between alice and bob. alice, bob := ht.Alice, ht.Bob + + // Restart Alice with the new flag so she understands the new payment + // status. + ht.RestartNodeWithExtraArgs(alice, []string{ + "--routerrpc.usestatusinitiated", + }) + + // Open a channel between alice and bob. + ht.EnsureConnected(alice, bob) channel := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{ Amt: btcutil.Amount(300000), @@ -47,36 +55,115 @@ func testTrackPayments(ht *lntest.HarnessTest) { // Make sure the payment doesn't error due to invalid parameters or so. _, err := paymentClient.Recv() - require.NoError(ht, err, "unable to get payment update.") + require.NoError(ht, err, "unable to get payment update") - // Assert the first payment update is an inflight update. + // Assert the first payment update is an initiated update. update1, err := tracker.Recv() - require.NoError(ht, err, "unable to receive payment update 1.") + require.NoError(ht, err, "unable to receive payment update 1") - require.Equal( - ht, lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, - update1.FailureReason, - ) - require.Equal(ht, lnrpc.Payment_IN_FLIGHT, update1.Status) + require.Equal(ht, lnrpc.Payment_INITIATED, update1.Status) + require.Equal(ht, lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, + update1.FailureReason) require.Equal(ht, invoice.PaymentRequest, update1.PaymentRequest) require.Equal(ht, amountMsat, update1.ValueMsat) - // Assert the second payment update is a payment success update. + // Assert the first payment update is an inflight update. update2, err := tracker.Recv() - require.NoError(ht, err, "unable to receive payment update 2.") + require.NoError(ht, err, "unable to receive payment update 2") - require.Equal( - ht, lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, - update2.FailureReason, - ) - require.Equal(ht, lnrpc.Payment_SUCCEEDED, update2.Status) + require.Equal(ht, lnrpc.Payment_IN_FLIGHT, update2.Status) + require.Equal(ht, lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, + update2.FailureReason) require.Equal(ht, invoice.PaymentRequest, update2.PaymentRequest) require.Equal(ht, amountMsat, update2.ValueMsat) - require.Equal( - ht, hex.EncodeToString(invoice.RPreimage), - update2.PaymentPreimage, + + // Assert the third payment update is a payment success update. + update3, err := tracker.Recv() + require.NoError(ht, err, "unable to receive payment update 3") + + require.Equal(ht, lnrpc.Payment_SUCCEEDED, update3.Status) + require.Equal(ht, lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, + update3.FailureReason) + require.Equal(ht, invoice.PaymentRequest, update3.PaymentRequest) + require.Equal(ht, amountMsat, update3.ValueMsat) + require.Equal(ht, hex.EncodeToString(invoice.RPreimage), + update3.PaymentPreimage) + + // TODO(yy): remove the sleep once the following bug is fixed. + // When the invoice is reported settled, the commitment dance is not + // yet finished, which can cause an error when closing the channel, + // saying there's active HTLCs. We need to investigate this issue and + // reverse the order to, first finish the commitment dance, then report + // the invoice as settled. + time.Sleep(2 * time.Second) + + ht.CloseChannel(alice, channel) +} + +// testTrackPaymentsCompatible checks that when `routerrpc.usestatusinitiated` +// is not set, the new Payment_INITIATED is replaced with Payment_IN_FLIGHT. +func testTrackPaymentsCompatible(ht *lntest.HarnessTest) { + // Open a channel between alice and bob. + alice, bob := ht.Alice, ht.Bob + channel := ht.OpenChannel( + alice, bob, lntest.OpenChannelParams{ + Amt: btcutil.Amount(300000), + }, ) + // Call the TrackPayments api to listen for payment updates. + req := &routerrpc.TrackPaymentsRequest{ + NoInflightUpdates: false, + } + tracker := alice.RPC.TrackPayments(req) + + // Create an invoice from bob. + var amountMsat int64 = 1000 + invoiceResp := bob.RPC.AddInvoice( + &lnrpc.Invoice{ + ValueMsat: amountMsat, + }, + ) + invoice := bob.RPC.LookupInvoice(invoiceResp.RHash) + + // Send payment from alice to bob. + paymentClient := alice.RPC.SendPayment( + &routerrpc.SendPaymentRequest{ + PaymentRequest: invoice.PaymentRequest, + TimeoutSeconds: 60, + }, + ) + + // Assert the first track payment update is an inflight update. + update1, err := tracker.Recv() + require.NoError(ht, err, "unable to receive payment update 1") + require.Equal(ht, lnrpc.Payment_IN_FLIGHT, update1.Status) + + // Assert the first track payment update is an inflight update. + update2, err := tracker.Recv() + require.NoError(ht, err, "unable to receive payment update 2") + require.Equal(ht, lnrpc.Payment_IN_FLIGHT, update2.Status) + + // Assert the third track payment update is a payment success update. + update3, err := tracker.Recv() + require.NoError(ht, err, "unable to receive payment update 3") + require.Equal(ht, lnrpc.Payment_SUCCEEDED, update3.Status) + + // Assert the first payment client update is an inflight update. + payment1, err := paymentClient.Recv() + require.NoError(ht, err, "unable to get payment update") + require.Equal(ht, lnrpc.Payment_IN_FLIGHT, payment1.Status) + + // Assert the second payment client update is an inflight update. + payment2, err := paymentClient.Recv() + require.NoError(ht, err, "unable to get payment update") + require.Equal(ht, lnrpc.Payment_IN_FLIGHT, payment2.Status) + + // Assert the third payment client update is a success update. + payment3, err := paymentClient.Recv() + require.NoError(ht, err, "unable to get payment update") + require.Equal(ht, lnrpc.Payment_SUCCEEDED, payment3.Status) + // TODO(yy): remove the sleep once the following bug is fixed. // When the invoice is reported settled, the commitment dance is not // yet finished, which can cause an error when closing the channel, diff --git a/lnrpc/routerrpc/router_server.go b/lnrpc/routerrpc/router_server.go index 595eb1ea0a..5414f9e608 100644 --- a/lnrpc/routerrpc/router_server.go +++ b/lnrpc/routerrpc/router_server.go @@ -940,6 +940,9 @@ func (s *Server) trackPaymentStream(context context.Context, } result := item.(*channeldb.MPPayment) + log.Tracef("Payment %v updated to state %v", + result.Info.PaymentIdentifier, result.Status) + // Skip in-flight updates unless requested. if noInflightUpdates { if result.Status == channeldb.StatusInitiated {