diff --git a/.gitignore b/.gitignore index fbeffa8a9c9..780bfdb1445 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,6 @@ lightning/net_graph-*.bin lightning-rapid-gossip-sync/res/full_graph.lngossip lightning-custom-message/target lightning-transaction-sync/target +ext-functional-test-demo/target no-std-check/target msrv-no-dev-deps-check/target diff --git a/Cargo.toml b/Cargo.toml index 54b552b31a1..3aecd48aa79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ ] exclude = [ + "ext-functional-test-demo", "no-std-check", "msrv-no-dev-deps-check", "bench", diff --git a/ci/ci-tests.sh b/ci/ci-tests.sh index 47f0621683c..37df655a0d2 100755 --- a/ci/ci-tests.sh +++ b/ci/ci-tests.sh @@ -138,6 +138,12 @@ cargo check --verbose --color always --features lightning-transaction-sync [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean popd +echo -e "\n\Running functional tests from outside the workspace" +pushd ext-functional-test-demo +cargo test --color always +[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean +popd + # Test that we can build downstream code with only the "release pins". pushd msrv-no-dev-deps-check PIN_RELEASE_DEPS diff --git a/ext-functional-test-demo/Cargo.toml b/ext-functional-test-demo/Cargo.toml new file mode 100644 index 00000000000..f86c78bd839 --- /dev/null +++ b/ext-functional-test-demo/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ext-functional-tester" +version = "0.1.0" +edition = "2021" + +[dependencies] +lightning = { path = "../lightning", features = ["_test_utils"] } diff --git a/ext-functional-test-demo/src/main.rs b/ext-functional-test-demo/src/main.rs new file mode 100644 index 00000000000..98a554b07e5 --- /dev/null +++ b/ext-functional-test-demo/src/main.rs @@ -0,0 +1,31 @@ +fn main() { + println!("Hello, world!"); +} + +#[cfg(test)] +mod tests { + use lightning::util::dyn_signer::{DynKeysInterfaceTrait, DynSigner}; + use lightning::util::test_utils::{TestSignerFactory, SIGNER_FACTORY}; + use std::panic::catch_unwind; + use std::sync::Arc; + use std::time::Duration; + + struct BrokenSignerFactory(); + + impl TestSignerFactory for BrokenSignerFactory { + fn make_signer( + &self, _seed: &[u8; 32], _now: Duration, + ) -> Box> { + panic!() + } + } + + #[test] + fn test_functional() { + lightning::ln::functional_tests::test_insane_channel_opens(); + lightning::ln::functional_tests::fake_network_test(); + + SIGNER_FACTORY.set(Arc::new(BrokenSignerFactory())); + catch_unwind(|| lightning::ln::functional_tests::fake_network_test()).unwrap_err(); + } +} diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 9616b6f54b9..cd36fef3f60 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -81,6 +81,7 @@ use bitcoin::secp256k1::schnorr; use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey}; use lightning::io::Cursor; +use lightning::util::dyn_signer::DynSigner; use std::cmp::{self, Ordering}; use std::mem; use std::sync::atomic; @@ -391,6 +392,7 @@ impl SignerProvider for KeyProvider { channel_keys_id, ); let revoked_commitment = self.make_enforcement_state_cell(keys.commitment_seed); + let keys = DynSigner::new(keys); TestChannelSigner::new_with_revoked(keys, revoked_commitment, false) } @@ -399,6 +401,7 @@ impl SignerProvider for KeyProvider { let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; let state = self.make_enforcement_state_cell(inner.commitment_seed); + let inner = DynSigner::new(inner); Ok(TestChannelSigner::new_with_revoked(inner, state, false)) } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 8ce17c93dbd..cf57126c384 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -77,6 +77,7 @@ use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature}; use bitcoin::secp256k1::schnorr; use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey}; +use lightning::util::dyn_signer::DynSigner; use std::cell::RefCell; use std::cmp; use std::convert::TryInto; @@ -455,7 +456,7 @@ impl SignerProvider for KeyProvider { let ctr = channel_keys_id[0]; let (inbound, state) = self.signer_state.borrow().get(&ctr).unwrap().clone(); TestChannelSigner::new_with_revoked( - if inbound { + DynSigner::new(if inbound { InMemorySigner::new( &secp_ctx, SecretKey::from_slice(&[ @@ -527,7 +528,7 @@ impl SignerProvider for KeyProvider { channel_keys_id, channel_keys_id, ) - }, + }), state, false, ) @@ -536,6 +537,7 @@ impl SignerProvider for KeyProvider { fn read_chan_signer(&self, mut data: &[u8]) -> Result { let inner: InMemorySigner = ReadableArgs::read(&mut data, self)?; let state = Arc::new(Mutex::new(EnforcementState::new())); + let inner = DynSigner::new(inner); Ok(TestChannelSigner::new_with_revoked(inner, state, false)) } diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index fdeb46229a3..b3f6eb34031 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -2557,6 +2557,8 @@ mod tests { failure: PathFailure::OnPath { network_update: None }, path: path.clone(), short_channel_id: Some(scored_scid), + error_code: None, + error_data: None, }); let event = $receive.expect("PaymentPathFailed not handled within deadline"); match event { @@ -2574,6 +2576,8 @@ mod tests { failure: PathFailure::OnPath { network_update: None }, path: path.clone(), short_channel_id: None, + error_code: None, + error_data: None, }); let event = $receive.expect("PaymentPathFailed not handled within deadline"); match event { diff --git a/lightning/Cargo.toml b/lightning/Cargo.toml index f85c18d89b4..40ad96b79eb 100644 --- a/lightning/Cargo.toml +++ b/lightning/Cargo.toml @@ -17,7 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] # Internal test utilities exposed to other repo crates -_test_utils = ["regex", "bitcoin/bitcoinconsensus", "lightning-types/_test_utils"] +_test_utils = ["regex", "bitcoin/bitcoinconsensus", "ext-test-macro", "lightning-types/_test_utils"] # Unlog messages superior at targeted level. max_level_off = [] max_level_error = [] @@ -50,6 +50,7 @@ backtrace = { version = "0.3", optional = true } libm = { version = "0.2", default-features = false } delegate = "0.12.0" +ext-test-macro = { path = "../ext-test-macro", optional = true } [dev-dependencies] regex = "1.5.6" diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index afd9df62851..9cd647271f6 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -464,7 +464,7 @@ where C::Target: chain::Filter, } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn remove_monitor(&self, funding_txo: &OutPoint) -> ChannelMonitor { self.monitors.write().unwrap().remove(funding_txo).unwrap().monitor } diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 86f0d3de5ed..c57b3c433f7 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -844,10 +844,7 @@ impl Readable for IrrevocablyResolvedHTLC { /// returned block hash and the the current chain and then reconnecting blocks to get to the /// best chain) upon deserializing the object! pub struct ChannelMonitor { - #[cfg(test)] pub(crate) inner: Mutex>, - #[cfg(not(test))] - pub(super) inner: Mutex>, } impl Clone for ChannelMonitor where Signer: Clone { @@ -946,9 +943,9 @@ pub(crate) struct ChannelMonitorImpl { // Obviously Correct (tm) if we just keep track of them explicitly. outputs_to_watch: HashMap>, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub onchain_tx_handler: OnchainTxHandler, - #[cfg(not(test))] + #[cfg(not(any(test, feature = "_test_utils")))] onchain_tx_handler: OnchainTxHandler, // This is set when the Channel[Manager] generated a ChannelMonitorUpdate which indicated the @@ -1726,7 +1723,7 @@ impl ChannelMonitor { /// Unsafe test-only version of `broadcast_latest_holder_commitment_txn` used by our test framework /// to bypass HolderCommitmentTransaction state update lockdown after signature and generate /// revoked commitment transaction. - #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] pub fn unsafe_get_latest_holder_commitment_txn(&self, logger: &L) -> Vec where L::Target: Logger { let mut inner = self.inner.lock().unwrap(); @@ -2026,7 +2023,7 @@ impl ChannelMonitor { self.inner.lock().unwrap().counterparty_payment_script = script; } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn do_mut_signer_call ()>(&self, mut f: F) { let mut inner = self.inner.lock().unwrap(); f(&mut inner.onchain_tx_handler.signer); @@ -2668,7 +2665,7 @@ macro_rules! fail_unbroadcast_htlcs { // witness length match (ie is 136 bytes long). We generate one here which we also use in some // in-line tests later. -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] pub fn deliberately_bogus_accepted_htlc_witness_program() -> Vec { use bitcoin::opcodes; let mut ret = [opcodes::all::OP_NOP.to_u8(); 136]; @@ -2680,7 +2677,7 @@ pub fn deliberately_bogus_accepted_htlc_witness_program() -> Vec { Vec::from(&ret[..]) } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] pub fn deliberately_bogus_accepted_htlc_witness() -> Vec> { vec![Vec::new(), Vec::new(), Vec::new(), Vec::new(), deliberately_bogus_accepted_htlc_witness_program().into()].into() } @@ -3808,7 +3805,7 @@ impl ChannelMonitorImpl { } } - #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] /// Note that this includes possibly-locktimed-in-the-future transactions! fn unsafe_get_latest_holder_commitment_txn( &mut self, logger: &WithChannelMonitor @@ -5066,7 +5063,7 @@ mod tests { nodes[1].chain_monitor.chain_monitor.transactions_confirmed(&new_header, &[(0, broadcast_tx)], conf_height); - let (_, pre_update_monitor) = <(BlockHash, ChannelMonitor)>::read( + let (_, pre_update_monitor) = <(BlockHash, ChannelMonitor<_>)>::read( &mut io::Cursor::new(&get_monitor!(nodes[1], channel.2).encode()), (&nodes[1].keys_manager.backing, &nodes[1].keys_manager.backing)).unwrap(); diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index 7ac8f9a63f6..31c690fce54 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -249,10 +249,7 @@ pub struct OnchainTxHandler { // Key is identifier of the pending claim request, i.e the txid of the initial claiming transaction generated by // us and is immutable until all outpoint of the claimable set are post-anti-reorg-delay solved. // Entry is cache of elements need to generate a bumped claiming transaction (see ClaimTxBumpMaterial) - #[cfg(test)] // Used in functional_test to verify sanitization pub(crate) pending_claim_requests: HashMap, - #[cfg(not(test))] - pending_claim_requests: HashMap, // Used to track external events that need to be forwarded to the `ChainMonitor`. This `Vec` // essentially acts as an insertion-ordered `HashMap` – there should only ever be one occurrence @@ -272,10 +269,7 @@ pub struct OnchainTxHandler { // block height, and are immutable until the outpoint has enough confirmations to meet our // [`ANTI_REORG_DELAY`]. The initial confirmation block height is used to remove the entry if // the block gets disconnected. - #[cfg(test)] // Used in functional_test to verify sanitization - pub claimable_outpoints: HashMap, - #[cfg(not(test))] - claimable_outpoints: HashMap, + pub(crate) claimable_outpoints: HashMap, locktimed_packages: BTreeMap>, @@ -1176,7 +1170,7 @@ impl OnchainTxHandler { MaybeSignedTransaction(tx) } - #[cfg(any(test, feature="unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature="_test_utils", feature="unsafe_revoked_tx_signing"))] pub(crate) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction { let sig = self.signer.unsafe_sign_holder_commitment(&self.holder_commitment, &self.secp_ctx).expect("sign holder commitment"); self.holder_commitment.add_holder_sig(funding_redeemscript, sig) diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index 379a0d79a9a..bfb9a647e97 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -1009,9 +1009,9 @@ pub enum Event { /// If this is `Some`, then the corresponding channel should be avoided when the payment is /// retried. May be `None` for older [`Event`] serializations. short_channel_id: Option, -#[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_code: Option, -#[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_data: Option>, }, /// Indicates that a probe payment we sent returned successful, i.e., only failed at the destination. @@ -1509,15 +1509,15 @@ impl Writeable for Event { &Event::PaymentPathFailed { ref payment_id, ref payment_hash, ref payment_failed_permanently, ref failure, ref path, ref short_channel_id, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] ref error_code, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] ref error_data, } => { 3u8.write(writer)?; - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_code.write(writer)?; - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_data.write(writer)?; write_tlv_fields!(writer, { (0, payment_hash, required), @@ -1850,9 +1850,9 @@ impl MaybeReadable for Event { }, 3u8 => { let mut f = || { - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] let error_code = Readable::read(reader)?; - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] let error_data = Readable::read(reader)?; let mut payment_hash = PaymentHash([0; 32]); let mut payment_failed_permanently = false; @@ -1882,9 +1882,9 @@ impl MaybeReadable for Event { failure, path: Path { hops: path.unwrap(), blinded_tail }, short_channel_id, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_code, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_data, })) }; diff --git a/lightning/src/ln/bolt11_payment.rs b/lightning/src/ln/bolt11_payment.rs index 13840dc05d7..a88acf8ab4b 100644 --- a/lightning/src/ln/bolt11_payment.rs +++ b/lightning/src/ln/bolt11_payment.rs @@ -89,6 +89,7 @@ mod tests { use super::*; use crate::ln::types::PaymentSecret; use crate::routing::router::Payee; + use crate::sign::{NodeSigner, Recipient}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use lightning_invoice::{Currency, InvoiceBuilder}; @@ -178,8 +179,6 @@ mod tests { let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(None, 7200, None).unwrap(); - let secp_ctx = Secp256k1::new(); - let node_secret = nodes[1].keys_manager.backing.get_node_secret_key(); let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); let invoice = InvoiceBuilder::new(Currency::Bitcoin) .description("test".into()) @@ -189,8 +188,11 @@ mod tests { .min_final_cltv_expiry_delta(144) .amount_milli_satoshis(50_000) .payment_metadata(payment_metadata.clone()) - .build_signed(|hash| secp_ctx.sign_ecdsa_recoverable(hash, &node_secret)) + .build_raw() .unwrap(); + let sig = nodes[1].keys_manager.backing.sign_invoice(&invoice, Recipient::Node).unwrap(); + let invoice = invoice.sign::<_, ()>(|_| Ok(sig)).unwrap(); + let invoice = Bolt11Invoice::from_signed(invoice).unwrap(); let (hash, onion, params) = payment_parameters_from_invoice(&invoice).unwrap(); nodes[0] diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index d543142e1ab..d2257ec56d4 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -176,9 +176,9 @@ impl HTLCClaim { } } -#[cfg(not(test))] +#[cfg(not(any(test, feature = "_test_utils")))] const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; pub(crate) fn commitment_tx_base_weight(channel_type_features: &ChannelTypeFeatures) -> u64 { diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 46b35a94038..e87fab173cd 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -66,7 +66,8 @@ use crate::sign::type_resolver::ChannelSignerType; use super::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint}; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] +#[allow(unused)] pub struct ChannelValueStat { pub value_to_self_msat: u64, pub channel_value_msat: u64, @@ -1055,9 +1056,9 @@ impl HolderCommitmentPoint { /// the channel. Sadly, there isn't really a good number for this - if we expect to have no new /// HTLCs for days we may need this to suffice for feerate increases across days, but that may /// leave the channel less usable as we hold a bigger reserve. -#[cfg(any(fuzzing, test))] +#[cfg(any(fuzzing, test, feature = "_test_utils"))] pub const FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE: u64 = 2; -#[cfg(not(any(fuzzing, test)))] +#[cfg(not(any(fuzzing, test, feature = "_test_utils")))] const FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE: u64 = 2; /// If we fail to see a funding transaction confirmed on-chain within this many blocks after the @@ -1316,9 +1317,9 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { /// The minimum and maximum absolute fee, in satoshis, we are willing to place on the closing /// transaction. These are set once we reach `closing_negotiation_ready`. - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(crate) closing_fee_limits: Option<(u64, u64)>, - #[cfg(not(test))] + #[cfg(not(any(test, feature = "_test_utils")))] closing_fee_limits: Option<(u64, u64)>, /// If we remove an HTLC (or fee update), commit, and receive our counterparty's @@ -1345,34 +1346,22 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { counterparty_dust_limit_satoshis: u64, - #[cfg(test)] pub(super) holder_dust_limit_satoshis: u64, - #[cfg(not(test))] - holder_dust_limit_satoshis: u64, - #[cfg(test)] pub(super) counterparty_max_htlc_value_in_flight_msat: u64, - #[cfg(not(test))] - counterparty_max_htlc_value_in_flight_msat: u64, - #[cfg(test)] pub(super) holder_max_htlc_value_in_flight_msat: u64, - #[cfg(not(test))] - holder_max_htlc_value_in_flight_msat: u64, /// minimum channel reserve for self to maintain - set by them. counterparty_selected_channel_reserve_satoshis: Option, - #[cfg(test)] pub(super) holder_selected_channel_reserve_satoshis: u64, - #[cfg(not(test))] - holder_selected_channel_reserve_satoshis: u64, counterparty_htlc_minimum_msat: u64, holder_htlc_minimum_msat: u64, - #[cfg(test)] + #[cfg(any(test, feature="_test_utils"))] pub counterparty_max_accepted_htlcs: u16, - #[cfg(not(test))] + #[cfg(not(any(test, feature="_test_utils")))] counterparty_max_accepted_htlcs: u16, holder_max_accepted_htlcs: u16, minimum_depth: Option, @@ -1484,9 +1473,9 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { /// The unique identifier used to re-derive the private key material for the channel through /// [`SignerProvider::derive_channel_signer`]. - #[cfg(not(test))] + #[cfg(not(any(test, feature = "_test_utils")))] channel_keys_id: [u8; 32], - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub channel_keys_id: [u8; 32], /// If we can't release a [`ChannelMonitorUpdate`] until some external action completes, we @@ -2188,7 +2177,7 @@ impl ChannelContext where SP::Target: SignerProvider { } /// Returns the holder signer for this channel. - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn get_mut_signer(&mut self) -> &mut ChannelSignerType { return &mut self.holder_signer } @@ -6476,12 +6465,12 @@ impl Channel where self.context.cur_counterparty_commitment_transaction_number + 2 } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn get_signer(&self) -> &ChannelSignerType { &self.context.holder_signer } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn get_value_stat(&self) -> ChannelValueStat { ChannelValueStat { value_to_self_msat: self.context.value_to_self_msat, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 7e13d56667f..cbfffad7be8 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -2200,10 +2200,7 @@ where message_router: MR, /// See `ChannelManager` struct-level documentation for lock order requirements. - #[cfg(test)] pub(super) best_block: RwLock, - #[cfg(not(test))] - best_block: RwLock, secp_ctx: Secp256k1, /// Storage for PaymentSecrets and any requirements on future inbound payments before we will @@ -2292,9 +2289,6 @@ where /// required to access the channel with the `counterparty_node_id`. /// /// See `ChannelManager` struct-level documentation for lock order requirements. - #[cfg(not(test))] - outpoint_to_peer: Mutex>, - #[cfg(test)] pub(crate) outpoint_to_peer: Mutex>, /// SCIDs (and outbound SCID aliases) -> `counterparty_node_id`s and `channel_id`s. @@ -4165,7 +4159,7 @@ where }) } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(crate) fn test_send_payment_along_path(&self, path: &Path, payment_hash: &PaymentHash, recipient_onion: RecipientOnionFields, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option, session_priv_bytes: [u8; 32]) -> Result<(), APIError> { let _lck = self.total_consistency_lock.read().unwrap(); self.send_payment_along_path(SendAlongPathArgs { @@ -4342,7 +4336,7 @@ where &self.pending_events, |args| self.send_payment_along_path(args)) } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(super) fn test_send_payment_internal(&self, route: &Route, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, keysend_preimage: Option, payment_id: PaymentId, recv_value_msat: Option, onion_session_privs: Vec<[u8; 32]>) -> Result<(), PaymentSendFailure> { let best_block_height = self.best_block.read().unwrap().height; let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); @@ -4351,7 +4345,7 @@ where best_block_height, |args| self.send_payment_along_path(args)) } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(crate) fn test_add_new_pending_payment(&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId, route: &Route) -> Result, PaymentSendFailure> { let best_block_height = self.best_block.read().unwrap().height; self.pending_outbound_payments.test_add_new_pending_payment(payment_hash, recipient_onion, payment_id, route, None, &self.entropy_source, best_block_height) @@ -4804,7 +4798,7 @@ where Ok(()) } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(crate) fn funding_transaction_generated_unchecked(&self, temporary_channel_id: ChannelId, counterparty_node_id: PublicKey, funding_transaction: Transaction, output_index: u16) -> Result<(), APIError> { let txid = funding_transaction.compute_txid(); self.funding_transaction_generated_intern(temporary_channel_id, counterparty_node_id, funding_transaction, false, |_| { diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index afab38c7bc2..feac57130ed 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -27,11 +27,11 @@ use crate::routing::router::{self, PaymentParameters, Route, RouteParameters}; use crate::sign::{EntropySource, RandomBytes}; use crate::util::config::{UserConfig, MaxDustHTLCExposure}; use crate::util::errors::APIError; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] use crate::util::logger::Logger; use crate::util::scid_utils; use crate::util::test_channel_signer::TestChannelSigner; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] use crate::util::test_channel_signer::SignerOp; use crate::util::test_utils; use crate::util::test_utils::{TestChainMonitor, TestScorer, TestKeysInterface}; @@ -496,7 +496,7 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> { /// Toggles this node's signer to be available for the given signer operation. /// This is useful for testing behavior for restoring an async signer that previously /// could not return a signature immediately. - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn enable_channel_signer_op(&self, peer_id: &PublicKey, chan_id: &ChannelId, signer_op: SignerOp) { self.set_channel_signer_ops(peer_id, chan_id, signer_op, true); } @@ -516,7 +516,7 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> { /// will behave normally, returning `Ok`. When set to `false`, and the channel signer will /// act like an off-line remote signer, returning `Err`. This applies to the signer in all /// relevant places, i.e. the channel manager, chain monitor, and the keys manager. - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] fn set_channel_signer_ops(&self, peer_id: &PublicKey, chan_id: &ChannelId, signer_op: SignerOp, available: bool) { use crate::sign::ChannelSigner; log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available); @@ -969,7 +969,7 @@ pub fn remove_first_msg_event_to_node(msg_node_id: &PublicKey, msg_events: &mut } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] macro_rules! get_channel_ref { ($node: expr, $counterparty_node: expr, $per_peer_state_lock: ident, $peer_state_lock: ident, $channel_id: expr) => { { @@ -980,7 +980,7 @@ macro_rules! get_channel_ref { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] macro_rules! get_feerate { ($node: expr, $counterparty_node: expr, $channel_id: expr) => { { @@ -992,7 +992,7 @@ macro_rules! get_feerate { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] macro_rules! get_channel_type_features { ($node: expr, $counterparty_node: expr, $channel_id: expr) => { { @@ -1155,7 +1155,7 @@ pub fn _reload_node<'a, 'b, 'c>(node: &'a Node<'a, 'b, 'c>, default_config: User node_deserialized } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] macro_rules! reload_node { ($node: expr, $new_config: expr, $chanman_encoded: expr, $monitors_encoded: expr, $persister: ident, $new_chain_monitor: ident, $new_channelmanager: ident) => { let chanman_encoded = $chanman_encoded; @@ -1955,7 +1955,7 @@ macro_rules! expect_pending_htlcs_forwardable_and_htlc_handling_failed { }} } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] macro_rules! expect_pending_htlcs_forwardable_from_events { ($node: expr, $events: expr, $ignore: expr) => {{ assert_eq!($events.len(), 1); @@ -2153,7 +2153,7 @@ macro_rules! get_route { }} } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] #[macro_export] macro_rules! get_route_and_payment_hash { ($send_node: expr, $recv_node: expr, $recv_value: expr) => {{ @@ -2288,7 +2288,7 @@ macro_rules! expect_payment_sent { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] #[macro_export] macro_rules! expect_payment_path_successful { ($node: expr) => { @@ -2372,7 +2372,7 @@ macro_rules! expect_payment_forwarded { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] #[macro_export] macro_rules! expect_channel_shutdown_state { ($node: expr, $chan_id: expr, $state: path) => { @@ -2461,7 +2461,7 @@ impl<'a> PaymentFailedConditions<'a> { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] macro_rules! expect_payment_failed_with_update { ($node: expr, $expected_payment_hash: expr, $payment_failed_permanently: expr, $scid: expr, $chan_closed: expr) => { $crate::ln::functional_test_utils::expect_payment_failed_conditions( @@ -2471,7 +2471,7 @@ macro_rules! expect_payment_failed_with_update { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] macro_rules! expect_payment_failed { ($node: expr, $expected_payment_hash: expr, $payment_failed_permanently: expr $(, $expected_error_code: expr, $expected_error_data: expr)*) => { #[allow(unused_mut)] @@ -2490,13 +2490,13 @@ pub fn expect_payment_failed_conditions_event<'a, 'b, 'c, 'd, 'e>( if conditions.expected_mpp_parts_remain { assert_eq!(payment_failed_events.len(), 1); } else { assert_eq!(payment_failed_events.len(), 2); } let expected_payment_id = match &payment_failed_events[0] { Event::PaymentPathFailed { payment_hash, payment_failed_permanently, payment_id, failure, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_code, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_data, .. } => { assert_eq!(*payment_hash, expected_payment_hash, "unexpected payment_hash"); assert_eq!(*payment_failed_permanently, expected_payment_failed_permanently, "unexpected payment_failed_permanently value"); - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] { assert!(error_code.is_some(), "expected error_code.is_some() = true"); assert!(error_data.is_some(), "expected error_data.is_some() = true"); @@ -3542,7 +3542,7 @@ pub fn get_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec {{ let peer_state_lock = $node.node.per_peer_state.read().unwrap(); diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 31346c6b78b..b36a3bf7b52 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -56,6 +56,7 @@ use alloc::collections::BTreeSet; use core::iter::repeat; use bitcoin::hashes::Hash; use crate::sync::{Arc, Mutex, RwLock}; +use ext_test_macro::xtest; use crate::ln::functional_test_utils::*; use crate::ln::chan_utils::CommitmentTransaction; @@ -94,8 +95,8 @@ fn test_channel_resumption_fail_post_funding() { assert_eq!(nodes[0].node.get_and_clear_pending_msg_events(), Vec::new()); } -#[test] -fn test_insane_channel_opens() { +#[xtest(feature = "_test_utils")] +pub fn test_insane_channel_opens() { // Stand up a network of 2 nodes use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS; let mut cfg = UserConfig::default(); @@ -155,8 +156,8 @@ fn test_insane_channel_opens() { insane_open_helper("max_accepted_htlcs was 484. It must not be larger than 483", |mut msg| { msg.common_fields.max_accepted_htlcs = 484; msg }); } -#[test] -fn test_funding_exceeds_no_wumbo_limit() { +#[xtest(feature = "_test_utils")] +pub fn test_funding_exceeds_no_wumbo_limit() { // Test that if a peer does not support wumbo channels, we'll refuse to open a wumbo channel to // them. use crate::ln::channel::MAX_FUNDING_SATOSHIS_NO_WUMBO; @@ -241,14 +242,14 @@ fn do_test_counterparty_no_reserve(send_from_initiator: bool) { } } -#[test] -fn test_counterparty_no_reserve() { +#[xtest(feature = "_test_utils")] +pub fn test_counterparty_no_reserve() { do_test_counterparty_no_reserve(true); do_test_counterparty_no_reserve(false); } -#[test] -fn test_async_inbound_update_fee() { +#[xtest(feature = "_test_utils")] +pub fn test_async_inbound_update_fee() { 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]); @@ -362,8 +363,8 @@ fn test_async_inbound_update_fee() { check_added_monitors!(nodes[1], 1); } -#[test] -fn test_update_fee_unordered_raa() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fee_unordered_raa() { // Just the intro to the previous test followed by an out-of-order RAA (which caused a // crash in an earlier version of the update_fee patch) let chanmon_cfgs = create_chanmon_cfgs(2); @@ -421,8 +422,8 @@ fn test_update_fee_unordered_raa() { // We can't continue, sadly, because our (1) now has a bogus signature } -#[test] -fn test_multi_flight_update_fee() { +#[xtest(feature = "_test_utils")] +pub fn test_multi_flight_update_fee() { 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]); @@ -606,8 +607,8 @@ fn do_test_sanity_on_in_flight_opens(steps: u8) { expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id()); } -#[test] -fn test_sanity_on_in_flight_opens() { +#[xtest(feature = "_test_utils")] +pub fn test_sanity_on_in_flight_opens() { do_test_sanity_on_in_flight_opens(0); do_test_sanity_on_in_flight_opens(0 | 0b1000_0000); do_test_sanity_on_in_flight_opens(1); @@ -628,8 +629,8 @@ fn test_sanity_on_in_flight_opens() { do_test_sanity_on_in_flight_opens(8 | 0b1000_0000); } -#[test] -fn test_update_fee_vanilla() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fee_vanilla() { 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]); @@ -671,8 +672,8 @@ fn test_update_fee_vanilla() { check_added_monitors!(nodes[1], 1); } -#[test] -fn test_update_fee_that_funder_cannot_afford() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fee_that_funder_cannot_afford() { 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]); @@ -806,8 +807,8 @@ fn test_update_fee_that_funder_cannot_afford() { [nodes[0].node.get_our_node_id()], channel_value); } -#[test] -fn test_update_fee_with_fundee_update_add_htlc() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fee_with_fundee_update_add_htlc() { 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]); @@ -906,8 +907,8 @@ fn test_update_fee_with_fundee_update_add_htlc() { check_closed_event!(nodes[1], 1, ClosureReason::LocallyInitiatedCooperativeClosure, [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_update_fee() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fee() { 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]); @@ -1020,8 +1021,8 @@ fn test_update_fee() { check_closed_event!(nodes[1], 1, ClosureReason::LocallyInitiatedCooperativeClosure, [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn fake_network_test() { +#[xtest(feature = "_test_utils")] +pub fn fake_network_test() { // Simple test which builds a network of ChannelManagers, connects them to each other, and // tests that payments get routed and transactions broadcast in semi-reasonable ways. let chanmon_cfgs = create_chanmon_cfgs(4); @@ -1148,8 +1149,8 @@ fn fake_network_test() { check_closed_event!(nodes[3], 1, ClosureReason::CounterpartyInitiatedCooperativeClosure, [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn holding_cell_htlc_counting() { +#[xtest(feature = "_test_utils")] +pub fn holding_cell_htlc_counting() { // Tests that HTLCs in the holding cell count towards the pending HTLC limits on outbound HTLCs // to ensure we don't end up with HTLCs sitting around in our holding cell for several // commitment dance rounds. @@ -1266,8 +1267,8 @@ fn holding_cell_htlc_counting() { send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1000000); } -#[test] -fn duplicate_htlc_test() { +#[xtest(feature = "_test_utils")] +pub fn duplicate_htlc_test() { // Test that we accept duplicate payment_hash HTLCs across the network and that // claiming/failing them are all separate and don't affect each other let chanmon_cfgs = create_chanmon_cfgs(6); @@ -1295,8 +1296,8 @@ fn duplicate_htlc_test() { claim_payment(&nodes[1], &vec!(&nodes[3])[..], payment_preimage); } -#[test] -fn test_duplicate_htlc_different_direction_onchain() { +#[xtest(feature = "_test_utils")] +pub fn test_duplicate_htlc_different_direction_onchain() { // Test that ChannelMonitor doesn't generate 2 preimage txn // when we have 2 HTLCs with same preimage that go across a node // in opposite directions, even with the same payment secret. @@ -1386,8 +1387,8 @@ fn test_duplicate_htlc_different_direction_onchain() { } } -#[test] -fn test_basic_channel_reserve() { +#[xtest(feature = "_test_utils")] +pub fn test_basic_channel_reserve() { 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]); @@ -1417,8 +1418,8 @@ fn test_basic_channel_reserve() { send_payment(&nodes[0], &vec![&nodes[1]], max_can_send); } -#[test] -fn test_fee_spike_violation_fails_htlc() { +#[xtest(feature = "_test_utils")] +pub fn test_fee_spike_violation_fails_htlc() { 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]); @@ -1568,8 +1569,8 @@ fn test_fee_spike_violation_fails_htlc() { check_added_monitors!(nodes[1], 2); } -#[test] -fn test_chan_reserve_violation_outbound_htlc_inbound_chan() { +#[xtest(feature = "_test_utils")] +pub fn test_chan_reserve_violation_outbound_htlc_inbound_chan() { let mut chanmon_cfgs = create_chanmon_cfgs(2); // Set the fee rate for the channel very high, to the point where the fundee // sending any above-dust amount would result in a channel reserve violation. @@ -1603,8 +1604,8 @@ fn test_chan_reserve_violation_outbound_htlc_inbound_chan() { assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); } -#[test] -fn test_chan_reserve_violation_inbound_htlc_outbound_channel() { +#[xtest(feature = "_test_utils")] +pub fn test_chan_reserve_violation_inbound_htlc_outbound_channel() { let mut chanmon_cfgs = create_chanmon_cfgs(2); let feerate_per_kw = *chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap(); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -1660,8 +1661,8 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() { [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_chan_reserve_dust_inbound_htlcs_outbound_chan() { +#[xtest(feature = "_test_utils")] +pub fn test_chan_reserve_dust_inbound_htlcs_outbound_chan() { // Test that if we receive many dust HTLCs over an outbound channel, they don't count when // calculating our commitment transaction fee (this was previously broken). let mut chanmon_cfgs = create_chanmon_cfgs(2); @@ -1702,8 +1703,8 @@ fn test_chan_reserve_dust_inbound_htlcs_outbound_chan() { ), true, APIError::ChannelUnavailable { .. }, {}); } -#[test] -fn test_chan_init_feerate_unaffordability() { +#[xtest(feature = "_test_utils")] +pub fn test_chan_init_feerate_unaffordability() { // Test that we will reject channel opens which do not leave enough to pay for any HTLCs due to // channel reserve and feerate requirements. let mut chanmon_cfgs = create_chanmon_cfgs(2); @@ -1739,8 +1740,8 @@ fn test_chan_init_feerate_unaffordability() { } } -#[test] -fn test_chan_reserve_dust_inbound_htlcs_inbound_chan() { +#[xtest(feature = "_test_utils")] +pub fn test_chan_reserve_dust_inbound_htlcs_inbound_chan() { // Test that if we receive many dust HTLCs over an inbound channel, they don't count when // calculating our counterparty's commitment transaction fee (this was previously broken). let chanmon_cfgs = create_chanmon_cfgs(2); @@ -1769,8 +1770,8 @@ fn test_chan_reserve_dust_inbound_htlcs_inbound_chan() { route_payment(&nodes[0], &[&nodes[1]], payment_amt); } -#[test] -fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { +#[xtest(feature = "_test_utils")] +pub fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); @@ -1840,8 +1841,8 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_inbound_outbound_capacity_is_not_zero() { +#[xtest(feature = "_test_utils")] +pub fn test_inbound_outbound_capacity_is_not_zero() { 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]); @@ -1865,8 +1866,8 @@ fn commit_tx_fee_msat(feerate: u32, num_htlcs: u64, channel_type_features: &Chan (commitment_tx_base_weight(channel_type_features) + num_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate as u64 / 1000 * 1000 } -#[test] -fn test_channel_reserve_holding_cell_htlcs() { +#[xtest(feature = "_test_utils")] +pub fn test_channel_reserve_holding_cell_htlcs() { let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); // When this test was written, the default base fee floated based on the HTLC count. @@ -2121,8 +2122,8 @@ fn test_channel_reserve_holding_cell_htlcs() { assert_eq!(stat2.value_to_self_msat, stat22.value_to_self_msat + recv_value_1 + recv_value_21 + recv_value_22 + recv_value_3); } -#[test] -fn channel_reserve_in_flight_removes() { +#[xtest(feature = "_test_utils")] +pub fn channel_reserve_in_flight_removes() { // In cases where one side claims an HTLC, it thinks it has additional available funds that it // can send to its counterparty, but due to update ordering, the other side may not yet have // considered those HTLCs fully removed. @@ -2276,8 +2277,8 @@ fn channel_reserve_in_flight_removes() { claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_3); } -#[test] -fn channel_monitor_network_test() { +#[xtest(feature = "_test_utils")] +pub fn channel_monitor_network_test() { // Simple test which builds a network of ChannelManagers, connects them to each other, and // tests that ChannelMonitor is able to recover from various states. let chanmon_cfgs = create_chanmon_cfgs(5); @@ -2473,8 +2474,8 @@ fn channel_monitor_network_test() { check_closed_event!(nodes[3], 1, ClosureReason::HTLCsTimedOut, [node_id_4], 100000); } -#[test] -fn test_justice_tx_htlc_timeout() { +#[xtest(feature = "_test_utils")] +pub fn test_justice_tx_htlc_timeout() { // Test justice txn built on revoked HTLC-Timeout tx, against both sides let mut alice_config = test_default_channel_config(); alice_config.channel_handshake_config.announce_for_forwarding = true; @@ -2536,8 +2537,8 @@ fn test_justice_tx_htlc_timeout() { assert_eq!(nodes[1].node.list_channels().len(), 0); } -#[test] -fn test_justice_tx_htlc_success() { +#[xtest(feature = "_test_utils")] +pub fn test_justice_tx_htlc_success() { // Test justice txn built on revoked HTLC-Success tx, against both sides let mut alice_config = test_default_channel_config(); alice_config.channel_handshake_config.announce_for_forwarding = true; @@ -2593,8 +2594,8 @@ fn test_justice_tx_htlc_success() { assert_eq!(nodes[1].node.list_channels().len(), 0); } -#[test] -fn revoked_output_claim() { +#[xtest(feature = "_test_utils")] +pub fn revoked_output_claim() { // Simple test to ensure a node will claim a revoked output when a stale remote commitment // transaction is broadcast by its counterparty let chanmon_cfgs = create_chanmon_cfgs(2); @@ -2626,8 +2627,8 @@ fn revoked_output_claim() { check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed, [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_forming_justice_tx_from_monitor_updates() { +#[xtest(feature = "_test_utils")] +pub fn test_forming_justice_tx_from_monitor_updates() { do_test_forming_justice_tx_from_monitor_updates(true); do_test_forming_justice_tx_from_monitor_updates(false); } @@ -2692,8 +2693,8 @@ fn do_test_forming_justice_tx_from_monitor_updates(broadcast_initial_commitment: } -#[test] -fn claim_htlc_outputs_shared_tx() { +#[xtest(feature = "_test_utils")] +pub fn claim_htlc_outputs_shared_tx() { // Node revoked old state, htlcs haven't time out yet, claim them in shared justice tx let mut chanmon_cfgs = create_chanmon_cfgs(2); chanmon_cfgs[0].keys_manager.disable_revocation_policy_check = true; @@ -2759,8 +2760,8 @@ fn claim_htlc_outputs_shared_tx() { assert_eq!(nodes[1].node.list_channels().len(), 0); } -#[test] -fn claim_htlc_outputs_single_tx() { +#[xtest(feature = "_test_utils")] +pub fn claim_htlc_outputs_single_tx() { // Node revoked old state, htlcs have timed out, claim each of them in separated justice tx let mut chanmon_cfgs = create_chanmon_cfgs(2); chanmon_cfgs[0].keys_manager.disable_revocation_policy_check = true; @@ -2843,8 +2844,8 @@ fn claim_htlc_outputs_single_tx() { assert_eq!(nodes[1].node.list_channels().len(), 0); } -#[test] -fn test_htlc_on_chain_success() { +#[xtest(feature = "_test_utils")] +pub fn test_htlc_on_chain_success() { // Test that in case of a unilateral close onchain, we detect the state of output and pass // the preimage backward accordingly. So here we test that ChannelManager is // broadcasting the right event to other nodes in payment path. @@ -3188,15 +3189,15 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) { assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); } -#[test] -fn test_htlc_on_chain_timeout() { +#[xtest(feature = "_test_utils")] +pub fn test_htlc_on_chain_timeout() { do_test_htlc_on_chain_timeout(ConnectStyle::BestBlockFirstSkippingBlocks); do_test_htlc_on_chain_timeout(ConnectStyle::TransactionsFirstSkippingBlocks); do_test_htlc_on_chain_timeout(ConnectStyle::FullBlockViaListen); } -#[test] -fn test_simple_commitment_revoked_fail_backward() { +#[xtest(feature = "_test_utils")] +pub fn test_simple_commitment_revoked_fail_backward() { // Test that in case of a revoked commitment tx, we detect the resolution of output by justice tx // and fail backward accordingly. @@ -3487,24 +3488,24 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use assert!(failed_htlcs.contains(&third_payment_hash.0)); } -#[test] -fn test_commitment_revoked_fail_backward_exhaustive_a() { +#[xtest(feature = "_test_utils")] +pub fn test_commitment_revoked_fail_backward_exhaustive_a() { do_test_commitment_revoked_fail_backward_exhaustive(false, true, false); do_test_commitment_revoked_fail_backward_exhaustive(true, true, false); do_test_commitment_revoked_fail_backward_exhaustive(false, false, false); do_test_commitment_revoked_fail_backward_exhaustive(true, false, false); } -#[test] -fn test_commitment_revoked_fail_backward_exhaustive_b() { +#[xtest(feature = "_test_utils")] +pub fn test_commitment_revoked_fail_backward_exhaustive_b() { do_test_commitment_revoked_fail_backward_exhaustive(false, true, true); do_test_commitment_revoked_fail_backward_exhaustive(true, true, true); do_test_commitment_revoked_fail_backward_exhaustive(false, false, true); do_test_commitment_revoked_fail_backward_exhaustive(true, false, true); } -#[test] -fn fail_backward_pending_htlc_upon_channel_failure() { +#[xtest(feature = "_test_utils")] +pub fn fail_backward_pending_htlc_upon_channel_failure() { 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]); @@ -3588,8 +3589,8 @@ fn fail_backward_pending_htlc_upon_channel_failure() { check_added_monitors!(nodes[0], 1); } -#[test] -fn test_htlc_ignore_latest_remote_commitment() { +#[xtest(feature = "_test_utils")] +pub fn test_htlc_ignore_latest_remote_commitment() { // Test that HTLC transactions spending the latest remote commitment transaction are simply // ignored if we cannot claim them. This originally tickled an invalid unwrap(). let chanmon_cfgs = create_chanmon_cfgs(2); @@ -3627,8 +3628,8 @@ fn test_htlc_ignore_latest_remote_commitment() { connect_block(&nodes[1], &block); } -#[test] -fn test_force_close_fail_back() { +#[xtest(feature = "_test_utils")] +pub fn test_force_close_fail_back() { // Check which HTLCs are failed-backwards on channel force-closure let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); @@ -3706,8 +3707,8 @@ fn test_force_close_fail_back() { check_spends!(htlc_tx, commitment_tx); } -#[test] -fn test_dup_events_on_peer_disconnect() { +#[xtest(feature = "_test_utils")] +pub fn test_dup_events_on_peer_disconnect() { // Test that if we receive a duplicative update_fulfill_htlc message after a reconnect we do // not generate a corresponding duplicative PaymentSent event. This did not use to be the case // as we used to generate the event immediately upon receipt of the payment preimage in the @@ -3737,8 +3738,8 @@ fn test_dup_events_on_peer_disconnect() { expect_payment_path_successful!(nodes[0]); } -#[test] -fn test_peer_disconnected_before_funding_broadcasted() { +#[xtest(feature = "_test_utils")] +pub fn test_peer_disconnected_before_funding_broadcasted() { // Test that channels are closed with `ClosureReason::DisconnectedPeer` if the peer disconnects // before the funding transaction has been broadcasted, and doesn't reconnect back within time. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -3787,8 +3788,8 @@ fn test_peer_disconnected_before_funding_broadcasted() { , [nodes[0].node.get_our_node_id()], 1000000); } -#[test] -fn test_simple_peer_disconnect() { +#[xtest(feature = "_test_utils")] +pub fn test_simple_peer_disconnect() { // Test that we can reconnect when there are no lost messages let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); @@ -4120,24 +4121,24 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8, simulate_broken claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2); } -#[test] -fn test_drop_messages_peer_disconnect_a() { +#[xtest(feature = "_test_utils")] +pub fn test_drop_messages_peer_disconnect_a() { do_test_drop_messages_peer_disconnect(0, true); do_test_drop_messages_peer_disconnect(0, false); do_test_drop_messages_peer_disconnect(1, false); do_test_drop_messages_peer_disconnect(2, false); } -#[test] -fn test_drop_messages_peer_disconnect_b() { +#[xtest(feature = "_test_utils")] +pub fn test_drop_messages_peer_disconnect_b() { do_test_drop_messages_peer_disconnect(3, false); do_test_drop_messages_peer_disconnect(4, false); do_test_drop_messages_peer_disconnect(5, false); do_test_drop_messages_peer_disconnect(6, false); } -#[test] -fn test_channel_ready_without_best_block_updated() { +#[xtest(feature = "_test_utils")] +pub fn test_channel_ready_without_best_block_updated() { // Previously, if we were offline when a funding transaction was locked in, and then we came // back online, calling best_block_updated once followed by transactions_confirmed, we'd not // generate a channel_ready until a later best_block_updated. This tests that we generate the @@ -4162,8 +4163,8 @@ fn test_channel_ready_without_best_block_updated() { nodes[1].node.handle_channel_ready(nodes[0].node.get_our_node_id(), &as_channel_ready); } -#[test] -fn test_channel_monitor_skipping_block_when_channel_manager_is_leading() { +#[xtest(feature = "_test_utils")] +pub fn test_channel_monitor_skipping_block_when_channel_manager_is_leading() { 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]); @@ -4194,8 +4195,8 @@ fn test_channel_monitor_skipping_block_when_channel_manager_is_leading() { nodes[1].node.handle_channel_ready(nodes[0].node.get_our_node_id(), &as_channel_ready); } -#[test] -fn test_channel_monitor_skipping_block_when_channel_manager_is_lagging() { +#[xtest(feature = "_test_utils")] +pub fn test_channel_monitor_skipping_block_when_channel_manager_is_lagging() { 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]); @@ -4229,8 +4230,8 @@ fn test_channel_monitor_skipping_block_when_channel_manager_is_lagging() { nodes[1].node.handle_channel_ready(nodes[0].node.get_our_node_id(), &as_channel_ready); } -#[test] -fn test_drop_messages_peer_disconnect_dual_htlc() { +#[xtest(feature = "_test_utils")] +pub fn test_drop_messages_peer_disconnect_dual_htlc() { // Test that we can handle reconnecting when both sides of a channel have pending // commitment_updates when we disconnect. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -4443,8 +4444,8 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) { expect_payment_failed!(nodes[0], our_payment_hash, true, 0x4000 | 15, &expected_failure_data[..]); } -#[test] -fn test_htlc_timeout() { +#[xtest(feature = "_test_utils")] +pub fn test_htlc_timeout() { do_test_htlc_timeout(true); do_test_htlc_timeout(false); } @@ -4507,8 +4508,8 @@ fn do_test_holding_cell_htlc_add_timeouts(forwarded_htlc: bool) { } } -#[test] -fn test_holding_cell_htlc_add_timeouts() { +#[xtest(feature = "_test_utils")] +pub fn test_holding_cell_htlc_add_timeouts() { do_test_holding_cell_htlc_add_timeouts(false); do_test_holding_cell_htlc_add_timeouts(true); } @@ -4541,8 +4542,8 @@ macro_rules! check_spendable_outputs { } } -#[test] -fn test_claim_sizeable_push_msat() { +#[xtest(feature = "_test_utils")] +pub fn test_claim_sizeable_push_msat() { // Incidentally test SpendableOutput event generation due to detection of to_local output on commitment tx let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -4570,8 +4571,8 @@ fn test_claim_sizeable_push_msat() { assert_eq!(spend_txn[0].input[0].sequence.0, BREAKDOWN_TIMEOUT as u32); } -#[test] -fn test_claim_on_remote_sizeable_push_msat() { +#[xtest(feature = "_test_utils")] +pub fn test_claim_on_remote_sizeable_push_msat() { // Same test as previous, just test on remote commitment tx, as per_commitment_point registration changes following you're funder/fundee and // to_remote output is encumbered by a P2WPKH let chanmon_cfgs = create_chanmon_cfgs(2); @@ -4602,8 +4603,8 @@ fn test_claim_on_remote_sizeable_push_msat() { check_spends!(spend_txn[0], node_txn[0]); } -#[test] -fn test_claim_on_remote_revoked_sizeable_push_msat() { +#[xtest(feature = "_test_utils")] +pub fn test_claim_on_remote_revoked_sizeable_push_msat() { // Same test as previous, just test on remote revoked commitment tx, as per_commitment_point registration changes following you're funder/fundee and // to_remote output is encumbered by a P2WPKH @@ -4635,8 +4636,8 @@ fn test_claim_on_remote_revoked_sizeable_push_msat() { check_spends!(spend_txn[2], revoked_local_txn[0], node_txn[0]); // Both outputs } -#[test] -fn test_static_spendable_outputs_preimage_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_static_spendable_outputs_preimage_tx() { 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]); @@ -4682,8 +4683,8 @@ fn test_static_spendable_outputs_preimage_tx() { check_spends!(spend_txn[0], node_txn[0]); } -#[test] -fn test_static_spendable_outputs_timeout_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_static_spendable_outputs_timeout_tx() { 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]); @@ -4729,8 +4730,8 @@ fn test_static_spendable_outputs_timeout_tx() { check_spends!(spend_txn[2], node_txn[0], commitment_tx[0]); // All outputs } -#[test] -fn test_static_spendable_outputs_justice_tx_revoked_commitment_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_static_spendable_outputs_justice_tx_revoked_commitment_tx() { 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]); @@ -4764,8 +4765,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_commitment_tx() { check_spends!(spend_txn[0], node_txn[0]); } -#[test] -fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() { let mut chanmon_cfgs = create_chanmon_cfgs(2); chanmon_cfgs[0].keys_manager.disable_revocation_policy_check = true; let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -4829,8 +4830,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() { check_spends!(spend_txn[0], node_txn[1]); } -#[test] -fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() { let mut chanmon_cfgs = create_chanmon_cfgs(2); chanmon_cfgs[1].keys_manager.disable_revocation_policy_check = true; let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -4906,8 +4907,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() { check_spends!(spend_txn[2], revoked_local_txn[0], node_txn[1]); // Both outputs } -#[test] -fn test_onchain_to_onchain_claim() { +#[xtest(feature = "_test_utils")] +pub fn test_onchain_to_onchain_claim() { // Test that in case of channel closure, we detect the state of output and claim HTLC // on downstream peer's remote commitment tx. // First, have C claim an HTLC against its own latest commitment transaction. @@ -5024,8 +5025,8 @@ fn test_onchain_to_onchain_claim() { check_added_monitors!(nodes[1], 1); } -#[test] -fn test_duplicate_payment_hash_one_failure_one_success() { +#[xtest(feature = "_test_utils")] +pub fn test_duplicate_payment_hash_one_failure_one_success() { // Topology : A --> B --> C --> D // We route 2 payments with same hash between B and C, one will be timeout, the other successfully claim // Note that because C will refuse to generate two payment secrets for the same payment hash, @@ -5170,8 +5171,8 @@ fn test_duplicate_payment_hash_one_failure_one_success() { expect_payment_sent(&nodes[0], our_payment_preimage, None, true, true); } -#[test] -fn test_dynamic_spendable_outputs_local_htlc_success_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_dynamic_spendable_outputs_local_htlc_success_tx() { 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]); @@ -5512,25 +5513,25 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno assert_eq!(bs_updates, if deliver_last_raa { 2 } else if !announce_latest { 3 } else { 4 }); } -#[test] -fn test_fail_backwards_latest_remote_announce_a() { +#[xtest(feature = "_test_utils")] +pub fn test_fail_backwards_latest_remote_announce_a() { do_test_fail_backwards_unrevoked_remote_announce(false, true); } -#[test] -fn test_fail_backwards_latest_remote_announce_b() { +#[xtest(feature = "_test_utils")] +pub fn test_fail_backwards_latest_remote_announce_b() { do_test_fail_backwards_unrevoked_remote_announce(true, true); } -#[test] -fn test_fail_backwards_previous_remote_announce() { +#[xtest(feature = "_test_utils")] +pub fn test_fail_backwards_previous_remote_announce() { do_test_fail_backwards_unrevoked_remote_announce(false, false); // Note that true, true doesn't make sense as it implies we announce a revoked state, which is // tested for in test_commitment_revoked_fail_backward_exhaustive() } -#[test] -fn test_dynamic_spendable_outputs_local_htlc_timeout_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_dynamic_spendable_outputs_local_htlc_timeout_tx() { 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]); @@ -5577,8 +5578,8 @@ fn test_dynamic_spendable_outputs_local_htlc_timeout_tx() { spend_txn[2].input[1].sequence.0 == BREAKDOWN_TIMEOUT as u32); } -#[test] -fn test_key_derivation_params() { +#[xtest(feature = "_test_utils")] +pub fn test_key_derivation_params() { // This test is a copy of test_dynamic_spendable_outputs_local_htlc_timeout_tx, with a key // manager rotation to test that `channel_keys_id` returned in // [`SpendableOutputDescriptor::DelayedPaymentOutput`] let us re-derive the channel key set to @@ -5665,8 +5666,8 @@ fn test_key_derivation_params() { spend_txn[2].input[1].sequence.0 == BREAKDOWN_TIMEOUT as u32); } -#[test] -fn test_static_output_closing_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_static_output_closing_tx() { 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]); @@ -5822,8 +5823,8 @@ fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no // Note that we don't bother testing both outbound and inbound HTLC failures for each case, and we // assume they are handled the same across all six cases, as both outbound and inbound failures are // tested for at least one of the cases in other tests. -#[test] -fn htlc_claim_single_commitment_only_a() { +#[xtest(feature = "_test_utils")] +pub fn htlc_claim_single_commitment_only_a() { do_htlc_claim_local_commitment_only(true); do_htlc_claim_local_commitment_only(false); @@ -5831,17 +5832,17 @@ fn htlc_claim_single_commitment_only_a() { do_htlc_claim_current_remote_commitment_only(false); } -#[test] -fn htlc_claim_single_commitment_only_b() { +#[xtest(feature = "_test_utils")] +pub fn htlc_claim_single_commitment_only_b() { do_htlc_claim_previous_remote_commitment_only(true, false); do_htlc_claim_previous_remote_commitment_only(false, false); do_htlc_claim_previous_remote_commitment_only(true, true); do_htlc_claim_previous_remote_commitment_only(false, true); } -#[test] +#[xtest(feature = "_test_utils")] #[should_panic] -fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on its own as we are catching a panic +pub fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on its own as we are catching a panic 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]); @@ -5864,8 +5865,8 @@ fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on i assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None, None).is_err()); } -#[test] -fn bolt2_open_channel_sending_node_checks_part2() { +#[xtest(feature = "_test_utils")] +pub fn bolt2_open_channel_sending_node_checks_part2() { 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]); @@ -5909,8 +5910,8 @@ fn bolt2_open_channel_sending_node_checks_part2() { assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.common_fields.delayed_payment_basepoint.serialize()).is_ok()); } -#[test] -fn bolt2_open_channel_sane_dust_limit() { +#[xtest(feature = "_test_utils")] +pub fn bolt2_open_channel_sane_dust_limit() { 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]); @@ -5938,8 +5939,8 @@ fn bolt2_open_channel_sane_dust_limit() { // originated from our node, its failure is surfaced to the user. We trigger this failure to // free the HTLC by increasing our fee while the HTLC is in the holding cell such that the HTLC // is no longer affordable once it's freed. -#[test] -fn test_fail_holding_cell_htlc_upon_free() { +#[xtest(feature = "_test_utils")] +pub fn test_fail_holding_cell_htlc_upon_free() { 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]); @@ -6018,8 +6019,8 @@ fn test_fail_holding_cell_htlc_upon_free() { // Test that if multiple HTLCs are released from the holding cell and one is // valid but the other is no longer valid upon release, the valid HTLC can be // successfully completed while the other one fails as expected. -#[test] -fn test_free_and_fail_holding_cell_htlcs() { +#[xtest(feature = "_test_utils")] +pub fn test_free_and_fail_holding_cell_htlcs() { 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]); @@ -6143,8 +6144,8 @@ fn test_free_and_fail_holding_cell_htlcs() { // HTLC is failed backwards. We trigger this failure to forward the freed HTLC by increasing // our fee while the HTLC is in the holding cell such that the HTLC is no longer affordable // once it's freed. -#[test] -fn test_fail_holding_cell_htlc_upon_free_multihop() { +#[xtest(feature = "_test_utils")] +pub fn test_fail_holding_cell_htlc_upon_free_multihop() { let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); // Avoid having to include routing fees in calculations @@ -6272,8 +6273,8 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() { check_added_monitors!(nodes[0], 1); } -#[test] -fn test_payment_route_reaching_same_channel_twice() { +#[xtest(feature = "_test_utils")] +pub fn test_payment_route_reaching_same_channel_twice() { //A route should not go through the same channel twice //It is enforced when constructing a route. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6300,8 +6301,8 @@ fn test_payment_route_reaching_same_channel_twice() { // BOLT 2 Requirement: MUST NOT offer amount_msat it cannot pay for in the remote commitment transaction at the current feerate_per_kw (see "Updating Fees") while maintaining its channel reserve. //TODO: I don't believe this is explicitly enforced when sending an HTLC but as the Fee aspect of the BOLT specs is in flux leaving this as a TODO. -#[test] -fn test_update_add_htlc_bolt2_sender_value_below_minimum_msat() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_sender_value_below_minimum_msat() { //BOLT2 Requirement: MUST NOT offer amount_msat below the receiving node's htlc_minimum_msat (same validation check catches both of these) let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -6318,8 +6319,8 @@ fn test_update_add_htlc_bolt2_sender_value_below_minimum_msat() { assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); } -#[test] -fn test_update_add_htlc_bolt2_sender_zero_value_msat() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_sender_zero_value_msat() { //BOLT2 Requirement: MUST offer amount_msat greater than 0. let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -6338,8 +6339,8 @@ fn test_update_add_htlc_bolt2_sender_zero_value_msat() { nodes[0].logger.assert_log_contains("lightning::ln::channelmanager", "Cannot send 0-msat HTLC", 1); } -#[test] -fn test_update_add_htlc_bolt2_receiver_zero_value_msat() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_receiver_zero_value_msat() { //BOLT2 Requirement: MUST offer amount_msat greater than 0. let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -6362,8 +6363,8 @@ fn test_update_add_htlc_bolt2_receiver_zero_value_msat() { [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_update_add_htlc_bolt2_sender_cltv_expiry_too_high() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_sender_cltv_expiry_too_high() { //BOLT 2 Requirement: MUST set cltv_expiry less than 500000000. //It is enforced when constructing a route. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6382,8 +6383,8 @@ fn test_update_add_htlc_bolt2_sender_cltv_expiry_too_high() { assert_eq!(err, &"Channel CLTV overflowed?")); } -#[test] -fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_num_and_htlc_id_increment() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_num_and_htlc_id_increment() { //BOLT 2 Requirement: if result would be offering more than the remote's max_accepted_htlcs HTLCs, in the remote commitment transaction: MUST NOT add an HTLC. //BOLT 2 Requirement: for the first HTLC it offers MUST set id to 0. //BOLT 2 Requirement: MUST increase the value of id by 1 for each successive offer. @@ -6427,8 +6428,8 @@ fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_num_and_htlc_id_increment() assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); } -#[test] -fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_value_in_flight() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_value_in_flight() { //BOLT 2 Requirement: if the sum of total offered HTLCs would exceed the remote's max_htlc_value_in_flight_msat: MUST NOT add an HTLC. let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -6453,8 +6454,8 @@ fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_value_in_flight() { } // BOLT 2 Requirements for the Receiver when handling an update_add_htlc message. -#[test] -fn test_update_add_htlc_bolt2_receiver_check_amount_received_more_than_min() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_receiver_check_amount_received_more_than_min() { //BOLT2 Requirement: receiving an amount_msat equal to 0, OR less than its own htlc_minimum_msat -> SHOULD fail the channel. let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -6483,8 +6484,8 @@ fn test_update_add_htlc_bolt2_receiver_check_amount_received_more_than_min() { check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_update_add_htlc_bolt2_receiver_sender_can_afford_amount_sent() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_receiver_sender_can_afford_amount_sent() { //BOLT2 Requirement: receiving an amount_msat that the sending node cannot afford at the current feerate_per_kw (while maintaining its channel reserve): SHOULD fail the channel let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -6519,8 +6520,8 @@ fn test_update_add_htlc_bolt2_receiver_sender_can_afford_amount_sent() { check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() { //BOLT 2 Requirement: if a sending node adds more than its max_accepted_htlcs HTLCs to its local commitment transaction: SHOULD fail the channel //BOLT 2 Requirement: MUST allow multiple HTLCs with the same payment_hash. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6566,8 +6567,8 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() { check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_update_add_htlc_bolt2_receiver_check_max_in_flight_msat() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_receiver_check_max_in_flight_msat() { //OR adds more than its max_htlc_value_in_flight_msat worth of offered HTLCs to its local commitment transaction: SHOULD fail the channel let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -6590,8 +6591,8 @@ fn test_update_add_htlc_bolt2_receiver_check_max_in_flight_msat() { check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[0].node.get_our_node_id()], 1000000); } -#[test] -fn test_update_add_htlc_bolt2_receiver_check_cltv_expiry() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_receiver_check_cltv_expiry() { //BOLT2 Requirement: if sending node sets cltv_expiry to greater or equal to 500000000: SHOULD fail the channel. let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -6614,8 +6615,8 @@ fn test_update_add_htlc_bolt2_receiver_check_cltv_expiry() { check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_update_add_htlc_bolt2_receiver_check_repeated_id_ignore() { +#[xtest(feature = "_test_utils")] +pub fn test_update_add_htlc_bolt2_receiver_check_repeated_id_ignore() { //BOLT 2 requirement: if the sender did not previously acknowledge the commitment of that HTLC: MUST ignore a repeated id value after a reconnection. // We test this by first testing that that repeated HTLCs pass commitment signature checks // after disconnect and that non-sequential htlc_ids result in a channel failure. @@ -6666,8 +6667,8 @@ fn test_update_add_htlc_bolt2_receiver_check_repeated_id_ignore() { check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_update_fulfill_htlc_bolt2_update_fulfill_htlc_before_commitment() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fulfill_htlc_bolt2_update_fulfill_htlc_before_commitment() { //BOLT 2 Requirement: until the corresponding HTLC is irrevocably committed in both sides' commitment transactions: MUST NOT send an update_fulfill_htlc, update_fail_htlc, or update_fail_malformed_htlc. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6698,8 +6699,8 @@ fn test_update_fulfill_htlc_bolt2_update_fulfill_htlc_before_commitment() { check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_update_fulfill_htlc_bolt2_update_fail_htlc_before_commitment() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fulfill_htlc_bolt2_update_fail_htlc_before_commitment() { //BOLT 2 Requirement: until the corresponding HTLC is irrevocably committed in both sides' commitment transactions: MUST NOT send an update_fulfill_htlc, update_fail_htlc, or update_fail_malformed_htlc. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6730,8 +6731,8 @@ fn test_update_fulfill_htlc_bolt2_update_fail_htlc_before_commitment() { check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_update_fulfill_htlc_bolt2_update_fail_malformed_htlc_before_commitment() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fulfill_htlc_bolt2_update_fail_malformed_htlc_before_commitment() { //BOLT 2 Requirement: until the corresponding HTLC is irrevocably committed in both sides' commitment transactions: MUST NOT send an update_fulfill_htlc, update_fail_htlc, or update_fail_malformed_htlc. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6762,8 +6763,8 @@ fn test_update_fulfill_htlc_bolt2_update_fail_malformed_htlc_before_commitment() check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_update_fulfill_htlc_bolt2_incorrect_htlc_id() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fulfill_htlc_bolt2_incorrect_htlc_id() { //BOLT 2 Requirement: A receiving node: if the id does not correspond to an HTLC in its current commitment transaction MUST fail the channel. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6805,8 +6806,8 @@ fn test_update_fulfill_htlc_bolt2_incorrect_htlc_id() { check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_update_fulfill_htlc_bolt2_wrong_preimage() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fulfill_htlc_bolt2_wrong_preimage() { //BOLT 2 Requirement: A receiving node: if the payment_preimage value in update_fulfill_htlc doesn't SHA256 hash to the corresponding HTLC payment_hash MUST fail the channel. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6848,8 +6849,8 @@ fn test_update_fulfill_htlc_bolt2_wrong_preimage() { check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_update_fulfill_htlc_bolt2_missing_badonion_bit_for_malformed_htlc_message() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fulfill_htlc_bolt2_missing_badonion_bit_for_malformed_htlc_message() { //BOLT 2 Requirement: A receiving node: if the BADONION bit in failure_code is not set for update_fail_malformed_htlc MUST fail the channel. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -6895,8 +6896,8 @@ fn test_update_fulfill_htlc_bolt2_missing_badonion_bit_for_malformed_htlc_messag check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: err_msg.data }, [nodes[1].node.get_our_node_id()], 1000000); } -#[test] -fn test_update_fulfill_htlc_bolt2_after_malformed_htlc_message_must_forward_update_fail_htlc() { +#[xtest(feature = "_test_utils")] +pub fn test_update_fulfill_htlc_bolt2_after_malformed_htlc_message_must_forward_update_fail_htlc() { //BOLT 2 Requirement: a receiving node which has an outgoing HTLC canceled by update_fail_malformed_htlc: // * MUST return an error in the update_fail_htlc sent to the link which originally sent the HTLC, using the failure_code given and setting the data to sha256_of_onion. @@ -6973,8 +6974,8 @@ fn test_update_fulfill_htlc_bolt2_after_malformed_htlc_message_must_forward_upda check_added_monitors!(nodes[1], 1); } -#[test] -fn test_channel_failed_after_message_with_badonion_node_perm_bits_set() { +#[xtest(feature = "_test_utils")] +pub fn test_channel_failed_after_message_with_badonion_node_perm_bits_set() { let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); @@ -7143,8 +7144,8 @@ fn do_test_failure_delay_dust_htlc_local_commitment(announce_latest: bool) { } } -#[test] -fn test_failure_delay_dust_htlc_local_commitment() { +#[xtest(feature = "_test_utils")] +pub fn test_failure_delay_dust_htlc_local_commitment() { do_test_failure_delay_dust_htlc_local_commitment(true); do_test_failure_delay_dust_htlc_local_commitment(false); } @@ -7226,15 +7227,15 @@ fn do_test_sweep_outbound_htlc_failure_update(revoked: bool, local: bool) { } } -#[test] -fn test_sweep_outbound_htlc_failure_update() { +#[xtest(feature = "_test_utils")] +pub fn test_sweep_outbound_htlc_failure_update() { do_test_sweep_outbound_htlc_failure_update(false, true); do_test_sweep_outbound_htlc_failure_update(false, false); do_test_sweep_outbound_htlc_failure_update(true, false); } -#[test] -fn test_user_configurable_csv_delay() { +#[xtest(feature = "_test_utils")] +pub fn test_user_configurable_csv_delay() { // We test our channel constructors yield errors when we pass them absurd csv delay let mut low_our_to_self_config = UserConfig::default(); @@ -7312,8 +7313,8 @@ fn test_user_configurable_csv_delay() { } else { assert!(false); } } -#[test] -fn test_check_htlc_underpaying() { +#[xtest(feature = "_test_utils")] +pub fn test_check_htlc_underpaying() { // Send payment through A -> B but A is maliciously // sending a probe payment (i.e less than expected value0 // to B, B should refuse payment. @@ -7378,8 +7379,8 @@ fn test_check_htlc_underpaying() { expect_payment_failed!(nodes[0], our_payment_hash, true, 0x4000|15, &expected_failure_data[..]); } -#[test] -fn test_announce_disable_channels() { +#[xtest(feature = "_test_utils")] +pub fn test_announce_disable_channels() { // Create 2 channels between A and B. Disconnect B. Call timer_tick_occurred and check for generated // ChannelUpdate. Reconnect B, reestablish and check there is non-generated ChannelUpdate. @@ -7470,8 +7471,8 @@ fn test_announce_disable_channels() { assert!(chans_disabled.is_empty()); } -#[test] -fn test_bump_penalty_txn_on_revoked_commitment() { +#[xtest(feature = "_test_utils")] +pub fn test_bump_penalty_txn_on_revoked_commitment() { // In case of penalty txn with too low feerates for getting into mempools, RBF-bump them to be sure // we're able to claim outputs on revoked commitment transaction before timelocks expiration @@ -7575,8 +7576,8 @@ fn test_bump_penalty_txn_on_revoked_commitment() { nodes[1].node.get_and_clear_pending_msg_events(); } -#[test] -fn test_bump_penalty_txn_on_revoked_htlcs() { +#[xtest(feature = "_test_utils")] +pub fn test_bump_penalty_txn_on_revoked_htlcs() { // In case of penalty txn with too low feerates for getting into mempools, RBF-bump them to sure // we're able to claim outputs on revoked HTLC transactions before timelocks expiration @@ -7730,8 +7731,8 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { check_added_monitors!(nodes[0], 1); } -#[test] -fn test_bump_penalty_txn_on_remote_commitment() { +#[xtest(feature = "_test_utils")] +pub fn test_bump_penalty_txn_on_remote_commitment() { // In case of claim txn with too low feerates for getting into mempools, RBF-bump them to be sure // we're able to claim outputs on remote commitment transaction before timelocks expiration @@ -7833,8 +7834,8 @@ fn test_bump_penalty_txn_on_remote_commitment() { nodes[1].node.get_and_clear_pending_msg_events(); } -#[test] -fn test_counterparty_raa_skip_no_crash() { +#[xtest(feature = "_test_utils")] +pub 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 @@ -7887,8 +7888,8 @@ fn test_counterparty_raa_skip_no_crash() { , [nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_bump_txn_sanitize_tracking_maps() { +#[xtest(feature = "_test_utils")] +pub fn test_bump_txn_sanitize_tracking_maps() { // Sanitizing pendning_claim_request and claimable_outpoints used to be buggy, // verify we clean then right after expiration of ANTI_REORG_DELAY. @@ -7937,8 +7938,8 @@ fn test_bump_txn_sanitize_tracking_maps() { } } -#[test] -fn test_channel_conf_timeout() { +#[xtest(feature = "_test_utils")] +pub fn test_channel_conf_timeout() { // Tests that, for inbound channels, we give up on them if the funding transaction does not // confirm within 2016 blocks, as recommended by BOLT 2. let chanmon_cfgs = create_chanmon_cfgs(2); @@ -7973,8 +7974,8 @@ fn test_channel_conf_timeout() { } } -#[test] -fn test_override_channel_config() { +#[xtest(feature = "_test_utils")] +pub fn test_override_channel_config() { 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]); @@ -7992,8 +7993,8 @@ fn test_override_channel_config() { assert_eq!(res.common_fields.to_self_delay, 200); } -#[test] -fn test_override_0msat_htlc_minimum() { +#[xtest(feature = "_test_utils")] +pub fn test_override_0msat_htlc_minimum() { let mut zero_config = UserConfig::default(); zero_config.channel_handshake_config.our_htlc_minimum_msat = 0; let chanmon_cfgs = create_chanmon_cfgs(2); @@ -8010,8 +8011,8 @@ fn test_override_0msat_htlc_minimum() { assert_eq!(res.common_fields.htlc_minimum_msat, 1); } -#[test] -fn test_channel_update_has_correct_htlc_maximum_msat() { +#[xtest(feature = "_test_utils")] +pub fn test_channel_update_has_correct_htlc_maximum_msat() { // Tests that the `ChannelUpdate` message has the correct values for `htlc_maximum_msat` set. // Bolt 7 specifies that if present `htlc_maximum_msat`: // 1. MUST be set to less than or equal to the channel capacity. In LDK, this is capped to @@ -8062,8 +8063,8 @@ fn test_channel_update_has_correct_htlc_maximum_msat() { assert_eq!(node_3_chan_update.contents.htlc_maximum_msat, channel_value_90_percent_msat); } -#[test] -fn test_manually_accept_inbound_channel_request() { +#[xtest(feature = "_test_utils")] +pub fn test_manually_accept_inbound_channel_request() { let mut manually_accept_conf = UserConfig::default(); manually_accept_conf.manually_accept_inbound_channels = true; let chanmon_cfgs = create_chanmon_cfgs(2); @@ -8112,8 +8113,8 @@ fn test_manually_accept_inbound_channel_request() { } } -#[test] -fn test_manually_reject_inbound_channel_request() { +#[xtest(feature = "_test_utils")] +pub fn test_manually_reject_inbound_channel_request() { let mut manually_accept_conf = UserConfig::default(); manually_accept_conf.manually_accept_inbound_channels = true; let chanmon_cfgs = create_chanmon_cfgs(2); @@ -8152,8 +8153,8 @@ fn test_manually_reject_inbound_channel_request() { assert!(nodes[1].node.get_and_clear_pending_events().is_empty()); } -#[test] -fn test_can_not_accept_inbound_channel_twice() { +#[xtest(feature = "_test_utils")] +pub fn test_can_not_accept_inbound_channel_twice() { let mut manually_accept_conf = UserConfig::default(); manually_accept_conf.manually_accept_inbound_channels = true; let chanmon_cfgs = create_chanmon_cfgs(2); @@ -8198,8 +8199,8 @@ fn test_can_not_accept_inbound_channel_twice() { } } -#[test] -fn test_can_not_accept_unknown_inbound_channel() { +#[xtest(feature = "_test_utils")] +pub fn test_can_not_accept_unknown_inbound_channel() { let chanmon_cfg = create_chanmon_cfgs(2); let node_cfg = create_node_cfgs(2, &chanmon_cfg); let node_chanmgr = create_node_chanmgrs(2, &node_cfg, &[None, None]); @@ -8216,8 +8217,8 @@ fn test_can_not_accept_unknown_inbound_channel() { } } -#[test] -fn test_onion_value_mpp_set_calculation() { +#[xtest(feature = "_test_utils")] +pub fn test_onion_value_mpp_set_calculation() { // Test that we use the onion value `amt_to_forward` when // calculating whether we've reached the `total_msat` of an MPP // by having a routing node forward more than `amt_to_forward` @@ -8389,14 +8390,14 @@ fn do_test_overshoot_mpp(msat_amounts: &[u64], total_msat: u64) { ); } -#[test] -fn test_overshoot_mpp() { +#[xtest(feature = "_test_utils")] +pub fn test_overshoot_mpp() { do_test_overshoot_mpp(&[100_000, 101_000], 200_000); do_test_overshoot_mpp(&[100_000, 10_000, 100_000], 200_000); } -#[test] -fn test_simple_mpp() { +#[xtest(feature = "_test_utils")] +pub fn test_simple_mpp() { // Simple test of sending a multi-path payment. let chanmon_cfgs = create_chanmon_cfgs(4); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); @@ -8423,8 +8424,8 @@ fn test_simple_mpp() { ); } -#[test] -fn test_preimage_storage() { +#[xtest(feature = "_test_utils")] +pub fn test_preimage_storage() { // Simple test of payment preimage storage allowing no client-side storage to claim payments let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -8462,8 +8463,8 @@ fn test_preimage_storage() { } } -#[test] -fn test_bad_secret_hash() { +#[xtest(feature = "_test_utils")] +pub fn test_bad_secret_hash() { // Simple test of unregistered payment hash/invalid payment secret handling let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -8528,8 +8529,8 @@ fn test_bad_secret_hash() { expect_payment_failed!(nodes[0], random_payment_hash, true, expected_error_code, expected_error_data); } -#[test] -fn test_update_err_monitor_lockdown() { +#[xtest(feature = "_test_utils")] +pub fn test_update_err_monitor_lockdown() { // Our monitor will lock update of local commitment transaction if a broadcastion condition // has been fulfilled (either force-close from Channel or block height requiring a HTLC- // timeout). Trying to update monitor after lockdown should return a ChannelMonitorUpdateStatus @@ -8602,8 +8603,8 @@ fn test_update_err_monitor_lockdown() { assert_eq!(events.len(), 1); } -#[test] -fn test_concurrent_monitor_claim() { +#[xtest(feature = "_test_utils")] +pub fn test_concurrent_monitor_claim() { // Watchtower A receives block, broadcasts state N, then channel receives new state N+1, // sending it to both watchtowers, Bob accepts N+1, then receives block and broadcasts // the latest state N+1, Alice rejects state N+1, but Bob has already broadcast it, @@ -8729,8 +8730,8 @@ fn test_concurrent_monitor_claim() { } } -#[test] -fn test_pre_lockin_no_chan_closed_update() { +#[xtest(feature = "_test_utils")] +pub fn test_pre_lockin_no_chan_closed_update() { // Test that if a peer closes a channel in response to a funding_created message we don't // generate a channel update (as the channel cannot appear on chain without a funding_signed // message). @@ -8768,8 +8769,8 @@ fn test_pre_lockin_no_chan_closed_update() { [nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_htlc_no_detection() { +#[xtest(feature = "_test_utils")] +pub 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 @@ -9000,16 +9001,16 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain } } -#[test] -fn test_onchain_htlc_settlement_after_close() { +#[xtest(feature = "_test_utils")] +pub fn test_onchain_htlc_settlement_after_close() { do_test_onchain_htlc_settlement_after_close(true, true); do_test_onchain_htlc_settlement_after_close(false, true); // Technically redundant, but may as well do_test_onchain_htlc_settlement_after_close(true, false); do_test_onchain_htlc_settlement_after_close(false, false); } -#[test] -fn test_duplicate_temporary_channel_id_from_different_peers() { +#[xtest(feature = "_test_utils")] +pub fn test_duplicate_temporary_channel_id_from_different_peers() { // Tests that we can accept two different `OpenChannel` requests with the same // `temporary_channel_id`, as long as they are from different peers. let chanmon_cfgs = create_chanmon_cfgs(3); @@ -9058,8 +9059,8 @@ fn test_duplicate_temporary_channel_id_from_different_peers() { } } -#[test] -fn test_peer_funding_sidechannel() { +#[xtest(feature = "_test_utils")] +pub fn test_peer_funding_sidechannel() { // Test that if a peer somehow learns which txid we'll use for our channel funding before we // receive `funding_transaction_generated` the peer cannot cause us to crash. We'd previously // assumed that LDK would receive `funding_transaction_generated` prior to our peer learning @@ -9113,8 +9114,8 @@ fn test_peer_funding_sidechannel() { get_err_msg(&nodes[0], &nodes[1].node.get_our_node_id()); } -#[test] -fn test_duplicate_conflicting_funding_from_second_peer() { +#[xtest(feature = "_test_utils")] +pub fn test_duplicate_conflicting_funding_from_second_peer() { // Test that if a user tries to fund a channel with a funding outpoint they'd previously used // we don't try to remove the previous ChannelMonitor. This is largely a test to ensure we // don't regress in the fuzzer, as such funding getting passed our outpoint-matches checks @@ -9153,8 +9154,8 @@ fn test_duplicate_conflicting_funding_from_second_peer() { check_closed_events(&nodes[0], &[ExpectedCloseEvent::from_id_reason(funding_signed_msg.channel_id, true, err_reason)]); } -#[test] -fn test_duplicate_funding_err_in_funding() { +#[xtest(feature = "_test_utils")] +pub fn test_duplicate_funding_err_in_funding() { // Test that if we have a live channel with one peer, then another peer comes along and tries // to create a second channel with the same txid we'll fail and not overwrite the // outpoint_to_peer map in `ChannelManager`. @@ -9201,8 +9202,8 @@ fn test_duplicate_funding_err_in_funding() { ); } -#[test] -fn test_duplicate_chan_id() { +#[xtest(feature = "_test_utils")] +pub fn test_duplicate_chan_id() { // Test that if a given peer tries to open a channel with the same channel_id as one that is // already open we reject it and keep the old channel. // @@ -9355,8 +9356,8 @@ fn test_duplicate_chan_id() { send_payment(&nodes[0], &[&nodes[1]], 8000000); } -#[test] -fn test_error_chans_closed() { +#[xtest(feature = "_test_utils")] +pub fn test_error_chans_closed() { // Test that we properly handle error messages, closing appropriate channels. // // Prior to #787 we'd allow a peer to make us force-close a channel we had with a different @@ -9421,8 +9422,8 @@ fn test_error_chans_closed() { assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_3.2); } -#[test] -fn test_invalid_funding_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_invalid_funding_tx() { // Test that we properly handle invalid funding transactions sent to us from a peer. // // Previously, all other major lightning implementations had failed to properly sanitize @@ -9509,8 +9510,8 @@ fn test_invalid_funding_tx() { mine_transaction(&nodes[1], &spend_tx); } -#[test] -fn test_coinbase_funding_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_coinbase_funding_tx() { // Miners are able to fund channels directly from coinbase transactions, however // by consensus rules, outputs of a coinbase transaction are encumbered by a 100 // block maturity timelock. To ensure that a (non-0conf) channel like this is enforceable @@ -9651,8 +9652,8 @@ fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_t } } -#[test] -fn test_tx_confirmed_skipping_blocks_immediate_broadcast() { +#[xtest(feature = "_test_utils")] +pub fn test_tx_confirmed_skipping_blocks_immediate_broadcast() { do_test_tx_confirmed_skipping_blocks_immediate_broadcast(false); do_test_tx_confirmed_skipping_blocks_immediate_broadcast(true); } @@ -9744,8 +9745,8 @@ fn do_test_dup_htlc_second_rejected(test_for_second_fail_panic: bool) { } } -#[test] -fn test_dup_htlc_second_fail_panic() { +#[xtest(feature = "_test_utils")] +pub fn test_dup_htlc_second_fail_panic() { // Previously, if we received two HTLCs back-to-back, where the second overran the expected // value for the payment, we'd fail back both HTLCs after generating a `PaymentClaimable` event. // Then, if the user failed the second payment, they'd hit a "tried to fail an already failed @@ -9753,15 +9754,15 @@ fn test_dup_htlc_second_fail_panic() { do_test_dup_htlc_second_rejected(true); } -#[test] -fn test_dup_htlc_second_rejected() { +#[xtest(feature = "_test_utils")] +pub fn test_dup_htlc_second_rejected() { // Test that if we receive a second HTLC for an MPP payment that overruns the payment amount we // simply reject the second HTLC but are still able to claim the first HTLC. do_test_dup_htlc_second_rejected(false); } -#[test] -fn test_inconsistent_mpp_params() { +#[xtest(feature = "_test_utils")] +pub fn test_inconsistent_mpp_params() { // Test that if we recieve two HTLCs with different payment parameters we fail back the first // such HTLC and allow the second to stay. let chanmon_cfgs = create_chanmon_cfgs(4); @@ -9871,8 +9872,8 @@ fn test_inconsistent_mpp_params() { expect_payment_sent(&nodes[0], our_payment_preimage, Some(None), true, true); } -#[test] -fn test_double_partial_claim() { +#[xtest(feature = "_test_utils")] +pub fn test_double_partial_claim() { // Test what happens if a node receives a payment, generates a PaymentClaimable event, the HTLCs // time out, the sender resends only some of the MPP parts, then the user processes the // PaymentClaimable event, ensuring they don't inadvertently claim only part of the full payment @@ -10174,8 +10175,8 @@ fn do_test_max_dust_htlc_exposure_by_threshold_type(multiplier_dust_limit: bool, } } -#[test] -fn test_max_dust_htlc_exposure() { +#[xtest(feature = "_test_utils")] +pub fn test_max_dust_htlc_exposure() { do_test_max_dust_htlc_exposure_by_threshold_type(false, false); do_test_max_dust_htlc_exposure_by_threshold_type(false, true); do_test_max_dust_htlc_exposure_by_threshold_type(true, false); @@ -10270,8 +10271,8 @@ fn test_nondust_htlc_fees_are_dust() { } -#[test] -fn test_non_final_funding_tx() { +#[xtest(feature = "_test_utils")] +pub fn test_non_final_funding_tx() { 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]); @@ -10310,8 +10311,8 @@ fn test_non_final_funding_tx() { assert_eq!(get_err_msg(&nodes[0], &nodes[1].node.get_our_node_id()).data, "Failed to fund channel"); } -#[test] -fn test_non_final_funding_tx_within_headroom() { +#[xtest(feature = "_test_utils")] +pub fn test_non_final_funding_tx_within_headroom() { 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]); @@ -10344,8 +10345,8 @@ fn test_non_final_funding_tx_within_headroom() { get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id()); } -#[test] -fn accept_busted_but_better_fee() { +#[xtest(feature = "_test_utils")] +pub fn accept_busted_but_better_fee() { // If a peer sends us a fee update that is too low, but higher than our previous channel // feerate, we should accept it. In the future we may want to consider closing the channel // later, but for now we only accept the update. @@ -10473,16 +10474,16 @@ fn do_payment_with_custom_min_final_cltv_expiry(valid_delta: bool, use_user_hash } } -#[test] -fn test_payment_with_custom_min_cltv_expiry_delta() { +#[xtest(feature = "_test_utils")] +pub fn test_payment_with_custom_min_cltv_expiry_delta() { do_payment_with_custom_min_final_cltv_expiry(false, false); do_payment_with_custom_min_final_cltv_expiry(false, true); do_payment_with_custom_min_final_cltv_expiry(true, false); do_payment_with_custom_min_final_cltv_expiry(true, true); } -#[test] -fn test_disconnects_peer_awaiting_response_ticks() { +#[xtest(feature = "_test_utils")] +pub fn test_disconnects_peer_awaiting_response_ticks() { // Tests that nodes which are awaiting on a response critical for channel responsiveness // disconnect their counterparty after `DISCONNECT_PEER_AWAITING_RESPONSE_TICKS`. let mut chanmon_cfgs = create_chanmon_cfgs(2); @@ -10610,8 +10611,8 @@ fn test_disconnects_peer_awaiting_response_ticks() { } } -#[test] -fn test_remove_expired_outbound_unfunded_channels() { +#[xtest(feature = "_test_utils")] +pub fn test_remove_expired_outbound_unfunded_channels() { 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]); @@ -10661,8 +10662,8 @@ fn test_remove_expired_outbound_unfunded_channels() { check_closed_event(&nodes[0], 1, ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }, false, &[nodes[1].node.get_our_node_id()], 100000); } -#[test] -fn test_remove_expired_inbound_unfunded_channels() { +#[xtest(feature = "_test_utils")] +pub fn test_remove_expired_inbound_unfunded_channels() { 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]); @@ -10712,8 +10713,8 @@ fn test_remove_expired_inbound_unfunded_channels() { check_closed_event(&nodes[1], 1, ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }, false, &[nodes[0].node.get_our_node_id()], 100000); } -#[test] -fn test_channel_close_when_not_timely_accepted() { +#[xtest(feature = "_test_utils")] +pub fn test_channel_close_when_not_timely_accepted() { // Create network of two nodes let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -10755,8 +10756,8 @@ fn test_channel_close_when_not_timely_accepted() { } } -#[test] -fn test_rebroadcast_open_channel_when_reconnect_mid_handshake() { +#[xtest(feature = "_test_utils")] +pub fn test_rebroadcast_open_channel_when_reconnect_mid_handshake() { // Create network of two nodes let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); @@ -10877,14 +10878,14 @@ fn do_test_multi_post_event_actions(do_reload: bool) { check_added_monitors(&nodes[0], 3); } -#[test] -fn test_multi_post_event_actions() { +#[xtest(feature = "_test_utils")] +pub fn test_multi_post_event_actions() { do_test_multi_post_event_actions(true); do_test_multi_post_event_actions(false); } -#[test] -fn test_batch_channel_open() { +#[xtest(feature = "_test_utils")] +pub fn test_batch_channel_open() { let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); @@ -10951,8 +10952,8 @@ fn test_batch_channel_open() { ))); } -#[test] -fn test_close_in_funding_batch() { +#[xtest(feature = "_test_utils")] +pub fn test_close_in_funding_batch() { // This test ensures that if one of the channels // in the batch closes, the complete batch will close. let chanmon_cfgs = create_chanmon_cfgs(3); @@ -11032,8 +11033,8 @@ fn test_close_in_funding_batch() { assert!(nodes[0].node.list_channels().is_empty()); } -#[test] -fn test_batch_funding_close_after_funding_signed() { +#[xtest(feature = "_test_utils")] +pub fn test_batch_funding_close_after_funding_signed() { let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); @@ -11172,14 +11173,14 @@ fn do_test_funding_and_commitment_tx_confirm_same_block(confirm_remote_commitmen assert!(nodes[1].node.list_channels().is_empty()); } -#[test] -fn test_funding_and_commitment_tx_confirm_same_block() { +#[xtest(feature = "_test_utils")] +pub fn test_funding_and_commitment_tx_confirm_same_block() { do_test_funding_and_commitment_tx_confirm_same_block(false); do_test_funding_and_commitment_tx_confirm_same_block(true); } -#[test] -fn test_accept_inbound_channel_errors_queued() { +#[xtest(feature = "_test_utils")] +pub fn test_accept_inbound_channel_errors_queued() { // For manually accepted inbound channels, tests that a close error is correctly handled // and the channel fails for the initiator. let mut config0 = test_default_channel_config(); @@ -11211,8 +11212,8 @@ fn test_accept_inbound_channel_errors_queued() { open_channel_msg.common_fields.temporary_channel_id); } -#[test] -fn test_manual_funding_abandon() { +#[xtest(feature = "_test_utils")] +pub fn test_manual_funding_abandon() { let mut cfg = UserConfig::default(); cfg.channel_handshake_config.minimum_depth = 1; let chanmon_cfgs = create_chanmon_cfgs(2); diff --git a/lightning/src/ln/invoice_utils.rs b/lightning/src/ln/invoice_utils.rs index 4c7e347dab1..710618b1e75 100644 --- a/lightning/src/ln/invoice_utils.rs +++ b/lightning/src/ln/invoice_utils.rs @@ -844,6 +844,7 @@ mod test { use crate::util::test_utils; use crate::util::config::UserConfig; use std::collections::HashSet; + use crate::util::dyn_signer::{DynKeysInterface, DynPhantomKeysInterface}; #[test] fn test_prefer_current_channel() { @@ -1297,6 +1298,13 @@ mod test { do_test_multi_node_receive(false); } + fn make_dyn_keys_interface(seed: &[u8; 32]) -> DynKeysInterface { + let cross_node_seed = [44u8; 32]; + let inner = PhantomKeysManager::new(&seed, 43, 44, &cross_node_seed); + let dyn_inner = DynPhantomKeysInterface::new(inner); + DynKeysInterface::new(Box::new(dyn_inner)) + } + fn do_test_multi_node_receive(user_generated_pmt_hash: bool) { use crate::events::{Event, EventsProvider}; use core::cell::RefCell; @@ -1304,9 +1312,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(3); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); let nodes = create_network(3, &node_cfgs, &node_chanmgrs); @@ -1408,9 +1415,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(3); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); let nodes = create_network(3, &node_cfgs, &node_chanmgrs); @@ -1499,9 +1505,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(3); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); let nodes = create_network(3, &node_cfgs, &node_chanmgrs); @@ -1527,9 +1532,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(4); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[3].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[3].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); @@ -1557,9 +1561,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(4); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[3].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[3].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); @@ -1614,9 +1617,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(3); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); let nodes = create_network(3, &node_cfgs, &node_chanmgrs); @@ -1646,9 +1648,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(4); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); @@ -1679,9 +1680,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(3); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); let nodes = create_network(3, &node_cfgs, &node_chanmgrs); @@ -1709,9 +1709,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(4); let seed_1 = [42u8; 32]; let seed_2 = [43u8; 32]; - let cross_node_seed = [44u8; 32]; - chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); @@ -1784,11 +1783,10 @@ mod test { let seed_2 = [43 as u8; 32]; let seed_3 = [44 as u8; 32]; let seed_4 = [45 as u8; 32]; - let cross_node_seed = [44 as u8; 32]; - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[3].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); - chanmon_cfgs[4].keys_manager.backing = PhantomKeysManager::new(&seed_3, 43, 44, &cross_node_seed); - chanmon_cfgs[5].keys_manager.backing = PhantomKeysManager::new(&seed_4, 43, 44, &cross_node_seed); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[3].keys_manager.backing = make_dyn_keys_interface(&seed_2); + chanmon_cfgs[4].keys_manager.backing = make_dyn_keys_interface(&seed_3); + chanmon_cfgs[4].keys_manager.backing = make_dyn_keys_interface(&seed_4); let node_cfgs = create_node_cfgs(6, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs, &[None, None, None, None, None, None]); let nodes = create_network(6, &node_cfgs, &node_chanmgrs); @@ -1841,9 +1839,8 @@ mod test { let mut chanmon_cfgs = create_chanmon_cfgs(5); let seed_1 = [42 as u8; 32]; let seed_2 = [43 as u8; 32]; - let cross_node_seed = [44 as u8; 32]; - chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed); - chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed); + chanmon_cfgs[1].keys_manager.backing = make_dyn_keys_interface(&seed_1); + chanmon_cfgs[2].keys_manager.backing = make_dyn_keys_interface(&seed_2); let node_cfgs = create_node_cfgs(5, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(5, &node_cfgs, &[None, None, None, None, None]); let nodes = create_network(5, &node_cfgs, &node_chanmgrs); diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index dceb52ab4ae..e846eaa5a78 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -60,9 +60,9 @@ pub use onion_utils::create_payment_onion; #[cfg(test)] #[allow(unused_mut)] mod blinded_payment_tests; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] #[allow(unused_mut)] -mod functional_tests; +pub mod functional_tests; #[cfg(test)] #[allow(unused_mut)] mod max_payment_path_len_tests; diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index 947ec4a1304..1ae243b725f 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -2251,8 +2251,8 @@ fn do_test_restored_packages_retry(check_old_monitor_retries_after_upgrade: bool let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); // Reset our RNG counters to mirror the RNG output from when this test was written. - nodes[0].keys_manager.backing.inner.entropy_source.set_counter(0x1_0000_0004); - nodes[1].keys_manager.backing.inner.entropy_source.set_counter(0x1_0000_0004); + nodes[0].keys_manager.backing.inner.set_counter(0x1_0000_0004); + nodes[1].keys_manager.backing.inner.set_counter(0x1_0000_0004); // Open a channel, lock in an HTLC, and immediately broadcast the commitment transaction. This // ensures that the HTLC timeout package is held until we reach its expiration height. diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index 5ad68407631..ef0c284f3b7 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -608,9 +608,9 @@ pub(crate) struct DecodedOnionFailure { pub(crate) short_channel_id: Option, pub(crate) payment_failed_permanently: bool, pub(crate) failed_within_blinded_path: bool, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(crate) onion_error_code: Option, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(crate) onion_error_data: Option>, } @@ -888,9 +888,9 @@ where short_channel_id, payment_failed_permanently, failed_within_blinded_path, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] onion_error_code: error_code_ret, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] onion_error_data: error_packet_ret, } } else { @@ -901,9 +901,9 @@ where short_channel_id: None, payment_failed_permanently: is_from_final_node, failed_within_blinded_path: false, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] onion_error_code: None, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] onion_error_data: None, } } @@ -1059,9 +1059,9 @@ impl HTLCFailReason { payment_failed_permanently: false, short_channel_id: Some(path.hops[0].short_channel_id), failed_within_blinded_path: false, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] onion_error_code: Some(*failure_code), - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] onion_error_data: Some(data.clone()), } } else { diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 2bc1c9b4edc..fa810cc4285 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -1471,9 +1471,9 @@ impl OutboundPayments { failure: events::PathFailure::InitialSend { err: e }, path, short_channel_id: failed_scid, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_code: None, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_data: None, }, None)); } @@ -1529,7 +1529,7 @@ impl OutboundPayments { } } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(super) fn test_add_new_pending_payment( &self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId, route: &Route, retry_strategy: Option, entropy_source: &ES, best_block_height: u32 @@ -1747,7 +1747,7 @@ impl OutboundPayments { } } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(super) fn test_send_payment_internal( &self, route: &Route, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, keysend_preimage: Option, payment_id: PaymentId, recv_value_msat: Option, @@ -1935,12 +1935,12 @@ impl OutboundPayments { probing_cookie_secret: [u8; 32], secp_ctx: &Secp256k1, pending_events: &Mutex)>>, logger: &L, ) -> bool where L::Target: Logger { - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] let DecodedOnionFailure { network_update, short_channel_id, payment_failed_permanently, onion_error_code, onion_error_data, failed_within_blinded_path } = onion_error.decode_onion_failure(secp_ctx, logger, &source); - #[cfg(not(test))] + #[cfg(not(any(test, feature = "_test_utils")))] let DecodedOnionFailure { network_update, short_channel_id, payment_failed_permanently, failed_within_blinded_path } = onion_error.decode_onion_failure(secp_ctx, logger, &source); @@ -2048,9 +2048,9 @@ impl OutboundPayments { failure: events::PathFailure::OnPath { network_update }, path: path.clone(), short_channel_id, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_code: onion_error_code, - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] error_data: onion_error_data } } diff --git a/lightning/src/ln/wire.rs b/lightning/src/ln/wire.rs index 4cf5e21c173..6936aeb3a2f 100644 --- a/lightning/src/ln/wire.rs +++ b/lightning/src/ln/wire.rs @@ -46,7 +46,7 @@ impl TestEq for T {} /// variant contains a message from [`msgs`] or otherwise the message type if unknown. #[allow(missing_docs)] #[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] +#[cfg_attr(any(test, feature = "_test_utils"), derive(PartialEq))] pub(crate) enum Message where T: core::fmt::Debug + Type + TestEq { Init(msgs::Init), Error(msgs::ErrorMessage), diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 4b7ba02e4dd..d67272c1a21 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -1152,7 +1152,7 @@ where } } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub(crate) fn set_offers_handler(&mut self, offers_handler: OMH) { self.offers_handler = offers_handler; } diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index ecdd45aa3f5..13ca7c73d7a 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -70,7 +70,7 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// commitment transactions which will be broadcasted later, after the channel has moved on to a /// newer state. Thus, needs its own method as [`sign_holder_commitment`] may enforce that we /// only ever get called once. - #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment( &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result; diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 8ad34f2d653..e35d526b434 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -31,7 +31,6 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature}; use bitcoin::secp256k1::schnorr; -#[cfg(taproot)] use bitcoin::secp256k1::All; use bitcoin::secp256k1::{Keypair, PublicKey, Scalar, Secp256k1, SecretKey, Signing}; use bitcoin::{secp256k1, Psbt, Sequence, Txid, WPubkeyHash, Witness}; @@ -730,6 +729,32 @@ impl HTLCDescriptor { /// is not yet complete, and panics may occur in certain situations when returning errors /// for these methods. pub trait ChannelSigner { + /// Returns the commitment seed for the channel. + fn commitment_seed(&self) -> [u8; 32]; + /// Returns the counterparty's pubkeys. + /// + /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. + /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. + fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys>; + /// Funding outpoint + /// + /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. + /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. + fn funding_outpoint(&self) -> Option<&OutPoint>; + /// Returns a [`ChannelTransactionParameters`] for this channel, to be used when verifying or + /// building transactions. + /// + /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. + /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. + fn get_channel_parameters(&self) -> Option<&ChannelTransactionParameters>; + + /// Returns the channel type features of the channel parameters. Should be helpful for + /// determining a channel's category, i. e. legacy/anchors/taproot/etc. + /// + /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. + /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. + fn channel_type_features(&self) -> Option<&ChannelTypeFeatures>; + /// Gets the per-commitment point for a specific commitment number /// /// Note that the commitment number starts at `(1 << 48) - 1` and counts backwards. @@ -924,10 +949,10 @@ pub trait OutputSpender { /// Returns `Err(())` if the output value is greater than the input value minus required fee, /// if a descriptor was duplicated, or if an output descriptor `script_pubkey` /// does not match the one we can spend. - fn spend_spendable_outputs( + fn spend_spendable_outputs( &self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, - locktime: Option, secp_ctx: &Secp256k1, + locktime: Option, secp_ctx: &Secp256k1, ) -> Result; } @@ -1133,16 +1158,6 @@ impl InMemorySigner { } } - /// Returns the counterparty's pubkeys. - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> { - self.get_channel_parameters().and_then(|params| { - params.counterparty_parameters.as_ref().map(|params| ¶ms.pubkeys) - }) - } - /// Returns the `contest_delay` value specified by our counterparty and applied on holder-broadcastable /// transactions, i.e., the amount of time that we have to wait to recover our funds if we /// broadcast a transaction. @@ -1173,14 +1188,6 @@ impl InMemorySigner { self.get_channel_parameters().map(|params| params.is_outbound_from_holder) } - /// Funding outpoint - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn funding_outpoint(&self) -> Option<&OutPoint> { - self.get_channel_parameters().map(|params| params.funding_outpoint.as_ref()).flatten() - } - /// Returns a [`ChannelTransactionParameters`] for this channel, to be used when verifying or /// building transactions. /// @@ -1190,15 +1197,6 @@ impl InMemorySigner { self.channel_parameters.as_ref() } - /// Returns the channel type features of the channel parameters. Should be helpful for - /// determining a channel's category, i. e. legacy/anchors/taproot/etc. - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn channel_type_features(&self) -> Option<&ChannelTypeFeatures> { - self.get_channel_parameters().map(|params| ¶ms.channel_type_features) - } - /// Sign the single input of `spend_tx` at index `input_idx`, which spends the output described /// by `descriptor`, returning the witness stack for the input. /// @@ -1351,6 +1349,33 @@ impl EntropySource for InMemorySigner { } impl ChannelSigner for InMemorySigner { + fn commitment_seed(&self) -> [u8; 32] { + self.commitment_seed + } + + fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> { + self.get_channel_parameters().and_then(|params| { + params.counterparty_parameters.as_ref().map(|params| ¶ms.pubkeys) + }) + } + + fn funding_outpoint(&self) -> Option<&OutPoint> { + self.get_channel_parameters().map(|params| params.funding_outpoint.as_ref()).flatten() + } + + fn get_channel_parameters(&self) -> Option<&ChannelTransactionParameters> { + self.channel_parameters.as_ref() + } + + /// Returns the channel type features of the channel parameters. Should be helpful for + /// determining a channel's category, i. e. legacy/anchors/taproot/etc. + /// + /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. + /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. + fn channel_type_features(&self) -> Option<&ChannelTypeFeatures> { + self.get_channel_parameters().map(|params| ¶ms.channel_type_features) + } + fn get_per_commitment_point( &self, idx: u64, secp_ctx: &Secp256k1, ) -> Result { @@ -1482,7 +1507,7 @@ impl EcdsaChannelSigner for InMemorySigner { )) } - #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment( &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result { @@ -2219,10 +2244,10 @@ impl OutputSpender for KeysManager { /// /// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used /// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`]. - fn spend_spendable_outputs( + fn spend_spendable_outputs( &self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, - locktime: Option, secp_ctx: &Secp256k1, + locktime: Option, secp_ctx: &Secp256k1, ) -> Result { let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt( @@ -2383,10 +2408,10 @@ impl NodeSigner for PhantomKeysManager { impl OutputSpender for PhantomKeysManager { /// See [`OutputSpender::spend_spendable_outputs`] and [`KeysManager::spend_spendable_outputs`] /// for documentation on this method. - fn spend_spendable_outputs( + fn spend_spendable_outputs( &self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, - locktime: Option, secp_ctx: &Secp256k1, + locktime: Option, secp_ctx: &Secp256k1, ) -> Result { self.inner.spend_spendable_outputs( descriptors, diff --git a/lightning/src/util/dyn_signer.rs b/lightning/src/util/dyn_signer.rs new file mode 100644 index 00000000000..3228a8ab21c --- /dev/null +++ b/lightning/src/util/dyn_signer.rs @@ -0,0 +1,510 @@ +//! A dynamically dispatched signer + +use crate::prelude::*; + +use core::any::Any; +use delegate::delegate; + +use crate::chain::transaction::OutPoint; +use crate::io::{Error, Read}; +use crate::ln::chan_utils::{ + ChannelPublicKeys, ChannelTransactionParameters, ClosingTransaction, CommitmentTransaction, + HTLCOutputInCommitment, HolderCommitmentTransaction, +}; +use crate::ln::features::ChannelTypeFeatures; +use crate::ln::msgs::{DecodeError, UnsignedChannelAnnouncement, UnsignedGossipMessage}; +use crate::ln::script::ShutdownScript; +use crate::ln::PaymentPreimage; +use crate::sign::ecdsa::EcdsaChannelSigner; +#[cfg(taproot)] +use crate::sign::taproot::TaprootChannelSigner; +use crate::sign::ChannelSigner; +use crate::sign::InMemorySigner; +use crate::sign::{EntropySource, HTLCDescriptor, OutputSpender, PhantomKeysManager}; +use crate::sign::{KeyMaterial, NodeSigner, Recipient, SignerProvider, SpendableOutputDescriptor}; +use crate::util::ser::{Readable, ReadableArgs}; +use crate::util::ser::{Writeable, Writer}; +#[cfg(any(test, feature = "_test_utils"))] +use crate::util::test_utils::OnlyReadsKeysInterface; +use bitcoin; +use bitcoin::absolute::LockTime; +use bitcoin::secp256k1::All; +use bitcoin::{secp256k1, ScriptBuf, Transaction, TxOut}; +use lightning_invoice::RawBolt11Invoice; +#[cfg(taproot)] +use musig2::types::{PartialSignature, PublicNonce}; +use secp256k1::ecdsa::RecoverableSignature; +use secp256k1::{ecdh::SharedSecret, ecdsa::Signature, PublicKey, Scalar, Secp256k1, SecretKey}; + +#[cfg(not(taproot))] +/// A super-trait for all the traits that a dyn signer backing implements +pub trait DynSignerTrait: EcdsaChannelSigner + Send + Sync {} + +#[cfg(taproot)] +/// A super-trait for all the traits that a dyn signer backing implements +pub trait DynSignerTrait: EcdsaChannelSigner + TaprootChannelSigner + Send + Sync {} + +/// Helper to allow DynSigner to clone itself +pub trait InnerSign: DynSignerTrait { + /// Clone into a Box + fn box_clone(&self) -> Box; + /// Cast to Any for runtime type checking + fn as_any(&self) -> &dyn Any; + /// Serialize the signer. + /// We can't have a write method with a generic (i.e. `Writeable`) because that would make signers + /// dyn object incompatible. + fn vwrite(&self, writer: &mut Vec) -> Result<(), Error>; +} + +/// A ChannelSigner derived struct allowing run-time selection of a signer +pub struct DynSigner { + /// The inner signer + pub inner: Box, +} + +impl DynSigner { + /// Create a new DynSigner + pub fn new(inner: S) -> Self { + DynSigner { inner: Box::new(inner) } + } +} + +#[cfg(taproot)] +#[allow(unused_variables)] +impl TaprootChannelSigner for DynSigner { + fn generate_local_nonce_pair( + &self, commitment_number: u64, secp_ctx: &Secp256k1, + ) -> PublicNonce { + todo!() + } + + fn partially_sign_counterparty_commitment( + &self, counterparty_nonce: PublicNonce, commitment_tx: &CommitmentTransaction, + inbound_htlc_preimages: Vec, + outbound_htlc_preimages: Vec, secp_ctx: &Secp256k1, + ) -> Result<(crate::ln::msgs::PartialSignatureWithNonce, Vec), ()> + { + todo!(); + } + + fn finalize_holder_commitment( + &self, commitment_tx: &HolderCommitmentTransaction, + counterparty_partial_signature: crate::ln::msgs::PartialSignatureWithNonce, + secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_justice_revoked_output( + &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_justice_revoked_htlc( + &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_holder_htlc_transaction( + &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, + secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_counterparty_htlc_transaction( + &self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, + htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn partially_sign_closing_transaction( + &self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_holder_anchor_input( + &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } +} + +impl Clone for DynSigner { + fn clone(&self) -> Self { + DynSigner { inner: self.inner.box_clone() } + } +} + +// This is taken care of by KeysInterface +impl Readable for DynSigner { + fn read(_reader: &mut R) -> Result { + unimplemented!() + } +} + +impl EcdsaChannelSigner for DynSigner { + fn sign_holder_commitment( + &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, + ) -> Result { + self.inner.sign_holder_commitment(commitment_tx, secp_ctx) + } + + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] + fn unsafe_sign_holder_commitment( + &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, + ) -> Result { + self.inner.unsafe_sign_holder_commitment(commitment_tx, secp_ctx) + } + + fn sign_counterparty_commitment( + &self, commitment_tx: &CommitmentTransaction, inbound_htlc_preimages: Vec, + outbound_htlc_preimages: Vec, secp_ctx: &Secp256k1, + ) -> Result<(Signature, Vec), ()> { + self.inner.sign_counterparty_commitment( + commitment_tx, + inbound_htlc_preimages, + outbound_htlc_preimages, + secp_ctx, + ) + } + + fn sign_justice_revoked_output( + &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + secp_ctx: &Secp256k1, + ) -> Result { + EcdsaChannelSigner::sign_justice_revoked_output( + &*self.inner, + justice_tx, + input, + amount, + per_commitment_key, + secp_ctx, + ) + } + + fn sign_justice_revoked_htlc( + &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + ) -> Result { + EcdsaChannelSigner::sign_justice_revoked_htlc( + &*self.inner, + justice_tx, + input, + amount, + per_commitment_key, + htlc, + secp_ctx, + ) + } + + fn sign_counterparty_htlc_transaction( + &self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, + htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + ) -> Result { + EcdsaChannelSigner::sign_counterparty_htlc_transaction( + &*self.inner, + htlc_tx, + input, + amount, + per_commitment_point, + htlc, + secp_ctx, + ) + } + + fn sign_closing_transaction( + &self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1, + ) -> Result { + self.inner.sign_closing_transaction(closing_tx, secp_ctx) + } + + fn sign_channel_announcement_with_funding_key( + &self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1, + ) -> Result { + self.inner.sign_channel_announcement_with_funding_key(msg, secp_ctx) + } + + fn sign_holder_anchor_input( + &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, + ) -> Result { + EcdsaChannelSigner::sign_holder_anchor_input(&*self.inner, anchor_tx, input, secp_ctx) + } + + fn sign_holder_htlc_transaction( + &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, + secp_ctx: &Secp256k1, + ) -> Result { + EcdsaChannelSigner::sign_holder_htlc_transaction( + &*self.inner, + htlc_tx, + input, + htlc_descriptor, + secp_ctx, + ) + } +} + +impl ChannelSigner for DynSigner { + delegate! { + to self.inner { + fn commitment_seed(&self) -> [u8; 32]; + fn channel_type_features(&self) -> Option<&ChannelTypeFeatures>; + fn get_per_commitment_point( + &self, + idx: u64, + secp_ctx: &Secp256k1, + ) -> Result; + fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys>; + fn funding_outpoint(&self) -> Option<&OutPoint>; + fn get_channel_parameters(&self) -> Option<&ChannelTransactionParameters>; + fn release_commitment_secret(&self, idx: u64) -> Result<[u8; 32], ()>; + + fn validate_holder_commitment( + &self, + holder_tx: &HolderCommitmentTransaction, + preimages: Vec, + ) -> Result<(), ()>; + + fn pubkeys(&self) -> &ChannelPublicKeys; + + fn channel_keys_id(&self) -> [u8; 32]; + + fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); + + fn validate_counterparty_revocation(&self, idx: u64, secret: &SecretKey) -> Result<(), ()>; + } + } +} + +impl Writeable for DynSigner { + fn write(&self, writer: &mut W) -> Result<(), Error> { + let inner = self.inner.as_ref(); + let mut buf = Vec::new(); + inner.vwrite(&mut buf)?; + writer.write_all(&buf) + } +} + +impl DynSignerTrait for InMemorySigner {} + +impl InnerSign for InMemorySigner { + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn vwrite(&self, writer: &mut Vec) -> Result<(), Error> { + self.write(writer) + } +} + +/// A convenience wrapper for DynKeysInterfaceTrait +pub struct DynKeysInterface { + /// The inner dyn keys interface + pub inner: Box, +} + +impl DynKeysInterface { + /// Create a new DynKeysInterface + pub fn new(inner: Box) -> Self { + DynKeysInterface { inner } + } +} + +impl NodeSigner for DynKeysInterface { + delegate! { + to self.inner { + fn get_node_id(&self, recipient: Recipient) -> Result; + fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result; + fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result; + + fn sign_invoice(&self, invoice: &RawBolt11Invoice, recipient: Recipient) -> Result; + + fn sign_bolt12_invoice( + &self, invoice: &crate::offers::invoice::UnsignedBolt12Invoice + ) -> Result; + + fn sign_bolt12_invoice_request( + &self, invoice_request: &crate::offers::invoice_request::UnsignedInvoiceRequest + ) -> Result; + + fn get_inbound_payment_key_material(&self) -> KeyMaterial; + } + } +} + +impl SignerProvider for DynKeysInterface { + type EcdsaSigner = DynSigner; + #[cfg(taproot)] + type TaprootSigner = DynSigner; + + delegate! { + to self.inner { + fn get_destination_script(&self, channel_keys_id: [u8; 32]) -> Result; + + fn get_shutdown_scriptpubkey(&self) -> Result; + + fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32]; + + fn derive_channel_signer(&self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32]) -> Self::EcdsaSigner; + + fn read_chan_signer(&self, reader: &[u8]) -> Result; + } + } +} + +impl EntropySource for DynKeysInterface { + delegate! { + to self.inner { + fn get_secure_random_bytes(&self) -> [u8; 32]; + } + } +} + +impl OutputSpender for DynKeysInterface { + delegate! { + to self.inner { + fn spend_spendable_outputs( + &self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, + change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, + locktime: Option, secp_ctx: &Secp256k1, + ) -> Result; + } + } +} + +#[cfg(not(taproot))] +/// A supertrait for all the traits that a keys interface implements +pub trait DynKeysInterfaceTrait: + NodeSigner + OutputSpender + SignerProvider + EntropySource + Send + Sync +{ + #[cfg(test)] + fn set_counter(&self, _count: u64) {} +} + +#[cfg(taproot)] +/// A supertrait for all the traits that a keys interface implements +pub trait DynKeysInterfaceTrait: + NodeSigner + + OutputSpender + + SignerProvider + + EntropySource + + Send + + Sync +{ + #[cfg(test)] + fn set_counter(&self, _count: u64) {} +} + +/// A dyn wrapper for PhantomKeysManager +pub struct DynPhantomKeysInterface { + inner: PhantomKeysManager, +} + +impl DynPhantomKeysInterface { + /// Create a new DynPhantomKeysInterface + pub fn new(inner: PhantomKeysManager) -> Self { + DynPhantomKeysInterface { inner } + } +} + +impl NodeSigner for DynPhantomKeysInterface { + delegate! { + to self.inner { + fn get_node_id(&self, recipient: Recipient) -> Result; + fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result; + fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result; + + fn sign_invoice(&self, invoice: &RawBolt11Invoice, recipient: Recipient) -> Result; + + fn sign_bolt12_invoice( + &self, invoice: &crate::offers::invoice::UnsignedBolt12Invoice + ) -> Result; + + fn sign_bolt12_invoice_request( + &self, invoice_request: &crate::offers::invoice_request::UnsignedInvoiceRequest + ) -> Result; + + fn get_inbound_payment_key_material(&self) -> KeyMaterial; + } + } +} + +impl SignerProvider for DynPhantomKeysInterface { + type EcdsaSigner = DynSigner; + #[cfg(taproot)] + type TaprootSigner = DynSigner; + + delegate! { + to self.inner { + fn get_destination_script(&self, channel_keys_id: [u8; 32]) -> Result; + + fn get_shutdown_scriptpubkey(&self) -> Result; + + fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32]; + } + } + + fn derive_channel_signer( + &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], + ) -> Self::EcdsaSigner { + let inner = self.inner.derive_channel_signer(channel_value_satoshis, channel_keys_id); + DynSigner::new(inner) + } + + fn read_chan_signer(&self, _reader: &[u8]) -> Result { + todo!() + } +} + +impl EntropySource for DynPhantomKeysInterface { + delegate! { + to self.inner { + fn get_secure_random_bytes(&self) -> [u8; 32]; + } + } +} + +impl OutputSpender for DynPhantomKeysInterface { + delegate! { + to self.inner { + fn spend_spendable_outputs( + &self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, + change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, + locktime: Option, secp_ctx: &Secp256k1, + ) -> Result; + } + } +} + +impl DynKeysInterfaceTrait for DynPhantomKeysInterface { + #[cfg(test)] + fn set_counter(&self, count: u64) { + self.inner.inner.entropy_source.set_counter(count); + } +} + +impl ReadableArgs<&DynKeysInterface> for DynSigner { + fn read(_reader: &mut R, _params: &DynKeysInterface) -> Result { + todo!() + } +} + +#[cfg(any(test, feature = "_test_utils"))] +impl ReadableArgs<&OnlyReadsKeysInterface> for DynSigner { + fn read( + _reader: &mut R, _params: &OnlyReadsKeysInterface, + ) -> Result { + todo!() + } +} diff --git a/lightning/src/util/mod.rs b/lightning/src/util/mod.rs index a1d8d53195c..6adc26acc54 100644 --- a/lightning/src/util/mod.rs +++ b/lightning/src/util/mod.rs @@ -15,7 +15,10 @@ pub(crate) mod fuzz_wrappers; #[macro_use] pub mod ser_macros; -#[cfg(feature = "std")] +#[cfg(any(test, feature = "_test_utils"))] +pub mod dyn_signer; + +#[cfg(any(test, feature = "_test_utils"))] pub mod mut_global; pub mod errors; diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 9aa34fd4ca6..0cfa2781ba6 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -12,7 +12,7 @@ use crate::ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, HolderCom use crate::ln::channel_keys::{HtlcKey}; use crate::ln::msgs; use crate::ln::types::PaymentPreimage; -use crate::sign::{InMemorySigner, ChannelSigner}; +use crate::sign::ChannelSigner; use crate::sign::ecdsa::EcdsaChannelSigner; #[allow(unused_imports)] @@ -20,7 +20,7 @@ use crate::prelude::*; use core::cmp; use crate::sync::{Mutex, Arc}; -#[cfg(test)] use crate::sync::MutexGuard; +#[cfg(any(test, feature = "_test_utils"))] use crate::sync::MutexGuard; use bitcoin::transaction::Transaction; use bitcoin::hashes::Hash; @@ -34,6 +34,7 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature}; #[cfg(taproot)] use musig2::types::{PartialSignature, PublicNonce}; +use crate::chain::transaction::OutPoint; use crate::sign::HTLCDescriptor; use crate::util::ser::{Writeable, Writer}; use crate::io::Error; @@ -42,6 +43,7 @@ use crate::ln::features::ChannelTypeFeatures; use crate::ln::msgs::PartialSignatureWithNonce; #[cfg(taproot)] use crate::sign::taproot::TaprootChannelSigner; +use crate::util::dyn_signer::DynSigner; /// Initial value for revoked commitment downward counter pub const INITIAL_REVOKED_COMMITMENT_NUMBER: u64 = 1 << 48; @@ -67,7 +69,7 @@ pub const INITIAL_REVOKED_COMMITMENT_NUMBER: u64 = 1 << 48; /// forwards-compatibility prefix/suffixes! #[derive(Clone)] pub struct TestChannelSigner { - pub inner: InMemorySigner, + pub inner: DynSigner, /// Channel state used for policy enforcement pub state: Arc>, pub disable_revocation_policy_check: bool, @@ -118,7 +120,7 @@ impl PartialEq for TestChannelSigner { impl TestChannelSigner { /// Construct an TestChannelSigner - pub fn new(inner: InMemorySigner) -> Self { + pub fn new(inner: DynSigner) -> Self { let state = Arc::new(Mutex::new(EnforcementState::new())); Self { inner, @@ -132,7 +134,7 @@ impl TestChannelSigner { /// Since there are multiple copies of this struct for each channel, some coordination is needed /// so that all copies are aware of enforcement state. A pointer to this state is provided /// here, usually by an implementation of KeysInterface. - pub fn new_with_revoked(inner: InMemorySigner, state: Arc>, disable_revocation_policy_check: bool) -> Self { + pub fn new_with_revoked(inner: DynSigner, state: Arc>, disable_revocation_policy_check: bool) -> Self { Self { inner, state, @@ -142,17 +144,17 @@ impl TestChannelSigner { pub fn channel_type_features(&self) -> &ChannelTypeFeatures { self.inner.channel_type_features().unwrap() } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn get_enforcement_state(&self) -> MutexGuard { self.state.lock().unwrap() } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn enable_op(&self, signer_op: SignerOp) { self.get_enforcement_state().disabled_signer_ops.remove(&signer_op); } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn disable_op(&self, signer_op: SignerOp) { self.get_enforcement_state().disabled_signer_ops.insert(signer_op); } @@ -164,6 +166,26 @@ impl TestChannelSigner { } impl ChannelSigner for TestChannelSigner { + fn commitment_seed(&self) -> [u8; 32] { + todo!() + } + + fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> { + todo!() + } + + fn funding_outpoint(&self) -> Option<&OutPoint> { + todo!() + } + + fn get_channel_parameters(&self) -> Option<&ChannelTransactionParameters> { + todo!() + } + + fn channel_type_features(&self) -> Option<&ChannelTypeFeatures> { + todo!() + } + fn get_per_commitment_point(&self, idx: u64, secp_ctx: &Secp256k1) -> Result { #[cfg(test)] if !self.is_signer_available(SignerOp::GetPerCommitmentPoint) { @@ -249,13 +271,13 @@ impl EcdsaChannelSigner for TestChannelSigner { if state.last_holder_revoked_commitment - 1 != commitment_number && state.last_holder_revoked_commitment - 2 != commitment_number { if !self.disable_revocation_policy_check { panic!("can only sign the next two unrevoked commitment numbers, revoked={} vs requested={} for {}", - state.last_holder_revoked_commitment, commitment_number, self.inner.commitment_seed[0]) + state.last_holder_revoked_commitment, commitment_number, self.inner.commitment_seed()[0]) } } Ok(self.inner.sign_holder_commitment(commitment_tx, secp_ctx).unwrap()) } - #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1) -> Result { Ok(self.inner.unsafe_sign_holder_commitment(commitment_tx, secp_ctx).unwrap()) } @@ -290,7 +312,7 @@ impl EcdsaChannelSigner for TestChannelSigner { { if !self.disable_revocation_policy_check { panic!("can only sign the next two unrevoked commitment numbers, revoked={} vs requested={} for {}", - state.last_holder_revoked_commitment, htlc_descriptor.per_commitment_number, self.inner.commitment_seed[0]) + state.last_holder_revoked_commitment, htlc_descriptor.per_commitment_number, self.inner.commitment_seed()[0]) } } assert_eq!(htlc_tx.input[input], htlc_descriptor.unsigned_tx_input()); diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 12e027d32fc..3593ea3e99d 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -14,7 +14,7 @@ use crate::chain; use crate::chain::WatchedOutput; use crate::chain::chaininterface; use crate::chain::chaininterface::ConfirmationTarget; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] use crate::chain::chaininterface::FEERATE_FLOOR_SATS_PER_KW; use crate::chain::chainmonitor; use crate::chain::channelmonitor; @@ -27,7 +27,7 @@ use crate::events::bump_transaction::{WalletSource, Utxo}; use crate::ln::types::ChannelId; use crate::ln::channel_state::ChannelDetails; use crate::ln::channelmanager; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] use crate::ln::chan_utils::CommitmentTransaction; use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use crate::ln::{msgs, wire}; @@ -41,11 +41,15 @@ use crate::routing::utxo::{UtxoLookup, UtxoLookupError, UtxoResult}; use crate::routing::router::{DefaultRouter, InFlightHtlcs, Path, Route, RouteParameters, RouteHintHop, Router, ScorerAccountingForInFlightHtlcs}; use crate::routing::scoring::{ChannelUsage, ScoreUpdate, ScoreLookUp}; use crate::sync::RwLock; +use crate::sign::ChannelSigner; use crate::util::config::UserConfig; use crate::util::test_channel_signer::{TestChannelSigner, EnforcementState}; use crate::util::logger::{Logger, Record}; +#[cfg(feature = "std")] +use crate::util::mut_global::MutGlobal; use crate::util::ser::{Readable, ReadableArgs, Writer, Writeable}; use crate::util::persist::KVStore; +use crate::util::dyn_signer::{DynKeysInterface, DynPhantomKeysInterface, DynSigner, DynKeysInterfaceTrait}; use bitcoin::amount::Amount; use bitcoin::constants::ChainHash; @@ -73,7 +77,7 @@ use core::time::Duration; use crate::sync::{Mutex, Arc}; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use core::mem; -use crate::sign::{InMemorySigner, RandomBytes, Recipient, EntropySource, NodeSigner, SignerProvider}; +use crate::sign::{RandomBytes, Recipient, EntropySource, NodeSigner, SignerProvider}; use bitcoin::psbt::Psbt; use bitcoin::Sequence; @@ -321,7 +325,7 @@ impl SignerProvider for OnlyReadsKeysInterface { fn derive_channel_signer(&self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { unreachable!(); } fn read_chan_signer(&self, mut reader: &[u8]) -> Result { - let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; + let inner: DynSigner = ReadableArgs::read(&mut reader, self)?; let state = Arc::new(Mutex::new(EnforcementState::new())); Ok(TestChannelSigner::new_with_revoked( @@ -425,14 +429,14 @@ impl<'a> chain::Watch for TestChainMonitor<'a> { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] struct JusticeTxData { justice_tx: Transaction, value: Amount, commitment_number: u64, } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] pub(crate) struct WatchtowerPersister { persister: TestPersister, /// Upon a new commitment_signed, we'll get a @@ -446,9 +450,8 @@ pub(crate) struct WatchtowerPersister { destination_script: ScriptBuf, } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] impl WatchtowerPersister { - #[cfg(test)] pub(crate) fn new(destination_script: ScriptBuf) -> Self { WatchtowerPersister { persister: TestPersister::new(), @@ -458,7 +461,6 @@ impl WatchtowerPersister { } } - #[cfg(test)] pub(crate) fn justice_tx(&self, funding_txo: OutPoint, commitment_txid: &Txid) -> Option { self.watchtower_state.lock().unwrap().get(&funding_txo).unwrap().get(commitment_txid).cloned() @@ -477,7 +479,7 @@ impl WatchtowerPersister { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] impl chainmonitor::Persist for WatchtowerPersister { fn persist_new_channel(&self, funding_txo: OutPoint, data: &channelmonitor::ChannelMonitor @@ -768,7 +770,7 @@ impl TestChannelMessageHandler { let mut msgs = self.expected_recv_msgs.lock().unwrap(); if msgs.is_none() { return; } assert!(!msgs.as_ref().unwrap().is_empty(), "Received message when we weren't expecting one"); - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] assert_eq!(msgs.as_ref().unwrap()[0], _ev); msgs.as_mut().unwrap().remove(0); } @@ -1228,7 +1230,7 @@ impl NodeSigner for TestNodeSigner { } pub struct TestKeysInterface { - pub backing: sign::PhantomKeysManager, + pub backing: DynKeysInterface, pub override_random_bytes: Mutex>, pub disable_revocation_policy_check: bool, enforcement_states: Mutex>>>, @@ -1291,7 +1293,7 @@ impl SignerProvider for TestKeysInterface { fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> TestChannelSigner { let keys = self.backing.derive_channel_signer(channel_value_satoshis, channel_keys_id); - let state = self.make_enforcement_state_cell(keys.commitment_seed); + let state = self.make_enforcement_state_cell(keys.commitment_seed()); let signer = TestChannelSigner::new_with_revoked(keys, state, self.disable_revocation_policy_check); #[cfg(test)] if let Some(ops) = self.unavailable_signers_ops.lock().unwrap().get(&channel_keys_id) { @@ -1305,8 +1307,8 @@ impl SignerProvider for TestKeysInterface { fn read_chan_signer(&self, buffer: &[u8]) -> Result { let mut reader = io::Cursor::new(buffer); - let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; - let state = self.make_enforcement_state_cell(inner.commitment_seed); + let inner: DynSigner = ReadableArgs::read(&mut reader, &self.backing)?; + let state = self.make_enforcement_state_cell(inner.commitment_seed()); Ok(TestChannelSigner::new_with_revoked( inner, @@ -1328,11 +1330,38 @@ impl SignerProvider for TestKeysInterface { } } +#[cfg(feature = "std")] +pub static SIGNER_FACTORY: MutGlobal> = MutGlobal::new(|| { Arc::new(DefaultSignerFactory()) }); + +pub trait TestSignerFactory: Send + Sync { + /// Make a dynamic signer + fn make_signer(&self, seed: &[u8; 32], now: Duration) -> Box>; +} + +#[derive(Clone)] +struct DefaultSignerFactory(); + +impl TestSignerFactory for DefaultSignerFactory { + fn make_signer(&self, seed: &[u8; 32], now: Duration) -> Box> { + let phantom = sign::PhantomKeysManager::new(seed, now.as_secs(), now.subsec_nanos(), seed); + let dphantom = DynPhantomKeysInterface::new(phantom); + let backing = Box::new(dphantom) as Box>; + backing + } +} + impl TestKeysInterface { pub fn new(seed: &[u8; 32], network: Network) -> Self { + #[cfg(feature = "std")] + let factory = SIGNER_FACTORY.get(); + + #[cfg(not(feature = "std"))] + let factory = DefaultSignerFactory(); + let now = Duration::from_secs(genesis_block(network).header.time as u64); + let backing = factory.make_signer(seed, now); Self { - backing: sign::PhantomKeysManager::new(seed, now.as_secs(), now.subsec_nanos(), seed), + backing: DynKeysInterface::new(backing), override_random_bytes: Mutex::new(None), disable_revocation_policy_check: false, enforcement_states: Mutex::new(new_hash_map()),