@@ -18,17 +18,106 @@ use std::marker::PhantomData;
1818use ln:: msgs:: DecodeError ;
1919use util:: ser:: { Readable , Writeable , Writer } ;
2020
21- #[ macro_use]
22- mod sealed { // You should just use the type aliases instead.
23- pub struct InitContext { }
24- pub struct NodeContext { }
25- pub struct ChannelContext { }
26-
27- /// An internal trait capturing the various feature context types
28- pub trait Context { }
29- impl Context for InitContext { }
30- impl Context for NodeContext { }
31- impl Context for ChannelContext { }
21+ mod sealed {
22+ /// The context in which [`Features`] are applicable. Defines which features are supported.
23+ ///
24+ /// [`Features`]: ../struct.Features.html
25+ pub trait Context {
26+ /// Features that are supported by the implementation, indicated by setting their
27+ /// optional (odd) bits.
28+ const SUPPORTED_FEATURE_FLAGS : & ' static [ u8 ] ;
29+
30+ /// Bitmask for selecting features that are known though not necessarily implemented.
31+ const KNOWN_FEATURE_MASK : & ' static [ u8 ] ;
32+
33+ /// Bitmask for selecting features that are unknown to the implementation.
34+ const UNKNOWN_FEATURE_MASK : & ' static [ u8 ] ;
35+ }
36+
37+ /// Defines a [`Context`] by stating which features it does and does not support. Features are
38+ /// specified as a comma-separated list of bytes where each byte is a pipe-delimited list of
39+ /// feature identifiers.
40+ ///
41+ /// [`Context`]: trait.Context.html
42+ macro_rules! define_context {
43+ ( $context: ident {
44+ supported_features: [ $( $( $supported_feature: ident ) |* , ) * ] ,
45+ unsupported_features: [ $( $( $unsupported_feature: ident ) |* , ) * ] ,
46+ } ) => {
47+ pub struct $context { }
48+
49+ impl Context for $context {
50+ const SUPPORTED_FEATURE_FLAGS : & ' static [ u8 ] = & [
51+ $(
52+ 0b00_00_00_00 $( | <Self as $supported_feature>:: OPTIONAL_MASK ) * ,
53+ ) *
54+ ] ;
55+
56+ const KNOWN_FEATURE_MASK : & ' static [ u8 ] = & [
57+ $(
58+ 0b00_00_00_00 $( |
59+ <Self as $supported_feature>:: REQUIRED_MASK |
60+ <Self as $supported_feature>:: OPTIONAL_MASK ) *
61+ $( |
62+ <Self as $unsupported_feature>:: REQUIRED_MASK |
63+ <Self as $unsupported_feature>:: OPTIONAL_MASK ) * ,
64+ ) *
65+ ] ;
66+
67+ const UNKNOWN_FEATURE_MASK : & ' static [ u8 ] = & [
68+ $(
69+ 0b11_11_11_11 $( &
70+ !<Self as $supported_feature>:: REQUIRED_MASK &
71+ !<Self as $supported_feature>:: OPTIONAL_MASK ) *
72+ $( &
73+ !<Self as $unsupported_feature>:: REQUIRED_MASK &
74+ !<Self as $unsupported_feature>:: OPTIONAL_MASK ) * ,
75+ ) *
76+ ] ;
77+ }
78+ } ;
79+ }
80+
81+ define_context ! ( InitContext {
82+ supported_features: [
83+ // Byte 0
84+ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ,
85+ // Byte 1
86+ VariableLengthOnion | PaymentSecret ,
87+ // Byte 2
88+ BasicMPP ,
89+ ] ,
90+ unsupported_features: [
91+ // Byte 0
92+ ,
93+ // Byte 1
94+ ,
95+ // Byte 2
96+ ,
97+ ] ,
98+ } ) ;
99+ define_context ! ( NodeContext {
100+ supported_features: [
101+ // Byte 0
102+ DataLossProtect | UpfrontShutdownScript ,
103+ // Byte 1
104+ VariableLengthOnion | PaymentSecret ,
105+ // Byte 2
106+ BasicMPP ,
107+ ] ,
108+ unsupported_features: [
109+ // Byte 0
110+ ,
111+ // Byte 1
112+ ,
113+ // Byte 2
114+ ,
115+ ] ,
116+ } ) ;
117+ define_context ! ( ChannelContext {
118+ supported_features: [ ] ,
119+ unsupported_features: [ ] ,
120+ } ) ;
32121
33122 /// Defines a feature with the given bits for the specified [`Context`]s. The generated trait is
34123 /// useful for manipulating feature flags.
@@ -122,20 +211,6 @@ mod sealed { // You should just use the type aliases instead.
122211 "Feature flags for `payment_secret`." ) ;
123212 define_feature ! ( 17 , BasicMPP , [ InitContext , NodeContext ] ,
124213 "Feature flags for `basic_mpp`." ) ;
125-
126- /// Generates a feature flag byte with the given features set as optional. Useful for initializing
127- /// the flags within [`Features`].
128- ///
129- /// [`Features`]: struct.Features.html
130- macro_rules! feature_flags {
131- ( $context: ty; $( $feature: ident) |* ) => {
132- ( 0b00_00_00_00
133- $(
134- | <$context as sealed:: $feature>:: OPTIONAL_MASK
135- ) *
136- )
137- }
138- }
139214}
140215
141216/// Tracks the set of features which a node implements, templated by the context in which it
@@ -173,18 +248,6 @@ pub type NodeFeatures = Features<sealed::NodeContext>;
173248pub type ChannelFeatures = Features < sealed:: ChannelContext > ;
174249
175250impl InitFeatures {
176- /// Create a Features with the features we support
177- pub fn supported ( ) -> InitFeatures {
178- InitFeatures {
179- flags : vec ! [
180- feature_flags![ sealed:: InitContext ; DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ,
181- feature_flags![ sealed:: InitContext ; VariableLengthOnion | PaymentSecret ] ,
182- feature_flags![ sealed:: InitContext ; BasicMPP ] ,
183- ] ,
184- mark : PhantomData ,
185- }
186- }
187-
188251 /// Writes all features present up to, and including, 13.
189252 pub ( crate ) fn write_up_to_13 < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
190253 let len = cmp:: min ( 2 , self . flags . len ( ) ) ;
@@ -214,22 +277,6 @@ impl InitFeatures {
214277}
215278
216279impl ChannelFeatures {
217- /// Create a Features with the features we support
218- #[ cfg( not( feature = "fuzztarget" ) ) ]
219- pub ( crate ) fn supported ( ) -> ChannelFeatures {
220- ChannelFeatures {
221- flags : Vec :: new ( ) ,
222- mark : PhantomData ,
223- }
224- }
225- #[ cfg( feature = "fuzztarget" ) ]
226- pub fn supported ( ) -> ChannelFeatures {
227- ChannelFeatures {
228- flags : Vec :: new ( ) ,
229- mark : PhantomData ,
230- }
231- }
232-
233280 /// Takes the flags that we know how to interpret in an init-context features that are also
234281 /// relevant in a channel-context features and creates a channel-context features from them.
235282 pub ( crate ) fn with_known_relevant_init_flags ( _init_ctx : & InitFeatures ) -> Self {
@@ -239,54 +286,17 @@ impl ChannelFeatures {
239286}
240287
241288impl NodeFeatures {
242- /// Create a Features with the features we support
243- #[ cfg( not( feature = "fuzztarget" ) ) ]
244- pub ( crate ) fn supported ( ) -> NodeFeatures {
245- NodeFeatures {
246- flags : vec ! [
247- feature_flags![ sealed:: NodeContext ; DataLossProtect | UpfrontShutdownScript ] ,
248- feature_flags![ sealed:: NodeContext ; VariableLengthOnion | PaymentSecret ] ,
249- feature_flags![ sealed:: NodeContext ; BasicMPP ] ,
250- ] ,
251- mark : PhantomData ,
252- }
253- }
254- #[ cfg( feature = "fuzztarget" ) ]
255- pub fn supported ( ) -> NodeFeatures {
256- NodeFeatures {
257- flags : vec ! [
258- feature_flags![ sealed:: NodeContext ; DataLossProtect | UpfrontShutdownScript ] ,
259- feature_flags![ sealed:: NodeContext ; VariableLengthOnion | PaymentSecret ] ,
260- feature_flags![ sealed:: NodeContext ; BasicMPP ] ,
261- ] ,
262- mark : PhantomData ,
263- }
264- }
265-
266289 /// Takes the flags that we know how to interpret in an init-context features that are also
267290 /// relevant in a node-context features and creates a node-context features from them.
268291 /// Be sure to blank out features that are unknown to us.
269292 pub ( crate ) fn with_known_relevant_init_flags ( init_ctx : & InitFeatures ) -> Self {
270- // Generates a bitmask with both even and odd bits set for the given features. Bitwise
271- // AND-ing it with a byte will select only common features.
272- macro_rules! features_including {
273- ( $( $feature: ident) |* ) => {
274- ( 0b00_00_00_00
275- $(
276- | <sealed:: NodeContext as sealed:: $feature>:: REQUIRED_MASK
277- | <sealed:: NodeContext as sealed:: $feature>:: OPTIONAL_MASK
278- ) *
279- )
280- }
281- }
293+ use ln:: features:: sealed:: Context ;
294+ let byte_count = sealed:: NodeContext :: KNOWN_FEATURE_MASK . len ( ) ;
282295
283296 let mut flags = Vec :: new ( ) ;
284- for ( i, feature_byte) in init_ctx. flags . iter ( ) . enumerate ( ) {
285- match i {
286- 0 => flags. push ( feature_byte & features_including ! [ DataLossProtect | UpfrontShutdownScript ] ) ,
287- 1 => flags. push ( feature_byte & features_including ! [ VariableLengthOnion | PaymentSecret ] ) ,
288- 2 => flags. push ( feature_byte & features_including ! [ BasicMPP ] ) ,
289- _ => ( ) ,
297+ for ( i, feature_byte) in init_ctx. flags . iter ( ) . enumerate ( ) {
298+ if i < byte_count {
299+ flags. push ( feature_byte & sealed:: NodeContext :: KNOWN_FEATURE_MASK [ i] ) ;
290300 }
291301 }
292302 Self { flags, mark : PhantomData , }
@@ -302,6 +312,14 @@ impl<T: sealed::Context> Features<T> {
302312 }
303313 }
304314
315+ /// Creates features supported by the implementation.
316+ pub fn supported ( ) -> Features < T > {
317+ Self {
318+ flags : T :: SUPPORTED_FEATURE_FLAGS . to_vec ( ) ,
319+ mark : PhantomData ,
320+ }
321+ }
322+
305323 #[ cfg( test) ]
306324 /// Create a Features given a set of flags, in LE.
307325 pub fn from_le_bytes ( flags : Vec < u8 > ) -> Features < T > {
@@ -318,49 +336,35 @@ impl<T: sealed::Context> Features<T> {
318336 }
319337
320338 pub ( crate ) fn requires_unknown_bits ( & self ) -> bool {
321- // Generates a bitmask with all even bits set except for the given features. Bitwise
322- // AND-ing it with a byte will select unknown required features.
323- macro_rules! features_excluding {
324- ( $( $feature: ident) |* ) => {
325- ( 0b01_01_01_01
326- $(
327- & !( <sealed:: InitContext as sealed:: $feature>:: REQUIRED_MASK )
328- ) *
329- )
330- }
331- }
332-
333- self . flags . iter ( ) . enumerate ( ) . any ( |( idx, & byte) | {
334- ( match idx {
335- 0 => ( byte & features_excluding ! [ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ) ,
336- 1 => ( byte & features_excluding ! [ VariableLengthOnion | PaymentSecret ] ) ,
337- 2 => ( byte & features_excluding ! [ BasicMPP ] ) ,
338- _ => ( byte & features_excluding ! [ ] ) ,
339- } ) != 0
339+ use ln:: features:: sealed:: Context ;
340+ let byte_count = sealed:: InitContext :: UNKNOWN_FEATURE_MASK . len ( ) ;
341+
342+ // Bitwise AND-ing with all even bits set except for known features will select unknown
343+ // required features.
344+ self . flags . iter ( ) . enumerate ( ) . any ( |( i, & byte) | {
345+ let required_features = 0b01_01_01_01 ;
346+ let unknown_features = if i < byte_count {
347+ sealed:: InitContext :: UNKNOWN_FEATURE_MASK [ i]
348+ } else {
349+ 0b11_11_11_11
350+ } ;
351+ ( byte & ( required_features & unknown_features) ) != 0
340352 } )
341353 }
342354
343355 pub ( crate ) fn supports_unknown_bits ( & self ) -> bool {
344- // Generates a bitmask with all even and odd bits set except for the given features. Bitwise
345- // AND-ing it with a byte will select unknown supported features.
346- macro_rules! features_excluding {
347- ( $( $feature: ident) |* ) => {
348- ( 0b11_11_11_11
349- $(
350- & !( <sealed:: InitContext as sealed:: $feature>:: REQUIRED_MASK )
351- & !( <sealed:: InitContext as sealed:: $feature>:: OPTIONAL_MASK )
352- ) *
353- )
354- }
355- }
356-
357- self . flags . iter ( ) . enumerate ( ) . any ( |( idx, & byte) | {
358- ( match idx {
359- 0 => ( byte & features_excluding ! [ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ) ,
360- 1 => ( byte & features_excluding ! [ VariableLengthOnion | PaymentSecret ] ) ,
361- 2 => ( byte & features_excluding ! [ BasicMPP ] ) ,
362- _ => byte,
363- } ) != 0
356+ use ln:: features:: sealed:: Context ;
357+ let byte_count = sealed:: InitContext :: UNKNOWN_FEATURE_MASK . len ( ) ;
358+
359+ // Bitwise AND-ing with all even and odd bits set except for known features will select
360+ // unknown features.
361+ self . flags . iter ( ) . enumerate ( ) . any ( |( i, & byte) | {
362+ let unknown_features = if i < byte_count {
363+ sealed:: InitContext :: UNKNOWN_FEATURE_MASK [ i]
364+ } else {
365+ 0b11_11_11_11
366+ } ;
367+ ( byte & unknown_features) != 0
364368 } )
365369 }
366370
0 commit comments