Merge pull request #2280 from TheBlueMatt/2023-05-event-deadlock
authorWilmer Paulino <9447167+wpaulino@users.noreply.github.com>
Wed, 24 May 2023 17:51:16 +0000 (10:51 -0700)
committerGitHub <noreply@github.com>
Wed, 24 May 2023 17:51:16 +0000 (10:51 -0700)
Never block a thread on the `PeerManager` event handling lock

49 files changed:
.github/workflows/build.yml
.gitignore
Cargo.toml
bench/Cargo.toml [new file with mode: 0644]
bench/README.md [new file with mode: 0644]
bench/benches/bench.rs [new file with mode: 0644]
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
fuzz/src/router.rs
lightning-background-processor/src/lib.rs
lightning-block-sync/src/poll.rs
lightning-custom-message/src/lib.rs
lightning-invoice/src/lib.rs
lightning-persister/Cargo.toml
lightning-persister/src/lib.rs
lightning-rapid-gossip-sync/Cargo.toml
lightning-rapid-gossip-sync/src/lib.rs
lightning-transaction-sync/src/lib.rs
lightning/Cargo.toml
lightning/src/chain/chaininterface.rs
lightning/src/chain/chainmonitor.rs
lightning/src/chain/channelmonitor.rs
lightning/src/chain/onchaintx.rs
lightning/src/chain/package.rs
lightning/src/lib.rs
lightning/src/ln/chanmon_update_fail_tests.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/features.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/mod.rs
lightning/src/ln/monitor_tests.rs
lightning/src/ln/msgs.rs
lightning/src/ln/onion_route_tests.rs
lightning/src/ln/onion_utils.rs
lightning/src/ln/payment_tests.rs
lightning/src/ln/peer_handler.rs
lightning/src/ln/reorg_tests.rs
lightning/src/ln/shutdown_tests.rs
lightning/src/onion_message/functional_tests.rs
lightning/src/onion_message/messenger.rs
lightning/src/routing/gossip.rs
lightning/src/routing/router.rs
lightning/src/routing/scoring.rs
lightning/src/sign/mod.rs
lightning/src/sync/mod.rs
lightning/src/util/ser.rs
lightning/src/util/test_utils.rs
pending_changelog/big-om-error.txt [new file with mode: 0644]

index 8e02ec9da75c803caa0dfd9b797ea6b892a13298..3b6d1a0388c693e407419af903f295a57cd715b7 100644 (file)
@@ -141,7 +141,12 @@ jobs:
           cd ..
       - name: Run benchmarks on Rust ${{ matrix.toolchain }}
         run: |
-          RUSTC_BOOTSTRAP=1 cargo bench --features _bench_unstable
+          cd bench
+          RUSTFLAGS="--cfg=ldk_bench --cfg=require_route_graph_test" cargo bench
+      - name: Run benchmarks with hashbrown on Rust ${{ matrix.toolchain }}
+        run: |
+          cd bench
+          RUSTFLAGS="--cfg=ldk_bench --cfg=require_route_graph_test" cargo bench --features hashbrown
 
   check_commits:
     runs-on: ubuntu-latest
index 7a889b5b8230af929cd28134454d2f93502531bd..7a6dc4c793032bc2c1ddf8e3e465201df6cf3543 100644 (file)
@@ -8,6 +8,8 @@ lightning-c-bindings/a.out
 Cargo.lock
 .idea
 lightning/target
-lightning/ldk-net_graph-*.bin
+lightning/net_graph-*.bin
+lightning-rapid-gossip-sync/res/full_graph.lngossip
 lightning-custom-message/target
+lightning-transaction-sync/target
 no-std-check/target
index afc0092c72da50a1a9fecbf8bfb2edf5daa04104..a3acccfdaea91614b98421590dd567d1a678ef58 100644 (file)
@@ -14,6 +14,7 @@ exclude = [
     "lightning-custom-message",
     "lightning-transaction-sync",
     "no-std-check",
+    "bench",
 ]
 
 # Our tests do actual crypto and lots of work, the tradeoff for -O2 is well
@@ -35,8 +36,3 @@ lto = "off"
 opt-level = 3
 lto = true
 panic = "abort"
-
-[profile.bench]
-opt-level = 3
-codegen-units = 1
-lto = true
diff --git a/bench/Cargo.toml b/bench/Cargo.toml
new file mode 100644 (file)
index 0000000..e582d29
--- /dev/null
@@ -0,0 +1,25 @@
+[package]
+name = "lightning-bench"
+version = "0.0.1"
+authors = ["Matt Corallo"]
+edition = "2018"
+
+[[bench]]
+name = "bench"
+harness = false
+
+[features]
+hashbrown = ["lightning/hashbrown"]
+
+[dependencies]
+lightning = { path = "../lightning", features = ["_test_utils", "criterion"] }
+lightning-persister = { path = "../lightning-persister", features = ["criterion"] }
+lightning-rapid-gossip-sync = { path = "../lightning-rapid-gossip-sync", features = ["criterion"] }
+criterion = { version = "0.4", default-features = false }
+
+[profile.release]
+opt-level = 3
+codegen-units = 1
+lto = true
+panic = "abort"
+debug = true
diff --git a/bench/README.md b/bench/README.md
new file mode 100644 (file)
index 0000000..7d4cacc
--- /dev/null
@@ -0,0 +1,6 @@
+This crate uses criterion to benchmark various LDK functions.
+
+It can be run as `RUSTFLAGS=--cfg=ldk_bench cargo bench`.
+
+For routing or other HashMap-bottlenecked functions, the `hashbrown` feature
+should also be benchmarked.
diff --git a/bench/benches/bench.rs b/bench/benches/bench.rs
new file mode 100644 (file)
index 0000000..54799f4
--- /dev/null
@@ -0,0 +1,22 @@
+extern crate lightning;
+extern crate lightning_persister;
+
+extern crate criterion;
+
+use criterion::{criterion_group, criterion_main};
+
+criterion_group!(benches,
+       // Note that benches run in the order given here. Thus, they're sorted according to how likely
+       // developers are to be working on the specific code listed, then by runtime.
+       lightning::routing::router::benches::generate_routes_with_zero_penalty_scorer,
+       lightning::routing::router::benches::generate_mpp_routes_with_zero_penalty_scorer,
+       lightning::routing::router::benches::generate_routes_with_probabilistic_scorer,
+       lightning::routing::router::benches::generate_mpp_routes_with_probabilistic_scorer,
+       lightning::routing::router::benches::generate_large_mpp_routes_with_probabilistic_scorer,
+       lightning::sign::benches::bench_get_secure_random_bytes,
+       lightning::ln::channelmanager::bench::bench_sends,
+       lightning_persister::bench::bench_sends,
+       lightning_rapid_gossip_sync::bench::bench_reading_full_graph_from_file,
+       lightning::routing::gossip::benches::read_network_graph,
+       lightning::routing::gossip::benches::write_network_graph);
+criterion_main!(benches);
index 837386bd94ce6a4f288102be3fca40b20f0cca75..f8c6c08a2baca464273858365e770e35145655e4 100644 (file)
@@ -18,8 +18,6 @@
 //! send-side handling is correct, other peers. We consider it a failure if any action results in a
 //! channel being force-closed.
 
-use bitcoin::TxMerkleNode;
-use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::blockdata::transaction::{Transaction, TxOut};
 use bitcoin::blockdata::script::{Builder, Script};
@@ -45,6 +43,7 @@ use lightning::ln::channelmanager::{ChainParameters, ChannelDetails, ChannelMana
 use lightning::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
 use lightning::ln::msgs::{self, CommitmentUpdate, ChannelMessageHandler, DecodeError, UpdateAddHTLC, Init};
 use lightning::ln::script::ShutdownScript;
+use lightning::ln::functional_test_utils::*;
 use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
 use lightning::util::errors::APIError;
 use lightning::util::logger::Logger;
@@ -101,7 +100,7 @@ impl Router for FuzzRouter {
 
 pub struct TestBroadcaster {}
 impl BroadcasterInterface for TestBroadcaster {
-       fn broadcast_transaction(&self, _tx: &Transaction) { }
+       fn broadcast_transactions(&self, _txs: &[&Transaction]) { }
 }
 
 pub struct VecWriter(pub Vec<u8>);
@@ -547,11 +546,11 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
        macro_rules! confirm_txn {
                ($node: expr) => { {
                        let chain_hash = genesis_block(Network::Bitcoin).block_hash();
-                       let mut header = BlockHeader { version: 0x20000000, prev_blockhash: chain_hash, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
+                       let mut header = create_dummy_header(chain_hash, 42);
                        let txdata: Vec<_> = channel_txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect();
                        $node.transactions_confirmed(&header, &txdata, 1);
                        for _ in 2..100 {
-                               header = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
+                               header = create_dummy_header(header.block_hash(), 42);
                        }
                        $node.best_block_updated(&header, 99);
                } }
index d044a35f01bba364a8d17d1831591df4f74c8627..1192766bf3e0baadb5c61fef3c0c07dbff0f56f3 100644 (file)
@@ -13,8 +13,6 @@
 //! or payments to send/ways to handle events generated.
 //! This test has been very useful, though due to its complexity good starting inputs are critical.
 
-use bitcoin::TxMerkleNode;
-use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::blockdata::transaction::{Transaction, TxOut};
 use bitcoin::blockdata::script::{Builder, Script};
@@ -41,6 +39,7 @@ use lightning::ln::channelmanager::{ChainParameters, ChannelDetails, ChannelMana
 use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor,IgnoringMessageHandler};
 use lightning::ln::msgs::{self, DecodeError};
 use lightning::ln::script::ShutdownScript;
+use lightning::ln::functional_test_utils::*;
 use lightning::routing::gossip::{P2PGossipSync, NetworkGraph};
 use lightning::routing::utxo::UtxoLookup;
 use lightning::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router};
@@ -48,7 +47,7 @@ use lightning::util::config::UserConfig;
 use lightning::util::errors::APIError;
 use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
 use lightning::util::logger::Logger;
-use lightning::util::ser::{Readable, ReadableArgs, Writeable};
+use lightning::util::ser::{ReadableArgs, Writeable};
 
 use crate::utils::test_logger;
 use crate::utils::test_persister::TestPersister;
@@ -145,8 +144,9 @@ struct TestBroadcaster {
        txn_broadcasted: Mutex<Vec<Transaction>>,
 }
 impl BroadcasterInterface for TestBroadcaster {
-       fn broadcast_transaction(&self, tx: &Transaction) {
-               self.txn_broadcasted.lock().unwrap().push(tx.clone());
+       fn broadcast_transactions(&self, txs: &[&Transaction]) {
+               let owned_txs: Vec<Transaction> = txs.iter().map(|tx| (*tx).clone()).collect();
+               self.txn_broadcasted.lock().unwrap().extend(owned_txs);
        }
 }
 
@@ -228,7 +228,7 @@ impl<'a> MoneyLossDetector<'a> {
                }
 
                self.blocks_connected += 1;
-               let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height].0, merkle_root: TxMerkleNode::all_zeros(), time: self.blocks_connected, bits: 42, nonce: 42 };
+               let header = create_dummy_header(self.header_hashes[self.height].0, self.blocks_connected);
                self.height += 1;
                self.manager.transactions_confirmed(&header, &txdata, self.height as u32);
                self.manager.best_block_updated(&header, self.height as u32);
@@ -245,7 +245,7 @@ impl<'a> MoneyLossDetector<'a> {
 
        fn disconnect_block(&mut self) {
                if self.height > 0 && (self.max_height < 6 || self.height >= self.max_height - 6) {
-                       let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height - 1].0, merkle_root: TxMerkleNode::all_zeros(), time: self.header_hashes[self.height].1, bits: 42, nonce: 42 };
+                       let header = create_dummy_header(self.header_hashes[self.height - 1].0, self.header_hashes[self.height].1);
                        self.manager.block_disconnected(&header, self.height as u32);
                        self.monitor.block_disconnected(&header, self.height as u32);
                        self.height -= 1;
@@ -752,16 +752,16 @@ mod tests {
                // 00 030000000000000000000000000000000000000000000000000000000000000002 03000000000000000000000000000000 - noise act two (0||pubkey||mac)
                //
                // 030012 - inbound read from peer id 0 of len 18
-               // 000a 03000000000000000000000000000000 - message header indicating message length 10
-               // 03001a - inbound read from peer id 0 of len 26
-               // 0010 00022000 00022000 03000000000000000000000000000000 - init message (type 16) with static_remotekey (0x2000) and mac
+               // 0010 03000000000000000000000000000000 - message header indicating message length 16
+               // 030020 - inbound read from peer id 0 of len 32
+               // 0010 00021aaa 0008aaaaaaaaaaaa9aaa 03000000000000000000000000000000 - init message (type 16) with static_remotekey required and other bits optional and mac
                //
                // 030012 - inbound read from peer id 0 of len 18
-               // 0141 03000000000000000000000000000000 - message header indicating message length 321
+               // 0147 03000000000000000000000000000000 - message header indicating message length 327
                // 0300fe - inbound read from peer id 0 of len 254
                // 0020 7500000000000000000000000000000000000000000000000000000000000000 ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679 000000000000c350 0000000000000000 0000000000000162 ffffffffffffffff 0000000000000222 0000000000000000 000000fd 0006 01e3 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 030000000000000000000000000000000000000000000000000000000000000004 - beginning of open_channel message
-               // 030053 - inbound read from peer id 0 of len 83
-               // 030000000000000000000000000000000000000000000000000000000000000005 020900000000000000000000000000000000000000000000000000000000000000 01 03000000000000000000000000000000 - rest of open_channel and mac
+               // 030059 - inbound read from peer id 0 of len 89
+               // 030000000000000000000000000000000000000000000000000000000000000005 020900000000000000000000000000000000000000000000000000000000000000 01 0000 01021000 03000000000000000000000000000000 - rest of open_channel and mac
                //
                // 00fd00fd - Two feerate requests (all returning min feerate, which our open_channel also uses) (gonna be ingested by FuzzEstimator)
                // - client should now respond with accept_channel (CHECK 1: type 33 to peer 03000000)
@@ -800,19 +800,19 @@ mod tests {
                // 000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000 - inbound noise act 3
                //
                // 030112 - inbound read from peer id 1 of len 18
-               // 000a 01000000000000000000000000000000 - message header indicating message length 10
-               // 03011a - inbound read from peer id 1 of len 26
-               // 0010 00022000 00022000 01000000000000000000000000000000 - init message (type 16) with static_remotekey (0x2000) and mac
+               // 0010 01000000000000000000000000000000 - message header indicating message length 16
+               // 030120 - inbound read from peer id 1 of len 32
+               // 0010 00021aaa 0008aaaaaaaaaaaa9aaa 01000000000000000000000000000000 - init message (type 16) with static_remotekey required and other bits optional and mac
                //
                // 05 01 030200000000000000000000000000000000000000000000000000000000000000 00c350 0003e8 - create outbound channel to peer 1 for 50k sat
                // 00fd - One feerate requests (all returning min feerate) (gonna be ingested by FuzzEstimator)
                //
                // 030112 - inbound read from peer id 1 of len 18
-               // 0110 01000000000000000000000000000000 - message header indicating message length 272
+               // 0112 01000000000000000000000000000000 - message header indicating message length 274
                // 0301ff - inbound read from peer id 1 of len 255
                // 0021 0000000000000000000000000000000000000000000000000000000000000e05 0000000000000162 00000000004c4b40 00000000000003e8 00000000000003e8 00000002 03f0 0005 030000000000000000000000000000000000000000000000000000000000000100 030000000000000000000000000000000000000000000000000000000000000200 030000000000000000000000000000000000000000000000000000000000000300 030000000000000000000000000000000000000000000000000000000000000400 030000000000000000000000000000000000000000000000000000000000000500 02660000000000000000000000000000 - beginning of accept_channel
-               // 030121 - inbound read from peer id 1 of len 33
-               // 0000000000000000000000000000000000 01000000000000000000000000000000 - rest of accept_channel and mac
+               // 030123 - inbound read from peer id 1 of len 35
+               // 0000000000000000000000000000000000 0000 01000000000000000000000000000000 - rest of accept_channel and mac
                //
                // 0a - create the funding transaction (client should send funding_created now)
                //
@@ -1006,7 +1006,7 @@ mod tests {
                // - client now fails the HTLC backwards as it was unable to extract the payment preimage (CHECK 9 duplicate and CHECK 10)
 
                let logger = Arc::new(TrackingLogger { lines: Mutex::new(HashMap::new()) });
-               super::do_test(&::hex::decode("01000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000020300320003000000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000030012000a0300000000000000000000000000000003001a00100002200000022000030000000000000000000000000000000300120141030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000162ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030053030000000000000000000000000000000000000000000000000000000000000005020900000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112000a0100000000000000000000000000000003011a0010000220000002200001000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd0301120110010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e05000000000000016200000000004c4b4000000000000003e800000000000003e80000000203f00005030000000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000200030000000000000000000000000000000000000000000000000000000000000300030000000000000000000000000000000000000000000000000000000000000400030000000000000000000000000000000000000000000000000000000000000500026600000000000000000000000000000301210000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000b03011200430100000000000000000000000000000003015300243a000000000000000000000000000000000000000000000000000000000000000267000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000020b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000002640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a00823a000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a0000000000000000000000000000000000000000000000000000000000000067000000000000000000000000000000000000000000000000000000000000000265000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020d00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833a00000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005551202030927c00401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff53000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007501000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006705000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c00000000000001600142800000000000000000000000000000000000000050000200c005e0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b200000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc<dyn Logger>));
+               super::do_test(&::hex::decode("01000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000020300320003000000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000030012001003000000000000000000000000000000030020001000021aaa0008aaaaaaaaaaaa9aaa030000000000000000000000000000000300120147030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000162ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030059030000000000000000000000000000000000000000000000000000000000000005020900000000000000000000000000000000000000000000000000000000000000010000010210000300000000000000000000000000000000fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112001001000000000000000000000000000000030120001000021aaa0008aaaaaaaaaaaa9aaa01000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd0301120112010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e05000000000000016200000000004c4b4000000000000003e800000000000003e80000000203f000050300000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000002000300000000000000000000000000000000000000000000000000000000000003000300000000000000000000000000000000000000000000000000000000000004000300000000000000000000000000000000000000000000000000000000000005000266000000000000000000000000000003012300000000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000b03011200430100000000000000000000000000000003015300243a000000000000000000000000000000000000000000000000000000000000000267000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000020b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000002640000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a00823a000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a0000000000000000000000000000000000000000000000000000000000000067000000000000000000000000000000000000000000000000000000000000000265000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff00000000000000000000000000000000000000000000000000000000000000000003f00003000000000000000000000000000000000000000000000000000000000000055511020203e80401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffab000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020d00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833a00000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853a000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032010000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff00000000000000000000000000000000000000000000000000000000000000000003f0000300000000000000000000000000000000000000000000000000000000000005551202030927c00401a0060800000e00000100000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff53000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007501000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006705000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c00000000000001600142800000000000000000000000000000000000000050000200c005e0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b200000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc<dyn Logger>));
 
                let log_entries = logger.lines.lock().unwrap();
                assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1
index 7c09c860025f8ce084cafd854a05cf9569384335..00c53dfe58e5d2ca7ed365bc6381f0de6fb4427b 100644 (file)
@@ -17,7 +17,7 @@ use lightning::ln::msgs;
 use lightning::routing::gossip::{NetworkGraph, RoutingFees};
 use lightning::routing::utxo::{UtxoFuture, UtxoLookup, UtxoLookupError, UtxoResult};
 use lightning::routing::router::{find_route, PaymentParameters, RouteHint, RouteHintHop, RouteParameters};
-use lightning::routing::scoring::ProbabilisticScorer;
+use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
 use lightning::util::config::UserConfig;
 use lightning::util::ser::Readable;
 
@@ -293,7 +293,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                }]));
                                        }
                                }
-                               let scorer = ProbabilisticScorer::new(Default::default(), &net_graph, &logger);
+                               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &net_graph, &logger);
                                let random_seed_bytes: [u8; 32] = [get_slice!(1)[0]; 32];
                                for target in node_pks.iter() {
                                        let final_value_msat = slice_to_be64(get_slice!(8));
@@ -305,7 +305,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                        };
                                        let _ = find_route(&our_pubkey, &route_params, &net_graph,
                                                first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),
-                                               &logger, &scorer, &random_seed_bytes);
+                                               &logger, &scorer, &ProbabilisticScoringFeeParameters::default(), &random_seed_bytes);
                                }
                        },
                }
index 9d13facad8110490ddbbf12bb40bc7747881d5a5..4d270286d5027c780d36a16a58711d11e72dcf47 100644 (file)
@@ -108,7 +108,7 @@ const PING_TIMER: u64 = 1;
 const NETWORK_PRUNE_TIMER: u64 = 60 * 60;
 
 #[cfg(not(test))]
-const SCORER_PERSIST_TIMER: u64 = 30;
+const SCORER_PERSIST_TIMER: u64 = 60 * 60;
 #[cfg(test)]
 const SCORER_PERSIST_TIMER: u64 = 1;
 
@@ -236,9 +236,11 @@ fn handle_network_graph_update<L: Deref>(
        }
 }
 
+/// Updates scorer based on event and returns whether an update occurred so we can decide whether
+/// to persist.
 fn update_scorer<'a, S: 'static + Deref<Target = SC> + Send + Sync, SC: 'a + WriteableScore<'a>>(
        scorer: &'a S, event: &Event
-) {
+) -> bool {
        let mut score = scorer.lock();
        match event {
                Event::PaymentPathFailed { ref path, short_channel_id: Some(scid), .. } => {
@@ -258,8 +260,9 @@ fn update_scorer<'a, S: 'static + Deref<Target = SC> + Send + Sync, SC: 'a + Wri
                Event::ProbeFailed { path, short_channel_id: Some(scid), .. } => {
                        score.probe_failed(path, *scid);
                },
-               _ => {},
+               _ => return false,
        }
+       true
 }
 
 macro_rules! define_run_body {
@@ -352,9 +355,15 @@ macro_rules! define_run_body {
                        // Note that we want to run a graph prune once not long after startup before
                        // falling back to our usual hourly prunes. This avoids short-lived clients never
                        // pruning their network graph. We run once 60 seconds after startup before
-                       // continuing our normal cadence.
+                       // continuing our normal cadence. For RGS, since 60 seconds is likely too long,
+                       // we prune after an initial sync completes.
                        let prune_timer = if have_pruned { NETWORK_PRUNE_TIMER } else { FIRST_NETWORK_PRUNE_TIMER };
-                       if $timer_elapsed(&mut last_prune_call, prune_timer) {
+                       let prune_timer_elapsed = $timer_elapsed(&mut last_prune_call, prune_timer);
+                       let should_prune = match $gossip_sync {
+                               GossipSync::Rapid(_) => !have_pruned || prune_timer_elapsed,
+                               _ => prune_timer_elapsed,
+                       };
+                       if should_prune {
                                // The network graph must not be pruned while rapid sync completion is pending
                                if let Some(network_graph) = $gossip_sync.prunable_network_graph() {
                                        #[cfg(feature = "std")] {
@@ -616,12 +625,19 @@ where
                let network_graph = gossip_sync.network_graph();
                let event_handler = &event_handler;
                let scorer = &scorer;
+               let logger = &logger;
+               let persister = &persister;
                async move {
                        if let Some(network_graph) = network_graph {
                                handle_network_graph_update(network_graph, &event)
                        }
                        if let Some(ref scorer) = scorer {
-                               update_scorer(scorer, &event);
+                               if update_scorer(scorer, &event) {
+                                       log_trace!(logger, "Persisting scorer after update");
+                                       if let Err(e) = persister.persist_scorer(&scorer) {
+                                               log_error!(logger, "Error: Failed to persist scorer, check your disk and permissions {}", e)
+                                       }
+                               }
                        }
                        event_handler(event).await;
                }
@@ -751,7 +767,12 @@ impl BackgroundProcessor {
                                        handle_network_graph_update(network_graph, &event)
                                }
                                if let Some(ref scorer) = scorer {
-                                       update_scorer(scorer, &event);
+                                       if update_scorer(scorer, &event) {
+                                               log_trace!(logger, "Persisting scorer after update");
+                                               if let Err(e) = persister.persist_scorer(&scorer) {
+                                                       log_error!(logger, "Error: Failed to persist scorer, check your disk and permissions {}", e)
+                                               }
+                                       }
                                }
                                event_handler.handle_event(event);
                        };
@@ -817,7 +838,6 @@ impl Drop for BackgroundProcessor {
 
 #[cfg(all(feature = "std", test))]
 mod tests {
-       use bitcoin::blockdata::block::BlockHeader;
        use bitcoin::blockdata::constants::genesis_block;
        use bitcoin::blockdata::locktime::PackedLockTime;
        use bitcoin::blockdata::transaction::{Transaction, TxOut};
@@ -833,6 +853,7 @@ mod tests {
        use lightning::ln::channelmanager;
        use lightning::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChainParameters, MIN_CLTV_EXPIRY_DELTA, PaymentId};
        use lightning::ln::features::{ChannelFeatures, NodeFeatures};
+       use lightning::ln::functional_test_utils::*;
        use lightning::ln::msgs::{ChannelMessageHandler, Init};
        use lightning::ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor, IgnoringMessageHandler};
        use lightning::routing::gossip::{NetworkGraph, NodeId, P2PGossipSync};
@@ -849,8 +870,6 @@ mod tests {
        use std::sync::{Arc, Mutex};
        use std::sync::mpsc::SyncSender;
        use std::time::Duration;
-       use bitcoin::hashes::Hash;
-       use bitcoin::TxMerkleNode;
        use lightning_rapid_gossip_sync::RapidGossipSync;
        use super::{BackgroundProcessor, GossipSync, FRESHNESS_TIMER};
 
@@ -866,7 +885,7 @@ mod tests {
                fn disconnect_socket(&mut self) {}
        }
 
-       type ChannelManager = channelmanager::ChannelManager<Arc<ChainMonitor>, Arc<test_utils::TestBroadcaster>, Arc<KeysManager>, Arc<KeysManager>, Arc<KeysManager>, Arc<test_utils::TestFeeEstimator>, Arc<DefaultRouter< Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestLogger>, Arc<Mutex<TestScorer>>>>, Arc<test_utils::TestLogger>>;
+       type ChannelManager = channelmanager::ChannelManager<Arc<ChainMonitor>, Arc<test_utils::TestBroadcaster>, Arc<KeysManager>, Arc<KeysManager>, Arc<KeysManager>, Arc<test_utils::TestFeeEstimator>, Arc<DefaultRouter<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestLogger>, Arc<Mutex<TestScorer>>, (), TestScorer>>, Arc<test_utils::TestLogger>>;
 
        type ChainMonitor = chainmonitor::ChainMonitor<InMemorySigner, Arc<test_utils::TestChainSource>, Arc<test_utils::TestBroadcaster>, Arc<test_utils::TestFeeEstimator>, Arc<test_utils::TestLogger>, Arc<FilesystemPersister>>;
 
@@ -1000,8 +1019,9 @@ mod tests {
        }
 
        impl Score for TestScorer {
+               type ScoreParams = ();
                fn channel_penalty_msat(
-                       &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId, _usage: ChannelUsage
+                       &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId, _usage: ChannelUsage, _score_params: &Self::ScoreParams
                ) -> u64 { unimplemented!(); }
 
                fn payment_path_failed(&mut self, actual_path: &Path, actual_short_channel_id: u64) {
@@ -1114,7 +1134,7 @@ mod tests {
                        let network_graph = Arc::new(NetworkGraph::new(network, logger.clone()));
                        let scorer = Arc::new(Mutex::new(TestScorer::new()));
                        let seed = [i as u8; 32];
-                       let router = Arc::new(DefaultRouter::new(network_graph.clone(), logger.clone(), seed, scorer.clone()));
+                       let router = Arc::new(DefaultRouter::new(network_graph.clone(), logger.clone(), seed, scorer.clone(), ()));
                        let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
                        let persister = Arc::new(FilesystemPersister::new(format!("{}_persister_{}", &persist_dir, i)));
                        let now = Duration::from_secs(genesis_block.header.time as u64);
@@ -1189,7 +1209,7 @@ mod tests {
                for i in 1..=depth {
                        let prev_blockhash = node.best_block.block_hash();
                        let height = node.best_block.height() + 1;
-                       let header = BlockHeader { version: 0x20000000, prev_blockhash, merkle_root: TxMerkleNode::all_zeros(), time: height, bits: 42, nonce: 42 };
+                       let header = create_dummy_header(prev_blockhash, height);
                        let txdata = vec![(0, tx)];
                        node.best_block = BestBlock::new(header.block_hash(), height);
                        match i {
@@ -1709,6 +1729,10 @@ mod tests {
                if !std::thread::panicking() {
                        bg_processor.stop().unwrap();
                }
+
+               let log_entries = nodes[0].logger.lines.lock().unwrap();
+               let expected_log = "Persisting scorer after update".to_string();
+               assert_eq!(*log_entries.get(&("lightning_background_processor".to_string(), expected_log)).unwrap(), 5);
        }
 
        #[tokio::test]
@@ -1751,6 +1775,10 @@ mod tests {
                let t2 = tokio::spawn(async move {
                        do_test_payment_path_scoring!(nodes, receiver.recv().await);
                        exit_sender.send(()).unwrap();
+
+                       let log_entries = nodes[0].logger.lines.lock().unwrap();
+                       let expected_log = "Persisting scorer after update".to_string();
+                       assert_eq!(*log_entries.get(&("lightning_background_processor".to_string(), expected_log)).unwrap(), 5);
                });
 
                let (r1, r2) = tokio::join!(t1, t2);
index 9f7e8becf5060c2f62471825a2aa0cfeca573f5e..e7171cf3656138036d50385691c96e419db29bcd 100644 (file)
@@ -136,8 +136,11 @@ impl ValidatedBlockHeader {
 
                if let Network::Bitcoin = network {
                        if self.height % 2016 == 0 {
-                               let previous_work = previous_header.header.work();
-                               if work > (previous_work << 2) || work < (previous_work >> 2) {
+                               let target = self.header.target();
+                               let previous_target = previous_header.header.target();
+                               let min_target = previous_target >> 2;
+                               let max_target = previous_target << 2;
+                               if target > max_target || target < min_target {
                                        return Err(BlockSourceError::persistent("invalid difficulty transition"))
                                }
                        } else if self.header.bits != previous_header.header.bits {
index a6e43978d47ded2e1c9efd58c50fe234d7a02564..a0a70c9de03ff26dfd499bb7b8cb1dc6eeee8dbe 100644 (file)
@@ -20,6 +20,7 @@
 //! # use bitcoin::secp256k1::PublicKey;
 //! # use lightning::io;
 //! # use lightning::ln::msgs::{DecodeError, LightningError};
+//! # use lightning::ln::features::{InitFeatures, NodeFeatures};
 //! use lightning::ln::peer_handler::CustomMessageHandler;
 //! use lightning::ln::wire::{CustomMessageReader, self};
 //! use lightning::util::ser::Writeable;
 //! #     fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> {
 //! #         unimplemented!()
 //! #     }
+//! #     fn provided_node_features(&self) -> NodeFeatures {
+//! #         unimplemented!()
+//! #     }
+//! #     fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
+//! #         unimplemented!()
+//! #     }
 //! }
 //!
 //! #[derive(Debug)]
 //! #     fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> {
 //! #         unimplemented!()
 //! #     }
+//! #     fn provided_node_features(&self) -> NodeFeatures {
+//! #         unimplemented!()
+//! #     }
+//! #     fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
+//! #         unimplemented!()
+//! #     }
 //! }
 //!
 //! #[derive(Debug)]
 //! #     fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> {
 //! #         unimplemented!()
 //! #     }
+//! #     fn provided_node_features(&self) -> NodeFeatures {
+//! #         unimplemented!()
+//! #     }
+//! #     fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
+//! #         unimplemented!()
+//! #     }
 //! }
 //!
 //! # fn main() {
@@ -268,6 +287,22 @@ macro_rules! composite_custom_message_handler {
                                        )*
                                        .collect()
                        }
+
+                       fn provided_node_features(&self) -> $crate::lightning::ln::features::NodeFeatures {
+                               $crate::lightning::ln::features::NodeFeatures::empty()
+                                       $(
+                                               | self.$field.provided_node_features()
+                                       )*
+                       }
+
+                       fn provided_init_features(
+                               &self, their_node_id: &$crate::bitcoin::secp256k1::PublicKey
+                       ) -> $crate::lightning::ln::features::InitFeatures {
+                               $crate::lightning::ln::features::InitFeatures::empty()
+                                       $(
+                                               | self.$field.provided_init_features(their_node_id)
+                                       )*
+                       }
                }
 
                impl $crate::lightning::ln::wire::CustomMessageReader for $handler {
index f53c8953b47c66b9344d86a928d9e834790989f7..8ccd9d979ab139899731d3724566b0b12e27069d 100644 (file)
@@ -61,6 +61,7 @@ use secp256k1::PublicKey;
 use secp256k1::{Message, Secp256k1};
 use secp256k1::ecdsa::RecoverableSignature;
 
+use core::cmp::Ordering;
 use core::fmt::{Display, Formatter, self};
 use core::iter::FilterMap;
 use core::num::ParseIntError;
@@ -248,7 +249,7 @@ pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S:
 ///  3. using `str::parse::<Invoice>(&str)` (see [`Invoice::from_str`])
 ///
 /// [`Invoice::from_str`]: crate::Invoice#impl-FromStr
-#[derive(Eq, PartialEq, Debug, Clone, Hash)]
+#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
 pub struct Invoice {
        signed_invoice: SignedRawInvoice,
 }
@@ -258,7 +259,7 @@ pub struct Invoice {
 ///
 /// This is not exported to bindings users as we don't have a good way to map the reference lifetimes making this
 /// practically impossible to use safely in languages like C.
-#[derive(Eq, PartialEq, Debug, Clone)]
+#[derive(Eq, PartialEq, Debug, Clone, Ord, PartialOrd)]
 pub enum InvoiceDescription<'f> {
        /// Reference to the directly supplied description in the invoice
        Direct(&'f Description),
@@ -272,7 +273,7 @@ pub enum InvoiceDescription<'f> {
 ///
 /// # Invariants
 /// The hash has to be either from the deserialized invoice or from the serialized [`RawInvoice`].
-#[derive(Eq, PartialEq, Debug, Clone, Hash)]
+#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
 pub struct SignedRawInvoice {
        /// The rawInvoice that the signature belongs to
        raw_invoice: RawInvoice,
@@ -295,7 +296,7 @@ pub struct SignedRawInvoice {
 /// Decoding and encoding should not lead to information loss but may lead to different hashes.
 ///
 /// For methods without docs see the corresponding methods in [`Invoice`].
-#[derive(Eq, PartialEq, Debug, Clone, Hash)]
+#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
 pub struct RawInvoice {
        /// human readable part
        pub hrp: RawHrp,
@@ -307,7 +308,7 @@ pub struct RawInvoice {
 /// Data of the [`RawInvoice`] that is encoded in the human readable part.
 ///
 /// This is not exported to bindings users as we don't yet support `Option<Enum>`
-#[derive(Eq, PartialEq, Debug, Clone, Hash)]
+#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
 pub struct RawHrp {
        /// The currency deferred from the 3rd and 4th character of the bech32 transaction
        pub currency: Currency,
@@ -320,7 +321,7 @@ pub struct RawHrp {
 }
 
 /// Data of the [`RawInvoice`] that is encoded in the data part
-#[derive(Eq, PartialEq, Debug, Clone, Hash)]
+#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
 pub struct RawDataPart {
        /// generation time of the invoice
        pub timestamp: PositiveTimestamp,
@@ -335,11 +336,11 @@ pub struct RawDataPart {
 ///
 /// The Unix timestamp representing the stored time has to be positive and no greater than
 /// [`MAX_TIMESTAMP`].
-#[derive(Eq, PartialEq, Debug, Clone, Hash)]
+#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
 pub struct PositiveTimestamp(Duration);
 
 /// SI prefixes for the human readable part
-#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
+#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Ord, PartialOrd)]
 pub enum SiPrefix {
        /// 10^-3
        Milli,
@@ -376,7 +377,7 @@ impl SiPrefix {
 }
 
 /// Enum representing the crypto currencies (or networks) supported by this library
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub enum Currency {
        /// Bitcoin mainnet
        Bitcoin,
@@ -420,7 +421,7 @@ impl From<Currency> for Network {
 /// Tagged field which may have an unknown tag
 ///
 /// This is not exported to bindings users as we don't currently support TaggedField
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub enum RawTaggedField {
        /// Parsed tagged field with known tag
        KnownSemantics(TaggedField),
@@ -435,7 +436,7 @@ pub enum RawTaggedField {
 /// This is not exported to bindings users as we don't yet support enum variants with the same name the struct contained
 /// in the variant.
 #[allow(missing_docs)]
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub enum TaggedField {
        PaymentHash(Sha256),
        Description(Description),
@@ -451,7 +452,7 @@ pub enum TaggedField {
 }
 
 /// SHA-256 hash
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub struct Sha256(/// This is not exported to bindings users as the native hash types are not currently mapped
        pub sha256::Hash);
 
@@ -468,25 +469,25 @@ impl Sha256 {
 ///
 /// # Invariants
 /// The description can be at most 639 __bytes__ long
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub struct Description(String);
 
 /// Payee public key
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub struct PayeePubKey(pub PublicKey);
 
 /// Positive duration that defines when (relatively to the timestamp) in the future the invoice
 /// expires
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub struct ExpiryTime(Duration);
 
 /// `min_final_cltv_expiry_delta` to use for the last HTLC in the route
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub struct MinFinalCltvExpiryDelta(pub u64);
 
 /// Fallback address in case no LN payment is possible
 #[allow(missing_docs)]
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub enum Fallback {
        SegWitProgram {
                version: WitnessVersion,
@@ -500,12 +501,24 @@ pub enum Fallback {
 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
 pub struct InvoiceSignature(pub RecoverableSignature);
 
+impl PartialOrd for InvoiceSignature {
+       fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+               self.0.serialize_compact().1.partial_cmp(&other.0.serialize_compact().1)
+       }
+}
+
+impl Ord for InvoiceSignature {
+       fn cmp(&self, other: &Self) -> Ordering {
+               self.0.serialize_compact().1.cmp(&other.0.serialize_compact().1)
+       }
+}
+
 /// Private routing information
 ///
 /// # Invariants
 /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
 ///
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub struct PrivateRoute(RouteHint);
 
 /// Tag constants as specified in BOLT11
index 88132bdcfd660ed70e367ed63c420a08244e408c..22d4b16c42dde8a4828fb424ad64ab5da52ad326 100644 (file)
@@ -13,9 +13,6 @@ edition = "2018"
 all-features = true
 rustdoc-args = ["--cfg", "docsrs"]
 
-[features]
-_bench_unstable = ["lightning/_bench_unstable"]
-
 [dependencies]
 bitcoin = "0.29.0"
 lightning = { version = "0.0.115", path = "../lightning" }
@@ -24,5 +21,8 @@ libc = "0.2"
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["winbase"] }
 
+[target.'cfg(ldk_bench)'.dependencies]
+criterion = { version = "0.4", optional = true, default-features = false }
+
 [dev-dependencies]
 lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] }
index d25ab6f9fca9db824c6f0b7a6d1a3d1086989d72..670a7369d8b92c7bb415125f3dc49186c4b2f3d3 100644 (file)
@@ -8,8 +8,7 @@
 
 #![cfg_attr(docsrs, feature(doc_auto_cfg))]
 
-#![cfg_attr(all(test, feature = "_bench_unstable"), feature(test))]
-#[cfg(all(test, feature = "_bench_unstable"))] extern crate test;
+#[cfg(ldk_bench)] extern crate criterion;
 
 mod util;
 
@@ -91,13 +90,13 @@ impl FilesystemPersister {
                                continue;
                        }
 
-                       let txid = Txid::from_hex(filename.split_at(64).0)
+                       let txid: Txid = Txid::from_hex(filename.split_at(64).0)
                                .map_err(|_| std::io::Error::new(
                                        std::io::ErrorKind::InvalidData,
                                        "Invalid tx ID in filename",
                                ))?;
 
-                       let index = filename.split_at(65).1.parse()
+                       let index: u16 = filename.split_at(65).1.parse()
                                .map_err(|_| std::io::Error::new(
                                        std::io::ErrorKind::InvalidData,
                                        "Invalid tx index in filename",
@@ -136,9 +135,8 @@ mod tests {
        extern crate lightning;
        extern crate bitcoin;
        use crate::FilesystemPersister;
-       use bitcoin::blockdata::block::{Block, BlockHeader};
        use bitcoin::hashes::hex::FromHex;
-       use bitcoin::{Txid, TxMerkleNode};
+       use bitcoin::Txid;
        use lightning::chain::ChannelMonitorUpdateStatus;
        use lightning::chain::chainmonitor::Persist;
        use lightning::chain::channelmonitor::CLOSED_CHANNEL_UPDATE_ID;
@@ -148,7 +146,6 @@ mod tests {
        use lightning::ln::functional_test_utils::*;
        use lightning::util::test_utils;
        use std::fs;
-       use bitcoin::hashes::Hash;
        #[cfg(target_os = "windows")]
        use {
                lightning::get_event_msg,
@@ -247,8 +244,7 @@ mod tests {
                let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
                assert_eq!(node_txn.len(), 1);
 
-               let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-               connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[0].clone()]});
+               connect_block(&nodes[1], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![node_txn[0].clone(), node_txn[0].clone()]));
                check_closed_broadcast!(nodes[1], true);
                check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
                check_added_monitors!(nodes[1], 1);
@@ -338,14 +334,16 @@ mod tests {
        }
 }
 
-#[cfg(all(test, feature = "_bench_unstable"))]
+#[cfg(ldk_bench)]
+/// Benches
 pub mod bench {
-       use test::Bencher;
+       use criterion::Criterion;
 
-       #[bench]
-       fn bench_sends(bench: &mut Bencher) {
+       /// Bench!
+       pub fn bench_sends(bench: &mut Criterion) {
                let persister_a = super::FilesystemPersister::new("bench_filesystem_persister_a".to_string());
                let persister_b = super::FilesystemPersister::new("bench_filesystem_persister_b".to_string());
-               lightning::ln::channelmanager::bench::bench_two_sends(bench, persister_a, persister_b);
+               lightning::ln::channelmanager::bench::bench_two_sends(
+                       bench, "bench_filesystem_persisted_sends", persister_a, persister_b);
        }
 }
index 6673431d93b210d24c87ac42e9c9561b4728d66b..73a68751128809a694ac8eaeede95fb58754d2b8 100644 (file)
@@ -13,11 +13,13 @@ Utility to process gossip routing data from Rapid Gossip Sync Server.
 default = ["std"]
 no-std = ["lightning/no-std"]
 std = ["lightning/std"]
-_bench_unstable = []
 
 [dependencies]
 lightning = { version = "0.0.115", path = "../lightning", default-features = false }
 bitcoin = { version = "0.29.0", default-features = false }
 
+[target.'cfg(ldk_bench)'.dependencies]
+criterion = { version = "0.4", optional = true, default-features = false }
+
 [dev-dependencies]
 lightning = { version = "0.0.115", path = "../lightning", features = ["_test_utils"] }
index c8f140cc18955d8225bbf300fcda2aee6ddae267..5a61be7990e2a17270b7c61deeb8944952255735 100644 (file)
 
 #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
 
-// Allow and import test features for benching
-#![cfg_attr(all(test, feature = "_bench_unstable"), feature(test))]
-#[cfg(all(test, feature = "_bench_unstable"))]
-extern crate test;
+#[cfg(ldk_bench)] extern crate criterion;
 
 #[cfg(not(feature = "std"))]
 extern crate alloc;
@@ -287,36 +284,42 @@ mod tests {
        }
 }
 
-#[cfg(all(test, feature = "_bench_unstable"))]
+#[cfg(ldk_bench)]
+/// Benches
 pub mod bench {
-       use test::Bencher;
-
        use bitcoin::Network;
 
-       use lightning::ln::msgs::DecodeError;
+       use criterion::Criterion;
+
+       use std::fs;
+
        use lightning::routing::gossip::NetworkGraph;
        use lightning::util::test_utils::TestLogger;
 
        use crate::RapidGossipSync;
 
-       #[bench]
-       fn bench_reading_full_graph_from_file(b: &mut Bencher) {
+       /// Bench!
+       pub fn bench_reading_full_graph_from_file(b: &mut Criterion) {
                let logger = TestLogger::new();
-               b.iter(|| {
+               b.bench_function("read_full_graph_from_rgs", |b| b.iter(|| {
                        let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
                        let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
-                       let sync_result = rapid_sync.sync_network_graph_with_file_path("./res/full_graph.lngossip");
-                       if let Err(crate::error::GraphSyncError::DecodeError(DecodeError::Io(io_error))) = &sync_result {
-                               let error_string = format!("Input file lightning-rapid-gossip-sync/res/full_graph.lngossip is missing! Download it from https://bitcoin.ninja/ldk-compressed_graph-bc08df7542-2022-05-05.bin\n\n{:?}", io_error);
-                               #[cfg(not(require_route_graph_test))]
-                               {
-                                       println!("{}", error_string);
-                                       return;
-                               }
-                               #[cfg(require_route_graph_test)]
-                               panic!("{}", error_string);
-                       }
-                       assert!(sync_result.is_ok())
-               });
+                       let mut file = match fs::read("../lightning-rapid-gossip-sync/res/full_graph.lngossip") {
+                               Ok(f) => f,
+                               Err(io_error) => {
+                                       let error_string = format!(
+                                               "Input file lightning-rapid-gossip-sync/res/full_graph.lngossip is missing! Download it from https://bitcoin.ninja/ldk-compressed_graph-bc08df7542-2022-05-05.bin\n\n{:?}",
+                                               io_error);
+                                       #[cfg(not(require_route_graph_test))]
+                                       {
+                                               println!("{}", error_string);
+                                               return;
+                                       }
+                                       #[cfg(require_route_graph_test)]
+                                       panic!("{}", error_string);
+                               },
+                       };
+                       rapid_sync.update_network_graph_no_std(&mut file, None).unwrap();
+               }));
        }
 }
index 05b71d21bb5faaa05d5b0cebccb252b69e9e8db0..ca3ce3f8ad68d5280c2c611fbe2eaab0f81e1bb0 100644 (file)
@@ -13,7 +13,8 @@
 //!
 //! ## Version Compatibility
 //!
-//! Currently this crate is compatible with nodes that were created with LDK version 0.0.113 and above.
+//! Currently this crate is compatible with LDK version 0.0.114 and above using channels which were
+//! created on LDK version 0.0.113 and above.
 //!
 //! ## Usage Example:
 //!
index 1804be0f1bb50ac26b84c6472a7c1137f5b8ebf8..efaa82d2031ba27e2a40cd930f367780f26efb71 100644 (file)
@@ -28,7 +28,6 @@ max_level_trace = []
 # Allow signing of local transactions that may have been revoked or will be revoked, for functional testing (e.g. justice tx handling).
 # This is unsafe to use in production because it may result in the counterparty publishing taking our funds.
 unsafe_revoked_tx_signing = []
-_bench_unstable = []
 # Override signing to not include randomness when generating signatures for test vectors.
 _test_vectors = []
 
@@ -59,5 +58,8 @@ version = "0.29.0"
 default-features = false
 features = ["bitcoinconsensus", "secp-recovery"]
 
+[target.'cfg(ldk_bench)'.dependencies]
+criterion = { version = "0.4", optional = true, default-features = false }
+
 [target.'cfg(taproot)'.dependencies]
 musig2 = { git = "https://github.com/arik-so/rust-musig2", rev = "27797d7" }
index e923a94bb6d3e7afb5f37376b6de132225821d21..d875dcce3e128c1443a2deaa46f1a8465a7cd06b 100644 (file)
@@ -19,8 +19,20 @@ use bitcoin::blockdata::transaction::Transaction;
 
 /// An interface to send a transaction to the Bitcoin network.
 pub trait BroadcasterInterface {
-       /// Sends a transaction out to (hopefully) be mined.
-       fn broadcast_transaction(&self, tx: &Transaction);
+       /// Sends a list of transactions out to (hopefully) be mined.
+       /// This only needs to handle the actual broadcasting of transactions, LDK will automatically
+       /// rebroadcast transactions that haven't made it into a block.
+       ///
+       /// In some cases LDK may attempt to broadcast a transaction which double-spends another
+       /// and this isn't a bug and can be safely ignored.
+       ///
+       /// If more than one transaction is given, these transactions should be considered to be a
+       /// package and broadcast together. Some of the transactions may or may not depend on each other,
+       /// be sure to manage both cases correctly.
+       ///
+       /// Bitcoin transaction packages are defined in BIP 331 and here:
+       /// https://github.com/bitcoin/bitcoin/blob/master/doc/policy/packages.md
+       fn broadcast_transactions(&self, txs: &[&Transaction]);
 }
 
 /// An enum that represents the speed at which we want a transaction to confirm used for feerate
index 37a497005d9948dc531ee7c53c277d927a6fc33c..261e5593b5b4600ad661142a4579308b68903316 100644 (file)
@@ -825,8 +825,6 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner, C: Deref, T: Deref, F: Deref, L
 
 #[cfg(test)]
 mod tests {
-       use bitcoin::{BlockHeader, TxMerkleNode};
-       use bitcoin::hashes::Hash;
        use crate::{check_added_monitors, check_closed_broadcast, check_closed_event};
        use crate::{expect_payment_sent, expect_payment_claimed, expect_payment_sent_without_paths, expect_payment_path_successful, get_event_msg};
        use crate::{get_htlc_update_msgs, get_local_commitment_txn, get_revoke_commit_msgs, get_route_and_payment_hash, unwrap_send_err};
@@ -972,10 +970,7 @@ mod tests {
 
                // Connect B's commitment transaction, but only to the ChainMonitor/ChannelMonitor. The
                // channel is now closed, but the ChannelManager doesn't know that yet.
-               let new_header = BlockHeader {
-                       version: 2, time: 0, bits: 0, nonce: 0,
-                       prev_blockhash: nodes[0].best_block_info().0,
-                       merkle_root: TxMerkleNode::all_zeros() };
+               let new_header = create_dummy_header(nodes[0].best_block_info().0, 0);
                nodes[0].chain_monitor.chain_monitor.transactions_confirmed(&new_header,
                        &[(0, &remote_txn[0]), (1, &remote_txn[1])], nodes[0].best_block_info().1 + 1);
                assert!(nodes[0].chain_monitor.release_pending_monitor_events().is_empty());
@@ -999,10 +994,7 @@ mod tests {
 
                if block_timeout {
                        // After three blocks, pending MontiorEvents should be released either way.
-                       let latest_header = BlockHeader {
-                               version: 2, time: 0, bits: 0, nonce: 0,
-                               prev_blockhash: nodes[0].best_block_info().0,
-                               merkle_root: TxMerkleNode::all_zeros() };
+                       let latest_header = create_dummy_header(nodes[0].best_block_info().0, 0);
                        nodes[0].chain_monitor.chain_monitor.best_block_updated(&latest_header, nodes[0].best_block_info().1 + LATENCY_GRACE_PERIOD_BLOCKS);
                } else {
                        let persistences = chanmon_cfgs[0].persister.chain_sync_monitor_persistences.lock().unwrap().clone();
index e3be6bff2fa88b4191d9b3fdc8bccf665d4ac580..a48f169a4d5e605b330f49896bc191779dd389d7 100644 (file)
@@ -2327,10 +2327,13 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                where B::Target: BroadcasterInterface,
                                        L::Target: Logger,
        {
-               for tx in self.get_latest_holder_commitment_txn(logger).iter() {
+               let commit_txs = self.get_latest_holder_commitment_txn(logger);
+               let mut txs = vec![];
+               for tx in commit_txs.iter() {
                        log_info!(logger, "Broadcasting local {}", log_tx!(tx));
-                       broadcaster.broadcast_transaction(tx);
+                       txs.push(tx);
                }
+               broadcaster.broadcast_transactions(&txs);
                self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
        }
 
@@ -2431,7 +2434,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                        let commitment_package = PackageTemplate::build_package(
                                                                self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
                                                                PackageSolvingData::HolderFundingOutput(funding_output),
-                                                               best_block_height, false, best_block_height,
+                                                               best_block_height, best_block_height
                                                        );
                                                        self.onchain_tx_handler.update_claims_view_from_requests(
                                                                vec![commitment_package], best_block_height, best_block_height,
@@ -2614,8 +2617,8 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        // First, process non-htlc outputs (to_holder & to_counterparty)
                        for (idx, outp) in tx.output.iter().enumerate() {
                                if outp.script_pubkey == revokeable_p2wsh {
-                                       let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv);
-                                       let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, true, height);
+                                       let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv, self.onchain_tx_handler.opt_anchors());
+                                       let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, height);
                                        claimable_outpoints.push(justice_package);
                                        to_counterparty_output_info =
                                                Some((idx.try_into().expect("Txn can't have more than 2^32 outputs"), outp.value));
@@ -2633,7 +2636,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                                to_counterparty_output_info);
                                                }
                                                let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_some());
-                                               let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, true, height);
+                                               let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, height);
                                                claimable_outpoints.push(justice_package);
                                        }
                                }
@@ -2758,8 +2761,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                                self.counterparty_commitment_params.counterparty_htlc_base_key,
                                                                htlc.clone(), self.onchain_tx_handler.opt_anchors()))
                                        };
-                                       let aggregation = if !htlc.offered { false } else { true };
-                                       let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry,aggregation, 0);
+                                       let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry, 0);
                                        claimable_outpoints.push(counterparty_package);
                                }
                        }
@@ -2798,11 +2800,12 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                let revk_outp = RevokedOutput::build(
                                        per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key,
                                        self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key,
-                                       tx.output[idx].value, self.counterparty_commitment_params.on_counterparty_tx_csv
+                                       tx.output[idx].value, self.counterparty_commitment_params.on_counterparty_tx_csv,
+                                       false
                                );
                                let justice_package = PackageTemplate::build_package(
                                        htlc_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp),
-                                       height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, true, height
+                                       height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, height
                                );
                                claimable_outpoints.push(justice_package);
                                if outputs_to_watch.is_none() {
@@ -2825,11 +2828,11 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
 
                for &(ref htlc, _, _) in holder_tx.htlc_outputs.iter() {
                        if let Some(transaction_output_index) = htlc.transaction_output_index {
-                               let (htlc_output, aggregable) = if htlc.offered {
+                               let htlc_output = if htlc.offered {
                                        let htlc_output = HolderHTLCOutput::build_offered(
                                                htlc.amount_msat, htlc.cltv_expiry, self.onchain_tx_handler.opt_anchors()
                                        );
-                                       (htlc_output, false)
+                                       htlc_output
                                } else {
                                        let payment_preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
                                                preimage.clone()
@@ -2840,12 +2843,12 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                        let htlc_output = HolderHTLCOutput::build_accepted(
                                                payment_preimage, htlc.amount_msat, self.onchain_tx_handler.opt_anchors()
                                        );
-                                       (htlc_output, self.onchain_tx_handler.opt_anchors())
+                                       htlc_output
                                };
                                let htlc_package = PackageTemplate::build_package(
                                        holder_tx.txid, transaction_output_index,
                                        PackageSolvingData::HolderHTLCOutput(htlc_output),
-                                       htlc.cltv_expiry, aggregable, conf_height
+                                       htlc.cltv_expiry, conf_height
                                );
                                claim_requests.push(htlc_package);
                        }
@@ -3185,7 +3188,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
                if should_broadcast {
                        let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.opt_anchors());
-                       let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), self.best_block.height(), false, self.best_block.height());
+                       let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), self.best_block.height(), self.best_block.height());
                        claimable_outpoints.push(commitment_package);
                        self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
                        let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
@@ -4084,7 +4087,6 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
 
 #[cfg(test)]
 mod tests {
-       use bitcoin::blockdata::block::BlockHeader;
        use bitcoin::blockdata::script::{Script, Builder};
        use bitcoin::blockdata::opcodes;
        use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, EcdsaSighashType};
@@ -4121,7 +4123,7 @@ mod tests {
        use crate::util::ser::{ReadableArgs, Writeable};
        use crate::sync::{Arc, Mutex};
        use crate::io;
-       use bitcoin::{PackedLockTime, Sequence, TxMerkleNode, Witness};
+       use bitcoin::{PackedLockTime, Sequence, Witness};
        use crate::prelude::*;
 
        fn do_test_funding_spend_refuses_updates(use_local_txn: bool) {
@@ -4160,10 +4162,7 @@ mod tests {
 
                // Connect a commitment transaction, but only to the ChainMonitor/ChannelMonitor. The
                // channel is now closed, but the ChannelManager doesn't know that yet.
-               let new_header = BlockHeader {
-                       version: 2, time: 0, bits: 0, nonce: 0,
-                       prev_blockhash: nodes[0].best_block_info().0,
-                       merkle_root: TxMerkleNode::all_zeros() };
+               let new_header = create_dummy_header(nodes[0].best_block_info().0, 0);
                let conf_height = nodes[0].best_block_info().1 + 1;
                nodes[1].chain_monitor.chain_monitor.transactions_confirmed(&new_header,
                        &[(0, broadcast_tx)], conf_height);
index 21b4717e1d9786dfd2b0eb68092e41f7b3d19afd..45968c57e537077c2d583a24fe9702300d19a8cb 100644 (file)
@@ -513,7 +513,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                OnchainClaim::Tx(tx) => {
                                                        let log_start = if bumped_feerate { "Broadcasting RBF-bumped" } else { "Rebroadcasting" };
                                                        log_info!(logger, "{} onchain {}", log_start, log_tx!(tx));
-                                                       broadcaster.broadcast_transaction(&tx);
+                                                       broadcaster.broadcast_transactions(&[&tx]);
                                                },
                                                #[cfg(anchors)]
                                                OnchainClaim::Event(event) => {
@@ -767,7 +767,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                let package_id = match claim {
                                        OnchainClaim::Tx(tx) => {
                                                log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
-                                               broadcaster.broadcast_transaction(&tx);
+                                               broadcaster.broadcast_transactions(&[&tx]);
                                                tx.txid().into_inner()
                                        },
                                        #[cfg(anchors)]
@@ -960,7 +960,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                match bump_claim {
                                        OnchainClaim::Tx(bump_tx) => {
                                                log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx));
-                                               broadcaster.broadcast_transaction(&bump_tx);
+                                               broadcaster.broadcast_transactions(&[&bump_tx]);
                                        },
                                        #[cfg(anchors)]
                                        OnchainClaim::Event(claim_event) => {
@@ -1046,7 +1046,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                match bump_claim {
                                        OnchainClaim::Tx(bump_tx) => {
                                                log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
-                                               broadcaster.broadcast_transaction(&bump_tx);
+                                               broadcaster.broadcast_transactions(&[&bump_tx]);
                                        },
                                        #[cfg(anchors)]
                                        OnchainClaim::Event(claim_event) => {
index e66092222d83ad4b583db839ea08e94da0751ce4..4604a164cd634534169e46f0df40670f346172c3 100644 (file)
@@ -98,10 +98,11 @@ pub(crate) struct RevokedOutput {
        weight: u64,
        amount: u64,
        on_counterparty_tx_csv: u16,
+       is_counterparty_balance_on_anchors: Option<()>,
 }
 
 impl RevokedOutput {
-       pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, on_counterparty_tx_csv: u16) -> Self {
+       pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, on_counterparty_tx_csv: u16, is_counterparty_balance_on_anchors: bool) -> Self {
                RevokedOutput {
                        per_commitment_point,
                        counterparty_delayed_payment_base_key,
@@ -109,7 +110,8 @@ impl RevokedOutput {
                        per_commitment_key,
                        weight: WEIGHT_REVOKED_OUTPUT,
                        amount,
-                       on_counterparty_tx_csv
+                       on_counterparty_tx_csv,
+                       is_counterparty_balance_on_anchors: if is_counterparty_balance_on_anchors { Some(()) } else { None }
                }
        }
 }
@@ -122,6 +124,7 @@ impl_writeable_tlv_based!(RevokedOutput, {
        (8, weight, required),
        (10, amount, required),
        (12, on_counterparty_tx_csv, required),
+       (14, is_counterparty_balance_on_anchors, option)
 });
 
 /// A struct to describe a revoked offered output and corresponding information to generate a
@@ -479,6 +482,24 @@ impl PackageSolvingData {
                };
                absolute_timelock
        }
+
+       fn map_output_type_flags(&self) -> (PackageMalleability, bool) {
+               // Post-anchor, aggregation of outputs of different types is unsafe. See https://github.com/lightning/bolts/pull/803.
+               let (malleability, aggregable) = match self {
+                       PackageSolvingData::RevokedOutput(RevokedOutput { is_counterparty_balance_on_anchors: Some(()), .. }) => { (PackageMalleability::Malleable, false) },
+                       PackageSolvingData::RevokedOutput(RevokedOutput { is_counterparty_balance_on_anchors: None, .. }) => { (PackageMalleability::Malleable, true) },
+                       PackageSolvingData::RevokedHTLCOutput(..) => { (PackageMalleability::Malleable, true) },
+                       PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { (PackageMalleability::Malleable, true) },
+                       PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { (PackageMalleability::Malleable, false) },
+                       PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.opt_anchors() {
+                               (PackageMalleability::Malleable, outp.preimage.is_some())
+                       } else {
+                               (PackageMalleability::Untractable, false)
+                       },
+                       PackageSolvingData::HolderFundingOutput(..) => { (PackageMalleability::Untractable, false) },
+               };
+               (malleability, aggregable)
+       }
 }
 
 impl_writeable_tlv_based_enum!(PackageSolvingData, ;
@@ -491,8 +512,7 @@ impl_writeable_tlv_based_enum!(PackageSolvingData, ;
 );
 
 /// A malleable package might be aggregated with other packages to save on fees.
-/// A untractable package has been counter-signed and aggregable will break cached counterparty
-/// signatures.
+/// A untractable package has been counter-signed and aggregable will break cached counterparty signatures.
 #[derive(Clone, PartialEq, Eq)]
 pub(crate) enum PackageMalleability {
        Malleable,
@@ -826,19 +846,8 @@ impl PackageTemplate {
                }).is_some()
        }
 
-       pub (crate) fn build_package(txid: Txid, vout: u32, input_solving_data: PackageSolvingData, soonest_conf_deadline: u32, aggregable: bool, height_original: u32) -> Self {
-               let malleability = match input_solving_data {
-                       PackageSolvingData::RevokedOutput(..) => PackageMalleability::Malleable,
-                       PackageSolvingData::RevokedHTLCOutput(..) => PackageMalleability::Malleable,
-                       PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => PackageMalleability::Malleable,
-                       PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => PackageMalleability::Malleable,
-                       PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.opt_anchors() {
-                               PackageMalleability::Malleable
-                       } else {
-                               PackageMalleability::Untractable
-                       },
-                       PackageSolvingData::HolderFundingOutput(..) => PackageMalleability::Untractable,
-               };
+       pub (crate) fn build_package(txid: Txid, vout: u32, input_solving_data: PackageSolvingData, soonest_conf_deadline: u32, height_original: u32) -> Self {
+               let (malleability, aggregable) = PackageSolvingData::map_output_type_flags(&input_solving_data);
                let mut inputs = Vec::with_capacity(1);
                inputs.push((BitcoinOutPoint { txid, vout }, input_solving_data));
                PackageTemplate {
@@ -880,18 +889,7 @@ impl Readable for PackageTemplate {
                        inputs.push((outpoint, rev_outp));
                }
                let (malleability, aggregable) = if let Some((_, lead_input)) = inputs.first() {
-                       match lead_input {
-                               PackageSolvingData::RevokedOutput(..) => { (PackageMalleability::Malleable, true) },
-                               PackageSolvingData::RevokedHTLCOutput(..) => { (PackageMalleability::Malleable, true) },
-                               PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { (PackageMalleability::Malleable, true) },
-                               PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { (PackageMalleability::Malleable, false) },
-                               PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.opt_anchors() {
-                                       (PackageMalleability::Malleable, outp.preimage.is_some())
-                               } else {
-                                       (PackageMalleability::Untractable, false)
-                               },
-                               PackageSolvingData::HolderFundingOutput(..) => { (PackageMalleability::Untractable, false) },
-                       }
+                       PackageSolvingData::map_output_type_flags(&lead_input)
                } else { return Err(DecodeError::InvalidValue); };
                let mut soonest_conf_deadline = 0;
                let mut feerate_previous = 0;
@@ -1029,11 +1027,11 @@ mod tests {
        use bitcoin::secp256k1::Secp256k1;
 
        macro_rules! dumb_revk_output {
-               ($secp_ctx: expr) => {
+               ($secp_ctx: expr, $is_counterparty_balance_on_anchors: expr) => {
                        {
                                let dumb_scalar = SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap();
                                let dumb_point = PublicKey::from_secret_key(&$secp_ctx, &dumb_scalar);
-                               PackageSolvingData::RevokedOutput(RevokedOutput::build(dumb_point, dumb_point, dumb_point, dumb_scalar, 0, 0))
+                               PackageSolvingData::RevokedOutput(RevokedOutput::build(dumb_point, dumb_point, dumb_point, dumb_scalar, 0, 0, $is_counterparty_balance_on_anchors))
                        }
                }
        }
@@ -1077,10 +1075,10 @@ mod tests {
        fn test_package_differing_heights() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let revk_outp = dumb_revk_output!(secp_ctx);
+               let revk_outp = dumb_revk_output!(secp_ctx, false);
 
-               let mut package_one_hundred = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100);
-               let package_two_hundred = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 200);
+               let mut package_one_hundred = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, 100);
+               let package_two_hundred = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, 200);
                package_one_hundred.merge_package(package_two_hundred);
        }
 
@@ -1089,11 +1087,11 @@ mod tests {
        fn test_package_untractable_merge_to() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let revk_outp = dumb_revk_output!(secp_ctx);
+               let revk_outp = dumb_revk_output!(secp_ctx, false);
                let htlc_outp = dumb_htlc_output!();
 
-               let mut untractable_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100);
-               let malleable_package = PackageTemplate::build_package(txid, 1, htlc_outp.clone(), 1000, true, 100);
+               let mut untractable_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, 100);
+               let malleable_package = PackageTemplate::build_package(txid, 1, htlc_outp.clone(), 1000, 100);
                untractable_package.merge_package(malleable_package);
        }
 
@@ -1103,10 +1101,10 @@ mod tests {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
                let htlc_outp = dumb_htlc_output!();
-               let revk_outp = dumb_revk_output!(secp_ctx);
+               let revk_outp = dumb_revk_output!(secp_ctx, false);
 
-               let mut malleable_package = PackageTemplate::build_package(txid, 0, htlc_outp.clone(), 1000, true, 100);
-               let untractable_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100);
+               let mut malleable_package = PackageTemplate::build_package(txid, 0, htlc_outp.clone(), 1000, 100);
+               let untractable_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, 100);
                malleable_package.merge_package(untractable_package);
        }
 
@@ -1115,10 +1113,11 @@ mod tests {
        fn test_package_noaggregation_to() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let revk_outp = dumb_revk_output!(secp_ctx);
+               let revk_outp = dumb_revk_output!(secp_ctx, false);
+               let revk_outp_counterparty_balance = dumb_revk_output!(secp_ctx, true);
 
-               let mut noaggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, false, 100);
-               let aggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100);
+               let mut noaggregation_package = PackageTemplate::build_package(txid, 0, revk_outp_counterparty_balance.clone(), 1000, 100);
+               let aggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, 100);
                noaggregation_package.merge_package(aggregation_package);
        }
 
@@ -1127,10 +1126,11 @@ mod tests {
        fn test_package_noaggregation_from() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let revk_outp = dumb_revk_output!(secp_ctx);
+               let revk_outp = dumb_revk_output!(secp_ctx, false);
+               let revk_outp_counterparty_balance = dumb_revk_output!(secp_ctx, true);
 
-               let mut aggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100);
-               let noaggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, false, 100);
+               let mut aggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, 100);
+               let noaggregation_package = PackageTemplate::build_package(txid, 1, revk_outp_counterparty_balance.clone(), 1000, 100);
                aggregation_package.merge_package(noaggregation_package);
        }
 
@@ -1139,11 +1139,11 @@ mod tests {
        fn test_package_empty() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let revk_outp = dumb_revk_output!(secp_ctx);
+               let revk_outp = dumb_revk_output!(secp_ctx, false);
 
-               let mut empty_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, true, 100);
+               let mut empty_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000, 100);
                empty_package.inputs = vec![];
-               let package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, true, 100);
+               let package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000, 100);
                empty_package.merge_package(package);
        }
 
@@ -1152,11 +1152,11 @@ mod tests {
        fn test_package_differing_categories() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let revk_outp = dumb_revk_output!(secp_ctx);
+               let revk_outp = dumb_revk_output!(secp_ctx, false);
                let counterparty_outp = dumb_counterparty_output!(secp_ctx, 0, false);
 
-               let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, true, 100);
-               let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000, true, 100);
+               let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, 100);
+               let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000, 100);
                revoked_package.merge_package(counterparty_package);
        }
 
@@ -1164,13 +1164,13 @@ mod tests {
        fn test_package_split_malleable() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let revk_outp_one = dumb_revk_output!(secp_ctx);
-               let revk_outp_two = dumb_revk_output!(secp_ctx);
-               let revk_outp_three = dumb_revk_output!(secp_ctx);
+               let revk_outp_one = dumb_revk_output!(secp_ctx, false);
+               let revk_outp_two = dumb_revk_output!(secp_ctx, false);
+               let revk_outp_three = dumb_revk_output!(secp_ctx, false);
 
-               let mut package_one = PackageTemplate::build_package(txid, 0, revk_outp_one, 1000, true, 100);
-               let package_two = PackageTemplate::build_package(txid, 1, revk_outp_two, 1000, true, 100);
-               let package_three = PackageTemplate::build_package(txid, 2, revk_outp_three, 1000, true, 100);
+               let mut package_one = PackageTemplate::build_package(txid, 0, revk_outp_one, 1000, 100);
+               let package_two = PackageTemplate::build_package(txid, 1, revk_outp_two, 1000, 100);
+               let package_three = PackageTemplate::build_package(txid, 2, revk_outp_three, 1000, 100);
 
                package_one.merge_package(package_two);
                package_one.merge_package(package_three);
@@ -1193,7 +1193,7 @@ mod tests {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let htlc_outp_one = dumb_htlc_output!();
 
-               let mut package_one = PackageTemplate::build_package(txid, 0, htlc_outp_one, 1000, true, 100);
+               let mut package_one = PackageTemplate::build_package(txid, 0, htlc_outp_one, 1000, 100);
                let ret_split = package_one.split_package(&BitcoinOutPoint { txid, vout: 0});
                assert!(ret_split.is_none());
        }
@@ -1202,9 +1202,9 @@ mod tests {
        fn test_package_timer() {
                let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
                let secp_ctx = Secp256k1::new();
-               let revk_outp = dumb_revk_output!(secp_ctx);
+               let revk_outp = dumb_revk_output!(secp_ctx, false);
 
-               let mut package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, true, 100);
+               let mut package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, 100);
                assert_eq!(package.timer(), 100);
                package.set_timer(101);
                assert_eq!(package.timer(), 101);
@@ -1216,7 +1216,7 @@ mod tests {
                let secp_ctx = Secp256k1::new();
                let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, false);
 
-               let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100);
+               let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100);
                assert_eq!(package.package_amount(), 1000);
        }
 
@@ -1229,15 +1229,15 @@ mod tests {
                let weight_sans_output = (4 + 4 + 1 + 36 + 4 + 1 + 1 + 8 + 1) * WITNESS_SCALE_FACTOR + 2;
 
                {
-                       let revk_outp = dumb_revk_output!(secp_ctx);
-                       let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, true, 100);
+                       let revk_outp = dumb_revk_output!(secp_ctx, false);
+                       let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, 100);
                        assert_eq!(package.package_weight(&Script::new()),  weight_sans_output + WEIGHT_REVOKED_OUTPUT as usize);
                }
 
                {
                        for &opt_anchors in [false, true].iter() {
                                let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, opt_anchors);
-                               let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100);
+                               let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100);
                                assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_received_htlc(opt_anchors) as usize);
                        }
                }
@@ -1245,7 +1245,7 @@ mod tests {
                {
                        for &opt_anchors in [false, true].iter() {
                                let counterparty_outp = dumb_counterparty_offered_output!(secp_ctx, 1_000_000, opt_anchors);
-                               let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100);
+                               let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100);
                                assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_offered_htlc(opt_anchors) as usize);
                        }
                }
index e7e7e0ede6bb137a802cfdd016bf86c0fa4df5f2..cea15b21ad2fba1b6f1937b030d59551bede682c 100644 (file)
@@ -54,9 +54,6 @@
 
 #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
 
-#![cfg_attr(all(any(test, feature = "_test_utils"), feature = "_bench_unstable"), feature(test))]
-#[cfg(all(any(test, feature = "_test_utils"), feature = "_bench_unstable"))] extern crate test;
-
 #[cfg(not(any(feature = "std", feature = "no-std")))]
 compile_error!("at least one of the `std` or `no-std` features must be enabled");
 
@@ -74,6 +71,8 @@ extern crate core;
 
 #[cfg(not(feature = "std"))] extern crate core2;
 
+#[cfg(ldk_bench)] extern crate criterion;
+
 #[macro_use]
 pub mod util;
 pub mod chain;
@@ -177,7 +176,7 @@ mod prelude {
        pub use alloc::string::ToString;
 }
 
-#[cfg(all(not(feature = "_bench_unstable"), feature = "backtrace", feature = "std", test))]
+#[cfg(all(not(ldk_bench), feature = "backtrace", feature = "std", test))]
 extern crate backtrace;
 
 mod sync;
index d495910eed10242917f0c7ad713896fe7a5eaa02..e59cf47f17600963c9852389fc5723d8189816ef 100644 (file)
@@ -12,7 +12,6 @@
 //! There are a bunch of these as their handling is relatively error-prone so they are split out
 //! here. See also the chanmon_fail_consistency fuzz test.
 
-use bitcoin::blockdata::block::{Block, BlockHeader};
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::hash_types::BlockHash;
 use bitcoin::network::constants::Network;
@@ -35,7 +34,6 @@ use crate::util::test_utils;
 
 use crate::io;
 use bitcoin::hashes::Hash;
-use bitcoin::TxMerkleNode;
 use crate::prelude::*;
 use crate::sync::{Arc, Mutex};
 
@@ -121,15 +119,7 @@ fn test_monitor_and_persister_update_fail() {
                assert_eq!(chain_mon.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed);
                chain_mon
        };
-       let header = BlockHeader {
-               version: 0x20000000,
-               prev_blockhash: BlockHash::all_zeros(),
-               merkle_root: TxMerkleNode::all_zeros(),
-               time: 42,
-               bits: 42,
-               nonce: 42
-       };
-       chain_mon.chain_monitor.block_connected(&Block { header, txdata: vec![] }, 200);
+       chain_mon.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, Vec::new()), 200);
 
        // Set the persister's return value to be a InProgress.
        persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
index d6cd6e24cadfeada3bf918a4ee949a1501fe33f3..30eab9066fd0b4190ef65167d8e82c98c51c9be1 100644 (file)
@@ -46,7 +46,7 @@ use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, No
 use crate::ln::features::InvoiceFeatures;
 use crate::routing::gossip::NetworkGraph;
 use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteHop, RouteParameters, Router};
-use crate::routing::scoring::ProbabilisticScorer;
+use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
 use crate::ln::msgs;
 use crate::ln::onion_utils;
 use crate::ln::onion_utils::HTLCFailReason;
@@ -501,9 +501,11 @@ struct ClaimablePayments {
 /// for some reason. They are handled in timer_tick_occurred, so may be processed with
 /// quite some time lag.
 enum BackgroundEvent {
-       /// Handle a ChannelMonitorUpdate that closes a channel, broadcasting its current latest holder
-       /// commitment transaction.
-       ClosingMonitorUpdate((OutPoint, ChannelMonitorUpdate)),
+       /// Handle a ChannelMonitorUpdate
+       ///
+       /// Note that any such events are lost on shutdown, so in general they must be updates which
+       /// are regenerated on startup.
+       MonitorUpdateRegeneratedOnStartup((OutPoint, ChannelMonitorUpdate)),
 }
 
 #[derive(Debug)]
@@ -623,7 +625,9 @@ pub type SimpleArcChannelManager<M, T, F, L> = ChannelManager<
        Arc<DefaultRouter<
                Arc<NetworkGraph<Arc<L>>>,
                Arc<L>,
-               Arc<Mutex<ProbabilisticScorer<Arc<NetworkGraph<Arc<L>>>, Arc<L>>>>
+               Arc<Mutex<ProbabilisticScorer<Arc<NetworkGraph<Arc<L>>>, Arc<L>>>>,
+               ProbabilisticScoringFeeParameters,
+               ProbabilisticScorer<Arc<NetworkGraph<Arc<L>>>, Arc<L>>,
        >>,
        Arc<L>
 >;
@@ -639,7 +643,7 @@ pub type SimpleArcChannelManager<M, T, F, L> = ChannelManager<
 /// of [`KeysManager`] and [`DefaultRouter`].
 ///
 /// This is not exported to bindings users as Arcs don't make sense in bindings
-pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L> = ChannelManager<&'a M, &'b T, &'c KeysManager, &'c KeysManager, &'c KeysManager, &'d F, &'e DefaultRouter<&'f NetworkGraph<&'g L>, &'g L, &'h Mutex<ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>>, &'g L>;
+pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L> = ChannelManager<&'a M, &'b T, &'c KeysManager, &'c KeysManager, &'c KeysManager, &'d F, &'e DefaultRouter<&'f NetworkGraph<&'g L>, &'g L, &'h Mutex<ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>, ProbabilisticScoringFeeParameters, ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>, &'g L>;
 
 /// A trivial trait which describes any [`ChannelManager`] used in testing.
 #[cfg(any(test, feature = "_test_utils"))]
@@ -2728,10 +2732,9 @@ where
                let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
                        .map_err(|_| APIError::InvalidRoute{err: "Pubkey along hop was maliciously selected".to_owned()})?;
                let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, recipient_onion, cur_height, keysend_preimage)?;
-               if onion_utils::route_size_insane(&onion_payloads) {
-                       return Err(APIError::InvalidRoute{err: "Route size too large considering onion data".to_owned()});
-               }
-               let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash);
+
+               let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash)
+                       .map_err(|_| APIError::InvalidRoute { err: "Route size too large considering onion data".to_owned()})?;
 
                let err: Result<(), _> = loop {
                        let (counterparty_node_id, id) = match self.short_to_chan_info.read().unwrap().get(&path.hops.first().unwrap().short_channel_id) {
@@ -3090,6 +3093,12 @@ where
                        }
                }
                self.funding_transaction_generated_intern(temporary_channel_id, counterparty_node_id, funding_transaction, |chan, tx| {
+                       if tx.output.len() > u16::max_value() as usize {
+                               return Err(APIError::APIMisuseError {
+                                       err: "Transaction had more than 2^16 outputs, which is not supported".to_owned()
+                               });
+                       }
+
                        let mut output_index = None;
                        let expected_spk = chan.get_funding_redeemscript().to_v0_p2wsh();
                        for (idx, outp) in tx.output.iter().enumerate() {
@@ -3099,11 +3108,6 @@ where
                                                        err: "Multiple outputs matched the expected script and value".to_owned()
                                                });
                                        }
-                                       if idx > u16::max_value() as usize {
-                                               return Err(APIError::APIMisuseError {
-                                                       err: "Transaction had more than 2^16 outputs, which is not supported".to_owned()
-                                               });
-                                       }
                                        output_index = Some(idx as u16);
                                }
                        }
@@ -3773,7 +3777,7 @@ where
 
                for event in background_events.drain(..) {
                        match event {
-                               BackgroundEvent::ClosingMonitorUpdate((funding_txo, update)) => {
+                               BackgroundEvent::MonitorUpdateRegeneratedOnStartup((funding_txo, update)) => {
                                        // The channel has already been closed, so no use bothering to care about the
                                        // monitor updating completing.
                                        let _ = self.chain_monitor.update_channel(funding_txo, &update);
@@ -4513,7 +4517,7 @@ where
 
                if let Some(tx) = funding_broadcastable {
                        log_info!(self.logger, "Broadcasting funding transaction with txid {}", tx.txid());
-                       self.tx_broadcaster.broadcast_transaction(&tx);
+                       self.tx_broadcaster.broadcast_transactions(&[&tx]);
                }
 
                {
@@ -5043,7 +5047,7 @@ where
                };
                if let Some(broadcast_tx) = tx {
                        log_info!(self.logger, "Broadcasting {}", log_tx!(broadcast_tx));
-                       self.tx_broadcaster.broadcast_transaction(&broadcast_tx);
+                       self.tx_broadcaster.broadcast_transactions(&[&broadcast_tx]);
                }
                if let Some(chan) = chan_option {
                        if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
@@ -5653,7 +5657,7 @@ where
                                                                self.issue_channel_close_events(chan, ClosureReason::CooperativeClosure);
 
                                                                log_info!(self.logger, "Broadcasting {}", log_tx!(tx));
-                                                               self.tx_broadcaster.broadcast_transaction(&tx);
+                                                               self.tx_broadcaster.broadcast_transactions(&[&tx]);
                                                                update_maps_on_chan_removal!(self, chan);
                                                                false
                                                        } else { true }
@@ -5693,7 +5697,7 @@ where
                                if let ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } = update.updates[0] {
                                        assert!(should_broadcast);
                                } else { unreachable!(); }
-                               self.pending_background_events.lock().unwrap().push(BackgroundEvent::ClosingMonitorUpdate((funding_txo, update)));
+                               self.pending_background_events.lock().unwrap().push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup((funding_txo, update)));
                        }
                        self.finish_force_close_channel(failure);
                }
@@ -7447,17 +7451,12 @@ where
                        }
                }
 
-               let background_events = self.pending_background_events.lock().unwrap();
-               (background_events.len() as u64).write(writer)?;
-               for event in background_events.iter() {
-                       match event {
-                               BackgroundEvent::ClosingMonitorUpdate((funding_txo, monitor_update)) => {
-                                       0u8.write(writer)?;
-                                       funding_txo.write(writer)?;
-                                       monitor_update.write(writer)?;
-                               },
-                       }
-               }
+               // LDK versions prior to 0.0.116 wrote the `pending_background_events`
+               // `MonitorUpdateRegeneratedOnStartup`s here, however there was never a reason to do so -
+               // the closing monitor updates were always effectively replayed on startup (either directly
+               // by calling `broadcast_latest_holder_commitment_txn` on a `ChannelMonitor` during
+               // deserialization or, in 0.0.115, by regenerating the monitor update itself).
+               0u64.write(writer)?;
 
                // Prior to 0.0.111 we tracked node_announcement serials here, however that now happens in
                // `PeerManager`, and thus we simply write the `highest_seen_timestamp` twice, which is
@@ -7772,7 +7771,7 @@ where
                                                log_bytes!(channel.channel_id()), monitor.get_latest_update_id(), channel.get_latest_monitor_update_id());
                                        let (monitor_update, mut new_failed_htlcs) = channel.force_shutdown(true);
                                        if let Some(monitor_update) = monitor_update {
-                                               pending_background_events.push(BackgroundEvent::ClosingMonitorUpdate(monitor_update));
+                                               pending_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup(monitor_update));
                                        }
                                        failed_htlcs.append(&mut new_failed_htlcs);
                                        channel_closures.push_back((events::Event::ChannelClosed {
@@ -7847,7 +7846,7 @@ where
                                        update_id: CLOSED_CHANNEL_UPDATE_ID,
                                        updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast: true }],
                                };
-                               pending_background_events.push(BackgroundEvent::ClosingMonitorUpdate((*funding_txo, monitor_update)));
+                               pending_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup((*funding_txo, monitor_update)));
                        }
                }
 
@@ -7904,13 +7903,11 @@ where
                for _ in 0..background_event_count {
                        match <u8 as Readable>::read(reader)? {
                                0 => {
-                                       let (funding_txo, monitor_update): (OutPoint, ChannelMonitorUpdate) = (Readable::read(reader)?, Readable::read(reader)?);
-                                       if pending_background_events.iter().find(|e| {
-                                               let BackgroundEvent::ClosingMonitorUpdate((pending_funding_txo, pending_monitor_update)) = e;
-                                               *pending_funding_txo == funding_txo && *pending_monitor_update == monitor_update
-                                       }).is_none() {
-                                               pending_background_events.push(BackgroundEvent::ClosingMonitorUpdate((funding_txo, monitor_update)));
-                                       }
+                                       // LDK versions prior to 0.0.116 wrote pending `MonitorUpdateRegeneratedOnStartup`s here,
+                                       // however we really don't (and never did) need them - we regenerate all
+                                       // on-startup monitor updates.
+                                       let _: OutPoint = Readable::read(reader)?;
+                                       let _: ChannelMonitorUpdate = Readable::read(reader)?;
                                }
                                _ => return Err(DecodeError::InvalidValue),
                        }
@@ -8588,7 +8585,7 @@ mod tests {
                };
                let route = find_route(
                        &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph,
-                       None, nodes[0].logger, &scorer, &random_seed_bytes
+                       None, nodes[0].logger, &scorer, &(), &random_seed_bytes
                ).unwrap();
                nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage),
                        RecipientOnionFields::spontaneous_empty(), PaymentId(payment_preimage.0)).unwrap();
@@ -8622,7 +8619,7 @@ mod tests {
                let payment_preimage = PaymentPreimage([42; 32]);
                let route = find_route(
                        &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph,
-                       None, nodes[0].logger, &scorer, &random_seed_bytes
+                       None, nodes[0].logger, &scorer, &(), &random_seed_bytes
                ).unwrap();
                let payment_hash = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage),
                        RecipientOnionFields::spontaneous_empty(), PaymentId(payment_preimage.0)).unwrap();
@@ -8685,7 +8682,7 @@ mod tests {
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
                        &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
-                       nodes[0].logger, &scorer, &random_seed_bytes
+                       nodes[0].logger, &scorer, &(), &random_seed_bytes
                ).unwrap();
 
                let test_preimage = PaymentPreimage([42; 32]);
@@ -8729,7 +8726,7 @@ mod tests {
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
                        &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
-                       nodes[0].logger, &scorer, &random_seed_bytes
+                       nodes[0].logger, &scorer, &(), &random_seed_bytes
                ).unwrap();
 
                let test_preimage = PaymentPreimage([42; 32]);
@@ -9269,7 +9266,7 @@ mod tests {
        }
 }
 
-#[cfg(all(any(test, feature = "_test_utils"), feature = "_bench_unstable"))]
+#[cfg(ldk_bench)]
 pub mod bench {
        use crate::chain::Listen;
        use crate::chain::chainmonitor::{ChainMonitor, Persist};
@@ -9289,7 +9286,7 @@ pub mod bench {
 
        use crate::sync::{Arc, Mutex};
 
-       use test::Bencher;
+       use criterion::Criterion;
 
        type Manager<'a, P> = ChannelManager<
                &'a ChainMonitor<InMemorySigner, &'a test_utils::TestChainSource,
@@ -9310,13 +9307,11 @@ pub mod bench {
                fn chain_monitor(&self) -> Option<&test_utils::TestChainMonitor> { None }
        }
 
-       #[cfg(test)]
-       #[bench]
-       fn bench_sends(bench: &mut Bencher) {
-               bench_two_sends(bench, test_utils::TestPersister::new(), test_utils::TestPersister::new());
+       pub fn bench_sends(bench: &mut Criterion) {
+               bench_two_sends(bench, "bench_sends", test_utils::TestPersister::new(), test_utils::TestPersister::new());
        }
 
-       pub fn bench_two_sends<P: Persist<InMemorySigner>>(bench: &mut Bencher, persister_a: P, persister_b: P) {
+       pub fn bench_two_sends<P: Persist<InMemorySigner>>(bench: &mut Criterion, bench_name: &str, persister_a: P, persister_b: P) {
                // Do a simple benchmark of sending a payment back and forth between two nodes.
                // Note that this is unrealistic as each payment send will require at least two fsync
                // calls per node.
@@ -9386,10 +9381,7 @@ pub mod bench {
 
                assert_eq!(&tx_broadcaster.txn_broadcasted.lock().unwrap()[..], &[tx.clone()]);
 
-               let block = Block {
-                       header: BlockHeader { version: 0x20000000, prev_blockhash: BestBlock::from_network(network).block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
-                       txdata: vec![tx],
-               };
+               let block = create_dummy_block(BestBlock::from_network(network).block_hash(), 42, vec![tx]);
                Listen::block_connected(&node_a, &block, 1);
                Listen::block_connected(&node_b, &block, 1);
 
@@ -9472,9 +9464,9 @@ pub mod bench {
                        }
                }
 
-               bench.iter(|| {
+               bench.bench_function(bench_name, |b| b.iter(|| {
                        send_payment!(node_a, node_b);
                        send_payment!(node_b, node_a);
-               });
+               }));
        }
 }
index ca8150b09cfa580d69e55550cc6661b3068ea15c..b8087546c7445060230a5ad776a9b3f13c113d37 100644 (file)
@@ -422,8 +422,10 @@ pub struct Features<T: sealed::Context> {
        mark: PhantomData<T>,
 }
 
-impl <T: sealed::Context> Features<T> {
-       pub(crate) fn or(mut self, o: Self) -> Self {
+impl<T: sealed::Context> core::ops::BitOr for Features<T> {
+       type Output = Self;
+
+       fn bitor(mut self, o: Self) -> Self {
                let total_feature_len = cmp::max(self.flags.len(), o.flags.len());
                self.flags.resize(total_feature_len, 0u8);
                for (byte, o_byte) in self.flags.iter_mut().zip(o.flags.iter()) {
@@ -451,6 +453,16 @@ impl<T: sealed::Context> PartialEq for Features<T> {
                self.flags.eq(&o.flags)
        }
 }
+impl<T: sealed::Context> PartialOrd for Features<T> {
+       fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+               self.flags.partial_cmp(&other.flags)
+       }
+}
+impl<T: sealed::Context + Eq> Ord for Features<T> {
+       fn cmp(&self, other: &Self) -> cmp::Ordering {
+               self.flags.cmp(&other.flags)
+       }
+}
 impl<T: sealed::Context> fmt::Debug for Features<T> {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                self.flags.fmt(fmt)
@@ -685,6 +697,25 @@ impl<T: sealed::Context> Features<T> {
                self.flags.iter().any(|&byte| (byte & 0b10_10_10_10) != 0)
        }
 
+       /// Returns true if this `Features` object contains required features unknown by `other`.
+       pub fn requires_unknown_bits_from(&self, other: &Features<T>) -> bool {
+               // Bitwise AND-ing with all even bits set except for known features will select required
+               // unknown features.
+               self.flags.iter().enumerate().any(|(i, &byte)| {
+                       const REQUIRED_FEATURES: u8 = 0b01_01_01_01;
+                       const OPTIONAL_FEATURES: u8 = 0b10_10_10_10;
+                       let unknown_features = if i < other.flags.len() {
+                               // Form a mask similar to !T::KNOWN_FEATURE_MASK only for `other`
+                               !(other.flags[i]
+                                       | ((other.flags[i] >> 1) & REQUIRED_FEATURES)
+                                       | ((other.flags[i] << 1) & OPTIONAL_FEATURES))
+                       } else {
+                               0b11_11_11_11
+                       };
+                       (byte & (REQUIRED_FEATURES & unknown_features)) != 0
+               })
+       }
+
        /// Returns true if this `Features` object contains unknown feature flags which are set as
        /// "required".
        pub fn requires_unknown_bits(&self) -> bool {
@@ -733,6 +764,50 @@ impl<T: sealed::Context> Features<T> {
                }
                true
        }
+
+       /// Sets a required custom feature bit. Errors if `bit` is outside the custom range as defined
+       /// by [bLIP 2] or if it is a known `T` feature.
+       ///
+       /// Note: Required bits are even. If an odd bit is given, then the corresponding even bit will
+       /// be set instead (i.e., `bit - 1`).
+       ///
+       /// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits
+       pub fn set_required_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
+               self.set_custom_bit(bit - (bit % 2))
+       }
+
+       /// Sets an optional custom feature bit. Errors if `bit` is outside the custom range as defined
+       /// by [bLIP 2] or if it is a known `T` feature.
+       ///
+       /// Note: Optional bits are odd. If an even bit is given, then the corresponding odd bit will be
+       /// set instead (i.e., `bit + 1`).
+       ///
+       /// [bLIP 2]: https://github.com/lightning/blips/blob/master/blip-0002.md#feature-bits
+       pub fn set_optional_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
+               self.set_custom_bit(bit + (1 - (bit % 2)))
+       }
+
+       fn set_custom_bit(&mut self, bit: usize) -> Result<(), ()> {
+               if bit < 256 {
+                       return Err(());
+               }
+
+               let byte_offset = bit / 8;
+               let mask = 1 << (bit - 8 * byte_offset);
+               if byte_offset < T::KNOWN_FEATURE_MASK.len() {
+                       if (T::KNOWN_FEATURE_MASK[byte_offset] & mask) != 0 {
+                               return Err(());
+                       }
+               }
+
+               if self.flags.len() <= byte_offset {
+                       self.flags.resize(byte_offset + 1, 0u8);
+               }
+
+               self.flags[byte_offset] |= mask;
+
+               Ok(())
+       }
 }
 
 impl<T: sealed::UpfrontShutdownScript> Features<T> {
@@ -859,6 +934,43 @@ mod tests {
                assert!(features.supports_unknown_bits());
        }
 
+       #[test]
+       fn requires_unknown_bits_from() {
+               let mut features1 = InitFeatures::empty();
+               let mut features2 = InitFeatures::empty();
+               assert!(!features1.requires_unknown_bits_from(&features2));
+               assert!(!features2.requires_unknown_bits_from(&features1));
+
+               features1.set_data_loss_protect_required();
+               assert!(features1.requires_unknown_bits_from(&features2));
+               assert!(!features2.requires_unknown_bits_from(&features1));
+
+               features2.set_data_loss_protect_optional();
+               assert!(!features1.requires_unknown_bits_from(&features2));
+               assert!(!features2.requires_unknown_bits_from(&features1));
+
+               features2.set_gossip_queries_required();
+               assert!(!features1.requires_unknown_bits_from(&features2));
+               assert!(features2.requires_unknown_bits_from(&features1));
+
+               features1.set_gossip_queries_optional();
+               assert!(!features1.requires_unknown_bits_from(&features2));
+               assert!(!features2.requires_unknown_bits_from(&features1));
+
+               features1.set_variable_length_onion_required();
+               assert!(features1.requires_unknown_bits_from(&features2));
+               assert!(!features2.requires_unknown_bits_from(&features1));
+
+               features2.set_variable_length_onion_optional();
+               assert!(!features1.requires_unknown_bits_from(&features2));
+               assert!(!features2.requires_unknown_bits_from(&features1));
+
+               features1.set_basic_mpp_required();
+               features2.set_wumbo_required();
+               assert!(features1.requires_unknown_bits_from(&features2));
+               assert!(features2.requires_unknown_bits_from(&features1));
+       }
+
        #[test]
        fn convert_to_context_with_relevant_flags() {
                let mut init_features = InitFeatures::empty();
@@ -871,12 +983,12 @@ mod tests {
                init_features.set_payment_secret_required();
                init_features.set_basic_mpp_optional();
                init_features.set_wumbo_optional();
+               init_features.set_anchors_zero_fee_htlc_tx_optional();
                init_features.set_shutdown_any_segwit_optional();
                init_features.set_onion_messages_optional();
                init_features.set_channel_type_optional();
                init_features.set_scid_privacy_optional();
                init_features.set_zero_conf_optional();
-               init_features.set_anchors_zero_fee_htlc_tx_optional();
 
                assert!(init_features.initial_routing_sync());
                assert!(!init_features.supports_upfront_shutdown_script());
@@ -887,7 +999,7 @@ mod tests {
                        // Check that the flags are as expected:
                        // - option_data_loss_protect (req)
                        // - var_onion_optin (req) | static_remote_key (req) | payment_secret(req)
-                       // - basic_mpp | wumbo
+                       // - basic_mpp | wumbo | anchors_zero_fee_htlc_tx
                        // - opt_shutdown_anysegwit
                        // - onion_messages
                        // - option_channel_type | option_scid_alias
@@ -935,6 +1047,36 @@ mod tests {
                assert!(features.supports_payment_secret());
        }
 
+       #[test]
+       fn set_custom_bits() {
+               let mut features = InvoiceFeatures::empty();
+               features.set_variable_length_onion_optional();
+               assert_eq!(features.flags[1], 0b00000010);
+
+               assert!(features.set_optional_custom_bit(255).is_err());
+               assert!(features.set_required_custom_bit(256).is_ok());
+               assert!(features.set_required_custom_bit(258).is_ok());
+               assert_eq!(features.flags[31], 0b00000000);
+               assert_eq!(features.flags[32], 0b00000101);
+
+               let known_bit = <sealed::InvoiceContext as sealed::PaymentSecret>::EVEN_BIT;
+               let byte_offset = <sealed::InvoiceContext as sealed::PaymentSecret>::BYTE_OFFSET;
+               assert_eq!(byte_offset, 1);
+               assert_eq!(features.flags[byte_offset], 0b00000010);
+               assert!(features.set_required_custom_bit(known_bit).is_err());
+               assert_eq!(features.flags[byte_offset], 0b00000010);
+
+               let mut features = InvoiceFeatures::empty();
+               assert!(features.set_optional_custom_bit(256).is_ok());
+               assert!(features.set_optional_custom_bit(259).is_ok());
+               assert_eq!(features.flags[32], 0b00001010);
+
+               let mut features = InvoiceFeatures::empty();
+               assert!(features.set_required_custom_bit(257).is_ok());
+               assert!(features.set_required_custom_bit(258).is_ok());
+               assert_eq!(features.flags[32], 0b00000101);
+       }
+
        #[test]
        fn encodes_features_without_length() {
                let features = OfferFeatures::from_le_bytes(vec![1, 2, 3, 4, 5, 42, 100, 101]);
index 637c05ff2e447ce5202d59ad70a16dcdeb0a547b..93841517ba75ecfbc154382c2340d238cda93daf 100644 (file)
@@ -85,16 +85,14 @@ pub fn confirm_transactions_at<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, txn:
        if conf_height > first_connect_height {
                connect_blocks(node, conf_height - first_connect_height);
        }
-       let mut block = Block {
-               header: BlockHeader { version: 0x20000000, prev_blockhash: node.best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: conf_height, bits: 42, nonce: 42 },
-               txdata: Vec::new(),
-       };
+       let mut txdata = Vec::new();
        for _ in 0..*node.network_chan_count.borrow() { // Make sure we don't end up with channels at the same short id by offsetting by chan_count
-               block.txdata.push(Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() });
+               txdata.push(Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() });
        }
        for tx in txn {
-               block.txdata.push((*tx).clone());
+               txdata.push((*tx).clone());
        }
+       let block = create_dummy_block(node.best_block_hash(), conf_height, txdata);
        connect_block(node, &block);
        scid_utils::scid_from_parts(conf_height as u64, block.txdata.len() as u64 - 1, 0).unwrap()
 }
@@ -191,22 +189,31 @@ impl ConnectStyle {
        }
 }
 
+pub fn create_dummy_header(prev_blockhash: BlockHash, time: u32) -> BlockHeader {
+       BlockHeader {
+               version: 0x2000_0000,
+               prev_blockhash,
+               merkle_root: TxMerkleNode::all_zeros(),
+               time,
+               bits: 42,
+               nonce: 42,
+       }
+}
+
+pub fn create_dummy_block(prev_blockhash: BlockHash, time: u32, txdata: Vec<Transaction>) -> Block {
+       Block { header: create_dummy_header(prev_blockhash, time), txdata }
+}
+
 pub fn connect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, depth: u32) -> BlockHash {
        let skip_intermediaries = node.connect_style.borrow().skips_blocks();
 
        let height = node.best_block_info().1 + 1;
-       let mut block = Block {
-               header: BlockHeader { version: 0x2000000, prev_blockhash: node.best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: height, bits: 42, nonce: 42 },
-               txdata: vec![],
-       };
+       let mut block = create_dummy_block(node.best_block_hash(), height, Vec::new());
        assert!(depth >= 1);
        for i in 1..depth {
                let prev_blockhash = block.header.block_hash();
                do_connect_block(node, block, skip_intermediaries);
-               block = Block {
-                       header: BlockHeader { version: 0x20000000, prev_blockhash, merkle_root: TxMerkleNode::all_zeros(), time: height + i, bits: 42, nonce: 42 },
-                       txdata: vec![],
-               };
+               block = create_dummy_block(prev_blockhash, height + i, Vec::new());
        }
        let hash = block.header.block_hash();
        do_connect_block(node, block, false);
@@ -1738,7 +1745,7 @@ pub fn get_route(send_node: &Node, payment_params: &PaymentParameters, recv_valu
        router::get_route(
                &send_node.node.get_our_node_id(), payment_params, &send_node.network_graph.read_only(),
                Some(&send_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
-               recv_value, send_node.logger, &scorer, &random_seed_bytes
+               recv_value, send_node.logger, &scorer, &(), &random_seed_bytes
        )
 }
 
@@ -1769,7 +1776,7 @@ macro_rules! get_route_and_payment_hash {
 }
 
 #[macro_export]
-#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))]
+#[cfg(any(test, ldk_bench, feature = "_test_utils"))]
 macro_rules! expect_payment_claimable {
        ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr) => {
                expect_payment_claimable!($node, $expected_payment_hash, $expected_payment_secret, $expected_recv_value, None, $node.node.get_our_node_id())
@@ -1796,7 +1803,7 @@ macro_rules! expect_payment_claimable {
 }
 
 #[macro_export]
-#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))]
+#[cfg(any(test, ldk_bench, feature = "_test_utils"))]
 macro_rules! expect_payment_claimed {
        ($node: expr, $expected_payment_hash: expr, $expected_recv_value: expr) => {
                let events = $node.node.get_and_clear_pending_events();
@@ -1913,7 +1920,7 @@ macro_rules! expect_payment_forwarded {
        }
 }
 
-#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))]
+#[cfg(any(test, ldk_bench, feature = "_test_utils"))]
 pub fn expect_channel_pending_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) {
        let events = node.node.get_and_clear_pending_events();
        assert_eq!(events.len(), 1);
@@ -1925,7 +1932,7 @@ pub fn expect_channel_pending_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>,
        }
 }
 
-#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))]
+#[cfg(any(test, ldk_bench, feature = "_test_utils"))]
 pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) {
        let events = node.node.get_and_clear_pending_events();
        assert_eq!(events.len(), 1);
@@ -2328,7 +2335,7 @@ pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_rou
        let random_seed_bytes = keys_manager.get_secure_random_bytes();
        let route = router::get_route(
                &origin_node.node.get_our_node_id(), &payment_params, &network_graph,
-               None, recv_value, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
+               None, recv_value, origin_node.logger, &scorer, &(), &random_seed_bytes).unwrap();
        assert_eq!(route.paths.len(), 1);
        assert_eq!(route.paths[0].hops.len(), expected_route.len());
        for (node, hop) in expected_route.iter().zip(route.paths[0].hops.iter()) {
index bbff80b1f6267275c16acba2d7dd8f3091e53ee5..98fc4bd95b6d58f100ae09aaa32519e57237598c 100644 (file)
@@ -38,12 +38,11 @@ use crate::util::string::UntrustedString;
 use crate::util::config::UserConfig;
 
 use bitcoin::hash_types::BlockHash;
-use bitcoin::blockdata::block::{Block, BlockHeader};
 use bitcoin::blockdata::script::{Builder, Script};
 use bitcoin::blockdata::opcodes;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::network::constants::Network;
-use bitcoin::{PackedLockTime, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Witness};
+use bitcoin::{PackedLockTime, Sequence, Transaction, TxIn, TxOut, Witness};
 use bitcoin::OutPoint as BitcoinOutPoint;
 
 use bitcoin::secp256k1::Secp256k1;
@@ -509,10 +508,7 @@ fn do_test_sanity_on_in_flight_opens(steps: u8) {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        if steps & 0b1000_0000 != 0{
-               let block = Block {
-                       header: BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
-                       txdata: vec![],
-               };
+               let block = create_dummy_block(nodes[0].best_block_hash(), 42, Vec::new());
                connect_block(&nodes[0], &block);
                connect_block(&nodes[1], &block);
        }
@@ -1383,7 +1379,7 @@ fn test_fee_spike_violation_fails_htlc() {
        let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
        let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0],
                3460001, RecipientOnionFields::secret_only(payment_secret), cur_height, &None).unwrap();
-       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
+       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
        let msg = msgs::UpdateAddHTLC {
                channel_id: chan.2,
                htlc_id: 0,
@@ -1571,7 +1567,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
        let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
        let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0],
                700_000, RecipientOnionFields::secret_only(payment_secret), cur_height, &None).unwrap();
-       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
+       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
        let msg = msgs::UpdateAddHTLC {
                channel_id: chan.2,
                htlc_id: MIN_AFFORDABLE_HTLC_COUNT as u64,
@@ -1745,7 +1741,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
        let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap();
        let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(
                &route_2.paths[0], recv_value_2, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap();
-       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1);
+       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1).unwrap();
        let msg = msgs::UpdateAddHTLC {
                channel_id: chan.2,
                htlc_id: 1,
@@ -2763,8 +2759,7 @@ fn test_htlc_on_chain_success() {
        assert_eq!(node_txn[1].lock_time.0, 0);
 
        // Verify that B's ChannelManager is able to extract preimage from HTLC Success tx and pass it backward
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
-       connect_block(&nodes[1], &Block { header, txdata: vec![commitment_tx[0].clone(), node_txn[0].clone(), node_txn[1].clone()]});
+       connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![commitment_tx[0].clone(), node_txn[0].clone(), node_txn[1].clone()]));
        connect_blocks(&nodes[1], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
        {
                let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
@@ -2900,8 +2895,7 @@ fn test_htlc_on_chain_success() {
        // we already checked the same situation with A.
 
        // Verify that A's ChannelManager is able to extract preimage from preimage tx and generate PaymentSent
-       let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
-       connect_block(&nodes[0], &Block { header, txdata: vec![node_a_commitment_tx[0].clone(), commitment_spend.clone()] });
+       connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![node_a_commitment_tx[0].clone(), commitment_spend.clone()]));
        connect_blocks(&nodes[0], TEST_FINAL_CLTV + MIN_CLTV_EXPIRY_DELTA as u32); // Confirm blocks until the HTLC expires
        check_closed_broadcast!(nodes[0], true);
        check_added_monitors!(nodes[0], 1);
@@ -3398,7 +3392,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() {
                let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(
                        &route.paths[0], 50_000, RecipientOnionFields::secret_only(payment_secret), current_height, &None).unwrap();
                let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
-               let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
+               let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
 
                // Send a 0-msat update_add_htlc to fail the channel.
                let update_add_htlc = msgs::UpdateAddHTLC {
@@ -3463,15 +3457,15 @@ fn test_htlc_ignore_latest_remote_commitment() {
        assert_eq!(node_txn.len(), 3);
        assert_eq!(node_txn[0].txid(), node_txn[1].txid());
 
-       let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[1].clone()]});
+       let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[0].clone(), node_txn[1].clone()]);
+       connect_block(&nodes[1], &block);
        check_closed_broadcast!(nodes[1], true);
        check_added_monitors!(nodes[1], 1);
        check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
 
        // Duplicate the connect_block call since this may happen due to other listeners
        // registering new transactions
-       connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[0].clone(), node_txn[2].clone()]});
+       connect_block(&nodes[1], &block);
 }
 
 #[test]
@@ -4152,10 +4146,7 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) {
                route_payment(&nodes[0], &[&nodes[1]], 100000).1
        };
 
-       let mut block = Block {
-               header: BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
-               txdata: vec![],
-       };
+       let mut block = create_dummy_block(nodes[0].best_block_hash(), 42, Vec::new());
        connect_block(&nodes[0], &block);
        connect_block(&nodes[1], &block);
        let block_count = TEST_FINAL_CLTV + CHAN_CONFIRM_DEPTH + 2 - CLTV_CLAIM_BUFFER - LATENCY_GRACE_PERIOD_BLOCKS;
@@ -4263,7 +4254,7 @@ macro_rules! check_spendable_outputs {
                                match event {
                                        Event::SpendableOutputs { mut outputs } => {
                                                for outp in outputs.drain(..) {
-                                                       txn.push($keysinterface.backing.spend_spendable_outputs(&[&outp], Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &secp_ctx).unwrap());
+                                                       txn.push($keysinterface.backing.spend_spendable_outputs(&[&outp], Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &secp_ctx).unwrap());
                                                        all_outputs.push(outp);
                                                }
                                        },
@@ -4271,7 +4262,7 @@ macro_rules! check_spendable_outputs {
                                };
                        }
                        if all_outputs.len() > 1 {
-                               if let Ok(tx) = $keysinterface.backing.spend_spendable_outputs(&all_outputs.iter().map(|a| a).collect::<Vec<_>>(), Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &secp_ctx) {
+                               if let Ok(tx) = $keysinterface.backing.spend_spendable_outputs(&all_outputs.iter().map(|a| a).collect::<Vec<_>>(), Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &secp_ctx) {
                                        txn.push(tx);
                                }
                        }
@@ -4534,8 +4525,7 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() {
        assert_ne!(revoked_htlc_txn[0].lock_time.0, 0); // HTLC-Timeout
 
        // B will generate justice tx from A's revoked commitment/HTLC tx
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[1], &Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()] });
+       connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()]));
        check_closed_broadcast!(nodes[1], true);
        check_added_monitors!(nodes[1], 1);
        check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
@@ -4605,8 +4595,7 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() {
        assert_eq!(revoked_local_txn[0].output[unspent_local_txn_output].script_pubkey.len(), 2 + 20); // P2WPKH
 
        // A will generate justice tx from B's revoked commitment/HTLC tx
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()] });
+       connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()]));
        check_closed_broadcast!(nodes[0], true);
        check_added_monitors!(nodes[0], 1);
        check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
@@ -4699,8 +4688,7 @@ fn test_onchain_to_onchain_claim() {
        assert_eq!(c_txn[0].lock_time.0, 0); // Success tx
 
        // So we broadcast C's commitment tx and HTLC-Success on B's chain, we should successfully be able to extract preimage and update downstream monitor
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
-       connect_block(&nodes[1], &Block { header, txdata: vec![commitment_tx[0].clone(), c_txn[0].clone()]});
+       connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![commitment_tx[0].clone(), c_txn[0].clone()]));
        check_added_monitors!(nodes[1], 1);
        let events = nodes[1].node.get_and_clear_pending_events();
        assert_eq!(events.len(), 2);
@@ -5457,10 +5445,7 @@ fn do_htlc_claim_local_commitment_only(use_dust: bool) {
        check_added_monitors!(nodes[1], 1);
 
        let starting_block = nodes[1].best_block_info();
-       let mut block = Block {
-               header: BlockHeader { version: 0x20000000, prev_blockhash: starting_block.0, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
-               txdata: vec![],
-       };
+       let mut block = create_dummy_block(starting_block.0, 42, Vec::new());
        for _ in starting_block.1 + 1..TEST_FINAL_CLTV - CLTV_CLAIM_BUFFER + starting_block.1 + 2 {
                connect_block(&nodes[1], &block);
                block.header.prev_blockhash = block.block_hash();
@@ -5490,11 +5475,11 @@ fn do_htlc_claim_current_remote_commitment_only(use_dust: bool) {
        // to "time out" the HTLC.
 
        let starting_block = nodes[1].best_block_info();
-       let mut header = BlockHeader { version: 0x20000000, prev_blockhash: starting_block.0, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
+       let mut block = create_dummy_block(starting_block.0, 42, Vec::new());
 
        for _ in starting_block.1 + 1..TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + starting_block.1 + 2 {
-               connect_block(&nodes[0], &Block { header, txdata: Vec::new()});
-               header.prev_blockhash = header.block_hash();
+               connect_block(&nodes[0], &block);
+               block.header.prev_blockhash = block.block_hash();
        }
        test_txn_broadcast(&nodes[0], &chan, None, HTLCType::NONE);
        check_closed_broadcast!(nodes[0], true);
@@ -5536,10 +5521,7 @@ fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no
        }
 
        let starting_block = nodes[1].best_block_info();
-       let mut block = Block {
-               header: BlockHeader { version: 0x20000000, prev_blockhash: starting_block.0, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
-               txdata: vec![],
-       };
+       let mut block = create_dummy_block(starting_block.0, 42, Vec::new());
        for _ in starting_block.1 + 1..TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + CHAN_CONFIRM_DEPTH + 2 {
                connect_block(&nodes[0], &block);
                block.header.prev_blockhash = block.block_hash();
@@ -6267,7 +6249,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() {
        let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap();
        let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(
                &route.paths[0], 3999999, RecipientOnionFields::secret_only(our_payment_secret), cur_height, &None).unwrap();
-       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
+       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash).unwrap();
 
        let mut msg = msgs::UpdateAddHTLC {
                channel_id: chan.2,
@@ -7044,7 +7026,7 @@ fn test_check_htlc_underpaying() {
        let scorer = test_utils::TestScorer::new();
        let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
        let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV).with_bolt11_features(nodes[1].node.invoice_features()).unwrap();
-       let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None, 10_000, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
+       let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None, 10_000, nodes[0].logger, &scorer, &(), &random_seed_bytes).unwrap();
        let (_, our_payment_hash, _) = get_payment_preimage_hash!(nodes[0]);
        let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200, None).unwrap();
        nodes[0].node.send_payment_with_route(&route, our_payment_hash,
@@ -7212,8 +7194,7 @@ fn test_bump_penalty_txn_on_revoked_commitment() {
 
        // Actually revoke tx by claiming a HTLC
        claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage);
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: header_114, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[1], &Block { header, txdata: vec![revoked_txn[0].clone()] });
+       connect_block(&nodes[1], &create_dummy_block(header_114, 42, vec![revoked_txn[0].clone()]));
        check_added_monitors!(nodes[1], 1);
 
        // One or more justice tx should have been broadcast, check it
@@ -7298,11 +7279,11 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
        let scorer = test_utils::TestScorer::new();
        let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
        let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None,
-               3_000_000, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
+               3_000_000, nodes[0].logger, &scorer, &(), &random_seed_bytes).unwrap();
        let payment_preimage = send_along_route(&nodes[0], route, &[&nodes[1]], 3_000_000).0;
        let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id(), 50).with_bolt11_features(nodes[0].node.invoice_features()).unwrap();
        let route = get_route(&nodes[1].node.get_our_node_id(), &payment_params, &nodes[1].network_graph.read_only(), None,
-               3_000_000, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
+               3_000_000, nodes[0].logger, &scorer, &(), &random_seed_bytes).unwrap();
        send_along_route(&nodes[1], route, &[&nodes[0]], 3_000_000);
 
        let revoked_local_txn = get_local_commitment_txn!(nodes[1], chan.2);
@@ -7312,9 +7293,8 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
        // Revoke local commitment tx
        claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage);
 
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
        // B will generate both revoked HTLC-timeout/HTLC-preimage txn from revoked commitment tx
-       connect_block(&nodes[1], &Block { header, txdata: vec![revoked_local_txn[0].clone()] });
+       connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![revoked_local_txn[0].clone()]));
        check_closed_broadcast!(nodes[1], true);
        check_added_monitors!(nodes[1], 1);
        check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
@@ -7338,10 +7318,10 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
 
        // Broadcast set of revoked txn on A
        let hash_128 = connect_blocks(&nodes[0], 40);
-       let header_11 = BlockHeader { version: 0x20000000, prev_blockhash: hash_128, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header: header_11, txdata: vec![revoked_local_txn[0].clone()] });
-       let header_129 = BlockHeader { version: 0x20000000, prev_blockhash: header_11.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header: header_129, txdata: vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()] });
+       let block_11 = create_dummy_block(hash_128, 42, vec![revoked_local_txn[0].clone()]);
+       connect_block(&nodes[0], &block_11);
+       let block_129 = create_dummy_block(block_11.block_hash(), 42, vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()]);
+       connect_block(&nodes[0], &block_129);
        let events = nodes[0].node.get_and_clear_pending_events();
        expect_pending_htlcs_forwardable_from_events!(nodes[0], events[0..1], true);
        match events.last().unwrap() {
@@ -7392,10 +7372,10 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
        }
 
        // Connect one more block to see if bumped penalty are issued for HTLC txn
-       let header_130 = BlockHeader { version: 0x20000000, prev_blockhash: header_129.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header: header_130, txdata: penalty_txn });
-       let header_131 = BlockHeader { version: 0x20000000, prev_blockhash: header_130.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header: header_131, txdata: Vec::new() });
+       let block_130 = create_dummy_block(block_129.block_hash(), 42, penalty_txn);
+       connect_block(&nodes[0], &block_130);
+       let block_131 = create_dummy_block(block_130.block_hash(), 42, Vec::new());
+       connect_block(&nodes[0], &block_131);
 
        // Few more blocks to confirm penalty txn
        connect_blocks(&nodes[0], 4);
@@ -7417,8 +7397,7 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
                txn
        };
        // Broadcast claim txn and confirm blocks to avoid further bumps on this outputs
-       let header_145 = BlockHeader { version: 0x20000000, prev_blockhash: header_144, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header: header_145, txdata: node_txn });
+       connect_block(&nodes[0], &create_dummy_block(header_144, 42, node_txn));
        connect_blocks(&nodes[0], 20);
        {
                let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
@@ -7630,8 +7609,7 @@ fn test_bump_txn_sanitize_tracking_maps() {
                node_txn.clear();
                penalty_txn
        };
-       let header_130 = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header: header_130, txdata: penalty_txn });
+       connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, penalty_txn));
        connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
        {
                let monitor = nodes[0].chain_monitor.chain_monitor.get_monitor(OutPoint { txid: chan.3.txid(), index: 0 }).unwrap();
@@ -8087,7 +8065,7 @@ fn test_onion_value_mpp_set_calculation() {
                        // Edit amt_to_forward to simulate the sender having set
                        // the final amount and the routing node taking less fee
                        onion_payloads[1].amt_to_forward = 99_000;
-                       let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
+                       let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash).unwrap();
                        payment_event.msgs[0].onion_routing_packet = new_onion_packet;
                }
 
@@ -8275,14 +8253,7 @@ fn test_secret_timeout() {
        } else { panic!(); }
        let mut block = {
                let node_1_blocks = nodes[1].blocks.lock().unwrap();
-               Block {
-                       header: BlockHeader {
-                               version: 0x2000000,
-                               prev_blockhash: node_1_blocks.last().unwrap().0.block_hash(),
-                               merkle_root: TxMerkleNode::all_zeros(),
-                               time: node_1_blocks.len() as u32 + 7200, bits: 42, nonce: 42 },
-                       txdata: vec![],
-               }
+               create_dummy_block(node_1_blocks.last().unwrap().0.block_hash(), node_1_blocks.len() as u32 + 7200, Vec::new())
        };
        connect_block(&nodes[1], &block);
        if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash_legacy(payment_hash, Some(100_000), 2) {
@@ -8430,8 +8401,7 @@ fn test_update_err_monitor_lockdown() {
                assert_eq!(watchtower.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed);
                watchtower
        };
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       let block = Block { header, txdata: vec![] };
+       let block = create_dummy_block(BlockHash::all_zeros(), 42, Vec::new());
        // Make the tx_broadcaster aware of enough blocks that it doesn't think we're violating
        // transaction lock time requirements here.
        chanmon_cfgs[0].tx_broadcaster.blocks.lock().unwrap().resize(200, (block.clone(), 200));
@@ -8501,8 +8471,7 @@ fn test_concurrent_monitor_claim() {
                assert_eq!(watchtower.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed);
                watchtower
        };
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       let block = Block { header, txdata: vec![] };
+       let block = create_dummy_block(BlockHash::all_zeros(), 42, Vec::new());
        // Make Alice aware of enough blocks that it doesn't think we're violating transaction lock time
        // requirements here.
        const HTLC_TIMEOUT_BROADCAST: u32 = CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS;
@@ -8533,8 +8502,7 @@ fn test_concurrent_monitor_claim() {
                assert_eq!(watchtower.watch_channel(outpoint, new_monitor), ChannelMonitorUpdateStatus::Completed);
                watchtower
        };
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       watchtower_bob.chain_monitor.block_connected(&Block { header, txdata: vec![] }, HTLC_TIMEOUT_BROADCAST - 1);
+       watchtower_bob.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, Vec::new()), HTLC_TIMEOUT_BROADCAST - 1);
 
        // Route another payment to generate another update with still previous HTLC pending
        let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], 3000000);
@@ -8560,8 +8528,7 @@ fn test_concurrent_monitor_claim() {
        check_added_monitors!(nodes[0], 1);
 
        //// Provide one more block to watchtower Bob, expect broadcast of commitment and HTLC-Timeout
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       watchtower_bob.chain_monitor.block_connected(&Block { header, txdata: vec![] }, HTLC_TIMEOUT_BROADCAST);
+       watchtower_bob.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, Vec::new()), HTLC_TIMEOUT_BROADCAST);
 
        // Watchtower Bob should have broadcast a commitment/HTLC-timeout
        let bob_state_y;
@@ -8572,12 +8539,11 @@ fn test_concurrent_monitor_claim() {
        };
 
        // We confirm Bob's state Y on Alice, she should broadcast a HTLC-timeout
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
        let height = HTLC_TIMEOUT_BROADCAST + 1;
        connect_blocks(&nodes[0], height - nodes[0].best_block_info().1);
        check_closed_broadcast(&nodes[0], 1, true);
        check_closed_event(&nodes[0], 1, ClosureReason::CommitmentTxConfirmed, false);
-       watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![bob_state_y.clone()] }, height);
+       watchtower_alice.chain_monitor.block_connected(&create_dummy_block(BlockHash::all_zeros(), 42, vec![bob_state_y.clone()]), height);
        check_added_monitors(&nodes[0], 1);
        {
                let htlc_txn = alice_broadcaster.txn_broadcast();
@@ -8652,11 +8618,11 @@ fn test_htlc_no_detection() {
        check_spends!(local_txn[0], chan_1.3);
 
        // Timeout HTLC on A's chain and so it can generate a HTLC-Timeout tx
-       let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header, txdata: vec![local_txn[0].clone()] });
+       let block = create_dummy_block(nodes[0].best_block_hash(), 42, vec![local_txn[0].clone()]);
+       connect_block(&nodes[0], &block);
        // We deliberately connect the local tx twice as this should provoke a failure calling
        // this test before #653 fix.
-       chain::Listen::block_connected(&nodes[0].chain_monitor.chain_monitor, &Block { header, txdata: vec![local_txn[0].clone()] }, nodes[0].best_block_info().1 + 1);
+       chain::Listen::block_connected(&nodes[0].chain_monitor.chain_monitor, &block, nodes[0].best_block_info().1 + 1);
        check_closed_broadcast!(nodes[0], true);
        check_added_monitors!(nodes[0], 1);
        check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
@@ -8671,8 +8637,7 @@ fn test_htlc_no_detection() {
                node_txn[0].clone()
        };
 
-       let header_201 = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[0], &Block { header: header_201, txdata: vec![htlc_timeout.clone()] });
+       connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![htlc_timeout.clone()]));
        connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
        expect_payment_failed!(nodes[0], our_payment_hash, false);
 }
@@ -8732,8 +8697,7 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
                        true => alice_txn.clone(),
                        false => get_local_commitment_txn!(nodes[1], chan_ab.2)
                };
-               let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
-               connect_block(&nodes[1], &Block { header, txdata: vec![txn_to_broadcast[0].clone()]});
+               connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![txn_to_broadcast[0].clone()]));
                if broadcast_alice {
                        check_closed_broadcast!(nodes[1], true);
                        check_added_monitors!(nodes[1], 1);
@@ -8812,8 +8776,7 @@ fn do_test_onchain_htlc_settlement_after_close(broadcast_alice: bool, go_onchain
        let mut txn_to_broadcast = alice_txn.clone();
        if !broadcast_alice { txn_to_broadcast = get_local_commitment_txn!(nodes[1], chan_ab.2); }
        if !go_onchain_before_fulfill {
-               let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
-               connect_block(&nodes[1], &Block { header, txdata: vec![txn_to_broadcast[0].clone()]});
+               connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![txn_to_broadcast[0].clone()]));
                // If Bob was the one to force-close, he will have already passed these checks earlier.
                if broadcast_alice {
                        check_closed_broadcast!(nodes[1], true);
@@ -9520,7 +9483,7 @@ fn test_keysend_payments_to_public_node() {
        };
        let scorer = test_utils::TestScorer::new();
        let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
-       let route = find_route(&payer_pubkey, &route_params, &network_graph, None, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
+       let route = find_route(&payer_pubkey, &route_params, &network_graph, None, nodes[0].logger, &scorer, &(), &random_seed_bytes).unwrap();
 
        let test_preimage = PaymentPreimage([42; 32]);
        let payment_hash = nodes[0].node.send_spontaneous_payment(&route, Some(test_preimage),
@@ -9555,7 +9518,7 @@ fn test_keysend_payments_to_private_node() {
        let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
        let route = find_route(
                &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
-               nodes[0].logger, &scorer, &random_seed_bytes
+               nodes[0].logger, &scorer, &(), &random_seed_bytes
        ).unwrap();
 
        let test_preimage = PaymentPreimage([42; 32]);
index 3a0efd38690946cd5a7f48da324449d52f13fe2c..92edb061165b04a9fe611c957dfdf43ada6dff1b 100644 (file)
@@ -72,19 +72,17 @@ pub use self::peer_channel_encryptor::LN_MAX_MSG_LEN;
 /// payment_hash type, use to cross-lock hop
 ///
 /// This is not exported to bindings users as we just use [u8; 32] directly
-#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
-#[cfg_attr(test, derive(PartialOrd, Ord))]
+#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
 pub struct PaymentHash(pub [u8; 32]);
 /// payment_preimage type, use to route payment between hop
 ///
 /// This is not exported to bindings users as we just use [u8; 32] directly
-#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
-#[cfg_attr(test, derive(PartialOrd, Ord))]
+#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
 pub struct PaymentPreimage(pub [u8; 32]);
 /// payment_secret type, use to authenticate sender to the receiver and tie MPP HTLCs together
 ///
 /// This is not exported to bindings users as we just use [u8; 32] directly
-#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
 pub struct PaymentSecret(pub [u8; 32]);
 
 use crate::prelude::*;
index 1f9a2cf3a74e3b9555e8a64c6e6ed9f143324697..5fa39137cf4577f41f85a57b95aedf067ea43e5b 100644 (file)
@@ -114,7 +114,7 @@ fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_t
        if let Event::SpendableOutputs { outputs } = spendable.pop().unwrap() {
                assert_eq!(outputs.len(), 1);
                let spend_tx = node.keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
-                       Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
+                       Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &Secp256k1::new()).unwrap();
                check_spends!(spend_tx, spendable_tx);
        } else { panic!(); }
 }
@@ -1696,7 +1696,7 @@ fn do_test_restored_packages_retry(check_old_monitor_retries_after_upgrade: bool
        // old `ChannelMonitor` that did not exercise said rebroadcasting logic.
        if check_old_monitor_retries_after_upgrade {
                let serialized_monitor = hex::decode(
-                       "0101fffffffffffffffff9550f22c95100160014d5a9aa98b89acc215fc3d23d6fec0ad59ca3665f00002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6302d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e2035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea0016001467822698d782e8421ebdf96d010de99382b7ec2300160014caf6d80fe2bab80473b021f57588a9c384bf23170000000000000000000000004d49e5da0000000000000000000000000000002a0270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f74c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000022002034c0cc0ad0dd5fe61dcf7ef58f995e3d34f8dbd24aa2a6fae68fefe102bf025c21391732ce658e1fe167300bb689a81e7db5399b9ee4095e217b0e997e8dd3d17a0000000000000000004a002103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84022103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a04020090004752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae00000000000186a0ffffffffffff0291e7c0a3232fb8650a6b4089568a81062b48a768780e5a74bb4a4a74e33aec2c029d5760248ec86c4a76d9df8308555785a06a65472fb995f5b392d520bbd000650090c1c94b11625690c9d84c5daa67b6ad19fcc7f9f23e194384140b08fcab9e8e810000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000002391732ce658e1fe167300bb689a81e7db5399b9ee4095e217b0e997e8dd3d17a00000000000000010000000000009896800000005166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f292505000000009c009900202d704fbfe342a9ff6eaca14d80a24aaed0e680bbbdd36157b6f2798c61d906910120f9fe5e552aa0fc45020f0505efde432a4e373e5d393863973a6899f8c26d33d10208000000000098968004494800210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c23020500030241000408000001000000000006020000080800000000009896800a0400000046167c86cc0e598a6b541f7c9bf9ef17222e4a76f636e2d22185aeadd2b02d029c00000000000000000000000000000000000000000000000166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925fffffffffffe01e3002004f8eda5676356f539169a8e9a1e86c7f125283328d6f4bded1b939b52a6a7e30108000000000000c299022103a1f98e85886df54add6908b4fc1ff515e44aedefe9eb9c02879c89994298fa79042103a650bf03971df0176c7b412247390ef717853e8bd487b204dccc2fe2078bb75206210390bbbcebe9f70ba5dfd98866a79f72f75e0a6ea550ef73b202dd87cd6477350a08210284152d57908488e666e872716a286eb670b3d06cbeebf3f2e4ad350e01ec5e5b0a2102295e2de39eb3dcc2882f8cc266df7882a8b6d2c32aa08799f49b693aad3be28e0c04000000fd0e00fd01fe002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01080000000000009b5e0221035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea04210230fde9c031f487db95ff55b7c0acbe0c7c26a8d82615e9184416bd350101616706210225afb4e88eac8b47b67adeaf085f5eb5d37d936f56138f0848de3d104edf113208210208e4687a95c172b86b920c3bc5dbd5f023094ec2cb0abdb74f9b624f45740df90a2102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e20c04000000fd0efd01193b00010102080000000000989680040400000051062066687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925080400000000417e2650c201383711eed2a7cb8652c3e77ee6a395e81849c5c222217ed68b333c0ca9f1e900662ae68a7359efa7ef9d90613f2a62f7c3ff90f8c25e2cc974c9d39c009900202d704fbfe342a9ff6eaca14d80a24aaed0e680bbbdd36157b6f2798c61d906910120f9fe5e552aa0fc45020f0505efde432a4e373e5d393863973a6899f8c26d33d10208000000000098968004494800210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c23020500030241000408000001000000000006020000080800000000009896800a0400000046fffffffffffefffffffffffe000000000000000000000000000000000000000000000000ffe099e83ae3761c7f1b781d22613bd1f6977e9ad59fae12b3eba34462ee8a3d000000500000000000000002fd01da002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01fd01840200000000010174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d304004730440220671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec602204b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613401473044022016a0da36f70cbf5d889586af88f238982889dc161462c56557125c7acfcb69e9022036ae10c6cc8cbc3b27d9e9ef6babb556086585bc819f252208bd175286699fdd014752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae50c9222002040000000b03209452ca8c90d4c78928b80ec41398f2a890324d8ad6e6c81408a0cb9b8d977b070406030400020090fd02a1002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01fd01840200000000010174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d304004730440220671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec602204b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613401473044022016a0da36f70cbf5d889586af88f238982889dc161462c56557125c7acfcb69e9022036ae10c6cc8cbc3b27d9e9ef6babb556086585bc819f252208bd175286699fdd014752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae50c9222002040000000b03209452ca8c90d4c78928b80ec41398f2a890324d8ad6e6c81408a0cb9b8d977b0704cd01cb00c901c7002245cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d0001022102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e204020090062b5e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c630821035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea0a200000000000000000000000004d49e5da0000000000000000000000000000002a0c0800000000000186a0000000000000000274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e0000000000000001000000000022002034c0cc0ad0dd5fe61dcf7ef58f995e3d34f8dbd24aa2a6fae68fefe102bf025c45cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d000000000000000100000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d5349010100160014d5a9aa98b89acc215fc3d23d6fec0ad59ca3665ffd027100fd01e6fd01e300080000fffffffffffe02080000000000009b5e0408000000000000c3500604000000fd08b0af002102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e20221035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea04210230fde9c031f487db95ff55b7c0acbe0c7c26a8d82615e9184416bd350101616706210225afb4e88eac8b47b67adeaf085f5eb5d37d936f56138f0848de3d104edf113208210208e4687a95c172b86b920c3bc5dbd5f023094ec2cb0abdb74f9b624f45740df90acdcc00a8020000000174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d350c92220022045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d0c3c3b00010102080000000000989680040400000051062066687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f29250804000000000240671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec64b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613404010006407e2650c201383711eed2a7cb8652c3e77ee6a395e81849c5c222217ed68b333c0ca9f1e900662ae68a7359efa7ef9d90613f2a62f7c3ff90f8c25e2cc974c9d3010000000000000001010000000000000000090b2a953d93a124c600ecb1a0ccfed420169cdd37f538ad94a3e4e6318c93c14adf59cdfbb40bdd40950c9f8dd547d29d75a173e1376a7850743394c46dea2dfd01cefd01ca00fd017ffd017c00080000ffffffffffff0208000000000000c2990408000000000000c3500604000000fd08b0af002102295e2de39eb3dcc2882f8cc266df7882a8b6d2c32aa08799f49b693aad3be28e022103a1f98e85886df54add6908b4fc1ff515e44aedefe9eb9c02879c89994298fa79042103a650bf03971df0176c7b412247390ef717853e8bd487b204dccc2fe2078bb75206210390bbbcebe9f70ba5dfd98866a79f72f75e0a6ea550ef73b202dd87cd6477350a08210284152d57908488e666e872716a286eb670b3d06cbeebf3f2e4ad350e01ec5e5b0aa2a1007d020000000174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800299c2000000000000220020740e108cfbc93967b6ab242a351ebee7de51814cf78d366adefd78b10281f17e50c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d351c92220022004f8eda5676356f539169a8e9a1e86c7f125283328d6f4bded1b939b52a6a7e30c00024045cb2485594bb1ec08e7bb6af4f89c912bd53f006d7876ea956773e04a4aad4a40e2b8d4fc612102f0b54061b3c1239fb78783053e8e6f9d92b1b99f81ae9ec2040100060000fd019600b0af002103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b02210270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f042103b4e59df102747edc3a3e2283b42b88a8c8218ffd0dcfb52f2524b371d64cadaa062103d902b7b8b3434076d2b210e912c76645048b71e28995aad227a465a65ccd817608210301e9a52f923c157941de4a7692e601f758660969dcf5abdb67817efe84cce2ef0202009004010106b7b600b0af00210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db30221034d0f817cb19b4a3bd144b615459bd06cbab3b4bdc96d73e18549a992cee80e8104210380542b59a9679890cba529fe155a9508ef57dac7416d035b23666e3fb98c3814062103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84082103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a02020090082274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e000000000287010108d30df34e3a1e00ecdd03a2c843db062479a81752c4dfd0cc4baef0f81e7bc7ef8820990daf8d8e8d30a3b4b08af12c9f5cd71e45c7238103e0c80ca13850862e4fd2c56b69b7195312518de1bfe9aed63c80bb7760d70b2a870d542d815895fd12423d11e2adb0cdf55d776dac8f487c9b3b7ea12f1b150eb15889cf41333ade465692bf1cdc360b9c2a19bf8c1ca4fed7639d8bc953d36c10d8c6c9a8c0a57608788979bcf145e61b308006896e21d03e92084f93bd78740c20639134a7a8fd019afd019600b0af002103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b02210270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f042103b4e59df102747edc3a3e2283b42b88a8c8218ffd0dcfb52f2524b371d64cadaa062103d902b7b8b3434076d2b210e912c76645048b71e28995aad227a465a65ccd817608210301e9a52f923c157941de4a7692e601f758660969dcf5abdb67817efe84cce2ef0202009004010106b7b600b0af00210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db30221034d0f817cb19b4a3bd144b615459bd06cbab3b4bdc96d73e18549a992cee80e8104210380542b59a9679890cba529fe155a9508ef57dac7416d035b23666e3fb98c3814062103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84082103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a02020090082274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e000000000000000186a00000000000000000000000004d49e5da0000000000000000000000000000002a000000000000000001b77b61346a2a408afdb01743a2230cb36e55771a0790f67a0910e207fd223fc8000000000000000145cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d00000000041000080000000000989680020400000051160004000000510208000000000000000004040000000b000000000000000145cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d00000000b77b61346a2a408afdb01743a2230cb36e55771a0790f67a0910e207fd223fc80000005000000000000000000000000000000000000101300300050007010109210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c230d000f020000",
+                       "0101fffffffffffffffff9550f22c95100160014d5a9aa98b89acc215fc3d23d6fec0ad59ca3665f00002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6302d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e2035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea0016001467822698d782e8421ebdf96d010de99382b7ec2300160014caf6d80fe2bab80473b021f57588a9c384bf23170000000000000000000000004d49e5da0000000000000000000000000000002a0270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f74c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000022002034c0cc0ad0dd5fe61dcf7ef58f995e3d34f8dbd24aa2a6fae68fefe102bf025c21391732ce658e1fe167300bb689a81e7db5399b9ee4095e217b0e997e8dd3d17a0000000000000000004a002103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84022103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a04020090004752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae00000000000186a0ffffffffffff0291e7c0a3232fb8650a6b4089568a81062b48a768780e5a74bb4a4a74e33aec2c029d5760248ec86c4a76d9df8308555785a06a65472fb995f5b392d520bbd000650090c1c94b11625690c9d84c5daa67b6ad19fcc7f9f23e194384140b08fcab9e8e810000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000002167c86cc0e598a6b541f7c9bf9ef17222e4a76f636e2d22185aeadd2b02d029c0000000000000000391732ce658e1fe167300bb689a81e7db5399b9ee4095e217b0e997e8dd3d17a00000000000000010000000000009896800000005166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f29250500000000a0009d00202d704fbfe342a9ff6eaca14d80a24aaed0e680bbbdd36157b6f2798c61d906910120f9fe5e552aa0fc45020f0505efde432a4e373e5d393863973a6899f8c26d33d102080000000000989680044d4c00210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c2302090007000000000241000408000001000000000006020000080800000000009896800a04000000460000000000000000000000000000000166687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925fffffffffffe01e3002004f8eda5676356f539169a8e9a1e86c7f125283328d6f4bded1b939b52a6a7e30108000000000000c299022103a1f98e85886df54add6908b4fc1ff515e44aedefe9eb9c02879c89994298fa79042103a650bf03971df0176c7b412247390ef717853e8bd487b204dccc2fe2078bb75206210390bbbcebe9f70ba5dfd98866a79f72f75e0a6ea550ef73b202dd87cd6477350a08210284152d57908488e666e872716a286eb670b3d06cbeebf3f2e4ad350e01ec5e5b0a2102295e2de39eb3dcc2882f8cc266df7882a8b6d2c32aa08799f49b693aad3be28e0c04000000fd0e00fd0202002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01080000000000009b5e0221035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea04210230fde9c031f487db95ff55b7c0acbe0c7c26a8d82615e9184416bd350101616706210225afb4e88eac8b47b67adeaf085f5eb5d37d936f56138f0848de3d104edf113208210208e4687a95c172b86b920c3bc5dbd5f023094ec2cb0abdb74f9b624f45740df90a2102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e20c04000000fd0efd011d3b00010102080000000000989680040400000051062066687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925080400000000417e2650c201383711eed2a7cb8652c3e77ee6a395e81849c5c222217ed68b333c0ca9f1e900662ae68a7359efa7ef9d90613f2a62f7c3ff90f8c25e2cc974c9d3a0009d00202d704fbfe342a9ff6eaca14d80a24aaed0e680bbbdd36157b6f2798c61d906910120f9fe5e552aa0fc45020f0505efde432a4e373e5d393863973a6899f8c26d33d102080000000000989680044d4c00210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c2302090007000000000241000408000001000000000006020000080800000000009896800a0400000046fffffffffffefffffffffffe000000000000000000000000000000000000000000000000f1600ef6ea657b8d411d553516ae35cedfe86b0cd48d1f91b32772facbae757d0000000b0000000000000002fd01da002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01fd01840200000000010174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d304004730440220671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec602204b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613401473044022016a0da36f70cbf5d889586af88f238982889dc161462c56557125c7acfcb69e9022036ae10c6cc8cbc3b27d9e9ef6babb556086585bc819f252208bd175286699fdd014752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae50c9222002040000000b0320f1600ef6ea657b8d411d553516ae35cedfe86b0cd48d1f91b32772facbae757d0406030400020090fd02a1002045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d01fd01840200000000010174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d304004730440220671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec602204b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613401473044022016a0da36f70cbf5d889586af88f238982889dc161462c56557125c7acfcb69e9022036ae10c6cc8cbc3b27d9e9ef6babb556086585bc819f252208bd175286699fdd014752210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db32103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b52ae50c9222002040000000b0320f1600ef6ea657b8d411d553516ae35cedfe86b0cd48d1f91b32772facbae757d04cd01cb00c901c7002245cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d0001022102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e204020090062b5e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c630821035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea0a200000000000000000000000004d49e5da0000000000000000000000000000002a0c0800000000000186a0000000000000000274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e0000000000000001000000000022002034c0cc0ad0dd5fe61dcf7ef58f995e3d34f8dbd24aa2a6fae68fefe102bf025c45cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d000000000000000100000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d5349010100160014d5a9aa98b89acc215fc3d23d6fec0ad59ca3665ffd027100fd01e6fd01e300080000fffffffffffe02080000000000009b5e0408000000000000c3500604000000fd08b0af002102d7dde8e10a5a22c9bd0d7ef5494d85683ac050253b917615d4f97af633f0a8e20221035f5e9d58b4328566223c107d86cf853e6b9fae1d26ff6d969be0178d1423c4ea04210230fde9c031f487db95ff55b7c0acbe0c7c26a8d82615e9184416bd350101616706210225afb4e88eac8b47b67adeaf085f5eb5d37d936f56138f0848de3d104edf113208210208e4687a95c172b86b920c3bc5dbd5f023094ec2cb0abdb74f9b624f45740df90acdcc00a8020000000174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800310270000000000002200208309b406e3b96e76cde414fbb8f5159f5b25b24075656c6382cec797854d53495e9b0000000000002200204c5f18e5e95b184f34d02ba6de8a2a4e36ae3d4ec87299ad81f3284dc7195c6350c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d350c92220022045cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d0c3c3b00010102080000000000989680040400000051062066687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f29250804000000000240671c9badf26bd3a1ebd2d17020c6be20587d7822530daacc52c28839875eaec64b575a21729ed27311f6d79fdf6fe8702b0a798f7d842e39ede1b56f249a613404010006407e2650c201383711eed2a7cb8652c3e77ee6a395e81849c5c222217ed68b333c0ca9f1e900662ae68a7359efa7ef9d90613f2a62f7c3ff90f8c25e2cc974c9d3010000000000000001010000000000000000090b2a953d93a124c600ecb1a0ccfed420169cdd37f538ad94a3e4e6318c93c14adf59cdfbb40bdd40950c9f8dd547d29d75a173e1376a7850743394c46dea2dfd01cefd01ca00fd017ffd017c00080000ffffffffffff0208000000000000c2990408000000000000c3500604000000fd08b0af002102295e2de39eb3dcc2882f8cc266df7882a8b6d2c32aa08799f49b693aad3be28e022103a1f98e85886df54add6908b4fc1ff515e44aedefe9eb9c02879c89994298fa79042103a650bf03971df0176c7b412247390ef717853e8bd487b204dccc2fe2078bb75206210390bbbcebe9f70ba5dfd98866a79f72f75e0a6ea550ef73b202dd87cd6477350a08210284152d57908488e666e872716a286eb670b3d06cbeebf3f2e4ad350e01ec5e5b0aa2a1007d020000000174c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e00000000000f55f9800299c2000000000000220020740e108cfbc93967b6ab242a351ebee7de51814cf78d366adefd78b10281f17e50c300000000000016001425df8ec4a074f80579fed67d4707d5ec8ed7e8d351c92220022004f8eda5676356f539169a8e9a1e86c7f125283328d6f4bded1b939b52a6a7e30c00024045cb2485594bb1ec08e7bb6af4f89c912bd53f006d7876ea956773e04a4aad4a40e2b8d4fc612102f0b54061b3c1239fb78783053e8e6f9d92b1b99f81ae9ec2040100060000fd019600b0af002103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b02210270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f042103b4e59df102747edc3a3e2283b42b88a8c8218ffd0dcfb52f2524b371d64cadaa062103d902b7b8b3434076d2b210e912c76645048b71e28995aad227a465a65ccd817608210301e9a52f923c157941de4a7692e601f758660969dcf5abdb67817efe84cce2ef0202009004010106b7b600b0af00210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db30221034d0f817cb19b4a3bd144b615459bd06cbab3b4bdc96d73e18549a992cee80e8104210380542b59a9679890cba529fe155a9508ef57dac7416d035b23666e3fb98c3814062103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84082103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a02020090082274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e000000000287010108d30df34e3a1e00ecdd03a2c843db062479a81752c4dfd0cc4baef0f81e7bc7ef8820990daf8d8e8d30a3b4b08af12c9f5cd71e45c7238103e0c80ca13850862e4fd2c56b69b7195312518de1bfe9aed63c80bb7760d70b2a870d542d815895fd12423d11e2adb0cdf55d776dac8f487c9b3b7ea12f1b150eb15889cf41333ade465692bf1cdc360b9c2a19bf8c1ca4fed7639d8bc953d36c10d8c6c9a8c0a57608788979bcf145e61b308006896e21d03e92084f93bd78740c20639134a7a8fd019afd019600b0af002103c21e841cbc0b48197d060c71e116c185fa0ac281b7d0aa5924f535154437ca3b02210270b20ad0f2c2bb30a55590fc77778495bc1b38c96476901145dda57491237f0f042103b4e59df102747edc3a3e2283b42b88a8c8218ffd0dcfb52f2524b371d64cadaa062103d902b7b8b3434076d2b210e912c76645048b71e28995aad227a465a65ccd817608210301e9a52f923c157941de4a7692e601f758660969dcf5abdb67817efe84cce2ef0202009004010106b7b600b0af00210307a78def56cba9fc4db22a25928181de538ee59ba1a475ae113af7790acd0db30221034d0f817cb19b4a3bd144b615459bd06cbab3b4bdc96d73e18549a992cee80e8104210380542b59a9679890cba529fe155a9508ef57dac7416d035b23666e3fb98c3814062103adde8029d3ee281a32e9db929b39f503ff9d7e93cd308eb157955344dc6def84082103205087e2dc1f6b9937e887dfa712c5bdfa950b01dbda3ebac4c85efdde48ee6a02020090082274c52ab4f11296d62b66a6dba9513b04a3e7fb5a09a30cee22fce7294ab55b7e000000000000000186a00000000000000000000000004d49e5da0000000000000000000000000000002a00000000000000000000000000000000000000000000000001000000510000000000000001000000000000000145cfd42d0989e55b953f516ac7fd152bd90ec4438a2fc636f97ddd32a0c8fe0d00000000041000080000000000989680020400000051160004000000510208000000000000000004040000000b0000000000000000000101300300050007010109210355f8d2238a322d16b602bd0ceaad5b01019fb055971eaadcc9b29226a4da6c230d000f020000",
                ).unwrap();
                reload_node!(nodes[0], &nodes[0].node.encode(), &[&serialized_monitor], persister, new_chain_monitor, node_deserialized);
        }
@@ -2185,21 +2185,20 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
        // revoked outputs.
        {
                let txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
-               assert_eq!(txn.len(), 2);
+               assert_eq!(txn.len(), 4);
 
-               let (revoked_claim_a, revoked_claim_b) = if txn[0].input[0].previous_output.txid == revoked_commitment_a.txid() {
-                       (&txn[0], &txn[1])
+               let (revoked_htlc_claim_a, revoked_htlc_claim_b) = if txn[0].input[0].previous_output.txid == revoked_commitment_a.txid() {
+                       (if txn[0].input.len() == 2 { &txn[0] } else { &txn[1] }, if txn[2].input.len() == 2 { &txn[2] } else { &txn[3] })
                } else {
-                       (&txn[1], &txn[0])
+                       (if txn[2].input.len() == 2 { &txn[2] } else { &txn[3] }, if txn[0].input.len() == 2 { &txn[0] } else { &txn[1] })
                };
 
-               // TODO: to_self claim must be separate from HTLC claims
-               assert_eq!(revoked_claim_a.input.len(), 3); // Spends both HTLC outputs and to_self output
-               assert_eq!(revoked_claim_a.output.len(), 1);
-               check_spends!(revoked_claim_a, revoked_commitment_a);
-               assert_eq!(revoked_claim_b.input.len(), 3); // Spends both HTLC outputs and to_self output
-               assert_eq!(revoked_claim_b.output.len(), 1);
-               check_spends!(revoked_claim_b, revoked_commitment_b);
+               assert_eq!(revoked_htlc_claim_a.input.len(), 2); // Spends both HTLC outputs
+               assert_eq!(revoked_htlc_claim_a.output.len(), 1);
+               check_spends!(revoked_htlc_claim_a, revoked_commitment_a);
+               assert_eq!(revoked_htlc_claim_b.input.len(), 2); // Spends both HTLC outputs
+               assert_eq!(revoked_htlc_claim_b.output.len(), 1);
+               check_spends!(revoked_htlc_claim_b, revoked_commitment_b);
        }
 
        // Since Bob was able to confirm his revoked commitment, he'll now try to claim the HTLCs
@@ -2296,21 +2295,7 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
        // the second level instead.
        let revoked_claims = {
                let txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
-               assert_eq!(txn.len(), 4);
-
-               let revoked_to_self_claim_a = txn.iter().find(|tx|
-                       tx.input.len() == 1 &&
-                       tx.output.len() == 1 &&
-                       tx.input[0].previous_output.txid == revoked_commitment_a.txid()
-               ).unwrap();
-               check_spends!(revoked_to_self_claim_a, revoked_commitment_a);
-
-               let revoked_to_self_claim_b = txn.iter().find(|tx|
-                       tx.input.len() == 1 &&
-                       tx.output.len() == 1 &&
-                       tx.input[0].previous_output.txid == revoked_commitment_b.txid()
-               ).unwrap();
-               check_spends!(revoked_to_self_claim_b, revoked_commitment_b);
+               assert_eq!(txn.len(), 2);
 
                let revoked_htlc_claims = txn.iter().filter(|tx|
                        tx.input.len() == 2 &&
@@ -2343,12 +2328,12 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
 
        assert!(nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
        let spendable_output_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
-       assert_eq!(spendable_output_events.len(), 4);
+       assert_eq!(spendable_output_events.len(), 2);
        for (idx, event) in spendable_output_events.iter().enumerate() {
                if let Event::SpendableOutputs { outputs } = event {
                        assert_eq!(outputs.len(), 1);
                        let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(
-                               &[&outputs[0]], Vec::new(), Script::new_op_return(&[]), 253, &Secp256k1::new(),
+                               &[&outputs[0]], Vec::new(), Script::new_op_return(&[]), 253, None, &Secp256k1::new(),
                        ).unwrap();
                        check_spends!(spend_tx, revoked_claims[idx]);
                } else {
@@ -2358,7 +2343,8 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
 
        assert!(nodes[0].node.list_channels().is_empty());
        assert!(nodes[1].node.list_channels().is_empty());
-       assert!(nodes[0].chain_monitor.chain_monitor.get_claimable_balances(&[]).is_empty());
+       // On the Alice side, the individual to_self_claim are still pending confirmation.
+       assert_eq!(nodes[0].chain_monitor.chain_monitor.get_claimable_balances(&[]).len(), 2);
        // TODO: From Bob's PoV, he still thinks he can claim the outputs from his revoked commitment.
        // This needs to be fixed before we enable pruning `ChannelMonitor`s once they don't have any
        // balances to claim.
index 27f8544e3b52021345f66ccd9c434beea2876bf2..76ed56635ac6a57bd22cb82f5bba93e4c210b5c6 100644 (file)
@@ -26,7 +26,7 @@
 
 use bitcoin::secp256k1::PublicKey;
 use bitcoin::secp256k1::ecdsa::Signature;
-use bitcoin::{secp256k1, Witness, Transaction};
+use bitcoin::{secp256k1, Witness};
 use bitcoin::blockdata::script::Script;
 use bitcoin::hash_types::{Txid, BlockHash};
 
@@ -42,7 +42,7 @@ use crate::io_extras::read_to_end;
 
 use crate::events::{MessageSendEventsProvider, OnionMessageProvider};
 use crate::util::logger;
-use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname};
+use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited};
 
 use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
 
@@ -425,45 +425,6 @@ pub struct ChannelReady {
        pub short_channel_id_alias: Option<u64>,
 }
 
-/// A wrapper for a `Transaction` which can only be constructed with [`TransactionU16LenLimited::new`]
-/// if the `Transaction`'s consensus-serialized length is <= u16::MAX.
-///
-/// Use [`TransactionU16LenLimited::into_transaction`] to convert into the contained `Transaction`.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct TransactionU16LenLimited(Transaction);
-
-impl TransactionU16LenLimited {
-       /// Constructs a new `TransactionU16LenLimited` from a `Transaction` only if it's consensus-
-       /// serialized length is <= u16::MAX.
-       pub fn new(transaction: Transaction) -> Result<Self, ()> {
-               if transaction.serialized_length() > (u16::MAX as usize) {
-                       Err(())
-               } else {
-                       Ok(Self(transaction))
-               }
-       }
-
-       /// Consumes this `TransactionU16LenLimited` and returns its contained `Transaction`.
-       pub fn into_transaction(self) -> Transaction {
-               self.0
-       }
-}
-
-impl Writeable for TransactionU16LenLimited {
-       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               (self.0.serialized_length() as u16).write(w)?;
-               self.0.write(w)
-       }
-}
-
-impl Readable for TransactionU16LenLimited {
-       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
-               let len = <u16 as Readable>::read(r)?;
-               let mut tx_reader = FixedLengthReader::new(r, len as u64);
-               Ok(Self(Readable::read(&mut tx_reader)?))
-       }
-}
-
 /// A tx_add_input message for adding an input during interactive transaction construction
 ///
 // TODO(dual_funding): Add spec link for `tx_add_input`.
@@ -850,7 +811,7 @@ impl NetAddress {
 }
 
 impl Writeable for NetAddress {
-fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
                match self {
                        &NetAddress::IPv4 { ref addr, ref port } => {
                                1u8.write(writer)?;
@@ -1777,7 +1738,7 @@ impl Readable for Init {
                        (3, remote_network_address, option)
                });
                Ok(Init {
-                       features: features.or(global_features),
+                       features: features | global_features,
                        remote_network_address,
                })
        }
@@ -2454,10 +2415,9 @@ mod tests {
        use hex;
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
        use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
-       use crate::ln::msgs::{self, TransactionU16LenLimited};
-       use crate::ln::msgs::{FinalOnionHopData, OnionErrorPacket, OnionHopDataFormat};
+       use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, OnionHopDataFormat};
        use crate::routing::gossip::{NodeAlias, NodeId};
-       use crate::util::ser::{Writeable, Readable, Hostname};
+       use crate::util::ser::{Writeable, Readable, Hostname, TransactionU16LenLimited};
 
        use bitcoin::hashes::hex::FromHex;
        use bitcoin::util::address::Address;
index 86bf8bdc3fabda830931ea61f26d74644ae88ca5..36e1bd753e294272150a403b5d24c5bd339d819d 100644 (file)
@@ -359,7 +359,7 @@ fn test_onion_failure() {
                // break the first (non-final) hop payload by swapping the realm (0) byte for a byte
                // describing a length-1 TLV payload, which is obviously bogus.
                new_payloads[0].data[0] = 1;
-               msg.onion_routing_packet = onion_utils::construct_onion_packet_with_writable_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash);
+               msg.onion_routing_packet = onion_utils::construct_onion_packet_with_writable_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
        }, ||{}, true, Some(PERM|22), Some(NetworkUpdate::ChannelFailure{short_channel_id, is_permanent: true}), Some(short_channel_id));
 
        // final node failure
@@ -377,7 +377,7 @@ fn test_onion_failure() {
                // break the last-hop payload by swapping the realm (0) byte for a byte describing a
                // length-1 TLV payload, which is obviously bogus.
                new_payloads[1].data[0] = 1;
-               msg.onion_routing_packet = onion_utils::construct_onion_packet_with_writable_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash);
+               msg.onion_routing_packet = onion_utils::construct_onion_packet_with_writable_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
        }, ||{}, false, Some(PERM|22), Some(NetworkUpdate::ChannelFailure{short_channel_id, is_permanent: true}), Some(short_channel_id));
 
        // the following three with run_onion_failure_test_with_fail_intercept() test only the origin node
@@ -607,7 +607,7 @@ fn test_onion_failure() {
                let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
                let (onion_payloads, _, htlc_cltv) = onion_utils::build_onion_payloads(
                        &route.paths[0], 40000, RecipientOnionFields::spontaneous_empty(), height, &None).unwrap();
-               let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
+               let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
                msg.cltv_expiry = htlc_cltv;
                msg.onion_routing_packet = onion_packet;
        }, ||{}, true, Some(21), Some(NetworkUpdate::NodeFailure{node_id: route.paths[0].hops[0].pubkey, is_permanent: true}), Some(route.paths[0].hops[0].short_channel_id));
@@ -993,7 +993,7 @@ macro_rules! get_phantom_route {
                (get_route(
                        &$nodes[0].node.get_our_node_id(), &payment_params, &network_graph,
                        Some(&$nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()),
-                       $amt, $nodes[0].logger, &scorer, &[0u8; 32]
+                       $amt, $nodes[0].logger, &scorer, &(), &[0u8; 32]
                ).unwrap(), phantom_route_hint.phantom_scid)
        }
 }}
@@ -1106,7 +1106,7 @@ fn test_phantom_invalid_onion_payload() {
                                        onion_keys.remove(0);
                                        onion_payloads.remove(0);
 
-                                       let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
+                                       let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
                                        onion_packet.hop_data = new_onion_packet.hop_data;
                                        onion_packet.hmac = new_onion_packet.hmac;
                                },
index ebcf83bd90dc2d0db68c5300e50cf2f6b06dd718..3b62c856334596b85bf58b8ee96b1a0eed8f36f6 100644 (file)
@@ -208,22 +208,7 @@ fn shift_slice_right(arr: &mut [u8], amt: usize) {
        }
 }
 
-pub(super) fn route_size_insane(payloads: &Vec<msgs::OnionHopData>) -> bool {
-       let mut len = 0;
-       for payload in payloads.iter() {
-               let mut payload_len = LengthCalculatingWriter(0);
-               payload.write(&mut payload_len).expect("Failed to calculate length");
-               assert!(payload_len.0 + 32 < ONION_DATA_LEN);
-               len += payload_len.0 + 32;
-               if len > ONION_DATA_LEN {
-                       return true;
-               }
-       }
-       false
-}
-
-/// panics if route_size_insane(payloads)
-pub(super) fn construct_onion_packet(payloads: Vec<msgs::OnionHopData>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], associated_data: &PaymentHash) -> msgs::OnionPacket {
+pub(super) fn construct_onion_packet(payloads: Vec<msgs::OnionHopData>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], associated_data: &PaymentHash) -> Result<msgs::OnionPacket, ()> {
        let mut packet_data = [0; ONION_DATA_LEN];
 
        let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]);
@@ -236,7 +221,7 @@ pub(super) fn construct_onion_packet(payloads: Vec<msgs::OnionHopData>, onion_ke
 #[cfg(test)]
 /// Used in testing to write bogus `BogusOnionHopData` as well as `RawOnionHopData`, which is
 /// otherwise not representable in `msgs::OnionHopData`.
-pub(super) fn construct_onion_packet_with_writable_hopdata<HD: Writeable>(payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], associated_data: &PaymentHash) -> msgs::OnionPacket {
+pub(super) fn construct_onion_packet_with_writable_hopdata<HD: Writeable>(payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], associated_data: &PaymentHash) -> Result<msgs::OnionPacket, ()> {
        let mut packet_data = [0; ONION_DATA_LEN];
 
        let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]);
@@ -268,9 +253,8 @@ pub(crate) fn payloads_serialized_length<HD: Writeable>(payloads: &Vec<HD>) -> u
        payloads.iter().map(|p| p.serialized_length() + 32 /* HMAC */).sum()
 }
 
-/// panics if payloads_serialized_length(payloads) > packet_data_len
 pub(crate) fn construct_onion_message_packet<HD: Writeable, P: Packet<Data = Vec<u8>>>(
-       payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], packet_data_len: usize) -> P
+       payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], packet_data_len: usize) -> Result<P, ()>
 {
        let mut packet_data = vec![0; packet_data_len];
 
@@ -280,9 +264,8 @@ pub(crate) fn construct_onion_message_packet<HD: Writeable, P: Packet<Data = Vec
        construct_onion_packet_with_init_noise::<_, _>(payloads, onion_keys, packet_data, None)
 }
 
-/// panics if payloads_serialized_length(payloads) > packet_data.len()
 fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
-       mut payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, mut packet_data: P::Data, associated_data: Option<&PaymentHash>) -> P
+       mut payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, mut packet_data: P::Data, associated_data: Option<&PaymentHash>) -> Result<P, ()>
 {
        let filler = {
                let packet_data = packet_data.as_mut();
@@ -302,7 +285,9 @@ fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
                        let mut payload_len = LengthCalculatingWriter(0);
                        payload.write(&mut payload_len).expect("Failed to calculate length");
                        pos += payload_len.0 + 32;
-                       assert!(pos <= packet_data.len());
+                       if pos > packet_data.len() {
+                               return Err(());
+                       }
 
                        res.resize(pos, 0u8);
                        chacha.process_in_place(&mut res);
@@ -324,7 +309,9 @@ fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
                chacha.process_in_place(packet_data);
 
                if i == 0 {
-                       packet_data[ONION_DATA_LEN - filler.len()..ONION_DATA_LEN].copy_from_slice(&filler[..]);
+                       let stop_index = packet_data.len();
+                       let start_index = stop_index.checked_sub(filler.len()).ok_or(())?;
+                       packet_data[start_index..stop_index].copy_from_slice(&filler[..]);
                }
 
                let mut hmac = HmacEngine::<Sha256>::new(&keys.mu);
@@ -335,7 +322,7 @@ fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
                hmac_res = Hmac::from_engine(hmac).into_inner();
        }
 
-       P::new(onion_keys.first().unwrap().ephemeral_pubkey, packet_data, hmac_res)
+       Ok(P::new(onion_keys.first().unwrap().ephemeral_pubkey, packet_data, hmac_res))
 }
 
 /// Encrypts a failure packet. raw_packet can either be a
@@ -1081,7 +1068,7 @@ mod tests {
 
                let pad_keytype_seed = super::gen_pad_from_shared_secret(&get_test_session_key().secret_bytes());
 
-               let packet: msgs::OnionPacket = super::construct_onion_packet_with_writable_hopdata::<_>(payloads, onion_keys, pad_keytype_seed, &PaymentHash([0x42; 32]));
+               let packet: msgs::OnionPacket = super::construct_onion_packet_with_writable_hopdata::<_>(payloads, onion_keys, pad_keytype_seed, &PaymentHash([0x42; 32])).unwrap();
 
                assert_eq!(packet.encode(), hex::decode("0002EEC7245D6B7D2CCB30380BFBE2A3648CD7A942653F5AA340EDCEA1F283686619F7F3416A5AA36DC7EEB3EC6D421E9615471AB870A33AC07FA5D5A51DF0A8823AABE3FEA3F90D387529D4F72837F9E687230371CCD8D263072206DBED0234F6505E21E282ABD8C0E4F5B9FF8042800BBAB065036EADD0149B37F27DDE664725A49866E052E809D2B0198AB9610FAA656BBF4EC516763A59F8F42C171B179166BA38958D4F51B39B3E98706E2D14A2DAFD6A5DF808093ABFCA5AEAACA16EDED5DB7D21FB0294DD1A163EDF0FB445D5C8D7D688D6DD9C541762BF5A5123BF9939D957FE648416E88F1B0928BFA034982B22548E1A4D922690EECF546275AFB233ACF4323974680779F1A964CFE687456035CC0FBA8A5428430B390F0057B6D1FE9A8875BFA89693EEB838CE59F09D207A503EE6F6299C92D6361BC335FCBF9B5CD44747AADCE2CE6069CFDC3D671DAEF9F8AE590CF93D957C9E873E9A1BC62D9640DC8FC39C14902D49A1C80239B6C5B7FD91D05878CBF5FFC7DB2569F47C43D6C0D27C438ABFF276E87364DEB8858A37E5A62C446AF95D8B786EAF0B5FCF78D98B41496794F8DCAAC4EEF34B2ACFB94C7E8C32A9E9866A8FA0B6F2A06F00A1CCDE569F97EEC05C803BA7500ACC96691D8898D73D8E6A47B8F43C3D5DE74458D20EDA61474C426359677001FBD75A74D7D5DB6CB4FEB83122F133206203E4E2D293F838BF8C8B3A29ACB321315100B87E80E0EDB272EE80FDA944E3FB6084ED4D7F7C7D21C69D9DA43D31A90B70693F9B0CC3EAC74C11AB8FF655905688916CFA4EF0BD04135F2E50B7C689A21D04E8E981E74C6058188B9B1F9DFC3EEC6838E9FFBCF22CE738D8A177C19318DFFEF090CEE67E12DE1A3E2A39F61247547BA5257489CBC11D7D91ED34617FCC42F7A9DA2E3CF31A94A210A1018143173913C38F60E62B24BF0D7518F38B5BAB3E6A1F8AEB35E31D6442C8ABB5178EFC892D2E787D79C6AD9E2FC271792983FA9955AC4D1D84A36C024071BC6E431B625519D556AF38185601F70E29035EA6A09C8B676C9D88CF7E05E0F17098B584C4168735940263F940033A220F40BE4C85344128B14BEB9E75696DB37014107801A59B13E89CD9D2258C169D523BE6D31552C44C82FF4BB18EC9F099F3BF0E5B1BB2BA9A87D7E26F98D294927B600B5529C47E04D98956677CBCEE8FA2B60F49776D8B8C367465B7C626DA53700684FB6C918EAD0EAB8360E4F60EDD25B4F43816A75ECF70F909301825B512469F8389D79402311D8AECB7B3EF8599E79485A4388D87744D899F7C47EE644361E17040A7958C8911BE6F463AB6A9B2AFACD688EC55EF517B38F1339EFC54487232798BB25522FF4572FF68567FE830F92F7B8113EFCE3E98C3FFFBAEDCE4FD8B50E41DA97C0C08E423A72689CC68E68F752A5E3A9003E64E35C957CA2E1C48BB6F64B05F56B70B575AD2F278D57850A7AD568C24A4D32A3D74B29F03DC125488BC7C637DA582357F40B0A52D16B3B40BB2C2315D03360BC24209E20972C200566BCF3BBE5C5B0AEDD83132A8A4D5B4242BA370B6D67D9B67EB01052D132C7866B9CB502E44796D9D356E4E3CB47CC527322CD24976FE7C9257A2864151A38E568EF7A79F10D6EF27CC04CE382347A2488B1F404FDBF407FE1CA1C9D0D5649E34800E25E18951C98CAE9F43555EEF65FEE1EA8F15828807366C3B612CD5753BF9FB8FCED08855F742CDDD6F765F74254F03186683D646E6F09AC2805586C7CF11998357CAFC5DF3F285329366F475130C928B2DCEBA4AA383758E7A9D20705C4BB9DB619E2992F608A1BA65DB254BB389468741D0502E2588AEB54390AC600C19AF5C8E61383FC1BEBE0029E4474051E4EF908828DB9CCA13277EF65DB3FD47CCC2179126AAEFB627719F421E20").unwrap());
        }
index ba7da5d5e6b5b184a500d430ef494f43a7135ba2..9e044d1c92d686479d6f76187001ac75c55d92aa 100644 (file)
@@ -30,8 +30,6 @@ use crate::util::errors::APIError;
 use crate::util::ser::Writeable;
 use crate::util::string::UntrustedString;
 
-use bitcoin::{Block, BlockHeader, TxMerkleNode};
-use bitcoin::hashes::Hash;
 use bitcoin::network::constants::Network;
 
 use crate::prelude::*;
@@ -693,8 +691,7 @@ fn do_test_dup_htlc_onchain_fails_on_reload(persist_manager_post_event: bool, co
        check_added_monitors!(nodes[1], 1);
        expect_payment_claimed!(nodes[1], payment_hash, 10_000_000);
 
-       let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
-       connect_block(&nodes[1], &Block { header, txdata: vec![node_txn[1].clone()]});
+       connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, vec![node_txn[1].clone()]));
        check_closed_broadcast!(nodes[1], true);
        check_added_monitors!(nodes[1], 1);
        check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
@@ -702,15 +699,13 @@ fn do_test_dup_htlc_onchain_fails_on_reload(persist_manager_post_event: bool, co
        assert_eq!(claim_txn.len(), 1);
        check_spends!(claim_txn[0], node_txn[1]);
 
-       header.prev_blockhash = nodes[0].best_block_hash();
-       connect_block(&nodes[0], &Block { header, txdata: vec![node_txn[1].clone()]});
+       connect_block(&nodes[0], &create_dummy_block(nodes[0].best_block_hash(), 42, vec![node_txn[1].clone()]));
 
        if confirm_commitment_tx {
                connect_blocks(&nodes[0], BREAKDOWN_TIMEOUT as u32 - 1);
        }
 
-       header.prev_blockhash = nodes[0].best_block_hash();
-       let claim_block = Block { header, txdata: if payment_timeout { timeout_txn } else { vec![claim_txn[0].clone()] } };
+       let claim_block = create_dummy_block(nodes[0].best_block_hash(), 42, if payment_timeout { timeout_txn } else { vec![claim_txn[0].clone()] });
 
        if payment_timeout {
                assert!(confirm_commitment_tx); // Otherwise we're spending below our CSV!
@@ -864,7 +859,7 @@ fn get_ldk_payment_preimage() {
        let route = get_route(
                &nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(),
                Some(&nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()),
-               amt_msat, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
+               amt_msat, nodes[0].logger, &scorer, &(), &random_seed_bytes).unwrap();
        nodes[0].node.send_payment_with_route(&route, payment_hash,
                RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
        check_added_monitors!(nodes[0], 1);
@@ -1418,7 +1413,7 @@ fn do_test_intercepted_payment(test: InterceptTest) {
        let route = get_route(
                &nodes[0].node.get_our_node_id(), &route_params.payment_params,
                &nodes[0].network_graph.read_only(), None, route_params.final_value_msat,
-               nodes[0].logger, &scorer, &random_seed_bytes,
+               nodes[0].logger, &scorer, &(), &random_seed_bytes,
        ).unwrap();
 
        let (payment_hash, payment_secret) = nodes[2].node.create_inbound_payment(Some(amt_msat), 60 * 60, None).unwrap();
@@ -1522,10 +1517,7 @@ fn do_test_intercepted_payment(test: InterceptTest) {
                        _ => panic!("Unexpected event")
                }
        } else if test == InterceptTest::Timeout {
-               let mut block = Block {
-                       header: BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
-                       txdata: vec![],
-               };
+               let mut block = create_dummy_block(nodes[0].best_block_hash(), 42, Vec::new());
                connect_block(&nodes[0], &block);
                connect_block(&nodes[1], &block);
                for _ in 0..TEST_FINAL_CLTV {
index 2fcfb713c23f5105762c48c3e42062aacb6960b0..3cb6a55f2e80ae0a8a1f717f6e03afe66a9faa64 100644 (file)
@@ -64,6 +64,20 @@ pub trait CustomMessageHandler: wire::CustomMessageReader {
        /// in the process. Each message is paired with the node id of the intended recipient. If no
        /// connection to the node exists, then the message is simply not sent.
        fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)>;
+
+       /// Gets the node feature flags which this handler itself supports. All available handlers are
+       /// queried similarly and their feature flags are OR'd together to form the [`NodeFeatures`]
+       /// which are broadcasted in our [`NodeAnnouncement`] message.
+       ///
+       /// [`NodeAnnouncement`]: crate::ln::msgs::NodeAnnouncement
+       fn provided_node_features(&self) -> NodeFeatures;
+
+       /// Gets the init feature flags which should be sent to the given peer. All available handlers
+       /// are queried similarly and their feature flags are OR'd together to form the [`InitFeatures`]
+       /// which are sent in our [`Init`] message.
+       ///
+       /// [`Init`]: crate::ln::msgs::Init
+       fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures;
 }
 
 /// A dummy struct which implements `RoutingMessageHandler` without storing any routing information
@@ -149,6 +163,12 @@ impl CustomMessageHandler for IgnoringMessageHandler {
        }
 
        fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> { Vec::new() }
+
+       fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
+
+       fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
+               InitFeatures::empty()
+       }
 }
 
 /// A dummy struct which implements `ChannelMessageHandler` without having any channels.
@@ -897,6 +917,13 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                SecretKey::from_slice(&Sha256::from_engine(ephemeral_hash).into_inner()).expect("You broke SHA-256!")
        }
 
+       fn init_features(&self, their_node_id: &PublicKey) -> InitFeatures {
+               self.message_handler.chan_handler.provided_init_features(their_node_id)
+                       | self.message_handler.route_handler.provided_init_features(their_node_id)
+                       | self.message_handler.onion_message_handler.provided_init_features(their_node_id)
+                       | self.message_handler.custom_message_handler.provided_init_features(their_node_id)
+       }
+
        /// Indicates a new outbound connection has been established to a node with the given `node_id`
        /// and an optional remote network address.
        ///
@@ -1292,9 +1319,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 
                                                                peer.set_their_node_id(their_node_id);
                                                                insert_node_id!();
-                                                               let features = self.message_handler.chan_handler.provided_init_features(&their_node_id)
-                                                                       .or(self.message_handler.route_handler.provided_init_features(&their_node_id))
-                                                                       .or(self.message_handler.onion_message_handler.provided_init_features(&their_node_id));
+                                                               let features = self.init_features(&their_node_id);
                                                                let resp = msgs::Init { features, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
                                                                self.enqueue_message(peer, &resp);
                                                                peer.awaiting_pong_timer_tick_intervals = 0;
@@ -1306,9 +1331,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                                                                peer.pending_read_is_header = true;
                                                                peer.set_their_node_id(their_node_id);
                                                                insert_node_id!();
-                                                               let features = self.message_handler.chan_handler.provided_init_features(&their_node_id)
-                                                                       .or(self.message_handler.route_handler.provided_init_features(&their_node_id))
-                                                                       .or(self.message_handler.onion_message_handler.provided_init_features(&their_node_id));
+                                                               let features = self.init_features(&their_node_id);
                                                                let resp = msgs::Init { features, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
                                                                self.enqueue_message(peer, &resp);
                                                                peer.awaiting_pong_timer_tick_intervals = 0;
@@ -1425,10 +1448,17 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 
                // Need an Init as first message
                if let wire::Message::Init(msg) = message {
-                       if msg.features.requires_unknown_bits() {
-                               log_debug!(self.logger, "Peer features required unknown version bits");
+                       let our_features = self.init_features(&their_node_id);
+                       if msg.features.requires_unknown_bits_from(&our_features) {
+                               log_debug!(self.logger, "Peer requires features unknown to us");
+                               return Err(PeerHandleError { }.into());
+                       }
+
+                       if our_features.requires_unknown_bits_from(&msg.features) {
+                               log_debug!(self.logger, "We require features unknown to our peer");
                                return Err(PeerHandleError { }.into());
                        }
+
                        if peer_lock.their_features.is_some() {
                                return Err(PeerHandleError { }.into());
                        }
@@ -2345,8 +2375,9 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                addresses.sort_by_key(|addr| addr.get_id());
 
                let features = self.message_handler.chan_handler.provided_node_features()
-                       .or(self.message_handler.route_handler.provided_node_features())
-                       .or(self.message_handler.onion_message_handler.provided_node_features());
+                       | self.message_handler.route_handler.provided_node_features()
+                       | self.message_handler.onion_message_handler.provided_node_features()
+                       | self.message_handler.custom_message_handler.provided_node_features();
                let announcement = msgs::UnsignedNodeAnnouncement {
                        features,
                        timestamp: self.last_node_announcement_serial.fetch_add(1, Ordering::AcqRel),
@@ -2395,16 +2426,19 @@ fn is_gossip_msg(type_id: u16) -> bool {
 mod tests {
        use crate::sign::{NodeSigner, Recipient};
        use crate::events;
+       use crate::io;
+       use crate::ln::features::{InitFeatures, NodeFeatures};
        use crate::ln::peer_channel_encryptor::PeerChannelEncryptor;
-       use crate::ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor, IgnoringMessageHandler, filter_addresses};
+       use crate::ln::peer_handler::{CustomMessageHandler, PeerManager, MessageHandler, SocketDescriptor, IgnoringMessageHandler, filter_addresses};
        use crate::ln::{msgs, wire};
-       use crate::ln::msgs::NetAddress;
+       use crate::ln::msgs::{LightningError, NetAddress};
        use crate::util::test_utils;
 
-       use bitcoin::secp256k1::SecretKey;
+       use bitcoin::secp256k1::{PublicKey, SecretKey};
 
        use crate::prelude::*;
        use crate::sync::{Arc, Mutex};
+       use core::convert::Infallible;
        use core::sync::atomic::{AtomicBool, Ordering};
 
        #[derive(Clone)]
@@ -2437,19 +2471,74 @@ mod tests {
        struct PeerManagerCfg {
                chan_handler: test_utils::TestChannelMessageHandler,
                routing_handler: test_utils::TestRoutingMessageHandler,
+               custom_handler: TestCustomMessageHandler,
                logger: test_utils::TestLogger,
                node_signer: test_utils::TestNodeSigner,
        }
 
+       struct TestCustomMessageHandler {
+               features: InitFeatures,
+       }
+
+       impl wire::CustomMessageReader for TestCustomMessageHandler {
+               type CustomMessage = Infallible;
+               fn read<R: io::Read>(&self, _: u16, _: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError> {
+                       Ok(None)
+               }
+       }
+
+       impl CustomMessageHandler for TestCustomMessageHandler {
+               fn handle_custom_message(&self, _: Infallible, _: &PublicKey) -> Result<(), LightningError> {
+                       unreachable!();
+               }
+
+               fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> { Vec::new() }
+
+               fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
+
+               fn provided_init_features(&self, _: &PublicKey) -> InitFeatures {
+                       self.features.clone()
+               }
+       }
+
        fn create_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
                let mut cfgs = Vec::new();
                for i in 0..peer_count {
                        let node_secret = SecretKey::from_slice(&[42 + i as u8; 32]).unwrap();
+                       let features = {
+                               let mut feature_bits = vec![0u8; 33];
+                               feature_bits[32] = 0b00000001;
+                               InitFeatures::from_le_bytes(feature_bits)
+                       };
+                       cfgs.push(
+                               PeerManagerCfg{
+                                       chan_handler: test_utils::TestChannelMessageHandler::new(),
+                                       logger: test_utils::TestLogger::new(),
+                                       routing_handler: test_utils::TestRoutingMessageHandler::new(),
+                                       custom_handler: TestCustomMessageHandler { features },
+                                       node_signer: test_utils::TestNodeSigner::new(node_secret),
+                               }
+                       );
+               }
+
+               cfgs
+       }
+
+       fn create_incompatible_peermgr_cfgs(peer_count: usize) -> Vec<PeerManagerCfg> {
+               let mut cfgs = Vec::new();
+               for i in 0..peer_count {
+                       let node_secret = SecretKey::from_slice(&[42 + i as u8; 32]).unwrap();
+                       let features = {
+                               let mut feature_bits = vec![0u8; 33 + i + 1];
+                               feature_bits[33 + i] = 0b00000001;
+                               InitFeatures::from_le_bytes(feature_bits)
+                       };
                        cfgs.push(
                                PeerManagerCfg{
                                        chan_handler: test_utils::TestChannelMessageHandler::new(),
                                        logger: test_utils::TestLogger::new(),
                                        routing_handler: test_utils::TestRoutingMessageHandler::new(),
+                                       custom_handler: TestCustomMessageHandler { features },
                                        node_signer: test_utils::TestNodeSigner::new(node_secret),
                                }
                        );
@@ -2458,13 +2547,13 @@ mod tests {
                cfgs
        }
 
-       fn create_network<'a>(peer_count: usize, cfgs: &'a Vec<PeerManagerCfg>) -> Vec<PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, IgnoringMessageHandler, &'a test_utils::TestNodeSigner>> {
+       fn create_network<'a>(peer_count: usize, cfgs: &'a Vec<PeerManagerCfg>) -> Vec<PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, &'a TestCustomMessageHandler, &'a test_utils::TestNodeSigner>> {
                let mut peers = Vec::new();
                for i in 0..peer_count {
                        let ephemeral_bytes = [i as u8; 32];
                        let msg_handler = MessageHandler {
                                chan_handler: &cfgs[i].chan_handler, route_handler: &cfgs[i].routing_handler,
-                               onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: IgnoringMessageHandler {}
+                               onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: &cfgs[i].custom_handler
                        };
                        let peer = PeerManager::new(msg_handler, 0, &ephemeral_bytes, &cfgs[i].logger, &cfgs[i].node_signer);
                        peers.push(peer);
@@ -2473,7 +2562,7 @@ mod tests {
                peers
        }
 
-       fn establish_connection<'a>(peer_a: &PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, IgnoringMessageHandler, &'a test_utils::TestNodeSigner>, peer_b: &PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, IgnoringMessageHandler, &'a test_utils::TestNodeSigner>) -> (FileDescriptor, FileDescriptor) {
+       fn establish_connection<'a>(peer_a: &PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, &'a TestCustomMessageHandler, &'a test_utils::TestNodeSigner>, peer_b: &PeerManager<FileDescriptor, &'a test_utils::TestChannelMessageHandler, &'a test_utils::TestRoutingMessageHandler, IgnoringMessageHandler, &'a test_utils::TestLogger, &'a TestCustomMessageHandler, &'a test_utils::TestNodeSigner>) -> (FileDescriptor, FileDescriptor) {
                let id_a = peer_a.node_signer.get_node_id(Recipient::Node).unwrap();
                let mut fd_a = FileDescriptor {
                        fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
@@ -2588,6 +2677,42 @@ mod tests {
                thrd_b.join().unwrap();
        }
 
+       #[test]
+       fn test_incompatible_peers() {
+               let cfgs = create_peermgr_cfgs(2);
+               let incompatible_cfgs = create_incompatible_peermgr_cfgs(2);
+
+               let peers = create_network(2, &cfgs);
+               let incompatible_peers = create_network(2, &incompatible_cfgs);
+               let peer_pairs = [(&peers[0], &incompatible_peers[0]), (&incompatible_peers[1], &peers[1])];
+               for (peer_a, peer_b) in peer_pairs.iter() {
+                       let id_a = peer_a.node_signer.get_node_id(Recipient::Node).unwrap();
+                       let mut fd_a = FileDescriptor {
+                               fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
+                               disconnect: Arc::new(AtomicBool::new(false)),
+                       };
+                       let addr_a = NetAddress::IPv4{addr: [127, 0, 0, 1], port: 1000};
+                       let mut fd_b = FileDescriptor {
+                               fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())),
+                               disconnect: Arc::new(AtomicBool::new(false)),
+                       };
+                       let addr_b = NetAddress::IPv4{addr: [127, 0, 0, 1], port: 1001};
+                       let initial_data = peer_b.new_outbound_connection(id_a, fd_b.clone(), Some(addr_a.clone())).unwrap();
+                       peer_a.new_inbound_connection(fd_a.clone(), Some(addr_b.clone())).unwrap();
+                       assert_eq!(peer_a.read_event(&mut fd_a, &initial_data).unwrap(), false);
+                       peer_a.process_events();
+
+                       let a_data = fd_a.outbound_data.lock().unwrap().split_off(0);
+                       assert_eq!(peer_b.read_event(&mut fd_b, &a_data).unwrap(), false);
+
+                       peer_b.process_events();
+                       let b_data = fd_b.outbound_data.lock().unwrap().split_off(0);
+
+                       // Should fail because of unknown required features
+                       assert!(peer_a.read_event(&mut fd_a, &b_data).is_err());
+               }
+       }
+
        #[test]
        fn test_disconnect_peer() {
                // Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and
index e8f0c1259437142a31f3f3481e788fe031786ba9..633eceddbd8721c19e5623cbc334bc648e57362d 100644 (file)
@@ -19,14 +19,11 @@ use crate::util::test_utils;
 use crate::util::ser::Writeable;
 use crate::util::string::UntrustedString;
 
-use bitcoin::blockdata::block::{Block, BlockHeader};
 use bitcoin::blockdata::script::Builder;
 use bitcoin::blockdata::opcodes;
 use bitcoin::secp256k1::Secp256k1;
 
 use crate::prelude::*;
-use bitcoin::hashes::Hash;
-use bitcoin::TxMerkleNode;
 
 use crate::ln::functional_test_utils::*;
 
@@ -67,7 +64,6 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) {
        check_added_monitors!(nodes[2], 1);
        get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
 
-       let mut header = BlockHeader { version: 0x2000_0000, prev_blockhash: nodes[2].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
        let claim_txn = if local_commitment {
                // Broadcast node 1 commitment txn to broadcast the HTLC-Timeout
                let node_1_commitment_txn = get_local_commitment_txn!(nodes[1], chan_2.2);
@@ -77,7 +73,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) {
                check_spends!(node_1_commitment_txn[1], node_1_commitment_txn[0]);
 
                // Give node 2 node 1's transactions and get its response (claiming the HTLC instead).
-               connect_block(&nodes[2], &Block { header, txdata: node_1_commitment_txn.clone() });
+               connect_block(&nodes[2], &create_dummy_block(nodes[2].best_block_hash(), 42, node_1_commitment_txn.clone()));
                check_added_monitors!(nodes[2], 1);
                check_closed_broadcast!(nodes[2], true); // We should get a BroadcastChannelUpdate (and *only* a BroadcstChannelUpdate)
                check_closed_event!(nodes[2], 1, ClosureReason::CommitmentTxConfirmed);
@@ -88,8 +84,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) {
                // Make sure node 1's height is the same as the !local_commitment case
                connect_blocks(&nodes[1], 1);
                // Confirm node 1's commitment txn (and HTLC-Timeout) on node 1
-               header.prev_blockhash = nodes[1].best_block_hash();
-               connect_block(&nodes[1], &Block { header, txdata: node_1_commitment_txn.clone() });
+               connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, node_1_commitment_txn.clone()));
 
                // ...but return node 1's commitment tx in case claim is set and we're preparing to reorg
                vec![node_1_commitment_txn[0].clone(), node_2_commitment_txn[0].clone()]
@@ -125,11 +120,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) {
                // Disconnect Node 1's HTLC-Timeout which was connected above
                disconnect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
 
-               let block = Block {
-                       header: BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
-                       txdata: claim_txn,
-               };
-               connect_block(&nodes[1], &block);
+               connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, claim_txn));
 
                // ChannelManager only polls chain::Watch::release_pending_monitor_events when we
                // probe it for events, so we probe non-message events here (which should just be the
@@ -137,11 +128,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) {
                expect_payment_forwarded!(nodes[1], nodes[0], nodes[2], Some(1000), true, true);
        } else {
                // Confirm the timeout tx and check that we fail the HTLC backwards
-               let block = Block {
-                       header: BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
-                       txdata: vec![],
-               };
-               connect_block(&nodes[1], &block);
+               connect_block(&nodes[1], &create_dummy_block(nodes[1].best_block_hash(), 42, Vec::new()));
                expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], vec![HTLCDestination::NextHopChannel { node_id: Some(nodes[2].node.get_our_node_id()), channel_id: chan_2.2 }]);
        }
 
@@ -587,7 +574,7 @@ fn do_test_to_remote_after_local_detection(style: ConnectStyle) {
        if let Event::SpendableOutputs { outputs } = node_a_spendable.pop().unwrap() {
                assert_eq!(outputs.len(), 1);
                let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
-                       Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
+                       Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &Secp256k1::new()).unwrap();
                check_spends!(spend_tx, remote_txn_b[0]);
        }
 
@@ -607,7 +594,7 @@ fn do_test_to_remote_after_local_detection(style: ConnectStyle) {
        if let Event::SpendableOutputs { outputs } = node_b_spendable.pop().unwrap() {
                assert_eq!(outputs.len(), 1);
                let spend_tx = nodes[1].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
-                       Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
+                       Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &Secp256k1::new()).unwrap();
                check_spends!(spend_tx, remote_txn_a[0]);
        }
 }
index 81a02f8a4b8c83979941194b56b8f17c5079c02c..1063bf76c2dab6749635168fd5c0dfe766cf1451 100644 (file)
@@ -95,9 +95,9 @@ fn updates_shutdown_wait() {
        let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[0]);
 
        let payment_params_1 = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV).with_bolt11_features(nodes[1].node.invoice_features()).unwrap();
-       let route_1 = get_route(&nodes[0].node.get_our_node_id(), &payment_params_1, &nodes[0].network_graph.read_only(), None, 100000, &logger, &scorer, &random_seed_bytes).unwrap();
+       let route_1 = get_route(&nodes[0].node.get_our_node_id(), &payment_params_1, &nodes[0].network_graph.read_only(), None, 100000, &logger, &scorer, &(), &random_seed_bytes).unwrap();
        let payment_params_2 = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id(), TEST_FINAL_CLTV).with_bolt11_features(nodes[0].node.invoice_features()).unwrap();
-       let route_2 = get_route(&nodes[1].node.get_our_node_id(), &payment_params_2, &nodes[1].network_graph.read_only(), None, 100000, &logger, &scorer, &random_seed_bytes).unwrap();
+       let route_2 = get_route(&nodes[1].node.get_our_node_id(), &payment_params_2, &nodes[1].network_graph.read_only(), None, 100000, &logger, &scorer, &(), &random_seed_bytes).unwrap();
        unwrap_send_err!(nodes[0].node.send_payment_with_route(&route_1, payment_hash,
                        RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)
                ), true, APIError::ChannelUnavailable {..}, {});
index 8eaf8ad163e2eaacdcaa768c1fad905be41670f7..98fcdb680ee03abd1f2c8f3730c0b740bb75977f 100644 (file)
@@ -20,6 +20,7 @@ use crate::util::test_utils;
 use bitcoin::network::constants::Network;
 use bitcoin::secp256k1::{PublicKey, Secp256k1};
 
+use core::sync::atomic::{AtomicU16, Ordering};
 use crate::io;
 use crate::io_extras::read_to_end;
 use crate::sync::Arc;
@@ -27,6 +28,7 @@ use crate::sync::Arc;
 struct MessengerNode {
        keys_manager: Arc<test_utils::TestKeysInterface>,
        messenger: OnionMessenger<Arc<test_utils::TestKeysInterface>, Arc<test_utils::TestKeysInterface>, Arc<test_utils::TestLogger>, Arc<TestCustomMessageHandler>>,
+       custom_message_handler: Arc<TestCustomMessageHandler>,
        logger: Arc<test_utils::TestLogger>,
 }
 
@@ -54,11 +56,32 @@ impl Writeable for TestCustomMessage {
        }
 }
 
-struct TestCustomMessageHandler {}
+struct TestCustomMessageHandler {
+       num_messages_expected: AtomicU16,
+}
+
+impl TestCustomMessageHandler {
+       fn new() -> Self {
+               Self { num_messages_expected: AtomicU16::new(0) }
+       }
+}
+
+impl Drop for TestCustomMessageHandler {
+       fn drop(&mut self) {
+               #[cfg(feature = "std")] {
+                       if std::thread::panicking() {
+                               return;
+                       }
+               }
+               assert_eq!(self.num_messages_expected.load(Ordering::SeqCst), 0);
+       }
+}
 
 impl CustomOnionMessageHandler for TestCustomMessageHandler {
        type CustomMessage = TestCustomMessage;
-       fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
+       fn handle_custom_message(&self, _msg: Self::CustomMessage) {
+               self.num_messages_expected.fetch_sub(1, Ordering::SeqCst);
+       }
        fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
                if message_type == CUSTOM_MESSAGE_TYPE {
                        let buf = read_to_end(buffer)?;
@@ -75,9 +98,11 @@ fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
                let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i)));
                let seed = [i as u8; 32];
                let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet));
+               let custom_message_handler = Arc::new(TestCustomMessageHandler::new());
                nodes.push(MessengerNode {
                        keys_manager: keys_manager.clone(),
-                       messenger: OnionMessenger::new(keys_manager.clone(), keys_manager.clone(), logger.clone(), Arc::new(TestCustomMessageHandler {})),
+                       messenger: OnionMessenger::new(keys_manager.clone(), keys_manager.clone(), logger.clone(), custom_message_handler.clone()),
+                       custom_message_handler,
                        logger,
                });
        }
@@ -92,10 +117,10 @@ fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
        nodes
 }
 
-fn pass_along_path(path: &Vec<MessengerNode>, expected_path_id: Option<[u8; 32]>) {
+fn pass_along_path(path: &Vec<MessengerNode>) {
+       path[path.len() - 1].custom_message_handler.num_messages_expected.fetch_add(1, Ordering::SeqCst);
        let mut prev_node = &path[0];
-       let num_nodes = path.len();
-       for (idx, node) in path.into_iter().skip(1).enumerate() {
+       for node in path.into_iter().skip(1) {
                let events = prev_node.messenger.release_pending_msgs();
                let onion_msg =  {
                        let msgs = events.get(&node.get_node_pk()).unwrap();
@@ -103,11 +128,6 @@ fn pass_along_path(path: &Vec<MessengerNode>, expected_path_id: Option<[u8; 32]>
                        msgs[0].clone()
                };
                node.messenger.handle_onion_message(&prev_node.get_node_pk(), &onion_msg);
-               if idx == num_nodes - 1 {
-                       node.logger.assert_log_contains(
-                               "lightning::onion_message::messenger",
-                               &format!("Received an onion message with path_id: {:02x?}", expected_path_id), 1);
-               }
                prev_node = node;
        }
 }
@@ -118,7 +138,7 @@ fn one_hop() {
        let test_msg = OnionMessageContents::Custom(TestCustomMessage {});
 
        nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_msg, None).unwrap();
-       pass_along_path(&nodes, None);
+       pass_along_path(&nodes);
 }
 
 #[test]
@@ -127,7 +147,7 @@ fn two_unblinded_hops() {
        let test_msg = OnionMessageContents::Custom(TestCustomMessage {});
 
        nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), test_msg, None).unwrap();
-       pass_along_path(&nodes, None);
+       pass_along_path(&nodes);
 }
 
 #[test]
@@ -139,7 +159,7 @@ fn two_unblinded_two_blinded() {
        let blinded_path = BlindedPath::new_for_message(&[nodes[3].get_node_pk(), nodes[4].get_node_pk()], &*nodes[4].keys_manager, &secp_ctx).unwrap();
 
        nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedPath(blinded_path), test_msg, None).unwrap();
-       pass_along_path(&nodes, None);
+       pass_along_path(&nodes);
 }
 
 #[test]
@@ -151,7 +171,7 @@ fn three_blinded_hops() {
        let blinded_path = BlindedPath::new_for_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
 
        nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), test_msg, None).unwrap();
-       pass_along_path(&nodes, None);
+       pass_along_path(&nodes);
 }
 
 #[test]
@@ -177,13 +197,13 @@ fn we_are_intro_node() {
        let blinded_path = BlindedPath::new_for_message(&[nodes[0].get_node_pk(), nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
 
        nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg.clone()), None).unwrap();
-       pass_along_path(&nodes, None);
+       pass_along_path(&nodes);
 
        // Try with a two-hop blinded path where we are the introduction node.
        let blinded_path = BlindedPath::new_for_message(&[nodes[0].get_node_pk(), nodes[1].get_node_pk()], &*nodes[1].keys_manager, &secp_ctx).unwrap();
        nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg), None).unwrap();
        nodes.remove(2);
-       pass_along_path(&nodes, None);
+       pass_along_path(&nodes);
 }
 
 #[test]
@@ -216,7 +236,7 @@ fn reply_path() {
        // Destination::Node
        let reply_path = BlindedPath::new_for_message(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
        nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), OnionMessageContents::Custom(test_msg.clone()), Some(reply_path)).unwrap();
-       pass_along_path(&nodes, None);
+       pass_along_path(&nodes);
        // Make sure the last node successfully decoded the reply path.
        nodes[3].logger.assert_log_contains(
                "lightning::onion_message::messenger",
@@ -227,7 +247,7 @@ fn reply_path() {
        let reply_path = BlindedPath::new_for_message(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
 
        nodes[0].messenger.send_onion_message(&[], Destination::BlindedPath(blinded_path), OnionMessageContents::Custom(test_msg), Some(reply_path)).unwrap();
-       pass_along_path(&nodes, None);
+       pass_along_path(&nodes);
        nodes[3].logger.assert_log_contains(
                "lightning::onion_message::messenger",
                &format!("Received an onion message with path_id None and a reply_path"), 2);
@@ -264,3 +284,20 @@ fn peer_buffer_full() {
        let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), OnionMessageContents::Custom(test_msg), None).unwrap_err();
        assert_eq!(err, SendError::BufferFull);
 }
+
+#[test]
+fn many_hops() {
+       // Check we can send over a route with many hops. This will exercise our logic for onion messages
+       // of size [`crate::onion_message::packet::BIG_PACKET_HOP_DATA_LEN`].
+       let num_nodes: usize = 25;
+       let nodes = create_nodes(num_nodes as u8);
+       let test_msg = OnionMessageContents::Custom(TestCustomMessage {});
+
+       let mut intermediates = vec![];
+       for i in 1..(num_nodes-1) {
+               intermediates.push(nodes[i].get_node_pk());
+       }
+
+       nodes[0].messenger.send_onion_message(&intermediates, Destination::Node(nodes[num_nodes-1].get_node_pk()), test_msg, None).unwrap();
+       pass_along_path(&nodes);
+}
index 8295e8f88de66765a89a260f34c82876811da374..5171422cb895ac45ace605871fb44c0630104e41 100644 (file)
@@ -567,6 +567,6 @@ fn construct_onion_message_packet<T: CustomOnionMessageContents>(payloads: Vec<(
                BIG_PACKET_HOP_DATA_LEN
        } else { return Err(()) };
 
-       Ok(onion_utils::construct_onion_message_packet::<_, _>(
-               payloads, onion_keys, prng_seed, hop_data_len))
+       onion_utils::construct_onion_message_packet::<_, _>(
+               payloads, onion_keys, prng_seed, hop_data_len)
 }
index 90ead987e7c99c4c8079f57a4c9f91ea4485fb64..f134bd0569e9905cf7a54b5359215c6b434ae4d0 100644 (file)
@@ -40,7 +40,7 @@ use crate::io_extras::{copy, sink};
 use crate::prelude::*;
 use core::{cmp, fmt};
 use core::convert::TryFrom;
-use crate::sync::{RwLock, RwLockReadGuard};
+use crate::sync::{RwLock, RwLockReadGuard, LockTestExt};
 #[cfg(feature = "std")]
 use core::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::Mutex;
@@ -1056,7 +1056,7 @@ impl EffectiveCapacity {
 }
 
 /// Fees for routing via a given channel or a node
-#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
+#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash, Ord, PartialOrd)]
 pub struct RoutingFees {
        /// Flat routing fee in millisatoshis.
        pub base_msat: u32,
@@ -1327,9 +1327,14 @@ impl<L: Deref> fmt::Display for NetworkGraph<L> where L::Target: Logger {
 impl<L: Deref> Eq for NetworkGraph<L> where L::Target: Logger {}
 impl<L: Deref> PartialEq for NetworkGraph<L> where L::Target: Logger {
        fn eq(&self, other: &Self) -> bool {
-               self.genesis_hash == other.genesis_hash &&
-                       *self.channels.read().unwrap() == *other.channels.read().unwrap() &&
-                       *self.nodes.read().unwrap() == *other.nodes.read().unwrap()
+               // For a total lockorder, sort by position in memory and take the inner locks in that order.
+               // (Assumes that we can't move within memory while a lock is held).
+               let ord = ((self as *const _) as usize) < ((other as *const _) as usize);
+               let a = if ord { (&self.channels, &self.nodes) } else { (&other.channels, &other.nodes) };
+               let b = if ord { (&other.channels, &other.nodes) } else { (&self.channels, &self.nodes) };
+               let (channels_a, channels_b) = (a.0.unsafe_well_ordered_double_lock_self(), b.0.unsafe_well_ordered_double_lock_self());
+               let (nodes_a, nodes_b) = (a.1.unsafe_well_ordered_double_lock_self(), b.1.unsafe_well_ordered_double_lock_self());
+               self.genesis_hash.eq(&other.genesis_hash) && channels_a.eq(&channels_b) && nodes_a.eq(&nodes_b)
        }
 }
 
@@ -3388,31 +3393,28 @@ pub(crate) mod tests {
        }
 }
 
-#[cfg(all(test, feature = "_bench_unstable"))]
-mod benches {
+#[cfg(ldk_bench)]
+pub mod benches {
        use super::*;
-
-       use test::Bencher;
        use std::io::Read;
+       use criterion::{black_box, Criterion};
 
-       #[bench]
-       fn read_network_graph(bench: &mut Bencher) {
+       pub fn read_network_graph(bench: &mut Criterion) {
                let logger = crate::util::test_utils::TestLogger::new();
                let mut d = crate::routing::router::bench_utils::get_route_file().unwrap();
                let mut v = Vec::new();
                d.read_to_end(&mut v).unwrap();
-               bench.iter(|| {
-                       let _ = NetworkGraph::read(&mut std::io::Cursor::new(&v), &logger).unwrap();
-               });
+               bench.bench_function("read_network_graph", |b| b.iter(||
+                       NetworkGraph::read(&mut std::io::Cursor::new(black_box(&v)), &logger).unwrap()
+               ));
        }
 
-       #[bench]
-       fn write_network_graph(bench: &mut Bencher) {
+       pub fn write_network_graph(bench: &mut Criterion) {
                let logger = crate::util::test_utils::TestLogger::new();
                let mut d = crate::routing::router::bench_utils::get_route_file().unwrap();
                let net_graph = NetworkGraph::read(&mut d, &logger).unwrap();
-               bench.iter(|| {
-                       let _ = net_graph.encode();
-               });
+               bench.bench_function("write_network_graph", |b| b.iter(||
+                       black_box(&net_graph).encode()
+               ));
        }
 }
index 46010475cebfd56550ef06ede0cba4824265684a..ef6fef0a7eb42ea87b8d0876f0b11f99112d83cb 100644 (file)
@@ -27,39 +27,43 @@ use crate::util::chacha20::ChaCha20;
 
 use crate::io;
 use crate::prelude::*;
-use crate::sync::Mutex;
+use crate::sync::{Mutex, MutexGuard};
 use alloc::collections::BinaryHeap;
 use core::{cmp, fmt};
 use core::ops::Deref;
 
 /// A [`Router`] implemented using [`find_route`].
-pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> where
+pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> where
        L::Target: Logger,
-       S::Target: for <'a> LockableScore<'a>,
+       S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
 {
        network_graph: G,
        logger: L,
        random_seed_bytes: Mutex<[u8; 32]>,
-       scorer: S
+       scorer: S,
+       score_params: SP
 }
 
-impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> DefaultRouter<G, L, S> where
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> DefaultRouter<G, L, S, SP, Sc> where
        L::Target: Logger,
-       S::Target: for <'a> LockableScore<'a>,
+       S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
 {
        /// Creates a new router.
-       pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S) -> Self {
+       pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S, score_params: SP) -> Self {
                let random_seed_bytes = Mutex::new(random_seed_bytes);
-               Self { network_graph, logger, random_seed_bytes, scorer }
+               Self { network_graph, logger, random_seed_bytes, scorer, score_params }
        }
 }
 
-impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> Router for DefaultRouter<G, L, S> where
+impl< G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref,  SP: Sized, Sc: Score<ScoreParams = SP>> Router for DefaultRouter<G, L, S, SP, Sc> where
        L::Target: Logger,
-       S::Target: for <'a> LockableScore<'a>,
+       S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
 {
        fn find_route(
-               &self, payer: &PublicKey, params: &RouteParameters, first_hops: Option<&[&ChannelDetails]>,
+               &self,
+               payer: &PublicKey,
+               params: &RouteParameters,
+               first_hops: Option<&[&ChannelDetails]>,
                inflight_htlcs: &InFlightHtlcs
        ) -> Result<Route, LightningError> {
                let random_seed_bytes = {
@@ -67,10 +71,10 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> Router for DefaultR
                        *locked_random_seed_bytes = Sha256::hash(&*locked_random_seed_bytes).into_inner();
                        *locked_random_seed_bytes
                };
-
                find_route(
                        payer, params, &self.network_graph, first_hops, &*self.logger,
                        &ScorerAccountingForInFlightHtlcs::new(self.scorer.lock(), inflight_htlcs),
+                       &self.score_params,
                        &random_seed_bytes
                )
        }
@@ -122,7 +126,8 @@ impl<'a, S: Score> Writeable for ScorerAccountingForInFlightHtlcs<'a, S> {
 }
 
 impl<'a, S: Score> Score for ScorerAccountingForInFlightHtlcs<'a, S> {
-       fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
+       type ScoreParams = S::ScoreParams;
+       fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams) -> u64 {
                if let Some(used_liquidity) = self.inflight_htlcs.used_liquidity_msat(
                        source, target, short_channel_id
                ) {
@@ -131,9 +136,9 @@ impl<'a, S: Score> Score for ScorerAccountingForInFlightHtlcs<'a, S> {
                                ..usage
                        };
 
-                       self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
+                       self.scorer.channel_penalty_msat(short_channel_id, source, target, usage, score_params)
                } else {
-                       self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
+                       self.scorer.channel_penalty_msat(short_channel_id, source, target, usage, score_params)
                }
        }
 
@@ -789,7 +794,7 @@ impl ReadableArgs<bool> for Features {
 }
 
 /// A list of hops along a payment path terminating with a channel to the recipient.
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub struct RouteHint(pub Vec<RouteHintHop>);
 
 impl Writeable for RouteHint {
@@ -814,7 +819,7 @@ impl Readable for RouteHint {
 }
 
 /// A channel descriptor for a hop along a payment path.
-#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
 pub struct RouteHintHop {
        /// The node_id of the non-target end of the route
        pub src_node_id: PublicKey,
@@ -1010,7 +1015,7 @@ struct PathBuildingHop<'a> {
        /// decrease as well. Thus, we have to explicitly track which nodes have been processed and
        /// avoid processing them again.
        was_processed: bool,
-       #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))]
+       #[cfg(all(not(ldk_bench), any(test, fuzzing)))]
        // In tests, we apply further sanity checks on cases where we skip nodes we already processed
        // to ensure it is specifically in cases where the fee has gone down because of a decrease in
        // value_contribution_msat, which requires tracking it here. See comments below where it is
@@ -1031,7 +1036,7 @@ impl<'a> core::fmt::Debug for PathBuildingHop<'a> {
                        .field("path_penalty_msat", &self.path_penalty_msat)
                        .field("path_htlc_minimum_msat", &self.path_htlc_minimum_msat)
                        .field("cltv_expiry_delta", &self.candidate.cltv_expiry_delta());
-               #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))]
+               #[cfg(all(not(ldk_bench), any(test, fuzzing)))]
                let debug_struct = debug_struct
                        .field("value_contribution_msat", &self.value_contribution_msat);
                debug_struct.finish()
@@ -1219,12 +1224,12 @@ impl fmt::Display for LoggedPayeePubkey {
 pub fn find_route<L: Deref, GL: Deref, S: Score>(
        our_node_pubkey: &PublicKey, route_params: &RouteParameters,
        network_graph: &NetworkGraph<GL>, first_hops: Option<&[&ChannelDetails]>, logger: L,
-       scorer: &S, random_seed_bytes: &[u8; 32]
+       scorer: &S, score_params: &S::ScoreParams, random_seed_bytes: &[u8; 32]
 ) -> Result<Route, LightningError>
 where L::Target: Logger, GL::Target: Logger {
        let graph_lock = network_graph.read_only();
        let mut route = get_route(our_node_pubkey, &route_params.payment_params, &graph_lock, first_hops,
-               route_params.final_value_msat, logger, scorer,
+               route_params.final_value_msat, logger, scorer, score_params,
                random_seed_bytes)?;
        add_random_cltv_offset(&mut route, &route_params.payment_params, &graph_lock, random_seed_bytes);
        Ok(route)
@@ -1232,7 +1237,7 @@ where L::Target: Logger, GL::Target: Logger {
 
 pub(crate) fn get_route<L: Deref, S: Score>(
        our_node_pubkey: &PublicKey, payment_params: &PaymentParameters, network_graph: &ReadOnlyNetworkGraph,
-       first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, logger: L, scorer: &S,
+       first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, logger: L, scorer: &S, score_params: &S::ScoreParams,
        _random_seed_bytes: &[u8; 32]
 ) -> Result<Route, LightningError>
 where L::Target: Logger {
@@ -1565,14 +1570,14 @@ where L::Target: Logger {
                                                                path_htlc_minimum_msat,
                                                                path_penalty_msat: u64::max_value(),
                                                                was_processed: false,
-                                                               #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))]
+                                                               #[cfg(all(not(ldk_bench), any(test, fuzzing)))]
                                                                value_contribution_msat,
                                                        }
                                                });
 
                                                #[allow(unused_mut)] // We only use the mut in cfg(test)
                                                let mut should_process = !old_entry.was_processed;
-                                               #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))]
+                                               #[cfg(all(not(ldk_bench), any(test, fuzzing)))]
                                                {
                                                        // In test/fuzzing builds, we do extra checks to make sure the skipping
                                                        // of already-seen nodes only happens in cases we expect (see below).
@@ -1598,7 +1603,7 @@ where L::Target: Logger {
                                                                effective_capacity,
                                                        };
                                                        let channel_penalty_msat = scorer.channel_penalty_msat(
-                                                               short_channel_id, &$src_node_id, &$dest_node_id, channel_usage
+                                                               short_channel_id, &$src_node_id, &$dest_node_id, channel_usage, score_params
                                                        );
                                                        let path_penalty_msat = $next_hops_path_penalty_msat
                                                                .saturating_add(channel_penalty_msat);
@@ -1643,13 +1648,13 @@ where L::Target: Logger {
                                                                old_entry.fee_msat = 0; // This value will be later filled with hop_use_fee_msat of the following channel
                                                                old_entry.path_htlc_minimum_msat = path_htlc_minimum_msat;
                                                                old_entry.path_penalty_msat = path_penalty_msat;
-                                                               #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))]
+                                                               #[cfg(all(not(ldk_bench), any(test, fuzzing)))]
                                                                {
                                                                        old_entry.value_contribution_msat = value_contribution_msat;
                                                                }
                                                                did_add_update_path_to_src_node = true;
                                                        } else if old_entry.was_processed && new_cost < old_cost {
-                                                               #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))]
+                                                               #[cfg(all(not(ldk_bench), any(test, fuzzing)))]
                                                                {
                                                                        // If we're skipping processing a node which was previously
                                                                        // processed even though we found another path to it with a
@@ -1846,7 +1851,7 @@ where L::Target: Logger {
                                                effective_capacity: candidate.effective_capacity(),
                                        };
                                        let channel_penalty_msat = scorer.channel_penalty_msat(
-                                               hop.short_channel_id, &source, &target, channel_usage
+                                               hop.short_channel_id, &source, &target, channel_usage, score_params
                                        );
                                        aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat
                                                .saturating_add(channel_penalty_msat);
@@ -2343,8 +2348,9 @@ fn build_route_from_hops_internal<L: Deref>(
        }
 
        impl Score for HopScorer {
+               type ScoreParams = ();
                fn channel_penalty_msat(&self, _short_channel_id: u64, source: &NodeId, target: &NodeId,
-                       _usage: ChannelUsage) -> u64
+                       _usage: ChannelUsage, _score_params: &Self::ScoreParams) -> u64
                {
                        let mut cur_id = self.our_node_id;
                        for i in 0..self.hop_ids.len() {
@@ -2389,7 +2395,7 @@ fn build_route_from_hops_internal<L: Deref>(
        let scorer = HopScorer { our_node_id, hop_ids };
 
        get_route(our_node_pubkey, payment_params, network_graph, None, final_value_msat,
-               logger, &scorer, random_seed_bytes)
+               logger, &scorer, &(), random_seed_bytes)
 }
 
 #[cfg(test)]
@@ -2400,7 +2406,7 @@ mod tests {
        use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features,
                BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
                DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE};
-       use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringParameters};
+       use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
        use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel};
        use crate::chain::transaction::OutPoint;
        use crate::sign::EntropySource;
@@ -2479,11 +2485,11 @@ mod tests {
 
                // Simple route to 2 via 1
 
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 0, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 0, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                        assert_eq!(err, "Cannot send a payment of 0 msat");
                } else { panic!(); }
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 2);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -2515,11 +2521,11 @@ mod tests {
                let our_chans = vec![get_channel_details(Some(2), our_id, InitFeatures::from_le_bytes(vec![0b11]), 100000)];
 
                if let Err(LightningError{err, action: ErrorAction::IgnoreError}) =
-                       get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                       get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                        assert_eq!(err, "First hop cannot have our_node_pubkey as a destination.");
                } else { panic!(); }
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 2);
        }
 
@@ -2627,7 +2633,7 @@ mod tests {
                });
 
                // Not possible to send 199_999_999, because the minimum on channel=2 is 200_000_000.
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
@@ -2646,7 +2652,7 @@ mod tests {
                });
 
                // A payment above the minimum should pass
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 2);
        }
 
@@ -2728,7 +2734,7 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                // Overpay fees to hit htlc_minimum_msat.
                let overpaid_fees = route.paths[0].hops[0].fee_msat + route.paths[1].hops[0].fee_msat;
                // TODO: this could be better balanced to overpay 10k and not 15k.
@@ -2773,14 +2779,14 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                // Fine to overpay for htlc_minimum_msat if it allows us to save fee.
                assert_eq!(route.paths.len(), 1);
                assert_eq!(route.paths[0].hops[0].short_channel_id, 12);
                let fees = route.paths[0].hops[0].fee_msat;
                assert_eq!(fees, 5_000);
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                // Not fine to overpay for htlc_minimum_msat if it requires paying more than fee on
                // the other channel.
                assert_eq!(route.paths.len(), 1);
@@ -2825,13 +2831,13 @@ mod tests {
                });
 
                // If all the channels require some features we don't understand, route should fail
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 2);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[7]);
@@ -2866,13 +2872,13 @@ mod tests {
                add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[7], unknown_features.clone(), 1);
 
                // If all nodes require some features we don't understand, route should fail
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 2);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[7]);
@@ -2904,7 +2910,7 @@ mod tests {
 
                // Route to 1 via 2 and 3 because our channel to 1 is disabled
                let payment_params = PaymentParameters::from_node_id(nodes[0], 42);
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 3);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -2931,7 +2937,7 @@ mod tests {
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 2);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[7]);
@@ -3054,13 +3060,13 @@ mod tests {
                invalid_last_hops.push(invalid_last_hop);
                {
                        let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(invalid_last_hops).unwrap();
-                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Route hint cannot have the payee as the source.");
                        } else { panic!(); }
                }
 
                let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops_multi_private_channels(&nodes)).unwrap();
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 5);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -3136,7 +3142,7 @@ mod tests {
 
                // Test handling of an empty RouteHint passed in Invoice.
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 5);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -3242,7 +3248,7 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 4);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -3314,7 +3320,7 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &[42u8; 32]).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &[42u8; 32]).unwrap();
                assert_eq!(route.paths[0].hops.len(), 4);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -3396,7 +3402,7 @@ mod tests {
                // This test shows that public routes can be present in the invoice
                // which would be handled in the same manner.
 
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 5);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -3449,7 +3455,7 @@ mod tests {
                let our_chans = vec![get_channel_details(Some(42), nodes[3].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
                let mut last_hops = last_hops(&nodes);
                let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone()).unwrap();
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 2);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[3]);
@@ -3470,7 +3476,7 @@ mod tests {
 
                // Revert to via 6 as the fee on 8 goes up
                let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops).unwrap();
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 4);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -3504,7 +3510,7 @@ mod tests {
                assert_eq!(route.paths[0].hops[3].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
 
                // ...but still use 8 for larger payments as 6 has a variable feerate
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 2000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 2000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].hops.len(), 5);
 
                assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
@@ -3570,7 +3576,7 @@ mod tests {
                let logger = ln_test_utils::TestLogger::new();
                let network_graph = NetworkGraph::new(Network::Testnet, &logger);
                let route = get_route(&source_node_id, &payment_params, &network_graph.read_only(),
-                               Some(&our_chans.iter().collect::<Vec<_>>()), route_val, &logger, &scorer, &random_seed_bytes);
+                               Some(&our_chans.iter().collect::<Vec<_>>()), route_val, &logger, &scorer, &(), &random_seed_bytes);
                route
        }
 
@@ -3692,14 +3698,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 250_000_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 250_000_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
 
                {
                        // Now, attempt to route an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000_000, Arc::clone(&logger), &scorer, &(),&random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.hops.len(), 2);
@@ -3728,14 +3734,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
 
                {
                        // Now, attempt to route an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.hops.len(), 2);
@@ -3775,14 +3781,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 15_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 15_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
 
                {
                        // Now, attempt to route an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.hops.len(), 2);
@@ -3846,14 +3852,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 15_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 15_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
 
                {
                        // Now, attempt to route an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.hops.len(), 2);
@@ -3878,14 +3884,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 10_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 10_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
 
                {
                        // Now, attempt to route an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 10_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 10_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.hops.len(), 2);
@@ -3990,14 +3996,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
 
                {
                        // Now, attempt to route 49 sats (just a bit below the capacity).
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 49_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 49_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4010,7 +4016,7 @@ mod tests {
 
                {
                        // Attempt to route an exact amount is also fine
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4058,7 +4064,7 @@ mod tests {
                });
 
                {
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4173,7 +4179,7 @@ mod tests {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
                                &our_id, &payment_params, &network_graph.read_only(), None, 300_000,
-                               Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                               Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                        assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -4183,7 +4189,7 @@ mod tests {
                        let zero_payment_params = payment_params.clone().with_max_path_count(0);
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
                                &our_id, &zero_payment_params, &network_graph.read_only(), None, 100,
-                               Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                               Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                        assert_eq!(err, "Can't find a route with no paths allowed.");
                        } else { panic!(); }
                }
@@ -4195,7 +4201,7 @@ mod tests {
                        let fail_payment_params = payment_params.clone().with_max_path_count(3);
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
                                &our_id, &fail_payment_params, &network_graph.read_only(), None, 250_000,
-                               Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                               Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                        assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -4204,7 +4210,7 @@ mod tests {
                        // Now, attempt to route 250 sats (just a bit below the capacity).
                        // Our algorithm should provide us with these 3 paths.
                        let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None,
-                               250_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                               250_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4218,7 +4224,7 @@ mod tests {
                {
                        // Attempt to route an exact amount is also fine
                        let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None,
-                               290_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                               290_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4374,7 +4380,7 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 350_000, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 350_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -4382,7 +4388,7 @@ mod tests {
                {
                        // Now, attempt to route 300 sats (exact amount we can route).
                        // Our algorithm should provide us with these 3 paths, 100 sats each.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 300_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 300_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
 
                        let mut total_amount_paid_msat = 0;
@@ -4543,7 +4549,7 @@ mod tests {
                {
                        // Now, attempt to route 180 sats.
                        // Our algorithm should provide us with these 2 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 180_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 180_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
 
                        let mut total_value_transferred_msat = 0;
@@ -4714,14 +4720,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 210_000, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 210_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
 
                {
                        // Now, attempt to route 200 sats (exact amount we can route).
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 200_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 200_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
 
                        let mut total_amount_paid_msat = 0;
@@ -4821,7 +4827,7 @@ mod tests {
 
                // Get a route for 100 sats and check that we found the MPP route no problem and didn't
                // overpay at all.
-               let mut route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let mut route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths.len(), 2);
                route.paths.sort_by_key(|path| path.hops[0].short_channel_id);
                // Paths are manually ordered ordered by SCID, so:
@@ -4940,7 +4946,7 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 150_000, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 150_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -4948,7 +4954,7 @@ mod tests {
                {
                        // Now, attempt to route 125 sats (just a bit below the capacity of 3 channels).
                        // Our algorithm should provide us with these 3 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 125_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 125_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4961,7 +4967,7 @@ mod tests {
 
                {
                        // Attempt to route without the last small cheap channel
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -5100,7 +5106,7 @@ mod tests {
 
                {
                        // Now ensure the route flows simply over nodes 1 and 4 to 6.
-                       let route = get_route(&our_id, &payment_params, &network.read_only(), None, 10_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network.read_only(), None, 10_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].hops.len(), 3);
 
@@ -5171,7 +5177,7 @@ mod tests {
                {
                        // Now, attempt to route 90 sats, which is exactly 90 sats at the last hop, plus the
                        // 200% fee charged channel 13 in the 1-to-2 direction.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].hops.len(), 2);
 
@@ -5237,7 +5243,7 @@ mod tests {
                        // Now, attempt to route 90 sats, hitting the htlc_minimum on channel 4, but
                        // overshooting the htlc_maximum on channel 2. Thus, we should pick the (absurdly
                        // expensive) channels 12-13 path.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].hops.len(), 2);
 
@@ -5279,7 +5285,7 @@ mod tests {
                        let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
                                &get_channel_details(Some(3), nodes[0], channelmanager::provided_init_features(&config), 200_000),
                                &get_channel_details(Some(2), nodes[0], channelmanager::provided_init_features(&config), 10_000),
-                       ]), 100_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       ]), 100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].hops.len(), 1);
 
@@ -5291,7 +5297,7 @@ mod tests {
                        let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
                                &get_channel_details(Some(3), nodes[0], channelmanager::provided_init_features(&config), 50_000),
                                &get_channel_details(Some(2), nodes[0], channelmanager::provided_init_features(&config), 50_000),
-                       ]), 100_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       ]), 100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
                        assert_eq!(route.paths[0].hops.len(), 1);
                        assert_eq!(route.paths[1].hops.len(), 1);
@@ -5323,7 +5329,7 @@ mod tests {
                                &get_channel_details(Some(8), nodes[0], channelmanager::provided_init_features(&config), 50_000),
                                &get_channel_details(Some(9), nodes[0], channelmanager::provided_init_features(&config), 50_000),
                                &get_channel_details(Some(4), nodes[0], channelmanager::provided_init_features(&config), 1_000_000),
-                       ]), 100_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       ]), 100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].hops.len(), 1);
 
@@ -5345,7 +5351,7 @@ mod tests {
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let route = get_route(
                        &our_id, &payment_params, &network_graph.read_only(), None, 100,
-                       Arc::clone(&logger), &scorer, &random_seed_bytes
+                       Arc::clone(&logger), &scorer, &(), &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -5358,7 +5364,7 @@ mod tests {
                let scorer = FixedPenaltyScorer::with_penalty(100);
                let route = get_route(
                        &our_id, &payment_params, &network_graph.read_only(), None, 100,
-                       Arc::clone(&logger), &scorer, &random_seed_bytes
+                       Arc::clone(&logger), &scorer, &(), &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -5376,7 +5382,8 @@ mod tests {
                fn write<W: Writer>(&self, _w: &mut W) -> Result<(), crate::io::Error> { unimplemented!() }
        }
        impl Score for BadChannelScorer {
-               fn channel_penalty_msat(&self, short_channel_id: u64, _: &NodeId, _: &NodeId, _: ChannelUsage) -> u64 {
+               type ScoreParams = ();
+               fn channel_penalty_msat(&self, short_channel_id: u64, _: &NodeId, _: &NodeId, _: ChannelUsage, _score_params:&Self::ScoreParams) -> u64 {
                        if short_channel_id == self.short_channel_id { u64::max_value() } else { 0 }
                }
 
@@ -5396,7 +5403,8 @@ mod tests {
        }
 
        impl Score for BadNodeScorer {
-               fn channel_penalty_msat(&self, _: u64, _: &NodeId, target: &NodeId, _: ChannelUsage) -> u64 {
+               type ScoreParams = ();
+               fn channel_penalty_msat(&self, _: u64, _: &NodeId, target: &NodeId, _: ChannelUsage, _score_params:&Self::ScoreParams) -> u64 {
                        if *target == self.node_id { u64::max_value() } else { 0 }
                }
 
@@ -5419,7 +5427,7 @@ mod tests {
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let route = get_route(
                        &our_id, &payment_params, &network_graph, None, 100,
-                       Arc::clone(&logger), &scorer, &random_seed_bytes
+                       Arc::clone(&logger), &scorer, &(), &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -5431,7 +5439,7 @@ mod tests {
                let scorer = BadChannelScorer { short_channel_id: 6 };
                let route = get_route(
                        &our_id, &payment_params, &network_graph, None, 100,
-                       Arc::clone(&logger), &scorer, &random_seed_bytes
+                       Arc::clone(&logger), &scorer, &(), &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -5443,7 +5451,7 @@ mod tests {
                let scorer = BadNodeScorer { node_id: NodeId::from_pubkey(&nodes[2]) };
                match get_route(
                        &our_id, &payment_params, &network_graph, None, 100,
-                       Arc::clone(&logger), &scorer, &random_seed_bytes
+                       Arc::clone(&logger), &scorer, &(), &random_seed_bytes
                ) {
                        Err(LightningError { err, .. } ) => {
                                assert_eq!(err, "Failed to find a path to the given destination");
@@ -5537,7 +5545,7 @@ mod tests {
                        .with_max_total_cltv_expiry_delta(feasible_max_total_cltv_delta);
                let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
-               let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
                assert_ne!(path.len(), 0);
 
@@ -5545,7 +5553,7 @@ mod tests {
                let fail_max_total_cltv_delta = 23;
                let fail_payment_params = PaymentParameters::from_node_id(nodes[6], 0).with_route_hints(last_hops(&nodes)).unwrap()
                        .with_max_total_cltv_expiry_delta(fail_max_total_cltv_delta);
-               match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes)
+               match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes)
                {
                        Err(LightningError { err, .. } ) => {
                                assert_eq!(err, "Failed to find a path to the given destination");
@@ -5570,9 +5578,9 @@ mod tests {
 
                // We should be able to find a route initially, and then after we fail a few random
                // channels eventually we won't be able to any longer.
-               assert!(get_route(&our_id, &payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).is_ok());
+               assert!(get_route(&our_id, &payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).is_ok());
                loop {
-                       if let Ok(route) = get_route(&our_id, &payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                       if let Ok(route) = get_route(&our_id, &payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
                                for chan in route.paths[0].hops.iter() {
                                        assert!(!payment_params.previously_failed_channels.contains(&chan.short_channel_id));
                                }
@@ -5596,14 +5604,14 @@ mod tests {
                // First check we can actually create a long route on this graph.
                let feasible_payment_params = PaymentParameters::from_node_id(nodes[18], 0);
                let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100,
-                       Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
                assert!(path.len() == MAX_PATH_LENGTH_ESTIMATE.into());
 
                // But we can't create a path surpassing the MAX_PATH_LENGTH_ESTIMATE limit.
                let fail_payment_params = PaymentParameters::from_node_id(nodes[19], 0);
                match get_route(&our_id, &fail_payment_params, &network_graph, None, 100,
-                       Arc::clone(&logger), &scorer, &random_seed_bytes)
+                       Arc::clone(&logger), &scorer, &(), &random_seed_bytes)
                {
                        Err(LightningError { err, .. } ) => {
                                assert_eq!(err, "Failed to find a path to the given destination");
@@ -5622,7 +5630,7 @@ mod tests {
                let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops(&nodes)).unwrap();
                let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths.len(), 1);
 
                let cltv_expiry_deltas_before = route.paths[0].hops.iter().map(|h| h.cltv_expiry_delta).collect::<Vec<u32>>();
@@ -5657,7 +5665,7 @@ mod tests {
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                let mut route = get_route(&our_id, &payment_params, &network_graph, None, 100,
-                                                                 Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                                                                 Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
                add_random_cltv_offset(&mut route, &payment_params, &network_graph, &random_seed_bytes);
 
                let mut path_plausibility = vec![];
@@ -5734,8 +5742,8 @@ mod tests {
        fn avoids_saturating_channels() {
                let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
                let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-
-               let scorer = ProbabilisticScorer::new(Default::default(), &*network_graph, Arc::clone(&logger));
+               let decay_params = ProbabilisticScoringDecayParameters::default();
+               let scorer = ProbabilisticScorer::new(decay_params, &*network_graph, Arc::clone(&logger));
 
                // Set the fee on channel 13 to 100% to match channel 4 giving us two equivalent paths (us
                // -> node 7 -> node2 and us -> node 1 -> node 2) which we should balance over.
@@ -5769,7 +5777,7 @@ mod tests {
                let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
                // 100,000 sats is less than the available liquidity on each channel, set above.
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000_000, Arc::clone(&logger), &scorer, &ProbabilisticScoringFeeParameters::default(), &random_seed_bytes).unwrap();
                assert_eq!(route.paths.len(), 2);
                assert!((route.paths[0].hops[1].short_channel_id == 4 && route.paths[1].hops[1].short_channel_id == 13) ||
                        (route.paths[1].hops[1].short_channel_id == 4 && route.paths[0].hops[1].short_channel_id == 13));
@@ -5783,82 +5791,68 @@ mod tests {
                println!("Using seed of {}", seed);
                seed
        }
-       #[cfg(not(feature = "no-std"))]
-       use crate::util::ser::ReadableArgs;
 
        #[test]
        #[cfg(not(feature = "no-std"))]
        fn generate_routes() {
-               use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+               use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
 
-               let mut d = match super::bench_utils::get_route_file() {
+               let logger = ln_test_utils::TestLogger::new();
+               let graph = match super::bench_utils::read_network_graph(&logger) {
                        Ok(f) => f,
                        Err(e) => {
                                eprintln!("{}", e);
                                return;
                        },
                };
-               let logger = ln_test_utils::TestLogger::new();
-               let graph = NetworkGraph::read(&mut d, &logger).unwrap();
-               let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
-               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
-               // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
-               let mut seed = random_init_seed() as usize;
-               let nodes = graph.read_only().nodes().clone();
-               'load_endpoints: for _ in 0..10 {
-                       loop {
-                               seed = seed.overflowing_mul(0xdeadbeef).0;
-                               let src = &PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
-                               seed = seed.overflowing_mul(0xdeadbeef).0;
-                               let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
-                               let payment_params = PaymentParameters::from_node_id(dst, 42);
-                               let amt = seed as u64 % 200_000_000;
-                               let params = ProbabilisticScoringParameters::default();
-                               let scorer = ProbabilisticScorer::new(params, &graph, &logger);
-                               if get_route(src, &payment_params, &graph.read_only(), None, amt, &logger, &scorer, &random_seed_bytes).is_ok() {
-                                       continue 'load_endpoints;
-                               }
-                       }
-               }
+               let params = ProbabilisticScoringFeeParameters::default();
+               let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
+               let features = super::InvoiceFeatures::empty();
+
+               super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed(), 0, 2);
        }
 
        #[test]
        #[cfg(not(feature = "no-std"))]
        fn generate_routes_mpp() {
-               use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+               use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
 
-               let mut d = match super::bench_utils::get_route_file() {
+               let logger = ln_test_utils::TestLogger::new();
+               let graph = match super::bench_utils::read_network_graph(&logger) {
                        Ok(f) => f,
                        Err(e) => {
                                eprintln!("{}", e);
                                return;
                        },
                };
+
+               let params = ProbabilisticScoringFeeParameters::default();
+               let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
+               let features = channelmanager::provided_invoice_features(&UserConfig::default());
+
+               super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed(), 0, 2);
+       }
+
+       #[test]
+       #[cfg(not(feature = "no-std"))]
+       fn generate_large_mpp_routes() {
+               use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
+
                let logger = ln_test_utils::TestLogger::new();
-               let graph = NetworkGraph::read(&mut d, &logger).unwrap();
-               let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
-               let random_seed_bytes = keys_manager.get_secure_random_bytes();
-               let config = UserConfig::default();
+               let graph = match super::bench_utils::read_network_graph(&logger) {
+                       Ok(f) => f,
+                       Err(e) => {
+                               eprintln!("{}", e);
+                               return;
+                       },
+               };
 
-               // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
-               let mut seed = random_init_seed() as usize;
-               let nodes = graph.read_only().nodes().clone();
-               'load_endpoints: for _ in 0..10 {
-                       loop {
-                               seed = seed.overflowing_mul(0xdeadbeef).0;
-                               let src = &PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
-                               seed = seed.overflowing_mul(0xdeadbeef).0;
-                               let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
-                               let payment_params = PaymentParameters::from_node_id(dst, 42).with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
-                               let amt = seed as u64 % 200_000_000;
-                               let params = ProbabilisticScoringParameters::default();
-                               let scorer = ProbabilisticScorer::new(params, &graph, &logger);
-                               if get_route(src, &payment_params, &graph.read_only(), None, amt, &logger, &scorer, &random_seed_bytes).is_ok() {
-                                       continue 'load_endpoints;
-                               }
-                       }
-               }
+               let params = ProbabilisticScoringFeeParameters::default();
+               let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
+               let features = channelmanager::provided_invoice_features(&UserConfig::default());
+
+               super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed(), 1_000_000, 2);
        }
 
        #[test]
@@ -5869,8 +5863,8 @@ mod tests {
                let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
-               let scorer_params = ProbabilisticScoringParameters::default();
-               let mut scorer = ProbabilisticScorer::new(scorer_params, Arc::clone(&network_graph), Arc::clone(&logger));
+               let mut scorer_params = ProbabilisticScoringFeeParameters::default();
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), Arc::clone(&network_graph), Arc::clone(&logger));
 
                // First check set manual penalties are returned by the scorer.
                let usage = ChannelUsage {
@@ -5878,23 +5872,23 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
                };
-               scorer.set_manual_penalty(&NodeId::from_pubkey(&nodes[3]), 123);
-               scorer.set_manual_penalty(&NodeId::from_pubkey(&nodes[4]), 456);
-               assert_eq!(scorer.channel_penalty_msat(42, &NodeId::from_pubkey(&nodes[3]), &NodeId::from_pubkey(&nodes[4]), usage), 456);
+               scorer_params.set_manual_penalty(&NodeId::from_pubkey(&nodes[3]), 123);
+               scorer_params.set_manual_penalty(&NodeId::from_pubkey(&nodes[4]), 456);
+               assert_eq!(scorer.channel_penalty_msat(42, &NodeId::from_pubkey(&nodes[3]), &NodeId::from_pubkey(&nodes[4]), usage, &scorer_params), 456);
 
                // Then check we can get a normal route
                let payment_params = PaymentParameters::from_node_id(nodes[10], 42);
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes);
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &scorer_params,&random_seed_bytes);
                assert!(route.is_ok());
 
                // Then check that we can't get a route if we ban an intermediate node.
-               scorer.add_banned(&NodeId::from_pubkey(&nodes[3]));
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes);
+               scorer_params.add_banned(&NodeId::from_pubkey(&nodes[3]));
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &scorer_params,&random_seed_bytes);
                assert!(route.is_err());
 
                // Finally make sure we can route again, when we remove the ban.
-               scorer.remove_banned(&NodeId::from_pubkey(&nodes[3]));
-               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes);
+               scorer_params.remove_banned(&NodeId::from_pubkey(&nodes[3]));
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &scorer_params,&random_seed_bytes);
                assert!(route.is_ok());
        }
 
@@ -6044,9 +6038,23 @@ mod tests {
        }
 }
 
-#[cfg(all(test, not(feature = "no-std")))]
+#[cfg(all(any(test, ldk_bench), not(feature = "no-std")))]
 pub(crate) mod bench_utils {
+       use super::*;
        use std::fs::File;
+
+       use bitcoin::hashes::Hash;
+       use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
+
+       use crate::chain::transaction::OutPoint;
+       use crate::sign::{EntropySource, KeysManager};
+       use crate::ln::channelmanager::{self, ChannelCounterparty, ChannelDetails};
+       use crate::ln::features::InvoiceFeatures;
+       use crate::routing::gossip::NetworkGraph;
+       use crate::util::config::UserConfig;
+       use crate::util::ser::ReadableArgs;
+       use crate::util::test_utils::TestLogger;
+
        /// Tries to open a network graph file, or panics with a URL to fetch it.
        pub(crate) fn get_route_file() -> Result<std::fs::File, &'static str> {
                let res = File::open("net_graph-2023-01-18.bin") // By default we're run in RL/lightning
@@ -6060,7 +6068,18 @@ pub(crate) mod bench_utils {
                                path.pop(); // target
                                path.push("lightning");
                                path.push("net_graph-2023-01-18.bin");
-                               eprintln!("{}", path.to_str().unwrap());
+                               File::open(path)
+                       })
+                       .or_else(|_| { // Fall back to guessing based on the binary location for a subcrate
+                               // path is likely something like .../rust-lightning/bench/target/debug/deps/bench..
+                               let mut path = std::env::current_exe().unwrap();
+                               path.pop(); // bench...
+                               path.pop(); // deps
+                               path.pop(); // debug
+                               path.pop(); // target
+                               path.pop(); // bench
+                               path.push("lightning");
+                               path.push("net_graph-2023-01-18.bin");
                                File::open(path)
                        })
                .map_err(|_| "Please fetch https://bitcoin.ninja/ldk-net_graph-v0.0.113-2023-01-18.bin and place it at lightning/net_graph-2023-01-18.bin");
@@ -6069,42 +6088,18 @@ pub(crate) mod bench_utils {
                #[cfg(not(require_route_graph_test))]
                return res;
        }
-}
 
-#[cfg(all(test, feature = "_bench_unstable", not(feature = "no-std")))]
-mod benches {
-       use super::*;
-       use bitcoin::hashes::Hash;
-       use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
-       use crate::chain::transaction::OutPoint;
-       use crate::sign::{EntropySource, KeysManager};
-       use crate::ln::channelmanager::{self, ChannelCounterparty, ChannelDetails};
-       use crate::ln::features::InvoiceFeatures;
-       use crate::routing::gossip::NetworkGraph;
-       use crate::routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringParameters};
-       use crate::util::config::UserConfig;
-       use crate::util::logger::{Logger, Record};
-       use crate::util::ser::ReadableArgs;
-
-       use test::Bencher;
-
-       struct DummyLogger {}
-       impl Logger for DummyLogger {
-               fn log(&self, _record: &Record) {}
-       }
-
-       fn read_network_graph(logger: &DummyLogger) -> NetworkGraph<&DummyLogger> {
-               let mut d = bench_utils::get_route_file().unwrap();
-               NetworkGraph::read(&mut d, logger).unwrap()
+       pub(crate) fn read_network_graph(logger: &TestLogger) -> Result<NetworkGraph<&TestLogger>, &'static str> {
+               get_route_file().map(|mut f| NetworkGraph::read(&mut f, logger).unwrap())
        }
 
-       fn payer_pubkey() -> PublicKey {
+       pub(crate) fn payer_pubkey() -> PublicKey {
                let secp_ctx = Secp256k1::new();
                PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap())
        }
 
        #[inline]
-       fn first_hop(node_id: PublicKey) -> ChannelDetails {
+       pub(crate) fn first_hop(node_id: PublicKey) -> ChannelDetails {
                ChannelDetails {
                        channel_id: [0; 32],
                        counterparty: ChannelCounterparty {
@@ -6122,11 +6117,11 @@ mod benches {
                        short_channel_id: Some(1),
                        inbound_scid_alias: None,
                        outbound_scid_alias: None,
-                       channel_value_satoshis: 10_000_000,
+                       channel_value_satoshis: 10_000_000_000,
                        user_channel_id: 0,
-                       balance_msat: 10_000_000,
-                       outbound_capacity_msat: 10_000_000,
-                       next_outbound_htlc_limit_msat: 10_000_000,
+                       balance_msat: 10_000_000_000,
+                       outbound_capacity_msat: 10_000_000_000,
+                       next_outbound_htlc_limit_msat: 10_000_000_000,
                        inbound_capacity_msat: 0,
                        unspendable_punishment_reserve: None,
                        confirmations_required: None,
@@ -6143,100 +6138,167 @@ mod benches {
                }
        }
 
-       #[bench]
-       fn generate_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
-               let logger = DummyLogger {};
-               let network_graph = read_network_graph(&logger);
-               let scorer = FixedPenaltyScorer::with_penalty(0);
-               generate_routes(bench, &network_graph, scorer, InvoiceFeatures::empty());
-       }
-
-       #[bench]
-       fn generate_mpp_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
-               let logger = DummyLogger {};
-               let network_graph = read_network_graph(&logger);
-               let scorer = FixedPenaltyScorer::with_penalty(0);
-               generate_routes(bench, &network_graph, scorer, channelmanager::provided_invoice_features(&UserConfig::default()));
-       }
-
-       #[bench]
-       fn generate_routes_with_probabilistic_scorer(bench: &mut Bencher) {
-               let logger = DummyLogger {};
-               let network_graph = read_network_graph(&logger);
-               let params = ProbabilisticScoringParameters::default();
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               generate_routes(bench, &network_graph, scorer, InvoiceFeatures::empty());
-       }
-
-       #[bench]
-       fn generate_mpp_routes_with_probabilistic_scorer(bench: &mut Bencher) {
-               let logger = DummyLogger {};
-               let network_graph = read_network_graph(&logger);
-               let params = ProbabilisticScoringParameters::default();
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               generate_routes(bench, &network_graph, scorer, channelmanager::provided_invoice_features(&UserConfig::default()));
-       }
-
-       fn generate_routes<S: Score>(
-               bench: &mut Bencher, graph: &NetworkGraph<&DummyLogger>, mut scorer: S,
-               features: InvoiceFeatures
-       ) {
-               let nodes = graph.read_only().nodes().clone();
+       pub(crate) fn generate_test_routes<S: Score>(graph: &NetworkGraph<&TestLogger>, scorer: &mut S,
+               score_params: &S::ScoreParams, features: InvoiceFeatures, mut seed: u64,
+               starting_amount: u64, route_count: usize,
+       ) -> Vec<(ChannelDetails, PaymentParameters, u64)> {
                let payer = payer_pubkey();
                let keys_manager = KeysManager::new(&[0u8; 32], 42, 42);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
-               // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
-               let mut routes = Vec::new();
+               let nodes = graph.read_only().nodes().clone();
                let mut route_endpoints = Vec::new();
-               let mut seed: usize = 0xdeadbeef;
-               'load_endpoints: for _ in 0..150 {
+               // Fetch 1.5x more routes than we need as after we do some scorer updates we may end up
+               // with some routes we picked being un-routable.
+               for _ in 0..route_count * 3 / 2 {
                        loop {
-                               seed *= 0xdeadbeef;
-                               let src = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
-                               seed *= 0xdeadbeef;
-                               let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
-                               let params = PaymentParameters::from_node_id(dst, 42).with_bolt11_features(features.clone()).unwrap();
+                               seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
+                               let src = PublicKey::from_slice(nodes.unordered_keys()
+                                       .skip((seed as usize) % nodes.len()).next().unwrap().as_slice()).unwrap();
+                               seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
+                               let dst = PublicKey::from_slice(nodes.unordered_keys()
+                                       .skip((seed as usize) % nodes.len()).next().unwrap().as_slice()).unwrap();
+                               let params = PaymentParameters::from_node_id(dst, 42)
+                                       .with_bolt11_features(features.clone()).unwrap();
                                let first_hop = first_hop(src);
-                               let amt = seed as u64 % 1_000_000;
-                               if let Ok(route) = get_route(&payer, &params, &graph.read_only(), Some(&[&first_hop]), amt, &DummyLogger{}, &scorer, &random_seed_bytes) {
-                                       routes.push(route);
-                                       route_endpoints.push((first_hop, params, amt));
-                                       continue 'load_endpoints;
-                               }
-                       }
-               }
+                               let amt = starting_amount + seed % 1_000_000;
+                               let path_exists =
+                                       get_route(&payer, &params, &graph.read_only(), Some(&[&first_hop]),
+                                               amt, &TestLogger::new(), &scorer, score_params, &random_seed_bytes).is_ok();
+                               if path_exists {
+                                       // ...and seed the scorer with success and failure data...
+                                       seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
+                                       let mut score_amt = seed % 1_000_000_000;
+                                       loop {
+                                               // Generate fail/success paths for a wider range of potential amounts with
+                                               // MPP enabled to give us a chance to apply penalties for more potential
+                                               // routes.
+                                               let mpp_features = channelmanager::provided_invoice_features(&UserConfig::default());
+                                               let params = PaymentParameters::from_node_id(dst, 42)
+                                                       .with_bolt11_features(mpp_features).unwrap();
+
+                                               let route_res = get_route(&payer, &params, &graph.read_only(),
+                                                       Some(&[&first_hop]), score_amt, &TestLogger::new(), &scorer,
+                                                       score_params, &random_seed_bytes);
+                                               if let Ok(route) = route_res {
+                                                       for path in route.paths {
+                                                               if seed & 0x80 == 0 {
+                                                                       scorer.payment_path_successful(&path);
+                                                               } else {
+                                                                       let short_channel_id = path.hops[path.hops.len() / 2].short_channel_id;
+                                                                       scorer.payment_path_failed(&path, short_channel_id);
+                                                               }
+                                                               seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
+                                                       }
+                                                       break;
+                                               }
+                                               // If we couldn't find a path with a higer amount, reduce and try again.
+                                               score_amt /= 100;
+                                       }
 
-               // ...and seed the scorer with success and failure data...
-               for route in routes {
-                       let amount = route.get_total_amount();
-                       if amount < 250_000 {
-                               for path in route.paths {
-                                       scorer.payment_path_successful(&path);
-                               }
-                       } else if amount > 750_000 {
-                               for path in route.paths {
-                                       let short_channel_id = path.hops[path.hops.len() / 2].short_channel_id;
-                                       scorer.payment_path_failed(&path, short_channel_id);
+                                       route_endpoints.push((first_hop, params, amt));
+                                       break;
                                }
                        }
                }
 
-               // Because we've changed channel scores, its possible we'll take different routes to the
+               // Because we've changed channel scores, it's possible we'll take different routes to the
                // selected destinations, possibly causing us to fail because, eg, the newly-selected path
                // requires a too-high CLTV delta.
                route_endpoints.retain(|(first_hop, params, amt)| {
-                       get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, &DummyLogger{}, &scorer, &random_seed_bytes).is_ok()
+                       get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt,
+                               &TestLogger::new(), &scorer, score_params, &random_seed_bytes).is_ok()
                });
-               route_endpoints.truncate(100);
-               assert_eq!(route_endpoints.len(), 100);
+               route_endpoints.truncate(route_count);
+               assert_eq!(route_endpoints.len(), route_count);
+               route_endpoints
+       }
+}
+
+#[cfg(ldk_bench)]
+pub mod benches {
+       use super::*;
+       use crate::sign::{EntropySource, KeysManager};
+       use crate::ln::channelmanager;
+       use crate::ln::features::InvoiceFeatures;
+       use crate::routing::gossip::NetworkGraph;
+       use crate::routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
+       use crate::util::config::UserConfig;
+       use crate::util::logger::{Logger, Record};
+       use crate::util::test_utils::TestLogger;
+
+       use criterion::Criterion;
+
+       struct DummyLogger {}
+       impl Logger for DummyLogger {
+               fn log(&self, _record: &Record) {}
+       }
+
+       pub fn generate_routes_with_zero_penalty_scorer(bench: &mut Criterion) {
+               let logger = TestLogger::new();
+               let network_graph = bench_utils::read_network_graph(&logger).unwrap();
+               let scorer = FixedPenaltyScorer::with_penalty(0);
+               generate_routes(bench, &network_graph, scorer, &(), InvoiceFeatures::empty(), 0,
+                       "generate_routes_with_zero_penalty_scorer");
+       }
+
+       pub fn generate_mpp_routes_with_zero_penalty_scorer(bench: &mut Criterion) {
+               let logger = TestLogger::new();
+               let network_graph = bench_utils::read_network_graph(&logger).unwrap();
+               let scorer = FixedPenaltyScorer::with_penalty(0);
+               generate_routes(bench, &network_graph, scorer, &(),
+                       channelmanager::provided_invoice_features(&UserConfig::default()), 0,
+                       "generate_mpp_routes_with_zero_penalty_scorer");
+       }
+
+       pub fn generate_routes_with_probabilistic_scorer(bench: &mut Criterion) {
+               let logger = TestLogger::new();
+               let network_graph = bench_utils::read_network_graph(&logger).unwrap();
+               let params = ProbabilisticScoringFeeParameters::default();
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+               generate_routes(bench, &network_graph, scorer, &params, InvoiceFeatures::empty(), 0,
+                       "generate_routes_with_probabilistic_scorer");
+       }
+
+       pub fn generate_mpp_routes_with_probabilistic_scorer(bench: &mut Criterion) {
+               let logger = TestLogger::new();
+               let network_graph = bench_utils::read_network_graph(&logger).unwrap();
+               let params = ProbabilisticScoringFeeParameters::default();
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+               generate_routes(bench, &network_graph, scorer, &params,
+                       channelmanager::provided_invoice_features(&UserConfig::default()), 0,
+                       "generate_mpp_routes_with_probabilistic_scorer");
+       }
+
+       pub fn generate_large_mpp_routes_with_probabilistic_scorer(bench: &mut Criterion) {
+               let logger = TestLogger::new();
+               let network_graph = bench_utils::read_network_graph(&logger).unwrap();
+               let params = ProbabilisticScoringFeeParameters::default();
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+               generate_routes(bench, &network_graph, scorer, &params,
+                       channelmanager::provided_invoice_features(&UserConfig::default()), 100_000_000,
+                       "generate_large_mpp_routes_with_probabilistic_scorer");
+       }
+
+       fn generate_routes<S: Score>(
+               bench: &mut Criterion, graph: &NetworkGraph<&TestLogger>, mut scorer: S,
+               score_params: &S::ScoreParams, features: InvoiceFeatures, starting_amount: u64,
+               bench_name: &'static str,
+       ) {
+               let payer = bench_utils::payer_pubkey();
+               let keys_manager = KeysManager::new(&[0u8; 32], 42, 42);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+
+               // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
+               let route_endpoints = bench_utils::generate_test_routes(graph, &mut scorer, score_params, features, 0xdeadbeef, starting_amount, 50);
 
                // ...then benchmark finding paths between the nodes we learned.
                let mut idx = 0;
-               bench.iter(|| {
+               bench.bench_function(bench_name, |b| b.iter(|| {
                        let (first_hop, params, amt) = &route_endpoints[idx % route_endpoints.len()];
-                       assert!(get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, &DummyLogger{}, &scorer, &random_seed_bytes).is_ok());
+                       assert!(get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt,
+                               &DummyLogger{}, &scorer, score_params, &random_seed_bytes).is_ok());
                        idx += 1;
-               });
+               }));
        }
 }
index e664b0d11e7c843b71cac7bd781c9711fd00fb59..235b1a148a5824ad020cf88dc3fc652679e3ba1f 100644 (file)
@@ -19,7 +19,7 @@
 //! #
 //! # use lightning::routing::gossip::NetworkGraph;
 //! # use lightning::routing::router::{RouteParameters, find_route};
-//! # use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+//! # use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
 //! # use lightning::sign::KeysManager;
 //! # use lightning::util::logger::{Logger, Record};
 //! # use bitcoin::secp256k1::PublicKey;
 //! # let logger = FakeLogger {};
 //! #
 //! // Use the default channel penalties.
-//! let params = ProbabilisticScoringParameters::default();
-//! let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+//! let params = ProbabilisticScoringFeeParameters::default();
+//! let decay_params = ProbabilisticScoringDecayParameters::default();
+//! let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
 //!
 //! // Or use custom channel penalties.
-//! let params = ProbabilisticScoringParameters {
-//!     liquidity_penalty_multiplier_msat: 2 * 1000,
-//!     ..ProbabilisticScoringParameters::default()
+//! let params = ProbabilisticScoringFeeParameters {
+//!    liquidity_penalty_multiplier_msat: 2 * 1000,
+//!    ..ProbabilisticScoringFeeParameters::default()
 //! };
-//! let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+//! let decay_params = ProbabilisticScoringDecayParameters::default();
+//! let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
 //! # let random_seed_bytes = [42u8; 32];
 //!
-//! let route = find_route(&payer, &route_params, &network_graph, None, &logger, &scorer, &random_seed_bytes);
+//! let route = find_route(&payer, &route_params, &network_graph, None, &logger, &scorer, &params, &random_seed_bytes);
 //! # }
 //! ```
 //!
@@ -86,6 +88,10 @@ macro_rules! define_score { ($($supertrait: path)*) => {
 ///
 ///    Scoring is in terms of fees willing to be paid in order to avoid routing through a channel.
 pub trait Score $(: $supertrait)* {
+       /// A configurable type which should contain various passed-in parameters for configuring the scorer,
+       /// on a per-routefinding-call basis through to the scorer methods,
+       /// which are used to determine the parameters for the suitability of channels for use.
+       type ScoreParams;
        /// Returns the fee in msats willing to be paid to avoid routing `send_amt_msat` through the
        /// given channel in the direction from `source` to `target`.
        ///
@@ -95,7 +101,7 @@ pub trait Score $(: $supertrait)* {
        /// [`u64::max_value`] is given to indicate sufficient capacity for the invoice's full amount.
        /// Thus, implementations should be overflow-safe.
        fn channel_penalty_msat(
-               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
+               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams
        ) -> u64;
 
        /// Handles updating channel penalties after failing to route through a channel.
@@ -112,10 +118,11 @@ pub trait Score $(: $supertrait)* {
 }
 
 impl<S: Score, T: DerefMut<Target=S> $(+ $supertrait)*> Score for T {
+       type ScoreParams = S::ScoreParams;
        fn channel_penalty_msat(
-               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
+               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams
        ) -> u64 {
-               self.deref().channel_penalty_msat(short_channel_id, source, target, usage)
+               self.deref().channel_penalty_msat(short_channel_id, source, target, usage, score_params)
        }
 
        fn payment_path_failed(&mut self, path: &Path, short_channel_id: u64) {
@@ -192,8 +199,9 @@ pub struct MultiThreadedLockableScore<S: Score> {
 pub struct MultiThreadedScoreLock<'a, S: Score>(MutexGuard<'a, S>);
 #[cfg(c_bindings)]
 impl<'a, T: Score + 'a> Score for MultiThreadedScoreLock<'a, T> {
-       fn channel_penalty_msat(&self, scid: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
-               self.0.channel_penalty_msat(scid, source, target, usage)
+       type ScoreParams = <T as Score>::ScoreParams;
+       fn channel_penalty_msat(&self, scid: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams) -> u64 {
+               self.0.channel_penalty_msat(scid, source, target, usage, score_params)
        }
        fn payment_path_failed(&mut self, path: &Path, short_channel_id: u64) {
                self.0.payment_path_failed(path, short_channel_id)
@@ -286,7 +294,8 @@ impl FixedPenaltyScorer {
 }
 
 impl Score for FixedPenaltyScorer {
-       fn channel_penalty_msat(&self, _: u64, _: &NodeId, _: &NodeId, _: ChannelUsage) -> u64 {
+       type ScoreParams = ();
+       fn channel_penalty_msat(&self, _: u64, _: &NodeId, _: &NodeId, _: ChannelUsage, _score_params: &Self::ScoreParams) -> u64 {
                self.penalty_msat
        }
 
@@ -353,11 +362,11 @@ type ConfiguredTime = Eternity;
 /// behavior.
 ///
 /// [1]: https://arxiv.org/abs/2107.05322
-/// [`liquidity_penalty_multiplier_msat`]: ProbabilisticScoringParameters::liquidity_penalty_multiplier_msat
-/// [`liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringParameters::liquidity_penalty_amount_multiplier_msat
-/// [`liquidity_offset_half_life`]: ProbabilisticScoringParameters::liquidity_offset_half_life
-/// [`historical_liquidity_penalty_multiplier_msat`]: ProbabilisticScoringParameters::historical_liquidity_penalty_multiplier_msat
-/// [`historical_liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringParameters::historical_liquidity_penalty_amount_multiplier_msat
+/// [`liquidity_penalty_multiplier_msat`]: ProbabilisticScoringFeeParameters::liquidity_penalty_multiplier_msat
+/// [`liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringFeeParameters::liquidity_penalty_amount_multiplier_msat
+/// [`liquidity_offset_half_life`]: ProbabilisticScoringDecayParameters::liquidity_offset_half_life
+/// [`historical_liquidity_penalty_multiplier_msat`]: ProbabilisticScoringFeeParameters::historical_liquidity_penalty_multiplier_msat
+/// [`historical_liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringFeeParameters::historical_liquidity_penalty_amount_multiplier_msat
 pub type ProbabilisticScorer<G, L> = ProbabilisticScorerUsingTime::<G, L, ConfiguredTime>;
 
 /// Probabilistic [`Score`] implementation.
@@ -365,7 +374,7 @@ pub type ProbabilisticScorer<G, L> = ProbabilisticScorerUsingTime::<G, L, Config
 /// This is not exported to bindings users generally all users should use the [`ProbabilisticScorer`] type alias.
 pub struct ProbabilisticScorerUsingTime<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time>
 where L::Target: Logger {
-       params: ProbabilisticScoringParameters,
+       decay_params: ProbabilisticScoringDecayParameters,
        network_graph: G,
        logger: L,
        // TODO: Remove entries of closed channels.
@@ -380,7 +389,7 @@ where L::Target: Logger {
 /// The penalty applied to any channel by the [`ProbabilisticScorer`] is the sum of each of the
 /// parameters here.
 #[derive(Clone)]
-pub struct ProbabilisticScoringParameters {
+pub struct ProbabilisticScoringFeeParameters {
        /// A fixed penalty in msats to apply to each channel.
        ///
        /// Default value: 500 msat
@@ -415,30 +424,9 @@ pub struct ProbabilisticScoringParameters {
        ///
        /// Default value: 30,000 msat
        ///
-       /// [`liquidity_offset_half_life`]: Self::liquidity_offset_half_life
+       /// [`liquidity_offset_half_life`]: ProbabilisticScoringDecayParameters::liquidity_offset_half_life
        pub liquidity_penalty_multiplier_msat: u64,
 
-       /// Whenever this amount of time elapses since the last update to a channel's liquidity bounds,
-       /// the distance from the bounds to "zero" is cut in half. In other words, the lower-bound on
-       /// the available liquidity is halved and the upper-bound moves half-way to the channel's total
-       /// capacity.
-       ///
-       /// Because halving the liquidity bounds grows the uncertainty on the channel's liquidity,
-       /// the penalty for an amount within the new bounds may change. See the [`ProbabilisticScorer`]
-       /// struct documentation for more info on the way the liquidity bounds are used.
-       ///
-       /// For example, if the channel's capacity is 1 million sats, and the current upper and lower
-       /// liquidity bounds are 200,000 sats and 600,000 sats, after this amount of time the upper
-       /// and lower liquidity bounds will be decayed to 100,000 and 800,000 sats.
-       ///
-       /// Default value: 6 hours
-       ///
-       /// # Note
-       ///
-       /// When built with the `no-std` feature, time will never elapse. Therefore, the channel
-       /// liquidity knowledge will never decay except when the bounds cross.
-       pub liquidity_offset_half_life: Duration,
-
        /// A multiplier used in conjunction with a payment amount and the negative `log10` of the
        /// channel's success probability for the payment, as determined by our latest estimates of the
        /// channel's liquidity, to determine the amount penalty.
@@ -495,16 +483,6 @@ pub struct ProbabilisticScoringParameters {
        /// [`liquidity_penalty_amount_multiplier_msat`]: Self::liquidity_penalty_amount_multiplier_msat
        pub historical_liquidity_penalty_amount_multiplier_msat: u64,
 
-       /// If we aren't learning any new datapoints for a channel, the historical liquidity bounds
-       /// tracking can simply live on with increasingly stale data. Instead, when a channel has not
-       /// seen a liquidity estimate update for this amount of time, the historical datapoints are
-       /// decayed by half.
-       ///
-       /// Note that after 16 or more half lives all historical data will be completely gone.
-       ///
-       /// Default value: 14 days
-       pub historical_no_updates_half_life: Duration,
-
        /// Manual penalties used for the given nodes. Allows to set a particular penalty for a given
        /// node. Note that a manual penalty of `u64::max_value()` means the node would not ever be
        /// considered during path finding.
@@ -513,9 +491,10 @@ pub struct ProbabilisticScoringParameters {
        pub manual_node_penalties: HashMap<NodeId, u64>,
 
        /// This penalty is applied when `htlc_maximum_msat` is equal to or larger than half of the
-       /// channel's capacity, which makes us prefer nodes with a smaller `htlc_maximum_msat`. We
-       /// treat such nodes preferentially as this makes balance discovery attacks harder to execute,
-       /// thereby creating an incentive to restrict `htlc_maximum_msat` and improve privacy.
+       /// channel's capacity, (ie. htlc_maximum_msat â‰¥ 0.5 * channel_capacity) which makes us
+       /// prefer nodes with a smaller `htlc_maximum_msat`. We treat such nodes preferentially
+       /// as this makes balance discovery attacks harder to execute, thereby creating an incentive
+       /// to restrict `htlc_maximum_msat` and improve privacy.
        ///
        /// Default value: 250 msat
        pub anti_probing_penalty_msat: u64,
@@ -540,6 +519,136 @@ pub struct ProbabilisticScoringParameters {
        pub considered_impossible_penalty_msat: u64,
 }
 
+impl Default for ProbabilisticScoringFeeParameters {
+       fn default() -> Self {
+               Self {
+                       base_penalty_msat: 500,
+                       base_penalty_amount_multiplier_msat: 8192,
+                       liquidity_penalty_multiplier_msat: 30_000,
+                       liquidity_penalty_amount_multiplier_msat: 192,
+                       manual_node_penalties: HashMap::new(),
+                       anti_probing_penalty_msat: 250,
+                       considered_impossible_penalty_msat: 1_0000_0000_000,
+                       historical_liquidity_penalty_multiplier_msat: 10_000,
+                       historical_liquidity_penalty_amount_multiplier_msat: 64,
+               }
+       }
+}
+
+impl ProbabilisticScoringFeeParameters {
+       /// Marks the node with the given `node_id` as banned,
+       /// i.e it will be avoided during path finding.
+       pub fn add_banned(&mut self, node_id: &NodeId) {
+               self.manual_node_penalties.insert(*node_id, u64::max_value());
+       }
+
+       /// Marks all nodes in the given list as banned, i.e.,
+       /// they will be avoided during path finding.
+       pub fn add_banned_from_list(&mut self, node_ids: Vec<NodeId>) {
+               for id in node_ids {
+                       self.manual_node_penalties.insert(id, u64::max_value());
+               }
+       }
+
+       /// Removes the node with the given `node_id` from the list of nodes to avoid.
+       pub fn remove_banned(&mut self, node_id: &NodeId) {
+               self.manual_node_penalties.remove(node_id);
+       }
+
+       /// Sets a manual penalty for the given node.
+       pub fn set_manual_penalty(&mut self, node_id: &NodeId, penalty: u64) {
+               self.manual_node_penalties.insert(*node_id, penalty);
+       }
+
+       /// Removes the node with the given `node_id` from the list of manual penalties.
+       pub fn remove_manual_penalty(&mut self, node_id: &NodeId) {
+               self.manual_node_penalties.remove(node_id);
+       }
+
+       /// Clears the list of manual penalties that are applied during path finding.
+       pub fn clear_manual_penalties(&mut self) {
+               self.manual_node_penalties = HashMap::new();
+       }
+}
+
+#[cfg(test)]
+impl ProbabilisticScoringFeeParameters {
+       fn zero_penalty() -> Self {
+               Self {
+                       base_penalty_msat: 0,
+                       base_penalty_amount_multiplier_msat: 0,
+                       liquidity_penalty_multiplier_msat: 0,
+                       liquidity_penalty_amount_multiplier_msat: 0,
+                       historical_liquidity_penalty_multiplier_msat: 0,
+                       historical_liquidity_penalty_amount_multiplier_msat: 0,
+                       manual_node_penalties: HashMap::new(),
+                       anti_probing_penalty_msat: 0,
+                       considered_impossible_penalty_msat: 0,
+               }
+       }
+}
+
+/// Parameters for configuring [`ProbabilisticScorer`].
+///
+/// Used to configure decay parameters that are static throughout the lifetime of the scorer.
+/// these decay parameters affect the score of the channel penalty and are not changed on a
+/// per-route penalty cost call.
+#[derive(Copy, Clone)]
+pub struct ProbabilisticScoringDecayParameters {
+       /// If we aren't learning any new datapoints for a channel, the historical liquidity bounds
+       /// tracking can simply live on with increasingly stale data. Instead, when a channel has not
+       /// seen a liquidity estimate update for this amount of time, the historical datapoints are
+       /// decayed by half.
+       /// For an example of historical_no_updates_half_life being used see [`historical_estimated_channel_liquidity_probabilities`]
+       ///
+       /// Note that after 16 or more half lives all historical data will be completely gone.
+       ///
+       /// Default value: 14 days
+       ///
+       /// [`historical_estimated_channel_liquidity_probabilities`]: ProbabilisticScorerUsingTime::historical_estimated_channel_liquidity_probabilities
+       pub historical_no_updates_half_life: Duration,
+
+       /// Whenever this amount of time elapses since the last update to a channel's liquidity bounds,
+       /// the distance from the bounds to "zero" is cut in half. In other words, the lower-bound on
+       /// the available liquidity is halved and the upper-bound moves half-way to the channel's total
+       /// capacity.
+       ///
+       /// Because halving the liquidity bounds grows the uncertainty on the channel's liquidity,
+       /// the penalty for an amount within the new bounds may change. See the [`ProbabilisticScorer`]
+       /// struct documentation for more info on the way the liquidity bounds are used.
+       ///
+       /// For example, if the channel's capacity is 1 million sats, and the current upper and lower
+       /// liquidity bounds are 200,000 sats and 600,000 sats, after this amount of time the upper
+       /// and lower liquidity bounds will be decayed to 100,000 and 800,000 sats.
+       ///
+       /// Default value: 6 hours
+       ///
+       /// # Note
+       ///
+       /// When built with the `no-std` feature, time will never elapse. Therefore, the channel
+       /// liquidity knowledge will never decay except when the bounds cross.
+       pub liquidity_offset_half_life: Duration,
+}
+
+impl Default for ProbabilisticScoringDecayParameters {
+       fn default() -> Self {
+               Self {
+                       liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
+                       historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
+               }
+       }
+}
+
+#[cfg(test)]
+impl ProbabilisticScoringDecayParameters {
+       fn zero_penalty() -> Self {
+               Self {
+                       liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
+                       historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
+               }
+       }
+}
+
 /// Tracks the historical state of a distribution as a weighted average of how much time was spent
 /// in each of 8 buckets.
 #[derive(Clone, Copy)]
@@ -702,7 +811,7 @@ struct ChannelLiquidity<T: Time> {
 
 /// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity and
 /// decayed with a given half life.
-struct DirectedChannelLiquidity<'a, L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> {
+struct DirectedChannelLiquidity<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> {
        min_liquidity_offset_msat: L,
        max_liquidity_offset_msat: L,
        min_liquidity_offset_history: BRT,
@@ -711,15 +820,15 @@ struct DirectedChannelLiquidity<'a, L: Deref<Target = u64>, BRT: Deref<Target =
        capacity_msat: u64,
        last_updated: U,
        now: T,
-       params: &'a ProbabilisticScoringParameters,
+       decay_params: ProbabilisticScoringDecayParameters,
 }
 
 impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
        /// Creates a new scorer using the given scoring parameters for sending payments from a node
        /// through a network graph.
-       pub fn new(params: ProbabilisticScoringParameters, network_graph: G, logger: L) -> Self {
+       pub fn new(decay_params: ProbabilisticScoringDecayParameters, network_graph: G, logger: L) -> Self {
                Self {
-                       params,
+                       decay_params,
                        network_graph,
                        logger,
                        channel_liquidities: HashMap::new(),
@@ -745,14 +854,14 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
                                let log_direction = |source, target| {
                                        if let Some((directed_info, _)) = chan_debug.as_directed_to(target) {
                                                let amt = directed_info.effective_capacity().as_msat();
-                                               let dir_liq = liq.as_directed(source, target, 0, amt, &self.params);
+                                               let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
 
                                                let buckets = HistoricalMinMaxBuckets {
                                                        min_liquidity_offset_history: &dir_liq.min_liquidity_offset_history,
                                                        max_liquidity_offset_history: &dir_liq.max_liquidity_offset_history,
                                                };
                                                let (min_buckets, max_buckets, _) = buckets.get_decayed_buckets(now,
-                                                       *dir_liq.last_updated, self.params.historical_no_updates_half_life);
+                                                       *dir_liq.last_updated, self.decay_params.historical_no_updates_half_life);
 
                                                log_debug!(self.logger, core::concat!(
                                                        "Liquidity from {} to {} via {} is in the range ({}, {}).\n",
@@ -787,7 +896,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
                        if let Some(liq) = self.channel_liquidities.get(&scid) {
                                if let Some((directed_info, source)) = chan.as_directed_to(target) {
                                        let amt = directed_info.effective_capacity().as_msat();
-                                       let dir_liq = liq.as_directed(source, target, 0, amt, &self.params);
+                                       let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
                                        return Some((dir_liq.min_liquidity_msat(), dir_liq.max_liquidity_msat()));
                                }
                        }
@@ -824,14 +933,14 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
                        if let Some(liq) = self.channel_liquidities.get(&scid) {
                                if let Some((directed_info, source)) = chan.as_directed_to(target) {
                                        let amt = directed_info.effective_capacity().as_msat();
-                                       let dir_liq = liq.as_directed(source, target, 0, amt, &self.params);
+                                       let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
 
                                        let buckets = HistoricalMinMaxBuckets {
                                                min_liquidity_offset_history: &dir_liq.min_liquidity_offset_history,
                                                max_liquidity_offset_history: &dir_liq.max_liquidity_offset_history,
                                        };
                                        let (min_buckets, mut max_buckets, _) = buckets.get_decayed_buckets(T::now(),
-                                               *dir_liq.last_updated, self.params.historical_no_updates_half_life);
+                                               *dir_liq.last_updated, self.decay_params.historical_no_updates_half_life);
                                        // Note that the liquidity buckets are an offset from the edge, so we inverse
                                        // the max order to get the probabilities from zero.
                                        max_buckets.reverse();
@@ -841,77 +950,6 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
                }
                None
        }
-
-       /// Marks the node with the given `node_id` as banned, i.e.,
-       /// it will be avoided during path finding.
-       pub fn add_banned(&mut self, node_id: &NodeId) {
-               self.params.manual_node_penalties.insert(*node_id, u64::max_value());
-       }
-
-       /// Removes the node with the given `node_id` from the list of nodes to avoid.
-       pub fn remove_banned(&mut self, node_id: &NodeId) {
-               self.params.manual_node_penalties.remove(node_id);
-       }
-
-       /// Sets a manual penalty for the given node.
-       pub fn set_manual_penalty(&mut self, node_id: &NodeId, penalty: u64) {
-               self.params.manual_node_penalties.insert(*node_id, penalty);
-       }
-
-       /// Removes the node with the given `node_id` from the list of manual penalties.
-       pub fn remove_manual_penalty(&mut self, node_id: &NodeId) {
-               self.params.manual_node_penalties.remove(node_id);
-       }
-
-       /// Clears the list of manual penalties that are applied during path finding.
-       pub fn clear_manual_penalties(&mut self) {
-               self.params.manual_node_penalties = HashMap::new();
-       }
-}
-
-impl ProbabilisticScoringParameters {
-       #[cfg(test)]
-       fn zero_penalty() -> Self {
-               Self {
-                       base_penalty_msat: 0,
-                       base_penalty_amount_multiplier_msat: 0,
-                       liquidity_penalty_multiplier_msat: 0,
-                       liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
-                       liquidity_penalty_amount_multiplier_msat: 0,
-                       historical_liquidity_penalty_multiplier_msat: 0,
-                       historical_liquidity_penalty_amount_multiplier_msat: 0,
-                       historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
-                       manual_node_penalties: HashMap::new(),
-                       anti_probing_penalty_msat: 0,
-                       considered_impossible_penalty_msat: 0,
-               }
-       }
-
-       /// Marks all nodes in the given list as banned, i.e.,
-       /// they will be avoided during path finding.
-       pub fn add_banned_from_list(&mut self, node_ids: Vec<NodeId>) {
-               for id in node_ids {
-                       self.manual_node_penalties.insert(id, u64::max_value());
-               }
-       }
-}
-
-impl Default for ProbabilisticScoringParameters {
-       fn default() -> Self {
-               Self {
-                       base_penalty_msat: 500,
-                       base_penalty_amount_multiplier_msat: 8192,
-                       liquidity_penalty_multiplier_msat: 30_000,
-                       liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
-                       liquidity_penalty_amount_multiplier_msat: 192,
-                       historical_liquidity_penalty_multiplier_msat: 10_000,
-                       historical_liquidity_penalty_amount_multiplier_msat: 64,
-                       historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
-                       manual_node_penalties: HashMap::new(),
-                       anti_probing_penalty_msat: 250,
-                       considered_impossible_penalty_msat: 1_0000_0000_000,
-               }
-       }
 }
 
 impl<T: Time> ChannelLiquidity<T> {
@@ -928,10 +966,9 @@ impl<T: Time> ChannelLiquidity<T> {
 
        /// Returns a view of the channel liquidity directed from `source` to `target` assuming
        /// `capacity_msat`.
-       fn as_directed<'a>(
-               &self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64,
-               params: &'a ProbabilisticScoringParameters
-       ) -> DirectedChannelLiquidity<'a, &u64, &HistoricalBucketRangeTracker, T, &T> {
+       fn as_directed(
+               &self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
+       ) -> DirectedChannelLiquidity<&u64, &HistoricalBucketRangeTracker, T, &T> {
                let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
                        if source < target {
                                (&self.min_liquidity_offset_msat, &self.max_liquidity_offset_msat,
@@ -950,16 +987,15 @@ impl<T: Time> ChannelLiquidity<T> {
                        capacity_msat,
                        last_updated: &self.last_updated,
                        now: T::now(),
-                       params,
+                       decay_params: decay_params,
                }
        }
 
        /// Returns a mutable view of the channel liquidity directed from `source` to `target` assuming
        /// `capacity_msat`.
-       fn as_directed_mut<'a>(
-               &mut self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64,
-               params: &'a ProbabilisticScoringParameters
-       ) -> DirectedChannelLiquidity<'a, &mut u64, &mut HistoricalBucketRangeTracker, T, &mut T> {
+       fn as_directed_mut(
+               &mut self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
+       ) -> DirectedChannelLiquidity<&mut u64, &mut HistoricalBucketRangeTracker, T, &mut T> {
                let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
                        if source < target {
                                (&mut self.min_liquidity_offset_msat, &mut self.max_liquidity_offset_msat,
@@ -978,7 +1014,7 @@ impl<T: Time> ChannelLiquidity<T> {
                        capacity_msat,
                        last_updated: &mut self.last_updated,
                        now: T::now(),
-                       params,
+                       decay_params: decay_params,
                }
        }
 }
@@ -995,10 +1031,10 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
 const AMOUNT_PENALTY_DIVISOR: u64 = 1 << 20;
 const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
 
-impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<'_, L, BRT, T, U> {
+impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity< L, BRT, T, U> {
        /// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
        /// this direction.
-       fn penalty_msat(&self, amount_msat: u64, params: &ProbabilisticScoringParameters) -> u64 {
+       fn penalty_msat(&self, amount_msat: u64, score_params: &ProbabilisticScoringFeeParameters) -> u64 {
                let max_liquidity_msat = self.max_liquidity_msat();
                let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
 
@@ -1010,9 +1046,9 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
                        // impossibility penalty.
                        let negative_log10_times_2048 = NEGATIVE_LOG10_UPPER_BOUND * 2048;
                        Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
-                                       params.liquidity_penalty_multiplier_msat,
-                                       params.liquidity_penalty_amount_multiplier_msat)
-                               .saturating_add(params.considered_impossible_penalty_msat)
+                                       score_params.liquidity_penalty_multiplier_msat,
+                                       score_params.liquidity_penalty_amount_multiplier_msat)
+                               .saturating_add(score_params.considered_impossible_penalty_msat)
                } else {
                        let numerator = (max_liquidity_msat - amount_msat).saturating_add(1);
                        let denominator = (max_liquidity_msat - min_liquidity_msat).saturating_add(1);
@@ -1025,13 +1061,13 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
                                let negative_log10_times_2048 =
                                        approx::negative_log10_times_2048(numerator, denominator);
                                Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
-                                       params.liquidity_penalty_multiplier_msat,
-                                       params.liquidity_penalty_amount_multiplier_msat)
+                                       score_params.liquidity_penalty_multiplier_msat,
+                                       score_params.liquidity_penalty_amount_multiplier_msat)
                        }
                };
 
-               if params.historical_liquidity_penalty_multiplier_msat != 0 ||
-                  params.historical_liquidity_penalty_amount_multiplier_msat != 0 {
+               if score_params.historical_liquidity_penalty_multiplier_msat != 0 ||
+                  score_params.historical_liquidity_penalty_amount_multiplier_msat != 0 {
                        let payment_amt_64th_bucket = if amount_msat < u64::max_value() / 64 {
                                amount_msat * 64 / self.capacity_msat.saturating_add(1)
                        } else {
@@ -1051,12 +1087,12 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
                        };
                        if let Some(cumulative_success_prob_times_billion) = buckets
                                .calculate_success_probability_times_billion(self.now, *self.last_updated,
-                                       params.historical_no_updates_half_life, payment_amt_64th_bucket as u8)
+                                       self.decay_params.historical_no_updates_half_life, payment_amt_64th_bucket as u8)
                        {
                                let historical_negative_log10_times_2048 = approx::negative_log10_times_2048(cumulative_success_prob_times_billion + 1, 1024 * 1024 * 1024);
                                res = res.saturating_add(Self::combined_penalty_msat(amount_msat,
-                                       historical_negative_log10_times_2048, params.historical_liquidity_penalty_multiplier_msat,
-                                       params.historical_liquidity_penalty_amount_multiplier_msat));
+                                       historical_negative_log10_times_2048, score_params.historical_liquidity_penalty_multiplier_msat,
+                                       score_params.historical_liquidity_penalty_amount_multiplier_msat));
                        } else {
                                // If we don't have any valid points (or, once decayed, we have less than a full
                                // point), redo the non-historical calculation with no liquidity bounds tracked and
@@ -1067,8 +1103,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
                                let negative_log10_times_2048 =
                                        approx::negative_log10_times_2048(numerator, denominator);
                                res = res.saturating_add(Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
-                                       params.historical_liquidity_penalty_multiplier_msat,
-                                       params.historical_liquidity_penalty_amount_multiplier_msat));
+                                       score_params.historical_liquidity_penalty_multiplier_msat,
+                                       score_params.historical_liquidity_penalty_amount_multiplier_msat));
                        }
                }
 
@@ -1111,13 +1147,13 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
 
        fn decayed_offset_msat(&self, offset_msat: u64) -> u64 {
                self.now.duration_since(*self.last_updated).as_secs()
-                       .checked_div(self.params.liquidity_offset_half_life.as_secs())
+                       .checked_div(self.decay_params.liquidity_offset_half_life.as_secs())
                        .and_then(|decays| offset_msat.checked_shr(decays as u32))
                        .unwrap_or(0)
        }
 }
 
-impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTracker>, T: Time, U: DerefMut<Target = T>> DirectedChannelLiquidity<'_, L, BRT, T, U> {
+impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTracker>, T: Time, U: DerefMut<Target = T>> DirectedChannelLiquidity<L, BRT, T, U> {
        /// Adjusts the channel liquidity balance bounds when failing to route `amount_msat`.
        fn failed_at_channel<Log: Deref>(&mut self, amount_msat: u64, chan_descr: fmt::Arguments, logger: &Log) where Log::Target: Logger {
                let existing_max_msat = self.max_liquidity_msat();
@@ -1154,7 +1190,7 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
 
        fn update_history_buckets(&mut self) {
                let half_lives = self.now.duration_since(*self.last_updated).as_secs()
-                       .checked_div(self.params.historical_no_updates_half_life.as_secs())
+                       .checked_div(self.decay_params.historical_no_updates_half_life.as_secs())
                        .map(|v| v.try_into().unwrap_or(u32::max_value())).unwrap_or(u32::max_value());
                self.min_liquidity_offset_history.time_decay_data(half_lives);
                self.max_liquidity_offset_history.time_decay_data(half_lives);
@@ -1193,15 +1229,16 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
 }
 
 impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
+       type ScoreParams = ProbabilisticScoringFeeParameters;
        fn channel_penalty_msat(
-               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
+               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &ProbabilisticScoringFeeParameters
        ) -> u64 {
-               if let Some(penalty) = self.params.manual_node_penalties.get(target) {
+               if let Some(penalty) = score_params.manual_node_penalties.get(target) {
                        return *penalty;
                }
 
-               let base_penalty_msat = self.params.base_penalty_msat.saturating_add(
-                       self.params.base_penalty_amount_multiplier_msat
+               let base_penalty_msat = score_params.base_penalty_msat.saturating_add(
+                       score_params.base_penalty_amount_multiplier_msat
                                .saturating_mul(usage.amount_msat) / BASE_AMOUNT_PENALTY_DIVISOR);
 
                let mut anti_probing_penalty_msat = 0;
@@ -1215,7 +1252,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
                        },
                        EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat } => {
                                if htlc_maximum_msat >= capacity_msat/2 {
-                                       anti_probing_penalty_msat = self.params.anti_probing_penalty_msat;
+                                       anti_probing_penalty_msat = score_params.anti_probing_penalty_msat;
                                }
                        },
                        _ => {},
@@ -1227,8 +1264,8 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
                self.channel_liquidities
                        .get(&short_channel_id)
                        .unwrap_or(&ChannelLiquidity::new())
-                       .as_directed(source, target, inflight_htlc_msat, capacity_msat, &self.params)
-                       .penalty_msat(amount_msat, &self.params)
+                       .as_directed(source, target, inflight_htlc_msat, capacity_msat, self.decay_params)
+                       .penalty_msat(amount_msat, score_params)
                        .saturating_add(anti_probing_penalty_msat)
                        .saturating_add(base_penalty_msat)
        }
@@ -1255,13 +1292,13 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
                                        self.channel_liquidities
                                                .entry(hop.short_channel_id)
                                                .or_insert_with(ChannelLiquidity::new)
-                                               .as_directed_mut(source, &target, 0, capacity_msat, &self.params)
+                                               .as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
                                                .failed_at_channel(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
                                } else {
                                        self.channel_liquidities
                                                .entry(hop.short_channel_id)
                                                .or_insert_with(ChannelLiquidity::new)
-                                               .as_directed_mut(source, &target, 0, capacity_msat, &self.params)
+                                               .as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
                                                .failed_downstream(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
                                }
                        } else {
@@ -1289,7 +1326,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
                                self.channel_liquidities
                                        .entry(hop.short_channel_id)
                                        .or_insert_with(ChannelLiquidity::new)
-                                       .as_directed_mut(source, &target, 0, capacity_msat, &self.params)
+                                       .as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
                                        .successful(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
                        } else {
                                log_debug!(self.logger, "Not able to learn for channel with SCID {} as we do not have graph info for it (likely a route-hint last-hop).",
@@ -1628,18 +1665,18 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Writeable for Probab
 }
 
 impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time>
-ReadableArgs<(ProbabilisticScoringParameters, G, L)> for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
+ReadableArgs<(ProbabilisticScoringDecayParameters, G, L)> for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
        #[inline]
        fn read<R: Read>(
-               r: &mut R, args: (ProbabilisticScoringParameters, G, L)
+               r: &mut R, args: (ProbabilisticScoringDecayParameters, G, L)
        ) -> Result<Self, DecodeError> {
-               let (params, network_graph, logger) = args;
+               let (decay_params, network_graph, logger) = args;
                let mut channel_liquidities = HashMap::new();
                read_tlv_fields!(r, {
                        (0, channel_liquidities, required),
                });
                Ok(Self {
-                       params,
+                       decay_params,
                        network_graph,
                        logger,
                        channel_liquidities,
@@ -1701,7 +1738,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
 
 #[cfg(test)]
 mod tests {
-       use super::{ChannelLiquidity, HistoricalBucketRangeTracker, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime};
+       use super::{ChannelLiquidity, HistoricalBucketRangeTracker, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters, ProbabilisticScorerUsingTime};
        use crate::blinded_path::{BlindedHop, BlindedPath};
        use crate::util::config::UserConfig;
        use crate::util::time::Time;
@@ -1874,8 +1911,8 @@ mod tests {
                let logger = TestLogger::new();
                let last_updated = SinceEpoch::now();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters::default();
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
+               let decay_params = ProbabilisticScoringDecayParameters::default();
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
                        .with_channel(42,
                                ChannelLiquidity {
                                        min_liquidity_offset_msat: 700, max_liquidity_offset_msat: 100, last_updated,
@@ -1897,52 +1934,52 @@ mod tests {
                // Update minimum liquidity.
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 100);
                assert_eq!(liquidity.max_liquidity_msat(), 300);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&target, &source, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &source, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 700);
                assert_eq!(liquidity.max_liquidity_msat(), 900);
 
                scorer.channel_liquidities.get_mut(&42).unwrap()
-                       .as_directed_mut(&source, &target, 0, 1_000, &scorer.params)
+                       .as_directed_mut(&source, &target, 0, 1_000, decay_params)
                        .set_min_liquidity_msat(200);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 200);
                assert_eq!(liquidity.max_liquidity_msat(), 300);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&target, &source, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &source, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 700);
                assert_eq!(liquidity.max_liquidity_msat(), 800);
 
                // Update maximum liquidity.
 
                let liquidity = scorer.channel_liquidities.get(&43).unwrap()
-                       .as_directed(&target, &recipient, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &recipient, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 700);
                assert_eq!(liquidity.max_liquidity_msat(), 900);
 
                let liquidity = scorer.channel_liquidities.get(&43).unwrap()
-                       .as_directed(&recipient, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&recipient, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 100);
                assert_eq!(liquidity.max_liquidity_msat(), 300);
 
                scorer.channel_liquidities.get_mut(&43).unwrap()
-                       .as_directed_mut(&target, &recipient, 0, 1_000, &scorer.params)
+                       .as_directed_mut(&target, &recipient, 0, 1_000, decay_params)
                        .set_max_liquidity_msat(200);
 
                let liquidity = scorer.channel_liquidities.get(&43).unwrap()
-                       .as_directed(&target, &recipient, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &recipient, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 0);
                assert_eq!(liquidity.max_liquidity_msat(), 200);
 
                let liquidity = scorer.channel_liquidities.get(&43).unwrap()
-                       .as_directed(&recipient, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&recipient, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 800);
                assert_eq!(liquidity.max_liquidity_msat(), 1000);
        }
@@ -1952,8 +1989,8 @@ mod tests {
                let logger = TestLogger::new();
                let last_updated = SinceEpoch::now();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters::default();
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
+               let decay_params = ProbabilisticScoringDecayParameters::default();
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
                        .with_channel(42,
                                ChannelLiquidity {
                                        min_liquidity_offset_msat: 200, max_liquidity_offset_msat: 400, last_updated,
@@ -1966,42 +2003,42 @@ mod tests {
 
                // Check initial bounds.
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 400);
                assert_eq!(liquidity.max_liquidity_msat(), 800);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&target, &source, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &source, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 200);
                assert_eq!(liquidity.max_liquidity_msat(), 600);
 
                // Reset from source to target.
                scorer.channel_liquidities.get_mut(&42).unwrap()
-                       .as_directed_mut(&source, &target, 0, 1_000, &scorer.params)
+                       .as_directed_mut(&source, &target, 0, 1_000, decay_params)
                        .set_min_liquidity_msat(900);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 900);
                assert_eq!(liquidity.max_liquidity_msat(), 1_000);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&target, &source, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &source, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 0);
                assert_eq!(liquidity.max_liquidity_msat(), 100);
 
                // Reset from target to source.
                scorer.channel_liquidities.get_mut(&42).unwrap()
-                       .as_directed_mut(&target, &source, 0, 1_000, &scorer.params)
+                       .as_directed_mut(&target, &source, 0, 1_000, decay_params)
                        .set_min_liquidity_msat(400);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 0);
                assert_eq!(liquidity.max_liquidity_msat(), 600);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&target, &source, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &source, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 400);
                assert_eq!(liquidity.max_liquidity_msat(), 1_000);
        }
@@ -2011,8 +2048,8 @@ mod tests {
                let logger = TestLogger::new();
                let last_updated = SinceEpoch::now();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters::default();
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
+               let decay_params = ProbabilisticScoringDecayParameters::default();
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
                        .with_channel(42,
                                ChannelLiquidity {
                                        min_liquidity_offset_msat: 200, max_liquidity_offset_msat: 400, last_updated,
@@ -2025,42 +2062,42 @@ mod tests {
 
                // Check initial bounds.
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 400);
                assert_eq!(liquidity.max_liquidity_msat(), 800);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&target, &source, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &source, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 200);
                assert_eq!(liquidity.max_liquidity_msat(), 600);
 
                // Reset from source to target.
                scorer.channel_liquidities.get_mut(&42).unwrap()
-                       .as_directed_mut(&source, &target, 0, 1_000, &scorer.params)
+                       .as_directed_mut(&source, &target, 0, 1_000, decay_params)
                        .set_max_liquidity_msat(300);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 0);
                assert_eq!(liquidity.max_liquidity_msat(), 300);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&target, &source, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &source, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 700);
                assert_eq!(liquidity.max_liquidity_msat(), 1_000);
 
                // Reset from target to source.
                scorer.channel_liquidities.get_mut(&42).unwrap()
-                       .as_directed_mut(&target, &source, 0, 1_000, &scorer.params)
+                       .as_directed_mut(&target, &source, 0, 1_000, decay_params)
                        .set_max_liquidity_msat(600);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 400);
                assert_eq!(liquidity.max_liquidity_msat(), 1_000);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&target, &source, 0, 1_000, &scorer.params);
+                       .as_directed(&target, &source, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 0);
                assert_eq!(liquidity.max_liquidity_msat(), 600);
        }
@@ -2069,11 +2106,12 @@ mod tests {
        fn increased_penalty_nearing_liquidity_upper_bound() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let decay_params = ProbabilisticScoringDecayParameters::default();
+               let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
 
@@ -2082,32 +2120,32 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 10_240, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 102_400, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 47);
                let usage = ChannelUsage { amount_msat: 1_023_999, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2_000);
 
                let usage = ChannelUsage {
                        amount_msat: 128,
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 58);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 58);
                let usage = ChannelUsage { amount_msat: 256, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 125);
                let usage = ChannelUsage { amount_msat: 374, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 198);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 198);
                let usage = ChannelUsage { amount_msat: 512, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
                let usage = ChannelUsage { amount_msat: 640, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 425);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 425);
                let usage = ChannelUsage { amount_msat: 768, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 602);
                let usage = ChannelUsage { amount_msat: 896, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 902);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 902);
        }
 
        #[test]
@@ -2115,12 +2153,15 @@ mod tests {
                let logger = TestLogger::new();
                let last_updated = SinceEpoch::now();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        considered_impossible_penalty_msat: u64::max_value(),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
+               let decay_params = ProbabilisticScoringDecayParameters {
+                       ..ProbabilisticScoringDecayParameters::zero_penalty()
+               };
+               let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
                        .with_channel(42,
                                ChannelLiquidity {
                                        min_liquidity_offset_msat: 40, max_liquidity_offset_msat: 40, last_updated,
@@ -2135,23 +2176,23 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 100, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 50, ..usage };
-               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
-               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
+               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
                let usage = ChannelUsage { amount_msat: 61, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
        }
 
        #[test]
        fn does_not_further_penalize_own_channel() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
                let sender = sender_node_id();
                let source = source_node_id();
                let usage = ChannelUsage {
@@ -2162,24 +2203,24 @@ mod tests {
                let failed_path = payment_path_for_amount(500);
                let successful_path = payment_path_for_amount(200);
 
-               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, &params), 301);
 
                scorer.payment_path_failed(&failed_path, 41);
-               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, &params), 301);
 
                scorer.payment_path_successful(&successful_path);
-               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, &params), 301);
        }
 
        #[test]
        fn sets_liquidity_lower_bound_on_downstream_failure() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
                let path = payment_path_for_amount(500);
@@ -2189,32 +2230,32 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 128);
                let usage = ChannelUsage { amount_msat: 500, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 301);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 301);
                let usage = ChannelUsage { amount_msat: 750, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 602);
 
                scorer.payment_path_failed(&path, 43);
 
                let usage = ChannelUsage { amount_msat: 250, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 500, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 750, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
        }
 
        #[test]
        fn sets_liquidity_upper_bound_on_failure() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        considered_impossible_penalty_msat: u64::max_value(),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
                let path = payment_path_for_amount(500);
@@ -2224,20 +2265,20 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 128);
                let usage = ChannelUsage { amount_msat: 500, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 301);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 301);
                let usage = ChannelUsage { amount_msat: 750, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 602);
 
                scorer.payment_path_failed(&path, 42);
 
                let usage = ChannelUsage { amount_msat: 250, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
                let usage = ChannelUsage { amount_msat: 500, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
                let usage = ChannelUsage { amount_msat: 750, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
        }
 
        #[test]
@@ -2274,39 +2315,39 @@ mod tests {
                let node_c = NodeId::from_pubkey(&pub_c);
                let node_d = NodeId::from_pubkey(&pub_d);
 
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
 
                let usage = ChannelUsage {
                        amount_msat: 250,
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage, &params), 128);
                // Note that a default liquidity bound is used for B -> C as no channel exists
-               assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage), 128);
-               assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage, &params), 128);
+               assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage, &params), 128);
 
                scorer.payment_path_failed(&Path { hops: path, blinded_tail: None }, 43);
 
-               assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage), 80);
+               assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage, &params), 80);
                // Note that a default liquidity bound is used for B -> C as no channel exists
-               assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage), 128);
-               assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage, &params), 128);
+               assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage, &params), 128);
        }
 
        #[test]
        fn reduces_liquidity_upper_bound_along_path_on_success() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
                let sender = sender_node_id();
                let source = source_node_id();
                let target = target_node_id();
@@ -2317,28 +2358,31 @@ mod tests {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
                };
 
-               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 128);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
-               assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, &params), 128);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 128);
+               assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage, &params), 128);
 
                scorer.payment_path_successful(&payment_path_for_amount(500));
 
-               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 128);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
-               assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, &params), 128);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
+               assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage, &params), 300);
        }
 
        #[test]
        fn decays_liquidity_bounds_over_time() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       liquidity_offset_half_life: Duration::from_secs(10),
                        considered_impossible_penalty_msat: u64::max_value(),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let decay_params = ProbabilisticScoringDecayParameters {
+                       liquidity_offset_half_life: Duration::from_secs(10),
+                       ..ProbabilisticScoringDecayParameters::zero_penalty()
+               };
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
 
@@ -2347,77 +2391,80 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_024 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 1_023, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2_000);
 
                scorer.payment_path_failed(&payment_path_for_amount(768), 42);
                scorer.payment_path_failed(&payment_path_for_amount(128), 43);
 
                let usage = ChannelUsage { amount_msat: 128, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 256, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 93);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 93);
                let usage = ChannelUsage { amount_msat: 768, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_479);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1_479);
                let usage = ChannelUsage { amount_msat: 896, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
 
                SinceEpoch::advance(Duration::from_secs(9));
                let usage = ChannelUsage { amount_msat: 128, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 256, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 93);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 93);
                let usage = ChannelUsage { amount_msat: 768, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_479);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1_479);
                let usage = ChannelUsage { amount_msat: 896, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
 
                SinceEpoch::advance(Duration::from_secs(1));
                let usage = ChannelUsage { amount_msat: 64, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 128, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 34);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 34);
                let usage = ChannelUsage { amount_msat: 896, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_970);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1_970);
                let usage = ChannelUsage { amount_msat: 960, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
 
                // Fully decay liquidity lower bound.
                SinceEpoch::advance(Duration::from_secs(10 * 7));
                let usage = ChannelUsage { amount_msat: 0, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 1, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 1_023, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2_000);
                let usage = ChannelUsage { amount_msat: 1_024, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
 
                // Fully decay liquidity upper bound.
                SinceEpoch::advance(Duration::from_secs(10));
                let usage = ChannelUsage { amount_msat: 0, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 1_024, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
 
                SinceEpoch::advance(Duration::from_secs(10));
                let usage = ChannelUsage { amount_msat: 0, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
                let usage = ChannelUsage { amount_msat: 1_024, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
        }
 
        #[test]
        fn decays_liquidity_bounds_without_shift_overflow() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
+               };
+               let decay_params = ProbabilisticScoringDecayParameters {
                        liquidity_offset_half_life: Duration::from_secs(10),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringDecayParameters::default()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
                let usage = ChannelUsage {
@@ -2425,30 +2472,33 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 125);
 
                scorer.payment_path_failed(&payment_path_for_amount(512), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 281);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 281);
 
                // An unchecked right shift 64 bits or more in DirectedChannelLiquidity::decayed_offset_msat
                // would cause an overflow.
                SinceEpoch::advance(Duration::from_secs(10 * 64));
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 125);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 125);
        }
 
        #[test]
        fn restricts_liquidity_bounds_after_decay() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
+               };
+               let decay_params = ProbabilisticScoringDecayParameters {
                        liquidity_offset_half_life: Duration::from_secs(10),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringDecayParameters::default()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
                let usage = ChannelUsage {
@@ -2457,43 +2507,46 @@ mod tests {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
                };
 
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
 
                // More knowledge gives higher confidence (256, 768), meaning a lower penalty.
                scorer.payment_path_failed(&payment_path_for_amount(768), 42);
                scorer.payment_path_failed(&payment_path_for_amount(256), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 281);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 281);
 
                // Decaying knowledge gives less confidence (128, 896), meaning a higher penalty.
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 291);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 291);
 
                // Reducing the upper bound gives more confidence (128, 832) that the payment amount (512)
                // is closer to the upper bound, meaning a higher penalty.
                scorer.payment_path_successful(&payment_path_for_amount(64));
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 331);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 331);
 
                // Increasing the lower bound gives more confidence (256, 832) that the payment amount (512)
                // is closer to the lower bound, meaning a lower penalty.
                scorer.payment_path_failed(&payment_path_for_amount(256), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 245);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 245);
 
                // Further decaying affects the lower bound more than the upper bound (128, 928).
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 280);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 280);
        }
 
        #[test]
        fn restores_persisted_liquidity_bounds() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       liquidity_offset_half_life: Duration::from_secs(10),
                        considered_impossible_penalty_msat: u64::max_value(),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger);
+               let decay_params = ProbabilisticScoringDecayParameters {
+                       liquidity_offset_half_life: Duration::from_secs(10),
+                       ..ProbabilisticScoringDecayParameters::default()
+               };
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
                let usage = ChannelUsage {
@@ -2503,34 +2556,37 @@ mod tests {
                };
 
                scorer.payment_path_failed(&payment_path_for_amount(500), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 473);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 473);
 
                scorer.payment_path_failed(&payment_path_for_amount(250), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
 
                let mut serialized_scorer = Vec::new();
                scorer.write(&mut serialized_scorer).unwrap();
 
                let mut serialized_scorer = io::Cursor::new(&serialized_scorer);
                let deserialized_scorer =
-                       <ProbabilisticScorer>::read(&mut serialized_scorer, (params, &network_graph, &logger)).unwrap();
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+                       <ProbabilisticScorer>::read(&mut serialized_scorer, (decay_params, &network_graph, &logger)).unwrap();
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
        }
 
        #[test]
        fn decays_persisted_liquidity_bounds() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       liquidity_offset_half_life: Duration::from_secs(10),
                        considered_impossible_penalty_msat: u64::max_value(),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger);
+               let decay_params = ProbabilisticScoringDecayParameters {
+                       liquidity_offset_half_life: Duration::from_secs(10),
+                       ..ProbabilisticScoringDecayParameters::zero_penalty()
+               };
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
                let usage = ChannelUsage {
@@ -2540,7 +2596,7 @@ mod tests {
                };
 
                scorer.payment_path_failed(&payment_path_for_amount(500), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
 
                let mut serialized_scorer = Vec::new();
                scorer.write(&mut serialized_scorer).unwrap();
@@ -2549,14 +2605,14 @@ mod tests {
 
                let mut serialized_scorer = io::Cursor::new(&serialized_scorer);
                let deserialized_scorer =
-                       <ProbabilisticScorer>::read(&mut serialized_scorer, (params, &network_graph, &logger)).unwrap();
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 473);
+                       <ProbabilisticScorer>::read(&mut serialized_scorer, (decay_params, &network_graph, &logger)).unwrap();
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage, &params), 473);
 
                scorer.payment_path_failed(&payment_path_for_amount(250), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 365);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage, &params), 365);
        }
 
        #[test]
@@ -2565,8 +2621,8 @@ mod tests {
                // 50k sat reserve).
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters::default();
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let params = ProbabilisticScoringFeeParameters::default();
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
 
@@ -2575,47 +2631,47 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 4375);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 4375);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2739);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2739);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2236);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2236);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1983);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1983);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1637);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1637);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1606);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1606);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1331);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1331);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1387);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1387);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1379);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1379);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1363);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1363);
                let usage = ChannelUsage {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1355);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 1355);
        }
 
        #[test]
@@ -2630,28 +2686,28 @@ mod tests {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
                };
 
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 58);
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 58);
 
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
-                       anti_probing_penalty_msat: 0, ..ProbabilisticScoringParameters::zero_penalty()
+                       anti_probing_penalty_msat: 0, ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 558);
 
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
                        base_penalty_amount_multiplier_msat: (1 << 30),
-                       anti_probing_penalty_msat: 0, ..ProbabilisticScoringParameters::zero_penalty()
+                       anti_probing_penalty_msat: 0, ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
 
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558 + 128);
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 558 + 128);
        }
 
        #[test]
@@ -2666,21 +2722,21 @@ mod tests {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
                };
 
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        liquidity_penalty_amount_multiplier_msat: 0,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
 
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        liquidity_penalty_amount_multiplier_msat: 256,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 337);
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 337);
        }
 
        #[test]
@@ -2695,23 +2751,24 @@ mod tests {
                        effective_capacity: EffectiveCapacity::Infinite,
                };
 
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 40_000,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 80_000);
+               let decay_params = ProbabilisticScoringDecayParameters::zero_penalty();
+               let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 80_000);
        }
 
        #[test]
        fn accounts_for_inflight_htlc_usage() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        considered_impossible_penalty_msat: u64::max_value(),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
 
@@ -2720,18 +2777,18 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
                };
-               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
 
                let usage = ChannelUsage { inflight_htlc_msat: 251, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
        }
 
        #[test]
        fn removes_uncertainity_when_exact_liquidity_known() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters::default();
-               let scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger);
+               let params = ProbabilisticScoringFeeParameters::default();
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
 
@@ -2741,27 +2798,29 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::ExactLiquidity { liquidity_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), base_penalty_msat);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), base_penalty_msat);
 
                let usage = ChannelUsage { amount_msat: 1_000, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), base_penalty_msat);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), base_penalty_msat);
 
                let usage = ChannelUsage { amount_msat: 1_001, ..usage };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), u64::max_value());
        }
 
        #[test]
        fn remembers_historical_failures() {
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
-                       liquidity_offset_half_life: Duration::from_secs(60 * 60),
+               let params = ProbabilisticScoringFeeParameters {
                        historical_liquidity_penalty_multiplier_msat: 1024,
                        historical_liquidity_penalty_amount_multiplier_msat: 1024,
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
+               };
+               let decay_params = ProbabilisticScoringDecayParameters {
+                       liquidity_offset_half_life: Duration::from_secs(60 * 60),
                        historical_no_updates_half_life: Duration::from_secs(10),
-                       ..ProbabilisticScoringParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
 
@@ -2771,12 +2830,12 @@ mod tests {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_024 },
                };
                // With no historical data the normal liquidity penalty calculation is used.
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 47);
                assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
                        None);
 
                scorer.payment_path_failed(&payment_path_for_amount(1), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2048);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2048);
                // The "it failed" increment is 32, where the probability should lie fully in the first
                // octile.
                assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
@@ -2785,7 +2844,7 @@ mod tests {
                // Even after we tell the scorer we definitely have enough available liquidity, it will
                // still remember that there was some failure in the past, and assign a non-0 penalty.
                scorer.payment_path_failed(&payment_path_for_amount(1000), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 198);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 198);
                // The first octile should be decayed just slightly and the last octile has a new point.
                assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
                        Some(([31, 0, 0, 0, 0, 0, 0, 32], [31, 0, 0, 0, 0, 0, 0, 32])));
@@ -2793,7 +2852,7 @@ mod tests {
                // Advance the time forward 16 half-lives (which the docs claim will ensure all data is
                // gone), and check that we're back to where we started.
                SinceEpoch::advance(Duration::from_secs(10 * 16));
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 47);
                // Once fully decayed we still have data, but its all-0s. In the future we may remove the
                // data entirely instead.
                assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
@@ -2805,14 +2864,14 @@ mod tests {
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_024 },
                };
                scorer.payment_path_failed(&payment_path_for_amount(1), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 409);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 409);
 
                let usage = ChannelUsage {
                        amount_msat: 1,
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::MaximumHTLC { amount_msat: 0 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &target, &source, usage), 2048);
+               assert_eq!(scorer.channel_penalty_msat(42, &target, &source, usage, &params), 2048);
 
                // Advance to decay all liquidity offsets to zero.
                SinceEpoch::advance(Duration::from_secs(60 * 60 * 10));
@@ -2833,11 +2892,11 @@ mod tests {
                let network_graph = network_graph(&logger);
                let source = source_node_id();
                let target = target_node_id();
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        anti_probing_penalty_msat: 500,
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
 
                // Check we receive no penalty for a low htlc_maximum_msat.
                let usage = ChannelUsage {
@@ -2845,7 +2904,7 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
 
                // Check we receive anti-probing penalty for htlc_maximum_msat == channel_capacity.
                let usage = ChannelUsage {
@@ -2853,7 +2912,7 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_024_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 500);
 
                // Check we receive anti-probing penalty for htlc_maximum_msat == channel_capacity/2.
                let usage = ChannelUsage {
@@ -2861,7 +2920,7 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 512_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 500);
 
                // Check we receive no anti-probing penalty for htlc_maximum_msat == channel_capacity/2 - 1.
                let usage = ChannelUsage {
@@ -2869,7 +2928,7 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 511_999 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 0);
        }
 
        #[test]
@@ -2877,12 +2936,12 @@ mod tests {
                // Make sure we'll account for a blinded path's final_value_msat in scoring
                let logger = TestLogger::new();
                let network_graph = network_graph(&logger);
-               let params = ProbabilisticScoringParameters {
+               let params = ProbabilisticScoringFeeParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
-                       liquidity_offset_half_life: Duration::from_secs(10),
-                       ..ProbabilisticScoringParameters::zero_penalty()
+                       ..ProbabilisticScoringFeeParameters::zero_penalty()
                };
-               let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let decay_params = ProbabilisticScoringDecayParameters::default();
+               let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
                let usage = ChannelUsage {
@@ -2890,7 +2949,7 @@ mod tests {
                        inflight_htlc_msat: 0,
                        effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
                };
-               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 300);
 
                let mut path = payment_path_for_amount(768);
                let recipient_hop = path.hops.pop().unwrap();
@@ -2917,7 +2976,7 @@ mod tests {
                scorer.payment_path_failed(&path, 43);
 
                let liquidity = scorer.channel_liquidities.get(&42).unwrap()
-                       .as_directed(&source, &target, 0, 1_000, &scorer.params);
+                       .as_directed(&source, &target, 0, 1_000, decay_params);
                assert_eq!(liquidity.min_liquidity_msat(), 256);
                assert_eq!(liquidity.max_liquidity_msat(), 768);
        }
index 9ba3ba556c8f150245aa35ab7cea07c0d08bc97d..226a2bab72b9c35d26bcac26d462a3d34bfe2a6c 100644 (file)
@@ -16,6 +16,7 @@ use bitcoin::blockdata::transaction::{Transaction, TxOut, TxIn, EcdsaSighashType
 use bitcoin::blockdata::script::{Script, Builder};
 use bitcoin::blockdata::opcodes;
 use bitcoin::network::constants::Network;
+use bitcoin::psbt::PartiallySignedTransaction;
 use bitcoin::util::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber};
 use bitcoin::util::sighash;
 
@@ -218,6 +219,126 @@ impl_writeable_tlv_based_enum!(SpendableOutputDescriptor,
        (2, StaticPaymentOutput),
 );
 
+impl SpendableOutputDescriptor {
+       /// Turns this into a [`bitcoin::psbt::Input`] which can be used to create a
+       /// [`PartiallySignedTransaction`] which spends the given descriptor.
+       ///
+       /// Note that this does not include any signatures, just the information required to
+       /// construct the transaction and sign it.
+       pub fn to_psbt_input(&self) -> bitcoin::psbt::Input {
+               match self {
+                       SpendableOutputDescriptor::StaticOutput { output, .. } => {
+                               // Is a standard P2WPKH, no need for witness script
+                               bitcoin::psbt::Input {
+                                       witness_utxo: Some(output.clone()),
+                                       ..Default::default()
+                               }
+                       },
+                       SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
+                               // TODO we could add the witness script as well
+                               bitcoin::psbt::Input {
+                                       witness_utxo: Some(descriptor.output.clone()),
+                                       ..Default::default()
+                               }
+                       },
+                       SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
+                               // TODO we could add the witness script as well
+                               bitcoin::psbt::Input {
+                                       witness_utxo: Some(descriptor.output.clone()),
+                                       ..Default::default()
+                               }
+                       },
+               }
+       }
+
+       /// Creates an unsigned [`PartiallySignedTransaction`] which spends the given descriptors to
+       /// the given outputs, plus an output to the given change destination (if sufficient
+       /// change value remains). The PSBT will have a feerate, at least, of the given value.
+       ///
+       /// The `locktime` argument is used to set the transaction's locktime. If `None`, the
+       /// transaction will have a locktime of 0. It it recommended to set this to the current block
+       /// height to avoid fee sniping, unless you have some specific reason to use a different
+       /// locktime.
+       ///
+       /// Returns the PSBT and expected max transaction weight.
+       ///
+       /// 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.
+       ///
+       /// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
+       pub fn create_spendable_outputs_psbt(descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: Script, feerate_sat_per_1000_weight: u32, locktime: Option<PackedLockTime>) -> Result<(PartiallySignedTransaction, usize), ()> {
+               let mut input = Vec::with_capacity(descriptors.len());
+               let mut input_value = 0;
+               let mut witness_weight = 0;
+               let mut output_set = HashSet::with_capacity(descriptors.len());
+               for outp in descriptors {
+                       match outp {
+                               SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
+                                       if !output_set.insert(descriptor.outpoint) { return Err(()); }
+                                       input.push(TxIn {
+                                               previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
+                                               script_sig: Script::new(),
+                                               sequence: Sequence::ZERO,
+                                               witness: Witness::new(),
+                                       });
+                                       witness_weight += StaticPaymentOutputDescriptor::MAX_WITNESS_LENGTH;
+                                       #[cfg(feature = "grind_signatures")]
+                                       { witness_weight -= 1; } // Guarantees a low R signature
+                                       input_value += descriptor.output.value;
+                               },
+                               SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
+                                       if !output_set.insert(descriptor.outpoint) { return Err(()); }
+                                       input.push(TxIn {
+                                               previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
+                                               script_sig: Script::new(),
+                                               sequence: Sequence(descriptor.to_self_delay as u32),
+                                               witness: Witness::new(),
+                                       });
+                                       witness_weight += DelayedPaymentOutputDescriptor::MAX_WITNESS_LENGTH;
+                                       #[cfg(feature = "grind_signatures")]
+                                       { witness_weight -= 1; } // Guarantees a low R signature
+                                       input_value += descriptor.output.value;
+                               },
+                               SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => {
+                                       if !output_set.insert(*outpoint) { return Err(()); }
+                                       input.push(TxIn {
+                                               previous_output: outpoint.into_bitcoin_outpoint(),
+                                               script_sig: Script::new(),
+                                               sequence: Sequence::ZERO,
+                                               witness: Witness::new(),
+                                       });
+                                       witness_weight += 1 + 73 + 34;
+                                       #[cfg(feature = "grind_signatures")]
+                                       { witness_weight -= 1; } // Guarantees a low R signature
+                                       input_value += output.value;
+                               }
+                       }
+                       if input_value > MAX_VALUE_MSAT / 1000 { return Err(()); }
+               }
+               let mut tx = Transaction {
+                       version: 2,
+                       lock_time: locktime.unwrap_or(PackedLockTime::ZERO),
+                       input,
+                       output: outputs,
+               };
+               let expected_max_weight =
+                       transaction_utils::maybe_add_change_output(&mut tx, input_value, witness_weight, feerate_sat_per_1000_weight, change_destination_script)?;
+
+               let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input()).collect::<Vec<_>>();
+               let psbt = PartiallySignedTransaction {
+                       inputs: psbt_inputs,
+                       outputs: vec![Default::default(); tx.output.len()],
+                       unsigned_tx: tx,
+                       xpub: Default::default(),
+                       version: 0,
+                       proprietary: Default::default(),
+                       unknown: Default::default(),
+               };
+               Ok((psbt, expected_max_weight))
+       }
+}
+
 /// A trait to handle Lightning channel key material without concretizing the channel type or
 /// the signature mechanism.
 pub trait ChannelSigner {
@@ -1171,97 +1292,40 @@ impl KeysManager {
                )
        }
 
-       /// Creates a [`Transaction`] which spends the given descriptors to the given outputs, plus an
-       /// output to the given change destination (if sufficient change value remains). The
-       /// transaction will have a feerate, at least, of the given value.
+       /// Signs the given [`PartiallySignedTransaction`] which spends the given [`SpendableOutputDescriptor`]s.
+       /// The resulting inputs will be finalized and the PSBT will be ready for broadcast if there
+       /// are no other inputs that need signing.
        ///
-       /// 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.
-       ///
-       /// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
+       /// Returns `Err(())` if the PSBT is missing a descriptor or if we fail to sign.
        ///
        /// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
        /// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
-       pub fn spend_spendable_outputs<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: Script, feerate_sat_per_1000_weight: u32, secp_ctx: &Secp256k1<C>) -> Result<Transaction, ()> {
-               let mut input = Vec::new();
-               let mut input_value = 0;
-               let mut witness_weight = 0;
-               let mut output_set = HashSet::with_capacity(descriptors.len());
-               for outp in descriptors {
-                       match outp {
-                               SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
-                                       input.push(TxIn {
-                                               previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
-                                               script_sig: Script::new(),
-                                               sequence: Sequence::ZERO,
-                                               witness: Witness::new(),
-                                       });
-                                       witness_weight += StaticPaymentOutputDescriptor::MAX_WITNESS_LENGTH;
-                                       #[cfg(feature = "grind_signatures")]
-                                       { witness_weight -= 1; } // Guarantees a low R signature
-                                       input_value += descriptor.output.value;
-                                       if !output_set.insert(descriptor.outpoint) { return Err(()); }
-                               },
-                               SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
-                                       input.push(TxIn {
-                                               previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
-                                               script_sig: Script::new(),
-                                               sequence: Sequence(descriptor.to_self_delay as u32),
-                                               witness: Witness::new(),
-                                       });
-                                       witness_weight += DelayedPaymentOutputDescriptor::MAX_WITNESS_LENGTH;
-                                       #[cfg(feature = "grind_signatures")]
-                                       { witness_weight -= 1; } // Guarantees a low R signature
-                                       input_value += descriptor.output.value;
-                                       if !output_set.insert(descriptor.outpoint) { return Err(()); }
-                               },
-                               SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => {
-                                       input.push(TxIn {
-                                               previous_output: outpoint.into_bitcoin_outpoint(),
-                                               script_sig: Script::new(),
-                                               sequence: Sequence::ZERO,
-                                               witness: Witness::new(),
-                                       });
-                                       witness_weight += 1 + 73 + 34;
-                                       #[cfg(feature = "grind_signatures")]
-                                       { witness_weight -= 1; } // Guarantees a low R signature
-                                       input_value += output.value;
-                                       if !output_set.insert(*outpoint) { return Err(()); }
-                               }
-                       }
-                       if input_value > MAX_VALUE_MSAT / 1000 { return Err(()); }
-               }
-               let mut spend_tx = Transaction {
-                       version: 2,
-                       lock_time: PackedLockTime(0),
-                       input,
-                       output: outputs,
-               };
-               let expected_max_weight =
-                       transaction_utils::maybe_add_change_output(&mut spend_tx, input_value, witness_weight, feerate_sat_per_1000_weight, change_destination_script)?;
-
+       pub fn sign_spendable_outputs_psbt<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], psbt: &mut PartiallySignedTransaction, secp_ctx: &Secp256k1<C>) -> Result<(), ()> {
                let mut keys_cache: Option<(InMemorySigner, [u8; 32])> = None;
-               let mut input_idx = 0;
                for outp in descriptors {
                        match outp {
                                SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
+                                       let input_idx = psbt.unsigned_tx.input.iter().position(|i| i.previous_output == descriptor.outpoint.into_bitcoin_outpoint()).ok_or(())?;
                                        if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id {
                                                keys_cache = Some((
                                                        self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id),
                                                        descriptor.channel_keys_id));
                                        }
-                                       spend_tx.input[input_idx].witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?);
+                                       let witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input(&psbt.unsigned_tx, input_idx, &descriptor, &secp_ctx)?);
+                                       psbt.inputs[input_idx].final_script_witness = Some(witness);
                                },
                                SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
+                                       let input_idx = psbt.unsigned_tx.input.iter().position(|i| i.previous_output == descriptor.outpoint.into_bitcoin_outpoint()).ok_or(())?;
                                        if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id {
                                                keys_cache = Some((
                                                        self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id),
                                                        descriptor.channel_keys_id));
                                        }
-                                       spend_tx.input[input_idx].witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_dynamic_p2wsh_input(&spend_tx, input_idx, &descriptor, &secp_ctx)?);
+                                       let witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_dynamic_p2wsh_input(&psbt.unsigned_tx, input_idx, &descriptor, &secp_ctx)?);
+                                       psbt.inputs[input_idx].final_script_witness = Some(witness);
                                },
-                               SpendableOutputDescriptor::StaticOutput { ref output, .. } => {
+                               SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => {
+                                       let input_idx = psbt.unsigned_tx.input.iter().position(|i| i.previous_output == outpoint.into_bitcoin_outpoint()).ok_or(())?;
                                        let derivation_idx = if output.script_pubkey == self.destination_script {
                                                1
                                        } else {
@@ -1288,17 +1352,42 @@ impl KeysManager {
 
                                        if payment_script != output.script_pubkey { return Err(()); };
 
-                                       let sighash = hash_to_message!(&sighash::SighashCache::new(&spend_tx).segwit_signature_hash(input_idx, &witness_script, output.value, EcdsaSighashType::All).unwrap()[..]);
+                                       let sighash = hash_to_message!(&sighash::SighashCache::new(&psbt.unsigned_tx).segwit_signature_hash(input_idx, &witness_script, output.value, EcdsaSighashType::All).unwrap()[..]);
                                        let sig = sign_with_aux_rand(secp_ctx, &sighash, &secret.private_key, &self);
                                        let mut sig_ser = sig.serialize_der().to_vec();
                                        sig_ser.push(EcdsaSighashType::All as u8);
-                                       spend_tx.input[input_idx].witness.push(sig_ser);
-                                       spend_tx.input[input_idx].witness.push(pubkey.inner.serialize().to_vec());
+                                       let witness = Witness::from_vec(vec![sig_ser, pubkey.inner.serialize().to_vec()]);
+                                       psbt.inputs[input_idx].final_script_witness = Some(witness);
                                },
                        }
-                       input_idx += 1;
                }
 
+               Ok(())
+       }
+
+       /// Creates a [`Transaction`] which spends the given descriptors to the given outputs, plus an
+       /// output to the given change destination (if sufficient change value remains). The
+       /// transaction will have a feerate, at least, of the given value.
+       ///
+       /// The `locktime` argument is used to set the transaction's locktime. If `None`, the
+       /// transaction will have a locktime of 0. It it recommended to set this to the current block
+       /// height to avoid fee sniping, unless you have some specific reason to use a different
+       /// locktime.
+       ///
+       /// 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.
+       ///
+       /// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
+       ///
+       /// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
+       /// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
+       pub fn spend_spendable_outputs<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: Script, feerate_sat_per_1000_weight: u32, locktime: Option<PackedLockTime>, secp_ctx: &Secp256k1<C>) -> Result<Transaction, ()> {
+               let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime)?;
+               self.sign_spendable_outputs_psbt(descriptors, &mut psbt, secp_ctx)?;
+
+               let spend_tx = psbt.extract_tx();
+
                debug_assert!(expected_max_weight >= spend_tx.weight());
                // Note that witnesses with a signature vary somewhat in size, so allow
                // `expected_max_weight` to overshoot by up to 3 bytes per input.
@@ -1512,8 +1601,8 @@ impl PhantomKeysManager {
        }
 
        /// See [`KeysManager::spend_spendable_outputs`] for documentation on this method.
-       pub fn spend_spendable_outputs<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: Script, feerate_sat_per_1000_weight: u32, secp_ctx: &Secp256k1<C>) -> Result<Transaction, ()> {
-               self.inner.spend_spendable_outputs(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, secp_ctx)
+       pub fn spend_spendable_outputs<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: Script, feerate_sat_per_1000_weight: u32, locktime: Option<PackedLockTime>, secp_ctx: &Secp256k1<C>) -> Result<Transaction, ()> {
+               self.inner.spend_spendable_outputs(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime, secp_ctx)
        }
 
        /// See [`KeysManager::derive_channel_keys`] for documentation on this method.
@@ -1539,8 +1628,8 @@ pub fn dyn_sign() {
        let _signer: Box<dyn EcdsaChannelSigner>;
 }
 
-#[cfg(all(test, feature = "_bench_unstable", not(feature = "no-std")))]
-mod benches {
+#[cfg(ldk_bench)]
+pub mod benches {
        use std::sync::{Arc, mpsc};
        use std::sync::mpsc::TryRecvError;
        use std::thread;
@@ -1549,10 +1638,9 @@ mod benches {
        use bitcoin::Network;
        use crate::sign::{EntropySource, KeysManager};
 
-       use test::Bencher;
+       use criterion::Criterion;
 
-       #[bench]
-       fn bench_get_secure_random_bytes(bench: &mut Bencher) {
+       pub fn bench_get_secure_random_bytes(bench: &mut Criterion) {
                let seed = [0u8; 32];
                let now = Duration::from_secs(genesis_block(Network::Testnet).header.time as u64);
                let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_micros()));
@@ -1578,11 +1666,8 @@ mod benches {
                        stops.push(stop_sender);
                }
 
-               bench.iter(|| {
-                       for _ in 1..100 {
-                               keys_manager.get_secure_random_bytes();
-                       }
-               });
+               bench.bench_function("get_secure_random_bytes", |b| b.iter(||
+                       keys_manager.get_secure_random_bytes()));
 
                for stop in stops {
                        let _ = stop.send(());
@@ -1591,5 +1676,4 @@ mod benches {
                        handle.join().unwrap();
                }
        }
-
 }
index 1b2b9a739b8c5d3078204917f55b0fef86e87f13..348bd90274ae1632b1cec63cf98e9249d9ac7425 100644 (file)
@@ -3,7 +3,7 @@
 pub(crate) enum LockHeldState {
        HeldByThread,
        NotHeldByThread,
-       #[cfg(any(feature = "_bench_unstable", not(test)))]
+       #[cfg(any(ldk_bench, not(test)))]
        Unsupported,
 }
 
@@ -20,20 +20,20 @@ pub(crate) trait LockTestExt<'a> {
        fn unsafe_well_ordered_double_lock_self(&'a self) -> Self::ExclLock;
 }
 
-#[cfg(all(feature = "std", not(feature = "_bench_unstable"), test))]
+#[cfg(all(feature = "std", not(ldk_bench), test))]
 mod debug_sync;
-#[cfg(all(feature = "std", not(feature = "_bench_unstable"), test))]
+#[cfg(all(feature = "std", not(ldk_bench), test))]
 pub use debug_sync::*;
-#[cfg(all(feature = "std", not(feature = "_bench_unstable"), test))]
+#[cfg(all(feature = "std", not(ldk_bench), test))]
 // Note that to make debug_sync's regex work this must not contain `debug_string` in the module name
 mod test_lockorder_checks;
 
-#[cfg(all(feature = "std", any(feature = "_bench_unstable", not(test))))]
+#[cfg(all(feature = "std", any(ldk_bench, not(test))))]
 pub(crate) mod fairrwlock;
-#[cfg(all(feature = "std", any(feature = "_bench_unstable", not(test))))]
+#[cfg(all(feature = "std", any(ldk_bench, not(test))))]
 pub use {std::sync::{Arc, Mutex, Condvar, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}, fairrwlock::FairRwLock};
 
-#[cfg(all(feature = "std", any(feature = "_bench_unstable", not(test))))]
+#[cfg(all(feature = "std", any(ldk_bench, not(test))))]
 mod ext_impl {
        use super::*;
        impl<'a, T: 'a> LockTestExt<'a> for Mutex<T> {
index 707ca2b326d0d5720cae5abec48885e443b46a59..cbdb5485e7bd984312c5a139e220835769f8f73b 100644 (file)
@@ -1349,6 +1349,50 @@ impl Readable for Duration {
        }
 }
 
+/// A wrapper for a `Transaction` which can only be constructed with [`TransactionU16LenLimited::new`]
+/// if the `Transaction`'s consensus-serialized length is <= u16::MAX.
+///
+/// Use [`TransactionU16LenLimited::into_transaction`] to convert into the contained `Transaction`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TransactionU16LenLimited(Transaction);
+
+impl TransactionU16LenLimited {
+       /// Constructs a new `TransactionU16LenLimited` from a `Transaction` only if it's consensus-
+       /// serialized length is <= u16::MAX.
+       pub fn new(transaction: Transaction) -> Result<Self, ()> {
+               if transaction.serialized_length() > (u16::MAX as usize) {
+                       Err(())
+               } else {
+                       Ok(Self(transaction))
+               }
+       }
+
+       /// Consumes this `TransactionU16LenLimited` and returns its contained `Transaction`.
+       pub fn into_transaction(self) -> Transaction {
+               self.0
+       }
+}
+
+impl Writeable for TransactionU16LenLimited {
+       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+               (self.0.serialized_length() as u16).write(w)?;
+               self.0.write(w)
+       }
+}
+
+impl Readable for TransactionU16LenLimited {
+       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+               let len = <u16 as Readable>::read(r)?;
+               let mut tx_reader = FixedLengthReader::new(r, len as u64);
+               let tx: Transaction = Readable::read(&mut tx_reader)?;
+               if tx_reader.bytes_remain() {
+                       Err(DecodeError::BadLengthDescriptor)
+               } else {
+                       Ok(Self(tx))
+               }
+       }
+}
+
 #[cfg(test)]
 mod tests {
        use core::convert::TryFrom;
index 598f73e0f1101dde53704cf01ceef83f220ccef0..331ef3b1172c9492d34c39626b556e31bc2e1a64 100644 (file)
@@ -126,10 +126,10 @@ impl<'a> Router for TestRouter<'a> {
                                                // Since the path is reversed, the last element in our iteration is the first
                                                // hop.
                                                if idx == path.hops.len() - 1 {
-                                                       scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage);
+                                                       scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage, &());
                                                } else {
                                                        let curr_hop_path_idx = path.hops.len() - 1 - idx;
-                                                       scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(&path.hops[curr_hop_path_idx - 1].pubkey), &NodeId::from_pubkey(&hop.pubkey), usage);
+                                                       scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(&path.hops[curr_hop_path_idx - 1].pubkey), &NodeId::from_pubkey(&hop.pubkey), usage, &());
                                                }
                                        }
                                }
@@ -140,7 +140,7 @@ impl<'a> Router for TestRouter<'a> {
                let scorer = self.scorer.lock().unwrap();
                find_route(
                        payer, params, &self.network_graph, first_hops, &logger,
-                       &ScorerAccountingForInFlightHtlcs::new(scorer, &inflight_htlcs),
+                       &ScorerAccountingForInFlightHtlcs::new(scorer, &inflight_htlcs), &(),
                        &[42; 32]
                )
        }
@@ -341,17 +341,20 @@ impl TestBroadcaster {
 }
 
 impl chaininterface::BroadcasterInterface for TestBroadcaster {
-       fn broadcast_transaction(&self, tx: &Transaction) {
-               let lock_time = tx.lock_time.0;
-               assert!(lock_time < 1_500_000_000);
-               if bitcoin::LockTime::from(tx.lock_time).is_block_height() && lock_time > self.blocks.lock().unwrap().last().unwrap().1 {
-                       for inp in tx.input.iter() {
-                               if inp.sequence != Sequence::MAX {
-                                       panic!("We should never broadcast a transaction before its locktime ({})!", tx.lock_time);
+       fn broadcast_transactions(&self, txs: &[&Transaction]) {
+               for tx in txs {
+                       let lock_time = tx.lock_time.0;
+                       assert!(lock_time < 1_500_000_000);
+                       if bitcoin::LockTime::from(tx.lock_time).is_block_height() && lock_time > self.blocks.lock().unwrap().last().unwrap().1 {
+                               for inp in tx.input.iter() {
+                                       if inp.sequence != Sequence::MAX {
+                                               panic!("We should never broadcast a transaction before its locktime ({})!", tx.lock_time);
+                                       }
                                }
                        }
                }
-               self.txn_broadcasted.lock().unwrap().push(tx.clone());
+               let owned_txs: Vec<Transaction> = txs.iter().map(|tx| (*tx).clone()).collect();
+               self.txn_broadcasted.lock().unwrap().extend(owned_txs);
        }
 }
 
@@ -741,7 +744,7 @@ impl Logger for TestLogger {
        fn log(&self, record: &Record) {
                *self.lines.lock().unwrap().entry((record.module_path.to_string(), format!("{}", record.args))).or_insert(0) += 1;
                if record.level >= self.level {
-                       #[cfg(feature = "std")]
+                       #[cfg(all(not(ldk_bench), feature = "std"))]
                        println!("{:<5} {} [{} : {}, {}] {}", record.level.to_string(), self.id, record.module_path, record.file, record.line, record.args);
                }
        }
@@ -1015,8 +1018,9 @@ impl crate::util::ser::Writeable for TestScorer {
 }
 
 impl Score for TestScorer {
+       type ScoreParams = ();
        fn channel_penalty_msat(
-               &self, short_channel_id: u64, _source: &NodeId, _target: &NodeId, usage: ChannelUsage
+               &self, short_channel_id: u64, _source: &NodeId, _target: &NodeId, usage: ChannelUsage, _score_params: &Self::ScoreParams
        ) -> u64 {
                if let Some(scorer_expectations) = self.scorer_expectations.borrow_mut().as_mut() {
                        match scorer_expectations.pop_front() {
diff --git a/pending_changelog/big-om-error.txt b/pending_changelog/big-om-error.txt
new file mode 100644 (file)
index 0000000..6f2ce89
--- /dev/null
@@ -0,0 +1,4 @@
+## Bug Fixes
+
+* Fixed sending large onion messages, which previously would result in an HMAC error on the second
+       hop (#2277).