+ /// Assertion that [`EVEN_BIT`] is actually even.
+ ///
+ /// [`EVEN_BIT`]: #associatedconstant.EVEN_BIT
+ const ASSERT_EVEN_BIT_PARITY: usize;
+
+ /// Assertion that [`ODD_BIT`] is actually odd.
+ ///
+ /// [`ODD_BIT`]: #associatedconstant.ODD_BIT
+ const ASSERT_ODD_BIT_PARITY: usize;
+
+ /// The byte where the feature is set.
+ const BYTE_OFFSET: usize = Self::EVEN_BIT / 8;
+
+ /// The bitmask for the feature's required flag relative to the [`BYTE_OFFSET`].
+ ///
+ /// [`BYTE_OFFSET`]: #associatedconstant.BYTE_OFFSET
+ const REQUIRED_MASK: u8 = 1 << (Self::EVEN_BIT - 8 * Self::BYTE_OFFSET);
+
+ /// The bitmask for the feature's optional flag relative to the [`BYTE_OFFSET`].
+ ///
+ /// [`BYTE_OFFSET`]: #associatedconstant.BYTE_OFFSET
+ const OPTIONAL_MASK: u8 = 1 << (Self::ODD_BIT - 8 * Self::BYTE_OFFSET);
+
+ /// Returns whether the feature is supported by the given flags.
+ #[inline]
+ fn supports_feature(flags: &Vec<u8>) -> bool {
+ flags.len() > Self::BYTE_OFFSET &&
+ (flags[Self::BYTE_OFFSET] & (Self::REQUIRED_MASK | Self::OPTIONAL_MASK)) != 0
+ }
+
+ /// Sets the feature's optional (odd) bit in the given flags.
+ #[inline]
+ fn set_optional_bit(flags: &mut Vec<u8>) {
+ if flags.len() <= Self::BYTE_OFFSET {
+ flags.resize(Self::BYTE_OFFSET + 1, 0u8);
+ }
+
+ flags[Self::BYTE_OFFSET] |= Self::OPTIONAL_MASK;
+ }
+
+ /// Clears the feature's optional (odd) bit from the given flags.
+ #[inline]
+ fn clear_optional_bit(flags: &mut Vec<u8>) {
+ if flags.len() > Self::BYTE_OFFSET {
+ flags[Self::BYTE_OFFSET] &= !Self::OPTIONAL_MASK;
+ }
+ }
+ }
+
+ $(
+ impl $feature for $context {
+ // EVEN_BIT % 2 == 0
+ const ASSERT_EVEN_BIT_PARITY: usize = 0 - (<Self as $feature>::EVEN_BIT % 2);
+
+ // ODD_BIT % 2 == 1
+ const ASSERT_ODD_BIT_PARITY: usize = (<Self as $feature>::ODD_BIT % 2) - 1;
+ }
+ )*
+ }
+ }
+
+ define_feature!(1, DataLossProtect, [InitContext, NodeContext],
+ "Feature flags for `option_data_loss_protect`.");
+ // NOTE: Per Bolt #9, initial_routing_sync has no even bit.
+ define_feature!(3, InitialRoutingSync, [InitContext],
+ "Feature flags for `initial_routing_sync`.");
+ define_feature!(5, UpfrontShutdownScript, [InitContext, NodeContext],
+ "Feature flags for `option_upfront_shutdown_script`.");
+ define_feature!(9, VariableLengthOnion, [InitContext, NodeContext],
+ "Feature flags for `var_onion_optin`.");
+ define_feature!(15, PaymentSecret, [InitContext, NodeContext],
+ "Feature flags for `payment_secret`.");
+ define_feature!(17, BasicMPP, [InitContext, NodeContext],
+ "Feature flags for `basic_mpp`.");
+
+ /// Generates a feature flag byte with the given features set as optional. Useful for initializing
+ /// the flags within [`Features`].
+ ///
+ /// [`Features`]: struct.Features.html
+ macro_rules! feature_flags {
+ ($context: ty; $($feature: ident)|*) => {
+ (0b00_00_00_00
+ $(
+ | <$context as sealed::$feature>::OPTIONAL_MASK
+ )*
+ )
+ }
+ }