+
+ /// Getting a route for a keysend payment to a private node requires providing the payee's
+ /// features (since they were not announced in a node announcement). However, keysend payments
+ /// don't have an invoice to pull the payee's features from, so this method is provided for use in
+ /// [`PaymentParameters::for_keysend`], thus omitting the need for payers to manually construct an
+ /// `InvoiceFeatures` for [`find_route`].
+ ///
+ /// [`PaymentParameters::for_keysend`]: crate::routing::router::PaymentParameters::for_keysend
+ /// [`find_route`]: crate::routing::router::find_route
+ pub(crate) fn for_keysend() -> InvoiceFeatures {
+ let mut res = InvoiceFeatures::empty();
+ res.set_variable_length_onion_optional();
+ res
+ }
+}
+
+impl ChannelTypeFeatures {
+ /// Constructs the implicit channel type based on the common supported types between us and our
+ /// counterparty
+ pub(crate) fn from_counterparty_init(counterparty_init: &InitFeatures) -> Self {
+ let mut ret = counterparty_init.to_context_internal();
+ // ChannelTypeFeatures must only contain required bits, so we OR the required forms of all
+ // optional bits and then AND out the optional ones.
+ for byte in ret.flags.iter_mut() {
+ *byte |= (*byte & 0b10_10_10_10) >> 1;
+ *byte &= 0b01_01_01_01;
+ }
+ ret
+ }
+
+ /// Constructs a ChannelTypeFeatures with only static_remotekey set
+ pub(crate) fn only_static_remote_key() -> Self {
+ let mut ret = Self::empty();
+ <sealed::ChannelTypeContext as sealed::StaticRemoteKey>::set_required_bit(&mut ret.flags);
+ ret
+ }
+}
+
+impl ToBase32 for InvoiceFeatures {
+ fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
+ // Explanation for the "4": the normal way to round up when dividing is to add the divisor
+ // minus one before dividing
+ let length_u5s = (self.flags.len() * 8 + 4) / 5 as usize;
+ let mut res_u5s: Vec<u5> = vec![u5::try_from_u8(0).unwrap(); length_u5s];
+ for (byte_idx, byte) in self.flags.iter().enumerate() {
+ let bit_pos_from_left_0_indexed = byte_idx * 8;
+ let new_u5_idx = length_u5s - (bit_pos_from_left_0_indexed / 5) as usize - 1;
+ let new_bit_pos = bit_pos_from_left_0_indexed % 5;
+ let shifted_chunk_u16 = (*byte as u16) << new_bit_pos;
+ let curr_u5_as_u8 = res_u5s[new_u5_idx].to_u8();
+ res_u5s[new_u5_idx] = u5::try_from_u8(curr_u5_as_u8 | ((shifted_chunk_u16 & 0x001f) as u8)).unwrap();
+ if new_u5_idx > 0 {
+ let curr_u5_as_u8 = res_u5s[new_u5_idx - 1].to_u8();
+ res_u5s[new_u5_idx - 1] = u5::try_from_u8(curr_u5_as_u8 | (((shifted_chunk_u16 >> 5) & 0x001f) as u8)).unwrap();
+ }
+ if new_u5_idx > 1 {
+ let curr_u5_as_u8 = res_u5s[new_u5_idx - 2].to_u8();
+ res_u5s[new_u5_idx - 2] = u5::try_from_u8(curr_u5_as_u8 | (((shifted_chunk_u16 >> 10) & 0x001f) as u8)).unwrap();
+ }
+ }
+ // Trim the highest feature bits.
+ while !res_u5s.is_empty() && res_u5s[0] == u5::try_from_u8(0).unwrap() {
+ res_u5s.remove(0);
+ }
+ writer.write(&res_u5s)
+ }
+}
+
+impl Base32Len for InvoiceFeatures {
+ fn base32_len(&self) -> usize {
+ self.to_base32().len()
+ }
+}
+
+impl FromBase32 for InvoiceFeatures {
+ type Err = bech32::Error;
+
+ fn from_base32(field_data: &[u5]) -> Result<InvoiceFeatures, bech32::Error> {
+ // Explanation for the "7": the normal way to round up when dividing is to add the divisor
+ // minus one before dividing
+ let length_bytes = (field_data.len() * 5 + 7) / 8 as usize;
+ let mut res_bytes: Vec<u8> = vec![0; length_bytes];
+ for (u5_idx, chunk) in field_data.iter().enumerate() {
+ let bit_pos_from_right_0_indexed = (field_data.len() - u5_idx - 1) * 5;
+ let new_byte_idx = (bit_pos_from_right_0_indexed / 8) as usize;
+ let new_bit_pos = bit_pos_from_right_0_indexed % 8;
+ let chunk_u16 = chunk.to_u8() as u16;
+ res_bytes[new_byte_idx] |= ((chunk_u16 << new_bit_pos) & 0xff) as u8;
+ if new_byte_idx != length_bytes - 1 {
+ res_bytes[new_byte_idx + 1] |= ((chunk_u16 >> (8-new_bit_pos)) & 0xff) as u8;
+ }
+ }
+ // Trim the highest feature bits.
+ while !res_bytes.is_empty() && res_bytes[res_bytes.len() - 1] == 0 {
+ res_bytes.pop();
+ }
+ Ok(InvoiceFeatures::from_le_bytes(res_bytes))
+ }