input: vec![input],
output: vec![outp],
};
+ spend_tx.output[0].value -= (spend_tx.get_weight() + 2 + 1 + 73 + 35 + 3) as u64 / 4; // (Max weight + 3 (to round up)) / 4
let secp_ctx = Secp256k1::new();
let keys = $keysinterface.derive_channel_keys($chan_value, key_derivation_params.0, key_derivation_params.1);
let remotepubkey = keys.pubkeys().payment_point;
let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key);
let witness_script = chan_utils::get_revokeable_redeemscript(revocation_pubkey, *to_self_delay, &delayed_payment_pubkey);
+ spend_tx.output[0].value -= (spend_tx.get_weight() + 2 + 1 + 73 + 1 + witness_script.len() + 1 + 3) as u64 / 4; // (Max weight + 3 (to round up)) / 4
let sighash = Message::from_slice(&bip143::SigHashCache::new(&spend_tx).signature_hash(0, &witness_script, output.value, SigHashType::All)[..]).unwrap();
let local_delayedsig = secp_ctx.sign(&sighash, &delayed_payment_key);
spend_tx.input[0].witness.push(local_delayedsig.serialize_der().to_vec());
input: vec![input],
output: vec![outp.clone()],
};
+ spend_tx.output[0].value -= (spend_tx.get_weight() + 2 + 1 + 73 + 35 + 3) as u64 / 4; // (Max weight + 3 (to round up)) / 4
let secret = {
match ExtendedPrivKey::new_master(Network::Testnet, &$node.node_seed) {
Ok(master_key) => {
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1, 1, true, header.block_hash());
let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000);
- assert_eq!(spend_txn.len(), 2);
- assert_eq!(spend_txn[0], spend_txn[1]);
+ assert_eq!(spend_txn.len(), 1);
check_spends!(spend_txn[0], node_txn[0]);
}
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1, 1, true, header.block_hash());
let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000);
- assert_eq!(spend_txn.len(), 3);
- assert_eq!(spend_txn[0], spend_txn[1]); // to_remote output on revoked remote commitment_tx
- check_spends!(spend_txn[0], revoked_local_txn[0]);
- check_spends!(spend_txn[2], node_txn[0]);
+ assert_eq!(spend_txn.len(), 2);
+ check_spends!(spend_txn[0], revoked_local_txn[0]); // to_remote output on revoked remote commitment_tx
+ check_spends!(spend_txn[1], node_txn[0]);
}
#[test]
expect_payment_failed!(nodes[1], our_payment_hash, true);
let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000);
- assert_eq!(spend_txn.len(), 3); // SpendableOutput: remote_commitment_tx.to_remote (*2), timeout_tx.output (*1)
- check_spends!(spend_txn[2], node_txn[0].clone());
+ assert_eq!(spend_txn.len(), 2); // SpendableOutput: remote_commitment_tx.to_remote, timeout_tx.output
+ check_spends!(spend_txn[1], node_txn[0]);
}
#[test]
// Check A's ChannelMonitor was able to generate the right spendable output descriptor
let spend_txn = check_spendable_outputs!(nodes[0], 1, node_cfgs[0].keys_manager, 100000);
- assert_eq!(spend_txn.len(), 3); // Duplicated SpendableOutput due to block rescan after revoked htlc output tracking
- assert_eq!(spend_txn[0], spend_txn[1]);
+ assert_eq!(spend_txn.len(), 2);
assert_eq!(spend_txn[0].input.len(), 1);
check_spends!(spend_txn[0], revoked_local_txn[0]); // spending to_remote output from revoked local tx
assert_ne!(spend_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
- check_spends!(spend_txn[2], node_txn[1]); // spending justice tx output on the htlc success tx
+ check_spends!(spend_txn[1], node_txn[1]); // spending justice tx output on the htlc success tx
}
#[test]
assert_eq!(b_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
assert!(b_txn[2].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
assert_ne!(b_txn[2].lock_time, 0); // Timeout tx
- check_spends!(b_txn[0], c_txn[1]); // timeout tx on C remote commitment tx, issued by ChannelMonitor, * 2 due to block rescan
+ check_spends!(b_txn[0], c_txn[1]); // timeout tx on C remote commitment tx, issued by ChannelMonitor
assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
assert!(b_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
assert_ne!(b_txn[2].lock_time, 0); // Timeout tx
// Verify that A is able to spend its own HTLC-Timeout tx thanks to spendable output event given back by its ChannelMonitor
let spend_txn = check_spendable_outputs!(nodes[0], 1, node_cfgs[0].keys_manager, 100000);
- assert_eq!(spend_txn.len(), 3);
- assert_eq!(spend_txn[0], spend_txn[1]);
+ assert_eq!(spend_txn.len(), 2);
check_spends!(spend_txn[0], local_txn[0]);
- check_spends!(spend_txn[2], htlc_timeout);
+ check_spends!(spend_txn[1], htlc_timeout);
}
#[test]
// Verify that A is able to spend its own HTLC-Timeout tx thanks to spendable output event given back by its ChannelMonitor
let new_keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
let spend_txn = check_spendable_outputs!(nodes[0], 1, new_keys_manager, 100000);
- assert_eq!(spend_txn.len(), 3);
- assert_eq!(spend_txn[0], spend_txn[1]);
+ assert_eq!(spend_txn.len(), 2);
check_spends!(spend_txn[0], local_txn_1[0]);
- check_spends!(spend_txn[2], htlc_timeout);
+ check_spends!(spend_txn[1], htlc_timeout);
}
#[test]
check_spends!(htlc_txn[1], bob_state_y);
}
}
+
+#[test]
+fn test_htlc_no_detection() {
+ // This test is a mutation to underscore the detection logic bug we had
+ // before #653. HTLC value routed is above the remaining balance, thus
+ // inverting HTLC and `to_remote` output. HTLC will come second and
+ // it wouldn't be seen by pre-#653 detection as we were enumerate()'ing
+ // on a watched outputs vector (Vec<TxOut>) thus implicitly relying on
+ // outputs order detection for correct spending children filtring.
+
+ let chanmon_cfgs = create_chanmon_cfgs(2);
+ let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+ let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+ let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+ // Create some initial channels
+ let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+
+ send_payment(&nodes[0], &vec!(&nodes[1])[..], 1_000_000, 1_000_000);
+ let (_, our_payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1])[..], 2_000_000);
+ let local_txn = get_local_commitment_txn!(nodes[0], chan_1.2);
+ assert_eq!(local_txn[0].input.len(), 1);
+ assert_eq!(local_txn[0].output.len(), 3);
+ check_spends!(local_txn[0], chan_1.3);
+
+ // Timeout HTLC on A's chain and so it can generate a HTLC-Timeout tx
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ connect_block(&nodes[0], &Block { header, txdata: vec![local_txn[0].clone()] }, 200);
+ // We deliberately connect the local tx twice as this should provoke a failure calling
+ // this test before #653 fix.
+ connect_block(&nodes[0], &Block { header, txdata: vec![local_txn[0].clone()] }, 200);
+ check_closed_broadcast!(nodes[0], false);
+ check_added_monitors!(nodes[0], 1);
+
+ let htlc_timeout = {
+ let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert_eq!(node_txn[0].input.len(), 1);
+ assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(node_txn[0], local_txn[0]);
+ node_txn[0].clone()
+ };
+
+ let header_201 = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ connect_block(&nodes[0], &Block { header: header_201, txdata: vec![htlc_timeout.clone()] }, 201);
+ connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1, 201, true, header_201.block_hash());
+ expect_payment_failed!(nodes[0], our_payment_hash, true);
+}