//! claim outputs on-chain.
use chain::transaction::OutPoint;
-use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor};
+use chain::keysinterface::{ChannelKeys, KeysInterface, SpendableOutputDescriptor};
use chain::chaininterface::{ChainListener, ChainWatchInterfaceUtil, BlockNotifier};
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT};
use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ManyChannelMonitor, ANTI_REORG_DELAY};
use ln::channel::{Channel, ChannelError};
-use ln::onion_utils;
+use ln::{chan_utils, onion_utils};
use ln::router::{Route, RouteHop};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs;
check_added_monitors!(nodes[1], 1);
}
+#[test]
+fn test_1_conf_open() {
+ // Previously, if the minium_depth config was set to 1, we'd never send a funding_locked. This
+ // tests that we properly send one in that case.
+ let mut alice_config = UserConfig::default();
+ alice_config.own_channel_config.minimum_depth = 1;
+ alice_config.channel_options.announced_channel = true;
+ alice_config.peer_channel_config_limits.force_announced_channel_preference = false;
+ let mut bob_config = UserConfig::default();
+ bob_config.own_channel_config.minimum_depth = 1;
+ bob_config.channel_options.announced_channel = true;
+ bob_config.peer_channel_config_limits.force_announced_channel_preference = false;
+ let node_cfgs = create_node_cfgs(2);
+ let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(alice_config), Some(bob_config)]);
+ let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+ let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::supported(), InitFeatures::supported());
+ assert!(nodes[0].chain_monitor.does_match_tx(&tx));
+ assert!(nodes[1].chain_monitor.does_match_tx(&tx));
+
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[1].block_notifier.block_connected_checked(&header, 1, &[&tx; 1], &[tx.version; 1]);
+ nodes[0].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingLocked, nodes[0].node.get_our_node_id()));
+
+ nodes[0].block_notifier.block_connected_checked(&header, 1, &[&tx; 1], &[tx.version; 1]);
+ let (funding_locked, _) = create_chan_between_nodes_with_value_confirm_second(&nodes[1], &nodes[0]);
+ let (announcement, as_update, bs_update) = create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &funding_locked);
+
+ for node in nodes {
+ assert!(node.router.handle_channel_announcement(&announcement).unwrap());
+ node.router.handle_channel_update(&as_update).unwrap();
+ node.router.handle_channel_update(&bs_update).unwrap();
+ }
+}
+
#[test]
fn test_update_fee_vanilla() {
let node_cfgs = create_node_cfgs(2);
nodes[0].router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id : as_chan.get_short_channel_id().unwrap(), is_permanent: false } );
- let as_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &as_chan.get_local_keys().inner.funding_key);
- let bs_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &bs_chan.get_local_keys().inner.funding_key);
+ let as_bitcoin_key = as_chan.get_local_keys().inner.local_channel_pubkeys.funding_pubkey;
+ let bs_bitcoin_key = bs_chan.get_local_keys().inner.local_channel_pubkeys.funding_pubkey;
let as_network_key = nodes[0].node.get_our_node_id();
let bs_network_key = nodes[1].node.get_our_node_id();
macro_rules! sign_msg {
($unsigned_msg: expr) => {
let msghash = Message::from_slice(&Sha256dHash::hash(&$unsigned_msg.encode()[..])[..]).unwrap();
- let as_bitcoin_sig = secp_ctx.sign(&msghash, &as_chan.get_local_keys().inner.funding_key);
- let bs_bitcoin_sig = secp_ctx.sign(&msghash, &bs_chan.get_local_keys().inner.funding_key);
+ let as_bitcoin_sig = secp_ctx.sign(&msghash, &as_chan.get_local_keys().inner.funding_key());
+ let bs_bitcoin_sig = secp_ctx.sign(&msghash, &bs_chan.get_local_keys().inner.funding_key());
let as_node_sig = secp_ctx.sign(&msghash, &nodes[0].keys_manager.get_node_secret());
let bs_node_sig = secp_ctx.sign(&msghash, &nodes[1].keys_manager.get_node_secret());
chan_announcement = msgs::ChannelAnnouncement {
new_chan_monitor = test_utils::TestChannelMonitor::new(nodes[0].chain_monitor.clone(), nodes[0].tx_broadcaster.clone(), Arc::new(test_utils::TestLogger::new()), Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 }));
nodes[0].chan_monitor = &new_chan_monitor;
let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..];
- let (_, mut chan_0_monitor) = <(Sha256dHash, ChannelMonitor)>::read(&mut chan_0_monitor_read, Arc::new(test_utils::TestLogger::new())).unwrap();
+ let (_, mut chan_0_monitor) = <(Sha256dHash, ChannelMonitor<EnforcingChannelKeys>)>::read(&mut chan_0_monitor_read, Arc::new(test_utils::TestLogger::new())).unwrap();
assert!(chan_0_monitor_read.is_empty());
let mut nodes_0_read = &nodes_0_serialized[..];
new_chan_monitor = test_utils::TestChannelMonitor::new(nodes[0].chain_monitor.clone(), nodes[0].tx_broadcaster.clone(), Arc::new(test_utils::TestLogger::new()), Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 }));
nodes[0].chan_monitor = &new_chan_monitor;
let mut chan_0_monitor_read = &chan_0_monitor_serialized.0[..];
- let (_, mut chan_0_monitor) = <(Sha256dHash, ChannelMonitor)>::read(&mut chan_0_monitor_read, Arc::new(test_utils::TestLogger::new())).unwrap();
+ let (_, mut chan_0_monitor) = <(Sha256dHash, ChannelMonitor<EnforcingChannelKeys>)>::read(&mut chan_0_monitor_read, Arc::new(test_utils::TestLogger::new())).unwrap();
assert!(chan_0_monitor_read.is_empty());
let mut nodes_0_read = &nodes_0_serialized[..];
let mut node_0_monitors = Vec::new();
for serialized in node_0_monitors_serialized.iter() {
let mut read = &serialized[..];
- let (_, monitor) = <(Sha256dHash, ChannelMonitor)>::read(&mut read, Arc::new(test_utils::TestLogger::new())).unwrap();
+ let (_, monitor) = <(Sha256dHash, ChannelMonitor<EnforcingChannelKeys>)>::read(&mut read, Arc::new(test_utils::TestLogger::new())).unwrap();
assert!(read.is_empty());
node_0_monitors.push(monitor);
}
// Restore node A from previous state
let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::with_id(format!("node {}", 0)));
- let mut chan_monitor = <(Sha256dHash, ChannelMonitor)>::read(&mut ::std::io::Cursor::new(previous_chan_monitor_state.0), Arc::clone(&logger)).unwrap().1;
+ let mut chan_monitor = <(Sha256dHash, ChannelMonitor<EnforcingChannelKeys>)>::read(&mut ::std::io::Cursor::new(previous_chan_monitor_state.0), Arc::clone(&logger)).unwrap().1;
let chain_monitor = Arc::new(ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
// Connect three more block to see if bumped penalty are issued for HTLC txn
let header_132 = connect_blocks(&nodes[0].block_notifier, 3, 129, true, header_129.bitcoin_hash());
- let node_txn = {
+ let penalty_local_tx;
+ {
let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 5); // 2 bumped penalty txn on offered/received HTLC outputs of revoked commitment tx + 1 penalty tx on to_local of revoked commitment tx + 2 bumped penalty tx on revoked HTLC txn
+ assert_eq!(node_txn.len(), 3); // 2 bumped penalty txn on offered/received HTLC outputs of revoked commitment tx + 1 penalty tx on to_local of revoked commitment tx + 2 bumped penalty tx on revoked HTLC txn
check_spends!(node_txn[0], revoked_local_txn[0].clone());
check_spends!(node_txn[1], revoked_local_txn[0].clone());
- let mut penalty_local = ::std::usize::MAX;
+ check_spends!(node_txn[2], revoked_local_txn[0].clone());
+
+ penalty_local_tx = node_txn[2].clone();
+ node_txn.clear();
+ };
+ // Few more blocks to broadcast and confirm penalty_local_tx
+ let header_133 = BlockHeader { version: 0x20000000, prev_blockhash: header_132, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[0].block_notifier.block_connected(&Block { header: header_133, txdata: vec![penalty_local_tx] }, 133);
+ let header_135 = connect_blocks(&nodes[0].block_notifier, 2, 133, true, header_133.bitcoin_hash());
+ {
+ let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert_eq!(node_txn.len(), 1);
+ check_spends!(node_txn[0], revoked_local_txn[0].clone());
+ node_txn.clear();
+ }
+ let header_144 = connect_blocks(&nodes[0].block_notifier, 9, 135, true, header_135);
+ let node_txn = {
+ let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert_eq!(node_txn.len(), 2);
+
let mut penalty_offered = ::std::usize::MAX;
let mut penalty_received = ::std::usize::MAX;
{
- let iter_txn = node_txn[2..].iter();
- for (i, tx) in iter_txn.enumerate() {
- if tx.input[0].previous_output.txid == revoked_local_txn[0].txid() {
- penalty_local = 2 + i;
- } else if tx.input[0].previous_output.txid == revoked_htlc_txn[offered].txid() {
- penalty_offered = 2+ i;
+ for (i, tx) in node_txn.iter().enumerate() {
+ if tx.input[0].previous_output.txid == revoked_htlc_txn[offered].txid() {
+ penalty_offered = i;
} else if tx.input[0].previous_output.txid == revoked_htlc_txn[received].txid() {
- penalty_received = 2 + i;
+ penalty_received = i;
}
}
}
- check_spends!(node_txn[penalty_local], revoked_local_txn[0].clone());
assert_eq!(node_txn[penalty_received].input.len(), 1);
assert_eq!(node_txn[penalty_received].output.len(), 1);
let fee = revoked_htlc_txn[received].output[0].value - node_txn[penalty_received].output[0].value;
let new_feerate = fee * 1000 / node_txn[penalty_received].get_weight() as u64;
assert!(new_feerate * 100 > feerate_2 * 125);
- let txn = vec![node_txn[2].clone(), node_txn[3].clone(), node_txn[4].clone()];
+ let txn = vec![node_txn[0].clone(), node_txn[1].clone()];
node_txn.clear();
txn
};
// Broadcast claim txn and confirm blocks to avoid further bumps on this outputs
- let header_133 = BlockHeader { version: 0x20000000, prev_blockhash: header_132, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- nodes[0].block_notifier.block_connected(&Block { header: header_133, txdata: node_txn }, 133);
- let header_140 = connect_blocks(&nodes[0].block_notifier, 6, 134, true, header_133.bitcoin_hash());
+ let header_145 = BlockHeader { version: 0x20000000, prev_blockhash: header_144, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[0].block_notifier.block_connected(&Block { header: header_145, txdata: node_txn }, 145);
+ connect_blocks(&nodes[0].block_notifier, 20, 145, true, header_145.bitcoin_hash());
{
let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- node_txn.clear();
- }
-
- // Connect few more blocks and check only penalty transaction for to_local output have been issued
- connect_blocks(&nodes[0].block_notifier, 7, 140, true, header_140);
- {
- let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
- assert_eq!(node_txn.len(), 2); //TODO: should be zero when we fix check_spend_remote_htlc
+ assert_eq!(node_txn.len(), 2); //TODO: fix check_spend_remote_htlc lack of watch output
node_txn.clear();
}
check_closed_broadcast!(nodes[0], false);
}
}
+#[test]
+fn test_counterparty_raa_skip_no_crash() {
+ // Previously, if our counterparty sent two RAAs in a row without us having provided a
+ // commitment transaction, we would have happily carried on and provided them the next
+ // commitment transaction based on one RAA forward. This would probably eventually have led to
+ // channel closure, but it would not have resulted in funds loss. Still, our
+ // EnforcingChannelKeys would have paniced as it doesn't like jumps into the future. Here, we
+ // check simply that the channel is closed in response to such an RAA, but don't check whether
+ // we decide to punish our counterparty for revoking their funds (as we don't currently
+ // implement that).
+ let node_cfgs = create_node_cfgs(2);
+ let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+ let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+ let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::supported(), InitFeatures::supported()).2;
+
+ let commitment_seed = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&channel_id).unwrap().local_keys.commitment_seed().clone();
+ const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
+ let next_per_commitment_point = PublicKey::from_secret_key(&Secp256k1::new(),
+ &SecretKey::from_slice(&chan_utils::build_commitment_secret(&commitment_seed, INITIAL_COMMITMENT_NUMBER - 2)).unwrap());
+ let per_commitment_secret = chan_utils::build_commitment_secret(&commitment_seed, INITIAL_COMMITMENT_NUMBER);
+
+ nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(),
+ &msgs::RevokeAndACK { channel_id, per_commitment_secret, next_per_commitment_point });
+ assert_eq!(check_closed_broadcast!(nodes[1], true).unwrap().data, "Received an unexpected revoke_and_ack");
+}
+
#[test]
fn test_bump_txn_sanitize_tracking_maps() {
// Sanitizing pendning_claim_request and claimable_outpoints used to be buggy,