Skip to content

Commit 41def65

Browse files
author
Antoine Riard
committed
Add test_data_loss_protect
1 parent 254af05 commit 41def65

File tree

1 file changed

+114
-2
lines changed

1 file changed

+114
-2
lines changed

src/ln/functional_tests.rs

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
//! claim outputs on-chain.
44
55
use chain::transaction::OutPoint;
6-
use chain::chaininterface::{ChainListener, ChainWatchInterface};
6+
use chain::chaininterface::{ChainListener, ChainWatchInterface, ChainWatchInterfaceUtil};
77
use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor, KeysManager};
8+
use chain::keysinterface;
89
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
910
use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT};
1011
use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ManyChannelMonitor, ANTI_REORG_DELAY};
@@ -18,6 +19,7 @@ use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsPro
1819
use util::errors::APIError;
1920
use util::ser::{Writeable, ReadableArgs};
2021
use util::config::UserConfig;
22+
use util::logger::Logger;
2123

2224
use bitcoin::util::hash::BitcoinHash;
2325
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
@@ -39,7 +41,7 @@ use secp256k1::key::{PublicKey,SecretKey};
3941

4042
use std::collections::{BTreeSet, HashMap, HashSet};
4143
use std::default::Default;
42-
use std::sync::Arc;
44+
use std::sync::{Arc, Mutex};
4345
use std::sync::atomic::Ordering;
4446
use std::mem;
4547

@@ -5945,3 +5947,113 @@ fn test_user_configurable_csv_delay() {
59455947
}
59465948
} else { assert!(false); }
59475949
}
5950+
5951+
#[test]
5952+
fn test_data_loss_protect() {
5953+
// We want to be sure that :
5954+
// * we don't broadcast our Local Commitment Tx in case of fallen behind
5955+
// * we close channel in case of detecting other being fallen behind
5956+
// * we are able to claim our own outputs thanks to remote my_current_per_commitment_point
5957+
let mut nodes = create_network(2, &[None, None]);
5958+
5959+
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, LocalFeatures::new(), LocalFeatures::new());
5960+
5961+
// Cache node A state before any channel update
5962+
let previous_node_state = nodes[0].node.encode();
5963+
let mut previous_chan_monitor_state = test_utils::TestVecWriter(Vec::new());
5964+
nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap().iter().next().unwrap().1.write_for_disk(&mut previous_chan_monitor_state).unwrap();
5965+
5966+
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
5967+
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
5968+
5969+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
5970+
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
5971+
5972+
// Restore node A from previous state
5973+
let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::with_id(format!("node {}", 0)));
5974+
let chan_monitor = <(Sha256dHash, ChannelMonitor)>::read(&mut ::std::io::Cursor::new(previous_chan_monitor_state.0), Arc::clone(&logger)).unwrap().1;
5975+
let chain_monitor = Arc::new(ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
5976+
let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
5977+
let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
5978+
let monitor = Arc::new(test_utils::TestChannelMonitor::new(chain_monitor.clone(), tx_broadcaster.clone(), logger.clone(), feeest.clone()));
5979+
let mut channel_monitors = HashMap::new();
5980+
channel_monitors.insert(OutPoint { txid: chan.3.txid(), index: 0 }, &chan_monitor);
5981+
let node_state_0 = <(Sha256dHash, ChannelManager)>::read(&mut ::std::io::Cursor::new(previous_node_state), ChannelManagerReadArgs {
5982+
keys_manager: Arc::new(keysinterface::KeysManager::new(&nodes[0].node_seed, Network::Testnet, Arc::clone(&logger), 42, 21)),
5983+
fee_estimator: feeest.clone(),
5984+
monitor: monitor.clone(),
5985+
chain_monitor: chain_monitor.clone(),
5986+
logger: Arc::clone(&logger),
5987+
tx_broadcaster,
5988+
default_config: UserConfig::new(),
5989+
channel_monitors: &channel_monitors
5990+
}).unwrap().1;
5991+
nodes[0].node = Arc::new(node_state_0);
5992+
monitor.add_update_monitor(OutPoint { txid: chan.3.txid(), index: 0 }, chan_monitor.clone()).is_ok();
5993+
nodes[0].chan_monitor = monitor;
5994+
nodes[0].chain_monitor = chain_monitor;
5995+
check_added_monitors!(nodes[0], 1);
5996+
5997+
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
5998+
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id());
5999+
6000+
let reestablish_0 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
6001+
6002+
// Check we update monitor following learning of per_commitment_point from B
6003+
if let Err(err) = nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &reestablish_0[0]) {
6004+
if let Some(error) = err.action {
6005+
match error {
6006+
ErrorAction::SendErrorMessage { msg } => {
6007+
assert_eq!(msg.data, "We have fallen behind - we have received proof that if we broadcast remote is going to claim our funds - we can't do any automated broadcasting");
6008+
},
6009+
_ => panic!("Unexpected event!"),
6010+
}
6011+
} else { assert!(false); }
6012+
} else { assert!(false); }
6013+
check_added_monitors!(nodes[0], 1);
6014+
6015+
{
6016+
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
6017+
assert_eq!(node_txn.len(), 0);
6018+
}
6019+
6020+
let mut reestablish_1 = Vec::with_capacity(1);
6021+
for msg in nodes[0].node.get_and_clear_pending_msg_events() {
6022+
if let MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } = msg {
6023+
assert_eq!(*node_id, nodes[1].node.get_our_node_id());
6024+
reestablish_1.push(msg.clone());
6025+
} else if let MessageSendEvent::BroadcastChannelUpdate { .. } = msg {
6026+
} else {
6027+
panic!("Unexpected event")
6028+
}
6029+
}
6030+
6031+
// Check we close channel detecting A is fallen-behind
6032+
if let Err(err) = nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[0]) {
6033+
if let Some(error) = err.action {
6034+
match error {
6035+
ErrorAction::SendErrorMessage { msg } => {
6036+
assert_eq!(msg.data, "Peer attempted to reestablish channel with a very old local commitment transaction"); },
6037+
_ => panic!("Unexpected event!"),
6038+
}
6039+
} else { assert!(false); }
6040+
} else { assert!(false); }
6041+
6042+
let events = nodes[1].node.get_and_clear_pending_msg_events();
6043+
assert_eq!(events.len(), 1);
6044+
match events[0] {
6045+
MessageSendEvent::BroadcastChannelUpdate { .. } => {},
6046+
_ => panic!("Unexpected event"),
6047+
}
6048+
6049+
// Check A is able to claim to_remote output
6050+
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
6051+
assert_eq!(node_txn.len(), 1);
6052+
check_spends!(node_txn[0], chan.3.clone());
6053+
assert_eq!(node_txn[0].output.len(), 2);
6054+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
6055+
nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![node_txn[0].clone()]}, 1);
6056+
let spend_txn = check_spendable_outputs!(nodes[0], 1);
6057+
assert_eq!(spend_txn.len(), 1);
6058+
check_spends!(spend_txn[0], node_txn[0].clone());
6059+
}

0 commit comments

Comments
 (0)