@@ -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,112 @@ 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 { }
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
+ ( $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 = $odd_bit - 1 ;
37
+
38
+ /// The bit used to signify that the feature is optional.
39
+ const ODD_BIT : usize = $odd_bit;
40
+
41
+ /// Assertion that [`EVEN_BIT`] is actually even.
42
+ ///
43
+ /// [`EVEN_BIT`]: #associatedconstant.EVEN_BIT
44
+ const ASSERT_EVEN_BIT_PARITY : usize ;
45
+
46
+ /// Assertion that [`ODD_BIT`] is actually odd.
47
+ ///
48
+ /// [`ODD_BIT`]: #associatedconstant.ODD_BIT
49
+ const ASSERT_ODD_BIT_PARITY : usize ;
50
+
51
+ /// The byte where the feature is set.
52
+ const BYTE_OFFSET : usize = Self :: EVEN_BIT / 8 ;
53
+
54
+ /// The bitmask for the feature's required flag relative to the [`BYTE_OFFSET`].
55
+ ///
56
+ /// [`BYTE_OFFSET`]: #associatedconstant.BYTE_OFFSET
57
+ const REQUIRED_MASK : u8 = 1 << ( Self :: EVEN_BIT - 8 * Self :: BYTE_OFFSET ) ;
58
+
59
+ /// The bitmask for the feature's optional flag relative to the [`BYTE_OFFSET`].
60
+ ///
61
+ /// [`BYTE_OFFSET`]: #associatedconstant.BYTE_OFFSET
62
+ const OPTIONAL_MASK : u8 = 1 << ( Self :: ODD_BIT - 8 * Self :: BYTE_OFFSET ) ;
63
+
64
+ /// Returns whether the feature is supported by the given flags.
65
+ #[ inline]
66
+ fn supports_feature( flags: & Vec <u8 >) -> bool {
67
+ flags. len( ) > Self :: BYTE_OFFSET &&
68
+ ( flags[ Self :: BYTE_OFFSET ] & ( Self :: REQUIRED_MASK | Self :: OPTIONAL_MASK ) ) != 0
69
+ }
70
+
71
+ /// Sets the feature's optional (odd) bit in the given flags.
72
+ #[ inline]
73
+ fn set_optional_bit( flags: & mut Vec <u8 >) {
74
+ if flags. len( ) <= Self :: BYTE_OFFSET {
75
+ flags. resize( Self :: BYTE_OFFSET + 1 , 0u8 ) ;
76
+ }
77
+
78
+ flags[ Self :: BYTE_OFFSET ] |= Self :: OPTIONAL_MASK ;
79
+ }
80
+
81
+ /// Clears the feature's optional (odd) bit from the given flags.
82
+ #[ inline]
83
+ fn clear_optional_bit( flags: & mut Vec <u8 >) {
84
+ if flags. len( ) > Self :: BYTE_OFFSET {
85
+ flags[ Self :: BYTE_OFFSET ] &= !Self :: OPTIONAL_MASK ;
86
+ }
87
+ }
88
+ }
32
89
33
- pub trait VariableLengthOnion : Context { }
34
- impl VariableLengthOnion for InitContext { }
35
- impl VariableLengthOnion for NodeContext { }
90
+ $(
91
+ impl $feature for $context {
92
+ // EVEN_BIT % 2 == 0
93
+ const ASSERT_EVEN_BIT_PARITY : usize = 0 - ( <Self as $feature>:: EVEN_BIT % 2 ) ;
36
94
37
- pub trait PaymentSecret : Context { }
38
- impl PaymentSecret for InitContext { }
39
- impl PaymentSecret for NodeContext { }
95
+ // ODD_BIT % 2 == 1
96
+ const ASSERT_ODD_BIT_PARITY : usize = ( <Self as $feature>:: ODD_BIT % 2 ) - 1 ;
97
+ }
98
+ ) *
99
+ }
100
+ }
40
101
41
- pub trait BasicMPP : Context { }
42
- impl BasicMPP for InitContext { }
43
- impl BasicMPP for NodeContext { }
102
+ define_feature ! ( 1 , DataLossProtect , [ InitContext , NodeContext ] ,
103
+ "Feature flags for `option_data_loss_protect`." ) ;
104
+ // NOTE: Per Bolt #9, initial_routing_sync has no even bit.
105
+ define_feature ! ( 3 , InitialRoutingSync , [ InitContext ] ,
106
+ "Feature flags for `initial_routing_sync`." ) ;
107
+ define_feature ! ( 5 , UpfrontShutdownScript , [ InitContext , NodeContext ] ,
108
+ "Feature flags for `option_upfront_shutdown_script`." ) ;
109
+ define_feature ! ( 9 , VariableLengthOnion , [ InitContext , NodeContext ] ,
110
+ "Feature flags for `var_onion_optin`." ) ;
111
+ define_feature ! ( 15 , PaymentSecret , [ InitContext , NodeContext ] ,
112
+ "Feature flags for `payment_secret`." ) ;
113
+ define_feature ! ( 17 , BasicMPP , [ InitContext , NodeContext ] ,
114
+ "Feature flags for `basic_mpp`." ) ;
115
+
116
+ /// Generates a feature flag byte with the given features set as optional. Useful for initializing
117
+ /// the flags within [`Features`].
118
+ ///
119
+ /// [`Features`]: struct.Features.html
120
+ macro_rules! feature_flags {
121
+ ( $context: ty; $( $feature: ident) |* ) => {
122
+ ( 0b00_00_00_00
123
+ $(
124
+ | <$context as sealed:: $feature>:: OPTIONAL_MASK
125
+ ) *
126
+ )
127
+ }
128
+ }
44
129
}
45
130
46
131
/// Tracks the set of features which a node implements, templated by the context in which it
@@ -81,7 +166,11 @@ impl InitFeatures {
81
166
/// Create a Features with the features we support
82
167
pub fn supported ( ) -> InitFeatures {
83
168
InitFeatures {
84
- flags : vec ! [ 2 | 1 << 3 | 1 << 5 , 1 << ( 9 -8 ) | 1 << ( 15 - 8 ) , 1 << ( 17 - 8 * 2 ) ] ,
169
+ flags : vec ! [
170
+ feature_flags![ sealed:: InitContext ; DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ,
171
+ feature_flags![ sealed:: InitContext ; VariableLengthOnion | PaymentSecret ] ,
172
+ feature_flags![ sealed:: InitContext ; BasicMPP ] ,
173
+ ] ,
85
174
mark : PhantomData ,
86
175
}
87
176
}
@@ -144,14 +233,22 @@ impl NodeFeatures {
144
233
#[ cfg( not( feature = "fuzztarget" ) ) ]
145
234
pub ( crate ) fn supported ( ) -> NodeFeatures {
146
235
NodeFeatures {
147
- flags : vec ! [ 2 | 1 << 5 , 1 << ( 9 - 8 ) | 1 << ( 15 - 8 ) , 1 << ( 17 - 8 * 2 ) ] ,
236
+ flags : vec ! [
237
+ feature_flags![ sealed:: NodeContext ; DataLossProtect | UpfrontShutdownScript ] ,
238
+ feature_flags![ sealed:: NodeContext ; VariableLengthOnion | PaymentSecret ] ,
239
+ feature_flags![ sealed:: NodeContext ; BasicMPP ] ,
240
+ ] ,
148
241
mark : PhantomData ,
149
242
}
150
243
}
151
244
#[ cfg( feature = "fuzztarget" ) ]
152
245
pub fn supported ( ) -> NodeFeatures {
153
246
NodeFeatures {
154
- flags : vec ! [ 2 | 1 << 5 , 1 << ( 9 - 8 ) | 1 << ( 15 - 8 ) , 1 << ( 17 - 8 * 2 ) ] ,
247
+ flags : vec ! [
248
+ feature_flags![ sealed:: NodeContext ; DataLossProtect | UpfrontShutdownScript ] ,
249
+ feature_flags![ sealed:: NodeContext ; VariableLengthOnion | PaymentSecret ] ,
250
+ feature_flags![ sealed:: NodeContext ; BasicMPP ] ,
251
+ ] ,
155
252
mark : PhantomData ,
156
253
}
157
254
}
@@ -160,15 +257,25 @@ impl NodeFeatures {
160
257
/// relevant in a node-context features and creates a node-context features from them.
161
258
/// Be sure to blank out features that are unknown to us.
162
259
pub ( crate ) fn with_known_relevant_init_flags ( init_ctx : & InitFeatures ) -> Self {
260
+ // Generates a bitmask with both even and odd bits set for the given features. Bitwise
261
+ // AND-ing it with a byte will select only common features.
262
+ macro_rules! features_including {
263
+ ( $( $feature: ident) |* ) => {
264
+ ( 0b00_00_00_00
265
+ $(
266
+ | <sealed:: NodeContext as sealed:: $feature>:: REQUIRED_MASK
267
+ | <sealed:: NodeContext as sealed:: $feature>:: OPTIONAL_MASK
268
+ ) *
269
+ )
270
+ }
271
+ }
272
+
163
273
let mut flags = Vec :: new ( ) ;
164
274
for ( i, feature_byte) in init_ctx. flags . iter ( ) . enumerate ( ) {
165
275
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 ) ,
276
+ 0 => flags. push ( feature_byte & features_including ! [ DataLossProtect | UpfrontShutdownScript ] ) ,
277
+ 1 => flags. push ( feature_byte & features_including ! [ VariableLengthOnion | PaymentSecret ] ) ,
278
+ 2 => flags. push ( feature_byte & features_including ! [ BasicMPP ] ) ,
172
279
_ => ( ) ,
173
280
}
174
281
}
@@ -201,33 +308,47 @@ impl<T: sealed::Context> Features<T> {
201
308
}
202
309
203
310
pub ( crate ) fn requires_unknown_bits ( & self ) -> bool {
311
+ // Generates a bitmask with all even bits set except for the given features. Bitwise
312
+ // AND-ing it with a byte will select unknown required features.
313
+ macro_rules! features_excluding {
314
+ ( $( $feature: ident) |* ) => {
315
+ ( 0b01_01_01_01
316
+ $(
317
+ & !( <sealed:: InitContext as sealed:: $feature>:: REQUIRED_MASK )
318
+ ) *
319
+ )
320
+ }
321
+ }
322
+
204
323
self . flags . iter ( ) . enumerate ( ) . any ( |( idx, & byte) | {
205
324
( 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 ) ,
325
+ 0 => ( byte & features_excluding ! [ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ) ,
326
+ 1 => ( byte & features_excluding ! [ VariableLengthOnion | PaymentSecret ] ) ,
327
+ 2 => ( byte & features_excluding ! [ BasicMPP ] ) ,
328
+ _ => ( byte & features_excluding ! [ ] ) ,
217
329
} ) != 0
218
330
} )
219
331
}
220
332
221
333
pub ( crate ) fn supports_unknown_bits ( & self ) -> bool {
334
+ // Generates a bitmask with all even and odd bits set except for the given features. Bitwise
335
+ // AND-ing it with a byte will select unknown supported features.
336
+ macro_rules! features_excluding {
337
+ ( $( $feature: ident) |* ) => {
338
+ ( 0b11_11_11_11
339
+ $(
340
+ & !( <sealed:: InitContext as sealed:: $feature>:: REQUIRED_MASK )
341
+ & !( <sealed:: InitContext as sealed:: $feature>:: OPTIONAL_MASK )
342
+ ) *
343
+ )
344
+ }
345
+ }
346
+
222
347
self . flags . iter ( ) . enumerate ( ) . any ( |( idx, & byte) | {
223
348
( 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 ) ,
349
+ 0 => ( byte & features_excluding ! [ DataLossProtect | InitialRoutingSync | UpfrontShutdownScript ] ) ,
350
+ 1 => ( byte & features_excluding ! [ VariableLengthOnion | PaymentSecret ] ) ,
351
+ 2 => ( byte & features_excluding ! [ BasicMPP ] ) ,
231
352
_ => byte,
232
353
} ) != 0
233
354
} )
@@ -262,34 +383,32 @@ impl<T: sealed::Context> Features<T> {
262
383
263
384
impl < T : sealed:: DataLossProtect > Features < T > {
264
385
pub ( crate ) fn supports_data_loss_protect ( & self ) -> bool {
265
- self . flags . len ( ) > 0 && ( self . flags [ 0 ] & 3 ) != 0
386
+ < T as sealed :: DataLossProtect > :: supports_feature ( & self . flags )
266
387
}
267
388
}
268
389
269
390
impl < T : sealed:: UpfrontShutdownScript > Features < T > {
270
391
pub ( crate ) fn supports_upfront_shutdown_script ( & self ) -> bool {
271
- self . flags . len ( ) > 0 && ( self . flags [ 0 ] & ( 3 << 4 ) ) != 0
392
+ < T as sealed :: UpfrontShutdownScript > :: supports_feature ( & self . flags )
272
393
}
273
394
#[ cfg( test) ]
274
395
pub ( crate ) fn unset_upfront_shutdown_script ( & mut self ) {
275
- self . flags [ 0 ] &= ! ( 1 << 5 ) ;
396
+ < T as sealed :: UpfrontShutdownScript > :: clear_optional_bit ( & mut self . flags )
276
397
}
277
398
}
278
399
279
400
impl < T : sealed:: VariableLengthOnion > Features < T > {
280
401
pub ( crate ) fn supports_variable_length_onion ( & self ) -> bool {
281
- self . flags . len ( ) > 1 && ( self . flags [ 1 ] & 3 ) != 0
402
+ < T as sealed :: VariableLengthOnion > :: supports_feature ( & self . flags )
282
403
}
283
404
}
284
405
285
406
impl < T : sealed:: InitialRoutingSync > Features < T > {
286
407
pub ( crate ) fn initial_routing_sync ( & self ) -> bool {
287
- self . flags . len ( ) > 0 && ( self . flags [ 0 ] & ( 1 << 3 ) ) != 0
408
+ < T as sealed :: InitialRoutingSync > :: supports_feature ( & self . flags )
288
409
}
289
410
pub ( crate ) fn clear_initial_routing_sync ( & mut self ) {
290
- if self . flags . len ( ) > 0 {
291
- self . flags [ 0 ] &= !( 1 << 3 ) ;
292
- }
411
+ <T as sealed:: InitialRoutingSync >:: clear_optional_bit ( & mut self . flags )
293
412
}
294
413
}
295
414
@@ -299,15 +418,15 @@ impl<T: sealed::PaymentSecret> Features<T> {
299
418
// invoice provides a payment_secret, we assume that we can use it (ie that the recipient
300
419
// supports payment_secret).
301
420
pub ( crate ) fn supports_payment_secret ( & self ) -> bool {
302
- self . flags . len ( ) > 1 && ( self . flags [ 1 ] & ( 3 << ( 14 - 8 ) ) ) != 0
421
+ < T as sealed :: PaymentSecret > :: supports_feature ( & self . flags )
303
422
}
304
423
}
305
424
306
425
impl < T : sealed:: BasicMPP > Features < T > {
307
426
// We currently never test for this since we don't actually *generate* multipath routes.
308
427
#[ allow( dead_code) ]
309
428
pub ( crate ) fn supports_basic_mpp ( & self ) -> bool {
310
- self . flags . len ( ) > 2 && ( self . flags [ 2 ] & ( 3 << ( 16 - 8 * 2 ) ) ) != 0
429
+ < T as sealed :: BasicMPP > :: supports_feature ( & self . flags )
311
430
}
312
431
}
313
432
0 commit comments