decode: print htlc_minimum_msat / htlc_maximum_msat in blinded paths.
What changed, and why it matters
This commit adds two missing fields, htlc_minimum_msat and htlc_maximum_msat, to the output of the 'decode' command when it shows blinded payment paths. Previously these values were decoded internally but not printed in JSON or CLI output. It is a display/information fix, not a code-execution vulnerability.
No security action required; treat as a normal feature/bug-fix update. Users relying on decode output for blinded path analysis may want to update to obtain complete payinfo fields.
Security signals we found
Missing output field in decode command for blinded path payinfo
No change to parsing, validation, or cryptographic handling
No memory safety, authorization, or consensus code modified
Reported-by line credits an external contributor
Evidence from the diff
The patch exposes htlc_minimum_msat and htlc_maximum_msat from struct blinded_payinfo in decode, bolt12-cli, gRPC conversion, schema docs, and tests. No parsing, validation, or payment logic is changed. The fields were already present in the underlying BOLT12 data structure; the commit only surfaces them to users.
Changed components
plugins/offers.c decode outputdevtools/bolt12-cli.ccontrib/pyln-testing/pyln/testing/grpc2py.pydoc/schemas/decode.jsoncontrib/msggen/msggen/schema.json.msggen.jsontests/test_pay.pyInspect captured patch +51 / −1
diff --git a/.msggen.json b/.msggen.json
index 337d2c7e..e1b4c984 100644
--- a/.msggen.json
+++ b/.msggen.json
@@ -6293,6 +6293,14 @@
"added": "v23.05",
"deprecated": null
},
+ "Decode.invoice_paths[].payinfo.htlc_maximum_msat": {
+ "added": "v26.04",
+ "deprecated": null
+ },
+ "Decode.invoice_paths[].payinfo.htlc_minimum_msat": {
+ "added": "v26.04",
+ "deprecated": null
+ },
"Decode.invoice_payment_hash": {
"added": "v23.05",
"deprecated": null
diff --git a/contrib/msggen/msggen/schema.json b/contrib/msggen/msggen/schema.json
index 8af25ff5..9ed9be9c 100644
--- a/contrib/msggen/msggen/schema.json
+++ b/contrib/msggen/msggen/schema.json
@@ -9422,6 +9422,8 @@
"fee_base_msat",
"fee_proportional_millionths",
"cltv_expiry_delta",
+ "htlc_minimum_msat",
+ "htlc_maximum_msat",
"features"
],
"additionalProperties": false,
@@ -9444,6 +9446,20 @@
"CLTV delta for path."
]
},
+ "htlc_minimum_msat": {
+ "type": "msat",
+ "added": "v26.04",
+ "description": [
+ "Minimum amount which can be sent via path."
+ ]
+ },
+ "htlc_maximum_msat": {
+ "type": "msat",
+ "added": "v26.04",
+ "description": [
+ "Maximum amount which can be sent via path."
+ ]
+ },
"features": {
"type": "hex",
"description": [
diff --git a/contrib/pyln-testing/pyln/testing/grpc2py.py b/contrib/pyln-testing/pyln/testing/grpc2py.py
index 5243f326..d49c7c4f 100644
--- a/contrib/pyln-testing/pyln/testing/grpc2py.py
+++ b/contrib/pyln-testing/pyln/testing/grpc2py.py
@@ -1151,6 +1151,8 @@ def decode_invoice_paths_payinfo2py(m):
"features": hexlify(m.features), # PrimitiveField in generate_composite
"fee_base_msat": amount2msat(m.fee_base_msat), # PrimitiveField in generate_composite
"fee_proportional_millionths": m.fee_proportional_millionths, # PrimitiveField in generate_composite
+ "htlc_maximum_msat": amount2msat(m.htlc_maximum_msat), # PrimitiveField in generate_composite
+ "htlc_minimum_msat": amount2msat(m.htlc_minimum_msat), # PrimitiveField in generate_composite
})
diff --git a/devtools/bolt12-cli.c b/devtools/bolt12-cli.c
index 9d8e0b6e..a72d57a1 100644
--- a/devtools/bolt12-cli.c
+++ b/devtools/bolt12-cli.c
@@ -276,10 +276,12 @@ static bool print_blindedpaths(const char *fieldname,
tal_hex(tmpctx, p[j]->encrypted_recipient_data));
}
if (i < tal_count(blindedpay)) {
- printf(" blindedpay: fee=%u/%u,cltv=%u,features=%s",
+ printf(" blindedpay: fee=%u/%u,cltv=%u,min/max=%s/%s,features=%s",
blindedpay[i]->fee_base_msat,
blindedpay[i]->fee_proportional_millionths,
blindedpay[i]->cltv_expiry_delta,
+ fmt_amount_msat(tmpctx, blindedpay[i]->htlc_minimum_msat),
+ fmt_amount_msat(tmpctx, blindedpay[i]->htlc_maximum_msat),
tal_hex(tmpctx, blindedpay[i]->features));
}
printf("\n");
diff --git a/doc/schemas/decode.json b/doc/schemas/decode.json
index e21bca5a..20bb6d5a 100644
--- a/doc/schemas/decode.json
+++ b/doc/schemas/decode.json
@@ -1624,6 +1624,8 @@
"fee_base_msat",
"fee_proportional_millionths",
"cltv_expiry_delta",
+ "htlc_minimum_msat",
+ "htlc_maximum_msat",
"features"
],
"additionalProperties": false,
@@ -1646,6 +1648,20 @@
"CLTV delta for path."
]
},
+ "htlc_minimum_msat": {
+ "type": "msat",
+ "added": "v26.04",
+ "description": [
+ "Minimum amount which can be sent via path."
+ ]
+ },
+ "htlc_maximum_msat": {
+ "type": "msat",
+ "added": "v26.04",
+ "description": [
+ "Maximum amount which can be sent via path."
+ ]
+ },
"features": {
"type": "hex",
"description": [
diff --git a/plugins/offers.c b/plugins/offers.c
index 0a9a82b2..841ebb17 100644
--- a/plugins/offers.c
+++ b/plugins/offers.c
@@ -754,6 +754,10 @@ static bool json_add_blinded_paths(struct command *cmd,
blindedpay[i]->fee_proportional_millionths);
json_add_u32(js, "cltv_expiry_delta",
blindedpay[i]->cltv_expiry_delta);
+ json_add_amount_msat(js, "htlc_minimum_msat",
+ blindedpay[i]->htlc_minimum_msat);
+ json_add_amount_msat(js, "htlc_maximum_msat",
+ blindedpay[i]->htlc_maximum_msat);
json_add_hex_talarr(js, "features", blindedpay[i]->features);
json_object_end(js);
}
diff --git a/tests/test_pay.py b/tests/test_pay.py
index 77456788..4b2cf800 100644
--- a/tests/test_pay.py
+++ b/tests/test_pay.py
@@ -6957,6 +6957,8 @@ def test_decode_expired_bolt12(node_factory):
'path': [{'blinded_node_id': '03f293aad04524af9d25e37e30975c9c48df7f46bb5707f5103c5f15477882ef0d',
'encrypted_recipient_data': 'ae4ae7ed0b821d8bbb394f8cd3013ed6c56d0b29baeddb1ce21fb8c34ce33ff59e2250758574924b03a1b567606479c7c9b0'}],
'payinfo': {'cltv_expiry_delta': 18,
+ 'htlc_maximum_msat': 2100000000000000000,
+ 'htlc_minimum_msat': 0,
'features': '',
'fee_base_msat': 0,
'fee_proportional_millionths': 0}}],
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.