@@ -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 | UpfrontShutdownScript ,
85
+ // Byte 1
86
+ VariableLengthOnion | PaymentSecret ,
87
+ // Byte 2
88
+ BasicMPP ,
89
+ ] ,
90
+ unsupported_features: [
91
+ // Byte 0
92
+ InitialRoutingSync ,
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.
@@ -120,20 +209,6 @@ mod sealed { // You should just use the type aliases instead.
120
209
"Feature flags for `payment_secret`." ) ;
121
210
define_feature ! ( 16 , 17 , BasicMPP , [ InitContext , NodeContext ] ,
122
211
"Feature flags for `basic_mpp`." ) ;
123
-
124
- /// Generates a feature flag byte with the given features set as optional. Useful for initializing
125
- /// the flags within [`Features`].
126
- ///
127
- /// [`Features`]: struct.Features.html
128
- macro_rules! feature_flags {
129
- ( $context: ty; $( $feature: ident) |* ) => {
130
- ( 0b00_00_00_00
131
- $(
132
- | <$context as sealed:: $feature>:: OPTIONAL_MASK
133
- ) *
134
- )
135
- }
136
- }
137
212
}
138
213
139
214
/// Tracks the set of features which a node implements, templated by the context in which it
@@ -171,18 +246,6 @@ pub type NodeFeatures = Features<sealed::NodeContext>;
171
246
pub type ChannelFeatures = Features < sealed:: ChannelContext > ;
172
247
173
248
impl InitFeatures {
174
- /// Create a Features with the features we support
175
- pub fn supported ( ) -> InitFeatures {
176
- InitFeatures {
177
- flags : vec ! [
178
- feature_flags![ sealed:: InitContext ; DataLossProtect | UpfrontShutdownScript ] ,
179
- feature_flags![ sealed:: InitContext ; VariableLengthOnion | PaymentSecret ] ,
180
- feature_flags![ sealed:: InitContext ; BasicMPP ] ,
181
- ] ,
182
- mark : PhantomData ,
183
- }
184
- }
185
-
186
249
/// Writes all features present up to, and including, 13.
187
250
pub ( crate ) fn write_up_to_13 < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
188
251
let len = cmp:: min ( 2 , self . flags . len ( ) ) ;
@@ -212,22 +275,6 @@ impl InitFeatures {
212
275
}
213
276
214
277
impl ChannelFeatures {
215
- /// Create a Features with the features we support
216
- #[ cfg( not( feature = "fuzztarget" ) ) ]
217
- pub ( crate ) fn supported ( ) -> ChannelFeatures {
218
- ChannelFeatures {
219
- flags : Vec :: new ( ) ,
220
- mark : PhantomData ,
221
- }
222
- }
223
- #[ cfg( feature = "fuzztarget" ) ]
224
- pub fn supported ( ) -> ChannelFeatures {
225
- ChannelFeatures {
226
- flags : Vec :: new ( ) ,
227
- mark : PhantomData ,
228
- }
229
- }
230
-
231
278
/// Takes the flags that we know how to interpret in an init-context features that are also
232
279
/// relevant in a channel-context features and creates a channel-context features from them.
233
280
pub ( crate ) fn with_known_relevant_init_flags ( _init_ctx : & InitFeatures ) -> Self {
@@ -237,54 +284,17 @@ impl ChannelFeatures {
237
284
}
238
285
239
286
impl NodeFeatures {
240
- /// Create a Features with the features we support
241
- #[ cfg( not( feature = "fuzztarget" ) ) ]
242
- pub ( crate ) fn supported ( ) -> NodeFeatures {
243
- NodeFeatures {
244
- flags : vec ! [
245
- feature_flags![ sealed:: NodeContext ; DataLossProtect | UpfrontShutdownScript ] ,
246
- feature_flags![ sealed:: NodeContext ; VariableLengthOnion | PaymentSecret ] ,
247
- feature_flags![ sealed:: NodeContext ; BasicMPP ] ,
248
- ] ,
249
- mark : PhantomData ,
250
- }
251
- }
252
- #[ cfg( feature = "fuzztarget" ) ]
253
- pub fn supported ( ) -> NodeFeatures {
254
- NodeFeatures {
255
- flags : vec ! [
256
- feature_flags![ sealed:: NodeContext ; DataLossProtect | UpfrontShutdownScript ] ,
257
- feature_flags![ sealed:: NodeContext ; VariableLengthOnion | PaymentSecret ] ,
258
- feature_flags![ sealed:: NodeContext ; BasicMPP ] ,
259
- ] ,
260
- mark : PhantomData ,
261
- }
262
- }
263
-
264
287
/// Takes the flags that we know how to interpret in an init-context features that are also
265
288
/// relevant in a node-context features and creates a node-context features from them.
266
289
/// Be sure to blank out features that are unknown to us.
267
290
pub ( crate ) fn with_known_relevant_init_flags ( init_ctx : & InitFeatures ) -> Self {
268
- // Generates a bitmask with both even and odd bits set for the given features. Bitwise
269
- // AND-ing it with a byte will select only common features.
270
- macro_rules! features_including {
271
- ( $( $feature: ident) |* ) => {
272
- ( 0b00_00_00_00
273
- $(
274
- | <sealed:: NodeContext as sealed:: $feature>:: REQUIRED_MASK
275
- | <sealed:: NodeContext as sealed:: $feature>:: OPTIONAL_MASK
276
- ) *
277
- )
278
- }
279
- }
291
+ use ln:: features:: sealed:: Context ;
292
+ let byte_count = sealed:: NodeContext :: KNOWN_FEATURE_MASK . len ( ) ;
280
293
281
294
let mut flags = Vec :: new ( ) ;
282
- for ( i, feature_byte) in init_ctx. flags . iter ( ) . enumerate ( ) {
283
- match i {
284
- 0 => flags. push ( feature_byte & features_including ! [ DataLossProtect | UpfrontShutdownScript ] ) ,
285
- 1 => flags. push ( feature_byte & features_including ! [ VariableLengthOnion | PaymentSecret ] ) ,
286
- 2 => flags. push ( feature_byte & features_including ! [ BasicMPP ] ) ,
287
- _ => ( ) ,
295
+ for ( i, feature_byte) in init_ctx. flags . iter ( ) . enumerate ( ) {
296
+ if i < byte_count {
297
+ flags. push ( feature_byte & sealed:: NodeContext :: KNOWN_FEATURE_MASK [ i] ) ;
288
298
}
289
299
}
290
300
Self { flags, mark : PhantomData , }
@@ -300,6 +310,14 @@ impl<T: sealed::Context> Features<T> {
300
310
}
301
311
}
302
312
313
+ /// Creates features supported by the implementation.
314
+ pub fn supported ( ) -> Features < T > {
315
+ Self {
316
+ flags : T :: SUPPORTED_FEATURE_FLAGS . to_vec ( ) ,
317
+ mark : PhantomData ,
318
+ }
319
+ }
320
+
303
321
#[ cfg( test) ]
304
322
/// Create a Features given a set of flags, in LE.
305
323
pub fn from_le_bytes ( flags : Vec < u8 > ) -> Features < T > {
@@ -316,49 +334,35 @@ impl<T: sealed::Context> Features<T> {
316
334
}
317
335
318
336
pub ( crate ) fn requires_unknown_bits ( & self ) -> bool {
319
- // Generates a bitmask with all even bits set except for the given features. Bitwise
320
- // AND-ing it with a byte will select unknown required features.
321
- macro_rules! features_excluding {
322
- ( $( $feature: ident) |* ) => {
323
- ( 0b01_01_01_01
324
- $(
325
- & !( <sealed:: InitContext as sealed:: $feature>:: REQUIRED_MASK )
326
- ) *
327
- )
328
- }
329
- }
330
-
331
- self . flags . iter ( ) . enumerate ( ) . any ( |( idx, & byte) | {
332
- ( match idx {
333
- 0 => ( byte & features_excluding ! [ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ) ,
334
- 1 => ( byte & features_excluding ! [ VariableLengthOnion | PaymentSecret ] ) ,
335
- 2 => ( byte & features_excluding ! [ BasicMPP ] ) ,
336
- _ => ( byte & features_excluding ! [ ] ) ,
337
- } ) != 0
337
+ use ln:: features:: sealed:: Context ;
338
+ let byte_count = sealed:: InitContext :: UNKNOWN_FEATURE_MASK . len ( ) ;
339
+
340
+ // Bitwise AND-ing with all even bits set except for known features will select unknown
341
+ // required features.
342
+ self . flags . iter ( ) . enumerate ( ) . any ( |( i, & byte) | {
343
+ let required_features = 0b01_01_01_01 ;
344
+ let unknown_features = if i < byte_count {
345
+ sealed:: InitContext :: UNKNOWN_FEATURE_MASK [ i]
346
+ } else {
347
+ 0b11_11_11_11
348
+ } ;
349
+ ( byte & ( required_features & unknown_features) ) != 0
338
350
} )
339
351
}
340
352
341
353
pub ( crate ) fn supports_unknown_bits ( & self ) -> bool {
342
- // Generates a bitmask with all even and odd bits set except for the given features. Bitwise
343
- // AND-ing it with a byte will select unknown supported features.
344
- macro_rules! features_excluding {
345
- ( $( $feature: ident) |* ) => {
346
- ( 0b11_11_11_11
347
- $(
348
- & !( <sealed:: InitContext as sealed:: $feature>:: REQUIRED_MASK )
349
- & !( <sealed:: InitContext as sealed:: $feature>:: OPTIONAL_MASK )
350
- ) *
351
- )
352
- }
353
- }
354
-
355
- self . flags . iter ( ) . enumerate ( ) . any ( |( idx, & byte) | {
356
- ( match idx {
357
- 0 => ( byte & features_excluding ! [ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ) ,
358
- 1 => ( byte & features_excluding ! [ VariableLengthOnion | PaymentSecret ] ) ,
359
- 2 => ( byte & features_excluding ! [ BasicMPP ] ) ,
360
- _ => byte,
361
- } ) != 0
354
+ use ln:: features:: sealed:: Context ;
355
+ let byte_count = sealed:: InitContext :: UNKNOWN_FEATURE_MASK . len ( ) ;
356
+
357
+ // Bitwise AND-ing with all even and odd bits set except for known features will select
358
+ // unknown features.
359
+ self . flags . iter ( ) . enumerate ( ) . any ( |( i, & byte) | {
360
+ let unknown_features = if i < byte_count {
361
+ sealed:: InitContext :: UNKNOWN_FEATURE_MASK [ i]
362
+ } else {
363
+ 0b11_11_11_11
364
+ } ;
365
+ ( byte & unknown_features) != 0
362
366
} )
363
367
}
364
368
0 commit comments