Skip to content

Commit 883908c

Browse files
committed
Add Features::set_{required|optional}_custom_bit
Custom message handlers may need to set feature bits that are unknown to LDK. Provide Features::set_required_custom_bit and Features::set_optional_custom_bit to allow for this.
1 parent 3ce87a3 commit 883908c

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

lightning/src/ln/features.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,50 @@ impl<T: sealed::Context> Features<T> {
746746
}
747747
true
748748
}
749+
750+
/// Sets a required custom feature bit. Errors if `bit` is outside the custom range as defined
751+
/// by [bLIP 2] or if it is a known `T` feature.
752+
///
753+
/// Note: Required bits are even. If an odd bit is given, then the corresponding even bit will
754+
/// be set instead (i.e., `bit - 1`).
755+
///
756+
/// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits
757+
pub fn set_required_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
758+
self.set_custom_bit(bit - (bit % 2))
759+
}
760+
761+
/// Sets an optional custom feature bit. Errors if `bit` is outside the custom range as defined
762+
/// by [bLIP 2] or if it is a known `T` feature.
763+
///
764+
/// Note: Optional bits are odd. If an even bit is given, then the corresponding odd bit will be
765+
/// set instead (i.e., `bit + 1`).
766+
///
767+
/// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits
768+
pub fn set_optional_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
769+
self.set_custom_bit(bit + (1 - (bit % 2)))
770+
}
771+
772+
fn set_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
773+
if bit < 256 {
774+
return Err(());
775+
}
776+
777+
let byte_offset = bit / 8;
778+
let mask = 1 << (bit - 8 * byte_offset);
779+
if byte_offset < T::KNOWN_FEATURE_MASK.len() {
780+
if (T::KNOWN_FEATURE_MASK[byte_offset] & mask) != 0 {
781+
return Err(());
782+
}
783+
}
784+
785+
if self.flags.len() <= byte_offset {
786+
self.flags.resize(byte_offset + 1, 0u8);
787+
}
788+
789+
self.flags[byte_offset] |= mask;
790+
791+
Ok(())
792+
}
749793
}
750794

751795
impl<T: sealed::UpfrontShutdownScript> Features<T> {
@@ -984,6 +1028,36 @@ mod tests {
9841028
assert!(features.supports_payment_secret());
9851029
}
9861030

1031+
#[test]
1032+
fn set_custom_bits() {
1033+
let mut features = InvoiceFeatures::empty();
1034+
features.set_variable_length_onion_optional();
1035+
assert_eq!(features.flags[1], 0b00000010);
1036+
1037+
assert!(features.set_optional_custom_bit(255).is_err());
1038+
assert!(features.set_required_custom_bit(256).is_ok());
1039+
assert!(features.set_required_custom_bit(258).is_ok());
1040+
assert_eq!(features.flags[31], 0b00000000);
1041+
assert_eq!(features.flags[32], 0b00000101);
1042+
1043+
let known_bit = <sealed::InvoiceContext as sealed::PaymentSecret>::EVEN_BIT;
1044+
let byte_offset = <sealed::InvoiceContext as sealed::PaymentSecret>::BYTE_OFFSET;
1045+
assert_eq!(byte_offset, 1);
1046+
assert_eq!(features.flags[byte_offset], 0b00000010);
1047+
assert!(features.set_required_custom_bit(known_bit).is_err());
1048+
assert_eq!(features.flags[byte_offset], 0b00000010);
1049+
1050+
let mut features = InvoiceFeatures::empty();
1051+
assert!(features.set_optional_custom_bit(256).is_ok());
1052+
assert!(features.set_optional_custom_bit(259).is_ok());
1053+
assert_eq!(features.flags[32], 0b00001010);
1054+
1055+
let mut features = InvoiceFeatures::empty();
1056+
assert!(features.set_required_custom_bit(257).is_ok());
1057+
assert!(features.set_required_custom_bit(258).is_ok());
1058+
assert_eq!(features.flags[32], 0b00000101);
1059+
}
1060+
9871061
#[test]
9881062
fn encodes_features_without_length() {
9891063
let features = OfferFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]);

0 commit comments

Comments
 (0)