Merge pull request #2305 from valentinewallace/2023-05-respect-hint-maxhtlc
authorvalentinewallace <valentinewallace@users.noreply.github.com>
Wed, 7 Jun 2023 13:02:26 +0000 (15:02 +0200)
committerGitHub <noreply@github.com>
Wed, 7 Jun 2023 13:02:26 +0000 (15:02 +0200)
Respect route hint `max_htlc` in pathfinding

50 files changed:
.github/workflows/build.yml
.gitignore
Cargo.toml
SECURITY.md
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
lightning-background-processor/src/lib.rs
lightning-custom-message/src/lib.rs
lightning-invoice/src/payment.rs
lightning-invoice/src/utils.rs
lightning-net-tokio/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-rapid-gossip-sync/src/processing.rs
lightning/Cargo.toml
lightning/src/chain/chaininterface.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/channel.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/monitor_tests.rs
lightning/src/ln/msgs.rs
lightning/src/ln/outbound_payment.rs
lightning/src/ln/payment_tests.rs
lightning/src/ln/peer_handler.rs
lightning/src/ln/priv_short_conf_tests.rs
lightning/src/ln/reload_tests.rs
lightning/src/ln/reorg_tests.rs
lightning/src/ln/shutdown_tests.rs
lightning/src/ln/wire.rs
lightning/src/onion_message/functional_tests.rs
lightning/src/routing/gossip.rs
lightning/src/routing/router.rs
lightning/src/sign/mod.rs
lightning/src/sync/mod.rs
lightning/src/sync/nostd_sync.rs
lightning/src/util/atomic_counter.rs
lightning/src/util/config.rs
lightning/src/util/test_utils.rs

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 28e55b41ce6430b1e15417d4debb0b86b10522e0..7a6dc4c793032bc2c1ddf8e3e465201df6cf3543 100644 (file)
@@ -8,7 +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
index 3f6b25fe8b993da805c3a8656527e74a50568fb8..ed19bc544aa9fa0e12fe9e58ce69cd0d746b0bf2 100644 (file)
@@ -17,4 +17,3 @@ your own public key as an attachment or inline for replies.
  * BD6EED4D339EDBF7E7CE7F8836153082BDF676FD (Elias Rohrer)
  * 6E0287D8849AE741E47CC586FD3E106A2CE099B4 (Valentine Wallace)
  * 69CFEA635D0E6E6F13FD9D9136D932FCAC0305F0 (Arik Sosman)
- * A5A6868D7AA91DD00AC1A67F817FFA028EF61C94 (Antoine Riard)
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 7d507fa431f664eadc163eb802db41c0d3ac6c8a..6e2ab0d891b3dd59cb2bb7f7b41eb7fa691a3182 100644 (file)
@@ -100,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>);
@@ -474,8 +474,12 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
        let mut channel_txn = Vec::new();
        macro_rules! make_channel {
                ($source: expr, $dest: expr, $chan_id: expr) => { {
-                       $source.peer_connected(&$dest.get_our_node_id(), &Init { features: $dest.init_features(), remote_network_address: None }, true).unwrap();
-                       $dest.peer_connected(&$source.get_our_node_id(), &Init { features: $source.init_features(), remote_network_address: None }, false).unwrap();
+                       $source.peer_connected(&$dest.get_our_node_id(), &Init {
+                               features: $dest.init_features(), networks: None, remote_network_address: None
+                       }, true).unwrap();
+                       $dest.peer_connected(&$source.get_our_node_id(), &Init {
+                               features: $source.init_features(), networks: None, remote_network_address: None
+                       }, false).unwrap();
 
                        $source.create_channel($dest.get_our_node_id(), 100_000, 42, 0, None).unwrap();
                        let open_channel = {
@@ -1006,15 +1010,23 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
                        },
                        0x0e => {
                                if chan_a_disconnected {
-                                       nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: nodes[1].init_features(), remote_network_address: None }, true).unwrap();
-                                       nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: nodes[0].init_features(), remote_network_address: None }, false).unwrap();
+                                       nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init {
+                                               features: nodes[1].init_features(), networks: None, remote_network_address: None
+                                       }, true).unwrap();
+                                       nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init {
+                                               features: nodes[0].init_features(), networks: None, remote_network_address: None
+                                       }, false).unwrap();
                                        chan_a_disconnected = false;
                                }
                        },
                        0x0f => {
                                if chan_b_disconnected {
-                                       nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: nodes[2].init_features(), remote_network_address: None }, true).unwrap();
-                                       nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: nodes[1].init_features(), remote_network_address: None }, false).unwrap();
+                                       nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init {
+                                               features: nodes[2].init_features(), networks: None, remote_network_address: None
+                                       }, true).unwrap();
+                                       nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init {
+                                               features: nodes[1].init_features(), networks: None, remote_network_address: None
+                                       }, false).unwrap();
                                        chan_b_disconnected = false;
                                }
                        },
@@ -1209,13 +1221,21 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
 
                                // Next, make sure peers are all connected to each other
                                if chan_a_disconnected {
-                                       nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: nodes[1].init_features(), remote_network_address: None }, true).unwrap();
-                                       nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: nodes[0].init_features(), remote_network_address: None }, false).unwrap();
+                                       nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init {
+                                               features: nodes[1].init_features(), networks: None, remote_network_address: None
+                                       }, true).unwrap();
+                                       nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init {
+                                               features: nodes[0].init_features(), networks: None, remote_network_address: None
+                                       }, false).unwrap();
                                        chan_a_disconnected = false;
                                }
                                if chan_b_disconnected {
-                                       nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: nodes[2].init_features(), remote_network_address: None }, true).unwrap();
-                                       nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: nodes[1].init_features(), remote_network_address: None }, false).unwrap();
+                                       nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init {
+                                               features: nodes[2].init_features(), networks: None, remote_network_address: None
+                                       }, true).unwrap();
+                                       nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init {
+                                               features: nodes[1].init_features(), networks: None, remote_network_address: None
+                                       }, false).unwrap();
                                        chan_b_disconnected = false;
                                }
 
index 7257972743a5dbc80e5ddc977c739679501d7b62..1192766bf3e0baadb5c61fef3c0c07dbff0f56f3 100644 (file)
@@ -144,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);
        }
 }
 
@@ -751,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)
@@ -799,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)
                //
@@ -1005,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 fb2082578cb31981ef76747338b16d4fd80409d0..248f79dd59ea5060a0239f566c308cd882120984 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,7 @@ impl Drop for BackgroundProcessor {
 
 #[cfg(all(feature = "std", test))]
 mod tests {
-       use bitcoin::blockdata::constants::genesis_block;
+       use bitcoin::blockdata::constants::{genesis_block, ChainHash};
        use bitcoin::blockdata::locktime::PackedLockTime;
        use bitcoin::blockdata::transaction::{Transaction, TxOut};
        use bitcoin::network::constants::Network;
@@ -1103,7 +1124,7 @@ mod tests {
        fn create_nodes(num_nodes: usize, persist_dir: &str) -> (String, Vec<Node>) {
                let persist_temp_path = env::temp_dir().join(persist_dir);
                let persist_dir = persist_temp_path.to_string_lossy().to_string();
-               let network = Network::Testnet;
+               let network = Network::Bitcoin;
                let mut nodes = Vec::new();
                for i in 0..num_nodes {
                        let tx_broadcaster = Arc::new(test_utils::TestBroadcaster::new(network));
@@ -1114,7 +1135,7 @@ mod tests {
                        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 chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
+                       let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Bitcoin));
                        let persister = Arc::new(FilesystemPersister::new(format!("{}_persister_{}", &persist_dir, i)));
                        let now = Duration::from_secs(genesis_block.header.time as u64);
                        let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos()));
@@ -1125,7 +1146,7 @@ mod tests {
                        let p2p_gossip_sync = Arc::new(P2PGossipSync::new(network_graph.clone(), Some(chain_source.clone()), logger.clone()));
                        let rapid_gossip_sync = Arc::new(RapidGossipSync::new(network_graph.clone(), logger.clone()));
                        let msg_handler = MessageHandler {
-                               chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new()),
+                               chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet))),
                                route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new()),
                                onion_message_handler: IgnoringMessageHandler{}, custom_message_handler: IgnoringMessageHandler{}
                        };
@@ -1136,8 +1157,12 @@ mod tests {
 
                for i in 0..num_nodes {
                        for j in (i+1)..num_nodes {
-                               nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &Init { features: nodes[j].node.init_features(), remote_network_address: None }, true).unwrap();
-                               nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &Init { features: nodes[i].node.init_features(), remote_network_address: None }, false).unwrap();
+                               nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &Init {
+                                       features: nodes[j].node.init_features(), networks: None, remote_network_address: None
+                               }, true).unwrap();
+                               nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &Init {
+                                       features: nodes[i].node.init_features(), networks: None, remote_network_address: None
+                               }, false).unwrap();
                        }
                }
 
@@ -1708,6 +1733,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]
@@ -1750,6 +1779,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 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 c08a00a0ca23ec18f31fcfbbe1afca9aff6ba57e..bf161dbbf0ebc34e78bf5309761621f4ad1662ee 100644 (file)
@@ -28,8 +28,8 @@ use core::time::Duration;
 /// Pays the given [`Invoice`], retrying if needed based on [`Retry`].
 ///
 /// [`Invoice::payment_hash`] is used as the [`PaymentId`], which ensures idempotency as long
-/// as the payment is still pending. Once the payment completes or fails, you must ensure that
-/// a second payment with the same [`PaymentHash`] is never sent.
+/// as the payment is still pending. If the payment succeeds, you must ensure that a second payment
+/// with the same [`PaymentHash`] is never sent.
 ///
 /// If you wish to use a different payment idempotency token, see [`pay_invoice_with_id`].
 pub fn pay_invoice<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
@@ -82,8 +82,8 @@ where
 /// [`Retry`].
 ///
 /// [`Invoice::payment_hash`] is used as the [`PaymentId`], which ensures idempotency as long
-/// as the payment is still pending. Once the payment completes or fails, you must ensure that
-/// a second payment with the same [`PaymentHash`] is never sent.
+/// as the payment is still pending. If the payment succeeds, you must ensure that a second payment
+/// with the same [`PaymentHash`] is never sent.
 ///
 /// If you wish to use a different payment idempotency token, see
 /// [`pay_zero_value_invoice_with_id`].
@@ -108,7 +108,7 @@ where
 }
 
 /// Pays the given zero-value [`Invoice`] using the given amount and custom idempotency key,
-/// retrying if needed based on [`Retry`].
+/// retrying if needed based on [`Retry`].
 ///
 /// Note that idempotency is only guaranteed as long as the payment is still pending. Once the
 /// payment completes or fails, no idempotency guarantees are made.
@@ -169,7 +169,7 @@ fn expiry_time_from_unix_epoch(invoice: &Invoice) -> Duration {
 }
 
 /// An error that may occur when making a payment.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub enum PaymentError {
        /// An error resulting from the provided [`Invoice`] or payment hash.
        Invoice(&'static str),
index b3b7c2b91e8b2702ed5ad693cc8971143b625292..d8e7bf12726454cfec9ac0134e7f3ab9fd6a1406 100644 (file)
@@ -18,6 +18,7 @@ use lightning::util::logger::Logger;
 use secp256k1::PublicKey;
 use core::ops::Deref;
 use core::time::Duration;
+use core::iter::Iterator;
 
 /// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
 /// See [`PhantomKeysManager`] for more information on phantom node payments.
@@ -132,6 +133,8 @@ where
        )
 }
 
+const MAX_CHANNEL_HINTS: usize = 3;
+
 fn _create_phantom_invoice<ES: Deref, NS: Deref, L: Deref>(
        amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, description: InvoiceDescription,
        invoice_expiry_delta_secs: u32, phantom_route_hints: Vec<PhantomRouteHints>, entropy_source: ES,
@@ -202,7 +205,8 @@ where
                invoice = invoice.amount_milli_satoshis(amt);
        }
 
-       for route_hint in select_phantom_hints(amt_msat, phantom_route_hints, logger) {
+
+       for route_hint in select_phantom_hints(amt_msat, phantom_route_hints, logger).take(MAX_CHANNEL_HINTS) {
                invoice = invoice.private_route(route_hint);
        }
 
@@ -229,36 +233,48 @@ where
 ///
 /// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager
 fn select_phantom_hints<L: Deref>(amt_msat: Option<u64>, phantom_route_hints: Vec<PhantomRouteHints>,
-       logger: L) -> Vec<RouteHint>
+       logger: L) -> impl Iterator<Item = RouteHint>
 where
        L::Target: Logger,
 {
-       let mut phantom_hints: Vec<Vec<RouteHint>> = Vec::new();
+       let mut phantom_hints: Vec<_> = Vec::new();
 
        for PhantomRouteHints { channels, phantom_scid, real_node_pubkey } in phantom_route_hints {
                log_trace!(logger, "Generating phantom route hints for node {}",
                        log_pubkey!(real_node_pubkey));
-               let mut route_hints = sort_and_filter_channels(channels, amt_msat, &logger);
+               let route_hints = sort_and_filter_channels(channels, amt_msat, &logger);
 
                // If we have any public channel, the route hints from `sort_and_filter_channels` will be
                // empty. In that case we create a RouteHint on which we will push a single hop with the
                // phantom route into the invoice, and let the sender find the path to the `real_node_pubkey`
                // node by looking at our public channels.
-               if route_hints.is_empty() {
-                       route_hints.push(RouteHint(vec![]))
-               }
-               for route_hint in &mut route_hints {
-                       route_hint.0.push(RouteHintHop {
-                               src_node_id: real_node_pubkey,
-                               short_channel_id: phantom_scid,
-                               fees: RoutingFees {
-                                       base_msat: 0,
-                                       proportional_millionths: 0,
-                               },
-                               cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
-                               htlc_minimum_msat: None,
-                               htlc_maximum_msat: None,});
-               }
+               let empty_route_hints = route_hints.len() == 0;
+               let mut have_pushed_empty = false;
+               let route_hints = route_hints
+                       .chain(core::iter::from_fn(move || {
+                               if empty_route_hints && !have_pushed_empty {
+                                       // set flag of having handled the empty route_hints and ensure empty vector
+                                       // returned only once
+                                       have_pushed_empty = true;
+                                       Some(RouteHint(Vec::new()))
+                               } else {
+                                       None
+                               }
+                       }))
+                       .map(move |mut hint| {
+                               hint.0.push(RouteHintHop {
+                                       src_node_id: real_node_pubkey,
+                                       short_channel_id: phantom_scid,
+                                       fees: RoutingFees {
+                                               base_msat: 0,
+                                               proportional_millionths: 0,
+                                       },
+                                       cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
+                                       htlc_minimum_msat: None,
+                                       htlc_maximum_msat: None,
+                               });
+                               hint
+                       });
 
                phantom_hints.push(route_hints);
        }
@@ -267,29 +283,34 @@ where
        // the hints across our real nodes we add one hint from each in turn until no node has any hints
        // left (if one node has more hints than any other, these will accumulate at the end of the
        // vector).
-       let mut invoice_hints: Vec<RouteHint> = Vec::new();
-       let mut hint_idx = 0;
+       rotate_through_iterators(phantom_hints)
+}
 
-       loop {
-               let mut remaining_hints = false;
+/// Draw items iteratively from multiple iterators.  The items are retrieved by index and
+/// rotates through the iterators - first the zero index then the first index then second index, etc.
+fn rotate_through_iterators<T, I: Iterator<Item = T>>(mut vecs: Vec<I>) -> impl Iterator<Item = T> {
+       let mut iterations = 0;
 
-               for hints in phantom_hints.iter() {
-                       if invoice_hints.len() == 3 {
-                               return invoice_hints
+       core::iter::from_fn(move || {
+               let mut exhausted_iterators = 0;
+               loop {
+                       if vecs.is_empty() {
+                               return None;
                        }
-
-                       if hint_idx < hints.len() {
-                               invoice_hints.push(hints[hint_idx].clone());
-                               remaining_hints = true
+                       let next_idx = iterations % vecs.len();
+                       iterations += 1;
+                       if let Some(item) = vecs[next_idx].next() {
+                               return Some(item);
+                       }
+                       // exhausted_vectors increase when the "next_idx" vector is exhausted
+                       exhausted_iterators += 1;
+                       // The check for exhausted iterators gets reset to 0 after each yield of `Some()`
+                       // The loop will return None when all of the nested iterators are exhausted
+                       if exhausted_iterators == vecs.len() {
+                               return None;
                        }
                }
-
-               if !remaining_hints {
-                       return invoice_hints
-               }
-
-               hint_idx +=1;
-       }
+       })
 }
 
 #[cfg(feature = "std")]
@@ -575,8 +596,13 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
 /// * Sorted by lowest inbound capacity if an online channel with the minimum amount requested exists,
 ///   otherwise sort by highest inbound capacity to give the payment the best chance of succeeding.
 fn sort_and_filter_channels<L: Deref>(
-       channels: Vec<ChannelDetails>, min_inbound_capacity_msat: Option<u64>, logger: &L
-) -> Vec<RouteHint> where L::Target: Logger {
+       channels: Vec<ChannelDetails>,
+       min_inbound_capacity_msat: Option<u64>,
+       logger: &L,
+) -> impl ExactSizeIterator<Item = RouteHint>
+where
+       L::Target: Logger,
+{
        let mut filtered_channels: HashMap<PublicKey, ChannelDetails> = HashMap::new();
        let min_inbound_capacity = min_inbound_capacity_msat.unwrap_or(0);
        let mut min_capacity_channel_exists = false;
@@ -584,6 +610,20 @@ fn sort_and_filter_channels<L: Deref>(
        let mut online_min_capacity_channel_exists = false;
        let mut has_pub_unconf_chan = false;
 
+       let route_hint_from_channel = |channel: ChannelDetails| {
+               let forwarding_info = channel.counterparty.forwarding_info.as_ref().unwrap();
+               RouteHint(vec![RouteHintHop {
+                       src_node_id: channel.counterparty.node_id,
+                       short_channel_id: channel.get_inbound_payment_scid().unwrap(),
+                       fees: RoutingFees {
+                               base_msat: forwarding_info.fee_base_msat,
+                               proportional_millionths: forwarding_info.fee_proportional_millionths,
+                       },
+                       cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
+                       htlc_minimum_msat: channel.inbound_htlc_minimum_msat,
+                       htlc_maximum_msat: channel.inbound_htlc_maximum_msat,}])
+       };
+
        log_trace!(logger, "Considering {} channels for invoice route hints", channels.len());
        for channel in channels.into_iter().filter(|chan| chan.is_channel_ready) {
                if channel.get_inbound_payment_scid().is_none() || channel.counterparty.forwarding_info.is_none() {
@@ -602,7 +642,7 @@ fn sort_and_filter_channels<L: Deref>(
                                // look at the public channels instead.
                                log_trace!(logger, "Not including channels in invoice route hints on account of public channel {}",
                                        log_bytes!(channel.channel_id));
-                               return vec![]
+                               return vec![].into_iter().take(MAX_CHANNEL_HINTS).map(route_hint_from_channel);
                        }
                }
 
@@ -662,19 +702,6 @@ fn sort_and_filter_channels<L: Deref>(
                }
        }
 
-       let route_hint_from_channel = |channel: ChannelDetails| {
-               let forwarding_info = channel.counterparty.forwarding_info.as_ref().unwrap();
-               RouteHint(vec![RouteHintHop {
-                       src_node_id: channel.counterparty.node_id,
-                       short_channel_id: channel.get_inbound_payment_scid().unwrap(),
-                       fees: RoutingFees {
-                               base_msat: forwarding_info.fee_base_msat,
-                               proportional_millionths: forwarding_info.fee_proportional_millionths,
-                       },
-                       cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
-                       htlc_minimum_msat: channel.inbound_htlc_minimum_msat,
-                       htlc_maximum_msat: channel.inbound_htlc_maximum_msat,}])
-       };
        // If all channels are private, prefer to return route hints which have a higher capacity than
        // the payment value and where we're currently connected to the channel counterparty.
        // Even if we cannot satisfy both goals, always ensure we include *some* hints, preferring
@@ -724,7 +751,8 @@ fn sort_and_filter_channels<L: Deref>(
                        } else {
                                b.inbound_capacity_msat.cmp(&a.inbound_capacity_msat)
                        }});
-               eligible_channels.into_iter().take(3).map(route_hint_from_channel).collect::<Vec<RouteHint>>()
+
+               eligible_channels.into_iter().take(MAX_CHANNEL_HINTS).map(route_hint_from_channel)
 }
 
 /// prefer_current_channel chooses a channel to use for route hints between a currently selected and candidate
@@ -777,7 +805,7 @@ mod test {
        use lightning::routing::router::{PaymentParameters, RouteParameters};
        use lightning::util::test_utils;
        use lightning::util::config::UserConfig;
-       use crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch;
+       use crate::utils::{create_invoice_from_channelmanager_and_duration_since_epoch, rotate_through_iterators};
        use std::collections::HashSet;
 
        #[test]
@@ -1886,4 +1914,111 @@ mod test {
                        _ => panic!(),
                }
        }
+
+       #[test]
+       fn test_rotate_through_iterators() {
+               // two nested vectors
+               let a = vec![vec!["a0", "b0", "c0"].into_iter(), vec!["a1", "b1"].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a0", "a1", "b0", "b1", "c0"];
+               assert_eq!(expected, result);
+
+               // test single nested vector
+               let a = vec![vec!["a0", "b0", "c0"].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a0", "b0", "c0"];
+               assert_eq!(expected, result);
+
+               // test second vector with only one element
+               let a = vec![vec!["a0", "b0", "c0"].into_iter(), vec!["a1"].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a0", "a1", "b0", "c0"];
+               assert_eq!(expected, result);
+
+               // test three nestend vectors
+               let a = vec![vec!["a0"].into_iter(), vec!["a1", "b1", "c1"].into_iter(), vec!["a2"].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a0", "a1", "a2", "b1", "c1"];
+               assert_eq!(expected, result);
+
+               // test single nested vector with a single value
+               let a = vec![vec!["a0"].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a0"];
+               assert_eq!(expected, result);
+
+               // test single empty nested vector
+               let a:Vec<std::vec::IntoIter<&str>> = vec![vec![].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<&str>>();
+               let expected:Vec<&str> = vec![];
+
+               assert_eq!(expected, result);
+
+               // test first nested vector is empty
+               let a:Vec<std::vec::IntoIter<&str>>= vec![vec![].into_iter(), vec!["a1", "b1", "c1"].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<&str>>();
+
+               let expected = vec!["a1", "b1", "c1"];
+               assert_eq!(expected, result);
+
+               // test two empty vectors
+               let a:Vec<std::vec::IntoIter<&str>> = vec![vec![].into_iter(), vec![].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<&str>>();
+
+               let expected:Vec<&str> = vec![];
+               assert_eq!(expected, result);
+
+               // test an empty vector amongst other filled vectors
+               let a = vec![
+                       vec!["a0", "b0", "c0"].into_iter(),
+                       vec![].into_iter(),
+                       vec!["a1", "b1", "c1"].into_iter(),
+                       vec!["a2", "b2", "c2"].into_iter(),
+               ];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a0", "a1", "a2", "b0", "b1", "b2", "c0", "c1", "c2"];
+               assert_eq!(expected, result);
+
+               // test a filled vector between two empty vectors
+               let a = vec![vec![].into_iter(), vec!["a1", "b1", "c1"].into_iter(), vec![].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a1", "b1", "c1"];
+               assert_eq!(expected, result);
+
+               // test an empty vector at the end of the vectors
+               let a = vec![vec!["a0", "b0", "c0"].into_iter(), vec![].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a0", "b0", "c0"];
+               assert_eq!(expected, result);
+
+               // test multiple empty vectors amongst multiple filled vectors
+               let a = vec![
+                       vec![].into_iter(),
+                       vec!["a1", "b1", "c1"].into_iter(),
+                       vec![].into_iter(),
+                       vec!["a3", "b3"].into_iter(),
+                       vec![].into_iter(),
+               ];
+
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a1", "a3", "b1", "b3", "c1"];
+               assert_eq!(expected, result);
+
+               // test one element in the first nested vectore and two elements in the second nested
+               // vector
+               let a = vec![vec!["a0"].into_iter(), vec!["a1", "b1"].into_iter()];
+               let result = rotate_through_iterators(a).collect::<Vec<_>>();
+
+               let expected = vec!["a0", "a1", "b1"];
+               assert_eq!(expected, result);
+       }
 }
index 2f0c96396bf92f69d2c9f88e4a1526c4990c96d7..724a57fb15c19bb1ba9c9c09bd3fbe44fc3a6478 100644 (file)
@@ -474,6 +474,8 @@ mod tests {
        use lightning::routing::gossip::NodeId;
        use lightning::events::*;
        use lightning::util::test_utils::TestNodeSigner;
+       use bitcoin::Network;
+       use bitcoin::blockdata::constants::ChainHash;
        use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey};
 
        use tokio::sync::mpsc;
@@ -556,6 +558,9 @@ mod tests {
                fn handle_error(&self, _their_node_id: &PublicKey, _msg: &ErrorMessage) {}
                fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
                fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::empty() }
+               fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
+                       Some(vec![ChainHash::using_genesis_block(Network::Testnet)])
+               }
        }
        impl MessageSendEventsProvider for MsgHandler {
                fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent> {
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 d1a1e4a299031a352564728200cf1829b66c2f89..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",
@@ -335,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 b387d49998e9a38d6f1693e1a18d05c4da57e675..fca318a5fa5f8cfac735ff8d3880819e8b6d93a0 100644 (file)
@@ -68,6 +68,16 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                }
 
                let chain_hash: BlockHash = Readable::read(read_cursor)?;
+               let ng_genesis_hash = self.network_graph.get_genesis_hash();
+               if chain_hash != ng_genesis_hash {
+                       return Err(
+                               LightningError {
+                                       err: "Rapid Gossip Sync data's chain hash does not match the network graph's".to_owned(),
+                                       action: ErrorAction::IgnoreError,
+                               }.into()
+                       );
+               }
+
                let latest_seen_timestamp: u32 = Readable::read(read_cursor)?;
 
                if let Some(time) = current_time_unix {
@@ -667,4 +677,22 @@ mod tests {
                        panic!("Unexpected update result: {:?}", update_result)
                }
        }
+
+       #[test]
+       fn fails_early_on_chain_hash_mismatch() {
+               let logger = TestLogger::new();
+               // Set to testnet so that the VALID_RGS_BINARY chain hash of mainnet does not match.
+               let network_graph = NetworkGraph::new(Network::Testnet, &logger);
+
+               assert_eq!(network_graph.read_only().channels().len(), 0);
+
+               let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
+               let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(0));
+               assert!(update_result.is_err());
+               if let Err(GraphSyncError::LightningError(err)) = update_result {
+                       assert_eq!(err.err, "Rapid Gossip Sync data's chain hash does not match the network graph's");
+               } else {
+                       panic!("Unexpected update result: {:?}", update_result)
+               }
+       }
 }
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 e3f6f428eb3aba1fd56a3ae95245f61a64e9b083..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);
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 e59cf47f17600963c9852389fc5723d8189816ef..015650cb82312523627902a87008366762a1313f 100644 (file)
@@ -350,10 +350,14 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
                nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
                nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
-               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
                assert_eq!(reestablish_1.len(), 1);
-               nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+               nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
                let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
                assert_eq!(reestablish_2.len(), 1);
 
@@ -372,10 +376,14 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
                assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
                assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
 
-               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
                assert_eq!(reestablish_1.len(), 1);
-               nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+               nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
                let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
                assert_eq!(reestablish_2.len(), 1);
 
@@ -1136,8 +1144,12 @@ fn test_monitor_update_fail_reestablish() {
        commitment_signed_dance!(nodes[1], nodes[2], updates.commitment_signed, false);
 
        chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
 
        let as_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
        let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
@@ -1155,8 +1167,12 @@ fn test_monitor_update_fail_reestablish() {
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
 
        assert_eq!(get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap(), as_reestablish);
        assert_eq!(get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap(), bs_reestablish);
@@ -1331,8 +1347,12 @@ fn claim_while_disconnected_monitor_update_fail() {
        check_added_monitors!(nodes[1], 1);
        expect_payment_claimed!(nodes[1], payment_hash_1, 1_000_000);
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
 
        let as_reconnect = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
        let bs_reconnect = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
@@ -1467,8 +1487,12 @@ fn monitor_failed_no_reestablish_response() {
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
 
        let as_reconnect = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
        let bs_reconnect = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
@@ -2076,9 +2100,13 @@ fn test_pending_update_fee_ack_on_reconnect() {
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let as_connect_msg = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let bs_connect_msg = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
 
        nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_connect_msg);
@@ -2204,9 +2232,13 @@ fn do_update_fee_resend_test(deliver_update: bool, parallel_updates: bool) {
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let as_connect_msg = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let bs_connect_msg = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
 
        nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_connect_msg);
@@ -2341,10 +2373,14 @@ fn do_channel_holding_cell_serialize(disconnect: bool, reload_a: bool) {
                nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
                // Now reconnect the two
-               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
                assert_eq!(reestablish_1.len(), 1);
-               nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+               nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
                let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
                assert_eq!(reestablish_2.len(), 1);
 
index 11f0261d677a3df37b2fa36f94ea142e5ce8f16c..99b3c1691149960f599ab532a98419da03b66c8c 100644 (file)
@@ -432,6 +432,12 @@ pub(super) struct ReestablishResponses {
        pub shutdown_msg: Option<msgs::Shutdown>,
 }
 
+/// The return type of `force_shutdown`
+pub(crate) type ShutdownResult = (
+       Option<(PublicKey, OutPoint, ChannelMonitorUpdate)>,
+       Vec<(HTLCSource, PaymentHash, PublicKey, [u8; 32])>
+);
+
 /// If the majority of the channels funds are to the fundee and the initiator holds only just
 /// enough funds to cover their reserve value, channels are at risk of getting "stuck". Because the
 /// initiator controls the feerate, if they then go to increase the channel fee, they may have no
@@ -479,6 +485,13 @@ pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4;
 ///   * `EXPIRE_PREV_CONFIG_TICKS` = convergence_delay / tick_interval
 pub(crate) const EXPIRE_PREV_CONFIG_TICKS: usize = 5;
 
+/// The number of ticks that may elapse while we're waiting for a response to a
+/// [`msgs::RevokeAndACK`] or [`msgs::ChannelReestablish`] message before we attempt to disconnect
+/// them.
+///
+/// See [`Channel::sent_message_awaiting_response`] for more information.
+pub(crate) const DISCONNECT_PEER_AWAITING_RESPONSE_TICKS: usize = 2;
+
 struct PendingChannelMonitorUpdate {
        update: ChannelMonitorUpdate,
        /// In some cases we need to delay letting the [`ChannelMonitorUpdate`] go until after an
@@ -715,6 +728,19 @@ pub(super) struct Channel<Signer: ChannelSigner> {
        /// See-also <https://github.com/lightningnetwork/lnd/issues/4006>
        pub workaround_lnd_bug_4006: Option<msgs::ChannelReady>,
 
+       /// An option set when we wish to track how many ticks have elapsed while waiting for a response
+       /// from our counterparty after sending a message. If the peer has yet to respond after reaching
+       /// `DISCONNECT_PEER_AWAITING_RESPONSE_TICKS`, a reconnection should be attempted to try to
+       /// unblock the state machine.
+       ///
+       /// This behavior is mostly motivated by a lnd bug in which we don't receive a message we expect
+       /// to in a timely manner, which may lead to channels becoming unusable and/or force-closed. An
+       /// example of such can be found at <https://github.com/lightningnetwork/lnd/issues/7682>.
+       ///
+       /// This is currently only used when waiting for a [`msgs::ChannelReestablish`] or
+       /// [`msgs::RevokeAndACK`] message from the counterparty.
+       sent_message_awaiting_response: Option<usize>,
+
        #[cfg(any(test, fuzzing))]
        // When we receive an HTLC fulfill on an outbound path, we may immediately fulfill the
        // corresponding HTLC on the inbound path. If, then, the outbound path channel is
@@ -1130,6 +1156,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
 
                        workaround_lnd_bug_4006: None,
+                       sent_message_awaiting_response: None,
 
                        latest_inbound_scid_alias: None,
                        outbound_scid_alias,
@@ -1489,6 +1516,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
 
                        workaround_lnd_bug_4006: None,
+                       sent_message_awaiting_response: None,
 
                        latest_inbound_scid_alias: None,
                        outbound_scid_alias,
@@ -3526,6 +3554,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                // OK, we step the channel here and *then* if the new generation fails we can fail the
                // channel based on that, but stepping stuff here should be safe either way.
                self.channel_state &= !(ChannelState::AwaitingRemoteRevoke as u32);
+               self.sent_message_awaiting_response = None;
                self.counterparty_prev_commitment_point = self.counterparty_cur_commitment_point;
                self.counterparty_cur_commitment_point = Some(msg.next_per_commitment_point);
                self.cur_counterparty_commitment_transaction_number -= 1;
@@ -3841,6 +3870,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        }
                }
 
+               self.sent_message_awaiting_response = None;
+
                self.channel_state |= ChannelState::PeerDisconnected as u32;
                log_trace!(logger, "Peer disconnection resulted in {} remote-announced HTLC drops on channel {}", inbound_drop_count, log_bytes!(self.channel_id()));
        }
@@ -3943,6 +3974,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        Some(self.get_last_revoke_and_ack())
                } else { None };
                let commitment_update = if self.monitor_pending_commitment_signed {
+                       self.mark_awaiting_response();
                        Some(self.get_last_commitment_update(logger))
                } else { None };
 
@@ -4132,6 +4164,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                // Go ahead and unmark PeerDisconnected as various calls we may make check for it (and all
                // remaining cases either succeed or ErrorMessage-fail).
                self.channel_state &= !(ChannelState::PeerDisconnected as u32);
+               self.sent_message_awaiting_response = None;
 
                let shutdown_msg = if self.channel_state & (ChannelState::LocalShutdownSent as u32) != 0 {
                        assert!(self.shutdown_scriptpubkey.is_some());
@@ -4192,7 +4225,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                // revoke_and_ack, not on sending commitment_signed, so we add one if have
                // AwaitingRemoteRevoke set, which indicates we sent a commitment_signed but haven't gotten
                // the corresponding revoke_and_ack back yet.
-               let next_counterparty_commitment_number = INITIAL_COMMITMENT_NUMBER - self.cur_counterparty_commitment_transaction_number + if (self.channel_state & ChannelState::AwaitingRemoteRevoke as u32) != 0 { 1 } else { 0 };
+               let is_awaiting_remote_revoke = self.channel_state & ChannelState::AwaitingRemoteRevoke as u32 != 0;
+               if is_awaiting_remote_revoke && !self.is_awaiting_monitor_update() {
+                       self.mark_awaiting_response();
+               }
+               let next_counterparty_commitment_number = INITIAL_COMMITMENT_NUMBER - self.cur_counterparty_commitment_transaction_number + if is_awaiting_remote_revoke { 1 } else { 0 };
 
                let channel_ready = if msg.next_local_commitment_number == 1 && INITIAL_COMMITMENT_NUMBER - self.cur_holder_commitment_transaction_number == 1 {
                        // We should never have to worry about MonitorUpdateInProgress resending ChannelReady
@@ -4361,6 +4398,28 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                }), None))
        }
 
+       // Marks a channel as waiting for a response from the counterparty. If it's not received
+       // [`DISCONNECT_PEER_AWAITING_RESPONSE_TICKS`] after sending our own to them, then we'll attempt
+       // a reconnection.
+       fn mark_awaiting_response(&mut self) {
+               self.sent_message_awaiting_response = Some(0);
+       }
+
+       /// Determines whether we should disconnect the counterparty due to not receiving a response
+       /// within our expected timeframe.
+       ///
+       /// This should be called on every [`super::channelmanager::ChannelManager::timer_tick_occurred`].
+       pub fn should_disconnect_peer_awaiting_response(&mut self) -> bool {
+               let ticks_elapsed = if let Some(ticks_elapsed) = self.sent_message_awaiting_response.as_mut() {
+                       ticks_elapsed
+               } else {
+                       // Don't disconnect when we're not waiting on a response.
+                       return false;
+               };
+               *ticks_elapsed += 1;
+               *ticks_elapsed >= DISCONNECT_PEER_AWAITING_RESPONSE_TICKS
+       }
+
        pub fn shutdown<SP: Deref>(
                &mut self, signer_provider: &SP, their_features: &InitFeatures, msg: &msgs::Shutdown
        ) -> Result<(Option<msgs::Shutdown>, Option<&ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
@@ -5044,10 +5103,25 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                self.pending_monitor_updates.is_empty()
        }
 
+       pub fn complete_all_mon_updates_through(&mut self, update_id: u64) {
+               self.pending_monitor_updates.retain(|upd| {
+                       if upd.update.update_id <= update_id {
+                               assert!(!upd.blocked, "Completed update must have flown");
+                               false
+                       } else { true }
+               });
+       }
+
        pub fn complete_one_mon_update(&mut self, update_id: u64) {
                self.pending_monitor_updates.retain(|upd| upd.update.update_id != update_id);
        }
 
+       /// Returns an iterator over all unblocked monitor updates which have not yet completed.
+       pub fn uncompleted_unblocked_mon_updates(&self) -> impl Iterator<Item=&ChannelMonitorUpdate> {
+               self.pending_monitor_updates.iter()
+                       .filter_map(|upd| if upd.blocked { None } else { Some(&upd.update) })
+       }
+
        /// Returns true if funding_created was sent/received.
        pub fn is_funding_initiated(&self) -> bool {
                self.channel_state >= ChannelState::FundingSent as u32
@@ -5733,7 +5807,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 
        /// May panic if called on a channel that wasn't immediately-previously
        /// self.remove_uncommitted_htlcs_and_mark_paused()'d
-       pub fn get_channel_reestablish<L: Deref>(&self, logger: &L) -> msgs::ChannelReestablish where L::Target: Logger {
+       pub fn get_channel_reestablish<L: Deref>(&mut self, logger: &L) -> msgs::ChannelReestablish where L::Target: Logger {
                assert_eq!(self.channel_state & ChannelState::PeerDisconnected as u32, ChannelState::PeerDisconnected as u32);
                assert_ne!(self.cur_counterparty_commitment_transaction_number, INITIAL_COMMITMENT_NUMBER);
                // Prior to static_remotekey, my_current_per_commitment_point was critical to claiming
@@ -5752,6 +5826,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        log_info!(logger, "Sending a data_loss_protect with no previous remote per_commitment_secret for channel {}", log_bytes!(self.channel_id()));
                        [0;32]
                };
+               self.mark_awaiting_response();
                msgs::ChannelReestablish {
                        channel_id: self.channel_id(),
                        // The protocol has two different commitment number concepts - the "commitment
@@ -6228,7 +6303,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
        /// those explicitly stated to be allowed after shutdown completes, eg some simple getters).
        /// Also returns the list of payment_hashes for channels which we can safely fail backwards
        /// immediately (others we will have to allow to time out).
-       pub fn force_shutdown(&mut self, should_broadcast: bool) -> (Option<(OutPoint, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash, PublicKey, [u8; 32])>) {
+       pub fn force_shutdown(&mut self, should_broadcast: bool) -> ShutdownResult {
                // Note that we MUST only generate a monitor update that indicates force-closure - we're
                // called during initialization prior to the chain_monitor in the encompassing ChannelManager
                // being fully configured in some cases. Thus, its likely any monitor events we generate will
@@ -6257,7 +6332,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
                        // See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more.
                        if self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::ChannelReady as u32 | ChannelState::ShutdownComplete as u32) != 0 {
                                self.latest_monitor_update_id = CLOSED_CHANNEL_UPDATE_ID;
-                               Some((funding_txo, ChannelMonitorUpdate {
+                               Some((self.get_counterparty_node_id(), funding_txo, ChannelMonitorUpdate {
                                        update_id: self.latest_monitor_update_id,
                                        updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast }],
                                }))
@@ -7090,6 +7165,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                        next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
 
                        workaround_lnd_bug_4006: None,
+                       sent_message_awaiting_response: None,
 
                        latest_inbound_scid_alias,
                        // Later in the ChannelManager deserialization phase we scan for channels and assign scid aliases if its missing
index f6cb81376e2490a205127760d5d6f14f0798bf0c..aa452b81da23d1052147c12c7075441935ec0254 100644 (file)
@@ -19,7 +19,7 @@
 
 use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::transaction::Transaction;
-use bitcoin::blockdata::constants::genesis_block;
+use bitcoin::blockdata::constants::{genesis_block, ChainHash};
 use bitcoin::network::constants::Network;
 
 use bitcoin::hashes::Hash;
@@ -40,7 +40,7 @@ use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, Messa
 // Since this struct is returned in `list_channels` methods, expose it here in case users want to
 // construct one themselves.
 use crate::ln::{inbound_payment, PaymentHash, PaymentPreimage, PaymentSecret};
-use crate::ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch};
+use crate::ln::channel::{Channel, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch};
 use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 #[cfg(any(feature = "_test_utils", test))]
 use crate::ln::features::InvoiceFeatures;
@@ -56,7 +56,7 @@ use crate::ln::outbound_payment;
 use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment};
 use crate::ln::wire::Encode;
 use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner, WriteableEcdsaChannelSigner};
-use crate::util::config::{UserConfig, ChannelConfig};
+use crate::util::config::{UserConfig, ChannelConfig, ChannelConfigUpdate};
 use crate::util::wakers::{Future, Notifier};
 use crate::util::scid_utils::fake_scid;
 use crate::util::string::UntrustedString;
@@ -359,8 +359,6 @@ pub enum FailureCode {
        IncorrectOrUnknownPaymentDetails = 0x4000 | 15,
 }
 
-type ShutdownResult = (Option<(OutPoint, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash, PublicKey, [u8; 32])>);
-
 /// Error type returned across the peer_state mutex boundary. When an Err is generated for a
 /// Channel, we generally end up with a ChannelError::Close for which we have to close the channel
 /// immediately (ie with no further calls on it made). Thus, this step happens inside a
@@ -497,15 +495,34 @@ struct ClaimablePayments {
        pending_claiming_payments: HashMap<PaymentHash, ClaimingPayment>,
 }
 
-/// Events which we process internally but cannot be procsesed immediately at the generation site
-/// for some reason. They are handled in timer_tick_occurred, so may be processed with
-/// quite some time lag.
+/// Events which we process internally but cannot be processed immediately at the generation site
+/// usually because we're running pre-full-init. They are handled immediately once we detect we are
+/// running normally, and specifically must be processed before any other non-background
+/// [`ChannelMonitorUpdate`]s are applied.
 enum BackgroundEvent {
-       /// Handle a ChannelMonitorUpdate
+       /// Handle a ChannelMonitorUpdate which closes the channel. This is only separated from
+       /// [`Self::MonitorUpdateRegeneratedOnStartup`] as the maybe-non-closing variant needs a public
+       /// key to handle channel resumption, whereas if the channel has been force-closed we do not
+       /// need the counterparty node_id.
+       ///
+       /// Note that any such events are lost on shutdown, so in general they must be updates which
+       /// are regenerated on startup.
+       ClosingMonitorUpdateRegeneratedOnStartup((OutPoint, ChannelMonitorUpdate)),
+       /// Handle a ChannelMonitorUpdate which may or may not close the channel and may unblock the
+       /// channel to continue normal operation.
+       ///
+       /// In general this should be used rather than
+       /// [`Self::ClosingMonitorUpdateRegeneratedOnStartup`], however in cases where the
+       /// `counterparty_node_id` is not available as the channel has closed from a [`ChannelMonitor`]
+       /// error the other variant is acceptable.
        ///
        /// Note that any such events are lost on shutdown, so in general they must be updates which
        /// are regenerated on startup.
-       MonitorUpdateRegeneratedOnStartup((OutPoint, ChannelMonitorUpdate)),
+       MonitorUpdateRegeneratedOnStartup {
+               counterparty_node_id: PublicKey,
+               funding_txo: OutPoint,
+               update: ChannelMonitorUpdate
+       },
 }
 
 #[derive(Debug)]
@@ -515,13 +532,31 @@ pub(crate) enum MonitorUpdateCompletionAction {
        /// this payment. Note that this is only best-effort. On restart it's possible such a duplicate
        /// event can be generated.
        PaymentClaimed { payment_hash: PaymentHash },
-       /// Indicates an [`events::Event`] should be surfaced to the user.
-       EmitEvent { event: events::Event },
+       /// Indicates an [`events::Event`] should be surfaced to the user and possibly resume the
+       /// operation of another channel.
+       ///
+       /// This is usually generated when we've forwarded an HTLC and want to block the outbound edge
+       /// from completing a monitor update which removes the payment preimage until the inbound edge
+       /// completes a monitor update containing the payment preimage. In that case, after the inbound
+       /// edge completes, we will surface an [`Event::PaymentForwarded`] as well as unblock the
+       /// outbound edge.
+       EmitEventAndFreeOtherChannel {
+               event: events::Event,
+               downstream_counterparty_and_funding_outpoint: Option<(PublicKey, OutPoint, RAAMonitorUpdateBlockingAction)>,
+       },
 }
 
 impl_writeable_tlv_based_enum_upgradable!(MonitorUpdateCompletionAction,
        (0, PaymentClaimed) => { (0, payment_hash, required) },
-       (2, EmitEvent) => { (0, event, upgradable_required) },
+       (2, EmitEventAndFreeOtherChannel) => {
+               (0, event, upgradable_required),
+               // LDK prior to 0.0.116 did not have this field as the monitor update application order was
+               // required by clients. If we downgrade to something prior to 0.0.116 this may result in
+               // monitor updates which aren't properly blocked or resumed, however that's fine - we don't
+               // support async monitor updates even in LDK 0.0.116 and once we do we'll require no
+               // downgrades to prior versions.
+               (1, downstream_counterparty_and_funding_outpoint, option),
+       },
 );
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -538,6 +573,36 @@ impl_writeable_tlv_based_enum!(EventCompletionAction,
        };
 );
 
+#[derive(Clone, PartialEq, Eq, Debug)]
+/// If something is blocked on the completion of an RAA-generated [`ChannelMonitorUpdate`] we track
+/// the blocked action here. See enum variants for more info.
+pub(crate) enum RAAMonitorUpdateBlockingAction {
+       /// A forwarded payment was claimed. We block the downstream channel completing its monitor
+       /// update which removes the HTLC preimage until the upstream channel has gotten the preimage
+       /// durably to disk.
+       ForwardedPaymentInboundClaim {
+               /// The upstream channel ID (i.e. the inbound edge).
+               channel_id: [u8; 32],
+               /// The HTLC ID on the inbound edge.
+               htlc_id: u64,
+       },
+}
+
+impl RAAMonitorUpdateBlockingAction {
+       #[allow(unused)]
+       fn from_prev_hop_data(prev_hop: &HTLCPreviousHopData) -> Self {
+               Self::ForwardedPaymentInboundClaim {
+                       channel_id: prev_hop.outpoint.to_channel_id(),
+                       htlc_id: prev_hop.htlc_id,
+               }
+       }
+}
+
+impl_writeable_tlv_based_enum!(RAAMonitorUpdateBlockingAction,
+       (0, ForwardedPaymentInboundClaim) => { (0, channel_id, required), (2, htlc_id, required) }
+;);
+
+
 /// State we hold per-peer.
 pub(super) struct PeerState<Signer: ChannelSigner> {
        /// `temporary_channel_id` or `channel_id` -> `channel`.
@@ -566,6 +631,11 @@ pub(super) struct PeerState<Signer: ChannelSigner> {
        /// to funding appearing on-chain), the downstream `ChannelMonitor` set is required to ensure
        /// duplicates do not occur, so such channels should fail without a monitor update completing.
        monitor_update_blocked_actions: BTreeMap<[u8; 32], Vec<MonitorUpdateCompletionAction>>,
+       /// If another channel's [`ChannelMonitorUpdate`] needs to complete before a channel we have
+       /// with this peer can complete an RAA [`ChannelMonitorUpdate`] (e.g. because the RAA update
+       /// will remove a preimage that needs to be durably in an upstream channel first), we put an
+       /// entry here to note that the channel with the key's ID is blocked on a set of actions.
+       actions_blocking_raa_monitor_updates: BTreeMap<[u8; 32], Vec<RAAMonitorUpdateBlockingAction>>,
        /// The peer is currently connected (i.e. we've seen a
        /// [`ChannelMessageHandler::peer_connected`] and no corresponding
        /// [`ChannelMessageHandler::peer_disconnected`].
@@ -645,40 +715,44 @@ pub type SimpleArcChannelManager<M, T, F, L> = ChannelManager<
 /// 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>>, ProbabilisticScoringFeeParameters, ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>, &'g L>;
 
+macro_rules! define_test_pub_trait { ($vis: vis) => {
 /// A trivial trait which describes any [`ChannelManager`] used in testing.
-#[cfg(any(test, feature = "_test_utils"))]
-pub trait AChannelManager {
-       type Watch: chain::Watch<Self::Signer>;
+$vis trait AChannelManager {
+       type Watch: chain::Watch<Self::Signer> + ?Sized;
        type M: Deref<Target = Self::Watch>;
-       type Broadcaster: BroadcasterInterface;
+       type Broadcaster: BroadcasterInterface + ?Sized;
        type T: Deref<Target = Self::Broadcaster>;
-       type EntropySource: EntropySource;
+       type EntropySource: EntropySource + ?Sized;
        type ES: Deref<Target = Self::EntropySource>;
-       type NodeSigner: NodeSigner;
+       type NodeSigner: NodeSigner + ?Sized;
        type NS: Deref<Target = Self::NodeSigner>;
-       type Signer: WriteableEcdsaChannelSigner;
-       type SignerProvider: SignerProvider<Signer = Self::Signer>;
+       type Signer: WriteableEcdsaChannelSigner + Sized;
+       type SignerProvider: SignerProvider<Signer = Self::Signer> + ?Sized;
        type SP: Deref<Target = Self::SignerProvider>;
-       type FeeEstimator: FeeEstimator;
+       type FeeEstimator: FeeEstimator + ?Sized;
        type F: Deref<Target = Self::FeeEstimator>;
-       type Router: Router;
+       type Router: Router + ?Sized;
        type R: Deref<Target = Self::Router>;
-       type Logger: Logger;
+       type Logger: Logger + ?Sized;
        type L: Deref<Target = Self::Logger>;
        fn get_cm(&self) -> &ChannelManager<Self::M, Self::T, Self::ES, Self::NS, Self::SP, Self::F, Self::R, Self::L>;
 }
+} }
 #[cfg(any(test, feature = "_test_utils"))]
+define_test_pub_trait!(pub);
+#[cfg(not(any(test, feature = "_test_utils")))]
+define_test_pub_trait!(pub(crate));
 impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> AChannelManager
 for ChannelManager<M, T, ES, NS, SP, F, R, L>
 where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer> + Sized,
-       T::Target: BroadcasterInterface + Sized,
-       ES::Target: EntropySource + Sized,
-       NS::Target: NodeSigner + Sized,
-       SP::Target: SignerProvider + Sized,
-       F::Target: FeeEstimator + Sized,
-       R::Target: Router + Sized,
-       L::Target: Logger + Sized,
+       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
+       T::Target: BroadcasterInterface,
+       ES::Target: EntropySource,
+       NS::Target: NodeSigner,
+       SP::Target: SignerProvider,
+       F::Target: FeeEstimator,
+       R::Target: Router,
+       L::Target: Logger,
 {
        type Watch = M::Target;
        type M = M;
@@ -964,7 +1038,18 @@ where
        pending_events: Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
        /// A simple atomic flag to ensure only one task at a time can be processing events asynchronously.
        pending_events_processor: AtomicBool,
+
+       /// If we are running during init (either directly during the deserialization method or in
+       /// block connection methods which run after deserialization but before normal operation) we
+       /// cannot provide the user with [`ChannelMonitorUpdate`]s through the normal update flow -
+       /// prior to normal operation the user may not have loaded the [`ChannelMonitor`]s into their
+       /// [`ChainMonitor`] and thus attempting to update it will fail or panic.
+       ///
+       /// Thus, we place them here to be handled as soon as possible once we are running normally.
+       ///
        /// See `ChannelManager` struct-level documentation for lock order requirements.
+       ///
+       /// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor
        pending_background_events: Mutex<Vec<BackgroundEvent>>,
        /// Used when we have to take a BIG lock to make sure everything is self-consistent.
        /// Essentially just when we're serializing ourselves out.
@@ -974,6 +1059,9 @@ where
        /// Notifier the lock contains sends out a notification when the lock is released.
        total_consistency_lock: RwLock<()>,
 
+       #[cfg(debug_assertions)]
+       background_events_processed_since_startup: AtomicBool,
+
        persistence_notifier: Notifier,
 
        entropy_source: ES,
@@ -1000,6 +1088,7 @@ pub struct ChainParameters {
 }
 
 #[derive(Copy, Clone, PartialEq)]
+#[must_use]
 enum NotifyOption {
        DoPersist,
        SkipPersist,
@@ -1023,10 +1112,20 @@ struct PersistenceNotifierGuard<'a, F: Fn() -> NotifyOption> {
 }
 
 impl<'a> PersistenceNotifierGuard<'a, fn() -> NotifyOption> { // We don't care what the concrete F is here, it's unused
-       fn notify_on_drop(lock: &'a RwLock<()>, notifier: &'a Notifier) -> PersistenceNotifierGuard<'a, impl Fn() -> NotifyOption> {
-               PersistenceNotifierGuard::optionally_notify(lock, notifier, || -> NotifyOption { NotifyOption::DoPersist })
+       fn notify_on_drop<C: AChannelManager>(cm: &'a C) -> PersistenceNotifierGuard<'a, impl Fn() -> NotifyOption> {
+               let read_guard = cm.get_cm().total_consistency_lock.read().unwrap();
+               let _ = cm.get_cm().process_background_events(); // We always persist
+
+               PersistenceNotifierGuard {
+                       persistence_notifier: &cm.get_cm().persistence_notifier,
+                       should_persist: || -> NotifyOption { NotifyOption::DoPersist },
+                       _read_guard: read_guard,
+               }
+
        }
 
+       /// Note that if any [`ChannelMonitorUpdate`]s are possibly generated,
+       /// [`ChannelManager::process_background_events`] MUST be called first.
        fn optionally_notify<F: Fn() -> NotifyOption>(lock: &'a RwLock<()>, notifier: &'a Notifier, persist_check: F) -> PersistenceNotifierGuard<'a, F> {
                let read_guard = lock.read().unwrap();
 
@@ -1690,6 +1789,9 @@ macro_rules! handle_new_monitor_update {
                // update_maps_on_chan_removal needs to be able to take id_to_peer, so make sure we can in
                // any case so that it won't deadlock.
                debug_assert_ne!($self.id_to_peer.held_by_thread(), LockHeldState::HeldByThread);
+               #[cfg(debug_assertions)] {
+                       debug_assert!($self.background_events_processed_since_startup.load(Ordering::Acquire));
+               }
                match $update_res {
                        ChannelMonitorUpdateStatus::InProgress => {
                                log_debug!($self.logger, "ChannelMonitor update for {} in flight, holding messages until the update completes.",
@@ -1736,6 +1838,10 @@ macro_rules! process_events_body {
                                // persists happen while processing monitor events.
                                let _read_guard = $self.total_consistency_lock.read().unwrap();
 
+                               // Because `handle_post_event_actions` may send `ChannelMonitorUpdate`s to the user we must
+                               // ensure any startup-generated background events are handled first.
+                               if $self.process_background_events() == NotifyOption::DoPersist { result = NotifyOption::DoPersist; }
+
                                // TODO: This behavior should be documented. It's unintuitive that we query
                                // ChannelMonitors when clearing other events.
                                if $self.process_pending_monitor_events() {
@@ -1845,6 +1951,8 @@ where
                        pending_events_processor: AtomicBool::new(false),
                        pending_background_events: Mutex::new(Vec::new()),
                        total_consistency_lock: RwLock::new(()),
+                       #[cfg(debug_assertions)]
+                       background_events_processed_since_startup: AtomicBool::new(false),
                        persistence_notifier: Notifier::new(),
 
                        entropy_source,
@@ -1913,7 +2021,7 @@ where
                        return Err(APIError::APIMisuseError { err: format!("Channel value must be at least 1000 satoshis. It was {}", channel_value_satoshis) });
                }
 
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                // We want to make sure the lock is actually acquired by PersistenceNotifierGuard.
                debug_assert!(&self.total_consistency_lock.try_write().is_err());
 
@@ -2067,7 +2175,7 @@ where
        }
 
        fn close_channel_internal(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>, override_shutdown_script: Option<ShutdownScript>) -> Result<(), APIError> {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                let mut failed_htlcs: Vec<(HTLCSource, PaymentHash)>;
                let result: Result<(), _> = loop {
@@ -2197,7 +2305,7 @@ where
                        let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id };
                        self.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
                }
-               if let Some((funding_txo, monitor_update)) = monitor_update_option {
+               if let Some((_, funding_txo, monitor_update)) = monitor_update_option {
                        // There isn't anything we can do if we get an update failure - we're already
                        // force-closing. The monitor update on the required in-memory copy should broadcast
                        // the latest local state, which is the best we can do anyway. Thus, it is safe to
@@ -2240,7 +2348,7 @@ where
        }
 
        fn force_close_sending_error(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, broadcast: bool) -> Result<(), APIError> {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                match self.force_close_channel_with_peer(channel_id, counterparty_node_id, None, broadcast) {
                        Ok(counterparty_node_id) => {
                                let per_peer_state = self.per_peer_state.read().unwrap();
@@ -2849,18 +2957,18 @@ where
        /// [`ChannelMonitorUpdateStatus::InProgress`]: crate::chain::ChannelMonitorUpdateStatus::InProgress
        pub fn send_payment_with_route(&self, route: &Route, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId) -> Result<(), PaymentSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments
                        .send_payment_with_route(route, payment_hash, recipient_onion, payment_id, &self.entropy_source, &self.node_signer, best_block_height,
                                |path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv|
                                self.send_payment_along_path(path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv))
        }
 
-       /// Similar to [`ChannelManager::send_payment`], but will automatically find a route based on
+       /// Similar to [`ChannelManager::send_payment_with_route`], but will automatically find a route based on
        /// `route_params` and retry failed payment paths based on `retry_strategy`.
        pub fn send_payment(&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<(), RetryableSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments
                        .send_payment(payment_hash, recipient_onion, payment_id, retry_strategy, route_params,
                                &self.router, self.list_usable_channels(), || self.compute_inflight_htlcs(),
@@ -2873,7 +2981,7 @@ where
        #[cfg(test)]
        pub(super) fn test_send_payment_internal(&self, route: &Route, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, keysend_preimage: Option<PaymentPreimage>, payment_id: PaymentId, recv_value_msat: Option<u64>, onion_session_privs: Vec<[u8; 32]>) -> Result<(), PaymentSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments.test_send_payment_internal(route, payment_hash, recipient_onion, keysend_preimage, payment_id, recv_value_msat, onion_session_privs, &self.node_signer, best_block_height,
                        |path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv|
                        self.send_payment_along_path(path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv))
@@ -2908,7 +3016,7 @@ where
        /// [`Event::PaymentFailed`]: events::Event::PaymentFailed
        /// [`Event::PaymentSent`]: events::Event::PaymentSent
        pub fn abandon_payment(&self, payment_id: PaymentId) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments.abandon_payment(payment_id, PaymentFailureReason::UserAbandoned, &self.pending_events);
        }
 
@@ -2929,7 +3037,7 @@ where
        /// [`send_payment`]: Self::send_payment
        pub fn send_spontaneous_payment(&self, route: &Route, payment_preimage: Option<PaymentPreimage>, recipient_onion: RecipientOnionFields, payment_id: PaymentId) -> Result<PaymentHash, PaymentSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments.send_spontaneous_payment_with_route(
                        route, payment_preimage, recipient_onion, payment_id, &self.entropy_source,
                        &self.node_signer, best_block_height,
@@ -2946,7 +3054,7 @@ where
        /// [`PaymentParameters::for_keysend`]: crate::routing::router::PaymentParameters::for_keysend
        pub fn send_spontaneous_payment_with_retry(&self, payment_preimage: Option<PaymentPreimage>, recipient_onion: RecipientOnionFields, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<PaymentHash, RetryableSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments.send_spontaneous_payment(payment_preimage, recipient_onion,
                        payment_id, retry_strategy, route_params, &self.router, self.list_usable_channels(),
                        || self.compute_inflight_htlcs(),  &self.entropy_source, &self.node_signer, best_block_height,
@@ -2960,7 +3068,7 @@ where
        /// us to easily discern them from real payments.
        pub fn send_probe(&self, path: Path) -> Result<(PaymentHash, PaymentId), PaymentSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments.send_probe(path, self.probing_cookie_secret, &self.entropy_source, &self.node_signer, best_block_height,
                        |path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv|
                        self.send_payment_along_path(path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv))
@@ -3071,7 +3179,7 @@ where
        /// [`Event::FundingGenerationReady`]: crate::events::Event::FundingGenerationReady
        /// [`Event::ChannelClosed`]: crate::events::Event::ChannelClosed
        pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, funding_transaction: Transaction) -> Result<(), APIError> {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                for inp in funding_transaction.input.iter() {
                        if inp.witness.is_empty() {
@@ -3120,7 +3228,7 @@ where
                })
        }
 
-       /// Atomically updates the [`ChannelConfig`] for the given channels.
+       /// Atomically applies partial updates to the [`ChannelConfig`] of the given channels.
        ///
        /// Once the updates are applied, each eligible channel (advertised with a known short channel
        /// ID and a change in [`forwarding_fee_proportional_millionths`], [`forwarding_fee_base_msat`],
@@ -3142,18 +3250,16 @@ where
        /// [`ChannelUpdate`]: msgs::ChannelUpdate
        /// [`ChannelUnavailable`]: APIError::ChannelUnavailable
        /// [`APIMisuseError`]: APIError::APIMisuseError
-       pub fn update_channel_config(
-               &self, counterparty_node_id: &PublicKey, channel_ids: &[[u8; 32]], config: &ChannelConfig,
+       pub fn update_partial_channel_config(
+               &self, counterparty_node_id: &PublicKey, channel_ids: &[[u8; 32]], config_update: &ChannelConfigUpdate,
        ) -> Result<(), APIError> {
-               if config.cltv_expiry_delta < MIN_CLTV_EXPIRY_DELTA {
+               if config_update.cltv_expiry_delta.map(|delta| delta < MIN_CLTV_EXPIRY_DELTA).unwrap_or(false) {
                        return Err(APIError::APIMisuseError {
                                err: format!("The chosen CLTV expiry delta is below the minimum of {}", MIN_CLTV_EXPIRY_DELTA),
                        });
                }
 
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(
-                       &self.total_consistency_lock, &self.persistence_notifier,
-               );
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let per_peer_state = self.per_peer_state.read().unwrap();
                let peer_state_mutex = per_peer_state.get(counterparty_node_id)
                        .ok_or_else(|| APIError::ChannelUnavailable { err: format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id) })?;
@@ -3168,7 +3274,9 @@ where
                }
                for channel_id in channel_ids {
                        let channel = peer_state.channel_by_id.get_mut(channel_id).unwrap();
-                       if !channel.update_config(config) {
+                       let mut config = channel.config();
+                       config.apply(config_update);
+                       if !channel.update_config(&config) {
                                continue;
                        }
                        if let Ok(msg) = self.get_channel_update_for_broadcast(channel) {
@@ -3183,6 +3291,34 @@ where
                Ok(())
        }
 
+       /// Atomically updates the [`ChannelConfig`] for the given channels.
+       ///
+       /// Once the updates are applied, each eligible channel (advertised with a known short channel
+       /// ID and a change in [`forwarding_fee_proportional_millionths`], [`forwarding_fee_base_msat`],
+       /// or [`cltv_expiry_delta`]) has a [`BroadcastChannelUpdate`] event message generated
+       /// containing the new [`ChannelUpdate`] message which should be broadcast to the network.
+       ///
+       /// Returns [`ChannelUnavailable`] when a channel is not found or an incorrect
+       /// `counterparty_node_id` is provided.
+       ///
+       /// Returns [`APIMisuseError`] when a [`cltv_expiry_delta`] update is to be applied with a value
+       /// below [`MIN_CLTV_EXPIRY_DELTA`].
+       ///
+       /// If an error is returned, none of the updates should be considered applied.
+       ///
+       /// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
+       /// [`forwarding_fee_base_msat`]: ChannelConfig::forwarding_fee_base_msat
+       /// [`cltv_expiry_delta`]: ChannelConfig::cltv_expiry_delta
+       /// [`BroadcastChannelUpdate`]: events::MessageSendEvent::BroadcastChannelUpdate
+       /// [`ChannelUpdate`]: msgs::ChannelUpdate
+       /// [`ChannelUnavailable`]: APIError::ChannelUnavailable
+       /// [`APIMisuseError`]: APIError::APIMisuseError
+       pub fn update_channel_config(
+               &self, counterparty_node_id: &PublicKey, channel_ids: &[[u8; 32]], config: &ChannelConfig,
+       ) -> Result<(), APIError> {
+               return self.update_partial_channel_config(counterparty_node_id, channel_ids, &(*config).into());
+       }
+
        /// Attempts to forward an intercepted HTLC over the provided channel id and with the provided
        /// amount to forward. Should only be called in response to an [`HTLCIntercepted`] event.
        ///
@@ -3206,7 +3342,7 @@ where
        // TODO: when we move to deciding the best outbound channel at forward time, only take
        // `next_node_id` and not `next_hop_channel_id`
        pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                let next_hop_scid = {
                        let peer_state_lock = self.per_peer_state.read().unwrap();
@@ -3262,7 +3398,7 @@ where
        ///
        /// [`HTLCIntercepted`]: events::Event::HTLCIntercepted
        pub fn fail_intercepted_htlc(&self, intercept_id: InterceptId) -> Result<(), APIError> {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                let payment = self.pending_intercepted_htlcs.lock().unwrap().remove(&intercept_id)
                        .ok_or_else(|| APIError::APIMisuseError {
@@ -3291,7 +3427,7 @@ where
        /// Should only really ever be called in response to a PendingHTLCsForwardable event.
        /// Will likely generate further events.
        pub fn process_pending_htlc_forwards(&self) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                let mut new_events = VecDeque::new();
                let mut failed_forwards = Vec::new();
@@ -3762,35 +3898,63 @@ where
                events.append(&mut new_events);
        }
 
-       /// Free the background events, generally called from timer_tick_occurred.
-       ///
-       /// Exposed for testing to allow us to process events quickly without generating accidental
-       /// BroadcastChannelUpdate events in timer_tick_occurred.
+       /// Free the background events, generally called from [`PersistenceNotifierGuard`] constructors.
        ///
        /// Expects the caller to have a total_consistency_lock read lock.
-       fn process_background_events(&self) -> bool {
+       fn process_background_events(&self) -> NotifyOption {
+               debug_assert_ne!(self.total_consistency_lock.held_by_thread(), LockHeldState::NotHeldByThread);
+
+               #[cfg(debug_assertions)]
+               self.background_events_processed_since_startup.store(true, Ordering::Release);
+
                let mut background_events = Vec::new();
                mem::swap(&mut *self.pending_background_events.lock().unwrap(), &mut background_events);
                if background_events.is_empty() {
-                       return false;
+                       return NotifyOption::SkipPersist;
                }
 
                for event in background_events.drain(..) {
                        match event {
-                               BackgroundEvent::MonitorUpdateRegeneratedOnStartup((funding_txo, update)) => {
+                               BackgroundEvent::ClosingMonitorUpdateRegeneratedOnStartup((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);
                                },
+                               BackgroundEvent::MonitorUpdateRegeneratedOnStartup { counterparty_node_id, funding_txo, update } => {
+                                       let update_res = self.chain_monitor.update_channel(funding_txo, &update);
+
+                                       let res = {
+                                               let per_peer_state = self.per_peer_state.read().unwrap();
+                                               if let Some(peer_state_mutex) = per_peer_state.get(&counterparty_node_id) {
+                                                       let mut peer_state_lock = peer_state_mutex.lock().unwrap();
+                                                       let peer_state = &mut *peer_state_lock;
+                                                       match peer_state.channel_by_id.entry(funding_txo.to_channel_id()) {
+                                                               hash_map::Entry::Occupied(mut chan) => {
+                                                                       handle_new_monitor_update!(self, update_res, update.update_id, peer_state_lock, peer_state, per_peer_state, chan)
+                                                               },
+                                                               hash_map::Entry::Vacant(_) => Ok(()),
+                                                       }
+                                               } else { Ok(()) }
+                                       };
+                                       // TODO: If this channel has since closed, we're likely providing a payment
+                                       // preimage update, which we must ensure is durable! We currently don't,
+                                       // however, ensure that.
+                                       if res.is_err() {
+                                               log_error!(self.logger,
+                                                       "Failed to provide ChannelMonitorUpdate to closed channel! This likely lost us a payment preimage!");
+                                       }
+                                       let _ = handle_error!(self, res, counterparty_node_id);
+                               },
                        }
                }
-               true
+               NotifyOption::DoPersist
        }
 
        #[cfg(any(test, feature = "_test_utils"))]
        /// Process background events, for functional testing
        pub fn test_process_background_events(&self) {
-               self.process_background_events();
+               let _lck = self.total_consistency_lock.read().unwrap();
+               let _ = self.process_background_events();
        }
 
        fn update_channel_fee(&self, chan_id: &[u8; 32], chan: &mut Channel<<SP::Target as SignerProvider>::Signer>, new_feerate: u32) -> NotifyOption {
@@ -3820,7 +3984,7 @@ where
        /// it wants to detect). Thus, we have a variant exposed here for its benefit.
        pub fn maybe_update_chan_fees(&self) {
                PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock, &self.persistence_notifier, || {
-                       let mut should_persist = NotifyOption::SkipPersist;
+                       let mut should_persist = self.process_background_events();
 
                        let new_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
 
@@ -3856,8 +4020,7 @@ where
        /// [`ChannelConfig`]: crate::util::config::ChannelConfig
        pub fn timer_tick_occurred(&self) {
                PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock, &self.persistence_notifier, || {
-                       let mut should_persist = NotifyOption::SkipPersist;
-                       if self.process_background_events() { should_persist = NotifyOption::DoPersist; }
+                       let mut should_persist = self.process_background_events();
 
                        let new_feerate = self.fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal);
 
@@ -3921,6 +4084,20 @@ where
 
                                                chan.maybe_expire_prev_config();
 
+                                               if chan.should_disconnect_peer_awaiting_response() {
+                                                       log_debug!(self.logger, "Disconnecting peer {} due to not making any progress on channel {}",
+                                                                       counterparty_node_id, log_bytes!(*chan_id));
+                                                       pending_msg_events.push(MessageSendEvent::HandleError {
+                                                               node_id: counterparty_node_id,
+                                                               action: msgs::ErrorAction::DisconnectPeerWithWarning {
+                                                                       msg: msgs::WarningMessage {
+                                                                               channel_id: *chan_id,
+                                                                               data: "Disconnecting due to timeout awaiting response".to_owned(),
+                                                                       },
+                                                               },
+                                                       });
+                                               }
+
                                                true
                                        });
                                        if peer_state.ok_to_remove(true) {
@@ -4029,7 +4206,7 @@ where
        ///
        /// See [`FailureCode`] for valid failure codes.
        pub fn fail_htlc_backwards_with_reason(&self, payment_hash: &PaymentHash, failure_code: FailureCode) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                let removed_source = self.claimable_payments.lock().unwrap().claimable_payments.remove(payment_hash);
                if let Some(payment) = removed_source {
@@ -4206,7 +4383,7 @@ where
        pub fn claim_funds(&self, payment_preimage: PaymentPreimage) {
                let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
 
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                let mut sources = {
                        let mut claimable_payments = self.claimable_payments.lock().unwrap();
@@ -4411,16 +4588,16 @@ where
                                                                Some(claimed_htlc_value - forwarded_htlc_value)
                                                        } else { None };
 
-                                                       let prev_channel_id = Some(prev_outpoint.to_channel_id());
-                                                       let next_channel_id = Some(next_channel_id);
-
-                                                       Some(MonitorUpdateCompletionAction::EmitEvent { event: events::Event::PaymentForwarded {
-                                                               fee_earned_msat,
-                                                               claim_from_onchain_tx: from_onchain,
-                                                               prev_channel_id,
-                                                               next_channel_id,
-                                                               outbound_amount_forwarded_msat: forwarded_htlc_value_msat,
-                                                       }})
+                                                       Some(MonitorUpdateCompletionAction::EmitEventAndFreeOtherChannel {
+                                                               event: events::Event::PaymentForwarded {
+                                                                       fee_earned_msat,
+                                                                       claim_from_onchain_tx: from_onchain,
+                                                                       prev_channel_id: Some(prev_outpoint.to_channel_id()),
+                                                                       next_channel_id: Some(next_channel_id),
+                                                                       outbound_amount_forwarded_msat: forwarded_htlc_value_msat,
+                                                               },
+                                                               downstream_counterparty_and_funding_outpoint: None,
+                                                       })
                                                } else { None }
                                        });
                                if let Err((pk, err)) = res {
@@ -4447,8 +4624,13 @@ where
                                                }, None));
                                        }
                                },
-                               MonitorUpdateCompletionAction::EmitEvent { event } => {
+                               MonitorUpdateCompletionAction::EmitEventAndFreeOtherChannel {
+                                       event, downstream_counterparty_and_funding_outpoint
+                               } => {
                                        self.pending_events.lock().unwrap().push_back((event, None));
+                                       if let Some((node_id, funding_outpoint, blocker)) = downstream_counterparty_and_funding_outpoint {
+                                               self.handle_monitor_update_release(node_id, funding_outpoint, Some(blocker));
+                                       }
                                },
                        }
                }
@@ -4517,7 +4699,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]);
                }
 
                {
@@ -4607,7 +4789,7 @@ where
        }
 
        fn do_accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, accept_0conf: bool, user_channel_id: u128) -> Result<(), APIError> {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                let peers_without_funded_channels = self.peers_without_funded_channels(|peer| !peer.channel_by_id.is_empty());
                let per_peer_state = self.per_peer_state.read().unwrap();
@@ -5047,7 +5229,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) {
@@ -5295,6 +5477,24 @@ where
                }
        }
 
+       /// Checks whether [`ChannelMonitorUpdate`]s generated by the receipt of a remote
+       /// [`msgs::RevokeAndACK`] should be held for the given channel until some other event
+       /// completes. Note that this needs to happen in the same [`PeerState`] mutex as any release of
+       /// the [`ChannelMonitorUpdate`] in question.
+       fn raa_monitor_updates_held(&self,
+               actions_blocking_raa_monitor_updates: &BTreeMap<[u8; 32], Vec<RAAMonitorUpdateBlockingAction>>,
+               channel_funding_outpoint: OutPoint, counterparty_node_id: PublicKey
+       ) -> bool {
+               actions_blocking_raa_monitor_updates
+                       .get(&channel_funding_outpoint.to_channel_id()).map(|v| !v.is_empty()).unwrap_or(false)
+               || self.pending_events.lock().unwrap().iter().any(|(_, action)| {
+                       action == &Some(EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
+                               channel_funding_outpoint,
+                               counterparty_node_id,
+                       })
+               })
+       }
+
        fn internal_revoke_and_ack(&self, counterparty_node_id: &PublicKey, msg: &msgs::RevokeAndACK) -> Result<(), MsgHandleErrInternal> {
                let (htlcs_to_fail, res) = {
                        let per_peer_state = self.per_peer_state.read().unwrap();
@@ -5554,13 +5754,8 @@ where
        /// update events as a separate process method here.
        #[cfg(fuzzing)]
        pub fn process_monitor_events(&self) {
-               PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock, &self.persistence_notifier, || {
-                       if self.process_pending_monitor_events() {
-                               NotifyOption::DoPersist
-                       } else {
-                               NotifyOption::SkipPersist
-                       }
-               });
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
+               self.process_pending_monitor_events();
        }
 
        /// Check the holding cell in each channel and free any pending HTLCs in them if possible.
@@ -5657,7 +5852,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 }
@@ -5692,12 +5887,15 @@ where
                        // Channel::force_shutdown tries to make us do) as we may still be in initialization,
                        // so we track the update internally and handle it when the user next calls
                        // timer_tick_occurred, guaranteeing we're running normally.
-                       if let Some((funding_txo, update)) = failure.0.take() {
+                       if let Some((counterparty_node_id, funding_txo, update)) = failure.0.take() {
                                assert_eq!(update.updates.len(), 1);
                                if let ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } = update.updates[0] {
                                        assert!(should_broadcast);
                                } else { unreachable!(); }
-                               self.pending_background_events.lock().unwrap().push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup((funding_txo, update)));
+                               self.pending_background_events.lock().unwrap().push(
+                                       BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
+                                               counterparty_node_id, funding_txo, update
+                                       });
                        }
                        self.finish_force_close_channel(failure);
                }
@@ -5712,7 +5910,7 @@ where
 
                let payment_secret = PaymentSecret(self.entropy_source.get_secure_random_bytes());
 
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let mut payment_secrets = self.pending_inbound_payments.lock().unwrap();
                match payment_secrets.entry(payment_hash) {
                        hash_map::Entry::Vacant(e) => {
@@ -5961,25 +6159,37 @@ where
                self.pending_outbound_payments.clear_pending_payments()
        }
 
-       fn handle_monitor_update_release(&self, counterparty_node_id: PublicKey, channel_funding_outpoint: OutPoint) {
+       /// When something which was blocking a channel from updating its [`ChannelMonitor`] (e.g. an
+       /// [`Event`] being handled) completes, this should be called to restore the channel to normal
+       /// operation. It will double-check that nothing *else* is also blocking the same channel from
+       /// making progress and then any blocked [`ChannelMonitorUpdate`]s fly.
+       fn handle_monitor_update_release(&self, counterparty_node_id: PublicKey, channel_funding_outpoint: OutPoint, mut completed_blocker: Option<RAAMonitorUpdateBlockingAction>) {
                let mut errors = Vec::new();
                loop {
                        let per_peer_state = self.per_peer_state.read().unwrap();
                        if let Some(peer_state_mtx) = per_peer_state.get(&counterparty_node_id) {
                                let mut peer_state_lck = peer_state_mtx.lock().unwrap();
                                let peer_state = &mut *peer_state_lck;
-                               if self.pending_events.lock().unwrap().iter()
-                                       .any(|(_ev, action_opt)| action_opt == &Some(EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
-                                               channel_funding_outpoint, counterparty_node_id
-                                       }))
-                               {
-                                       // Check that, while holding the peer lock, we don't have another event
-                                       // blocking any monitor updates for this channel. If we do, let those
-                                       // events be the ones that ultimately release the monitor update(s).
-                                       log_trace!(self.logger, "Delaying monitor unlock for channel {} as another event is pending",
+
+                               if let Some(blocker) = completed_blocker.take() {
+                                       // Only do this on the first iteration of the loop.
+                                       if let Some(blockers) = peer_state.actions_blocking_raa_monitor_updates
+                                               .get_mut(&channel_funding_outpoint.to_channel_id())
+                                       {
+                                               blockers.retain(|iter| iter != &blocker);
+                                       }
+                               }
+
+                               if self.raa_monitor_updates_held(&peer_state.actions_blocking_raa_monitor_updates,
+                                       channel_funding_outpoint, counterparty_node_id) {
+                                       // Check that, while holding the peer lock, we don't have anything else
+                                       // blocking monitor updates for this channel. If we do, release the monitor
+                                       // update(s) when those blockers complete.
+                                       log_trace!(self.logger, "Delaying monitor unlock for channel {} as another channel's mon update needs to complete first",
                                                log_bytes!(&channel_funding_outpoint.to_channel_id()[..]));
                                        break;
                                }
+
                                if let hash_map::Entry::Occupied(mut chan) = peer_state.channel_by_id.entry(channel_funding_outpoint.to_channel_id()) {
                                        debug_assert_eq!(chan.get().get_funding_txo().unwrap(), channel_funding_outpoint);
                                        if let Some((monitor_update, further_update_exists)) = chan.get_mut().unblock_next_blocked_monitor_update() {
@@ -6021,7 +6231,7 @@ where
                                EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
                                        channel_funding_outpoint, counterparty_node_id
                                } => {
-                                       self.handle_monitor_update_release(counterparty_node_id, channel_funding_outpoint);
+                                       self.handle_monitor_update_release(counterparty_node_id, channel_funding_outpoint, None);
                                }
                        }
                }
@@ -6066,7 +6276,7 @@ where
        fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent> {
                let events = RefCell::new(Vec::new());
                PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock, &self.persistence_notifier, || {
-                       let mut result = NotifyOption::SkipPersist;
+                       let mut result = self.process_background_events();
 
                        // TODO: This behavior should be documented. It's unintuitive that we query
                        // ChannelMonitors when clearing other events.
@@ -6147,7 +6357,8 @@ where
        }
 
        fn block_disconnected(&self, header: &BlockHeader, height: u32) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock,
+                       &self.persistence_notifier, || -> NotifyOption { NotifyOption::DoPersist });
                let new_height = height - 1;
                {
                        let mut best_block = self.best_block.write().unwrap();
@@ -6181,7 +6392,8 @@ where
                let block_hash = header.block_hash();
                log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height);
 
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock,
+                       &self.persistence_notifier, || -> NotifyOption { NotifyOption::DoPersist });
                self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, self.genesis_hash.clone(), &self.node_signer, &self.default_configuration, &self.logger)
                        .map(|(a, b)| (a, Vec::new(), b)));
 
@@ -6200,8 +6412,8 @@ where
                let block_hash = header.block_hash();
                log_trace!(self.logger, "New best block: {} at height {}", block_hash, height);
 
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
-
+               let _persistence_guard = PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock,
+                       &self.persistence_notifier, || -> NotifyOption { NotifyOption::DoPersist });
                *self.best_block.write().unwrap() = BestBlock::new(block_hash, height);
 
                self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time, self.genesis_hash.clone(), &self.node_signer, &self.default_configuration, &self.logger));
@@ -6244,7 +6456,8 @@ where
        }
 
        fn transaction_unconfirmed(&self, txid: &Txid) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock,
+                       &self.persistence_notifier, || -> NotifyOption { NotifyOption::DoPersist });
                self.do_chain_event(None, |channel| {
                        if let Some(funding_txo) = channel.get_funding_txo() {
                                if funding_txo.txid == *txid {
@@ -6488,7 +6701,7 @@ where
        L::Target: Logger,
 {
        fn handle_open_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::OpenChannel) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_open_channel(counterparty_node_id, msg), *counterparty_node_id);
        }
 
@@ -6499,7 +6712,7 @@ where
        }
 
        fn handle_accept_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::AcceptChannel) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_accept_channel(counterparty_node_id, msg), *counterparty_node_id);
        }
 
@@ -6510,74 +6723,75 @@ where
        }
 
        fn handle_funding_created(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingCreated) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_funding_created(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_funding_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingSigned) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_funding_signed(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_channel_ready(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReady) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_channel_ready(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_shutdown(&self, counterparty_node_id: &PublicKey, msg: &msgs::Shutdown) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_shutdown(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_closing_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::ClosingSigned) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_closing_signed(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_update_add_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateAddHTLC) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_update_add_htlc(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_update_fulfill_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFulfillHTLC) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_update_fulfill_htlc(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_update_fail_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_update_fail_htlc(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_update_fail_malformed_htlc(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFailMalformedHTLC) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_update_fail_malformed_htlc(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_commitment_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::CommitmentSigned) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_commitment_signed(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_revoke_and_ack(&self, counterparty_node_id: &PublicKey, msg: &msgs::RevokeAndACK) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_revoke_and_ack(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_update_fee(&self, counterparty_node_id: &PublicKey, msg: &msgs::UpdateFee) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_update_fee(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_announcement_signatures(&self, counterparty_node_id: &PublicKey, msg: &msgs::AnnouncementSignatures) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_announcement_signatures(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn handle_channel_update(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelUpdate) {
                PersistenceNotifierGuard::optionally_notify(&self.total_consistency_lock, &self.persistence_notifier, || {
+                       let force_persist = self.process_background_events();
                        if let Ok(persist) = handle_error!(self, self.internal_channel_update(counterparty_node_id, msg), *counterparty_node_id) {
-                               persist
+                               if force_persist == NotifyOption::DoPersist { NotifyOption::DoPersist } else { persist }
                        } else {
                                NotifyOption::SkipPersist
                        }
@@ -6585,12 +6799,12 @@ where
        }
 
        fn handle_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let _ = handle_error!(self, self.internal_channel_reestablish(counterparty_node_id, msg), *counterparty_node_id);
        }
 
        fn peer_disconnected(&self, counterparty_node_id: &PublicKey) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let mut failed_channels = Vec::new();
                let mut per_peer_state = self.per_peer_state.write().unwrap();
                let remove_peer = {
@@ -6672,7 +6886,7 @@ where
                        return Err(());
                }
 
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                // If we have too many peers connected which don't have funded channels, disconnect the
                // peer immediately (as long as it doesn't have funded channels). If we have a bunch of
@@ -6693,6 +6907,7 @@ where
                                                latest_features: init_msg.features.clone(),
                                                pending_msg_events: Vec::new(),
                                                monitor_update_blocked_actions: BTreeMap::new(),
+                                               actions_blocking_raa_monitor_updates: BTreeMap::new(),
                                                is_connected: true,
                                        }));
                                },
@@ -6755,7 +6970,7 @@ where
        }
 
        fn handle_error(&self, counterparty_node_id: &PublicKey, msg: &msgs::ErrorMessage) {
-               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
+               let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
                if msg.channel_id == [0; 32] {
                        let channel_ids: Vec<[u8; 32]> = {
@@ -6802,6 +7017,10 @@ where
                provided_init_features(&self.default_configuration)
        }
 
+       fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
+               Some(vec![ChainHash::from(&self.genesis_hash[..])])
+       }
+
        fn handle_tx_add_input(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAddInput) {
                let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
                        "Dual-funded channels not supported".to_owned(),
@@ -7770,8 +7989,10 @@ where
                                        log_error!(args.logger, " The ChannelMonitor for channel {} is at update_id {} but the ChannelManager is at update_id {}.",
                                                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::MonitorUpdateRegeneratedOnStartup(monitor_update));
+                                       if let Some((counterparty_node_id, funding_txo, update)) = monitor_update {
+                                               pending_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
+                                                       counterparty_node_id, funding_txo, update
+                                               });
                                        }
                                        failed_htlcs.append(&mut new_failed_htlcs);
                                        channel_closures.push_back((events::Event::ChannelClosed {
@@ -7799,7 +8020,10 @@ where
                                                }
                                        }
                                } else {
-                                       log_info!(args.logger, "Successfully loaded channel {}", log_bytes!(channel.channel_id()));
+                                       log_info!(args.logger, "Successfully loaded channel {} at update_id {} against monitor at update id {}",
+                                               log_bytes!(channel.channel_id()), channel.get_latest_monitor_update_id(),
+                                               monitor.get_latest_update_id());
+                                       channel.complete_all_mon_updates_through(monitor.get_latest_update_id());
                                        if let Some(short_channel_id) = channel.get_short_channel_id() {
                                                short_to_chan_info.insert(short_channel_id, (channel.get_counterparty_node_id(), channel.channel_id()));
                                        }
@@ -7846,7 +8070,7 @@ where
                                        update_id: CLOSED_CHANNEL_UPDATE_ID,
                                        updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast: true }],
                                };
-                               pending_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup((*funding_txo, monitor_update)));
+                               pending_background_events.push(BackgroundEvent::ClosingMonitorUpdateRegeneratedOnStartup((*funding_txo, monitor_update)));
                        }
                }
 
@@ -7884,6 +8108,7 @@ where
                                latest_features: Readable::read(reader)?,
                                pending_msg_events: Vec::new(),
                                monitor_update_blocked_actions: BTreeMap::new(),
+                               actions_blocking_raa_monitor_updates: BTreeMap::new(),
                                is_connected: false,
                        };
                        per_peer_state.insert(peer_pubkey, Mutex::new(peer_state));
@@ -7913,6 +8138,24 @@ where
                        }
                }
 
+               for (node_id, peer_mtx) in per_peer_state.iter() {
+                       let peer_state = peer_mtx.lock().unwrap();
+                       for (_, chan) in peer_state.channel_by_id.iter() {
+                               for update in chan.uncompleted_unblocked_mon_updates() {
+                                       if let Some(funding_txo) = chan.get_funding_txo() {
+                                               log_trace!(args.logger, "Replaying ChannelMonitorUpdate {} for channel {}",
+                                                       update.update_id, log_bytes!(funding_txo.to_channel_id()));
+                                               pending_background_events.push(
+                                                       BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
+                                                               counterparty_node_id: *node_id, funding_txo, update: update.clone(),
+                                                       });
+                                       } else {
+                                               return Err(DecodeError::InvalidValue);
+                                       }
+                               }
+                       }
+               }
+
                let _last_node_announcement_serial: u32 = Readable::read(reader)?; // Only used < 0.0.111
                let highest_seen_timestamp: u32 = Readable::read(reader)?;
 
@@ -7947,7 +8190,7 @@ where
                let mut claimable_htlc_purposes = None;
                let mut claimable_htlc_onion_fields = None;
                let mut pending_claiming_payments = Some(HashMap::new());
-               let mut monitor_update_blocked_actions_per_peer = Some(Vec::new());
+               let mut monitor_update_blocked_actions_per_peer: Option<Vec<(_, BTreeMap<_, Vec<_>>)>> = Some(Vec::new());
                let mut events_override = None;
                read_tlv_fields!(reader, {
                        (1, pending_outbound_payments_no_retry, option),
@@ -8272,7 +8515,21 @@ where
                }
 
                for (node_id, monitor_update_blocked_actions) in monitor_update_blocked_actions_per_peer.unwrap() {
-                       if let Some(peer_state) = per_peer_state.get_mut(&node_id) {
+                       if let Some(peer_state) = per_peer_state.get(&node_id) {
+                               for (_, actions) in monitor_update_blocked_actions.iter() {
+                                       for action in actions.iter() {
+                                               if let MonitorUpdateCompletionAction::EmitEventAndFreeOtherChannel {
+                                                       downstream_counterparty_and_funding_outpoint:
+                                                               Some((blocked_node_id, blocked_channel_outpoint, blocking_action)), ..
+                                               } = action {
+                                                       if let Some(blocked_peer_state) = per_peer_state.get(&blocked_node_id) {
+                                                               blocked_peer_state.lock().unwrap().actions_blocking_raa_monitor_updates
+                                                                       .entry(blocked_channel_outpoint.to_channel_id())
+                                                                       .or_insert_with(Vec::new).push(blocking_action.clone());
+                                                       }
+                                               }
+                                       }
+                               }
                                peer_state.lock().unwrap().monitor_update_blocked_actions = monitor_update_blocked_actions;
                        } else {
                                log_error!(args.logger, "Got blocked actions without a per-peer-state for {}", node_id);
@@ -8314,6 +8571,8 @@ where
                        pending_events_processor: AtomicBool::new(false),
                        pending_background_events: Mutex::new(pending_background_events),
                        total_consistency_lock: RwLock::new(()),
+                       #[cfg(debug_assertions)]
+                       background_events_processed_since_startup: AtomicBool::new(false),
                        persistence_notifier: Notifier::new(),
 
                        entropy_source: args.entropy_source,
@@ -8353,7 +8612,7 @@ mod tests {
        use crate::routing::router::{PaymentParameters, RouteParameters, find_route};
        use crate::util::errors::APIError;
        use crate::util::test_utils;
-       use crate::util::config::ChannelConfig;
+       use crate::util::config::{ChannelConfig, ChannelConfigUpdate};
        use crate::sign::EntropySource;
 
        #[test]
@@ -9072,12 +9331,14 @@ mod tests {
                                &SecretKey::from_slice(&nodes[1].keys_manager.get_secure_random_bytes()).unwrap());
                        peer_pks.push(random_pk);
                        nodes[1].node.peer_connected(&random_pk, &msgs::Init {
-                               features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+                       }, true).unwrap();
                }
                let last_random_pk = PublicKey::from_secret_key(&nodes[0].node.secp_ctx,
                        &SecretKey::from_slice(&nodes[1].keys_manager.get_secure_random_bytes()).unwrap());
                nodes[1].node.peer_connected(&last_random_pk, &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap_err();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap_err();
 
                // Also importantly, because nodes[0] isn't "protected", we will refuse a reconnection from
                // them if we have too many un-channel'd peers.
@@ -9088,13 +9349,16 @@ mod tests {
                        if let Event::ChannelClosed { .. } = ev { } else { panic!(); }
                }
                nodes[1].node.peer_connected(&last_random_pk, &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap_err();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap_err();
 
                // but of course if the connection is outbound its allowed...
                nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
                nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
                // Now nodes[0] is disconnected but still has a pending, un-funded channel lying around.
@@ -9118,7 +9382,8 @@ mod tests {
                // "protected" and can connect again.
                mine_transaction(&nodes[1], funding_tx.as_ref().unwrap());
                nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
 
                // Further, because the first channel was funded, we can open another channel with
@@ -9183,7 +9448,8 @@ mod tests {
                        let random_pk = PublicKey::from_secret_key(&nodes[0].node.secp_ctx,
                                &SecretKey::from_slice(&nodes[1].keys_manager.get_secure_random_bytes()).unwrap());
                        nodes[1].node.peer_connected(&random_pk, &msgs::Init {
-                               features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+                       }, true).unwrap();
 
                        nodes[1].node.handle_open_channel(&random_pk, &open_channel_msg);
                        let events = nodes[1].node.get_and_clear_pending_events();
@@ -9201,7 +9467,8 @@ mod tests {
                let last_random_pk = PublicKey::from_secret_key(&nodes[0].node.secp_ctx,
                        &SecretKey::from_slice(&nodes[1].keys_manager.get_secure_random_bytes()).unwrap());
                nodes[1].node.peer_connected(&last_random_pk, &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                nodes[1].node.handle_open_channel(&last_random_pk, &open_channel_msg);
                let events = nodes[1].node.get_and_clear_pending_events();
                match events[0] {
@@ -9264,9 +9531,65 @@ mod tests {
 
                check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed);
        }
+
+       #[test]
+       fn test_update_channel_config() {
+               let chanmon_cfg = create_chanmon_cfgs(2);
+               let node_cfg = create_node_cfgs(2, &chanmon_cfg);
+               let mut user_config = test_default_channel_config();
+               let node_chanmgr = create_node_chanmgrs(2, &node_cfg, &[Some(user_config), Some(user_config)]);
+               let nodes = create_network(2, &node_cfg, &node_chanmgr);
+               let _ = create_announced_chan_between_nodes(&nodes, 0, 1);
+               let channel = &nodes[0].node.list_channels()[0];
+
+               nodes[0].node.update_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &user_config.channel_config).unwrap();
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 0);
+
+               user_config.channel_config.forwarding_fee_base_msat += 10;
+               nodes[0].node.update_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &user_config.channel_config).unwrap();
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().forwarding_fee_base_msat, user_config.channel_config.forwarding_fee_base_msat);
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 1);
+               match &events[0] {
+                       MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+                       _ => panic!("expected BroadcastChannelUpdate event"),
+               }
+
+               nodes[0].node.update_partial_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &ChannelConfigUpdate::default()).unwrap();
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 0);
+
+               let new_cltv_expiry_delta = user_config.channel_config.cltv_expiry_delta + 6;
+               nodes[0].node.update_partial_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &ChannelConfigUpdate {
+                       cltv_expiry_delta: Some(new_cltv_expiry_delta),
+                       ..Default::default()
+               }).unwrap();
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().cltv_expiry_delta, new_cltv_expiry_delta);
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 1);
+               match &events[0] {
+                       MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+                       _ => panic!("expected BroadcastChannelUpdate event"),
+               }
+
+               let new_fee = user_config.channel_config.forwarding_fee_proportional_millionths + 100;
+               nodes[0].node.update_partial_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &ChannelConfigUpdate {
+                       forwarding_fee_proportional_millionths: Some(new_fee),
+                       ..Default::default()
+               }).unwrap();
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().cltv_expiry_delta, new_cltv_expiry_delta);
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().forwarding_fee_proportional_millionths, new_fee);
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 1);
+               match &events[0] {
+                       MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+                       _ => panic!("expected BroadcastChannelUpdate event"),
+               }
+       }
 }
 
-#[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};
@@ -9286,7 +9609,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,
@@ -9307,13 +9630,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.
@@ -9347,8 +9668,12 @@ pub mod bench {
                });
                let node_b_holder = ANodeHolder { node: &node_b };
 
-               node_a.peer_connected(&node_b.get_our_node_id(), &Init { features: node_b.init_features(), remote_network_address: None }, true).unwrap();
-               node_b.peer_connected(&node_a.get_our_node_id(), &Init { features: node_a.init_features(), remote_network_address: None }, false).unwrap();
+               node_a.peer_connected(&node_b.get_our_node_id(), &Init {
+                       features: node_b.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
+               node_b.peer_connected(&node_a.get_our_node_id(), &Init {
+                       features: node_a.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
                node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None).unwrap();
                node_b.handle_open_channel(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendOpenChannel, node_b.get_our_node_id()));
                node_a.handle_accept_channel(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendAcceptChannel, node_a.get_our_node_id()));
@@ -9466,9 +9791,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 7d4b86f5acabf6ae81d5f0df9b13f3090fb11d29..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()) {
@@ -695,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 {
@@ -743,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> {
@@ -869,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();
@@ -881,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());
@@ -897,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
@@ -945,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 fa8bdcc58be01ef57547cbf9beaf548be38ca474..b7200e102f93fabc90aa31c969bb83d20c04effe 100644 (file)
@@ -1776,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())
@@ -1803,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();
@@ -1920,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);
@@ -1932,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);
@@ -2571,8 +2571,16 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
 
        for i in 0..node_count {
                for j in (i+1)..node_count {
-                       nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &msgs::Init { features: nodes[j].override_init_features.borrow().clone().unwrap_or_else(|| nodes[j].node.init_features()), remote_network_address: None }, true).unwrap();
-                       nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &msgs::Init { features: nodes[i].override_init_features.borrow().clone().unwrap_or_else(|| nodes[i].node.init_features()), remote_network_address: None }, false).unwrap();
+                       nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &msgs::Init {
+                               features: nodes[j].override_init_features.borrow().clone().unwrap_or_else(|| nodes[j].node.init_features()),
+                               networks: None,
+                               remote_network_address: None,
+                       }, true).unwrap();
+                       nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &msgs::Init {
+                               features: nodes[i].override_init_features.borrow().clone().unwrap_or_else(|| nodes[i].node.init_features()),
+                               networks: None,
+                               remote_network_address: None,
+                       }, false).unwrap();
                }
        }
 
@@ -2856,9 +2864,13 @@ macro_rules! handle_chan_reestablish_msgs {
 /// pending_htlc_adds includes both the holding cell and in-flight update_add_htlcs, whereas
 /// for claims/fails they are separated out.
 pub fn reconnect_nodes<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, send_channel_ready: (bool, bool), pending_htlc_adds: (i64, i64), pending_htlc_claims: (usize, usize), pending_htlc_fails: (usize, usize), pending_cell_htlc_claims: (usize, usize), pending_cell_htlc_fails: (usize, usize), pending_raa: (bool, bool))  {
-       node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { features: node_b.node.init_features(), remote_network_address: None }, true).unwrap();
+       node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init {
+               features: node_b.node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let reestablish_1 = get_chan_reestablish_msgs!(node_a, node_b);
-       node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { features: node_a.node.init_features(), remote_network_address: None }, false).unwrap();
+       node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init {
+               features: node_a.node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let reestablish_2 = get_chan_reestablish_msgs!(node_b, node_a);
 
        if send_channel_ready.0 {
index 98fc4bd95b6d58f100ae09aaa32519e57237598c..17a105e35267fb71aed377245ed9e6d1f59ce0e7 100644 (file)
@@ -22,7 +22,7 @@ use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, PathFail
 use crate::ln::{PaymentPreimage, PaymentSecret, PaymentHash};
 use crate::ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT};
 use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA};
-use crate::ln::channel::{Channel, ChannelError};
+use crate::ln::channel::{DISCONNECT_PEER_AWAITING_RESPONSE_TICKS, Channel, ChannelError};
 use crate::ln::{chan_utils, onion_utils};
 use crate::ln::chan_utils::{OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
 use crate::routing::gossip::{NetworkGraph, NetworkUpdate};
@@ -4025,10 +4025,14 @@ fn test_drop_messages_peer_disconnect_dual_htlc() {
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
        assert_eq!(reestablish_1.len(), 1);
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
        assert_eq!(reestablish_2.len(), 1);
 
@@ -6343,10 +6347,14 @@ fn test_update_add_htlc_bolt2_receiver_check_repeated_id_ignore() {
        //Disconnect and Reconnect
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
        assert_eq!(reestablish_1.len(), 1);
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
        assert_eq!(reestablish_2.len(), 1);
        nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &reestablish_2[0]);
@@ -7109,10 +7117,14 @@ fn test_announce_disable_channels() {
                }
        }
        // Reconnect peers
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
        assert_eq!(reestablish_1.len(), 3);
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
        assert_eq!(reestablish_2.len(), 3);
 
@@ -9955,3 +9967,132 @@ fn test_payment_with_custom_min_cltv_expiry_delta() {
        do_payment_with_custom_min_final_cltv_expiry(true, false);
        do_payment_with_custom_min_final_cltv_expiry(true, true);
 }
+
+#[test]
+fn test_disconnects_peer_awaiting_response_ticks() {
+       // Tests that nodes which are awaiting on a response critical for channel responsiveness
+       // disconnect their counterparty after `DISCONNECT_PEER_AWAITING_RESPONSE_TICKS`.
+       let mut chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       // Asserts a disconnect event is queued to the user.
+       let check_disconnect_event = |node: &Node, should_disconnect: bool| {
+               let disconnect_event = node.node.get_and_clear_pending_msg_events().iter().find_map(|event|
+                       if let MessageSendEvent::HandleError { action, .. } = event {
+                               if let msgs::ErrorAction::DisconnectPeerWithWarning { .. } = action {
+                                       Some(())
+                               } else {
+                                       None
+                               }
+                       } else {
+                               None
+                       }
+               );
+               assert_eq!(disconnect_event.is_some(), should_disconnect);
+       };
+
+       // Fires timer ticks ensuring we only attempt to disconnect peers after reaching
+       // `DISCONNECT_PEER_AWAITING_RESPONSE_TICKS`.
+       let check_disconnect = |node: &Node| {
+               // No disconnect without any timer ticks.
+               check_disconnect_event(node, false);
+
+               // No disconnect with 1 timer tick less than required.
+               for _ in 0..DISCONNECT_PEER_AWAITING_RESPONSE_TICKS - 1 {
+                       node.node.timer_tick_occurred();
+                       check_disconnect_event(node, false);
+               }
+
+               // Disconnect after reaching the required ticks.
+               node.node.timer_tick_occurred();
+               check_disconnect_event(node, true);
+
+               // Disconnect again on the next tick if the peer hasn't been disconnected yet.
+               node.node.timer_tick_occurred();
+               check_disconnect_event(node, true);
+       };
+
+       create_chan_between_nodes(&nodes[0], &nodes[1]);
+
+       // We'll start by performing a fee update with Alice (nodes[0]) on the channel.
+       *nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 2;
+       nodes[0].node.timer_tick_occurred();
+       check_added_monitors!(&nodes[0], 1);
+       let alice_fee_update = get_htlc_update_msgs(&nodes[0], &nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), alice_fee_update.update_fee.as_ref().unwrap());
+       nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &alice_fee_update.commitment_signed);
+       check_added_monitors!(&nodes[1], 1);
+
+       // This will prompt Bob (nodes[1]) to respond with his `CommitmentSigned` and `RevokeAndACK`.
+       let (bob_revoke_and_ack, bob_commitment_signed) = get_revoke_commit_msgs!(&nodes[1], nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bob_revoke_and_ack);
+       check_added_monitors!(&nodes[0], 1);
+       nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bob_commitment_signed);
+       check_added_monitors(&nodes[0], 1);
+
+       // Alice then needs to send her final `RevokeAndACK` to complete the commitment dance. We
+       // pretend Bob hasn't received the message and check whether he'll disconnect Alice after
+       // reaching `DISCONNECT_PEER_AWAITING_RESPONSE_TICKS`.
+       let alice_revoke_and_ack = get_event_msg!(nodes[0], MessageSendEvent::SendRevokeAndACK, nodes[1].node.get_our_node_id());
+       check_disconnect(&nodes[1]);
+
+       // Now, we'll reconnect them to test awaiting a `ChannelReestablish` message.
+       //
+       // Note that since the commitment dance didn't complete above, Alice is expected to resend her
+       // final `RevokeAndACK` to Bob to complete it.
+       nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
+       nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
+       let bob_init = msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       };
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &bob_init, true).unwrap();
+       let alice_init = msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       };
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();
+
+       // Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't
+       // received Bob's yet, so she should disconnect him after reaching
+       // `DISCONNECT_PEER_AWAITING_RESPONSE_TICKS`.
+       let alice_channel_reestablish = get_event_msg!(
+               nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()
+       );
+       nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &alice_channel_reestablish);
+       check_disconnect(&nodes[0]);
+
+       // Bob now sends his `ChannelReestablish` to Alice to resume the channel and consider it "live".
+       let bob_channel_reestablish = nodes[1].node.get_and_clear_pending_msg_events().iter().find_map(|event|
+               if let MessageSendEvent::SendChannelReestablish { node_id, msg } = event {
+                       assert_eq!(*node_id, nodes[0].node.get_our_node_id());
+                       Some(msg.clone())
+               } else {
+                       None
+               }
+       ).unwrap();
+       nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bob_channel_reestablish);
+
+       // Sanity check that Alice won't disconnect Bob since she's no longer waiting for any messages.
+       for _ in 0..DISCONNECT_PEER_AWAITING_RESPONSE_TICKS {
+               nodes[0].node.timer_tick_occurred();
+               check_disconnect_event(&nodes[0], false);
+       }
+
+       // However, Bob is still waiting on Alice's `RevokeAndACK`, so he should disconnect her after
+       // reaching `DISCONNECT_PEER_AWAITING_RESPONSE_TICKS`.
+       check_disconnect(&nodes[1]);
+
+       // Finally, have Bob process the last message.
+       nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &alice_revoke_and_ack);
+       check_added_monitors(&nodes[1], 1);
+
+       // At this point, neither node should attempt to disconnect each other, since they aren't
+       // waiting on any messages.
+       for node in &nodes {
+               for _ in 0..DISCONNECT_PEER_AWAITING_RESPONSE_TICKS {
+                       node.node.timer_tick_occurred();
+                       check_disconnect_event(node, false);
+               }
+       }
+}
index d186311d2e94f149b9e49ffddf018caaa14836dc..5fa39137cf4577f41f85a57b95aedf067ea43e5b 100644 (file)
@@ -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,7 +2328,7 @@ 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);
@@ -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 39cb9454db89a541ac5f039e8aa11d9d09ab8854..3dd4a6da70ccda8bde8a2e22f50db9c12e12d9cd 100644 (file)
@@ -24,6 +24,7 @@
 //! raw socket events into your non-internet-facing system and then send routing events back to
 //! track the network on the less-secure system.
 
+use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::secp256k1::PublicKey;
 use bitcoin::secp256k1::ecdsa::Signature;
 use bitcoin::{secp256k1, Witness};
@@ -88,6 +89,10 @@ pub enum DecodeError {
 pub struct Init {
        /// The relevant features which the sender supports.
        pub features: InitFeatures,
+       /// Indicates chains the sender is interested in.
+       ///
+       /// If there are no common chains, the connection will be closed.
+       pub networks: Option<Vec<ChainHash>>,
        /// The receipient's network address.
        ///
        /// This adds the option to report a remote IP address back to a connecting peer using the init
@@ -1137,6 +1142,11 @@ pub enum ErrorAction {
                /// An error message which we should make an effort to send before we disconnect.
                msg: Option<ErrorMessage>
        },
+       /// The peer did something incorrect. Tell them without closing any channels and disconnect them.
+       DisconnectPeerWithWarning {
+               /// A warning message which we should make an effort to send before we disconnect.
+               msg: WarningMessage,
+       },
        /// The peer did something harmless that we weren't able to process, just log and ignore
        // New code should *not* use this. New code must use IgnoreAndLog, below!
        IgnoreError,
@@ -1290,6 +1300,12 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
        ///
        /// Note that this method is called before [`Self::peer_connected`].
        fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures;
+
+       /// Gets the genesis hashes for this `ChannelMessageHandler` indicating which chains it supports.
+       ///
+       /// If it's `None`, then no particular network chain hash compatibility will be enforced when
+       /// connecting to peers.
+       fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>>;
 }
 
 /// A trait to describe an object which can receive routing messages.
@@ -1723,7 +1739,8 @@ impl Writeable for Init {
                self.features.write_up_to_13(w)?;
                self.features.write(w)?;
                encode_tlv_stream!(w, {
-                       (3, self.remote_network_address, option)
+                       (1, self.networks.as_ref().map(|n| WithoutLength(n)), option),
+                       (3, self.remote_network_address, option),
                });
                Ok(())
        }
@@ -1734,11 +1751,14 @@ impl Readable for Init {
                let global_features: InitFeatures = Readable::read(r)?;
                let features: InitFeatures = Readable::read(r)?;
                let mut remote_network_address: Option<NetAddress> = None;
+               let mut networks: Option<WithoutLength<Vec<ChainHash>>> = None;
                decode_tlv_stream!(r, {
+                       (1, networks, option),
                        (3, remote_network_address, option)
                });
                Ok(Init {
-                       features: features.or(global_features),
+                       features: features | global_features,
+                       networks: networks.map(|n| n.0),
                        remote_network_address,
                })
        }
@@ -2411,6 +2431,7 @@ impl_writeable_msg!(GossipTimestampFilter, {
 
 #[cfg(test)]
 mod tests {
+       use bitcoin::blockdata::constants::ChainHash;
        use bitcoin::{Transaction, PackedLockTime, TxIn, Script, Sequence, Witness, TxOut};
        use hex;
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
@@ -3418,27 +3439,36 @@ mod tests {
 
        #[test]
        fn encoding_init() {
+               let mainnet_hash = ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap();
                assert_eq!(msgs::Init {
                        features: InitFeatures::from_le_bytes(vec![0xFF, 0xFF, 0xFF]),
+                       networks: Some(vec![mainnet_hash]),
                        remote_network_address: None,
-               }.encode(), hex::decode("00023fff0003ffffff").unwrap());
+               }.encode(), hex::decode("00023fff0003ffffff01206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap());
                assert_eq!(msgs::Init {
                        features: InitFeatures::from_le_bytes(vec![0xFF]),
+                       networks: None,
                        remote_network_address: None,
                }.encode(), hex::decode("0001ff0001ff").unwrap());
                assert_eq!(msgs::Init {
                        features: InitFeatures::from_le_bytes(vec![]),
+                       networks: Some(vec![mainnet_hash]),
                        remote_network_address: None,
-               }.encode(), hex::decode("00000000").unwrap());
-
+               }.encode(), hex::decode("0000000001206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap());
+               assert_eq!(msgs::Init {
+                       features: InitFeatures::from_le_bytes(vec![]),
+                       networks: Some(vec![ChainHash::from(&[1; 32][..]), ChainHash::from(&[2; 32][..])]),
+                       remote_network_address: None,
+               }.encode(), hex::decode("00000000014001010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202").unwrap());
                let init_msg = msgs::Init { features: InitFeatures::from_le_bytes(vec![]),
+                       networks: Some(vec![mainnet_hash]),
                        remote_network_address: Some(msgs::NetAddress::IPv4 {
                                addr: [127, 0, 0, 1],
                                port: 1000,
                        }),
                };
                let encoded_value = init_msg.encode();
-               let target_value = hex::decode("000000000307017f00000103e8").unwrap();
+               let target_value = hex::decode("0000000001206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000307017f00000103e8").unwrap();
                assert_eq!(encoded_value, target_value);
                assert_eq!(msgs::Init::read(&mut Cursor::new(&target_value)).unwrap(), init_msg);
        }
index f107f3b558395fe7ea9da8f8a8194f8f52a9f634..a13a618d83c4c2b0e8988f6103a1a26c2fcb2d63 100644 (file)
@@ -312,7 +312,7 @@ impl<T: Time> Display for PaymentAttemptsUsingTime<T> {
 /// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
 /// [`Event::PaymentPathFailed`]: crate::events::Event::PaymentPathFailed
 /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub enum RetryableSendFailure {
        /// The provided [`PaymentParameters::expiry_time`] indicated that the payment has expired. Note
        /// that this error is *not* caused by [`Retry::Timeout`].
index 9e044d1c92d686479d6f76187001ac75c55d92aa..1b63a7167c326895b21b0209c312dc34c06e865d 100644 (file)
@@ -348,12 +348,16 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
        check_added_monitors!(nodes[0], 1);
 
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
 
        // Now nodes[1] should send a channel reestablish, which nodes[0] will respond to with an
        // error, as the channel has hit the chain.
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
        nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
        let as_err = nodes[0].node.get_and_clear_pending_msg_events();
@@ -518,12 +522,16 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) {
        assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0).len(), 1);
        check_added_monitors!(nodes[0], 1);
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
 
        // Now nodes[1] should send a channel reestablish, which nodes[0] will respond to with an
        // error, as the channel has hit the chain.
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
        nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
        let as_err = nodes[0].node.get_and_clear_pending_msg_events();
@@ -607,6 +615,9 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) {
        reload_node!(nodes[0], test_default_channel_config(), nodes_0_serialized, &[&chan_0_monitor_serialized, &chan_1_monitor_serialized], second_persister, second_new_chain_monitor, second_nodes_0_deserialized);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
+       nodes[0].node.test_process_background_events();
+       check_added_monitors(&nodes[0], 1);
+
        reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        // Now resend the payment, delivering the HTLC and actually claiming it this time. This ensures
@@ -632,6 +643,9 @@ fn do_test_completed_payment_not_retryable_on_reload(use_dust: bool) {
        reload_node!(nodes[0], test_default_channel_config(), nodes_0_serialized, &[&chan_0_monitor_serialized, &chan_1_monitor_serialized], third_persister, third_new_chain_monitor, third_nodes_0_deserialized);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
+       nodes[0].node.test_process_background_events();
+       check_added_monitors(&nodes[0], 1);
+
        reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        match nodes[0].node.send_payment_with_route(&new_route, payment_hash, RecipientOnionFields::secret_only(payment_secret), payment_id) {
@@ -777,6 +791,7 @@ fn do_test_dup_htlc_onchain_fails_on_reload(persist_manager_post_event: bool, co
        let height = nodes[0].blocks.lock().unwrap().len() as u32 - 1;
        nodes[0].chain_monitor.chain_monitor.block_connected(&claim_block, height);
        assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
+       check_added_monitors(&nodes[0], 1);
 }
 
 #[test]
@@ -2861,6 +2876,7 @@ fn do_no_missing_sent_on_midpoint_reload(persist_manager_with_payment: bool) {
        reload_node!(nodes[0], test_default_channel_config(), &nodes[0].node.encode(), &[&chan_0_monitor_serialized], persister_c, chain_monitor_c, nodes_0_deserialized_c);
        let events = nodes[0].node.get_and_clear_pending_events();
        assert!(events.is_empty());
+       check_added_monitors(&nodes[0], 1);
 }
 
 #[test]
index 0659412f774190ba7adee5ab599d3c4e0174cbb0..7d85d0ba1e5126a945e8a533fc14a2916b2a1575 100644 (file)
@@ -15,6 +15,7 @@
 //! call into the provided message handlers (probably a ChannelManager and P2PGossipSync) with
 //! messages they should handle, and encoding/sending response messages.
 
+use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey};
 
 use crate::sign::{KeysManager, NodeSigner, Recipient};
@@ -26,7 +27,7 @@ use crate::ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager
 use crate::util::ser::{VecWriter, Writeable, Writer};
 use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep};
 use crate::ln::wire;
-use crate::ln::wire::Encode;
+use crate::ln::wire::{Encode, Type};
 use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
 use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, NodeAlias};
 use crate::util::atomic_counter::AtomicCounter;
@@ -36,7 +37,7 @@ use crate::prelude::*;
 use crate::io;
 use alloc::collections::LinkedList;
 use crate::sync::{Arc, Mutex, MutexGuard, FairRwLock};
-use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
+use core::sync::atomic::{AtomicBool, AtomicU32, AtomicI32, Ordering};
 use core::{cmp, hash, fmt, mem};
 use core::ops::Deref;
 use core::convert::Infallible;
@@ -64,6 +65,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 +164,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.
@@ -253,6 +274,13 @@ impl ChannelMessageHandler for ErroringMessageHandler {
                features
        }
 
+       fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
+               // We don't enforce any chains upon peer connection for `ErroringMessageHandler` and leave it up
+               // to users of `ErroringMessageHandler` to make decisions on network compatiblility.
+               // There's not really any way to pull in specific networks here, and hardcoding can cause breakages.
+               None
+       }
+
        fn handle_open_channel_v2(&self, their_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
                ErroringMessageHandler::push_error(self, their_node_id, msg.temporary_channel_id);
        }
@@ -676,15 +704,18 @@ pub struct PeerManager<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: D
        /// lock held. Entries may be added with only the `peers` read lock held (though the
        /// `Descriptor` value must already exist in `peers`).
        node_id_to_descriptor: Mutex<HashMap<PublicKey, Descriptor>>,
-       /// We can only have one thread processing events at once, but we don't usually need the full
-       /// `peers` write lock to do so, so instead we block on this empty mutex when entering
-       /// `process_events`.
-       event_processing_lock: Mutex<()>,
-       /// Because event processing is global and always does all available work before returning,
-       /// there is no reason for us to have many event processors waiting on the lock at once.
-       /// Instead, we limit the total blocked event processors to always exactly one by setting this
-       /// when an event process call is waiting.
-       blocked_event_processors: AtomicBool,
+       /// We can only have one thread processing events at once, but if a second call to
+       /// `process_events` happens while a first call is in progress, one of the two calls needs to
+       /// start from the top to ensure any new messages are also handled.
+       ///
+       /// Because the event handler calls into user code which may block, we don't want to block a
+       /// second thread waiting for another thread to handle events which is then blocked on user
+       /// code, so we store an atomic counter here:
+       ///  * 0 indicates no event processor is running
+       ///  * 1 indicates an event processor is running
+       ///  * > 1 indicates an event processor is running but needs to start again from the top once
+       ///        it finishes as another thread tried to start processing events but returned early.
+       event_processing_state: AtomicI32,
 
        /// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this
        /// value increases strictly since we don't assume access to a time source.
@@ -854,8 +885,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                        message_handler,
                        peers: FairRwLock::new(HashMap::new()),
                        node_id_to_descriptor: Mutex::new(HashMap::new()),
-                       event_processing_lock: Mutex::new(()),
-                       blocked_event_processors: AtomicBool::new(false),
+                       event_processing_state: AtomicI32::new(0),
                        ephemeral_key_midstate,
                        peer_counter: AtomicCounter::new(),
                        gossip_processing_backlogged: AtomicBool::new(false),
@@ -895,6 +925,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.
        ///
@@ -1201,8 +1238,21 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                                                                Ok(x) => x,
                                                                Err(e) => {
                                                                        match e.action {
-                                                                               msgs::ErrorAction::DisconnectPeer { msg: _ } => {
-                                                                                       //TODO: Try to push msg
+                                                                               msgs::ErrorAction::DisconnectPeer { .. } => {
+                                                                                       // We may have an `ErrorMessage` to send to the peer,
+                                                                                       // but writing to the socket while reading can lead to
+                                                                                       // re-entrant code and possibly unexpected behavior. The
+                                                                                       // message send is optimistic anyway, and in this case
+                                                                                       // we immediately disconnect the peer.
+                                                                                       log_debug!(self.logger, "Error handling message{}; disconnecting peer with: {}", OptionalFromDebugger(&peer_node_id), e.err);
+                                                                                       return Err(PeerHandleError { });
+                                                                               },
+                                                                               msgs::ErrorAction::DisconnectPeerWithWarning { .. } => {
+                                                                                       // We have a `WarningMessage` to send to the peer, but
+                                                                                       // writing to the socket while reading can lead to
+                                                                                       // re-entrant code and possibly unexpected behavior. The
+                                                                                       // message send is optimistic anyway, and in this case
+                                                                                       // we immediately disconnect the peer.
                                                                                        log_debug!(self.logger, "Error handling message{}; disconnecting peer with: {}", OptionalFromDebugger(&peer_node_id), e.err);
                                                                                        return Err(PeerHandleError { });
                                                                                },
@@ -1290,10 +1340,9 @@ 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 resp = msgs::Init { features, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
+                                                               let features = self.init_features(&their_node_id);
+                                                               let networks = self.message_handler.chan_handler.get_genesis_hashes();
+                                                               let resp = msgs::Init { features, networks, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
                                                                self.enqueue_message(peer, &resp);
                                                                peer.awaiting_pong_timer_tick_intervals = 0;
                                                        },
@@ -1304,10 +1353,9 @@ 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 resp = msgs::Init { features, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
+                                                               let features = self.init_features(&their_node_id);
+                                                               let networks = self.message_handler.chan_handler.get_genesis_hashes();
+                                                               let resp = msgs::Init { features, networks, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
                                                                self.enqueue_message(peer, &resp);
                                                                peer.awaiting_pong_timer_tick_intervals = 0;
                                                        },
@@ -1337,7 +1385,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                                                                                Ok(x) => x,
                                                                                Err(e) => {
                                                                                        match e {
-                                                                                               // Note that to avoid recursion we never call
+                                                                                               // Note that to avoid re-entrancy we never call
                                                                                                // `do_attempt_write_data` from here, causing
                                                                                                // the messages enqueued here to not actually
                                                                                                // be sent before the peer is disconnected.
@@ -1358,9 +1406,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                                                                                                        });
                                                                                                        continue;
                                                                                                }
-                                                                                               (msgs::DecodeError::UnknownRequiredFeature, ty) => {
-                                                                                                       log_gossip!(self.logger, "Received a message with an unknown required feature flag or TLV, you may want to update!");
-                                                                                                       self.enqueue_message(peer, &msgs::WarningMessage { channel_id: [0; 32], data: format!("Received an unknown required feature/TLV in message type {:?}", ty) });
+                                                                                               (msgs::DecodeError::UnknownRequiredFeature, _) => {
+                                                                                                       log_debug!(self.logger, "Received a message with an unknown required feature flag or TLV, you may want to update!");
                                                                                                        return Err(PeerHandleError { });
                                                                                                }
                                                                                                (msgs::DecodeError::UnknownVersion, _) => return Err(PeerHandleError { }),
@@ -1423,10 +1470,36 @@ 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");
+                       // Check if we have any compatible chains if the `networks` field is specified.
+                       if let Some(networks) = &msg.networks {
+                               if let Some(our_chains) = self.message_handler.chan_handler.get_genesis_hashes() {
+                                       let mut have_compatible_chains = false;
+                                       'our_chains: for our_chain in our_chains.iter() {
+                                               for their_chain in networks {
+                                                       if our_chain == their_chain {
+                                                               have_compatible_chains = true;
+                                                               break 'our_chains;
+                                                       }
+                                               }
+                                       }
+                                       if !have_compatible_chains {
+                                               log_debug!(self.logger, "Peer does not support any of our supported chains");
+                                               return Err(PeerHandleError { }.into());
+                                       }
+                               }
+                       }
+
+                       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());
                        }
@@ -1784,356 +1857,364 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
        /// [`ChannelManager::process_pending_htlc_forwards`]: crate::ln::channelmanager::ChannelManager::process_pending_htlc_forwards
        /// [`send_data`]: SocketDescriptor::send_data
        pub fn process_events(&self) {
-               let mut _single_processor_lock = self.event_processing_lock.try_lock();
-               if _single_processor_lock.is_err() {
-                       // While we could wake the older sleeper here with a CV and make more even waiting
-                       // times, that would be a lot of overengineering for a simple "reduce total waiter
-                       // count" goal.
-                       match self.blocked_event_processors.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) {
-                               Err(val) => {
-                                       debug_assert!(val, "compare_exchange failed spuriously?");
-                                       return;
-                               },
-                               Ok(val) => {
-                                       debug_assert!(!val, "compare_exchange succeeded spuriously?");
-                                       // We're the only waiter, as the running process_events may have emptied the
-                                       // pending events "long" ago and there are new events for us to process, wait until
-                                       // its done and process any leftover events before returning.
-                                       _single_processor_lock = Ok(self.event_processing_lock.lock().unwrap());
-                                       self.blocked_event_processors.store(false, Ordering::Release);
-                               }
-                       }
+               if self.event_processing_state.fetch_add(1, Ordering::AcqRel) > 0 {
+                       // If we're not the first event processor to get here, just return early, the increment
+                       // we just did will be treated as "go around again" at the end.
+                       return;
                }
 
-               self.update_gossip_backlogged();
-               let flush_read_disabled = self.gossip_processing_backlog_lifted.swap(false, Ordering::Relaxed);
+               loop {
+                       self.update_gossip_backlogged();
+                       let flush_read_disabled = self.gossip_processing_backlog_lifted.swap(false, Ordering::Relaxed);
 
-               let mut peers_to_disconnect = HashMap::new();
-               let mut events_generated = self.message_handler.chan_handler.get_and_clear_pending_msg_events();
-               events_generated.append(&mut self.message_handler.route_handler.get_and_clear_pending_msg_events());
+                       let mut peers_to_disconnect = HashMap::new();
+                       let mut events_generated = self.message_handler.chan_handler.get_and_clear_pending_msg_events();
+                       events_generated.append(&mut self.message_handler.route_handler.get_and_clear_pending_msg_events());
 
-               {
-                       // TODO: There are some DoS attacks here where you can flood someone's outbound send
-                       // buffer by doing things like announcing channels on another node. We should be willing to
-                       // drop optional-ish messages when send buffers get full!
-
-                       let peers_lock = self.peers.read().unwrap();
-                       let peers = &*peers_lock;
-                       macro_rules! get_peer_for_forwarding {
-                               ($node_id: expr) => {
-                                       {
-                                               if peers_to_disconnect.get($node_id).is_some() {
-                                                       // If we've "disconnected" this peer, do not send to it.
-                                                       continue;
-                                               }
-                                               let descriptor_opt = self.node_id_to_descriptor.lock().unwrap().get($node_id).cloned();
-                                               match descriptor_opt {
-                                                       Some(descriptor) => match peers.get(&descriptor) {
-                                                               Some(peer_mutex) => {
-                                                                       let peer_lock = peer_mutex.lock().unwrap();
-                                                                       if !peer_lock.handshake_complete() {
+                       {
+                               // TODO: There are some DoS attacks here where you can flood someone's outbound send
+                               // buffer by doing things like announcing channels on another node. We should be willing to
+                               // drop optional-ish messages when send buffers get full!
+
+                               let peers_lock = self.peers.read().unwrap();
+                               let peers = &*peers_lock;
+                               macro_rules! get_peer_for_forwarding {
+                                       ($node_id: expr) => {
+                                               {
+                                                       if peers_to_disconnect.get($node_id).is_some() {
+                                                               // If we've "disconnected" this peer, do not send to it.
+                                                               continue;
+                                                       }
+                                                       let descriptor_opt = self.node_id_to_descriptor.lock().unwrap().get($node_id).cloned();
+                                                       match descriptor_opt {
+                                                               Some(descriptor) => match peers.get(&descriptor) {
+                                                                       Some(peer_mutex) => {
+                                                                               let peer_lock = peer_mutex.lock().unwrap();
+                                                                               if !peer_lock.handshake_complete() {
+                                                                                       continue;
+                                                                               }
+                                                                               peer_lock
+                                                                       },
+                                                                       None => {
+                                                                               debug_assert!(false, "Inconsistent peers set state!");
                                                                                continue;
                                                                        }
-                                                                       peer_lock
                                                                },
                                                                None => {
-                                                                       debug_assert!(false, "Inconsistent peers set state!");
                                                                        continue;
-                                                               }
-                                                       },
-                                                       None => {
-                                                               continue;
-                                                       },
+                                                               },
+                                                       }
                                                }
                                        }
                                }
-                       }
-                       for event in events_generated.drain(..) {
-                               match event {
-                                       MessageSendEvent::SendAcceptChannel { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendAcceptChannel event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.temporary_channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendAcceptChannelV2 { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendAcceptChannelV2 event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.temporary_channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendOpenChannel { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendOpenChannel event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.temporary_channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendOpenChannelV2 { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendOpenChannelV2 event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.temporary_channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendFundingCreated { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendFundingCreated event in peer_handler for node {} for channel {} (which becomes {})",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.temporary_channel_id),
-                                                               log_funding_channel_id!(msg.funding_txid, msg.funding_output_index));
-                                               // TODO: If the peer is gone we should generate a DiscardFunding event
-                                               // indicating to the wallet that they should just throw away this funding transaction
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendFundingSigned { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendFundingSigned event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendChannelReady { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendChannelReady event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxAddInput { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxAddInput event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxAddOutput { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxAddOutput event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxRemoveInput { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxRemoveInput event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxRemoveOutput { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxRemoveOutput event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxComplete { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxComplete event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxSignatures { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxSignatures event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxInitRbf { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxInitRbf event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxAckRbf { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxAckRbf event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendTxAbort { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendTxAbort event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendAnnouncementSignatures { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendAnnouncementSignatures event in peer_handler for node {} for channel {})",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => {
-                                               log_debug!(self.logger, "Handling UpdateHTLCs event in peer_handler for node {} with {} adds, {} fulfills, {} fails for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               update_add_htlcs.len(),
-                                                               update_fulfill_htlcs.len(),
-                                                               update_fail_htlcs.len(),
-                                                               log_bytes!(commitment_signed.channel_id));
-                                               let mut peer = get_peer_for_forwarding!(node_id);
-                                               for msg in update_add_htlcs {
-                                                       self.enqueue_message(&mut *peer, msg);
-                                               }
-                                               for msg in update_fulfill_htlcs {
-                                                       self.enqueue_message(&mut *peer, msg);
-                                               }
-                                               for msg in update_fail_htlcs {
-                                                       self.enqueue_message(&mut *peer, msg);
-                                               }
-                                               for msg in update_fail_malformed_htlcs {
-                                                       self.enqueue_message(&mut *peer, msg);
-                                               }
-                                               if let &Some(ref msg) = update_fee {
-                                                       self.enqueue_message(&mut *peer, msg);
-                                               }
-                                               self.enqueue_message(&mut *peer, commitment_signed);
-                                       },
-                                       MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendRevokeAndACK event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendClosingSigned { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendClosingSigned event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendShutdown { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling Shutdown event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } => {
-                                               log_debug!(self.logger, "Handling SendChannelReestablish event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id),
-                                                               log_bytes!(msg.channel_id));
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendChannelAnnouncement { ref node_id, ref msg, ref update_msg } => {
-                                               log_debug!(self.logger, "Handling SendChannelAnnouncement event in peer_handler for node {} for short channel id {}",
-                                                               log_pubkey!(node_id),
-                                                               msg.contents.short_channel_id);
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), update_msg);
-                                       },
-                                       MessageSendEvent::BroadcastChannelAnnouncement { msg, update_msg } => {
-                                               log_debug!(self.logger, "Handling BroadcastChannelAnnouncement event in peer_handler for short channel id {}", msg.contents.short_channel_id);
-                                               match self.message_handler.route_handler.handle_channel_announcement(&msg) {
-                                                       Ok(_) | Err(LightningError { action: msgs::ErrorAction::IgnoreDuplicateGossip, .. }) =>
-                                                               self.forward_broadcast_msg(peers, &wire::Message::ChannelAnnouncement(msg), None),
-                                                       _ => {},
-                                               }
-                                               if let Some(msg) = update_msg {
+                               for event in events_generated.drain(..) {
+                                       match event {
+                                               MessageSendEvent::SendAcceptChannel { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendAcceptChannel event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.temporary_channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendAcceptChannelV2 { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendAcceptChannelV2 event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.temporary_channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendOpenChannel { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendOpenChannel event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.temporary_channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendOpenChannelV2 { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendOpenChannelV2 event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.temporary_channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendFundingCreated { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendFundingCreated event in peer_handler for node {} for channel {} (which becomes {})",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.temporary_channel_id),
+                                                                       log_funding_channel_id!(msg.funding_txid, msg.funding_output_index));
+                                                       // TODO: If the peer is gone we should generate a DiscardFunding event
+                                                       // indicating to the wallet that they should just throw away this funding transaction
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendFundingSigned { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendFundingSigned event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendChannelReady { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendChannelReady event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxAddInput { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxAddInput event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxAddOutput { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxAddOutput event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxRemoveInput { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxRemoveInput event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxRemoveOutput { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxRemoveOutput event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxComplete { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxComplete event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxSignatures { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxSignatures event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxInitRbf { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxInitRbf event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxAckRbf { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxAckRbf event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendTxAbort { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendTxAbort event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendAnnouncementSignatures { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendAnnouncementSignatures event in peer_handler for node {} for channel {})",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => {
+                                                       log_debug!(self.logger, "Handling UpdateHTLCs event in peer_handler for node {} with {} adds, {} fulfills, {} fails for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       update_add_htlcs.len(),
+                                                                       update_fulfill_htlcs.len(),
+                                                                       update_fail_htlcs.len(),
+                                                                       log_bytes!(commitment_signed.channel_id));
+                                                       let mut peer = get_peer_for_forwarding!(node_id);
+                                                       for msg in update_add_htlcs {
+                                                               self.enqueue_message(&mut *peer, msg);
+                                                       }
+                                                       for msg in update_fulfill_htlcs {
+                                                               self.enqueue_message(&mut *peer, msg);
+                                                       }
+                                                       for msg in update_fail_htlcs {
+                                                               self.enqueue_message(&mut *peer, msg);
+                                                       }
+                                                       for msg in update_fail_malformed_htlcs {
+                                                               self.enqueue_message(&mut *peer, msg);
+                                                       }
+                                                       if let &Some(ref msg) = update_fee {
+                                                               self.enqueue_message(&mut *peer, msg);
+                                                       }
+                                                       self.enqueue_message(&mut *peer, commitment_signed);
+                                               },
+                                               MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendRevokeAndACK event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendClosingSigned { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendClosingSigned event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendShutdown { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling Shutdown event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } => {
+                                                       log_debug!(self.logger, "Handling SendChannelReestablish event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id),
+                                                                       log_bytes!(msg.channel_id));
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendChannelAnnouncement { ref node_id, ref msg, ref update_msg } => {
+                                                       log_debug!(self.logger, "Handling SendChannelAnnouncement event in peer_handler for node {} for short channel id {}",
+                                                                       log_pubkey!(node_id),
+                                                                       msg.contents.short_channel_id);
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), update_msg);
+                                               },
+                                               MessageSendEvent::BroadcastChannelAnnouncement { msg, update_msg } => {
+                                                       log_debug!(self.logger, "Handling BroadcastChannelAnnouncement event in peer_handler for short channel id {}", msg.contents.short_channel_id);
+                                                       match self.message_handler.route_handler.handle_channel_announcement(&msg) {
+                                                               Ok(_) | Err(LightningError { action: msgs::ErrorAction::IgnoreDuplicateGossip, .. }) =>
+                                                                       self.forward_broadcast_msg(peers, &wire::Message::ChannelAnnouncement(msg), None),
+                                                               _ => {},
+                                                       }
+                                                       if let Some(msg) = update_msg {
+                                                               match self.message_handler.route_handler.handle_channel_update(&msg) {
+                                                                       Ok(_) | Err(LightningError { action: msgs::ErrorAction::IgnoreDuplicateGossip, .. }) =>
+                                                                               self.forward_broadcast_msg(peers, &wire::Message::ChannelUpdate(msg), None),
+                                                                       _ => {},
+                                                               }
+                                                       }
+                                               },
+                                               MessageSendEvent::BroadcastChannelUpdate { msg } => {
+                                                       log_debug!(self.logger, "Handling BroadcastChannelUpdate event in peer_handler for short channel id {}", msg.contents.short_channel_id);
                                                        match self.message_handler.route_handler.handle_channel_update(&msg) {
                                                                Ok(_) | Err(LightningError { action: msgs::ErrorAction::IgnoreDuplicateGossip, .. }) =>
                                                                        self.forward_broadcast_msg(peers, &wire::Message::ChannelUpdate(msg), None),
                                                                _ => {},
                                                        }
+                                               },
+                                               MessageSendEvent::BroadcastNodeAnnouncement { msg } => {
+                                                       log_debug!(self.logger, "Handling BroadcastNodeAnnouncement event in peer_handler for node {}", msg.contents.node_id);
+                                                       match self.message_handler.route_handler.handle_node_announcement(&msg) {
+                                                               Ok(_) | Err(LightningError { action: msgs::ErrorAction::IgnoreDuplicateGossip, .. }) =>
+                                                                       self.forward_broadcast_msg(peers, &wire::Message::NodeAnnouncement(msg), None),
+                                                               _ => {},
+                                                       }
+                                               },
+                                               MessageSendEvent::SendChannelUpdate { ref node_id, ref msg } => {
+                                                       log_trace!(self.logger, "Handling SendChannelUpdate event in peer_handler for node {} for channel {}",
+                                                                       log_pubkey!(node_id), msg.contents.short_channel_id);
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::HandleError { node_id, action } => {
+                                                       match action {
+                                                               msgs::ErrorAction::DisconnectPeer { msg } => {
+                                                                       if let Some(msg) = msg.as_ref() {
+                                                                               log_trace!(self.logger, "Handling DisconnectPeer HandleError event in peer_handler for node {} with message {}",
+                                                                                       log_pubkey!(node_id), msg.data);
+                                                                       } else {
+                                                                               log_trace!(self.logger, "Handling DisconnectPeer HandleError event in peer_handler for node {}",
+                                                                                       log_pubkey!(node_id));
+                                                                       }
+                                                                       // We do not have the peers write lock, so we just store that we're
+                                                                       // about to disconenct the peer and do it after we finish
+                                                                       // processing most messages.
+                                                                       let msg = msg.map(|msg| wire::Message::<<<CMH as core::ops::Deref>::Target as wire::CustomMessageReader>::CustomMessage>::Error(msg));
+                                                                       peers_to_disconnect.insert(node_id, msg);
+                                                               },
+                                                               msgs::ErrorAction::DisconnectPeerWithWarning { msg } => {
+                                                                       log_trace!(self.logger, "Handling DisconnectPeer HandleError event in peer_handler for node {} with message {}",
+                                                                               log_pubkey!(node_id), msg.data);
+                                                                       // We do not have the peers write lock, so we just store that we're
+                                                                       // about to disconenct the peer and do it after we finish
+                                                                       // processing most messages.
+                                                                       peers_to_disconnect.insert(node_id, Some(wire::Message::Warning(msg)));
+                                                               },
+                                                               msgs::ErrorAction::IgnoreAndLog(level) => {
+                                                                       log_given_level!(self.logger, level, "Received a HandleError event to be ignored for node {}", log_pubkey!(node_id));
+                                                               },
+                                                               msgs::ErrorAction::IgnoreDuplicateGossip => {},
+                                                               msgs::ErrorAction::IgnoreError => {
+                                                                               log_debug!(self.logger, "Received a HandleError event to be ignored for node {}", log_pubkey!(node_id));
+                                                                       },
+                                                               msgs::ErrorAction::SendErrorMessage { ref msg } => {
+                                                                       log_trace!(self.logger, "Handling SendErrorMessage HandleError event in peer_handler for node {} with message {}",
+                                                                                       log_pubkey!(node_id),
+                                                                                       msg.data);
+                                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(&node_id), msg);
+                                                               },
+                                                               msgs::ErrorAction::SendWarningMessage { ref msg, ref log_level } => {
+                                                                       log_given_level!(self.logger, *log_level, "Handling SendWarningMessage HandleError event in peer_handler for node {} with message {}",
+                                                                                       log_pubkey!(node_id),
+                                                                                       msg.data);
+                                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(&node_id), msg);
+                                                               },
+                                                       }
+                                               },
+                                               MessageSendEvent::SendChannelRangeQuery { ref node_id, ref msg } => {
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
+                                               },
+                                               MessageSendEvent::SendShortIdsQuery { ref node_id, ref msg } => {
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
                                                }
-                                       },
-                                       MessageSendEvent::BroadcastChannelUpdate { msg } => {
-                                               log_debug!(self.logger, "Handling BroadcastChannelUpdate event in peer_handler for short channel id {}", msg.contents.short_channel_id);
-                                               match self.message_handler.route_handler.handle_channel_update(&msg) {
-                                                       Ok(_) | Err(LightningError { action: msgs::ErrorAction::IgnoreDuplicateGossip, .. }) =>
-                                                               self.forward_broadcast_msg(peers, &wire::Message::ChannelUpdate(msg), None),
-                                                       _ => {},
-                                               }
-                                       },
-                                       MessageSendEvent::BroadcastNodeAnnouncement { msg } => {
-                                               log_debug!(self.logger, "Handling BroadcastNodeAnnouncement event in peer_handler for node {}", msg.contents.node_id);
-                                               match self.message_handler.route_handler.handle_node_announcement(&msg) {
-                                                       Ok(_) | Err(LightningError { action: msgs::ErrorAction::IgnoreDuplicateGossip, .. }) =>
-                                                               self.forward_broadcast_msg(peers, &wire::Message::NodeAnnouncement(msg), None),
-                                                       _ => {},
+                                               MessageSendEvent::SendReplyChannelRange { ref node_id, ref msg } => {
+                                                       log_gossip!(self.logger, "Handling SendReplyChannelRange event in peer_handler for node {} with num_scids={} first_blocknum={} number_of_blocks={}, sync_complete={}",
+                                                               log_pubkey!(node_id),
+                                                               msg.short_channel_ids.len(),
+                                                               msg.first_blocknum,
+                                                               msg.number_of_blocks,
+                                                               msg.sync_complete);
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
                                                }
-                                       },
-                                       MessageSendEvent::SendChannelUpdate { ref node_id, ref msg } => {
-                                               log_trace!(self.logger, "Handling SendChannelUpdate event in peer_handler for node {} for channel {}",
-                                                               log_pubkey!(node_id), msg.contents.short_channel_id);
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::HandleError { ref node_id, ref action } => {
-                                               match *action {
-                                                       msgs::ErrorAction::DisconnectPeer { ref msg } => {
-                                                               // We do not have the peers write lock, so we just store that we're
-                                                               // about to disconenct the peer and do it after we finish
-                                                               // processing most messages.
-                                                               peers_to_disconnect.insert(*node_id, msg.clone());
-                                                       },
-                                                       msgs::ErrorAction::IgnoreAndLog(level) => {
-                                                               log_given_level!(self.logger, level, "Received a HandleError event to be ignored for node {}", log_pubkey!(node_id));
-                                                       },
-                                                       msgs::ErrorAction::IgnoreDuplicateGossip => {},
-                                                       msgs::ErrorAction::IgnoreError => {
-                                                               log_debug!(self.logger, "Received a HandleError event to be ignored for node {}", log_pubkey!(node_id));
-                                                       },
-                                                       msgs::ErrorAction::SendErrorMessage { ref msg } => {
-                                                               log_trace!(self.logger, "Handling SendErrorMessage HandleError event in peer_handler for node {} with message {}",
-                                                                               log_pubkey!(node_id),
-                                                                               msg.data);
-                                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                                       },
-                                                       msgs::ErrorAction::SendWarningMessage { ref msg, ref log_level } => {
-                                                               log_given_level!(self.logger, *log_level, "Handling SendWarningMessage HandleError event in peer_handler for node {} with message {}",
-                                                                               log_pubkey!(node_id),
-                                                                               msg.data);
-                                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                                       },
+                                               MessageSendEvent::SendGossipTimestampFilter { ref node_id, ref msg } => {
+                                                       self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
                                                }
-                                       },
-                                       MessageSendEvent::SendChannelRangeQuery { ref node_id, ref msg } => {
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       },
-                                       MessageSendEvent::SendShortIdsQuery { ref node_id, ref msg } => {
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       }
-                                       MessageSendEvent::SendReplyChannelRange { ref node_id, ref msg } => {
-                                               log_gossip!(self.logger, "Handling SendReplyChannelRange event in peer_handler for node {} with num_scids={} first_blocknum={} number_of_blocks={}, sync_complete={}",
-                                                       log_pubkey!(node_id),
-                                                       msg.short_channel_ids.len(),
-                                                       msg.first_blocknum,
-                                                       msg.number_of_blocks,
-                                                       msg.sync_complete);
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
-                                       }
-                                       MessageSendEvent::SendGossipTimestampFilter { ref node_id, ref msg } => {
-                                               self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
                                        }
                                }
-                       }
 
-                       for (node_id, msg) in self.message_handler.custom_message_handler.get_and_clear_pending_msg() {
-                               if peers_to_disconnect.get(&node_id).is_some() { continue; }
-                               self.enqueue_message(&mut *get_peer_for_forwarding!(&node_id), &msg);
-                       }
+                               for (node_id, msg) in self.message_handler.custom_message_handler.get_and_clear_pending_msg() {
+                                       if peers_to_disconnect.get(&node_id).is_some() { continue; }
+                                       self.enqueue_message(&mut *get_peer_for_forwarding!(&node_id), &msg);
+                               }
 
-                       for (descriptor, peer_mutex) in peers.iter() {
-                               let mut peer = peer_mutex.lock().unwrap();
-                               if flush_read_disabled { peer.received_channel_announce_since_backlogged = false; }
-                               self.do_attempt_write_data(&mut (*descriptor).clone(), &mut *peer, flush_read_disabled);
+                               for (descriptor, peer_mutex) in peers.iter() {
+                                       let mut peer = peer_mutex.lock().unwrap();
+                                       if flush_read_disabled { peer.received_channel_announce_since_backlogged = false; }
+                                       self.do_attempt_write_data(&mut (*descriptor).clone(), &mut *peer, flush_read_disabled);
+                               }
                        }
-               }
-               if !peers_to_disconnect.is_empty() {
-                       let mut peers_lock = self.peers.write().unwrap();
-                       let peers = &mut *peers_lock;
-                       for (node_id, msg) in peers_to_disconnect.drain() {
-                               // Note that since we are holding the peers *write* lock we can
-                               // remove from node_id_to_descriptor immediately (as no other
-                               // thread can be holding the peer lock if we have the global write
-                               // lock).
-
-                               let descriptor_opt = self.node_id_to_descriptor.lock().unwrap().remove(&node_id);
-                               if let Some(mut descriptor) = descriptor_opt {
-                                       if let Some(peer_mutex) = peers.remove(&descriptor) {
-                                               let mut peer = peer_mutex.lock().unwrap();
-                                               if let Some(msg) = msg {
-                                                       log_trace!(self.logger, "Handling DisconnectPeer HandleError event in peer_handler for node {} with message {}",
-                                                                       log_pubkey!(node_id),
-                                                                       msg.data);
-                                                       self.enqueue_message(&mut *peer, &msg);
-                                                       // This isn't guaranteed to work, but if there is enough free
-                                                       // room in the send buffer, put the error message there...
-                                                       self.do_attempt_write_data(&mut descriptor, &mut *peer, false);
-                                               }
-                                               self.do_disconnect(descriptor, &*peer, "DisconnectPeer HandleError");
-                                       } else { debug_assert!(false, "Missing connection for peer"); }
+                       if !peers_to_disconnect.is_empty() {
+                               let mut peers_lock = self.peers.write().unwrap();
+                               let peers = &mut *peers_lock;
+                               for (node_id, msg) in peers_to_disconnect.drain() {
+                                       // Note that since we are holding the peers *write* lock we can
+                                       // remove from node_id_to_descriptor immediately (as no other
+                                       // thread can be holding the peer lock if we have the global write
+                                       // lock).
+
+                                       let descriptor_opt = self.node_id_to_descriptor.lock().unwrap().remove(&node_id);
+                                       if let Some(mut descriptor) = descriptor_opt {
+                                               if let Some(peer_mutex) = peers.remove(&descriptor) {
+                                                       let mut peer = peer_mutex.lock().unwrap();
+                                                       if let Some(msg) = msg {
+                                                               self.enqueue_message(&mut *peer, &msg);
+                                                               // This isn't guaranteed to work, but if there is enough free
+                                                               // room in the send buffer, put the error message there...
+                                                               self.do_attempt_write_data(&mut descriptor, &mut *peer, false);
+                                                       }
+                                                       self.do_disconnect(descriptor, &*peer, "DisconnectPeer HandleError");
+                                               } else { debug_assert!(false, "Missing connection for peer"); }
+                                       }
                                }
                        }
+
+                       if self.event_processing_state.fetch_sub(1, Ordering::AcqRel) != 1 {
+                               // If another thread incremented the state while we were running we should go
+                               // around again, but only once.
+                               self.event_processing_state.store(1, Ordering::Release);
+                               continue;
+                       }
+                       break;
                }
        }
 
@@ -2348,8 +2429,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),
@@ -2398,16 +2480,21 @@ 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::Network;
+       use bitcoin::blockdata::constants::ChainHash;
+       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)]
@@ -2440,19 +2527,51 @@ 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(),
+                                       chan_handler: test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet)),
                                        logger: test_utils::TestLogger::new(),
                                        routing_handler: test_utils::TestRoutingMessageHandler::new(),
+                                       custom_handler: TestCustomMessageHandler { features },
                                        node_signer: test_utils::TestNodeSigner::new(node_secret),
                                }
                        );
@@ -2461,13 +2580,56 @@ 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_feature_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(ChainHash::using_genesis_block(Network::Testnet)),
+                                       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_chain_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 = InitFeatures::from_le_bytes(vec![0u8; 33]);
+                       let network = ChainHash::from(&[i as u8; 32][..]);
+                       cfgs.push(
+                               PeerManagerCfg{
+                                       chan_handler: test_utils::TestChannelMessageHandler::new(network),
+                                       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_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);
@@ -2476,7 +2638,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())),
@@ -2591,6 +2753,78 @@ mod tests {
                thrd_b.join().unwrap();
        }
 
+       #[test]
+       fn test_feature_incompatible_peers() {
+               let cfgs = create_peermgr_cfgs(2);
+               let incompatible_cfgs = create_feature_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_chain_incompatible_peers() {
+               let cfgs = create_peermgr_cfgs(2);
+               let incompatible_cfgs = create_chain_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 incompatible chains
+                       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
@@ -2615,8 +2849,8 @@ mod tests {
                // Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and
                // push a message from one peer to another.
                let cfgs = create_peermgr_cfgs(2);
-               let a_chan_handler = test_utils::TestChannelMessageHandler::new();
-               let b_chan_handler = test_utils::TestChannelMessageHandler::new();
+               let a_chan_handler = test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet));
+               let b_chan_handler = test_utils::TestChannelMessageHandler::new(ChainHash::using_genesis_block(Network::Testnet));
                let mut peers = create_network(2, &cfgs);
                let (fd_a, mut fd_b) = establish_connection(&peers[0], &peers[1]);
                assert_eq!(peers[0].peers.read().unwrap().len(), 1);
@@ -2879,4 +3113,53 @@ mod tests {
                // For (None)
                assert_eq!(filter_addresses(None), None);
        }
+
+       #[test]
+       #[cfg(feature = "std")]
+       fn test_process_events_multithreaded() {
+               use std::time::{Duration, Instant};
+               // Test that `process_events` getting called on multiple threads doesn't generate too many
+               // loop iterations.
+               // Each time `process_events` goes around the loop we call
+               // `get_and_clear_pending_msg_events`, which we count using the `TestMessageHandler`.
+               // Because the loop should go around once more after a call which fails to take the
+               // single-threaded lock, if we write zero to the counter before calling `process_events` we
+               // should never observe there having been more than 2 loop iterations.
+               // Further, because the last thread to exit will call `process_events` before returning, we
+               // should always have at least one count at the end.
+               let cfg = Arc::new(create_peermgr_cfgs(1));
+               // Until we have std::thread::scoped we have to unsafe { turn off the borrow checker }.
+               let peer = Arc::new(create_network(1, unsafe { &*(&*cfg as *const _) as &'static _ }).pop().unwrap());
+
+               let exit_flag = Arc::new(AtomicBool::new(false));
+               macro_rules! spawn_thread { () => { {
+                       let thread_cfg = Arc::clone(&cfg);
+                       let thread_peer = Arc::clone(&peer);
+                       let thread_exit = Arc::clone(&exit_flag);
+                       std::thread::spawn(move || {
+                               while !thread_exit.load(Ordering::Acquire) {
+                                       thread_cfg[0].chan_handler.message_fetch_counter.store(0, Ordering::Release);
+                                       thread_peer.process_events();
+                                       std::thread::sleep(Duration::from_micros(1));
+                               }
+                       })
+               } } }
+
+               let thread_a = spawn_thread!();
+               let thread_b = spawn_thread!();
+               let thread_c = spawn_thread!();
+
+               let start_time = Instant::now();
+               while start_time.elapsed() < Duration::from_millis(100) {
+                       let val = cfg[0].chan_handler.message_fetch_counter.load(Ordering::Acquire);
+                       assert!(val <= 2);
+                       std::thread::yield_now(); // Winblowz seemingly doesn't ever interrupt threads?!
+               }
+
+               exit_flag.store(true, Ordering::Release);
+               thread_a.join().unwrap();
+               thread_b.join().unwrap();
+               thread_c.join().unwrap();
+               assert!(cfg[0].chan_handler.message_fetch_counter.load(Ordering::Acquire) >= 1);
+       }
 }
index cfcc46dfedace4a7048341ad495ca437ae9b1122..8d3fbf0ec64667a756c48777fced8f53a2997b5b 100644 (file)
@@ -101,8 +101,12 @@ fn test_priv_forwarding_rejection() {
        no_announce_cfg.accept_forwards_to_priv_channels = true;
        reload_node!(nodes[1], no_announce_cfg, &nodes_1_serialized, &[&monitor_a_serialized, &monitor_b_serialized], persister, new_chain_monitor, nodes_1_deserialized);
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let as_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
        let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
        nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_reestablish);
@@ -110,8 +114,12 @@ fn test_priv_forwarding_rejection() {
        get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
        get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id());
 
-       nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: nodes[2].node.init_features(), remote_network_address: None }, true).unwrap();
-       nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init {
+               features: nodes[2].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
+       nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[2]).pop().unwrap();
        let cs_reestablish = get_chan_reestablish_msgs!(nodes[2], nodes[1]).pop().unwrap();
        nodes[2].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
@@ -853,10 +861,12 @@ fn test_0conf_channel_reorg() {
                err: "Funding transaction was un-confirmed. Locked at 0 confs, now have 0 confs.".to_owned()
        });
        check_closed_broadcast!(nodes[0], true);
+       check_added_monitors(&nodes[0], 1);
        check_closed_event!(&nodes[1], 1, ClosureReason::ProcessingError {
                err: "Funding transaction was un-confirmed. Locked at 0 confs, now have 0 confs.".to_owned()
        });
        check_closed_broadcast!(nodes[1], true);
+       check_added_monitors(&nodes[1], 1);
 }
 
 #[test]
index 9b694c7b869b4709ea213a820070896bf483fb59..bf2fb1de1e30d4a9ff3bf1fa5498d8f37fbbf5f8 100644 (file)
@@ -61,9 +61,13 @@ fn test_funding_peer_disconnect() {
        let events_2 = nodes[1].node.get_and_clear_pending_msg_events();
        assert!(events_2.is_empty());
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let as_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let bs_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
 
        // nodes[0] hasn't yet received a channel_ready, so it only sends that on reconnect.
@@ -197,9 +201,13 @@ fn test_no_txn_manager_serialize_deserialize() {
                get_monitor!(nodes[0], OutPoint { txid: tx.txid(), index: 0 }.to_channel_id()).encode();
        reload_node!(nodes[0], nodes[0].node.encode(), &[&chan_0_monitor_serialized], persister, new_chain_monitor, nodes_0_deserialized);
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
 
        nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[0]);
@@ -282,9 +290,13 @@ fn test_manager_serialize_deserialize_events() {
        // Make sure the channel is functioning as though the de/serialization never happened
        assert_eq!(nodes[0].node.list_channels().len(), 1);
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
 
        nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[0]);
@@ -449,9 +461,13 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
        //... and we can even still claim the payment!
        claim_payment(&nodes[2], &[&nodes[0], &nodes[1]], our_payment_preimage);
 
-       nodes[3].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[3].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let reestablish = get_chan_reestablish_msgs!(nodes[3], nodes[0]).pop().unwrap();
-       nodes[0].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: nodes[3].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[0].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init {
+               features: nodes[3].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        nodes[0].node.handle_channel_reestablish(&nodes[3].node.get_our_node_id(), &reestablish);
        let mut found_err = false;
        for msg_event in nodes[0].node.get_and_clear_pending_msg_events() {
@@ -500,8 +516,12 @@ fn do_test_data_loss_protect(reconnect_panicing: bool) {
        reload_node!(nodes[0], previous_node_state, &[&previous_chain_monitor_state], persister, new_chain_monitor, nodes_0_deserialized);
 
        if reconnect_panicing {
-               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
-               nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
+               nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
 
                let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
 
@@ -549,8 +569,12 @@ fn do_test_data_loss_protect(reconnect_panicing: bool) {
        // after the warning message sent by B, we should not able to
        // use the channel, or reconnect with success to the channel.
        assert!(nodes[0].node.list_usable_channels().is_empty());
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let retry_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
 
        nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &retry_reestablish[0]);
@@ -774,6 +798,9 @@ fn do_test_partial_claim_before_restart(persist_both_monitors: bool) {
        if let Event::ChannelClosed { reason: ClosureReason::OutdatedChannelManager, .. } = events[1] { } else { panic!(); }
        if persist_both_monitors {
                if let Event::ChannelClosed { reason: ClosureReason::OutdatedChannelManager, .. } = events[2] { } else { panic!(); }
+               check_added_monitors(&nodes[3], 2);
+       } else {
+               check_added_monitors(&nodes[3], 1);
        }
 
        // On restart, we should also get a duplicate PaymentClaimed event as we persisted the
@@ -788,9 +815,13 @@ fn do_test_partial_claim_before_restart(persist_both_monitors: bool) {
        if !persist_both_monitors {
                // If one of the two channels is still live, reveal the payment preimage over it.
 
-               nodes[3].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: nodes[2].node.init_features(), remote_network_address: None }, true).unwrap();
+               nodes[3].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[2].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                let reestablish_1 = get_chan_reestablish_msgs!(nodes[3], nodes[2]);
-               nodes[2].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: nodes[3].node.init_features(), remote_network_address: None }, false).unwrap();
+               nodes[2].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[3].node.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
                let reestablish_2 = get_chan_reestablish_msgs!(nodes[2], nodes[3]);
 
                nodes[2].node.handle_channel_reestablish(&nodes[3].node.get_our_node_id(), &reestablish_1[0]);
@@ -1047,6 +1078,9 @@ fn removed_payment_no_manager_persistence() {
                _ => panic!("Unexpected event"),
        }
 
+       nodes[1].node.test_process_background_events();
+       check_added_monitors(&nodes[1], 1);
+
        // Now that the ChannelManager has force-closed the channel which had the HTLC removed, it is
        // now forgotten everywhere. The ChannelManager should have, as a side-effect of reload,
        // learned that the HTLC is gone from the ChannelMonitor and added it to the to-fail-back set.
index 633eceddbd8721c19e5623cbc334bc648e57362d..be756840adc7ce2a26961193c85d87e1010b18ba 100644 (file)
@@ -289,8 +289,6 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_
                let relevant_txids = nodes[0].node.get_relevant_txids();
                assert_eq!(relevant_txids.len(), 0);
 
-               handle_announce_close_broadcast_events(&nodes, 0, 1, true, "Channel closed because of an exception: Funding transaction was un-confirmed. Locked at 6 confs, now have 0 confs.");
-               check_added_monitors!(nodes[1], 1);
                {
                        let per_peer_state = nodes[0].node.per_peer_state.read().unwrap();
                        let peer_state = per_peer_state.get(&nodes[1].node.get_our_node_id()).unwrap().lock().unwrap();
@@ -336,8 +334,6 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_
                let relevant_txids = nodes[0].node.get_relevant_txids();
                assert_eq!(relevant_txids.len(), 0);
 
-               handle_announce_close_broadcast_events(&nodes, 0, 1, true, "Channel closed because of an exception: Funding transaction was un-confirmed. Locked at 6 confs, now have 0 confs.");
-               check_added_monitors!(nodes[1], 1);
                {
                        let per_peer_state = nodes[0].node.per_peer_state.read().unwrap();
                        let peer_state = per_peer_state.get(&nodes[1].node.get_our_node_id()).unwrap().lock().unwrap();
@@ -351,7 +347,12 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_
        nodes[0].node.test_process_background_events(); // Required to free the pending background monitor update
        check_added_monitors!(nodes[0], 1);
        let expected_err = "Funding transaction was un-confirmed. Locked at 6 confs, now have 0 confs.";
-       check_closed_event!(nodes[1], 1, ClosureReason::CounterpartyForceClosed { peer_msg: UntrustedString(format!("Channel closed because of an exception: {}", expected_err)) });
+       if reorg_after_reload || !reload_node {
+               handle_announce_close_broadcast_events(&nodes, 0, 1, true, "Channel closed because of an exception: Funding transaction was un-confirmed. Locked at 6 confs, now have 0 confs.");
+               check_added_monitors!(nodes[1], 1);
+               check_closed_event!(nodes[1], 1, ClosureReason::CounterpartyForceClosed { peer_msg: UntrustedString(format!("Channel closed because of an exception: {}", expected_err)) });
+       }
+
        check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: expected_err.to_owned() });
        assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1);
        nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
@@ -361,7 +362,9 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_
                // If we dropped the channel before reloading the node, nodes[1] was also dropped from
                // nodes[0] storage, and hence not connected again on startup. We therefore need to
                // reconnect to the node before attempting to create a new channel.
-               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+               nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &Init {
+                       features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
        }
        create_announced_chan_between_nodes(&nodes, 0, 1);
        send_payment(&nodes[0], &[&nodes[1]], 8000000);
index 1063bf76c2dab6749635168fd5c0dfe766cf1451..d3823fc8f9e1c85c25db75da3eb944dae5a76bf8 100644 (file)
@@ -252,9 +252,13 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) {
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let node_0_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        let node_1_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
 
        nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &node_0_reestablish);
@@ -314,9 +318,13 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) {
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+       }, true).unwrap();
        let node_1_2nd_reestablish = get_chan_reestablish_msgs!(nodes[1], nodes[0]).pop().unwrap();
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), remote_network_address: None }, false).unwrap();
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init {
+               features: nodes[1].node.init_features(), networks: None, remote_network_address: None
+       }, false).unwrap();
        if recv_count == 0 {
                // If all closing_signeds weren't delivered we can just resume where we left off...
                let node_0_2nd_reestablish = get_chan_reestablish_msgs!(nodes[0], nodes[1]).pop().unwrap();
index 1a01e33826dbb9790086afb1063219ea2f42c98c..88e2ad7c1daee03ef245c795f0119eb229a10520 100644 (file)
@@ -96,9 +96,59 @@ pub(crate) enum Message<T> where T: core::fmt::Debug + Type + TestEq {
        Custom(T),
 }
 
-impl<T> Message<T> where T: core::fmt::Debug + Type + TestEq {
+impl<T> Writeable for Message<T> where T: core::fmt::Debug + Type + TestEq {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               match self {
+                       &Message::Init(ref msg) => msg.write(writer),
+                       &Message::Error(ref msg) => msg.write(writer),
+                       &Message::Warning(ref msg) => msg.write(writer),
+                       &Message::Ping(ref msg) => msg.write(writer),
+                       &Message::Pong(ref msg) => msg.write(writer),
+                       &Message::OpenChannel(ref msg) => msg.write(writer),
+                       &Message::OpenChannelV2(ref msg) => msg.write(writer),
+                       &Message::AcceptChannel(ref msg) => msg.write(writer),
+                       &Message::AcceptChannelV2(ref msg) => msg.write(writer),
+                       &Message::FundingCreated(ref msg) => msg.write(writer),
+                       &Message::FundingSigned(ref msg) => msg.write(writer),
+                       &Message::TxAddInput(ref msg) => msg.write(writer),
+                       &Message::TxAddOutput(ref msg) => msg.write(writer),
+                       &Message::TxRemoveInput(ref msg) => msg.write(writer),
+                       &Message::TxRemoveOutput(ref msg) => msg.write(writer),
+                       &Message::TxComplete(ref msg) => msg.write(writer),
+                       &Message::TxSignatures(ref msg) => msg.write(writer),
+                       &Message::TxInitRbf(ref msg) => msg.write(writer),
+                       &Message::TxAckRbf(ref msg) => msg.write(writer),
+                       &Message::TxAbort(ref msg) => msg.write(writer),
+                       &Message::ChannelReady(ref msg) => msg.write(writer),
+                       &Message::Shutdown(ref msg) => msg.write(writer),
+                       &Message::ClosingSigned(ref msg) => msg.write(writer),
+                       &Message::OnionMessage(ref msg) => msg.write(writer),
+                       &Message::UpdateAddHTLC(ref msg) => msg.write(writer),
+                       &Message::UpdateFulfillHTLC(ref msg) => msg.write(writer),
+                       &Message::UpdateFailHTLC(ref msg) => msg.write(writer),
+                       &Message::UpdateFailMalformedHTLC(ref msg) => msg.write(writer),
+                       &Message::CommitmentSigned(ref msg) => msg.write(writer),
+                       &Message::RevokeAndACK(ref msg) => msg.write(writer),
+                       &Message::UpdateFee(ref msg) => msg.write(writer),
+                       &Message::ChannelReestablish(ref msg) => msg.write(writer),
+                       &Message::AnnouncementSignatures(ref msg) => msg.write(writer),
+                       &Message::ChannelAnnouncement(ref msg) => msg.write(writer),
+                       &Message::NodeAnnouncement(ref msg) => msg.write(writer),
+                       &Message::ChannelUpdate(ref msg) => msg.write(writer),
+                       &Message::QueryShortChannelIds(ref msg) => msg.write(writer),
+                       &Message::ReplyShortChannelIdsEnd(ref msg) => msg.write(writer),
+                       &Message::QueryChannelRange(ref msg) => msg.write(writer),
+                       &Message::ReplyChannelRange(ref msg) => msg.write(writer),
+                       &Message::GossipTimestampFilter(ref msg) => msg.write(writer),
+                       &Message::Unknown(_) => { Ok(()) },
+                       &Message::Custom(ref msg) => msg.write(writer),
+               }
+       }
+}
+
+impl<T> Type for Message<T> where T: core::fmt::Debug + Type + TestEq {
        /// Returns the type that was used to decode the message payload.
-       pub fn type_id(&self) -> u16 {
+       fn type_id(&self) -> u16 {
                match self {
                        &Message::Init(ref msg) => msg.type_id(),
                        &Message::Error(ref msg) => msg.type_id(),
@@ -145,7 +195,9 @@ impl<T> Message<T> where T: core::fmt::Debug + Type + TestEq {
                        &Message::Custom(ref msg) => msg.type_id(),
                }
        }
+}
 
+impl<T> Message<T> where T: core::fmt::Debug + Type + TestEq {
        /// Returns whether the message's type is even, indicating both endpoints must support it.
        pub fn is_even(&self) -> bool {
                (self.type_id() & 1) == 0
index 98fcdb680ee03abd1f2c8f3730c0b740bb75977f..96e0c44b2ce8f31f77d1c5fcd936998b229be1eb 100644 (file)
@@ -110,7 +110,7 @@ fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
                let i = idx as usize;
                let mut features = InitFeatures::empty();
                features.set_onion_messages_optional();
-               let init_msg = msgs::Init { features, remote_network_address: None };
+               let init_msg = msgs::Init { features, networks: None, remote_network_address: None };
                nodes[i].messenger.peer_connected(&nodes[i + 1].get_node_pk(), &init_msg.clone(), true).unwrap();
                nodes[i + 1].messenger.peer_connected(&nodes[i].get_node_pk(), &init_msg.clone(), false).unwrap();
        }
index 14bf81baea8b752bc57b69688faf4dc2e95810da..40969b180af9d6904d79eb29d8cdf05b3c624bc9 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;
@@ -366,6 +366,11 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
                        },
                }
        }
+
+       /// Gets the genesis hash for this network graph.
+       pub fn get_genesis_hash(&self) -> BlockHash {
+               self.genesis_hash
+       }
 }
 
 macro_rules! secp_verify_sig {
@@ -1333,9 +1338,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)
        }
 }
 
@@ -2891,7 +2901,7 @@ pub(crate) mod tests {
 
                // It should ignore if gossip_queries feature is not enabled
                {
-                       let init_msg = Init { features: InitFeatures::empty(), remote_network_address: None };
+                       let init_msg = Init { features: InitFeatures::empty(), networks: None, remote_network_address: None };
                        gossip_sync.peer_connected(&node_id_1, &init_msg, true).unwrap();
                        let events = gossip_sync.get_and_clear_pending_msg_events();
                        assert_eq!(events.len(), 0);
@@ -2901,7 +2911,7 @@ pub(crate) mod tests {
                {
                        let mut features = InitFeatures::empty();
                        features.set_gossip_queries_optional();
-                       let init_msg = Init { features, remote_network_address: None };
+                       let init_msg = Init { features, networks: None, remote_network_address: None };
                        gossip_sync.peer_connected(&node_id_1, &init_msg, true).unwrap();
                        let events = gossip_sync.get_and_clear_pending_msg_events();
                        assert_eq!(events.len(), 1);
@@ -3394,31 +3404,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 9defe38aa7e115bd99515968a167c85a3c1c8c32..e9c2988d4a7d4faecbc0451291c34d33ae8ef6c0 100644 (file)
@@ -1021,7 +1021,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
@@ -1042,7 +1042,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()
@@ -1594,14 +1594,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).
@@ -1672,13 +1672,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 = Some(value_contribution_msat);
                                                        } 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
@@ -5823,44 +5823,26 @@ 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, 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 = ProbabilisticScoringFeeParameters::default();
-                               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
-                               if get_route(src, &payment_params, &graph.read_only(), None, amt, &logger, &scorer, &params, &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]
@@ -5868,37 +5850,41 @@ mod tests {
        fn generate_routes_mpp() {
                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 = ProbabilisticScoringFeeParameters::default();
-                               let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
-                               if get_route(src, &payment_params, &graph.read_only(), None, amt, &logger, &scorer, &params, &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]
@@ -6205,9 +6191,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
@@ -6221,7 +6221,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");
@@ -6230,42 +6241,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, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
-       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 {
@@ -6283,11 +6270,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,
@@ -6304,100 +6291,167 @@ mod benches {
                }
        }
 
-       #[bench]
-       fn generate_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
-               let logger = DummyLogger {};
-               let network_graph = read_network_graph(&logger);
+       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();
+
+               let nodes = graph.read_only().nodes().clone();
+               let mut route_endpoints = Vec::new();
+               // 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 = 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 = 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;
+                                       }
+
+                                       route_endpoints.push((first_hop, params, amt));
+                                       break;
+                               }
+                       }
+               }
+
+               // 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,
+                               &TestLogger::new(), &scorer, score_params, &random_seed_bytes).is_ok()
+               });
+               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());
+               generate_routes(bench, &network_graph, scorer, &(), InvoiceFeatures::empty(), 0,
+                       "generate_routes_with_zero_penalty_scorer");
        }
 
-       #[bench]
-       fn generate_mpp_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
-               let logger = DummyLogger {};
-               let network_graph = read_network_graph(&logger);
+       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()));
+               generate_routes(bench, &network_graph, scorer, &(),
+                       channelmanager::provided_invoice_features(&UserConfig::default()), 0,
+                       "generate_mpp_routes_with_zero_penalty_scorer");
        }
 
-       #[bench]
-       fn generate_routes_with_probabilistic_scorer(bench: &mut Bencher) {
-               let logger = DummyLogger {};
-               let network_graph = read_network_graph(&logger);
+       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());
+               generate_routes(bench, &network_graph, scorer, &params, InvoiceFeatures::empty(), 0,
+                       "generate_routes_with_probabilistic_scorer");
        }
 
-       #[bench]
-       fn generate_mpp_routes_with_probabilistic_scorer(bench: &mut Bencher) {
-               let logger = DummyLogger {};
-               let network_graph = read_network_graph(&logger);
+       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()));
+               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 Bencher, graph: &NetworkGraph<&DummyLogger>, mut scorer: S, score_params: &S::ScoreParams,
-               features: InvoiceFeatures
+               bench: &mut Criterion, graph: &NetworkGraph<&TestLogger>, mut scorer: S,
+               score_params: &S::ScoreParams, features: InvoiceFeatures, starting_amount: u64,
+               bench_name: &'static str,
        ) {
-               let nodes = graph.read_only().nodes().clone();
-               let payer = payer_pubkey();
+               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 mut routes = Vec::new();
-               let mut route_endpoints = Vec::new();
-               let mut seed: usize = 0xdeadbeef;
-               'load_endpoints: for _ in 0..150 {
-                       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();
-                               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, score_params, &random_seed_bytes) {
-                                       routes.push(route);
-                                       route_endpoints.push((first_hop, params, amt));
-                                       continue 'load_endpoints;
-                               }
-                       }
-               }
-
-               // ...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);
-                               }
-                       }
-               }
-
-               // Because we've changed channel scores, its 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, score_params, &random_seed_bytes).is_ok()
-               });
-               route_endpoints.truncate(100);
-               assert_eq!(route_endpoints.len(), 100);
+               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, score_params, &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 cd898f12b32e41ca7523f79843f4a1ceff3407be..da24510866e775742e9721cf0f68bdc0bd6774c2 100644 (file)
@@ -689,6 +689,7 @@ pub trait SignerProvider {
 ///
 /// This implementation performs no policy checks and is insufficient by itself as
 /// a secure external signer.
+#[derive(Debug)]
 pub struct InMemorySigner {
        /// Holder secret key in the 2-of-2 multisig script of a channel. This key also backs the
        /// holder's anchor output in a commitment transaction, if one is present.
@@ -718,6 +719,21 @@ pub struct InMemorySigner {
        rand_bytes_index: AtomicCounter,
 }
 
+impl PartialEq for InMemorySigner {
+       fn eq(&self, other: &Self) -> bool {
+               self.funding_key == other.funding_key &&
+                       self.revocation_base_key == other.revocation_base_key &&
+                       self.payment_key == other.payment_key &&
+                       self.delayed_payment_base_key == other.delayed_payment_base_key &&
+                       self.htlc_base_key == other.htlc_base_key &&
+                       self.commitment_seed == other.commitment_seed &&
+                       self.holder_channel_pubkeys == other.holder_channel_pubkeys &&
+                       self.channel_parameters == other.channel_parameters &&
+                       self.channel_value_satoshis == other.channel_value_satoshis &&
+                       self.channel_keys_id == other.channel_keys_id
+       }
+}
+
 impl Clone for InMemorySigner {
        fn clone(&self) -> Self {
                Self {
@@ -1628,8 +1644,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;
@@ -1638,10 +1654,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()));
@@ -1667,11 +1682,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(());
@@ -1680,5 +1692,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 08d54a939be66ecccb83d30c0569d25f31a523e1..27cfb9b8f782c4bafabecd5180a5d0d2256105c3 100644 (file)
@@ -49,7 +49,7 @@ impl<T> Mutex<T> {
 impl<'a, T: 'a> LockTestExt<'a> for Mutex<T> {
        #[inline]
        fn held_by_thread(&self) -> LockHeldState {
-               if self.lock().is_err() { return LockHeldState::HeldByThread; }
+               if self.inner.try_borrow_mut().is_err() { return LockHeldState::HeldByThread; }
                else { return LockHeldState::NotHeldByThread; }
        }
        type ExclLock = MutexGuard<'a, T>;
@@ -115,7 +115,7 @@ impl<T> RwLock<T> {
 impl<'a, T: 'a> LockTestExt<'a> for RwLock<T> {
        #[inline]
        fn held_by_thread(&self) -> LockHeldState {
-               if self.write().is_err() { return LockHeldState::HeldByThread; }
+               if self.inner.try_borrow_mut().is_err() { return LockHeldState::HeldByThread; }
                else { return LockHeldState::NotHeldByThread; }
        }
        type ExclLock = RwLockWriteGuard<'a, T>;
index 81cc1f496c36472d407964fc3a47ef07511fd239..d2e01411313d3c18c6dc7720c7cf68b0d0866e6a 100644 (file)
@@ -5,6 +5,7 @@ compile_error!("We need at least 32-bit pointers for atomic counter (and to have
 
 use core::sync::atomic::{AtomicUsize, Ordering};
 
+#[derive(Debug)]
 pub(crate) struct AtomicCounter {
        // Usize needs to be at least 32 bits to avoid overflowing both low and high. If usize is 64
        // bits we will never realistically count into high:
index 1e678152cccd9d3cfa4bdcc1d40dd441b739913e..758306c002d1a031199b0ca38b43a5decddca4ac 100644 (file)
@@ -399,6 +399,27 @@ pub struct ChannelConfig {
        pub force_close_avoidance_max_fee_satoshis: u64,
 }
 
+impl ChannelConfig {
+       /// Applies the given [`ChannelConfigUpdate`] as a partial update to the [`ChannelConfig`].
+       pub fn apply(&mut self, update: &ChannelConfigUpdate) {
+               if let Some(forwarding_fee_proportional_millionths) = update.forwarding_fee_proportional_millionths {
+                       self.forwarding_fee_proportional_millionths = forwarding_fee_proportional_millionths;
+               }
+               if let Some(forwarding_fee_base_msat) = update.forwarding_fee_base_msat {
+                       self.forwarding_fee_base_msat = forwarding_fee_base_msat;
+               }
+               if let Some(cltv_expiry_delta) = update.cltv_expiry_delta {
+                       self.cltv_expiry_delta = cltv_expiry_delta;
+               }
+               if let Some(max_dust_htlc_exposure_msat) = update.max_dust_htlc_exposure_msat {
+                       self.max_dust_htlc_exposure_msat = max_dust_htlc_exposure_msat;
+               }
+               if let Some(force_close_avoidance_max_fee_satoshis) = update.force_close_avoidance_max_fee_satoshis {
+                       self.force_close_avoidance_max_fee_satoshis = force_close_avoidance_max_fee_satoshis;
+               }
+       }
+}
+
 impl Default for ChannelConfig {
        /// Provides sane defaults for most configurations (but with zero relay fees!).
        fn default() -> Self {
@@ -423,6 +444,40 @@ impl_writeable_tlv_based!(ChannelConfig, {
        (10, force_close_avoidance_max_fee_satoshis, required),
 });
 
+/// A parallel struct to [`ChannelConfig`] to define partial updates.
+#[allow(missing_docs)]
+pub struct ChannelConfigUpdate {
+       pub forwarding_fee_proportional_millionths: Option<u32>,
+       pub forwarding_fee_base_msat: Option<u32>,
+       pub cltv_expiry_delta: Option<u16>,
+       pub max_dust_htlc_exposure_msat: Option<u64>,
+       pub force_close_avoidance_max_fee_satoshis: Option<u64>,
+}
+
+impl Default for ChannelConfigUpdate {
+       fn default() -> ChannelConfigUpdate {
+               ChannelConfigUpdate {
+                       forwarding_fee_proportional_millionths: None,
+                       forwarding_fee_base_msat: None,
+                       cltv_expiry_delta: None,
+                       max_dust_htlc_exposure_msat: None,
+                       force_close_avoidance_max_fee_satoshis: None,
+               }
+       }
+}
+
+impl From<ChannelConfig> for ChannelConfigUpdate {
+       fn from(config: ChannelConfig) -> ChannelConfigUpdate {
+               ChannelConfigUpdate {
+                       forwarding_fee_proportional_millionths: Some(config.forwarding_fee_proportional_millionths),
+                       forwarding_fee_base_msat: Some(config.forwarding_fee_base_msat),
+                       cltv_expiry_delta: Some(config.cltv_expiry_delta),
+                       max_dust_htlc_exposure_msat: Some(config.max_dust_htlc_exposure_msat),
+                       force_close_avoidance_max_fee_satoshis: Some(config.force_close_avoidance_max_fee_satoshis),
+               }
+       }
+}
+
 /// Legacy version of [`ChannelConfig`] that stored the static
 /// [`ChannelHandshakeConfig::announced_channel`] and
 /// [`ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`] fields.
index e51bbb9271983986650ac31fef823473ee498f0a..fe61e9c7214e25a8ad901f5242aea701e03950fe 100644 (file)
@@ -32,6 +32,7 @@ use crate::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
 use crate::util::logger::{Logger, Level, Record};
 use crate::util::ser::{Readable, ReadableArgs, Writer, Writeable};
 
+use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::blockdata::transaction::{Transaction, TxOut};
 use bitcoin::blockdata::script::{Builder, Script};
@@ -341,17 +342,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);
        }
 }
 
@@ -359,14 +363,18 @@ pub struct TestChannelMessageHandler {
        pub pending_events: Mutex<Vec<events::MessageSendEvent>>,
        expected_recv_msgs: Mutex<Option<Vec<wire::Message<()>>>>,
        connected_peers: Mutex<HashSet<PublicKey>>,
+       pub message_fetch_counter: AtomicUsize,
+       genesis_hash: ChainHash,
 }
 
 impl TestChannelMessageHandler {
-       pub fn new() -> Self {
+       pub fn new(genesis_hash: ChainHash) -> Self {
                TestChannelMessageHandler {
                        pending_events: Mutex::new(Vec::new()),
                        expected_recv_msgs: Mutex::new(None),
                        connected_peers: Mutex::new(HashSet::new()),
+                       message_fetch_counter: AtomicUsize::new(0),
+                       genesis_hash,
                }
        }
 
@@ -470,6 +478,10 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
                channelmanager::provided_init_features(&UserConfig::default())
        }
 
+       fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
+               Some(vec![self.genesis_hash])
+       }
+
        fn handle_open_channel_v2(&self, _their_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
                self.received_msg(wire::Message::OpenChannelV2(msg.clone()));
        }
@@ -517,6 +529,7 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
 
 impl events::MessageSendEventsProvider for TestChannelMessageHandler {
        fn get_and_clear_pending_msg_events(&self) -> Vec<events::MessageSendEvent> {
+               self.message_fetch_counter.fetch_add(1, Ordering::AcqRel);
                let mut pending_events = self.pending_events.lock().unwrap();
                let mut ret = Vec::new();
                mem::swap(&mut ret, &mut *pending_events);
@@ -738,7 +751,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);
                }
        }