lnrpc: clarify payment request expiry semantics - #11058
Conversation
Lrifton92
left a comment
There was a problem hiding this comment.
Verified against the implementation: DecodePayReq fills this field from payReq.Expiry().Seconds() (rpcserver.go), where zpay32.Invoice.Expiry() returns the relative duration from the BOLT-11 x tagged field, while timestamp is set separately from payReq.Timestamp.Unix(). So the clarification matches the actual semantics, and the .pb.go / swagger regeneration is consistent (the pb.go churn is just gofmt realignment from the inserted comment).
One optional addition while you're touching this comment: when the payment request carries no expiry tag, zpay32.Invoice.Expiry() returns the BOLT-11 default of 3600 seconds, so this field is never 0 in practice. Spelling that out would preempt the next likely misreading (0 = "no expiry"), e.g.:
// The expiry duration in seconds relative to the `timestamp` field. If
// the payment request does not encode an expiry, the BOLT-11 default of
// 3600 seconds is returned.Fine as-is too — the current wording is accurate.
|
@Lrifton92 Great proposal! Thanks! Applied. |
🟠 PR Severity: HIGH
🟠 High (2 files)
🟡 Medium (1 file)
AnalysisThis PR only touches To override, add a |
|
|
||
| string description = 6; | ||
| string description_hash = 7; | ||
| string fallback_addr = 8; |
There was a problem hiding this comment.
let's maybe add proper description to all of them ?
There was a problem hiding this comment.
+1 — since this PR is about making the PayReq semantics explicit, here is a draft for the remaining fields, checked against what DecodePayReq in rpcserver.go actually fills in from zpay32.Invoice (in case it saves @starius a round trip; feel free to reword):
message PayReq {
// The hex-encoded compressed public key of the payee (the node that
// created the payment request).
string destination = 1;
// The hex-encoded payment hash (BOLT-11 `p` field).
string payment_hash = 2;
// The amount in satoshis. 0 if the payment request does not specify
// an amount. Any millisatoshi remainder is truncated; see num_msat for
// the exact value.
int64 num_satoshis = 3;
// The creation time of the payment request as a Unix timestamp
// (seconds).
int64 timestamp = 4;
// The expiry duration in seconds relative to the `timestamp` field. If
// the payment request omits the BOLT-11 `x` expiry field, the BOLT-11
// default of 3600 seconds is returned.
int64 expiry = 5;
// The description (memo) of the payment (BOLT-11 `d` field). Empty if
// the payment request carries a description_hash instead.
string description = 6;
// The hex-encoded SHA-256 hash of the payment description (BOLT-11 `h`
// field). Empty if not present.
string description_hash = 7;
// The on-chain fallback address (BOLT-11 `f` field), encoded for the
// active network. Empty if not present.
string fallback_addr = 8;
// The minimum CLTV expiry delta to use for the final hop (BOLT-11 `c`
// field). If the payment request omits it, lnd's assumed default
// (zpay32.DefaultAssumedFinalCLTVDelta) is returned.
int64 cltv_expiry = 9;
// Route hints that can each be individually used to assist in reaching
// the invoice's destination (BOLT-11 `r` field).
repeated RouteHint route_hints = 10;
// The payment address / payment secret (BOLT-11 `s` field), used for MPP
// and required by newer invoices. All-zero (32 bytes) if not present.
// When using REST, this field is base64 encoded.
bytes payment_addr = 11;
// The amount in millisatoshis. 0 if the payment request does not
// specify an amount.
int64 num_msat = 12;
// The feature bits advertised in the payment request (BOLT-11 `9`
// field).
map<uint32, Feature> features = 13;
// The blinded payment paths included in the payment request, if any.
repeated BlindedPaymentPath blinded_paths = 14;
}Notes on the non-obvious ones, from the implementation:
num_satoshis/num_msat: both come frompayReq.MilliSat, which isnilfor amountless invoices → both are 0;num_satoshisisMilliSat.ToSatoshis()so it truncates sub-sat amounts.payment_addr:payReq.PaymentAddr.UnwrapOr([32]byte{})→ 32 zero bytes when thesfield is absent, not an empty slice.description_hash:hex.EncodeToStringof an empty slice →""when absent.cltv_expiry:payReq.MinFinalCLTVExpiry()falls back toDefaultAssumedFinalCLTVDelta; I referenced the constant rather than the number so the comment doesn't rot.
Document the encoding, units, defaults, and absent-value behavior of every field returned by DecodePayReq. Clarify in particular that expiry is a relative duration from the invoice timestamp and defaults to 3600 seconds when the BOLT-11 expiry field is omitted. This is a documentation-only change and does not alter RPC behavior.
Change Description
The DecodePayReq response exposes an absolute invoice timestamp and a relative expiry duration, but the expiry field did not document that distinction. Clarify that expiry is measured in seconds from timestamp to avoid it being interpreted as an absolute Unix timestamp.
This is a documentation-only change and does not alter RPC behavior.
Pull Request Checklist
Testing
Code Style and Documentation
[skip ci]in the commit message for small changes.📝 Please see our Contribution Guidelines for further guidance.