Skip to content

Commit 271d1b7

Browse files
committed
Expose functional tests under _externalize_tests feature flag
Also, introduce TestSignerFactory, a factory for dynamic signers and ext-functional-test-demo crate for testing this machinery.
1 parent d1c8d9a commit 271d1b7

32 files changed

+578
-494
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ lightning-rapid-gossip-sync/res/full_graph.lngossip
1313
lightning-custom-message/target
1414
lightning-transaction-sync/target
1515
lightning-dns-resolver/target
16+
ext-functional-test-demo/target
1617
no-std-check/target
1718
msrv-no-dev-deps-check/target

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ members = [
2121

2222
exclude = [
2323
"lightning-transaction-sync",
24+
"ext-functional-test-demo",
2425
"no-std-check",
2526
"msrv-no-dev-deps-check",
2627
"bench",

ci/ci-tests.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ cargo check --verbose --color always
112112
[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean
113113
popd
114114

115+
echo -e "\n\Running functional tests from outside the workspace"
116+
pushd ext-functional-test-demo
117+
[ "$RUSTC_MINOR_VERSION" -lt 65 ] && cargo update -p regex --precise "1.9.6" --verbose
118+
cargo test --color always
119+
[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean
120+
popd
121+
115122
# Test that we can build downstream code with only the "release pins".
116123
pushd msrv-no-dev-deps-check
117124
PIN_RELEASE_DEPS

ext-functional-test-demo/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "ext-functional-tester"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
lightning = { path = "../lightning", features = ["_externalize_tests"] }

ext-functional-test-demo/src/main.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
fn main() {
2+
println!("{} tests were exported", lightning::get_xtests().len());
3+
}
4+
5+
#[cfg(test)]
6+
mod tests {
7+
use lightning::util::dyn_signer::{DynKeysInterfaceTrait, DynSigner};
8+
use lightning::util::test_utils::{TestSignerFactory, SIGNER_FACTORY};
9+
use std::panic::catch_unwind;
10+
use std::sync::Arc;
11+
use std::time::Duration;
12+
13+
struct BrokenSignerFactory();
14+
15+
impl TestSignerFactory for BrokenSignerFactory {
16+
fn make_signer(
17+
&self, _seed: &[u8; 32], _now: Duration,
18+
) -> Box<dyn DynKeysInterfaceTrait<EcdsaSigner = DynSigner>> {
19+
panic!()
20+
}
21+
}
22+
23+
#[test]
24+
fn test_functional() {
25+
lightning::ln::functional_tests::test_insane_channel_opens();
26+
lightning::ln::functional_tests::fake_network_test();
27+
28+
SIGNER_FACTORY.set(Arc::new(BrokenSignerFactory()));
29+
catch_unwind(|| lightning::ln::functional_tests::fake_network_test()).unwrap_err();
30+
}
31+
}

fuzz/src/chanmon_consistency.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ use bitcoin::secp256k1::schnorr;
8181
use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey};
8282

8383
use lightning::io::Cursor;
84+
use lightning::util::dyn_signer::DynSigner;
8485
use std::cmp::{self, Ordering};
8586
use std::mem;
8687
use std::sync::atomic;
@@ -382,6 +383,7 @@ impl SignerProvider for KeyProvider {
382383
channel_keys_id,
383384
);
384385
let revoked_commitment = self.make_enforcement_state_cell(keys.commitment_seed);
386+
let keys = DynSigner::new(keys);
385387
TestChannelSigner::new_with_revoked(keys, revoked_commitment, false)
386388
}
387389

@@ -390,6 +392,7 @@ impl SignerProvider for KeyProvider {
390392

391393
let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?;
392394
let state = self.make_enforcement_state_cell(inner.commitment_seed);
395+
let inner = DynSigner::new(inner);
393396

394397
Ok(TestChannelSigner::new_with_revoked(inner, state, false))
395398
}

fuzz/src/full_stack.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
7676
use bitcoin::secp256k1::schnorr;
7777
use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey};
7878

79+
use lightning::util::dyn_signer::DynSigner;
7980
use std::cell::RefCell;
8081
use std::cmp;
8182
use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
@@ -444,7 +445,7 @@ impl SignerProvider for KeyProvider {
444445
let ctr = channel_keys_id[0];
445446
let (inbound, state) = self.signer_state.borrow().get(&ctr).unwrap().clone();
446447
TestChannelSigner::new_with_revoked(
447-
if inbound {
448+
DynSigner::new(if inbound {
448449
InMemorySigner::new(
449450
&secp_ctx,
450451
SecretKey::from_slice(&[
@@ -516,7 +517,7 @@ impl SignerProvider for KeyProvider {
516517
channel_keys_id,
517518
channel_keys_id,
518519
)
519-
},
520+
}),
520521
state,
521522
false,
522523
)
@@ -525,6 +526,7 @@ impl SignerProvider for KeyProvider {
525526
fn read_chan_signer(&self, mut data: &[u8]) -> Result<TestChannelSigner, DecodeError> {
526527
let inner: InMemorySigner = ReadableArgs::read(&mut data, self)?;
527528
let state = Arc::new(Mutex::new(EnforcementState::new()));
529+
let inner = DynSigner::new(inner);
528530

529531
Ok(TestChannelSigner::new_with_revoked(inner, state, false))
530532
}

lightning-background-processor/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,6 +2550,8 @@ mod tests {
25502550
failure: PathFailure::OnPath { network_update: None },
25512551
path: path.clone(),
25522552
short_channel_id: Some(scored_scid),
2553+
error_code: None,
2554+
error_data: None,
25532555
});
25542556
let event = $receive.expect("PaymentPathFailed not handled within deadline");
25552557
match event {
@@ -2567,6 +2569,8 @@ mod tests {
25672569
failure: PathFailure::OnPath { network_update: None },
25682570
path: path.clone(),
25692571
short_channel_id: None,
2572+
error_code: None,
2573+
error_data: None,
25702574
});
25712575
let event = $receive.expect("PaymentPathFailed not handled within deadline");
25722576
match event {

lightning-macros/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ pub fn drop_legacy_field_definition(expr: TokenStream) -> TokenStream {
306306
///
307307
/// fn f1() {}
308308
///
309-
/// #[xtest(feature = "_test_utils")]
309+
/// #[xtest(feature = "_externalize_tests")]
310310
/// pub fn test_f1() {
311311
/// f1();
312312
/// }
@@ -317,7 +317,7 @@ pub fn drop_legacy_field_definition(expr: TokenStream) -> TokenStream {
317317
/// ```rust
318318
/// use lightning_macros::xtest;
319319
///
320-
/// #[xtest(feature = "_test_utils")]
320+
/// #[xtest(feature = "_externalize_tests")]
321321
/// pub mod tests {
322322
/// use super::*;
323323
///

lightning/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ rustdoc-args = ["--cfg", "docsrs"]
1818
[features]
1919
# Internal test utilities exposed to other repo crates
2020
_test_utils = ["regex", "bitcoin/bitcoinconsensus", "lightning-types/_test_utils"]
21-
21+
_externalize_tests = ["inventory", "_test_utils"]
2222
# Allow signing of local transactions that may have been revoked or will be revoked, for functional testing (e.g. justice tx handling).
2323
# This is unsafe to use in production because it may result in the counterparty publishing taking our funds.
2424
unsafe_revoked_tx_signing = []
@@ -48,10 +48,12 @@ regex = { version = "1.5.6", optional = true }
4848
backtrace = { version = "0.3", optional = true }
4949

5050
libm = { version = "0.2", default-features = false }
51+
inventory = { version = "0.3", optional = true }
5152

5253
[dev-dependencies]
5354
regex = "1.5.6"
5455
lightning-types = { version = "0.3.0", path = "../lightning-types", features = ["_test_utils"] }
56+
lightning-macros = { path = "../lightning-macros" }
5557

5658
[dev-dependencies.bitcoin]
5759
version = "0.32.2"

lightning/src/chain/chainmonitor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ where C::Target: chain::Filter,
469469
}
470470

471471

472-
#[cfg(test)]
472+
#[cfg(any(test, feature = "_test_utils"))]
473473
pub fn remove_monitor(&self, channel_id: &ChannelId) -> ChannelMonitor<ChannelSigner> {
474474
self.monitors.write().unwrap().remove(channel_id).unwrap().monitor
475475
}

lightning/src/chain/channelmonitor.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -854,10 +854,7 @@ impl Readable for IrrevocablyResolvedHTLC {
854854
/// returned block hash and the the current chain and then reconnecting blocks to get to the
855855
/// best chain) upon deserializing the object!
856856
pub struct ChannelMonitor<Signer: EcdsaChannelSigner> {
857-
#[cfg(test)]
858857
pub(crate) inner: Mutex<ChannelMonitorImpl<Signer>>,
859-
#[cfg(not(test))]
860-
pub(super) inner: Mutex<ChannelMonitorImpl<Signer>>,
861858
}
862859

863860
impl<Signer: EcdsaChannelSigner> Clone for ChannelMonitor<Signer> where Signer: Clone {
@@ -965,9 +962,9 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
965962
// Obviously Correct (tm) if we just keep track of them explicitly.
966963
outputs_to_watch: HashMap<Txid, Vec<(u32, ScriptBuf)>>,
967964

968-
#[cfg(test)]
965+
#[cfg(any(test, feature = "_test_utils"))]
969966
pub onchain_tx_handler: OnchainTxHandler<Signer>,
970-
#[cfg(not(test))]
967+
#[cfg(not(any(test, feature = "_test_utils")))]
971968
onchain_tx_handler: OnchainTxHandler<Signer>,
972969

973970
// This is set when the Channel[Manager] generated a ChannelMonitorUpdate which indicated the
@@ -1814,7 +1811,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
18141811
/// Unsafe test-only version of `broadcast_latest_holder_commitment_txn` used by our test framework
18151812
/// to bypass HolderCommitmentTransaction state update lockdown after signature and generate
18161813
/// revoked commitment transaction.
1817-
#[cfg(any(test, feature = "unsafe_revoked_tx_signing"))]
1814+
#[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))]
18181815
pub fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
18191816
where L::Target: Logger {
18201817
let mut inner = self.inner.lock().unwrap();
@@ -2128,7 +2125,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
21282125
self.inner.lock().unwrap().counterparty_payment_script = script;
21292126
}
21302127

2131-
#[cfg(test)]
2128+
#[cfg(any(test, feature = "_test_utils"))]
21322129
pub fn do_mut_signer_call<F: FnMut(&mut Signer) -> ()>(&self, mut f: F) {
21332130
let mut inner = self.inner.lock().unwrap();
21342131
f(&mut inner.onchain_tx_handler.signer);
@@ -2769,7 +2766,7 @@ macro_rules! fail_unbroadcast_htlcs {
27692766
// witness length match (ie is 136 bytes long). We generate one here which we also use in some
27702767
// in-line tests later.
27712768

2772-
#[cfg(test)]
2769+
#[cfg(any(test, feature = "_test_utils"))]
27732770
pub fn deliberately_bogus_accepted_htlc_witness_program() -> Vec<u8> {
27742771
use bitcoin::opcodes;
27752772
let mut ret = [opcodes::all::OP_NOP.to_u8(); 136];
@@ -2781,7 +2778,7 @@ pub fn deliberately_bogus_accepted_htlc_witness_program() -> Vec<u8> {
27812778
Vec::from(&ret[..])
27822779
}
27832780

2784-
#[cfg(test)]
2781+
#[cfg(any(test, feature = "_test_utils"))]
27852782
pub fn deliberately_bogus_accepted_htlc_witness() -> Vec<Vec<u8>> {
27862783
vec![Vec::new(), Vec::new(), Vec::new(), Vec::new(), deliberately_bogus_accepted_htlc_witness_program().into()].into()
27872784
}
@@ -3947,7 +3944,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39473944
}
39483945
}
39493946

3950-
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
3947+
#[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))]
39513948
/// Note that this includes possibly-locktimed-in-the-future transactions!
39523949
fn unsafe_get_latest_holder_commitment_txn<L: Deref>(
39533950
&mut self, logger: &WithChannelMonitor<L>
@@ -5289,7 +5286,7 @@ mod tests {
52895286
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(&new_header,
52905287
&[(0, broadcast_tx)], conf_height);
52915288

5292-
let (_, pre_update_monitor) = <(BlockHash, ChannelMonitor<InMemorySigner>)>::read(
5289+
let (_, pre_update_monitor) = <(BlockHash, ChannelMonitor<_>)>::read(
52935290
&mut io::Cursor::new(&get_monitor!(nodes[1], channel.2).encode()),
52945291
(&nodes[1].keys_manager.backing, &nodes[1].keys_manager.backing)).unwrap();
52955292

lightning/src/chain/onchaintx.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,9 @@ pub struct OnchainTxHandler<ChannelSigner: EcdsaChannelSigner> {
250250
// Key is identifier of the pending claim request, i.e the txid of the initial claiming transaction generated by
251251
// us and is immutable until all outpoint of the claimable set are post-anti-reorg-delay solved.
252252
// Entry is cache of elements need to generate a bumped claiming transaction (see ClaimTxBumpMaterial)
253-
#[cfg(test)] // Used in functional_test to verify sanitization
253+
#[cfg(any(test, feature = "_test_utils"))]
254254
pub(crate) pending_claim_requests: HashMap<ClaimId, PackageTemplate>,
255-
#[cfg(not(test))]
255+
#[cfg(not(any(test, feature = "_test_utils")))]
256256
pending_claim_requests: HashMap<ClaimId, PackageTemplate>,
257257

258258
// Used to track external events that need to be forwarded to the `ChainMonitor`. This `Vec`
@@ -273,9 +273,9 @@ pub struct OnchainTxHandler<ChannelSigner: EcdsaChannelSigner> {
273273
// block height, and are immutable until the outpoint has enough confirmations to meet our
274274
// [`ANTI_REORG_DELAY`]. The initial confirmation block height is used to remove the entry if
275275
// the block gets disconnected.
276-
#[cfg(test)] // Used in functional_test to verify sanitization
277-
pub claimable_outpoints: HashMap<BitcoinOutPoint, (ClaimId, u32)>,
278-
#[cfg(not(test))]
276+
#[cfg(any(test, feature = "_test_utils"))]
277+
pub(crate) claimable_outpoints: HashMap<BitcoinOutPoint, (ClaimId, u32)>,
278+
#[cfg(not(any(test, feature = "_test_utils")))]
279279
claimable_outpoints: HashMap<BitcoinOutPoint, (ClaimId, u32)>,
280280

281281
locktimed_packages: BTreeMap<u32, Vec<PackageTemplate>>,
@@ -1194,7 +1194,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
11941194
MaybeSignedTransaction(tx)
11951195
}
11961196

1197-
#[cfg(any(test, feature="unsafe_revoked_tx_signing"))]
1197+
#[cfg(any(test, feature="_test_utils", feature="unsafe_revoked_tx_signing"))]
11981198
pub(crate) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction {
11991199
let sig = self.signer.unsafe_sign_holder_commitment(&self.holder_commitment, &self.secp_ctx).expect("sign holder commitment");
12001200
self.holder_commitment.add_holder_sig(funding_redeemscript, sig)

lightning/src/chain/package.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ pub(crate) fn verify_channel_type_features(channel_type_features: &Option<Channe
105105
// number_of_witness_elements + sig_length + revocation_sig + true_length + op_true + witness_script_length + witness_script
106106
pub(crate) const WEIGHT_REVOKED_OUTPUT: u64 = 1 + 1 + 73 + 1 + 1 + 1 + 77;
107107

108-
#[cfg(not(test))]
108+
#[cfg(not(any(test, feature = "_test_utils")))]
109109
/// Height delay at which transactions are fee-bumped/rebroadcasted with a low priority.
110110
const LOW_FREQUENCY_BUMP_INTERVAL: u32 = 15;
111-
#[cfg(test)]
111+
#[cfg(any(test, feature = "_test_utils"))]
112112
/// Height delay at which transactions are fee-bumped/rebroadcasted with a low priority.
113113
pub(crate) const LOW_FREQUENCY_BUMP_INTERVAL: u32 = 15;
114114

lightning/src/events/mod.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,9 +1054,9 @@ pub enum Event {
10541054
/// If this is `Some`, then the corresponding channel should be avoided when the payment is
10551055
/// retried. May be `None` for older [`Event`] serializations.
10561056
short_channel_id: Option<u64>,
1057-
#[cfg(test)]
1057+
#[cfg(any(test, feature = "_test_utils"))]
10581058
error_code: Option<u16>,
1059-
#[cfg(test)]
1059+
#[cfg(any(test, feature = "_test_utils"))]
10601060
error_data: Option<Vec<u8>>,
10611061
},
10621062
/// Indicates that a probe payment we sent returned successful, i.e., only failed at the destination.
@@ -1569,15 +1569,15 @@ impl Writeable for Event {
15691569
&Event::PaymentPathFailed {
15701570
ref payment_id, ref payment_hash, ref payment_failed_permanently, ref failure,
15711571
ref path, ref short_channel_id,
1572-
#[cfg(test)]
1572+
#[cfg(any(test, feature = "_test_utils"))]
15731573
ref error_code,
1574-
#[cfg(test)]
1574+
#[cfg(any(test, feature = "_test_utils"))]
15751575
ref error_data,
15761576
} => {
15771577
3u8.write(writer)?;
1578-
#[cfg(test)]
1578+
#[cfg(any(test, feature = "_test_utils"))]
15791579
error_code.write(writer)?;
1580-
#[cfg(test)]
1580+
#[cfg(any(test, feature = "_test_utils"))]
15811581
error_data.write(writer)?;
15821582
write_tlv_fields!(writer, {
15831583
(0, payment_hash, required),
@@ -1920,9 +1920,9 @@ impl MaybeReadable for Event {
19201920
},
19211921
3u8 => {
19221922
let mut f = || {
1923-
#[cfg(test)]
1923+
#[cfg(any(test, feature = "_test_utils"))]
19241924
let error_code = Readable::read(reader)?;
1925-
#[cfg(test)]
1925+
#[cfg(any(test, feature = "_test_utils"))]
19261926
let error_data = Readable::read(reader)?;
19271927
let mut payment_hash = PaymentHash([0; 32]);
19281928
let mut payment_failed_permanently = false;
@@ -1952,9 +1952,9 @@ impl MaybeReadable for Event {
19521952
failure,
19531953
path: Path { hops: path.unwrap(), blinded_tail },
19541954
short_channel_id,
1955-
#[cfg(test)]
1955+
#[cfg(any(test, feature = "_test_utils"))]
19561956
error_code,
1957-
#[cfg(test)]
1957+
#[cfg(any(test, feature = "_test_utils"))]
19581958
error_data,
19591959
}))
19601960
};
@@ -2364,7 +2364,7 @@ impl MaybeReadable for Event {
23642364
/// broadcast to most peers).
23652365
/// These events are handled by PeerManager::process_events if you are using a PeerManager.
23662366
#[derive(Clone, Debug)]
2367-
#[cfg_attr(test, derive(PartialEq))]
2367+
#[cfg_attr(any(test, feature = "_test_utils"), derive(PartialEq))]
23682368
pub enum MessageSendEvent {
23692369
/// Used to indicate that we've accepted a channel open and should send the accept_channel
23702370
/// message provided to the given peer.

lightning/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,6 @@ mod prelude {
142142
extern crate backtrace;
143143

144144
mod sync;
145+
146+
#[cfg(feature = "_externalize_tests")]
147+
lightning_macros::xtest_inventory!();

0 commit comments

Comments
 (0)