@@ -8,6 +8,7 @@ use std::marker::PhantomData;
8
8
use ln:: msgs:: DecodeError ;
9
9
use util:: ser:: { Readable , Writeable , Writer } ;
10
10
11
+ #[ macro_use]
11
12
mod sealed { // You should just use the type aliases instead.
12
13
pub struct InitContext { }
13
14
pub struct NodeContext { }
@@ -19,28 +20,96 @@ mod sealed { // You should just use the type aliases instead.
19
20
impl Context for NodeContext { }
20
21
impl Context for ChannelContext { }
21
22
22
- pub trait DataLossProtect : Context { }
23
- impl DataLossProtect for InitContext { }
24
- impl DataLossProtect for NodeContext { }
25
-
26
- pub trait InitialRoutingSync : Context { }
27
- impl InitialRoutingSync for InitContext { }
28
-
29
- pub trait UpfrontShutdownScript : Context { }
30
- impl UpfrontShutdownScript for InitContext { }
31
- impl UpfrontShutdownScript for NodeContext { }
32
-
33
- pub trait VariableLengthOnion : Context { }
34
- impl VariableLengthOnion for InitContext { }
35
- impl VariableLengthOnion for NodeContext { }
23
+ /// Defines a feature with the given bits for the specified [`Context`]s. The generated trait is
24
+ /// useful for manipulating feature flags.
25
+ ///
26
+ /// [`Context`]: trait.Context.html
27
+ macro_rules! define_feature {
28
+ ( $even_bit: expr, $odd_bit: expr, $feature: ident, [ $( $context: ty) ,+] , $doc: expr) => {
29
+ #[ doc = $doc]
30
+ ///
31
+ /// See [BOLT #9] for details.
32
+ ///
33
+ /// [BOLT #9]: https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md
34
+ pub trait $feature: Context {
35
+ /// The bit used to signify that the feature is required.
36
+ const EVEN_BIT : usize = $even_bit;
37
+
38
+ /// The bit used to signify that the feature is optional.
39
+ const ODD_BIT : usize = $odd_bit;
40
+
41
+ /// The byte where the feature is set.
42
+ const BYTE_OFFSET : usize = Self :: EVEN_BIT / 8 ;
43
+
44
+ /// The bitmask for the feature's required flag relative to the [`BYTE_OFFSET`].
45
+ ///
46
+ /// [`BYTE_OFFSET`]: #associatedconstant.BYTE_OFFSET
47
+ const REQUIRED_MASK : u8 = 1 << ( Self :: EVEN_BIT - 8 * Self :: BYTE_OFFSET ) ;
48
+
49
+ /// The bitmask for the feature's optional flag relative to the [`BYTE_OFFSET`].
50
+ ///
51
+ /// [`BYTE_OFFSET`]: #associatedconstant.BYTE_OFFSET
52
+ const OPTIONAL_MASK : u8 = 1 << ( Self :: ODD_BIT - 8 * Self :: BYTE_OFFSET ) ;
53
+
54
+ /// Returns whether the feature is supported by the given flags.
55
+ #[ inline]
56
+ fn supports_feature( flags: & Vec <u8 >) -> bool {
57
+ flags. len( ) > Self :: BYTE_OFFSET &&
58
+ ( flags[ Self :: BYTE_OFFSET ] & ( Self :: REQUIRED_MASK | Self :: OPTIONAL_MASK ) ) != 0
59
+ }
60
+
61
+ /// Sets the feature's optional (odd) bit in the given flags.
62
+ #[ inline]
63
+ fn set_optional_bit( flags: & mut Vec <u8 >) {
64
+ if flags. len( ) <= Self :: BYTE_OFFSET {
65
+ flags. resize( Self :: BYTE_OFFSET + 1 , 0u8 ) ;
66
+ }
67
+
68
+ flags[ Self :: BYTE_OFFSET ] |= Self :: OPTIONAL_MASK ;
69
+ }
70
+
71
+ /// Clears the feature's optional (odd) bit from the given flags.
72
+ #[ inline]
73
+ fn clear_optional_bit( flags: & mut Vec <u8 >) {
74
+ if flags. len( ) > Self :: BYTE_OFFSET {
75
+ flags[ Self :: BYTE_OFFSET ] &= !Self :: OPTIONAL_MASK ;
76
+ }
77
+ }
78
+ }
36
79
37
- pub trait PaymentSecret : Context { }
38
- impl PaymentSecret for InitContext { }
39
- impl PaymentSecret for NodeContext { }
80
+ $(
81
+ impl $feature for $context { }
82
+ ) *
83
+ }
84
+ }
40
85
41
- pub trait BasicMPP : Context { }
42
- impl BasicMPP for InitContext { }
43
- impl BasicMPP for NodeContext { }
86
+ define_feature ! ( 0 , 1 , DataLossProtect , [ InitContext , NodeContext ] ,
87
+ "Feature flags for `option_data_loss_protect`." ) ;
88
+ // NOTE: Per Bolt #9, initial_routing_sync has no even bit.
89
+ define_feature ! ( 3 , 3 , InitialRoutingSync , [ InitContext ] ,
90
+ "Feature flags for `initial_routing_sync`." ) ;
91
+ define_feature ! ( 4 , 5 , UpfrontShutdownScript , [ InitContext , NodeContext ] ,
92
+ "Feature flags for `option_upfront_shutdown_script`." ) ;
93
+ define_feature ! ( 8 , 9 , VariableLengthOnion , [ InitContext , NodeContext ] ,
94
+ "Feature flags for `var_onion_optin`." ) ;
95
+ define_feature ! ( 14 , 15 , PaymentSecret , [ InitContext , NodeContext ] ,
96
+ "Feature flags for `payment_secret`." ) ;
97
+ define_feature ! ( 16 , 17 , BasicMPP , [ InitContext , NodeContext ] ,
98
+ "Feature flags for `basic_mpp`." ) ;
99
+
100
+ /// Generates a feature flag byte with the given features set as optional. Useful for initializing
101
+ /// the flags within [`Features`].
102
+ ///
103
+ /// [`Features`]: struct.Features.html
104
+ macro_rules! feature_flags {
105
+ ( $context: ty; $( $feature: ident) |* ) => {
106
+ ( 0b00_00_00_00
107
+ $(
108
+ | <$context as sealed:: $feature>:: OPTIONAL_MASK
109
+ ) *
110
+ )
111
+ }
112
+ }
44
113
}
45
114
46
115
/// Tracks the set of features which a node implements, templated by the context in which it
@@ -81,7 +150,11 @@ impl InitFeatures {
81
150
/// Create a Features with the features we support
82
151
pub fn supported ( ) -> InitFeatures {
83
152
InitFeatures {
84
- flags : vec ! [ 2 | 1 << 3 | 1 << 5 , 1 << ( 9 -8 ) | 1 << ( 15 - 8 ) , 1 << ( 17 - 8 * 2 ) ] ,
153
+ flags : vec ! [
154
+ feature_flags![ sealed:: InitContext ; DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ,
155
+ feature_flags![ sealed:: InitContext ; VariableLengthOnion | PaymentSecret ] ,
156
+ feature_flags![ sealed:: InitContext ; BasicMPP ] ,
157
+ ] ,
85
158
mark : PhantomData ,
86
159
}
87
160
}
@@ -144,14 +217,22 @@ impl NodeFeatures {
144
217
#[ cfg( not( feature = "fuzztarget" ) ) ]
145
218
pub ( crate ) fn supported ( ) -> NodeFeatures {
146
219
NodeFeatures {
147
- flags : vec ! [ 2 | 1 << 5 , 1 << ( 9 - 8 ) | 1 << ( 15 - 8 ) , 1 << ( 17 - 8 * 2 ) ] ,
220
+ flags : vec ! [
221
+ feature_flags![ sealed:: NodeContext ; DataLossProtect | UpfrontShutdownScript ] ,
222
+ feature_flags![ sealed:: NodeContext ; VariableLengthOnion | PaymentSecret ] ,
223
+ feature_flags![ sealed:: NodeContext ; BasicMPP ] ,
224
+ ] ,
148
225
mark : PhantomData ,
149
226
}
150
227
}
151
228
#[ cfg( feature = "fuzztarget" ) ]
152
229
pub fn supported ( ) -> NodeFeatures {
153
230
NodeFeatures {
154
- flags : vec ! [ 2 | 1 << 5 , 1 << ( 9 - 8 ) | 1 << ( 15 - 8 ) , 1 << ( 17 - 8 * 2 ) ] ,
231
+ flags : vec ! [
232
+ feature_flags![ sealed:: NodeContext ; DataLossProtect | UpfrontShutdownScript ] ,
233
+ feature_flags![ sealed:: NodeContext ; VariableLengthOnion | PaymentSecret ] ,
234
+ feature_flags![ sealed:: NodeContext ; BasicMPP ] ,
235
+ ] ,
155
236
mark : PhantomData ,
156
237
}
157
238
}
@@ -160,15 +241,25 @@ impl NodeFeatures {
160
241
/// relevant in a node-context features and creates a node-context features from them.
161
242
/// Be sure to blank out features that are unknown to us.
162
243
pub ( crate ) fn with_known_relevant_init_flags ( init_ctx : & InitFeatures ) -> Self {
244
+ // Generates a bitmask with both even and odd bits set for the given features. Bitwise
245
+ // AND-ing it with a byte will select only common features.
246
+ macro_rules! features_including {
247
+ ( $( $feature: ident) |* ) => {
248
+ ( 0b00_00_00_00
249
+ $(
250
+ | <sealed:: NodeContext as sealed:: $feature>:: REQUIRED_MASK
251
+ | <sealed:: NodeContext as sealed:: $feature>:: OPTIONAL_MASK
252
+ ) *
253
+ )
254
+ }
255
+ }
256
+
163
257
let mut flags = Vec :: new ( ) ;
164
258
for ( i, feature_byte) in init_ctx. flags . iter ( ) . enumerate ( ) {
165
259
match i {
166
- // Blank out initial_routing_sync (feature bits 2/3), gossip_queries (6/7),
167
- // gossip_queries_ex (10/11), option_static_remotekey (12/13), and
168
- // option_support_large_channel (16/17)
169
- 0 => flags. push ( feature_byte & 0b00110011 ) ,
170
- 1 => flags. push ( feature_byte & 0b11000011 ) ,
171
- 2 => flags. push ( feature_byte & 0b00000011 ) ,
260
+ 0 => flags. push ( feature_byte & features_including ! [ DataLossProtect | UpfrontShutdownScript ] ) ,
261
+ 1 => flags. push ( feature_byte & features_including ! [ VariableLengthOnion | PaymentSecret ] ) ,
262
+ 2 => flags. push ( feature_byte & features_including ! [ BasicMPP ] ) ,
172
263
_ => ( ) ,
173
264
}
174
265
}
@@ -201,33 +292,47 @@ impl<T: sealed::Context> Features<T> {
201
292
}
202
293
203
294
pub ( crate ) fn requires_unknown_bits ( & self ) -> bool {
295
+ // Generates a bitmask with all even bits set except for the given features. Bitwise
296
+ // AND-ing it with a byte will select unknown required features.
297
+ macro_rules! features_excluding {
298
+ ( $( $feature: ident) |* ) => {
299
+ ( 0b01_01_01_01
300
+ $(
301
+ & !( <sealed:: InitContext as sealed:: $feature>:: REQUIRED_MASK )
302
+ ) *
303
+ )
304
+ }
305
+ }
306
+
204
307
self . flags . iter ( ) . enumerate ( ) . any ( |( idx, & byte) | {
205
308
( match idx {
206
- // Unknown bits are even bits which we don't understand, we list ones which we do
207
- // here:
208
- // unknown, upfront_shutdown_script, unknown (actually initial_routing_sync, but it
209
- // is only valid as an optional feature), and data_loss_protect:
210
- 0 => ( byte & 0b01000100 ) ,
211
- // payment_secret, unknown, unknown, var_onion_optin:
212
- 1 => ( byte & 0b00010100 ) ,
213
- // unknown, unknown, unknown, basic_mpp:
214
- 2 => ( byte & 0b01010100 ) ,
215
- // fallback, all even bits set:
216
- _ => ( byte & 0b01010101 ) ,
309
+ 0 => ( byte & features_excluding ! [ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ) ,
310
+ 1 => ( byte & features_excluding ! [ VariableLengthOnion | PaymentSecret ] ) ,
311
+ 2 => ( byte & features_excluding ! [ BasicMPP ] ) ,
312
+ _ => ( byte & features_excluding ! [ ] ) ,
217
313
} ) != 0
218
314
} )
219
315
}
220
316
221
317
pub ( crate ) fn supports_unknown_bits ( & self ) -> bool {
318
+ // Generates a bitmask with all even and odd bits set except for the given features. Bitwise
319
+ // AND-ing it with a byte will select unknown supported features.
320
+ macro_rules! features_excluding {
321
+ ( $( $feature: ident) |* ) => {
322
+ ( 0b11_11_11_11
323
+ $(
324
+ & !( <sealed:: InitContext as sealed:: $feature>:: REQUIRED_MASK )
325
+ & !( <sealed:: InitContext as sealed:: $feature>:: OPTIONAL_MASK )
326
+ ) *
327
+ )
328
+ }
329
+ }
330
+
222
331
self . flags . iter ( ) . enumerate ( ) . any ( |( idx, & byte) | {
223
332
( match idx {
224
- // unknown, upfront_shutdown_script, initial_routing_sync (is only valid as an
225
- // optional feature), and data_loss_protect:
226
- 0 => ( byte & 0b11000100 ) ,
227
- // payment_secret, unknown, unknown, var_onion_optin:
228
- 1 => ( byte & 0b00111100 ) ,
229
- // unknown, unknown, unknown, basic_mpp:
230
- 2 => ( byte & 0b11111100 ) ,
333
+ 0 => ( byte & features_excluding ! [ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ) ,
334
+ 1 => ( byte & features_excluding ! [ VariableLengthOnion | PaymentSecret ] ) ,
335
+ 2 => ( byte & features_excluding ! [ BasicMPP ] ) ,
231
336
_ => byte,
232
337
} ) != 0
233
338
} )
@@ -262,34 +367,32 @@ impl<T: sealed::Context> Features<T> {
262
367
263
368
impl < T : sealed:: DataLossProtect > Features < T > {
264
369
pub ( crate ) fn supports_data_loss_protect ( & self ) -> bool {
265
- self . flags . len ( ) > 0 && ( self . flags [ 0 ] & 3 ) != 0
370
+ < T as sealed :: DataLossProtect > :: supports_feature ( & self . flags )
266
371
}
267
372
}
268
373
269
374
impl < T : sealed:: UpfrontShutdownScript > Features < T > {
270
375
pub ( crate ) fn supports_upfront_shutdown_script ( & self ) -> bool {
271
- self . flags . len ( ) > 0 && ( self . flags [ 0 ] & ( 3 << 4 ) ) != 0
376
+ < T as sealed :: UpfrontShutdownScript > :: supports_feature ( & self . flags )
272
377
}
273
378
#[ cfg( test) ]
274
379
pub ( crate ) fn unset_upfront_shutdown_script ( & mut self ) {
275
- self . flags [ 0 ] &= ! ( 1 << 5 ) ;
380
+ < T as sealed :: UpfrontShutdownScript > :: clear_optional_bit ( & mut self . flags )
276
381
}
277
382
}
278
383
279
384
impl < T : sealed:: VariableLengthOnion > Features < T > {
280
385
pub ( crate ) fn supports_variable_length_onion ( & self ) -> bool {
281
- self . flags . len ( ) > 1 && ( self . flags [ 1 ] & 3 ) != 0
386
+ < T as sealed :: VariableLengthOnion > :: supports_feature ( & self . flags )
282
387
}
283
388
}
284
389
285
390
impl < T : sealed:: InitialRoutingSync > Features < T > {
286
391
pub ( crate ) fn initial_routing_sync ( & self ) -> bool {
287
- self . flags . len ( ) > 0 && ( self . flags [ 0 ] & ( 1 << 3 ) ) != 0
392
+ < T as sealed :: InitialRoutingSync > :: supports_feature ( & self . flags )
288
393
}
289
394
pub ( crate ) fn clear_initial_routing_sync ( & mut self ) {
290
- if self . flags . len ( ) > 0 {
291
- self . flags [ 0 ] &= !( 1 << 3 ) ;
292
- }
395
+ <T as sealed:: InitialRoutingSync >:: clear_optional_bit ( & mut self . flags )
293
396
}
294
397
}
295
398
@@ -299,15 +402,15 @@ impl<T: sealed::PaymentSecret> Features<T> {
299
402
// invoice provides a payment_secret, we assume that we can use it (ie that the recipient
300
403
// supports payment_secret).
301
404
pub ( crate ) fn supports_payment_secret ( & self ) -> bool {
302
- self . flags . len ( ) > 1 && ( self . flags [ 1 ] & ( 3 << ( 14 - 8 ) ) ) != 0
405
+ < T as sealed :: PaymentSecret > :: supports_feature ( & self . flags )
303
406
}
304
407
}
305
408
306
409
impl < T : sealed:: BasicMPP > Features < T > {
307
410
// We currently never test for this since we don't actually *generate* multipath routes.
308
411
#[ allow( dead_code) ]
309
412
pub ( crate ) fn supports_basic_mpp ( & self ) -> bool {
310
- self . flags . len ( ) > 2 && ( self . flags [ 2 ] & ( 3 << ( 16 - 8 * 2 ) ) ) != 0
413
+ < T as sealed :: BasicMPP > :: supports_feature ( & self . flags )
311
414
}
312
415
}
313
416
0 commit comments