@@ -18,6 +18,7 @@ use crate::sign::ecdsa::EcdsaChannelSigner;
18
18
#[ allow( unused_imports) ]
19
19
use crate :: prelude:: * ;
20
20
21
+ use core:: cell:: RefCell ;
21
22
use core:: cmp;
22
23
use crate :: sync:: { Mutex , Arc } ;
23
24
#[ cfg( test) ] use crate :: sync:: MutexGuard ;
@@ -76,6 +77,51 @@ pub struct TestChannelSigner {
76
77
pub available : Arc < Mutex < bool > > ,
77
78
}
78
79
80
+ /// Channel signer operations that can be individually enabled and disabled. If a particular value
81
+ /// is set in the `TestChannelSigner::unavailable` bitmask, then that operation will return an
82
+ /// error.
83
+ pub mod ops {
84
+ pub const GET_PER_COMMITMENT_POINT : u32 = 1 << 0 ;
85
+ pub const RELEASE_COMMITMENT_SECRET : u32 = 1 << 1 ;
86
+ pub const VALIDATE_HOLDER_COMMITMENT : u32 = 1 << 2 ;
87
+ pub const SIGN_COUNTERPARTY_COMMITMENT : u32 = 1 << 3 ;
88
+ pub const VALIDATE_COUNTERPARTY_REVOCATION : u32 = 1 << 4 ;
89
+ pub const SIGN_HOLDER_COMMITMENT_AND_HTLCS : u32 = 1 << 5 ;
90
+ pub const SIGN_JUSTICE_REVOKED_OUTPUT : u32 = 1 << 6 ;
91
+ pub const SIGN_JUSTICE_REVOKED_HTLC : u32 = 1 << 7 ;
92
+ pub const SIGN_HOLDER_HTLC_TRANSACTION : u32 = 1 << 8 ;
93
+ pub const SIGN_COUNTERPARTY_HTLC_TRANSATION : u32 = 1 << 9 ;
94
+ pub const SIGN_CLOSING_TRANSACTION : u32 = 1 << 10 ;
95
+ pub const SIGN_HOLDER_ANCHOR_INPUT : u32 = 1 << 11 ;
96
+ pub const SIGN_CHANNEL_ANNOUNCMENT_WITH_FUNDING_KEY : u32 = 1 << 12 ;
97
+
98
+ #[ cfg( test) ]
99
+ pub fn string_from ( mask : u32 ) -> String {
100
+ if mask == 0 {
101
+ return "nothing" . to_owned ( ) ;
102
+ }
103
+ if mask == !( 0 as u32 ) {
104
+ return "everything" . to_owned ( ) ;
105
+ }
106
+
107
+ vec ! [
108
+ if ( mask & GET_PER_COMMITMENT_POINT ) != 0 { Some ( "get_per_commitment_point" ) } else { None } ,
109
+ if ( mask & RELEASE_COMMITMENT_SECRET ) != 0 { Some ( "release_commitment_secret" ) } else { None } ,
110
+ if ( mask & VALIDATE_HOLDER_COMMITMENT ) != 0 { Some ( "validate_holder_commitment" ) } else { None } ,
111
+ if ( mask & SIGN_COUNTERPARTY_COMMITMENT ) != 0 { Some ( "sign_counterparty_commitment" ) } else { None } ,
112
+ if ( mask & VALIDATE_COUNTERPARTY_REVOCATION ) != 0 { Some ( "validate_counterparty_revocation" ) } else { None } ,
113
+ if ( mask & SIGN_HOLDER_COMMITMENT_AND_HTLCS ) != 0 { Some ( "sign_holder_commitment_and_htlcs" ) } else { None } ,
114
+ if ( mask & SIGN_JUSTICE_REVOKED_OUTPUT ) != 0 { Some ( "sign_justice_revoked_output" ) } else { None } ,
115
+ if ( mask & SIGN_JUSTICE_REVOKED_HTLC ) != 0 { Some ( "sign_justice_revoked_htlc" ) } else { None } ,
116
+ if ( mask & SIGN_HOLDER_HTLC_TRANSACTION ) != 0 { Some ( "sign_holder_htlc_transaction" ) } else { None } ,
117
+ if ( mask & SIGN_COUNTERPARTY_HTLC_TRANSATION ) != 0 { Some ( "sign_counterparty_htlc_transation" ) } else { None } ,
118
+ if ( mask & SIGN_CLOSING_TRANSACTION ) != 0 { Some ( "sign_closing_transaction" ) } else { None } ,
119
+ if ( mask & SIGN_HOLDER_ANCHOR_INPUT ) != 0 { Some ( "sign_holder_anchor_input" ) } else { None } ,
120
+ if ( mask & SIGN_CHANNEL_ANNOUNCMENT_WITH_FUNDING_KEY ) != 0 { Some ( "sign_channel_announcment_with_funding_key" ) } else { None } ,
121
+ ] . iter ( ) . flatten ( ) . map ( |s| s. to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( ", " )
122
+ }
123
+ }
124
+
79
125
impl PartialEq for TestChannelSigner {
80
126
fn eq ( & self , o : & Self ) -> bool {
81
127
Arc :: ptr_eq ( & self . state , & o. state )
@@ -123,12 +169,29 @@ impl TestChannelSigner {
123
169
pub fn set_available ( & self , available : bool ) {
124
170
* self . available . lock ( ) . unwrap ( ) = available;
125
171
}
172
+
173
+ #[ cfg( test) ]
174
+ pub fn set_ops_available ( & self , mask : u32 , available : bool ) {
175
+ let mut state = self . get_enforcement_state ( ) ;
176
+ if available {
177
+ state. unavailable_signer_ops &= !mask; // clear the bits that are now available
178
+ } else {
179
+ state. unavailable_signer_ops |= mask; // set the bits that are now unavailable
180
+ }
181
+ }
182
+
183
+ fn is_signer_available ( & self , ops_mask : u32 ) -> bool {
184
+ self . state . lock ( ) . unwrap ( ) . is_signer_available ( ops_mask)
185
+ }
126
186
}
127
187
128
188
impl ChannelSigner for TestChannelSigner {
129
189
fn get_per_commitment_point ( & self , idx : u64 , secp_ctx : & Secp256k1 < secp256k1:: All > ) -> Result < PublicKey , ( ) > {
130
190
// TODO: implement a mask in EnforcementState to let you test signatures being
131
191
// unavailable
192
+ if !self . is_signer_available ( ops:: GET_PER_COMMITMENT_POINT ) {
193
+ return Err ( ( ) ) ;
194
+ }
132
195
self . inner . get_per_commitment_point ( idx, secp_ctx)
133
196
}
134
197
@@ -379,16 +442,51 @@ pub struct EnforcementState {
379
442
pub last_holder_revoked_commitment : u64 ,
380
443
/// The last validated holder commitment number, backwards counting
381
444
pub last_holder_commitment : u64 ,
445
+ /// A flag array that indicates which signing operations are currently *not* available in the
446
+ /// channel. When a method's bit is set, then the signer will act as if the signature is
447
+ /// unavailable and return an error result.
448
+ pub unavailable_signer_ops : u32 ,
382
449
}
383
450
384
451
impl EnforcementState {
452
+ #[ cfg( feature = "std" ) ]
453
+ thread_local ! {
454
+ static DEFAULT_UNAVAILABLE_SIGNER_OPS : RefCell <u32 > = RefCell :: new( 0 ) ;
455
+ }
456
+
385
457
/// Enforcement state for a new channel
386
458
pub fn new ( ) -> Self {
387
459
EnforcementState {
388
460
last_counterparty_commitment : INITIAL_REVOKED_COMMITMENT_NUMBER ,
389
461
last_counterparty_revoked_commitment : INITIAL_REVOKED_COMMITMENT_NUMBER ,
390
462
last_holder_revoked_commitment : INITIAL_REVOKED_COMMITMENT_NUMBER ,
391
463
last_holder_commitment : INITIAL_REVOKED_COMMITMENT_NUMBER ,
464
+ unavailable_signer_ops : {
465
+ #[ cfg( feature = "std" ) ]
466
+ {
467
+ EnforcementState :: DEFAULT_UNAVAILABLE_SIGNER_OPS . with ( |ops| * ops. borrow ( ) )
468
+ }
469
+ #[ cfg( not( feature = "std" ) ) ]
470
+ {
471
+ 0
472
+ }
473
+ }
392
474
}
393
475
}
476
+
477
+ pub fn is_signer_available ( & self , ops_mask : u32 ) -> bool {
478
+ ( self . unavailable_signer_ops & ops_mask) == 0
479
+ }
480
+
481
+ #[ cfg( feature = "std" ) ]
482
+ pub fn with_default_unavailable < F , R > ( ops : u32 , f : F ) -> R
483
+ where F : FnOnce ( ) -> R
484
+ {
485
+ EnforcementState :: DEFAULT_UNAVAILABLE_SIGNER_OPS . with ( |unavailable_ops| {
486
+ unavailable_ops. replace ( ops) ;
487
+ let res = f ( ) ;
488
+ unavailable_ops. replace ( 0 ) ;
489
+ res
490
+ } )
491
+ }
394
492
}
0 commit comments