@@ -18,17 +18,106 @@ use std::marker::PhantomData;
18
18
use ln:: msgs:: DecodeError ;
19
19
use util:: ser:: { Readable , Writeable , Writer } ;
20
20
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
+ } ) ;
32
121
33
122
/// Defines a feature with the given bits for the specified [`Context`]s. The generated trait is
34
123
/// useful for manipulating feature flags.
@@ -122,20 +211,6 @@ mod sealed { // You should just use the type aliases instead.
122
211
"Feature flags for `payment_secret`." ) ;
123
212
define_feature ! ( 17 , BasicMPP , [ InitContext , NodeContext ] ,
124
213
"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
- }
139
214
}
140
215
141
216
/// 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>;
173
248
pub type ChannelFeatures = Features < sealed:: ChannelContext > ;
174
249
175
250
impl 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
-
188
251
/// Writes all features present up to, and including, 13.
189
252
pub ( crate ) fn write_up_to_13 < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
190
253
let len = cmp:: min ( 2 , self . flags . len ( ) ) ;
@@ -214,22 +277,6 @@ impl InitFeatures {
214
277
}
215
278
216
279
impl 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
-
233
280
/// Takes the flags that we know how to interpret in an init-context features that are also
234
281
/// relevant in a channel-context features and creates a channel-context features from them.
235
282
pub ( crate ) fn with_known_relevant_init_flags ( _init_ctx : & InitFeatures ) -> Self {
@@ -239,54 +286,17 @@ impl ChannelFeatures {
239
286
}
240
287
241
288
impl 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
-
266
289
/// Takes the flags that we know how to interpret in an init-context features that are also
267
290
/// relevant in a node-context features and creates a node-context features from them.
268
291
/// Be sure to blank out features that are unknown to us.
269
292
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 ( ) ;
282
295
283
296
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] ) ;
290
300
}
291
301
}
292
302
Self { flags, mark : PhantomData , }
@@ -302,6 +312,14 @@ impl<T: sealed::Context> Features<T> {
302
312
}
303
313
}
304
314
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
+
305
323
#[ cfg( test) ]
306
324
/// Create a Features given a set of flags, in LE.
307
325
pub fn from_le_bytes ( flags : Vec < u8 > ) -> Features < T > {
@@ -318,49 +336,35 @@ impl<T: sealed::Context> Features<T> {
318
336
}
319
337
320
338
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
340
352
} )
341
353
}
342
354
343
355
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
364
368
} )
365
369
}
366
370
0 commit comments