@@ -99,6 +99,26 @@ impl ShutdownScript {
99
99
ShutdownScriptImpl :: Bolt2 ( _) => None ,
100
100
}
101
101
}
102
+
103
+ /// Returns whether the shutdown script is compatible with the features as defined by BOLT #2.
104
+ ///
105
+ /// Specifically, checks for compliance with feature `option_shutdown_anysegwit`.
106
+ pub fn is_compatible ( & self , features : & InitFeatures ) -> bool {
107
+ match & self . 0 {
108
+ ShutdownScriptImpl :: Legacy ( _) => true ,
109
+ ShutdownScriptImpl :: Bolt2 ( script) => is_bolt2_compliant ( script, features) ,
110
+ }
111
+ }
112
+ }
113
+
114
+ fn is_bolt2_compliant ( script : & Script , features : & InitFeatures ) -> bool {
115
+ if script. is_p2pkh ( ) || script. is_p2sh ( ) || script. is_v0_p2wpkh ( ) || script. is_v0_p2wsh ( ) {
116
+ true
117
+ } else if features. supports_shutdown_anysegwit ( ) {
118
+ script. is_witness_program ( ) && script. as_bytes ( ) [ 0 ] != SEGWIT_V0 . into_u8 ( )
119
+ } else {
120
+ false
121
+ }
102
122
}
103
123
104
124
impl From < PublicKey > for ShutdownScript {
@@ -119,10 +139,8 @@ impl TryFrom<(Script, &InitFeatures)> for ShutdownScript {
119
139
type Error = InvalidShutdownScript ;
120
140
121
141
fn try_from ( ( script, features) : ( Script , & InitFeatures ) ) -> Result < Self , Self :: Error > {
122
- if script . is_p2pkh ( ) || script. is_p2sh ( ) || script . is_v0_p2wpkh ( ) || script . is_v0_p2wsh ( ) {
142
+ if is_bolt2_compliant ( & script, features ) {
123
143
Ok ( Self ( ShutdownScriptImpl :: Bolt2 ( script) ) )
124
- } else if features. supports_shutdown_anysegwit ( ) && script. is_witness_program ( ) && script. as_bytes ( ) [ 0 ] != SEGWIT_V0 . into_u8 ( ) {
125
- Ok ( Self ( ShutdownScriptImpl :: Bolt2 ( script) ) ) // option_shutdown_anysegwit
126
144
} else {
127
145
Err ( InvalidShutdownScript ( script) )
128
146
}
@@ -147,6 +165,7 @@ mod shutdown_script_tests {
147
165
use bitcoin:: blockdata:: script:: { Builder , Script } ;
148
166
use bitcoin:: secp256k1:: Secp256k1 ;
149
167
use bitcoin:: secp256k1:: key:: { PublicKey , SecretKey } ;
168
+ use ln:: features:: InitFeatures ;
150
169
use std:: convert:: TryFrom ;
151
170
152
171
fn pubkey ( ) -> bitcoin:: util:: ecdsa:: PublicKey {
@@ -173,6 +192,8 @@ mod shutdown_script_tests {
173
192
let p2wpkh_script = Script :: new_v0_wpkh ( & pubkey_hash) ;
174
193
175
194
let shutdown_script = ShutdownScript :: from ( pubkey. key ) ;
195
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) ) ) ;
196
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) . clear_shutdown_anysegwit( ) ) ) ;
176
197
assert_eq ! ( shutdown_script. into_inner( ) , p2wpkh_script) ;
177
198
}
178
199
@@ -182,6 +203,8 @@ mod shutdown_script_tests {
182
203
let p2pkh_script = Script :: new_p2pkh ( & pubkey_hash) ;
183
204
184
205
let shutdown_script = ShutdownScript :: new_p2pkh ( & pubkey_hash) ;
206
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) ) ) ;
207
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) . clear_shutdown_anysegwit( ) ) ) ;
185
208
assert_eq ! ( shutdown_script. into_inner( ) , p2pkh_script) ;
186
209
assert ! ( ShutdownScript :: try_from( p2pkh_script) . is_ok( ) ) ;
187
210
}
@@ -192,6 +215,8 @@ mod shutdown_script_tests {
192
215
let p2sh_script = Script :: new_p2sh ( & script_hash) ;
193
216
194
217
let shutdown_script = ShutdownScript :: new_p2sh ( & script_hash) ;
218
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) ) ) ;
219
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) . clear_shutdown_anysegwit( ) ) ) ;
195
220
assert_eq ! ( shutdown_script. into_inner( ) , p2sh_script) ;
196
221
assert ! ( ShutdownScript :: try_from( p2sh_script) . is_ok( ) ) ;
197
222
}
@@ -202,6 +227,8 @@ mod shutdown_script_tests {
202
227
let p2wpkh_script = Script :: new_v0_wpkh ( & pubkey_hash) ;
203
228
204
229
let shutdown_script = ShutdownScript :: new_p2wpkh ( & pubkey_hash) ;
230
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) ) ) ;
231
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) . clear_shutdown_anysegwit( ) ) ) ;
205
232
assert_eq ! ( shutdown_script. into_inner( ) , p2wpkh_script) ;
206
233
assert ! ( ShutdownScript :: try_from( p2wpkh_script) . is_ok( ) ) ;
207
234
}
@@ -212,19 +239,47 @@ mod shutdown_script_tests {
212
239
let p2wsh_script = Script :: new_v0_wsh ( & script_hash) ;
213
240
214
241
let shutdown_script = ShutdownScript :: new_p2wsh ( & script_hash) ;
242
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) ) ) ;
243
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) . clear_shutdown_anysegwit( ) ) ) ;
215
244
assert_eq ! ( shutdown_script. into_inner( ) , p2wsh_script) ;
216
245
assert ! ( ShutdownScript :: try_from( p2wsh_script) . is_ok( ) ) ;
217
246
}
218
247
248
+ #[ test]
249
+ fn generates_segwit_from_v0_witness_program ( ) {
250
+ let witness_program = Script :: new_witness_program ( u5:: try_from_u8 ( 0 ) . unwrap ( ) , & [ 0 ; 20 ] ) ;
251
+
252
+ let shutdown_script = ShutdownScript :: new_witness_program ( u5:: try_from_u8 ( 0 ) . unwrap ( ) , & [ 0 ; 20 ] ) ;
253
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) ) ) ;
254
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) . clear_shutdown_anysegwit( ) ) ) ;
255
+ assert_eq ! ( shutdown_script. into_inner( ) , witness_program) ;
256
+ }
257
+
258
+ #[ test]
259
+ fn generates_segwit_from_non_v0_witness_program ( ) {
260
+ let witness_program = Script :: new_witness_program ( u5:: try_from_u8 ( 16 ) . unwrap ( ) , & [ 0 ; 40 ] ) ;
261
+
262
+ let shutdown_script = ShutdownScript :: new_witness_program ( u5:: try_from_u8 ( 16 ) . unwrap ( ) , & [ 0 ; 40 ] ) ;
263
+ assert ! ( shutdown_script. is_compatible( & InitFeatures :: known( ) ) ) ;
264
+ assert ! ( !shutdown_script. is_compatible( & InitFeatures :: known( ) . clear_shutdown_anysegwit( ) ) ) ;
265
+ assert_eq ! ( shutdown_script. into_inner( ) , witness_program) ;
266
+ }
267
+
219
268
#[ test]
220
269
fn fails_from_unsupported_script ( ) {
221
270
let op_return = Script :: new_op_return ( & [ 0 ; 42 ] ) ;
222
271
assert ! ( ShutdownScript :: try_from( op_return) . is_err( ) ) ;
223
272
}
224
273
225
274
#[ test]
226
- fn fails_from_invalid_segwit_v0_program ( ) {
275
+ fn fails_from_invalid_segwit_v0_witness_program ( ) {
227
276
let witness_program = Script :: new_witness_program ( u5:: try_from_u8 ( 0 ) . unwrap ( ) , & [ 0 ; 2 ] ) ;
228
277
assert ! ( ShutdownScript :: try_from( witness_program) . is_err( ) ) ;
229
278
}
279
+
280
+ #[ test]
281
+ fn fails_from_invalid_segwit_non_v0_witness_program ( ) {
282
+ let witness_program = Script :: new_witness_program ( u5:: try_from_u8 ( 16 ) . unwrap ( ) , & [ 0 ; 42 ] ) ;
283
+ assert ! ( ShutdownScript :: try_from( witness_program) . is_err( ) ) ;
284
+ }
230
285
}
0 commit comments