@@ -155,6 +155,9 @@ pub struct ChannelMonitor {
155
155
old_secrets : [ ( [ u8 ; 32 ] , u64 ) ; 49 ] ,
156
156
remote_claimable_outpoints : HashMap < Sha256dHash , Vec < HTLCOutputInCommitment > > ,
157
157
remote_htlc_outputs_on_chain : Mutex < HashMap < Sha256dHash , u64 > > ,
158
+ //hash to commitment number mapping use to determine the state of transaction owning it
159
+ // (revoked/non-revoked) and so lightnen pruning
160
+ remote_hash_commitment_number : HashMap < [ u8 ; 32 ] , u64 > ,
158
161
159
162
// We store two local commitment transactions to avoid any race conditions where we may update
160
163
// some monitors (potentially on watchtowers) but then fail to update others, resulting in the
@@ -185,6 +188,7 @@ impl Clone for ChannelMonitor {
185
188
old_secrets : self . old_secrets . clone ( ) ,
186
189
remote_claimable_outpoints : self . remote_claimable_outpoints . clone ( ) ,
187
190
remote_htlc_outputs_on_chain : Mutex :: new ( ( * self . remote_htlc_outputs_on_chain . lock ( ) . unwrap ( ) ) . clone ( ) ) ,
191
+ remote_hash_commitment_number : self . remote_hash_commitment_number . clone ( ) ,
188
192
189
193
prev_local_signed_commitment_tx : self . prev_local_signed_commitment_tx . clone ( ) ,
190
194
current_local_signed_commitment_tx : self . current_local_signed_commitment_tx . clone ( ) ,
@@ -217,6 +221,7 @@ impl ChannelMonitor {
217
221
old_secrets : [ ( [ 0 ; 32 ] , 1 << 48 ) ; 49 ] ,
218
222
remote_claimable_outpoints : HashMap :: new ( ) ,
219
223
remote_htlc_outputs_on_chain : Mutex :: new ( HashMap :: new ( ) ) ,
224
+ remote_hash_commitment_number : HashMap :: new ( ) ,
220
225
221
226
prev_local_signed_commitment_tx : None ,
222
227
current_local_signed_commitment_tx : None ,
@@ -255,7 +260,9 @@ impl ChannelMonitor {
255
260
256
261
/// Inserts a revocation secret into this channel monitor. Also optionally tracks the next
257
262
/// revocation point which may be required to claim HTLC outputs which we know the preimage of
258
- /// in case the remote end force-closes using their latest state.
263
+ /// in case the remote end force-closes using their latest state. Prunes old preimages if neither
264
+ /// needed by local commitment transactions HTCLs nor by remote ones. Unless we haven't already seen remote
265
+ /// commitment transaction's secret, they are de facto pruned (we can use revocation key).
259
266
pub fn provide_secret ( & mut self , idx : u64 , secret : [ u8 ; 32 ] , their_next_revocation_point : Option < ( u64 , PublicKey ) > ) -> Result < ( ) , HandleError > {
260
267
let pos = ChannelMonitor :: place_secret ( idx) ;
261
268
for i in 0 ..pos {
@@ -286,20 +293,46 @@ impl ChannelMonitor {
286
293
}
287
294
}
288
295
}
289
- // TODO: Prune payment_preimages no longer needed by the revocation (just have to check
290
- // that non-revoked remote commitment tx(n) do not need it, and our latest local commitment
291
- // tx does not need it.
296
+
297
+ let mut waste_hash_state : Vec < [ u8 ; 32 ] > = Vec :: new ( ) ;
298
+ {
299
+ let local_signed_commitment_tx = & self . current_local_signed_commitment_tx ;
300
+ let remote_hash_commitment_number = & self . remote_hash_commitment_number ;
301
+ let min_idx = self . get_min_seen_secret ( ) ;
302
+ self . payment_preimages . retain ( |& k, _| {
303
+ for & ( ref htlc, _s1, _s2) in & local_signed_commitment_tx. as_ref ( ) . expect ( "Channel needs at least an initial commitment tx !" ) . htlc_outputs {
304
+ if k == htlc. payment_hash {
305
+ return true
306
+ }
307
+ }
308
+ if let Some ( cn) = remote_hash_commitment_number. get ( & k) {
309
+ if * cn < min_idx {
310
+ return true
311
+ }
312
+ }
313
+ waste_hash_state. push ( k) ;
314
+ false
315
+ } ) ;
316
+ }
317
+ for h in waste_hash_state {
318
+ self . remote_hash_commitment_number . remove ( & h) ;
319
+ }
320
+
292
321
Ok ( ( ) )
293
322
}
294
323
295
324
/// Informs this monitor of the latest remote (ie non-broadcastable) commitment transaction.
296
325
/// The monitor watches for it to be broadcasted and then uses the HTLC information (and
297
326
/// possibly future revocation/preimage information) to claim outputs where possible.
298
- pub fn provide_latest_remote_commitment_tx_info ( & mut self , unsigned_commitment_tx : & Transaction , htlc_outputs : Vec < HTLCOutputInCommitment > ) {
327
+ /// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers.
328
+ pub fn provide_latest_remote_commitment_tx_info ( & mut self , unsigned_commitment_tx : & Transaction , htlc_outputs : Vec < HTLCOutputInCommitment > , commitment_number : u64 ) {
299
329
// TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction
300
330
// so that a remote monitor doesn't learn anything unless there is a malicious close.
301
331
// (only maybe, sadly we cant do the same for local info, as we need to be aware of
302
332
// timeouts)
333
+ for htlc in & htlc_outputs {
334
+ self . remote_hash_commitment_number . insert ( htlc. payment_hash , commitment_number) ;
335
+ }
303
336
self . remote_claimable_outpoints . insert ( unsigned_commitment_tx. txid ( ) , htlc_outputs) ;
304
337
}
305
338
@@ -796,9 +829,15 @@ impl ChannelMonitor {
796
829
mod tests {
797
830
use bitcoin:: util:: misc:: hex_bytes;
798
831
use bitcoin:: blockdata:: script:: Script ;
832
+ use bitcoin:: util:: hash:: { Hash160 , Sha256dHash } ;
833
+ use bitcoin:: blockdata:: transaction:: Transaction ;
799
834
use ln:: channelmonitor:: ChannelMonitor ;
835
+ use ln:: channelmonitor:: LocalSignedTx ;
836
+ use ln:: chan_utils:: HTLCOutputInCommitment ;
800
837
use secp256k1:: key:: { SecretKey , PublicKey } ;
801
- use secp256k1:: Secp256k1 ;
838
+ use secp256k1:: { Secp256k1 , Signature } ;
839
+ use rand:: { thread_rng, Rng } ;
840
+ use std:: collections:: HashMap ;
802
841
803
842
#[ test]
804
843
fn test_per_commitment_storage ( ) {
@@ -1154,5 +1193,163 @@ mod tests {
1154
1193
}
1155
1194
}
1156
1195
1196
+ macro_rules! gen_local_tx {
1197
+ ( $hex : expr, $monitor : expr, $htlcs : expr, $rng : expr, $preimage : expr, $hash : expr) => {
1198
+ {
1199
+
1200
+ let mut htlcs = Vec :: new( ) ;
1201
+
1202
+ for _i in 0 ..$htlcs {
1203
+ $rng. fill_bytes( & mut $preimage) ;
1204
+ $hash[ 0 ..20 ] . clone_from_slice( & Hash160 :: from_data( & $preimage) [ 0 ..20 ] ) ;
1205
+ $monitor. provide_payment_preimage( & $hash, & $preimage) ;
1206
+ htlcs. push( ( HTLCOutputInCommitment {
1207
+ offered : true ,
1208
+ amount_msat : 0 ,
1209
+ cltv_expiry : 0 ,
1210
+ payment_hash : $hash. clone( ) ,
1211
+ transaction_output_index : 0 ,
1212
+ } , Signature :: from_der( & Secp256k1 :: new( ) , $hex) . unwrap( ) ,
1213
+ Signature :: from_der( & Secp256k1 :: new( ) , $hex) . unwrap( ) ) )
1214
+ }
1215
+
1216
+ Some ( LocalSignedTx {
1217
+ txid: Sha256dHash :: from_data( & [ ] ) ,
1218
+ tx: Transaction {
1219
+ version: 0 ,
1220
+ lock_time: 0 ,
1221
+ input: Vec :: new( ) ,
1222
+ output: Vec :: new( ) ,
1223
+ } ,
1224
+ revocation_key: PublicKey :: new( ) ,
1225
+ a_htlc_key: PublicKey :: new( ) ,
1226
+ b_htlc_key: PublicKey :: new( ) ,
1227
+ delayed_payment_key: PublicKey :: new( ) ,
1228
+ feerate_per_kw: 0 ,
1229
+ htlc_outputs: htlcs,
1230
+ } )
1231
+ }
1232
+ }
1233
+ }
1234
+
1235
+ macro_rules! gen_remote_outpoints {
1236
+ ( $monitor : expr, $tx : expr, $htlcs : expr, $rng : expr, $preimage : expr, $hash: expr, $number : expr) => {
1237
+ {
1238
+ let mut commitment_number = $number;
1239
+
1240
+ for i in 0 ..$tx {
1241
+
1242
+ let tx_zero = Transaction {
1243
+ version : 0 ,
1244
+ lock_time : i,
1245
+ input : Vec :: new( ) ,
1246
+ output: Vec :: new( ) ,
1247
+ } ;
1248
+
1249
+ let mut htlcs = Vec :: new( ) ;
1250
+
1251
+ for _i in 0 ..$htlcs {
1252
+ $rng. fill_bytes( & mut $preimage) ;
1253
+ $hash[ 0 ..20 ] . clone_from_slice( & Hash160 :: from_data( & $preimage) [ 0 ..20 ] ) ;
1254
+ $monitor. provide_payment_preimage( & $hash, & $preimage) ;
1255
+ htlcs. push( HTLCOutputInCommitment {
1256
+ offered : true ,
1257
+ amount_msat : 0 ,
1258
+ cltv_expiry : 0 ,
1259
+ payment_hash : $hash. clone( ) ,
1260
+ transaction_output_index : 0 ,
1261
+ } ) ;
1262
+ }
1263
+ commitment_number -= 1 ;
1264
+ $monitor. provide_latest_remote_commitment_tx_info( & tx_zero, htlcs, commitment_number) ;
1265
+ }
1266
+ }
1267
+ }
1268
+ }
1269
+
1270
+ #[ test]
1271
+ fn test_prune_preimages ( ) {
1272
+
1273
+ let mut monitor: ChannelMonitor ;
1274
+ let mut secrets: Vec < [ u8 ; 32 ] > = Vec :: new ( ) ;
1275
+ let secp_ctx = Secp256k1 :: new ( ) ;
1276
+ let mut preimage: [ u8 ; 32 ] = [ 0 ; 32 ] ;
1277
+ let mut hash: [ u8 ; 32 ] = [ 0 ; 32 ] ;
1278
+ let mut rng = thread_rng ( ) ;
1279
+
1280
+ {
1281
+ // insert 30 random hash, 10 from local, 10 from remote, prune 30/50
1282
+ monitor = ChannelMonitor :: new ( & SecretKey :: from_slice ( & secp_ctx, & [ 42 ; 32 ] ) . unwrap ( ) , & PublicKey :: new ( ) , & SecretKey :: from_slice ( & secp_ctx, & [ 43 ; 32 ] ) . unwrap ( ) , 0 , Script :: new ( ) ) ;
1283
+
1284
+ for _i in 0 ..30 {
1285
+ rng. fill_bytes ( & mut preimage) ;
1286
+ hash[ 0 ..20 ] . clone_from_slice ( & Hash160 :: from_data ( & preimage) [ 0 ..20 ] ) ;
1287
+ monitor. provide_payment_preimage ( & hash, & preimage) ;
1288
+ }
1289
+ monitor. current_local_signed_commitment_tx = gen_local_tx ! ( & hex_bytes( "3045022100fa86fa9a36a8cd6a7bb8f06a541787d51371d067951a9461d5404de6b928782e02201c8b7c334c10aed8976a3a465be9a28abff4cb23acbf00022295b378ce1fa3cd" ) . unwrap( ) [ ..] , monitor, 10 , rng, preimage, hash) ;
1290
+ gen_remote_outpoints ! ( monitor, 1 , 10 , rng, preimage, hash, 281474976710654 ) ;
1291
+ secrets. clear ( ) ;
1292
+ secrets. push ( [ 0 ; 32 ] ) ;
1293
+ secrets. last_mut ( ) . unwrap ( ) [ 0 ..32 ] . clone_from_slice ( & hex_bytes ( "7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc" ) . unwrap ( ) ) ;
1294
+ monitor. provide_secret ( 281474976710655 , secrets. last ( ) . unwrap ( ) . clone ( ) , None ) ;
1295
+ assert_eq ! ( monitor. payment_preimages. len( ) , 20 ) ;
1296
+ }
1297
+
1298
+
1299
+ {
1300
+ // insert 30 random hash, prune 30/30
1301
+ monitor = ChannelMonitor :: new ( & SecretKey :: from_slice ( & secp_ctx, & [ 42 ; 32 ] ) . unwrap ( ) , & PublicKey :: new ( ) , & SecretKey :: from_slice ( & secp_ctx, & [ 43 ; 32 ] ) . unwrap ( ) , 0 , Script :: new ( ) ) ;
1302
+
1303
+ for _i in 0 ..30 {
1304
+ rng. fill_bytes ( & mut preimage) ;
1305
+ hash[ 0 ..20 ] . clone_from_slice ( & Hash160 :: from_data ( & preimage) [ 0 ..20 ] ) ;
1306
+ monitor. provide_payment_preimage ( & hash, & preimage) ;
1307
+ }
1308
+ monitor. current_local_signed_commitment_tx = gen_local_tx ! ( & hex_bytes( "3045022100fa86fa9a36a8cd6a7bb8f06a541787d51371d067951a9461d5404de6b928782e02201c8b7c334c10aed8976a3a465be9a28abff4cb23acbf00022295b378ce1fa3cd" ) . unwrap( ) [ ..] , monitor, 0 , rng, preimage, hash) ;
1309
+ gen_remote_outpoints ! ( monitor, 0 , 0 , rng, preimage, hash, 281474976710655 ) ;
1310
+ secrets. clear ( ) ;
1311
+ secrets. push ( [ 0 ; 32 ] ) ;
1312
+ secrets. last_mut ( ) . unwrap ( ) [ 0 ..32 ] . clone_from_slice ( & hex_bytes ( "7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc" ) . unwrap ( ) ) ;
1313
+ monitor. provide_secret ( 281474976710655 , secrets. last ( ) . unwrap ( ) . clone ( ) , None ) ;
1314
+ assert_eq ! ( monitor. payment_preimages. len( ) , 0 ) ;
1315
+ }
1316
+
1317
+ {
1318
+ // insert 30 random hash, 25 on 5 remotes, prune 30/55
1319
+ monitor = ChannelMonitor :: new ( & SecretKey :: from_slice ( & secp_ctx, & [ 42 ; 32 ] ) . unwrap ( ) , & PublicKey :: new ( ) , & SecretKey :: from_slice ( & secp_ctx, & [ 43 ; 32 ] ) . unwrap ( ) , 0 , Script :: new ( ) ) ;
1320
+
1321
+ for _i in 0 ..30 {
1322
+ rng. fill_bytes ( & mut preimage) ;
1323
+ hash[ 0 ..20 ] . clone_from_slice ( & Hash160 :: from_data ( & preimage) [ 0 ..20 ] ) ;
1324
+ monitor. provide_payment_preimage ( & hash, & preimage) ;
1325
+ }
1326
+ monitor. current_local_signed_commitment_tx = gen_local_tx ! ( & hex_bytes( "3045022100fa86fa9a36a8cd6a7bb8f06a541787d51371d067951a9461d5404de6b928782e02201c8b7c334c10aed8976a3a465be9a28abff4cb23acbf00022295b378ce1fa3cd" ) . unwrap( ) [ ..] , monitor, 0 , rng, preimage, hash) ;
1327
+ gen_remote_outpoints ! ( monitor, 5 , 5 , rng, preimage, hash, 281474976710654 ) ;
1328
+ secrets. clear ( ) ;
1329
+ secrets. push ( [ 0 ; 32 ] ) ;
1330
+ secrets. last_mut ( ) . unwrap ( ) [ 0 ..32 ] . clone_from_slice ( & hex_bytes ( "7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc" ) . unwrap ( ) ) ;
1331
+ monitor. provide_secret ( 281474976710655 , secrets. last ( ) . unwrap ( ) . clone ( ) , None ) ;
1332
+ assert_eq ! ( monitor. payment_preimages. len( ) , 25 ) ;
1333
+ }
1334
+
1335
+ {
1336
+ // insert 30 random hash, 25 from local, prune 30/55
1337
+ monitor = ChannelMonitor :: new ( & SecretKey :: from_slice ( & secp_ctx, & [ 42 ; 32 ] ) . unwrap ( ) , & PublicKey :: new ( ) , & SecretKey :: from_slice ( & secp_ctx, & [ 43 ; 32 ] ) . unwrap ( ) , 0 , Script :: new ( ) ) ;
1338
+
1339
+ for _i in 0 ..30 {
1340
+ rng. fill_bytes ( & mut preimage) ;
1341
+ hash[ 0 ..20 ] . clone_from_slice ( & Hash160 :: from_data ( & preimage) [ 0 ..20 ] ) ;
1342
+ monitor. provide_payment_preimage ( & hash, & preimage) ;
1343
+ }
1344
+ monitor. current_local_signed_commitment_tx = gen_local_tx ! ( & hex_bytes( "3045022100fa86fa9a36a8cd6a7bb8f06a541787d51371d067951a9461d5404de6b928782e02201c8b7c334c10aed8976a3a465be9a28abff4cb23acbf00022295b378ce1fa3cd" ) . unwrap( ) [ ..] , monitor, 25 , rng, preimage, hash) ;
1345
+ gen_remote_outpoints ! ( monitor, 0 , 0 , rng, preimage, hash, 281474976710655 ) ;
1346
+ secrets. clear ( ) ;
1347
+ secrets. push ( [ 0 ; 32 ] ) ;
1348
+ secrets. last_mut ( ) . unwrap ( ) [ 0 ..32 ] . clone_from_slice ( & hex_bytes ( "7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc" ) . unwrap ( ) ) ;
1349
+ monitor. provide_secret ( 281474976710655 , secrets. last ( ) . unwrap ( ) . clone ( ) , None ) ;
1350
+ assert_eq ! ( monitor. payment_preimages. len( ) , 25 ) ;
1351
+ }
1352
+ }
1353
+
1157
1354
// Further testing is done in the ChannelManager integration tests.
1158
1355
}
0 commit comments