Skip to content

Commit 75959ae

Browse files
committed
Attributable failures optional feature bit
Signal to senders that the node will return attributable failures. When the sender makes sure all path nodes supports this, they will be able to attribute every failure that may occur.
1 parent e587420 commit 75959ae

File tree

3 files changed

+38
-11
lines changed

3 files changed

+38
-11
lines changed

lightning-invoice/src/lib.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -597,12 +597,18 @@ impl InvoiceBuilder<tb::False, tb::False, tb::False, tb::False, tb::False, tb::F
597597
/// Construct new, empty `InvoiceBuilder`. All necessary fields have to be filled first before
598598
/// `InvoiceBuilder::build(self)` becomes available.
599599
pub fn new(currency: Currency) -> Self {
600+
let mut features = Bolt11InvoiceFeatures::empty();
601+
features.set_attributable_failures_optional();
602+
603+
let mut tagged_fields = Vec::with_capacity(8);
604+
tagged_fields.push(TaggedField::Features(features));
605+
600606
InvoiceBuilder {
601607
currency,
602608
amount: None,
603609
si_prefix: None,
604610
timestamp: None,
605-
tagged_fields: Vec::with_capacity(8),
611+
tagged_fields,
606612
error: None,
607613

608614
phantom_d: core::marker::PhantomData,

lightning-types/src/features.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ mod sealed {
154154
// Byte 3
155155
RouteBlinding | ShutdownAnySegwit | DualFund | Taproot,
156156
// Byte 4
157-
Quiescence | OnionMessages,
157+
Quiescence | OnionMessages | AttributableFailures,
158158
// Byte 5
159159
ProvideStorage | ChannelType | SCIDPrivacy,
160160
// Byte 6
@@ -175,7 +175,7 @@ mod sealed {
175175
// Byte 3
176176
RouteBlinding | ShutdownAnySegwit | DualFund | Taproot,
177177
// Byte 4
178-
Quiescence | OnionMessages,
178+
Quiescence | OnionMessages | AttributableFailures,
179179
// Byte 5
180180
ProvideStorage | ChannelType | SCIDPrivacy,
181181
// Byte 6
@@ -199,7 +199,7 @@ mod sealed {
199199
// Byte 3
200200
,
201201
// Byte 4
202-
,
202+
AttributableFailures,
203203
// Byte 5
204204
,
205205
// Byte 6
@@ -219,7 +219,7 @@ mod sealed {
219219
// Byte 3
220220
,
221221
// Byte 4
222-
,
222+
AttributableFailures,
223223
// Byte 5
224224
,
225225
// Byte 6
@@ -548,6 +548,16 @@ mod sealed {
548548
supports_quiescence,
549549
requires_quiescence
550550
);
551+
define_feature!(
552+
37,
553+
AttributableFailures,
554+
[InitContext, NodeContext, Bolt11InvoiceContext, Bolt12InvoiceContext],
555+
"Feature flags for `option_attributable_failures`.",
556+
set_attributable_failures_optional,
557+
set_attributable_failures_required,
558+
supports_attributable_failures,
559+
requires_attributable_failures
560+
);
551561
define_feature!(
552562
39,
553563
OnionMessages,

lightning/src/offers/invoice.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -413,14 +413,17 @@ macro_rules! invoice_builder_methods {
413413
payment_paths: Vec<BlindedPaymentPath>, created_at: Duration,
414414
payment_hash: PaymentHash, amount_msats: u64, signing_pubkey: PublicKey,
415415
) -> InvoiceFields {
416+
let mut features = Bolt12InvoiceFeatures::empty();
417+
features.set_attributable_failures_optional();
418+
416419
InvoiceFields {
417420
payment_paths,
418421
created_at,
419422
relative_expiry: None,
420423
payment_hash,
421424
amount_msats,
422425
fallbacks: None,
423-
features: Bolt12InvoiceFeatures::empty(),
426+
features,
424427
signing_pubkey,
425428
#[cfg(test)]
426429
experimental_baz: None,
@@ -1878,7 +1881,10 @@ mod tests {
18781881
assert!(!unsigned_invoice.is_expired());
18791882
assert_eq!(unsigned_invoice.payment_hash(), payment_hash);
18801883
assert!(unsigned_invoice.fallbacks().is_empty());
1881-
assert_eq!(unsigned_invoice.invoice_features(), &Bolt12InvoiceFeatures::empty());
1884+
1885+
let mut expected_features = Bolt12InvoiceFeatures::empty();
1886+
expected_features.set_attributable_failures_optional();
1887+
assert_eq!(unsigned_invoice.invoice_features(), &expected_features);
18821888

18831889
match UnsignedBolt12Invoice::try_from(buffer) {
18841890
Err(e) => panic!("error parsing unsigned invoice: {:?}", e),
@@ -1926,7 +1932,7 @@ mod tests {
19261932
assert!(!invoice.is_expired());
19271933
assert_eq!(invoice.payment_hash(), payment_hash);
19281934
assert!(invoice.fallbacks().is_empty());
1929-
assert_eq!(invoice.invoice_features(), &Bolt12InvoiceFeatures::empty());
1935+
assert_eq!(invoice.invoice_features(), &expected_features);
19301936
assert!(!invoice.is_for_refund_without_paths());
19311937

19321938
let message = TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &invoice.bytes);
@@ -1974,7 +1980,7 @@ mod tests {
19741980
payment_hash: Some(&payment_hash),
19751981
amount: Some(1000),
19761982
fallbacks: None,
1977-
features: None,
1983+
features: Some(&expected_features),
19781984
node_id: Some(&recipient_pubkey()),
19791985
message_paths: None,
19801986
},
@@ -2009,6 +2015,9 @@ mod tests {
20092015
let mut buffer = Vec::new();
20102016
invoice.write(&mut buffer).unwrap();
20112017

2018+
let mut expected_features = Bolt12InvoiceFeatures::empty();
2019+
expected_features.set_attributable_failures_optional();
2020+
20122021
assert_eq!(invoice.bytes, buffer.as_slice());
20132022
assert_eq!(invoice.payer_metadata(), &[1; 32]);
20142023
assert_eq!(invoice.offer_chains(), None);
@@ -2034,7 +2043,7 @@ mod tests {
20342043
assert!(!invoice.is_expired());
20352044
assert_eq!(invoice.payment_hash(), payment_hash);
20362045
assert!(invoice.fallbacks().is_empty());
2037-
assert_eq!(invoice.invoice_features(), &Bolt12InvoiceFeatures::empty());
2046+
assert_eq!(invoice.invoice_features(), &expected_features);
20382047
assert!(invoice.is_for_refund_without_paths());
20392048

20402049
let message = TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &invoice.bytes);
@@ -2077,7 +2086,7 @@ mod tests {
20772086
payment_hash: Some(&payment_hash),
20782087
amount: Some(1000),
20792088
fallbacks: None,
2080-
features: None,
2089+
features: Some(&expected_features),
20812090
node_id: Some(&recipient_pubkey()),
20822091
message_paths: None,
20832092
},
@@ -2501,6 +2510,7 @@ mod tests {
25012510

25022511
let mut features = Bolt12InvoiceFeatures::empty();
25032512
features.set_basic_mpp_optional();
2513+
features.set_attributable_failures_optional();
25042514

25052515
let invoice = OfferBuilder::new(recipient_pubkey())
25062516
.amount_msats(1000)
@@ -2838,6 +2848,7 @@ mod tests {
28382848
Ok(invoice) => {
28392849
let mut features = Bolt12InvoiceFeatures::empty();
28402850
features.set_basic_mpp_optional();
2851+
features.set_attributable_failures_optional();
28412852
assert_eq!(invoice.invoice_features(), &features);
28422853
},
28432854
Err(e) => panic!("error parsing invoice: {:?}", e),

0 commit comments

Comments
 (0)