Skip to content

Commit

Permalink
Use BumpTransactionEventHandler in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wpaulino committed Apr 27, 2023
1 parent b775aec commit d5e25e5
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 58 deletions.
4 changes: 4 additions & 0 deletions lightning/src/ln/functional_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ pub struct Node<'a, 'b: 'a, 'c: 'b> {
pub blocks: Arc<Mutex<Vec<(Block, u32)>>>,
pub connect_style: Rc<RefCell<ConnectStyle>>,
pub override_init_features: Rc<RefCell<Option<InitFeatures>>>,
#[cfg(anchors)]
pub wallet_utxo_source: test_utils::TestWalletUtxoSource,
}
impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
pub fn best_block_hash(&self) -> BlockHash {
Expand Down Expand Up @@ -2525,6 +2527,8 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
blocks: Arc::clone(&cfgs[i].tx_broadcaster.blocks),
connect_style: Rc::clone(&connect_style),
override_init_features: Rc::clone(&cfgs[i].override_init_features),
#[cfg(anchors)]
wallet_utxo_source: test_utils::TestWalletUtxoSource::new(),
})
}

Expand Down
97 changes: 39 additions & 58 deletions lightning/src/ln/monitor_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::chain::channelmonitor::{ANTI_REORG_DELAY, Balance};
use crate::chain::transaction::OutPoint;
use crate::chain::chaininterface::LowerBoundedFeeEstimator;
#[cfg(anchors)]
use crate::events::bump_transaction::BumpTransactionEvent;
use crate::events::bump_transaction::{BumpTransactionEvent, BumpTransactionEventHandler, Wallet, WalletSource};
use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination};
use crate::ln::channel;
#[cfg(anchors)]
Expand Down Expand Up @@ -1938,7 +1938,6 @@ fn test_yield_anchors_events() {
// allowing the consumer to provide additional fees to the commitment transaction to be
// broadcast. Once the commitment transaction confirms, events for the HTLC resolution should be
// emitted by LDK, such that the consumer can attach fees to the zero fee HTLC transactions.
let secp = Secp256k1::new();
let mut chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let mut anchors_config = UserConfig::default();
Expand All @@ -1955,6 +1954,8 @@ fn test_yield_anchors_events() {

assert!(nodes[0].node.get_and_clear_pending_events().is_empty());

*nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 2;

connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
check_closed_broadcast!(&nodes[0], true);
assert!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
Expand All @@ -1964,34 +1965,38 @@ fn test_yield_anchors_events() {
&LowerBoundedFeeEstimator::new(node_cfgs[0].fee_estimator), &nodes[0].logger
);

let coinbase_tx = Transaction {
version: 2,
lock_time: PackedLockTime::ZERO,
input: vec![TxIn { ..Default::default() }],
output: vec![TxOut { // UTXO to attach fees to `anchor_tx` and `htlc_txs`
value: Amount::ONE_BTC.to_sat(),
script_pubkey: nodes[0].wallet_utxo_source.change_script().unwrap(),
}],
};
nodes[0].wallet_utxo_source.add_utxo(
bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value,
);
nodes[0].wallet_utxo_source.add_utxo(
bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 1 }, coinbase_tx.output[0].value * 2,
);
let wallet = Wallet::new(&nodes[0].wallet_utxo_source);
let bump_event_handler = BumpTransactionEventHandler::new(
nodes[0].tx_broadcaster, &wallet, nodes[0].keys_manager, nodes[0].logger,
);

let mut holder_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
assert_eq!(holder_events.len(), 1);
let (commitment_tx, anchor_tx) = match holder_events.pop().unwrap() {
Event::BumpTransaction(BumpTransactionEvent::ChannelClose { commitment_tx, anchor_descriptor, .. }) => {
assert_eq!(commitment_tx.input.len(), 1);
assert_eq!(commitment_tx.output.len(), 6);
let mut anchor_tx = Transaction {
version: 2,
lock_time: PackedLockTime::ZERO,
input: vec![
TxIn { previous_output: anchor_descriptor.outpoint, ..Default::default() },
TxIn { ..Default::default() },
],
output: vec![TxOut {
value: Amount::ONE_BTC.to_sat(),
script_pubkey: Script::new_op_return(&[]),
}],
};
let signer = nodes[0].keys_manager.derive_channel_keys(
anchor_descriptor.channel_value_satoshis, &anchor_descriptor.channel_keys_id,
);
let funding_sig = signer.sign_holder_anchor_input(&mut anchor_tx, 0, &secp).unwrap();
anchor_tx.input[0].witness = chan_utils::build_anchor_input_witness(
&signer.pubkeys().funding_pubkey, &funding_sig
);
(commitment_tx, anchor_tx)
},
_ => panic!("Unexpected event"),
let (commitment_tx, anchor_tx) = {
bump_event_handler.handle_event(holder_events.pop().unwrap());
let mut txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(txn.len(), 2);
let anchor_tx = txn.pop().unwrap();
let commitment_tx = txn.pop().unwrap();
assert_eq!(commitment_tx.input.len(), 1);
assert_eq!(commitment_tx.output.len(), 6);
check_spends!(anchor_tx, commitment_tx, coinbase_tx);
(commitment_tx, anchor_tx)
};

mine_transactions(&nodes[0], &[&commitment_tx, &anchor_tx]);
Expand All @@ -2011,36 +2016,12 @@ fn test_yield_anchors_events() {
};
let mut htlc_txs = Vec::with_capacity(2);
for event in holder_events {
match event {
Event::BumpTransaction(BumpTransactionEvent::HTLCResolution { htlc_descriptors, tx_lock_time, .. }) => {
assert_eq!(htlc_descriptors.len(), 1);
let htlc_descriptor = &htlc_descriptors[0];
let signer = nodes[0].keys_manager.derive_channel_keys(
htlc_descriptor.channel_value_satoshis, &htlc_descriptor.channel_keys_id
);
let per_commitment_point = signer.get_per_commitment_point(htlc_descriptor.per_commitment_number, &secp);
let mut htlc_tx = Transaction {
version: 2,
lock_time: tx_lock_time,
input: vec![
htlc_descriptor.unsigned_tx_input(), // HTLC input
TxIn { ..Default::default() } // Fee input
],
output: vec![
htlc_descriptor.tx_output(&per_commitment_point, &secp), // HTLC output
TxOut { // Fee input change
value: Amount::ONE_BTC.to_sat(),
script_pubkey: Script::new_op_return(&[]),
}
]
};
let our_sig = signer.sign_holder_htlc_transaction(&mut htlc_tx, 0, htlc_descriptor, &secp).unwrap();
let witness_script = htlc_descriptor.witness_script(&per_commitment_point, &secp);
htlc_tx.input[0].witness = htlc_descriptor.tx_input_witness(&our_sig, &witness_script);
htlc_txs.push(htlc_tx);
},
_ => panic!("Unexpected event"),
}
// Ideally we'd use the change UTXO from `anchor_tx` here to not reuse the same UTXO but it
// doesn't really matter since we're not validating against an actual chain backend anyway.
bump_event_handler.handle_event(event);
let mut txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(txn.len(), 1);
htlc_txs.push(txn.pop().unwrap());
}

mine_transactions(&nodes[0], &[&htlc_txs[0], &htlc_txs[1]]);
Expand Down
77 changes: 77 additions & 0 deletions lightning/src/util/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ use crate::util::config::UserConfig;
use crate::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
use crate::util::logger::{Logger, Level, Record};
use crate::util::ser::{Readable, ReadableArgs, Writer, Writeable};
#[cfg(anchors)]
use bitcoin::Witness;
#[cfg(anchors)]
use bitcoin::blockdata::transaction::EcdsaSighashType;
#[cfg(anchors)]
use bitcoin::util::sighash::SighashCache;
#[cfg(anchors)]
use crate::events::bump_transaction::{Utxo, WalletSource};
#[cfg(anchors)]
use crate::util::crypto::sign;

use bitcoin::blockdata::constants::genesis_block;
use bitcoin::blockdata::transaction::{Transaction, TxOut};
Expand Down Expand Up @@ -1007,3 +1017,70 @@ impl Drop for TestScorer {
}
}
}

#[cfg(anchors)]
pub struct TestWalletUtxoSource {
secp: Secp256k1<bitcoin::secp256k1::All>,
utxos: RefCell<Vec<Utxo>>,
}

#[cfg(anchors)]
impl TestWalletUtxoSource {
pub fn new() -> Self {
Self {
secp: Secp256k1::new(),
utxos: RefCell::new(Vec::new()),
}
}

pub fn add_utxo(&self, outpoint: bitcoin::OutPoint, value: u64) {
let secret_key = SecretKey::from_slice(&[1; 32]).unwrap();
let public_key = bitcoin::PublicKey::new(secret_key.public_key(&self.secp));
let script_pubkey = Script::new_v0_p2wpkh(&public_key.wpubkey_hash().unwrap());
self.utxos.borrow_mut().push(Utxo {
outpoint,
output: TxOut {
value,
script_pubkey,
},
witness_weight: 1 /* num stack items */ + 1 /* sig push */ + 73 /* sig */ + 1 /* pubkey push */ + 33 /* pubkey */,
})
}
}

#[cfg(anchors)]
impl WalletSource for TestWalletUtxoSource {
fn list_confirmed_utxos(&self) -> Result<Vec<Utxo>, ()> {
Ok(self.utxos.borrow().clone())
}
fn change_script(&self) -> Result<Script, ()> {
let secret_key = SecretKey::from_slice(&[1; 32]).unwrap();
let public_key = bitcoin::PublicKey::new(secret_key.public_key(&self.secp));
Ok(Script::new_v0_p2wpkh(&public_key.wpubkey_hash().unwrap()))
}
fn sign_tx(&self, tx: &mut Transaction) -> Result<(), ()> {
let utxos = self.utxos.borrow();
let mut witnesses = Vec::new();
for (idx, input) in tx.input.iter().enumerate() {
let utxo = utxos.iter().find(|utxo| input.previous_output == utxo.outpoint);
if utxo.is_none() {
continue;
}
let utxo = utxo.unwrap();
let secret_key = SecretKey::from_slice(&[1; 32]).unwrap();
let public_key = bitcoin::PublicKey::new(secret_key.public_key(&self.secp));
let witness_script = Script::new_p2pkh(&public_key.pubkey_hash());
let sighash = hash_to_message!(&SighashCache::new(&*tx).segwit_signature_hash(
idx, &witness_script, utxo.output.value, EcdsaSighashType::All
).unwrap()[..]);
let sig = sign(&self.secp, &sighash, &secret_key);
let mut sig = sig.serialize_der().to_vec();
sig.push(EcdsaSighashType::All as u8);
witnesses.push((idx, Witness::from_vec(vec![sig, public_key.to_bytes()])));
}
for (idx, witness) in witnesses {
tx.input[idx].witness = witness;
}
Ok(())
}
}

0 comments on commit d5e25e5

Please sign in to comment.