Merge pull request #1518 from valentinewallace/2022-06-OMs-prefactor
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Tue, 21 Jun 2022 23:13:37 +0000 (16:13 -0700)
committerGitHub <noreply@github.com>
Tue, 21 Jun 2022 23:13:37 +0000 (16:13 -0700)
Onion messages v1 pre-refactor

40 files changed:
.github/workflows/build.yml
CHANGELOG.md
README.md
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
fuzz/src/process_network_graph.rs
fuzz/src/router.rs
lightning-background-processor/Cargo.toml
lightning-background-processor/src/lib.rs
lightning-block-sync/Cargo.toml
lightning-invoice/Cargo.toml
lightning-invoice/src/lib.rs
lightning-invoice/src/utils.rs
lightning-net-tokio/Cargo.toml
lightning-persister/Cargo.toml
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/channelmonitor.rs
lightning/src/chain/keysinterface.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/onion_route_tests.rs
lightning/src/ln/payment_tests.rs
lightning/src/ln/peer_handler.rs
lightning/src/ln/priv_short_conf_tests.rs
lightning/src/ln/reorg_tests.rs
lightning/src/ln/shutdown_tests.rs
lightning/src/routing/gossip.rs
lightning/src/routing/router.rs
lightning/src/routing/scoring.rs
lightning/src/util/config.rs
lightning/src/util/events.rs
lightning/src/util/persist.rs

index 59a11b4e4a11efc7788b51fe04ad664ca15da7f9..68cf376235f7edcb1e812da6027da9e608e97ed2 100644 (file)
@@ -275,6 +275,27 @@ jobs:
       - name: For each commit, run cargo check (including in fuzz)
         run: ci/check-each-commit.sh upstream/main
 
+  check_release:
+    runs-on: ubuntu-latest
+    env:
+      TOOLCHAIN: stable
+    steps:
+      - name: Checkout source code
+        uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
+      - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
+        uses: actions-rs/toolchain@v1
+        with:
+          toolchain: ${{ env.TOOLCHAIN }}
+          override: true
+          profile: minimal
+      - name: Run cargo check for release build.
+        run: |
+          cargo check --release
+          cargo check --no-default-features --features=no-std --release
+          cargo doc --release
+
   fuzz:
     runs-on: ubuntu-latest
     env:
index 84d5529d88be1a885405bc29c469067b95ad7e7d..62b96df13d3b732b7a1d3ebaf6934389dcfb2b17 100644 (file)
@@ -1,3 +1,163 @@
+# 0.0.108 - 2022-06-10
+
+## Bug Fixes
+ * Fixed `lightning-background-processor` build in release mode.
+
+In total, this release features 9 files changed, 120 insertions, 74
+deletions in 5 commits from 4 authors, in alphabetical order:
+ * Elias Rohrer
+ * Matt Corallo
+ * Max Fang
+ * Viktor Tigerström
+
+# 0.0.107 - 2022-06-08
+
+## API Updates
+ * Channels larger than 16777215 sats (Wumbo!) are now supported and can be
+   enabled for inbound channels using
+   `ChannelHandshakeLimits::max_funding_satoshis` (#1425).
+ * Support for feature `option_zeroconf`, allowing immediate forwarding of
+   payments after channel opening. This is configured for outbound channels
+   using `ChannelHandshakeLimits::trust_own_funding_0conf` whereas
+   `ChannelManager::accept_inbound_channel_from_trusted_peer_0conf` has to be
+   used for accepting inbound channels (#1401, #1505).
+ * `ChannelManager::claim_funds` no longer returns a `bool` to indicate success.
+   Instead, an `Event::PaymentClaimed` is generated if the claim was successful.
+   Likewise, `ChannelManager::fail_htlc_backwards` no longer has a return value
+   (#1434).
+ * `lightning-rapid-gossip-sync` is a new crate for syncing gossip data from a
+   server, primarily aimed at mobile devices (#1155).
+ * `RapidGossipSync` can be passed to `BackgroundProcessor` in order to persist
+   the `NetworkGraph` and handle `NetworkUpdate`s during event handling (#1433,
+   #1517).
+ * `NetGraphMsgHandler` has been renamed to `P2PGossipSync`, the `network_graph`
+    module has been renamed to `gossip`, and `NetworkUpdate::ChannelClosed` has
+   been renamed `NetworkUpdate::ChannelFailure` (#1159).
+ * Added a `filtered_block_connected` method to `chain::Listen` and a default
+   implementation of `block_connected` for those fetching filtered instead of
+   full blocks (#1453).
+ * The `lightning-block-sync` crate's `BlockSource` trait methods now take
+   `&self` instead of `&mut self` (#1307).
+ * `inbound_payment` module is now public to allow for creating invoices without
+   a `ChannelManager` (#1384).
+ * `lightning-block-sync`'s `init` and `poll` modules support `&dyn BlockSource`
+   which can be determined at runtime (#1423).
+ * `lightning-invoice` crate's `utils` now accept an expiration time (#1422,
+   #1474).
+ * `Event::PaymentForwarded` includes `prev_channel_id` and `next_channel_id`
+   (#1419, #1475).
+ * `chain::Watch::release_pending_monitor_events`' return type now associates
+   `MonitorEvent`s with funding `OutPoints` (#1475).
+ * `lightning-background-processor` crate's `Persister` trait has been moved to
+   `lightning` crate's `util::persist` module, which now has a general
+   `KVStorePersister` trait. Blanket implementations of `Persister` and
+   `chainmonitor::Persist` are given for types implementing `KVStorePersister`.
+   ` lightning-persister`'s `FilesystemPersister` implements `KVStorePersister`
+   (#1417).
+ * `ChannelDetails` and `ChannelCounterparty` include fields for HTLC minimum
+   and maximum values (#1378).
+ * Added a `max_inbound_htlc_value_in_flight_percent_of_channel` field to
+   `ChannelHandshakeConfig`, capping the total value of outstanding inbound
+   HTLCs for a channel (#1444).
+ * `ProbabilisticScorer` is parameterized by a `Logger`, which it uses to log
+   channel liquidity updates or lack thereof (#1405).
+ * `ChannelDetails` has an `outbound_htlc_limit_msat` field, which should be
+   used in routing instead of `outbound_capacity_msat` (#1435).
+ * `ProbabilisticScorer`'s channel liquidities can be logged via
+   `debug_log_liquidity_stats` (#1460).
+ * `BackgroundProcessor` now takes an optional `WriteableScore` which it will
+   persist using the `Persister` trait's new `persist_scorer` method (#1416).
+ * Upgraded to `bitcoin` crate version 0.28.1 (#1389).
+ * `ShutdownScript::new_witness_program` now takes a `WitnessVersion` instead of
+   a `NonZeroU8` (#1389).
+ * Channels will no longer be automatically force closed when the counterparty
+   is disconnected due to incompatibility (#1429).
+ * `ChannelManager` methods for funding, accepting, and closing channels now
+   take a `counterparty_node_id` parameter, which has also been added as a field
+   to `Event::FundingGenerationReady` (#1479, #1485).
+ * `InvoicePayer::new` now takes a `Retry` enum (replacing the `RetryAttempts`
+   struct), which supports both attempt- and timeout-based retrying (#1418).
+ * `Score::channel_penalty_msat` takes a `ChannelUsage` struct, which contains
+   the capacity as an `EffectiveCapacity` enum and any potential in-flight HTLC
+   value, rather than a single `u64`. Used by `ProbabilisticScorer` for more
+   accurate penalties (#1456).
+ * `build_route_from_hops` is a new function useful for constructing a `Route`
+   given a specific list of public keys (#1491).
+ * `FundingLocked` message has been renamed `ChannelReady`, and related
+   identifiers have been renamed accordingly (#1506).
+ * `core2::io` or `std::io` (depending on feature flags `no-std` or `std`) is
+   exported as a `lightning::io` module (#1504).
+ * The deprecated `Scorer` has been removed in favor or `ProbabilisticScorer`
+   (#1512).
+
+## Performance Improvements
+ * `lightning-persister` crate's `FilesystemPersister` is faster by 15x (#1404).
+ * Log gossip query messages at `GOSSIP` instead of `TRACE` to avoid
+   overwhelming default logging (#1421).
+ * `PeerManager` supports processing messages from different peers in parallel,
+   and this is taken advantage of in gossip processing (#1023).
+ * Greatly reduced per-channel and per-node memory usage due to upgrade of
+   `secp256k1` crate to 0.22.1 and `bitcoin` crate to 0.28.1
+ * Reduced per-peer memory usage in `PeerManager` (#1472).
+
+## Spec Compliance
+ * `find_route` now assumes variable-length onions by default for nodes where
+   support for the feature is unknown (#1414).
+ * A `warn` message is now sent when receiving a `channel_reestablish` with an
+   old commitment transaction number rather than immediately force-closing the
+   channel (#1430).
+ * When a `channel_update` message is included in an onion error's `failuremsg`,
+   its message type is now encoded. Reading such messages is also supported
+   (#1465).
+
+## Bug Fixes
+ * Fixed a bug where crashing while persisting a `ChannelMonitorUpdate` for a
+   part of a multi-path payment could cause loss of funds due to a partial
+   payment claim on restart (#1434).
+ * `BackgroundProcessor` has been fixed to improve serialization reliability on
+   slow systems which can avoid force-closes (#1436).
+ * `gossip_timestamp_filter` filters are now honored when sending gossip to
+   peers (#1452).
+ * During a reorg, only force-close a channel if its funding transaction is
+   unconfirmed rather than as it loses confirmations (#1461).
+ * Fixed a rare panic in `lightning-net-tokio` when fetching a peer's socket
+   address after the connection has been closed caused by a race condition
+   (#1449).
+ * `find_route` will no longer return routes that would cause onion construction
+   to fail in some cases (#1476).
+ * `ProbabilisticScorer` uses more precision when approximating `log10` (#1406).
+
+## Serialization Compatibility
+ * All above new events/fields are ignored by prior clients. All above new
+   events/fields are not present when reading objects serialized by prior
+   versions of the library.
+ * `ChannelManager` serialization is no longer compatible with versions prior to
+   0.0.99 (#1401).
+ * Channels with `option_zeroconf` feature enabled (not required for 0-conf
+   channel use) will be unreadable by versions prior to 0.0.107 (#1401, #1505).
+
+In total, this release features 96 files changed, 9304 insertions, 4503
+deletions in 153 commits from 18 authors, in alphabetical order:
+ * Arik Sosman
+ * Devrandom
+ * Duncan Dean
+ * Elias Rohrer
+ * Jeffrey Czyz
+ * John Cantrell
+ * John Corser
+ * Jurvis Tan
+ * Justin Moon
+ * KaFai Choi
+ * Mateusz Faltyn
+ * Matt Corallo
+ * Valentine Wallace
+ * Viktor Tigerström
+ * Vincenzo Palazzo
+ * atalw
+ * dependabot[bot]
+ * shamardy
+
+
 # 0.0.106 - 2022-04-03
 
 ## API Updates
index dad0b39241576094ed5fe45d601d000bd0c3516d..3c34335c244af9d04734f2be010d424b06c498fd 100644 (file)
--- a/README.md
+++ b/README.md
@@ -50,6 +50,8 @@ Crates
   this is a simple alternative to implementing the required network stack, especially for those already using Tokio.
 6. [lightning-persister](./lightning-persister)
   Utilities to manage Rust-Lightning channel data persistence and retrieval.
+7. [lightning-rapid-gossip-sync](./lightning-rapid-gossip-sync)
+  Client for rapid gossip graph syncing, aimed primarily at mobile clients.
 
 About
 -----------
index 9625677c263378f3a9eed66be03e78989def25d4..615f3aad995ce054d9b073923bf31e23725b7bef 100644 (file)
@@ -356,8 +356,8 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
                                Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(&keys_manager)));
 
                        let mut config = UserConfig::default();
-                       config.channel_options.forwarding_fee_proportional_millionths = 0;
-                       config.channel_options.announced_channel = true;
+                       config.channel_config.forwarding_fee_proportional_millionths = 0;
+                       config.channel_handshake_config.announced_channel = true;
                        let network = Network::Bitcoin;
                        let params = ChainParameters {
                                network,
@@ -376,8 +376,8 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
                                Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(& $keys_manager)));
 
                        let mut config = UserConfig::default();
-                       config.channel_options.forwarding_fee_proportional_millionths = 0;
-                       config.channel_options.announced_channel = true;
+                       config.channel_config.forwarding_fee_proportional_millionths = 0;
+                       config.channel_handshake_config.announced_channel = true;
 
                        let mut monitors = HashMap::new();
                        let mut old_monitors = $old_monitors.latest_monitors.lock().unwrap();
index a59d78e1c54cc35507b2ec4d0f3a66fb0753a01a..fae14de57f18ec73fffc1613427f05503b6eeba8 100644 (file)
@@ -163,7 +163,7 @@ type ChannelMan = ChannelManager<
        EnforcingSigner,
        Arc<chainmonitor::ChainMonitor<EnforcingSigner, Arc<dyn chain::Filter>, Arc<TestBroadcaster>, Arc<FuzzEstimator>, Arc<dyn Logger>, Arc<TestPersister>>>,
        Arc<TestBroadcaster>, Arc<KeyProvider>, Arc<FuzzEstimator>, Arc<dyn Logger>>;
-type PeerMan<'a> = PeerManager<Peer<'a>, Arc<ChannelMan>, Arc<P2PGossipSync<Arc<NetworkGraph>, Arc<dyn chain::Access>, Arc<dyn Logger>>>, Arc<dyn Logger>, IgnoringMessageHandler>;
+type PeerMan<'a> = PeerManager<Peer<'a>, Arc<ChannelMan>, Arc<P2PGossipSync<Arc<NetworkGraph<Arc<dyn Logger>>>, Arc<dyn chain::Access>, Arc<dyn Logger>>>, Arc<dyn Logger>, IgnoringMessageHandler>;
 
 struct MoneyLossDetector<'a> {
        manager: Arc<ChannelMan>,
@@ -382,8 +382,8 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
 
        let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone(), inbound_payment_key: KeyMaterial(inbound_payment_key.try_into().unwrap()), counter: AtomicU64::new(0) });
        let mut config = UserConfig::default();
-       config.channel_options.forwarding_fee_proportional_millionths =  slice_to_be32(get_slice!(4));
-       config.channel_options.announced_channel = get_slice!(1)[0] != 0;
+       config.channel_config.forwarding_fee_proportional_millionths =  slice_to_be32(get_slice!(4));
+       config.channel_handshake_config.announced_channel = get_slice!(1)[0] != 0;
        let network = Network::Bitcoin;
        let params = ChainParameters {
                network,
@@ -395,7 +395,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
        // it's easier to just increment the counter here so the keys don't change.
        keys_manager.counter.fetch_sub(1, Ordering::AcqRel);
        let our_id = PublicKey::from_secret_key(&Secp256k1::signing_only(), &keys_manager.get_node_secret(Recipient::Node).unwrap());
-       let network_graph = Arc::new(NetworkGraph::new(genesis_block(network).block_hash()));
+       let network_graph = Arc::new(NetworkGraph::new(genesis_block(network).block_hash(), Arc::clone(&logger)));
        let gossip_sync = Arc::new(P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger)));
        let scorer = FixedPenaltyScorer::with_penalty(0);
 
@@ -460,7 +460,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
                                        final_cltv_expiry_delta: 42,
                                };
                                let random_seed_bytes: [u8; 32] = keys_manager.get_secure_random_bytes();
-                               let route = match find_route(&our_id, &params, &network_graph, None, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                               let route = match find_route(&our_id, &params, &network_graph.read_only(), None, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                        Ok(route) => route,
                                        Err(_) => return,
                                };
@@ -484,7 +484,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
                                        final_cltv_expiry_delta: 42,
                                };
                                let random_seed_bytes: [u8; 32] = keys_manager.get_secure_random_bytes();
-                               let mut route = match find_route(&our_id, &params, &network_graph, None, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                               let mut route = match find_route(&our_id, &params, &network_graph.read_only(), None, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                        Ok(route) => route,
                                        Err(_) => return,
                                };
index 118862569d039b47ea967c79207c463bbbe837f6..8b6462e81e48c95ab30d3db7409b3c63a18be28a 100644 (file)
@@ -1,22 +1,27 @@
 // Imports that need to be added manually
+use lightning::util::logger::Logger;
 use lightning_rapid_gossip_sync::RapidGossipSync;
+
 use utils::test_logger;
 
+use std::sync::Arc;
+
 /// Actual fuzz test, method signature and name are fixed
-fn do_test(data: &[u8]) {
+fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
        let block_hash = bitcoin::BlockHash::default();
-       let network_graph = lightning::routing::gossip::NetworkGraph::new(block_hash);
+       let logger = test_logger::TestLogger::new("".to_owned(), out);
+       let network_graph = lightning::routing::gossip::NetworkGraph::new(block_hash, &logger);
        let rapid_sync = RapidGossipSync::new(&network_graph);
        let _ = rapid_sync.update_network_graph(data);
 }
 
 /// Method that needs to be added manually, {name}_test
-pub fn process_network_graph_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
-       do_test(data);
+pub fn process_network_graph_test<Out: test_logger::Output>(data: &[u8], out: Out) {
+       do_test(data, out);
 }
 
 /// Method that needs to be added manually, {name}_run
 #[no_mangle]
 pub extern "C" fn process_network_graph_run(data: *const u8, datalen: usize) {
-       do_test(unsafe { std::slice::from_raw_parts(data, datalen) });
+       do_test(unsafe { std::slice::from_raw_parts(data, datalen) }, test_logger::DevNull {});
 }
index ec12ff7e144e4708670ccc3aea79cd91d1201247..cccc7c4f5a7f6cd21eeac3d10560f3d8f2fae298 100644 (file)
@@ -159,10 +159,10 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                }
        }
 
-       let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new("".to_owned(), out));
+       let logger = test_logger::TestLogger::new("".to_owned(), out);
 
        let our_pubkey = get_pubkey!();
-       let net_graph = NetworkGraph::new(genesis_block(Network::Bitcoin).header.block_hash());
+       let net_graph = NetworkGraph::new(genesis_block(Network::Bitcoin).header.block_hash(), &logger);
 
        let mut node_pks = HashSet::new();
        let mut scid = 42;
@@ -235,6 +235,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                                next_outbound_htlc_limit_msat: capacity.saturating_mul(1000),
                                                                inbound_htlc_minimum_msat: None,
                                                                inbound_htlc_maximum_msat: None,
+                                                               config: None,
                                                        });
                                                }
                                                Some(&first_hops_vec[..])
@@ -267,9 +268,9 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                final_value_msat: slice_to_be64(get_slice!(8)),
                                                final_cltv_expiry_delta: slice_to_be32(get_slice!(4)),
                                        };
-                                       let _ = find_route(&our_pubkey, &route_params, &net_graph,
+                                       let _ = find_route(&our_pubkey, &route_params, &net_graph.read_only(),
                                                first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),
-                                               Arc::clone(&logger), &scorer, &random_seed_bytes);
+                                               &logger, &scorer, &random_seed_bytes);
                                }
                        },
                }
index 5558eaaa67c43f49248fba1a4838c6a6143bdf41..4833822f89efb1398b5cc62b30497f1dafe98a83 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-background-processor"
-version = "0.0.106"
+version = "0.0.108"
 authors = ["Valentine Wallace <vwallace@protonmail.com>"]
 license = "MIT OR Apache-2.0"
 repository = "http://github.com/lightningdevkit/rust-lightning"
@@ -15,10 +15,10 @@ rustdoc-args = ["--cfg", "docsrs"]
 
 [dependencies]
 bitcoin = "0.28.1"
-lightning = { version = "0.0.106", path = "../lightning", features = ["std"] }
-lightning-rapid-gossip-sync = { version = "0.0.106", path = "../lightning-rapid-gossip-sync" }
+lightning = { version = "0.0.108", path = "../lightning", features = ["std"] }
+lightning-rapid-gossip-sync = { version = "0.0.108", path = "../lightning-rapid-gossip-sync" }
 
 [dev-dependencies]
-lightning = { version = "0.0.106", path = "../lightning", features = ["_test_utils"] }
-lightning-invoice = { version = "0.14.0", path = "../lightning-invoice" }
-lightning-persister = { version = "0.0.106", path = "../lightning-persister" }
+lightning = { version = "0.0.108", path = "../lightning", features = ["_test_utils"] }
+lightning-invoice = { version = "0.16.0", path = "../lightning-invoice" }
+lightning-persister = { version = "0.0.108", path = "../lightning-persister" }
index 2e947a7041afdd92c4c8ac86c053c6781de24f26..10ae69e2fe1791b1edf428dfe47181e40633d800 100644 (file)
@@ -40,8 +40,8 @@ use std::ops::Deref;
 ///   [`ChannelManager`] persistence should be done in the background.
 /// * Calling [`ChannelManager::timer_tick_occurred`] and [`PeerManager::timer_tick_occurred`]
 ///   at the appropriate intervals.
-/// * Calling [`NetworkGraph::remove_stale_channels`] (if a [`P2PGossipSync`] is provided to
-///   [`BackgroundProcessor::start`]).
+/// * Calling [`NetworkGraph::remove_stale_channels`] (if a [`GossipSync`] with a [`NetworkGraph`]
+///   is provided to [`BackgroundProcessor::start`]).
 ///
 /// It will also call [`PeerManager::process_events`] periodically though this shouldn't be relied
 /// upon as doing so may result in high latency.
@@ -79,7 +79,7 @@ const PING_TIMER: u64 = 1;
 /// Prune the network graph of stale entries hourly.
 const NETWORK_PRUNE_TIMER: u64 = 60 * 60;
 
-#[cfg(all(not(test), debug_assertions))]
+#[cfg(not(test))]
 const SCORER_PERSIST_TIMER: u64 = 30;
 #[cfg(test)]
 const SCORER_PERSIST_TIMER: u64 = 1;
@@ -89,31 +89,82 @@ const FIRST_NETWORK_PRUNE_TIMER: u64 = 60;
 #[cfg(test)]
 const FIRST_NETWORK_PRUNE_TIMER: u64 = 1;
 
+/// Either [`P2PGossipSync`] or [`RapidGossipSync`].
+pub enum GossipSync<
+       P: Deref<Target = P2PGossipSync<G, A, L>>,
+       R: Deref<Target = RapidGossipSync<G, L>>,
+       G: Deref<Target = NetworkGraph<L>>,
+       A: Deref,
+       L: Deref,
+>
+where A::Target: chain::Access, L::Target: Logger {
+       /// Gossip sync via the lightning peer-to-peer network as defined by BOLT 7.
+       P2P(P),
+       /// Rapid gossip sync from a trusted server.
+       Rapid(R),
+       /// No gossip sync.
+       None,
+}
+
+impl<
+       P: Deref<Target = P2PGossipSync<G, A, L>>,
+       R: Deref<Target = RapidGossipSync<G, L>>,
+       G: Deref<Target = NetworkGraph<L>>,
+       A: Deref,
+       L: Deref,
+> GossipSync<P, R, G, A, L>
+where A::Target: chain::Access, L::Target: Logger {
+       fn network_graph(&self) -> Option<&G> {
+               match self {
+                       GossipSync::P2P(gossip_sync) => Some(gossip_sync.network_graph()),
+                       GossipSync::Rapid(gossip_sync) => Some(gossip_sync.network_graph()),
+                       GossipSync::None => None,
+               }
+       }
+
+       fn prunable_network_graph(&self) -> Option<&G> {
+               match self {
+                       GossipSync::P2P(gossip_sync) => Some(gossip_sync.network_graph()),
+                       GossipSync::Rapid(gossip_sync) => {
+                               if gossip_sync.is_initial_sync_complete() {
+                                       Some(gossip_sync.network_graph())
+                               } else {
+                                       None
+                               }
+                       },
+                       GossipSync::None => None,
+               }
+       }
+}
 
 /// Decorates an [`EventHandler`] with common functionality provided by standard [`EventHandler`]s.
 struct DecoratingEventHandler<
+       'a,
        E: EventHandler,
-       P: Deref<Target = P2PGossipSync<G, A, L>>,
-       G: Deref<Target = NetworkGraph>,
+       PGS: Deref<Target = P2PGossipSync<G, A, L>>,
+       RGS: Deref<Target = RapidGossipSync<G, L>>,
+       G: Deref<Target = NetworkGraph<L>>,
        A: Deref,
        L: Deref,
 >
 where A::Target: chain::Access, L::Target: Logger {
        event_handler: E,
-       p2p_gossip_sync: Option<P>,
+       gossip_sync: &'a GossipSync<PGS, RGS, G, A, L>,
 }
 
 impl<
+       'a,
        E: EventHandler,
-       P: Deref<Target = P2PGossipSync<G, A, L>>,
-       G: Deref<Target = NetworkGraph>,
+       PGS: Deref<Target = P2PGossipSync<G, A, L>>,
+       RGS: Deref<Target = RapidGossipSync<G, L>>,
+       G: Deref<Target = NetworkGraph<L>>,
        A: Deref,
        L: Deref,
-> EventHandler for DecoratingEventHandler<E, P, G, A, L>
+> EventHandler for DecoratingEventHandler<'a, E, PGS, RGS, G, A, L>
 where A::Target: chain::Access, L::Target: Logger {
        fn handle_event(&self, event: &Event) {
-               if let Some(event_handler) = &self.p2p_gossip_sync {
-                       event_handler.handle_event(event);
+               if let Some(network_graph) = self.gossip_sync.network_graph() {
+                       network_graph.handle_event(event);
                }
                self.event_handler.handle_event(event);
        }
@@ -134,9 +185,9 @@ impl BackgroundProcessor {
        /// [`ChannelManager`]. See the `lightning-persister` crate for LDK's
        /// provided implementation.
        ///
-       /// [`Persister::persist_graph`] is responsible for writing out the [`NetworkGraph`] to disk. See
-       /// [`NetworkGraph::write`] for writing out a [`NetworkGraph`]. See the `lightning-persister` crate
-       /// for LDK's provided implementation.
+       /// [`Persister::persist_graph`] is responsible for writing out the [`NetworkGraph`] to disk, if
+       /// [`GossipSync`] is supplied. See [`NetworkGraph::write`] for writing out a [`NetworkGraph`].
+       /// See the `lightning-persister` crate for LDK's provided implementation.
        ///
        /// Typically, users should either implement [`Persister::persist_manager`] to never return an
        /// error or call [`join`] and handle any error that may arise. For the latter case,
@@ -151,9 +202,9 @@ impl BackgroundProcessor {
        ///
        /// # Rapid Gossip Sync
        ///
-       /// If rapid gossip sync is meant to run at startup, pass an optional [`RapidGossipSync`]
-       /// to `rapid_gossip_sync` to indicate to [`BackgroundProcessor`] not to prune the
-       /// [`NetworkGraph`] instance until the [`RapidGossipSync`] instance completes its first sync.
+       /// If rapid gossip sync is meant to run at startup, pass [`RapidGossipSync`] via `gossip_sync`
+       /// to indicate that the [`BackgroundProcessor`] should not prune the [`NetworkGraph`] instance
+       /// until the [`RapidGossipSync`] instance completes its first sync.
        ///
        /// [top-level documentation]: BackgroundProcessor
        /// [`join`]: Self::join
@@ -173,7 +224,7 @@ impl BackgroundProcessor {
                T: 'static + Deref + Send + Sync,
                K: 'static + Deref + Send + Sync,
                F: 'static + Deref + Send + Sync,
-               G: 'static + Deref<Target = NetworkGraph> + Send + Sync,
+               G: 'static + Deref<Target = NetworkGraph<L>> + Send + Sync,
                L: 'static + Deref + Send + Sync,
                P: 'static + Deref + Send + Sync,
                Descriptor: 'static + SocketDescriptor + Send + Sync,
@@ -184,15 +235,14 @@ impl BackgroundProcessor {
                M: 'static + Deref<Target = ChainMonitor<Signer, CF, T, F, L, P>> + Send + Sync,
                CM: 'static + Deref<Target = ChannelManager<Signer, CW, T, K, F, L>> + Send + Sync,
                PGS: 'static + Deref<Target = P2PGossipSync<G, CA, L>> + Send + Sync,
+               RGS: 'static + Deref<Target = RapidGossipSync<G, L>> + Send,
                UMH: 'static + Deref + Send + Sync,
                PM: 'static + Deref<Target = PeerManager<Descriptor, CMH, RMH, L, UMH>> + Send + Sync,
                S: 'static + Deref<Target = SC> + Send + Sync,
                SC: WriteableScore<'a>,
-               RGS: 'static + Deref<Target = RapidGossipSync<G>> + Send
        >(
                persister: PS, event_handler: EH, chain_monitor: M, channel_manager: CM,
-               p2p_gossip_sync: Option<PGS>, peer_manager: PM, logger: L, scorer: Option<S>,
-               rapid_gossip_sync: Option<RGS>
+               gossip_sync: GossipSync<PGS, RGS, G, CA, L>, peer_manager: PM, logger: L, scorer: Option<S>,
        ) -> Self
        where
                CA::Target: 'static + chain::Access,
@@ -211,7 +261,10 @@ impl BackgroundProcessor {
                let stop_thread = Arc::new(AtomicBool::new(false));
                let stop_thread_clone = stop_thread.clone();
                let handle = thread::spawn(move || -> Result<(), std::io::Error> {
-                       let event_handler = DecoratingEventHandler { event_handler, p2p_gossip_sync: p2p_gossip_sync.as_ref().map(|t| t.deref()) };
+                       let event_handler = DecoratingEventHandler {
+                               event_handler,
+                               gossip_sync: &gossip_sync,
+                       };
 
                        log_trace!(logger, "Calling ChannelManager's timer_tick_occurred on startup");
                        channel_manager.timer_tick_occurred();
@@ -290,21 +343,10 @@ impl BackgroundProcessor {
                                if last_prune_call.elapsed().as_secs() > if have_pruned { NETWORK_PRUNE_TIMER } else { FIRST_NETWORK_PRUNE_TIMER } {
                                        // The network graph must not be pruned while rapid sync completion is pending
                                        log_trace!(logger, "Assessing prunability of network graph");
-                                       let graph_to_prune = match rapid_gossip_sync.as_ref() {
-                                               Some(rapid_sync) => {
-                                                       if rapid_sync.is_initial_sync_complete() {
-                                                               Some(rapid_sync.network_graph())
-                                                       } else {
-                                                               None
-                                                       }
-                                               },
-                                               None => p2p_gossip_sync.as_ref().map(|sync| sync.network_graph())
-                                       };
-
-                                       if let Some(network_graph_reference) = graph_to_prune {
-                                               network_graph_reference.remove_stale_channels();
+                                       if let Some(network_graph) = gossip_sync.prunable_network_graph() {
+                                               network_graph.remove_stale_channels();
 
-                                               if let Err(e) = persister.persist_graph(network_graph_reference) {
+                                               if let Err(e) = persister.persist_graph(network_graph) {
                                                        log_error!(logger, "Error: Failed to persist network graph, check your disk and permissions {}", e)
                                                }
 
@@ -337,8 +379,8 @@ impl BackgroundProcessor {
                        }
 
                        // Persist NetworkGraph on exit
-                       if let Some(ref gossip_sync) = p2p_gossip_sync {
-                               persister.persist_graph(gossip_sync.network_graph())?;
+                       if let Some(network_graph) = gossip_sync.network_graph() {
+                               persister.persist_graph(network_graph)?;
                        }
 
                        Ok(())
@@ -424,7 +466,7 @@ mod tests {
        use std::time::Duration;
        use lightning::routing::scoring::{FixedPenaltyScorer};
        use lightning_rapid_gossip_sync::RapidGossipSync;
-       use super::{BackgroundProcessor, FRESHNESS_TIMER};
+       use super::{BackgroundProcessor, GossipSync, FRESHNESS_TIMER};
 
        const EVENT_DEADLINE: u64 = 5 * FRESHNESS_TIMER;
 
@@ -440,18 +482,35 @@ mod tests {
 
        type ChainMonitor = chainmonitor::ChainMonitor<InMemorySigner, Arc<test_utils::TestChainSource>, Arc<test_utils::TestBroadcaster>, Arc<test_utils::TestFeeEstimator>, Arc<test_utils::TestLogger>, Arc<FilesystemPersister>>;
 
+       type PGS = Arc<P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>>;
+       type RGS = Arc<RapidGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestLogger>>>;
+
        struct Node {
                node: Arc<SimpleArcChannelManager<ChainMonitor, test_utils::TestBroadcaster, test_utils::TestFeeEstimator, test_utils::TestLogger>>,
-               p2p_gossip_sync: Option<Arc<P2PGossipSync<Arc<NetworkGraph>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>>>,
+               p2p_gossip_sync: PGS,
+               rapid_gossip_sync: RGS,
                peer_manager: Arc<PeerManager<TestDescriptor, Arc<test_utils::TestChannelMessageHandler>, Arc<test_utils::TestRoutingMessageHandler>, Arc<test_utils::TestLogger>, IgnoringMessageHandler>>,
                chain_monitor: Arc<ChainMonitor>,
                persister: Arc<FilesystemPersister>,
                tx_broadcaster: Arc<test_utils::TestBroadcaster>,
-               network_graph: Arc<NetworkGraph>,
+               network_graph: Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
                logger: Arc<test_utils::TestLogger>,
                best_block: BestBlock,
                scorer: Arc<Mutex<FixedPenaltyScorer>>,
-               rapid_gossip_sync: Option<Arc<RapidGossipSync<Arc<NetworkGraph>>>>
+       }
+
+       impl Node {
+               fn p2p_gossip_sync(&self) -> GossipSync<PGS, RGS, Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>> {
+                       GossipSync::P2P(self.p2p_gossip_sync.clone())
+               }
+
+               fn rapid_gossip_sync(&self) -> GossipSync<PGS, RGS, Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>> {
+                       GossipSync::Rapid(self.rapid_gossip_sync.clone())
+               }
+
+               fn no_gossip_sync(&self) -> GossipSync<PGS, RGS, Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>> {
+                       GossipSync::None
+               }
        }
 
        impl Drop for Node {
@@ -546,13 +605,13 @@ mod tests {
                        let best_block = BestBlock::from_genesis(network);
                        let params = ChainParameters { network, best_block };
                        let manager = Arc::new(ChannelManager::new(fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster.clone(), logger.clone(), keys_manager.clone(), UserConfig::default(), params));
-                       let network_graph = Arc::new(NetworkGraph::new(genesis_block.header.block_hash()));
-                       let p2p_gossip_sync = Some(Arc::new(P2PGossipSync::new(network_graph.clone(), Some(chain_source.clone()), logger.clone())));
+                       let network_graph = Arc::new(NetworkGraph::new(genesis_block.header.block_hash(), logger.clone()));
+                       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()));
                        let msg_handler = MessageHandler { chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new()), route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new() )};
                        let peer_manager = Arc::new(PeerManager::new(msg_handler, keys_manager.get_node_secret(Recipient::Node).unwrap(), &seed, logger.clone(), IgnoringMessageHandler{}));
                        let scorer = Arc::new(Mutex::new(test_utils::TestScorer::with_penalty(0)));
-                       let rapid_gossip_sync = None;
-                       let node = Node { node: manager, p2p_gossip_sync, peer_manager, chain_monitor, persister, tx_broadcaster, network_graph, logger, best_block, scorer, rapid_gossip_sync };
+                       let node = Node { node: manager, p2p_gossip_sync, rapid_gossip_sync, peer_manager, chain_monitor, persister, tx_broadcaster, network_graph, logger, best_block, scorer };
                        nodes.push(node);
                }
 
@@ -650,7 +709,7 @@ mod tests {
                let data_dir = nodes[0].persister.get_data_dir();
                let persister = Arc::new(Persister::new(data_dir));
                let event_handler = |_: &_| {};
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(),  nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
 
                macro_rules! check_persisted_data {
                        ($node: expr, $filepath: expr) => {
@@ -695,10 +754,7 @@ mod tests {
 
                // Check network graph is persisted
                let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string());
-               if let Some(ref handler) = nodes[0].p2p_gossip_sync {
-                       let network_graph = handler.network_graph();
-                       check_persisted_data!(network_graph, filepath.clone());
-               }
+               check_persisted_data!(nodes[0].network_graph, filepath.clone());
 
                // Check scorer is persisted
                let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "scorer".to_string());
@@ -715,7 +771,7 @@ mod tests {
                let data_dir = nodes[0].persister.get_data_dir();
                let persister = Arc::new(Persister::new(data_dir));
                let event_handler = |_: &_| {};
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
                loop {
                        let log_entries = nodes[0].logger.lines.lock().unwrap();
                        let desired_log = "Calling ChannelManager's timer_tick_occurred".to_string();
@@ -738,7 +794,7 @@ mod tests {
                let data_dir = nodes[0].persister.get_data_dir();
                let persister = Arc::new(Persister::new(data_dir).with_manager_error(std::io::ErrorKind::Other, "test"));
                let event_handler = |_: &_| {};
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
                match bg_processor.join() {
                        Ok(_) => panic!("Expected error persisting manager"),
                        Err(e) => {
@@ -755,7 +811,7 @@ mod tests {
                let data_dir = nodes[0].persister.get_data_dir();
                let persister = Arc::new(Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other, "test"));
                let event_handler = |_: &_| {};
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
 
                match bg_processor.stop() {
                        Ok(_) => panic!("Expected error persisting network graph"),
@@ -773,7 +829,7 @@ mod tests {
                let data_dir = nodes[0].persister.get_data_dir();
                let persister = Arc::new(Persister::new(data_dir).with_scorer_error(std::io::ErrorKind::Other, "test"));
                let event_handler = |_: &_| {};
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(),  nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(),  nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
 
                match bg_processor.stop() {
                        Ok(_) => panic!("Expected error persisting scorer"),
@@ -796,7 +852,7 @@ mod tests {
                let event_handler = move |event: &Event| {
                        sender.send(handle_funding_generation_ready!(event, channel_value)).unwrap();
                };
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
 
                // Open a channel and check that the FundingGenerationReady event was handled.
                begin_open_channel!(nodes[0], nodes[1], channel_value);
@@ -821,7 +877,7 @@ mod tests {
                let (sender, receiver) = std::sync::mpsc::sync_channel(1);
                let event_handler = move |event: &Event| sender.send(event.clone()).unwrap();
                let persister = Arc::new(Persister::new(data_dir));
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
 
                // Force close the channel and check that the SpendableOutputs event was handled.
                nodes[0].node.force_close_channel(&nodes[0].node.list_channels()[0].channel_id, &nodes[1].node.get_our_node_id()).unwrap();
@@ -845,7 +901,7 @@ mod tests {
                let data_dir = nodes[0].persister.get_data_dir();
                let persister = Arc::new(Persister::new(data_dir));
                let event_handler = |_: &_| {};
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(),  nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
 
                loop {
                        let log_entries = nodes[0].logger.lines.lock().unwrap();
@@ -865,7 +921,6 @@ mod tests {
                let (sender, receiver) = std::sync::mpsc::sync_channel(1);
                let persister = Arc::new(Persister::new(data_dir.clone()).with_graph_persistence_notifier(sender));
                let network_graph = nodes[0].network_graph.clone();
-               let rapid_sync = Arc::new(RapidGossipSync::new(network_graph.clone()));
                let features = ChannelFeatures::empty();
                network_graph.add_channel_from_partial_announcement(42, 53, features, nodes[0].node.get_our_node_id(), nodes[1].node.get_our_node_id())
                        .expect("Failed to update channel from partial announcement");
@@ -874,7 +929,7 @@ mod tests {
                assert_eq!(network_graph.read_only().channels().len(), 1);
 
                let event_handler = |_: &_| {};
-               let background_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), Some(rapid_sync.clone()));
+               let background_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].rapid_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
 
                loop {
                        let log_entries = nodes[0].logger.lines.lock().unwrap();
@@ -901,7 +956,7 @@ mod tests {
                        0, 0, 0, 1, 0, 0, 0, 0, 58, 85, 116, 216, 255, 8, 153, 192, 0, 2, 27, 0, 0, 25, 0, 0,
                        0, 1, 0, 0, 0, 125, 255, 2, 68, 226, 0, 6, 11, 0, 1, 5, 0, 0, 0, 0, 29, 129, 25, 192,
                ];
-               rapid_sync.update_network_graph(&initialization_input[..]).unwrap();
+               nodes[0].rapid_gossip_sync.update_network_graph(&initialization_input[..]).unwrap();
 
                // this should have added two channels
                assert_eq!(network_graph.read_only().channels().len(), 3);
@@ -928,7 +983,7 @@ mod tests {
                let router = DefaultRouter::new(Arc::clone(&nodes[0].network_graph), Arc::clone(&nodes[0].logger), random_seed_bytes);
                let invoice_payer = Arc::new(InvoicePayer::new(Arc::clone(&nodes[0].node), router, Arc::clone(&nodes[0].scorer), Arc::clone(&nodes[0].logger), |_: &_| {}, Retry::Attempts(2)));
                let event_handler = Arc::clone(&invoice_payer);
-               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].p2p_gossip_sync.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()), nodes[0].rapid_gossip_sync.clone());
+               let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
                assert!(bg_processor.stop().is_ok());
        }
 }
index 1d6e7f40accd8410ac0c7c42bb78f56665da4b7c..1358370d3db0e090c12d06c59aab87eb0aadd9c7 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-block-sync"
-version = "0.0.106"
+version = "0.0.108"
 authors = ["Jeffrey Czyz", "Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "http://github.com/lightningdevkit/rust-lightning"
@@ -19,7 +19,7 @@ rpc-client = [ "serde", "serde_json", "chunked_transfer" ]
 
 [dependencies]
 bitcoin = "0.28.1"
-lightning = { version = "0.0.106", path = "../lightning" }
+lightning = { version = "0.0.108", path = "../lightning" }
 futures = { version = "0.3" }
 tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true }
 serde = { version = "1.0", features = ["derive"], optional = true }
index 9382d66303f05fae9947549b12b0ddbba8e21b16..98282d0df7bade4d88c6b80a56f9b880d6483a7f 100644 (file)
@@ -1,7 +1,7 @@
 [package]
 name = "lightning-invoice"
 description = "Data structures to parse and serialize BOLT11 lightning invoices"
-version = "0.14.0"
+version = "0.16.0"
 authors = ["Sebastian Geisler <sgeisler@wh2.tu-dresden.de>"]
 documentation = "https://docs.rs/lightning-invoice/"
 license = "MIT OR Apache-2.0"
@@ -20,13 +20,15 @@ std = ["bitcoin_hashes/std", "num-traits/std", "lightning/std", "bech32/std"]
 
 [dependencies]
 bech32 = { version = "0.8", default-features = false }
-lightning = { version = "0.0.106", path = "../lightning", default-features = false }
+lightning = { version = "0.0.108", path = "../lightning", default-features = false }
 secp256k1 = { version = "0.22", default-features = false, features = ["recovery", "alloc"] }
 num-traits = { version = "0.2.8", default-features = false }
 bitcoin_hashes = { version = "0.10", default-features = false }
 hashbrown = { version = "0.11", optional = true }
 core2 = { version = "0.3.0", default-features = false, optional = true }
+serde = { version = "1.0.118", optional = true }
 
 [dev-dependencies]
-lightning = { version = "0.0.106", path = "../lightning", default-features = false, features = ["_test_utils"] }
+lightning = { version = "0.0.108", path = "../lightning", default-features = false, features = ["_test_utils"] }
 hex = "0.4"
+serde_json = { version = "1"}
index 609b33b2d50d941f74585addc5cdd7565fb348fb..bad024c66c5a37114d144c146014294e0f747501 100644 (file)
@@ -35,6 +35,8 @@ extern crate secp256k1;
 extern crate alloc;
 #[cfg(any(test, feature = "std"))]
 extern crate core;
+#[cfg(feature = "serde")]
+extern crate serde;
 
 #[cfg(feature = "std")]
 use std::time::SystemTime;
@@ -61,6 +63,9 @@ use core::slice::Iter;
 use core::time::Duration;
 use core::str;
 
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Deserializer,Serialize, Serializer, de::Error};
+
 mod de;
 mod ser;
 mod tb;
@@ -1523,6 +1528,23 @@ impl<S> Display for SignOrCreationError<S> {
        }
 }
 
+#[cfg(feature = "serde")]
+impl Serialize for Invoice {
+       fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+               serializer.serialize_str(self.to_string().as_str())
+       }
+}
+#[cfg(feature = "serde")]
+impl<'de> Deserialize<'de> for Invoice {
+       fn deserialize<D>(deserializer: D) -> Result<Invoice, D::Error> where D: Deserializer<'de> {
+               let bolt11 = String::deserialize(deserializer)?
+                       .parse::<Invoice>()
+                       .map_err(|e| D::Error::custom(format!("{:?}", e)))?;
+
+               Ok(bolt11)
+       }
+}
+
 #[cfg(test)]
 mod test {
        use bitcoin_hashes::hex::FromHex;
@@ -1974,4 +1996,26 @@ mod test {
 
                assert!(invoice.would_expire(Duration::from_secs(1234567 + DEFAULT_EXPIRY_TIME + 1)));
        }
+
+       #[cfg(feature = "serde")]
+       #[test]
+       fn test_serde() {
+               let invoice_str = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
+                       h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
+                       5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
+                       h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
+                       j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
+                       ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
+                       guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
+                       ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
+                       p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
+                       8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
+                       j5r6drg6k6zcqj0fcwg";
+               let invoice = invoice_str.parse::<super::Invoice>().unwrap();
+               let serialized_invoice = serde_json::to_string(&invoice).unwrap();
+               let deserialized_invoice: super::Invoice = serde_json::from_str(serialized_invoice.as_str()).unwrap();
+               assert_eq!(invoice, deserialized_invoice);
+               assert_eq!(invoice_str, deserialized_invoice.to_string().as_str());
+               assert_eq!(invoice_str, serialized_invoice.as_str().trim_matches('\"'));
+       }
 }
index 04cfb3f147099181b37ed8e6dee70d989f983233..e09fd836224b80a339564b94d2239bca29ec9347 100644 (file)
@@ -440,13 +440,13 @@ fn filter_channels(channels: Vec<ChannelDetails>, min_inbound_capacity_msat: Opt
 }
 
 /// A [`Router`] implemented using [`find_route`].
-pub struct DefaultRouter<G: Deref<Target = NetworkGraph>, L: Deref> where L::Target: Logger {
+pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref> where L::Target: Logger {
        network_graph: G,
        logger: L,
        random_seed_bytes: Mutex<[u8; 32]>,
 }
 
-impl<G: Deref<Target = NetworkGraph>, L: Deref> DefaultRouter<G, L> where L::Target: Logger {
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> DefaultRouter<G, L> where L::Target: Logger {
        /// Creates a new router using the given [`NetworkGraph`], a [`Logger`], and a randomness source
        /// `random_seed_bytes`.
        pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32]) -> Self {
@@ -455,18 +455,19 @@ impl<G: Deref<Target = NetworkGraph>, L: Deref> DefaultRouter<G, L> where L::Tar
        }
 }
 
-impl<G: Deref<Target = NetworkGraph>, L: Deref, S: Score> Router<S> for DefaultRouter<G, L>
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Score> Router<S> for DefaultRouter<G, L>
 where L::Target: Logger {
        fn find_route(
                &self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
                first_hops: Option<&[&ChannelDetails]>, scorer: &S
        ) -> Result<Route, LightningError> {
+               let network_graph = self.network_graph.read_only();
                let random_seed_bytes = {
                        let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
                        *locked_random_seed_bytes = sha256::Hash::hash(&*locked_random_seed_bytes).into_inner();
                        *locked_random_seed_bytes
                };
-               find_route(payer, params, &*self.network_graph, first_hops, &*self.logger, scorer, &random_seed_bytes)
+               find_route(payer, params, &network_graph, first_hops, &*self.logger, scorer, &random_seed_bytes)
        }
 }
 
@@ -566,12 +567,12 @@ mod test {
                        final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
                };
                let first_hops = nodes[0].node.list_usable_channels();
-               let network_graph = node_cfgs[0].network_graph;
+               let network_graph = &node_cfgs[0].network_graph;
                let logger = test_utils::TestLogger::new();
                let scorer = test_utils::TestScorer::with_penalty(0);
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
-                       &nodes[0].node.get_our_node_id(), &route_params, network_graph,
+                       &nodes[0].node.get_our_node_id(), &route_params, &network_graph.read_only(),
                        Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer, &random_seed_bytes
                ).unwrap();
 
@@ -658,7 +659,7 @@ mod test {
                // `msgs::ChannelUpdate` is never handled for the node(s). As the `msgs::ChannelUpdate`
                // is never handled, the `channel.counterparty.forwarding_info` is never assigned.
                let mut private_chan_cfg = UserConfig::default();
-               private_chan_cfg.channel_options.announced_channel = false;
+               private_chan_cfg.channel_handshake_config.announced_channel = false;
                let temporary_channel_id = nodes[2].node.create_channel(nodes[0].node.get_our_node_id(), 1_000_000, 500_000_000, 42, Some(private_chan_cfg)).unwrap();
                let open_channel = get_event_msg!(nodes[2], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
                nodes[0].node.handle_open_channel(&nodes[2].node.get_our_node_id(), InitFeatures::known(), &open_channel);
@@ -842,12 +843,12 @@ mod test {
                        final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
                };
                let first_hops = nodes[0].node.list_usable_channels();
-               let network_graph = node_cfgs[0].network_graph;
+               let network_graph = &node_cfgs[0].network_graph;
                let logger = test_utils::TestLogger::new();
                let scorer = test_utils::TestScorer::with_penalty(0);
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
-                       &nodes[0].node.get_our_node_id(), &params, network_graph,
+                       &nodes[0].node.get_our_node_id(), &params, &network_graph.read_only(),
                        Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer, &random_seed_bytes
                ).unwrap();
                let (payment_event, fwd_idx) = {
@@ -1045,7 +1046,7 @@ mod test {
                // `msgs::ChannelUpdate` is never handled for the node(s). As the `msgs::ChannelUpdate`
                // is never handled, the `channel.counterparty.forwarding_info` is never assigned.
                let mut private_chan_cfg = UserConfig::default();
-               private_chan_cfg.channel_options.announced_channel = false;
+               private_chan_cfg.channel_handshake_config.announced_channel = false;
                let temporary_channel_id = nodes[1].node.create_channel(nodes[3].node.get_our_node_id(), 1_000_000, 500_000_000, 42, Some(private_chan_cfg)).unwrap();
                let open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[3].node.get_our_node_id());
                nodes[3].node.handle_open_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel);
index 08c649f79bc1f885e3dabe06a17c7b250733cdb7..9f22e61140b19d860a8718c98c4a7eae99a8015c 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-net-tokio"
-version = "0.0.106"
+version = "0.0.108"
 authors = ["Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
@@ -16,7 +16,7 @@ rustdoc-args = ["--cfg", "docsrs"]
 
 [dependencies]
 bitcoin = "0.28.1"
-lightning = { version = "0.0.106", path = "../lightning" }
+lightning = { version = "0.0.108", path = "../lightning" }
 tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "sync", "net", "time" ] }
 
 [dev-dependencies]
index 1bf4c5d2e75f87a1b759963b09adad28cadb838e..4b4551182a84f961bd7e48f9ca2a5b3fc52f9d7b 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-persister"
-version = "0.0.106"
+version = "0.0.108"
 authors = ["Valentine Wallace", "Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
@@ -17,11 +17,11 @@ _bench_unstable = ["lightning/_bench_unstable"]
 
 [dependencies]
 bitcoin = "0.28.1"
-lightning = { version = "0.0.106", path = "../lightning" }
+lightning = { version = "0.0.108", path = "../lightning" }
 libc = "0.2"
 
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["winbase"] }
 
 [dev-dependencies]
-lightning = { version = "0.0.106", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.108", path = "../lightning", features = ["_test_utils"] }
index 58446a46e7d8f02c64941296f00d8c6e1d4f1818..a65e2853177e0828057355a14e0822b1010c6b15 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-rapid-gossip-sync"
-version = "0.0.106"
+version = "0.0.108"
 authors = ["Arik Sosman <git@arik.io>"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning"
@@ -13,8 +13,8 @@ Utility to process gossip routing data from Rapid Gossip Sync Server.
 _bench_unstable = []
 
 [dependencies]
-lightning = { version = "0.0.106", path = "../lightning" }
+lightning = { version = "0.0.108", path = "../lightning" }
 bitcoin = { version = "0.28.1", default-features = false }
 
 [dev-dependencies]
-lightning = { version = "0.0.106", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.108", path = "../lightning", features = ["_test_utils"] }
index 278cede397411720415b89d20a6c9ccaecb1160d..7880e11a60ea45c824dfceb3e75d6ee9d48610c8 100644 (file)
 //! use lightning::routing::gossip::NetworkGraph;
 //! use lightning_rapid_gossip_sync::RapidGossipSync;
 //!
+//! # use lightning::util::logger::{Logger, Record};
+//! # struct FakeLogger {}
+//! # impl Logger for FakeLogger {
+//! #     fn log(&self, record: &Record) { unimplemented!() }
+//! # }
+//! # let logger = FakeLogger {};
+//!
 //! let block_hash = genesis_block(Network::Bitcoin).header.block_hash();
-//! let network_graph = NetworkGraph::new(block_hash);
+//! let network_graph = NetworkGraph::new(block_hash, &logger);
 //! let rapid_sync = RapidGossipSync::new(&network_graph);
 //! let new_last_sync_timestamp_result = rapid_sync.sync_network_graph_with_file_path("./rapid_sync.lngossip");
 //! ```
@@ -63,6 +70,7 @@ use std::ops::Deref;
 use std::sync::atomic::{AtomicBool, Ordering};
 
 use lightning::routing::gossip::NetworkGraph;
+use lightning::util::logger::Logger;
 
 use crate::error::GraphSyncError;
 
@@ -76,12 +84,13 @@ pub mod processing;
 /// See [crate-level documentation] for usage.
 ///
 /// [crate-level documentation]: crate
-pub struct RapidGossipSync<NG: Deref<Target=NetworkGraph>> {
+pub struct RapidGossipSync<NG: Deref<Target=NetworkGraph<L>>, L: Deref>
+where L::Target: Logger {
        network_graph: NG,
        is_initial_sync_complete: AtomicBool
 }
 
-impl<NG: Deref<Target=NetworkGraph>> RapidGossipSync<NG> {
+impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L::Target: Logger {
        /// Instantiate a new [`RapidGossipSync`] instance
        pub fn new(network_graph: NG) -> Self {
                Self {
@@ -128,6 +137,7 @@ mod tests {
 
        use lightning::ln::msgs::DecodeError;
        use lightning::routing::gossip::NetworkGraph;
+       use lightning::util::test_utils::TestLogger;
        use crate::RapidGossipSync;
 
        #[test]
@@ -187,7 +197,8 @@ mod tests {
                let graph_sync_test_file = sync_test.get_test_file_path();
 
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
-               let network_graph = NetworkGraph::new(block_hash);
+               let logger = TestLogger::new();
+               let network_graph = NetworkGraph::new(block_hash, &logger);
 
                assert_eq!(network_graph.read_only().channels().len(), 0);
 
@@ -219,7 +230,8 @@ mod tests {
        #[test]
        fn measure_native_read_from_file() {
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
-               let network_graph = NetworkGraph::new(block_hash);
+               let logger = TestLogger::new();
+               let network_graph = NetworkGraph::new(block_hash, &logger);
 
                assert_eq!(network_graph.read_only().channels().len(), 0);
 
@@ -254,14 +266,16 @@ pub mod bench {
 
        use lightning::ln::msgs::DecodeError;
        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) {
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
+               let logger = TestLogger::new();
                b.iter(|| {
-                       let network_graph = NetworkGraph::new(block_hash);
+                       let network_graph = NetworkGraph::new(block_hash, &logger);
                        let rapid_sync = RapidGossipSync::new(&network_graph);
                        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 {
index 21c1ce29a99142f427dd8f9947f8fe0c94cfbcfa..09693a76d6f3b4868424d863ddd97399802974f9 100644 (file)
@@ -11,6 +11,7 @@ use lightning::ln::msgs::{
        DecodeError, ErrorAction, LightningError, OptionalField, UnsignedChannelUpdate,
 };
 use lightning::routing::gossip::NetworkGraph;
+use lightning::util::logger::Logger;
 use lightning::util::ser::{BigSize, Readable};
 
 use crate::error::GraphSyncError;
@@ -26,7 +27,7 @@ const GOSSIP_PREFIX: [u8; 4] = [76, 68, 75, 1];
 /// avoid malicious updates being able to trigger excessive memory allocation.
 const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY: u32 = 50_000;
 
-impl<NG: Deref<Target=NetworkGraph>> RapidGossipSync<NG> {
+impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L::Target: Logger {
        /// Update network graph from binary data.
        /// Returns the last sync timestamp to be used the next time rapid sync data is queried.
        ///
@@ -236,6 +237,7 @@ mod tests {
 
        use lightning::ln::msgs::DecodeError;
        use lightning::routing::gossip::NetworkGraph;
+       use lightning::util::test_utils::TestLogger;
 
        use crate::error::GraphSyncError;
        use crate::RapidGossipSync;
@@ -243,7 +245,8 @@ mod tests {
        #[test]
        fn network_graph_fails_to_update_from_clipped_input() {
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
-               let network_graph = NetworkGraph::new(block_hash);
+               let logger = TestLogger::new();
+               let network_graph = NetworkGraph::new(block_hash, &logger);
 
                let example_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -282,7 +285,8 @@ mod tests {
                ];
 
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
-               let network_graph = NetworkGraph::new(block_hash);
+               let logger = TestLogger::new();
+               let network_graph = NetworkGraph::new(block_hash, &logger);
 
                assert_eq!(network_graph.read_only().channels().len(), 0);
 
@@ -315,7 +319,8 @@ mod tests {
                ];
 
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
-               let network_graph = NetworkGraph::new(block_hash);
+               let logger = TestLogger::new();
+               let network_graph = NetworkGraph::new(block_hash, &logger);
 
                assert_eq!(network_graph.read_only().channels().len(), 0);
 
@@ -351,7 +356,8 @@ mod tests {
                ];
 
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
-               let network_graph = NetworkGraph::new(block_hash);
+               let logger = TestLogger::new();
+               let network_graph = NetworkGraph::new(block_hash, &logger);
 
                assert_eq!(network_graph.read_only().channels().len(), 0);
 
@@ -417,7 +423,8 @@ mod tests {
                ];
 
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
-               let network_graph = NetworkGraph::new(block_hash);
+               let logger = TestLogger::new();
+               let network_graph = NetworkGraph::new(block_hash, &logger);
 
                assert_eq!(network_graph.read_only().channels().len(), 0);
 
@@ -476,7 +483,8 @@ mod tests {
                ];
 
                let block_hash = genesis_block(Network::Bitcoin).block_hash();
-               let network_graph = NetworkGraph::new(block_hash);
+               let logger = TestLogger::new();
+               let network_graph = NetworkGraph::new(block_hash, &logger);
 
                assert_eq!(network_graph.read_only().channels().len(), 0);
 
index f9321c7b649fceaf7ae1ccfbabfe0231733f2a72..b3e2af8c88eab1cde2a5e3441517e89cf4f40194 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning"
-version = "0.0.106"
+version = "0.0.108"
 authors = ["Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
index 5128600163a42854f0be6c2bb5f27f79608050e6..3f7a1055b6dc3f1dba4d21387051cbe0751293e9 100644 (file)
@@ -869,6 +869,9 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
                        writer.write_all(&txid[..])?;
                        writer.write_all(&byte_utils::be64_to_array(htlc_infos.len() as u64))?;
                        for &(ref htlc_output, ref htlc_source) in htlc_infos.iter() {
+                               debug_assert!(htlc_source.is_none() || Some(**txid) == self.current_counterparty_commitment_txid
+                                               || Some(**txid) == self.prev_counterparty_commitment_txid,
+                                       "HTLC Sources for all revoked commitment transactions should be none!");
                                serialize_htlc_in_commitment!(htlc_output);
                                htlc_source.as_ref().map(|b| b.as_ref()).write(writer)?;
                        }
@@ -1659,7 +1662,8 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
 /// as long as we examine both the current counterparty commitment transaction and, if it hasn't
 /// been revoked yet, the previous one, we we will never "forget" to resolve an HTLC.
 macro_rules! fail_unbroadcast_htlcs {
-       ($self: expr, $commitment_tx_type: expr, $commitment_tx_conf_height: expr, $confirmed_htlcs_list: expr, $logger: expr) => { {
+       ($self: expr, $commitment_tx_type: expr, $commitment_txid_confirmed: expr,
+        $commitment_tx_conf_height: expr, $confirmed_htlcs_list: expr, $logger: expr) => { {
                macro_rules! check_htlc_fails {
                        ($txid: expr, $commitment_tx: expr) => {
                                if let Some(ref latest_outpoints) = $self.counterparty_claimable_outpoints.get($txid) {
@@ -1675,9 +1679,14 @@ macro_rules! fail_unbroadcast_htlcs {
                                                        // cannot currently change after channel initialization, so we don't
                                                        // need to here.
                                                        let confirmed_htlcs_iter: &mut Iterator<Item = (&HTLCOutputInCommitment, Option<&HTLCSource>)> = &mut $confirmed_htlcs_list;
+
                                                        let mut matched_htlc = false;
                                                        for (ref broadcast_htlc, ref broadcast_source) in confirmed_htlcs_iter {
-                                                               if broadcast_htlc.transaction_output_index.is_some() && Some(&**source) == *broadcast_source {
+                                                               if broadcast_htlc.transaction_output_index.is_some() &&
+                                                                       (Some(&**source) == *broadcast_source ||
+                                                                        (broadcast_source.is_none() &&
+                                                                         broadcast_htlc.payment_hash == htlc.payment_hash &&
+                                                                         broadcast_htlc.amount_msat == htlc.amount_msat)) {
                                                                        matched_htlc = true;
                                                                        break;
                                                                }
@@ -1693,7 +1702,7 @@ macro_rules! fail_unbroadcast_htlcs {
                                                                }
                                                        });
                                                        let entry = OnchainEventEntry {
-                                                               txid: *$txid,
+                                                               txid: $commitment_txid_confirmed,
                                                                height: $commitment_tx_conf_height,
                                                                event: OnchainEvent::HTLCUpdate {
                                                                        source: (**source).clone(),
@@ -1702,8 +1711,9 @@ macro_rules! fail_unbroadcast_htlcs {
                                                                        commitment_tx_output_idx: None,
                                                                },
                                                        };
-                                                       log_trace!($logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of {} commitment transaction, waiting for confirmation (at height {})",
-                                                               log_bytes!(htlc.payment_hash.0), $commitment_tx, $commitment_tx_type, entry.confirmation_threshold());
+                                                       log_trace!($logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of {} commitment transaction {}, waiting for confirmation (at height {})",
+                                                               log_bytes!(htlc.payment_hash.0), $commitment_tx, $commitment_tx_type,
+                                                               $commitment_txid_confirmed, entry.confirmation_threshold());
                                                        $self.onchain_events_awaiting_threshold_conf.push(entry);
                                                }
                                        }
@@ -2100,7 +2110,16 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                                }
                                self.counterparty_commitment_txn_on_chain.insert(commitment_txid, commitment_number);
 
-                               fail_unbroadcast_htlcs!(self, "revoked counterparty", height, [].iter().map(|a| *a), logger);
+                               if let Some(per_commitment_data) = per_commitment_option {
+                                       fail_unbroadcast_htlcs!(self, "revoked_counterparty", commitment_txid, height,
+                                               per_commitment_data.iter().map(|(htlc, htlc_source)|
+                                                       (htlc, htlc_source.as_ref().map(|htlc_source| htlc_source.as_ref()))
+                                               ), logger);
+                               } else {
+                                       debug_assert!(false, "We should have per-commitment option for any recognized old commitment txn");
+                                       fail_unbroadcast_htlcs!(self, "revoked counterparty", commitment_txid, height,
+                                               [].iter().map(|reference| *reference), logger);
+                               }
                        }
                } else if let Some(per_commitment_data) = per_commitment_option {
                        // While this isn't useful yet, there is a potential race where if a counterparty
@@ -2116,7 +2135,10 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                        self.counterparty_commitment_txn_on_chain.insert(commitment_txid, commitment_number);
 
                        log_info!(logger, "Got broadcast of non-revoked counterparty commitment transaction {}", commitment_txid);
-                       fail_unbroadcast_htlcs!(self, "counterparty", height, per_commitment_data.iter().map(|(a, b)| (a, b.as_ref().map(|b| b.as_ref()))), logger);
+                       fail_unbroadcast_htlcs!(self, "counterparty", commitment_txid, height,
+                               per_commitment_data.iter().map(|(htlc, htlc_source)|
+                                       (htlc, htlc_source.as_ref().map(|htlc_source| htlc_source.as_ref()))
+                               ), logger);
 
                        let htlc_claim_reqs = self.get_counterparty_htlc_output_claim_reqs(commitment_number, commitment_txid, Some(tx));
                        for req in htlc_claim_reqs {
@@ -2272,7 +2294,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                        let res = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, height);
                        let mut to_watch = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, tx);
                        append_onchain_update!(res, to_watch);
-                       fail_unbroadcast_htlcs!(self, "latest holder", height, self.current_holder_commitment_tx.htlc_outputs.iter().map(|(a, _, c)| (a, c.as_ref())), logger);
+                       fail_unbroadcast_htlcs!(self, "latest holder", commitment_txid, height,
+                               self.current_holder_commitment_tx.htlc_outputs.iter()
+                               .map(|(htlc, _, htlc_source)| (htlc, htlc_source.as_ref())), logger);
                } else if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx {
                        if holder_tx.txid == commitment_txid {
                                is_holder_tx = true;
@@ -2280,7 +2304,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                                let res = self.get_broadcasted_holder_claims(holder_tx, height);
                                let mut to_watch = self.get_broadcasted_holder_watch_outputs(holder_tx, tx);
                                append_onchain_update!(res, to_watch);
-                               fail_unbroadcast_htlcs!(self, "previous holder", height, holder_tx.htlc_outputs.iter().map(|(a, _, c)| (a, c.as_ref())), logger);
+                               fail_unbroadcast_htlcs!(self, "previous holder", commitment_txid, height,
+                                       holder_tx.htlc_outputs.iter().map(|(htlc, _, htlc_source)| (htlc, htlc_source.as_ref())),
+                                       logger);
                        }
                }
 
@@ -2561,7 +2587,8 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                                                matured_htlcs.push(source.clone());
                                        }
 
-                                       log_debug!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!(payment_hash.0));
+                                       log_debug!(logger, "HTLC {} failure update in {} has got enough confirmations to be passed upstream",
+                                               log_bytes!(payment_hash.0), entry.txid);
                                        self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
                                                payment_hash,
                                                payment_preimage: None,
@@ -2640,7 +2667,10 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                F::Target: FeeEstimator,
                L::Target: Logger,
        {
-               self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.txid != *txid);
+               self.onchain_events_awaiting_threshold_conf.retain(|ref entry| if entry.txid == *txid {
+                       log_info!(logger, "Removing onchain event with txid {}", txid);
+                       false
+               } else { true });
                self.onchain_tx_handler.transaction_unconfirmed(txid, broadcaster, fee_estimator, logger);
        }
 
index 33c88cf11e38c672d6394bd3027b89b8664bbf0b..4231d08259abcbe1e4c50550f4b40aa7d7064faa 100644 (file)
@@ -397,7 +397,9 @@ pub trait KeysInterface {
        /// A type which implements Sign which will be returned by get_channel_signer.
        type Signer : Sign;
 
-       /// Get node secret key (aka node_id or network_key) based on the provided [`Recipient`].
+       /// Get node secret key based on the provided [`Recipient`].
+       ///
+       /// The node_id/network_key is the public key that corresponds to this secret key.
        ///
        /// This method must return the same value each time it is called with a given `Recipient`
        /// parameter.
index 495b507426c19bd7f31d6709da30db79c13f0dd9..91575195a8826a3ae510e322d85420f06269325c 100644 (file)
@@ -2541,7 +2541,7 @@ fn test_temporary_error_during_shutdown() {
        // Test that temporary failures when updating the monitor's shutdown script delay cooperative
        // close.
        let mut config = test_default_channel_config();
-       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
 
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
@@ -2596,7 +2596,7 @@ fn test_permanent_error_during_sending_shutdown() {
        // Test that permanent failures when updating the monitor's shutdown script result in a force
        // close when initiating a cooperative close.
        let mut config = test_default_channel_config();
-       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
 
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
@@ -2617,7 +2617,7 @@ fn test_permanent_error_during_handling_shutdown() {
        // Test that permanent failures when updating the monitor's shutdown script result in a force
        // close when handling a cooperative close.
        let mut config = test_default_channel_config();
-       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
 
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
index 4daaf630ac4e57bd7c96ed73e401badf986236d1..b88a38b56504eb652c68fb445c29b5e4e4addb5b 100644 (file)
@@ -39,7 +39,7 @@ use util::events::ClosureReason;
 use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
 use util::logger::Logger;
 use util::errors::APIError;
-use util::config::{UserConfig, ChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits};
+use util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits};
 use util::scid_utils::scid_from_parts;
 
 use io;
@@ -482,6 +482,16 @@ pub(crate) const CONCURRENT_INBOUND_HTLC_FEE_BUFFER: u32 = 2;
 /// transaction (not counting the value of the HTLCs themselves).
 pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4;
 
+/// When a [`Channel`] has its [`ChannelConfig`] updated, its existing one is stashed for up to this
+/// number of ticks to allow forwarding HTLCs by nodes that have yet to receive the new
+/// ChannelUpdate prompted by the config update. This value was determined as follows:
+///
+///   * The expected interval between ticks (1 minute).
+///   * The average convergence delay of updates across the network, i.e., ~300 seconds on average
+///      for a node to see an update as seen on `<https://arxiv.org/pdf/2205.12737.pdf>`.
+///   * `EXPIRE_PREV_CONFIG_TICKS` = convergence_delay / tick_interval
+pub(crate) const EXPIRE_PREV_CONFIG_TICKS: usize = 5;
+
 // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
 // has been completed, and then turn into a Channel to get compiler-time enforcement of things like
 // calling channel_id() before we're set up or things like get_outbound_funding_signed on an
@@ -490,10 +500,12 @@ pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4;
 // Holder designates channel data owned for the benefice of the user client.
 // Counterparty designates channel data owned by the another channel participant entity.
 pub(super) struct Channel<Signer: Sign> {
-       #[cfg(any(test, feature = "_test_utils"))]
-       pub(crate) config: ChannelConfig,
-       #[cfg(not(any(test, feature = "_test_utils")))]
-       config: ChannelConfig,
+       config: LegacyChannelConfig,
+
+       // Track the previous `ChannelConfig` so that we can continue forwarding HTLCs that were
+       // constructed using it. The second element in the tuple corresponds to the number of ticks that
+       // have elapsed since the update occurred.
+       prev_config: Option<(ChannelConfig, usize)>,
 
        inbound_handshake_limits_override: Option<ChannelHandshakeLimits>,
 
@@ -855,7 +867,7 @@ impl<Signer: Sign> Channel<Signer> {
                // available. If it's private, we first try `scid_privacy` as it provides better privacy
                // with no other changes, and fall back to `only_static_remotekey`
                let mut ret = ChannelTypeFeatures::only_static_remote_key();
-               if !config.channel_options.announced_channel && config.own_channel_config.negotiate_scid_privacy {
+               if !config.channel_handshake_config.announced_channel && config.channel_handshake_config.negotiate_scid_privacy {
                        ret.set_scid_privacy_required();
                }
                ret
@@ -885,7 +897,7 @@ impl<Signer: Sign> Channel<Signer> {
        {
                let opt_anchors = false; // TODO - should be based on features
 
-               let holder_selected_contest_delay = config.own_channel_config.our_to_self_delay;
+               let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay;
                let holder_signer = keys_provider.get_channel_signer(false, channel_value_satoshis);
                let pubkeys = holder_signer.pubkeys().clone();
 
@@ -918,7 +930,7 @@ impl<Signer: Sign> Channel<Signer> {
                let mut secp_ctx = Secp256k1::new();
                secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes());
 
-               let shutdown_scriptpubkey = if config.channel_options.commit_upfront_shutdown_pubkey {
+               let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey {
                        Some(keys_provider.get_shutdown_scriptpubkey())
                } else { None };
 
@@ -930,8 +942,16 @@ impl<Signer: Sign> Channel<Signer> {
 
                Ok(Channel {
                        user_id,
-                       config: config.channel_options.clone(),
-                       inbound_handshake_limits_override: Some(config.peer_channel_config_limits.clone()),
+
+                       config: LegacyChannelConfig {
+                               options: config.channel_config.clone(),
+                               announced_channel: config.channel_handshake_config.announced_channel,
+                               commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey,
+                       },
+
+                       prev_config: None,
+
+                       inbound_handshake_limits_override: Some(config.channel_handshake_limits.clone()),
 
                        channel_id: keys_provider.get_secure_random_bytes(),
                        channel_state: ChannelState::OurInitSent as u32,
@@ -988,11 +1008,11 @@ impl<Signer: Sign> Channel<Signer> {
                        counterparty_dust_limit_satoshis: 0,
                        holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
                        counterparty_max_htlc_value_in_flight_msat: 0,
-                       holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.own_channel_config),
+                       holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
                        counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel
                        holder_selected_channel_reserve_satoshis,
                        counterparty_htlc_minimum_msat: 0,
-                       holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
+                       holder_htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
                        counterparty_max_accepted_htlcs: 0,
                        minimum_depth: None, // Filled in in accept_channel
 
@@ -1000,7 +1020,7 @@ impl<Signer: Sign> Channel<Signer> {
 
                        channel_transaction_parameters: ChannelTransactionParameters {
                                holder_pubkeys: pubkeys,
-                               holder_selected_contest_delay: config.own_channel_config.our_to_self_delay,
+                               holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay,
                                is_outbound_from_holder: true,
                                counterparty_parameters: None,
                                funding_outpoint: None,
@@ -1117,15 +1137,14 @@ impl<Signer: Sign> Channel<Signer> {
                        delayed_payment_basepoint: msg.delayed_payment_basepoint,
                        htlc_basepoint: msg.htlc_basepoint
                };
-               let mut local_config = (*config).channel_options.clone();
 
-               if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
-                       return Err(ChannelError::Close(format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks. It must be greater than {}", config.own_channel_config.our_to_self_delay, BREAKDOWN_TIMEOUT)));
+               if config.channel_handshake_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
+                       return Err(ChannelError::Close(format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks. It must be greater than {}", config.channel_handshake_config.our_to_self_delay, BREAKDOWN_TIMEOUT)));
                }
 
                // Check sanity of message fields:
-               if msg.funding_satoshis > config.peer_channel_config_limits.max_funding_satoshis {
-                       return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.peer_channel_config_limits.max_funding_satoshis, msg.funding_satoshis)));
+               if msg.funding_satoshis > config.channel_handshake_limits.max_funding_satoshis {
+                       return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.channel_handshake_limits.max_funding_satoshis, msg.funding_satoshis)));
                }
                if msg.funding_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS {
                        return Err(ChannelError::Close(format!("Funding must be smaller than the total bitcoin supply. It was {}", msg.funding_satoshis)));
@@ -1145,7 +1164,7 @@ impl<Signer: Sign> Channel<Signer> {
                }
                Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
 
-               let max_counterparty_selected_contest_delay = u16::min(config.peer_channel_config_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
+               let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
                if msg.to_self_delay > max_counterparty_selected_contest_delay {
                        return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_counterparty_selected_contest_delay, msg.to_self_delay)));
                }
@@ -1157,20 +1176,20 @@ impl<Signer: Sign> Channel<Signer> {
                }
 
                // Now check against optional parameters as set by config...
-               if msg.funding_satoshis < config.peer_channel_config_limits.min_funding_satoshis {
-                       return Err(ChannelError::Close(format!("Funding satoshis ({}) is less than the user specified limit ({})", msg.funding_satoshis, config.peer_channel_config_limits.min_funding_satoshis)));
+               if msg.funding_satoshis < config.channel_handshake_limits.min_funding_satoshis {
+                       return Err(ChannelError::Close(format!("Funding satoshis ({}) is less than the user specified limit ({})", msg.funding_satoshis, config.channel_handshake_limits.min_funding_satoshis)));
                }
-               if msg.htlc_minimum_msat > config.peer_channel_config_limits.max_htlc_minimum_msat {
-                       return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat,  config.peer_channel_config_limits.max_htlc_minimum_msat)));
+               if msg.htlc_minimum_msat > config.channel_handshake_limits.max_htlc_minimum_msat {
+                       return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat,  config.channel_handshake_limits.max_htlc_minimum_msat)));
                }
-               if msg.max_htlc_value_in_flight_msat < config.peer_channel_config_limits.min_max_htlc_value_in_flight_msat {
-                       return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, config.peer_channel_config_limits.min_max_htlc_value_in_flight_msat)));
+               if msg.max_htlc_value_in_flight_msat < config.channel_handshake_limits.min_max_htlc_value_in_flight_msat {
+                       return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, config.channel_handshake_limits.min_max_htlc_value_in_flight_msat)));
                }
-               if msg.channel_reserve_satoshis > config.peer_channel_config_limits.max_channel_reserve_satoshis {
-                       return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, config.peer_channel_config_limits.max_channel_reserve_satoshis)));
+               if msg.channel_reserve_satoshis > config.channel_handshake_limits.max_channel_reserve_satoshis {
+                       return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, config.channel_handshake_limits.max_channel_reserve_satoshis)));
                }
-               if msg.max_accepted_htlcs < config.peer_channel_config_limits.min_max_accepted_htlcs {
-                       return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, config.peer_channel_config_limits.min_max_accepted_htlcs)));
+               if msg.max_accepted_htlcs < config.channel_handshake_limits.min_max_accepted_htlcs {
+                       return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, config.channel_handshake_limits.min_max_accepted_htlcs)));
                }
                if msg.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
                        return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
@@ -1181,13 +1200,11 @@ impl<Signer: Sign> Channel<Signer> {
 
                // Convert things into internal flags and prep our state:
 
-               if config.peer_channel_config_limits.force_announced_channel_preference {
-                       if local_config.announced_channel != announced_channel {
+               if config.channel_handshake_limits.force_announced_channel_preference {
+                       if config.channel_handshake_config.announced_channel != announced_channel {
                                return Err(ChannelError::Close("Peer tried to open channel but their announcement preference is different from ours".to_owned()));
                        }
                }
-               // we either accept their preference or the preferences match
-               local_config.announced_channel = announced_channel;
 
                let holder_selected_channel_reserve_satoshis = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis);
                if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
@@ -1239,7 +1256,7 @@ impl<Signer: Sign> Channel<Signer> {
                        }
                } else { None };
 
-               let shutdown_scriptpubkey = if config.channel_options.commit_upfront_shutdown_pubkey {
+               let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey {
                        Some(keys_provider.get_shutdown_scriptpubkey())
                } else { None };
 
@@ -1254,7 +1271,15 @@ impl<Signer: Sign> Channel<Signer> {
 
                let chan = Channel {
                        user_id,
-                       config: local_config,
+
+                       config: LegacyChannelConfig {
+                               options: config.channel_config.clone(),
+                               announced_channel,
+                               commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey,
+                       },
+
+                       prev_config: None,
+
                        inbound_handshake_limits_override: None,
 
                        channel_id: msg.temporary_channel_id,
@@ -1312,19 +1337,19 @@ impl<Signer: Sign> Channel<Signer> {
                        counterparty_dust_limit_satoshis: msg.dust_limit_satoshis,
                        holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
                        counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
-                       holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis, &config.own_channel_config),
+                       holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis, &config.channel_handshake_config),
                        counterparty_selected_channel_reserve_satoshis: Some(msg.channel_reserve_satoshis),
                        holder_selected_channel_reserve_satoshis,
                        counterparty_htlc_minimum_msat: msg.htlc_minimum_msat,
-                       holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
+                       holder_htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
                        counterparty_max_accepted_htlcs: msg.max_accepted_htlcs,
-                       minimum_depth: Some(cmp::max(config.own_channel_config.minimum_depth, 1)),
+                       minimum_depth: Some(cmp::max(config.channel_handshake_config.minimum_depth, 1)),
 
                        counterparty_forwarding_info: None,
 
                        channel_transaction_parameters: ChannelTransactionParameters {
                                holder_pubkeys: pubkeys,
-                               holder_selected_contest_delay: config.own_channel_config.our_to_self_delay,
+                               holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay,
                                is_outbound_from_holder: false,
                                counterparty_parameters: Some(CounterpartyChannelTransactionParameters {
                                        selected_contest_delay: msg.to_self_delay,
@@ -4011,7 +4036,7 @@ impl<Signer: Sign> Channel<Signer> {
                                // We always add force_close_avoidance_max_fee_satoshis to our normal
                                // feerate-calculated fee, but allow the max to be overridden if we're using a
                                // target feerate-calculated fee.
-                               cmp::max(normal_feerate as u64 * tx_weight / 1000 + self.config.force_close_avoidance_max_fee_satoshis,
+                               cmp::max(normal_feerate as u64 * tx_weight / 1000 + self.config.options.force_close_avoidance_max_fee_satoshis,
                                        proposed_max_feerate as u64 * tx_weight / 1000)
                        } else {
                                self.channel_value_satoshis - (self.value_to_self_msat + 999) / 1000
@@ -4471,15 +4496,93 @@ impl<Signer: Sign> Channel<Signer> {
        }
 
        pub fn get_fee_proportional_millionths(&self) -> u32 {
-               self.config.forwarding_fee_proportional_millionths
+               self.config.options.forwarding_fee_proportional_millionths
        }
 
        pub fn get_cltv_expiry_delta(&self) -> u16 {
-               cmp::max(self.config.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
+               cmp::max(self.config.options.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
        }
 
        pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 {
-               self.config.max_dust_htlc_exposure_msat
+               self.config.options.max_dust_htlc_exposure_msat
+       }
+
+       /// Returns the previous [`ChannelConfig`] applied to this channel, if any.
+       pub fn prev_config(&self) -> Option<ChannelConfig> {
+               self.prev_config.map(|prev_config| prev_config.0)
+       }
+
+       /// Tracks the number of ticks elapsed since the previous [`ChannelConfig`] was updated. Once
+       /// [`EXPIRE_PREV_CONFIG_TICKS`] is reached, the previous config is considered expired and will
+       /// no longer be considered when forwarding HTLCs.
+       pub fn maybe_expire_prev_config(&mut self) {
+               if self.prev_config.is_none() {
+                       return;
+               }
+               let prev_config = self.prev_config.as_mut().unwrap();
+               prev_config.1 += 1;
+               if prev_config.1 == EXPIRE_PREV_CONFIG_TICKS {
+                       self.prev_config = None;
+               }
+       }
+
+       /// Returns the current [`ChannelConfig`] applied to the channel.
+       pub fn config(&self) -> ChannelConfig {
+               self.config.options
+       }
+
+       /// Updates the channel's config. A bool is returned indicating whether the config update
+       /// applied resulted in a new ChannelUpdate message.
+       pub fn update_config(&mut self, config: &ChannelConfig) -> bool {
+               let did_channel_update =
+                       self.config.options.forwarding_fee_proportional_millionths != config.forwarding_fee_proportional_millionths ||
+                       self.config.options.forwarding_fee_base_msat != config.forwarding_fee_base_msat ||
+                       self.config.options.cltv_expiry_delta != config.cltv_expiry_delta;
+               if did_channel_update {
+                       self.prev_config = Some((self.config.options, 0));
+                       // Update the counter, which backs the ChannelUpdate timestamp, to allow the relay
+                       // policy change to propagate throughout the network.
+                       self.update_time_counter += 1;
+               }
+               self.config.options = *config;
+               did_channel_update
+       }
+
+       fn internal_htlc_satisfies_config(
+               &self, htlc: &msgs::UpdateAddHTLC, amt_to_forward: u64, outgoing_cltv_value: u32, config: &ChannelConfig,
+       ) -> Result<(), (&'static str, u16)> {
+               let fee = amt_to_forward.checked_mul(config.forwarding_fee_proportional_millionths as u64)
+                       .and_then(|prop_fee| (prop_fee / 1000000).checked_add(config.forwarding_fee_base_msat as u64));
+               if fee.is_none() || htlc.amount_msat < fee.unwrap() ||
+                       (htlc.amount_msat - fee.unwrap()) < amt_to_forward {
+                       return Err((
+                               "Prior hop has deviated from specified fees parameters or origin node has obsolete ones",
+                               0x1000 | 12, // fee_insufficient
+                       ));
+               }
+               if (htlc.cltv_expiry as u64) < outgoing_cltv_value as u64 + config.cltv_expiry_delta as u64 {
+                       return Err((
+                               "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
+                               0x1000 | 13, // incorrect_cltv_expiry
+                       ));
+               }
+               Ok(())
+       }
+
+       /// Determines whether the parameters of an incoming HTLC to be forwarded satisfy the channel's
+       /// [`ChannelConfig`]. This first looks at the channel's current [`ChannelConfig`], and if
+       /// unsuccessful, falls back to the previous one if one exists.
+       pub fn htlc_satisfies_config(
+               &self, htlc: &msgs::UpdateAddHTLC, amt_to_forward: u64, outgoing_cltv_value: u32,
+       ) -> Result<(), (&'static str, u16)> {
+               self.internal_htlc_satisfies_config(&htlc, amt_to_forward, outgoing_cltv_value, &self.config())
+                       .or_else(|err| {
+                               if let Some(prev_config) = self.prev_config() {
+                                       self.internal_htlc_satisfies_config(htlc, amt_to_forward, outgoing_cltv_value, &prev_config)
+                               } else {
+                                       Err(err)
+                               }
+                       })
        }
 
        pub fn get_feerate(&self) -> u32 {
@@ -4566,7 +4669,7 @@ impl<Signer: Sign> Channel<Signer> {
        /// Gets the fee we'd want to charge for adding an HTLC output to this Channel
        /// Allowed in any state (including after shutdown)
        pub fn get_outbound_forwarding_fee_base_msat(&self) -> u32 {
-               self.config.forwarding_fee_base_msat
+               self.config.options.forwarding_fee_base_msat
        }
 
        /// Returns true if we've ever received a message from the remote end for this Channel
@@ -4658,9 +4761,17 @@ impl<Signer: Sign> Channel<Signer> {
                } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurChannelReady as u32) {
                        // We got a reorg but not enough to trigger a force close, just ignore.
                        false
-               } else if self.channel_state < ChannelState::ChannelFunded as u32 {
-                       panic!("Started confirming a channel in a state pre-FundingSent?: {}", self.channel_state);
                } else {
+                       if self.channel_state < ChannelState::ChannelFunded as u32 {
+                               // We should never see a funding transaction on-chain until we've received
+                               // funding_signed (if we're an outbound channel), or seen funding_generated (if we're
+                               // an inbound channel - before that we have no known funding TXID). The fuzzer,
+                               // however, may do this and we shouldn't treat it as a bug.
+                               #[cfg(not(fuzzing))]
+                               panic!("Started confirming a channel in a state pre-FundingSent: {}.\n\
+                                       Do NOT broadcast a funding transaction manually - let LDK do it for you!",
+                                       self.channel_state);
+                       }
                        // We got a reorg but not enough to trigger a force close, just ignore.
                        false
                };
@@ -5979,7 +6090,7 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
                        if self.holder_selected_channel_reserve_satoshis != Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis)
                        { Some(self.holder_selected_channel_reserve_satoshis) } else { None };
 
-               let mut old_max_in_flight_percent_config = UserConfig::default().own_channel_config;
+               let mut old_max_in_flight_percent_config = UserConfig::default().channel_handshake_config;
                old_max_in_flight_percent_config.max_inbound_htlc_value_in_flight_percent_of_channel = MAX_IN_FLIGHT_PERCENT_LEGACY;
                let serialized_holder_htlc_max_in_flight =
                        if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis, &old_max_in_flight_percent_config)
@@ -6022,11 +6133,11 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
 
                let user_id = Readable::read(reader)?;
 
-               let mut config = Some(ChannelConfig::default());
+               let mut config = Some(LegacyChannelConfig::default());
                if ver == 1 {
                        // Read the old serialization of the ChannelConfig from version 0.0.98.
-                       config.as_mut().unwrap().forwarding_fee_proportional_millionths = Readable::read(reader)?;
-                       config.as_mut().unwrap().cltv_expiry_delta = Readable::read(reader)?;
+                       config.as_mut().unwrap().options.forwarding_fee_proportional_millionths = Readable::read(reader)?;
+                       config.as_mut().unwrap().options.cltv_expiry_delta = Readable::read(reader)?;
                        config.as_mut().unwrap().announced_channel = Readable::read(reader)?;
                        config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?;
                } else {
@@ -6252,7 +6363,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
                let mut target_closing_feerate_sats_per_kw = None;
                let mut monitor_pending_finalized_fulfills = Some(Vec::new());
                let mut holder_selected_channel_reserve_satoshis = Some(Self::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis));
-               let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &UserConfig::default().own_channel_config));
+               let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &UserConfig::default().channel_handshake_config));
                // Prior to supporting channel type negotiation, all of our channels were static_remotekey
                // only, so we default to that if none was written.
                let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key());
@@ -6322,6 +6433,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
 
                        config: config.unwrap(),
 
+                       prev_config: None,
+
                        // Note that we don't care about serializing handshake limits as we only ever serialize
                        // channel data after the handshake has completed.
                        inbound_handshake_limits_override: None,
@@ -6597,7 +6710,7 @@ mod tests {
                // Node B --> Node A: accept channel, explicitly setting B's dust limit.
                let mut accept_channel_msg = node_b_chan.accept_inbound_channel(0);
                accept_channel_msg.dust_limit_satoshis = 546;
-               node_a_chan.accept_channel(&accept_channel_msg, &config.peer_channel_config_limits, &InitFeatures::known()).unwrap();
+               node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &InitFeatures::known()).unwrap();
                node_a_chan.holder_dust_limit_satoshis = 1560;
 
                // Put some inbound and outbound HTLCs in A's channel.
@@ -6714,7 +6827,7 @@ mod tests {
 
                // Node B --> Node A: accept channel
                let accept_channel_msg = node_b_chan.accept_inbound_channel(0);
-               node_a_chan.accept_channel(&accept_channel_msg, &config.peer_channel_config_limits, &InitFeatures::known()).unwrap();
+               node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &InitFeatures::known()).unwrap();
 
                // Node A --> Node B: funding created
                let output_script = node_a_chan.get_funding_redeemscript();
@@ -6767,13 +6880,13 @@ mod tests {
                let inbound_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
 
                let mut config_2_percent = UserConfig::default();
-               config_2_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 2;
+               config_2_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 2;
                let mut config_99_percent = UserConfig::default();
-               config_99_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 99;
+               config_99_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 99;
                let mut config_0_percent = UserConfig::default();
-               config_0_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 0;
+               config_0_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 0;
                let mut config_101_percent = UserConfig::default();
-               config_101_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 101;
+               config_101_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 101;
 
                // Test that `new_outbound` creates a channel with the correct value for
                // `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value,
@@ -6918,7 +7031,7 @@ mod tests {
 
                let counterparty_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let mut config = UserConfig::default();
-               config.channel_options.announced_channel = false;
+               config.channel_handshake_config.announced_channel = false;
                let mut chan = Channel::<InMemorySigner>::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config, 0, 42).unwrap(); // Nothing uses their network key in this test
                chan.holder_dust_limit_satoshis = 546;
                chan.counterparty_selected_channel_reserve_satoshis = Some(0); // Filled in in accept_channel
index 0250efe220bab7b0cf48922daa4d6e08c154261b..54608e05e42bd8be9339273724a8f2115cf10b96 100644 (file)
@@ -51,7 +51,7 @@ use ln::onion_utils;
 use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT, OptionalField};
 use ln::wire::Encode;
 use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner, Recipient};
-use util::config::UserConfig;
+use util::config::{UserConfig, ChannelConfig};
 use util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
 use util::{byte_utils, events};
 use util::scid_utils::fake_scid;
@@ -870,7 +870,13 @@ pub(crate) const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 2 * 6 * 24 * 7;
 // the HTLC via a full update_fail_htlc/commitment_signed dance before we hit the
 // CLTV_CLAIM_BUFFER point (we static assert that it's at least 3 blocks more).
 pub const MIN_CLTV_EXPIRY_DELTA: u16 = 6*7;
-pub(super) const CLTV_FAR_FAR_AWAY: u32 = 6 * 24 * 7; //TODO?
+// This should be long enough to allow a payment path drawn across multiple routing hops with substantial
+// `cltv_expiry_delta`. Indeed, the length of those values is the reaction delay offered to a routing node
+// in case of HTLC on-chain settlement. While appearing less competitive, a node operator could decide to
+// scale them up to suit its security policy. At the network-level, we shouldn't constrain them too much,
+// while avoiding to introduce a DoS vector. Further, a low CTLV_FAR_FAR_AWAY could be a source of
+// routing failure for any HTLC sender picking up an LDK node among the first hops.
+pub(super) const CLTV_FAR_FAR_AWAY: u32 = 14 * 24 * 6;
 
 /// Minimum CLTV difference between the current block height and received inbound payments.
 /// Invoices generated for payment to us must set their `min_final_cltv_expiry` field to at least
@@ -1095,6 +1101,10 @@ pub struct ChannelDetails {
        pub inbound_htlc_minimum_msat: Option<u64>,
        /// The largest value HTLC (in msat) we currently will accept, for this channel.
        pub inbound_htlc_maximum_msat: Option<u64>,
+       /// Set of configurable parameters that affect channel operation.
+       ///
+       /// This field is only `None` for `ChannelDetails` objects serialized prior to LDK 0.0.109.
+       pub config: Option<ChannelConfig>,
 }
 
 impl ChannelDetails {
@@ -1759,7 +1769,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        is_usable: channel.is_live(),
                                        is_public: channel.should_announce(),
                                        inbound_htlc_minimum_msat: Some(channel.get_holder_htlc_minimum_msat()),
-                                       inbound_htlc_maximum_msat: channel.get_holder_htlc_maximum_msat()
+                                       inbound_htlc_maximum_msat: channel.get_holder_htlc_maximum_msat(),
+                                       config: Some(channel.config()),
                                });
                        }
                }
@@ -2213,7 +2224,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                },
                                                Some(id) => Some(id.clone()),
                                        };
-                                       let (chan_update_opt, forwardee_cltv_expiry_delta) = if let Some(forwarding_id) = forwarding_id_opt {
+                                       let chan_update_opt = if let Some(forwarding_id) = forwarding_id_opt {
                                                let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap();
                                                if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
                                                        // Note that the behavior here should be identical to the above block - we
@@ -2240,18 +2251,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                if *amt_to_forward < chan.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
                                                        break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
                                                }
-                                               let fee = amt_to_forward.checked_mul(chan.get_fee_proportional_millionths() as u64)
-                                                       .and_then(|prop_fee| { (prop_fee / 1000000)
-                                                       .checked_add(chan.get_outbound_forwarding_fee_base_msat() as u64) });
-                                               if fee.is_none() || msg.amount_msat < fee.unwrap() || (msg.amount_msat - fee.unwrap()) < *amt_to_forward { // fee_insufficient
-                                                       break Some(("Prior hop has deviated from specified fees parameters or origin node has obsolete ones", 0x1000 | 12, chan_update_opt));
+                                               if let Err((err, code)) = chan.htlc_satisfies_config(&msg, *amt_to_forward, *outgoing_cltv_value) {
+                                                       break Some((err, code, chan_update_opt));
+                                               }
+                                               chan_update_opt
+                                       } else {
+                                               if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 { // incorrect_cltv_expiry
+                                                       break Some((
+                                                               "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
+                                                               0x1000 | 13, None,
+                                                       ));
                                                }
-                                               (chan_update_opt, chan.get_cltv_expiry_delta())
-                                       } else { (None, MIN_CLTV_EXPIRY_DELTA) };
+                                               None
+                                       };
 
-                                       if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + forwardee_cltv_expiry_delta as u64 { // incorrect_cltv_expiry
-                                               break Some(("Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta", 0x1000 | 13, chan_update_opt));
-                                       }
                                        let cur_height = self.best_block.read().unwrap().height() + 1;
                                        // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
                                        // but we want to be robust wrt to counterparty packet sanitization (see
@@ -2517,12 +2530,6 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                if route.paths.len() < 1 {
                        return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
                }
-               if route.paths.len() > 10 {
-                       // This limit is completely arbitrary - there aren't any real fundamental path-count
-                       // limits. After we support retrying individual paths we should likely bump this, but
-                       // for now more than 10 paths likely carries too much one-path failure.
-                       return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Sending over more than 10 paths is not currently supported"}));
-               }
                if payment_secret.is_none() && route.paths.len() > 1 {
                        return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError{err: "Payment secret is required for multi-path payments".to_string()}));
                }
@@ -2771,6 +2778,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        /// Returns an [`APIError::APIMisuseError`] if the funding_transaction spent non-SegWit outputs
        /// or if no output was found which matches the parameters in [`Event::FundingGenerationReady`].
        ///
+       /// Returns [`APIError::APIMisuseError`] if the funding transaction is not final for propagation
+       /// across the p2p network.
+       ///
        /// Returns [`APIError::ChannelUnavailable`] if a funding transaction has already been provided
        /// for the channel or if the channel has been closed as indicated by [`Event::ChannelClosed`].
        ///
@@ -2786,6 +2796,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        /// not currently support replacing a funding transaction on an existing channel. Instead,
        /// create a new channel with a conflicting funding transaction.
        ///
+       /// Note to keep the miner incentives aligned in moving the blockchain forward, we recommend
+       /// the wallet software generating the funding transaction to apply anti-fee sniping as
+       /// implemented by Bitcoin Core wallet. See <https://bitcoinops.org/en/topics/fee-sniping/>
+       /// for more details.
+       ///
        /// [`Event::FundingGenerationReady`]: crate::util::events::Event::FundingGenerationReady
        /// [`Event::ChannelClosed`]: crate::util::events::Event::ChannelClosed
        pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, funding_transaction: Transaction) -> Result<(), APIError> {
@@ -2798,6 +2813,18 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                });
                        }
                }
+               {
+                       let height = self.best_block.read().unwrap().height();
+                       // Transactions are evaluated as final by network mempools at the next block. However, the modules
+                       // constituting our Lightning node might not have perfect sync about their blockchain views. Thus, if
+                       // the wallet module is in advance on the LDK view, allow one more block of headroom.
+                       // TODO: updated if/when https://github.com/rust-bitcoin/rust-bitcoin/pull/994 landed and rust-bitcoin bumped.
+                       if !funding_transaction.input.iter().all(|input| input.sequence == 0xffffffff) && funding_transaction.lock_time < 500_000_000 && funding_transaction.lock_time > height + 2 {
+                               return Err(APIError::APIMisuseError {
+                                       err: "Funding transaction absolute timelock is non-final".to_owned()
+                               });
+                       }
+               }
                self.funding_transaction_generated_intern(temporary_channel_id, counterparty_node_id, funding_transaction, |chan, tx| {
                        let mut output_index = None;
                        let expected_spk = chan.get_funding_redeemscript().to_v0_p2wsh();
@@ -2908,6 +2935,73 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                }
        }
 
+       /// 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> {
+               if config.cltv_expiry_delta < MIN_CLTV_EXPIRY_DELTA {
+                       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 mut channel_state_lock = self.channel_state.lock().unwrap();
+                       let channel_state = &mut *channel_state_lock;
+                       for channel_id in channel_ids {
+                               let channel_counterparty_node_id = channel_state.by_id.get(channel_id)
+                                       .ok_or(APIError::ChannelUnavailable {
+                                               err: format!("Channel with ID {} was not found", log_bytes!(*channel_id)),
+                                       })?
+                                       .get_counterparty_node_id();
+                               if channel_counterparty_node_id != *counterparty_node_id {
+                                       return Err(APIError::APIMisuseError {
+                                               err: "counterparty node id mismatch".to_owned(),
+                                       });
+                               }
+                       }
+                       for channel_id in channel_ids {
+                               let channel = channel_state.by_id.get_mut(channel_id).unwrap();
+                               if !channel.update_config(config) {
+                                       continue;
+                               }
+                               if let Ok(msg) = self.get_channel_update_for_broadcast(channel) {
+                                       channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate { msg });
+                               } else if let Ok(msg) = self.get_channel_update_for_unicast(channel) {
+                                       channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
+                                               node_id: channel.get_counterparty_node_id(),
+                                               msg,
+                                       });
+                               }
+                       }
+               }
+               Ok(())
+       }
+
        /// Processes HTLCs which are pending waiting on random forward delay.
        ///
        /// Should only really ever be called in response to a PendingHTLCsForwardable event.
@@ -3433,6 +3527,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        ///  * Broadcasting `ChannelUpdate` messages if we've been disconnected from our peer for more
        ///    than a minute, informing the network that they should no longer attempt to route over
        ///    the channel.
+       ///  * Expiring a channel's previous `ChannelConfig` if necessary to only allow forwarding HTLCs
+       ///    with the current `ChannelConfig`.
        ///
        /// Note that this may cause reentrancy through `chain::Watch::update_channel` calls or feerate
        /// estimate fetches.
@@ -3491,6 +3587,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                _ => {},
                                        }
 
+                                       chan.maybe_expire_prev_config();
+
                                        true
                                });
 
@@ -3608,7 +3706,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        // Fail a list of HTLCs that were just freed from the holding cell. The HTLCs need to be
        // failed backwards or, if they were one of our outgoing HTLCs, then their failure needs to
        // be surfaced to the user.
-       fn fail_holding_cell_htlcs(&self, mut htlcs_to_fail: Vec<(HTLCSource, PaymentHash)>, channel_id: [u8; 32]) {
+       fn fail_holding_cell_htlcs(
+               &self, mut htlcs_to_fail: Vec<(HTLCSource, PaymentHash)>, channel_id: [u8; 32],
+               _counterparty_node_id: &PublicKey
+       ) {
                for (htlc_src, payment_hash) in htlcs_to_fail.drain(..) {
                        match htlc_src {
                                HTLCSource::PreviousHopData(HTLCPreviousHopData { .. }) => {
@@ -4337,7 +4438,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        if chan.get().get_counterparty_node_id() != *counterparty_node_id {
                                                return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.temporary_channel_id));
                                        }
-                                       try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration.peer_channel_config_limits, &their_features), channel_state, chan);
+                                       try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration.channel_handshake_limits, &their_features), channel_state, chan);
                                        (chan.get().get_value_satoshis(), chan.get().get_funding_redeemscript().to_v0_p2wsh(), chan.get().get_user_id())
                                },
                                hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.temporary_channel_id))
@@ -4816,7 +4917,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                hash_map::Entry::Vacant(_) => break Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
                        }
                };
-               self.fail_holding_cell_htlcs(htlcs_to_fail, msg.channel_id);
+               self.fail_holding_cell_htlcs(htlcs_to_fail, msg.channel_id, counterparty_node_id);
                match res {
                        Ok((pending_forwards, mut pending_failures, finalized_claim_htlcs,
                                short_channel_id, channel_outpoint)) =>
@@ -4956,7 +5057,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                        }
                };
                post_handle_chan_restoration!(self, chan_restoration_res);
-               self.fail_holding_cell_htlcs(htlcs_failed_forward, msg.channel_id);
+               self.fail_holding_cell_htlcs(htlcs_failed_forward, msg.channel_id, counterparty_node_id);
 
                if let Some(channel_ready_msg) = need_lnd_workaround {
                        self.internal_channel_ready(counterparty_node_id, &channel_ready_msg)?;
@@ -5054,7 +5155,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                match chan.maybe_free_holding_cell_htlcs(&self.logger) {
                                        Ok((commitment_opt, holding_cell_failed_htlcs)) => {
                                                if !holding_cell_failed_htlcs.is_empty() {
-                                                       failed_htlcs.push((holding_cell_failed_htlcs, *channel_id));
+                                                       failed_htlcs.push((
+                                                               holding_cell_failed_htlcs,
+                                                               *channel_id,
+                                                               chan.get_counterparty_node_id()
+                                                       ));
                                                }
                                                if let Some((commitment_update, monitor_update)) = commitment_opt {
                                                        if let Err(e) = self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) {
@@ -5082,8 +5187,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                }
 
                let has_update = has_monitor_update || !failed_htlcs.is_empty() || !handle_errors.is_empty();
-               for (failures, channel_id) in failed_htlcs.drain(..) {
-                       self.fail_holding_cell_htlcs(failures, channel_id);
+               for (failures, channel_id, counterparty_node_id) in failed_htlcs.drain(..) {
+                       self.fail_holding_cell_htlcs(failures, channel_id, &counterparty_node_id);
                }
 
                for (counterparty_node_id, err) in handle_errors.drain(..) {
@@ -6076,6 +6181,7 @@ impl_writeable_tlv_based!(ChannelDetails, {
        (4, counterparty, required),
        (5, outbound_scid_alias, option),
        (6, funding_txo, option),
+       (7, config, option),
        (8, short_channel_id, option),
        (10, channel_value_satoshis, required),
        (12, unspendable_punishment_reserve, option),
@@ -7346,8 +7452,8 @@ mod tests {
                        final_cltv_expiry_delta: TEST_FINAL_CLTV,
                };
                let route = find_route(
-                       &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
-                       nodes[0].logger, &scorer, &random_seed_bytes
+                       &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph.read_only(),
+                       None, nodes[0].logger, &scorer, &random_seed_bytes
                ).unwrap();
                nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
                check_added_monitors!(nodes[0], 1);
@@ -7377,8 +7483,8 @@ mod tests {
                // To start (2), send a keysend payment but don't claim it.
                let payment_preimage = PaymentPreimage([42; 32]);
                let route = find_route(
-                       &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
-                       nodes[0].logger, &scorer, &random_seed_bytes
+                       &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph.read_only(),
+                       None, nodes[0].logger, &scorer, &random_seed_bytes
                ).unwrap();
                let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
                check_added_monitors!(nodes[0], 1);
@@ -7441,8 +7547,9 @@ mod tests {
                let scorer = test_utils::TestScorer::with_penalty(0);
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
-                       &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
-                       nodes[0].logger, &scorer, &random_seed_bytes
+                       &payer_pubkey, &route_params, &network_graph.read_only(),
+                       Some(&first_hops.iter().collect::<Vec<_>>()), nodes[0].logger, &scorer,
+                       &random_seed_bytes
                ).unwrap();
 
                let test_preimage = PaymentPreimage([42; 32]);
@@ -7485,8 +7592,9 @@ mod tests {
                let scorer = test_utils::TestScorer::with_penalty(0);
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
-                       &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
-                       nodes[0].logger, &scorer, &random_seed_bytes
+                       &payer_pubkey, &route_params, &network_graph.read_only(),
+                       Some(&first_hops.iter().collect::<Vec<_>>()), nodes[0].logger, &scorer,
+                       &random_seed_bytes
                ).unwrap();
 
                let test_preimage = PaymentPreimage([42; 32]);
@@ -7615,7 +7723,7 @@ pub mod bench {
                let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
 
                let mut config: UserConfig = Default::default();
-               config.own_channel_config.minimum_depth = 1;
+               config.channel_handshake_config.minimum_depth = 1;
 
                let logger_a = test_utils::TestLogger::with_id("node a".to_owned());
                let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a);
@@ -7678,7 +7786,7 @@ pub mod bench {
                        _ => panic!(),
                }
 
-               let dummy_graph = NetworkGraph::new(genesis_hash);
+               let dummy_graph = NetworkGraph::new(genesis_hash, &logger_a);
 
                let mut payment_count: u64 = 0;
                macro_rules! send_payment {
index 775e070ed76798d4082a77e097fb0d770568b3b0..dbc17a34138b04b59ca9207b574494c9a8485009 100644 (file)
 //! supports a feature if it advertises the feature (as either required or optional) to its peers.
 //! And the implementation can interpret a feature if the feature is known to it.
 //!
+//! The following features are currently required in the LDK:
+//! - `VariableLengthOnion` - requires/supports variable-length routing onion payloads
+//!     (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md) for more information).
+//! - `StaticRemoteKey` - requires/supports static key for remote output
+//!     (see [BOLT-3](https://github.com/lightning/bolts/blob/master/03-transactions.md) for more information).
+//!
+//! The following features are currently supported in the LDK:
+//! - `DataLossProtect` - requires/supports that a node which has somehow fallen behind, e.g., has been restored from an old backup,
+//!     can detect that it has fallen behind
+//!     (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
+//! - `InitialRoutingSync` - requires/supports that the sending node needs a complete routing information dump
+//!     (see [BOLT-7](https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#initial-sync) for more information).
+//! - `UpfrontShutdownScript` - commits to a shutdown scriptpubkey when opening a channel
+//!     (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-open_channel-message) for more information).
+//! - `GossipQueries` - requires/supports more sophisticated gossip control
+//!     (see [BOLT-7](https://github.com/lightning/bolts/blob/master/07-routing-gossip.md) for more information).
+//! - `PaymentSecret` - requires/supports that a node supports payment_secret field
+//!     (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md) for more information).
+//! - `BasicMPP` - requires/supports that a node can receive basic multi-part payments
+//!     (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md#basic-multi-part-payments) for more information).
+//! - `ShutdownAnySegwit` - requires/supports that future segwit versions are allowed in `shutdown`
+//!     (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
+//! - `ChannelType` - node supports the channel_type field in open/accept
+//!     (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
+//! - `SCIDPrivacy` - supply channel aliases for routing
+//!     (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
+//! - `Keysend` - send funds to a node without an invoice
+//!     (see the [`Keysend` feature assignment proposal](https://github.com/lightning/bolts/issues/605#issuecomment-606679798) for more information).
+//!
 //! [BOLT #9]: https://github.com/lightning/bolts/blob/master/09-features.md
 //! [messages]: crate::ln::msgs
 
index 594f02fc52e040e4981c312c8b2cf0e93078d08d..fe78395e2f97e685698968b0053d44dbc8a772ce 100644 (file)
@@ -15,7 +15,7 @@ use chain::channelmonitor::ChannelMonitor;
 use chain::transaction::OutPoint;
 use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
 use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId, MIN_CLTV_EXPIRY_DELTA};
-use routing::gossip::{P2PGossipSync, NetworkGraph};
+use routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
 use routing::router::{PaymentParameters, Route, get_route};
 use ln::features::{InitFeatures, InvoiceFeatures};
 use ln::msgs;
@@ -27,7 +27,7 @@ use util::test_utils::{panicking, TestChainMonitor};
 use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
 use util::errors::APIError;
 use util::config::UserConfig;
-use util::ser::{ReadableArgs, Writeable, Readable};
+use util::ser::{ReadableArgs, Writeable};
 
 use bitcoin::blockdata::block::{Block, BlockHeader};
 use bitcoin::blockdata::constants::genesis_block;
@@ -257,7 +257,6 @@ pub struct TestChanMonCfg {
        pub persister: test_utils::TestPersister,
        pub logger: test_utils::TestLogger,
        pub keys_manager: test_utils::TestKeysInterface,
-       pub network_graph: NetworkGraph,
 }
 
 pub struct NodeCfg<'a> {
@@ -267,7 +266,7 @@ pub struct NodeCfg<'a> {
        pub chain_monitor: test_utils::TestChainMonitor<'a>,
        pub keys_manager: &'a test_utils::TestKeysInterface,
        pub logger: &'a test_utils::TestLogger,
-       pub network_graph: &'a NetworkGraph,
+       pub network_graph: NetworkGraph<&'a test_utils::TestLogger>,
        pub node_seed: [u8; 32],
        pub features: InitFeatures,
 }
@@ -278,8 +277,8 @@ pub struct Node<'a, 'b: 'a, 'c: 'b> {
        pub chain_monitor: &'b test_utils::TestChainMonitor<'c>,
        pub keys_manager: &'b test_utils::TestKeysInterface,
        pub node: &'a ChannelManager<EnforcingSigner, &'b TestChainMonitor<'c>, &'c test_utils::TestBroadcaster, &'b test_utils::TestKeysInterface, &'c test_utils::TestFeeEstimator, &'c test_utils::TestLogger>,
-       pub network_graph: &'c NetworkGraph,
-       pub gossip_sync: P2PGossipSync<&'c NetworkGraph, &'c test_utils::TestChainSource, &'c test_utils::TestLogger>,
+       pub network_graph: &'b NetworkGraph<&'c test_utils::TestLogger>,
+       pub gossip_sync: P2PGossipSync<&'b NetworkGraph<&'c test_utils::TestLogger>, &'c test_utils::TestChainSource, &'c test_utils::TestLogger>,
        pub node_seed: [u8; 32],
        pub network_payment_count: Rc<RefCell<u8>>,
        pub network_chan_count: Rc<RefCell<u32>>,
@@ -311,7 +310,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
                        {
                                let mut w = test_utils::TestVecWriter(Vec::new());
                                self.network_graph.write(&mut w).unwrap();
-                               let network_graph_deser = <NetworkGraph>::read(&mut io::Cursor::new(&w.0)).unwrap();
+                               let network_graph_deser = <NetworkGraph<_>>::read(&mut io::Cursor::new(&w.0), self.logger).unwrap();
                                assert!(network_graph_deser == *self.network_graph);
                                let gossip_sync = P2PGossipSync::new(
                                        &network_graph_deser, Some(self.chain_source), self.logger
@@ -773,7 +772,7 @@ pub fn create_announced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a
 
 pub fn create_unannounced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize, channel_value: u64, push_msat: u64, a_flags: InitFeatures, b_flags: InitFeatures) -> (msgs::ChannelReady, Transaction) {
        let mut no_announce_cfg = test_default_channel_config();
-       no_announce_cfg.channel_options.announced_channel = false;
+       no_announce_cfg.channel_handshake_config.announced_channel = false;
        nodes[a].node.create_channel(nodes[b].node.get_our_node_id(), channel_value, push_msat, 42, Some(no_announce_cfg)).unwrap();
        let open_channel = get_event_msg!(nodes[a], MessageSendEvent::SendOpenChannel, nodes[b].node.get_our_node_id());
        nodes[b].node.handle_open_channel(&nodes[a].node.get_our_node_id(), a_flags, &open_channel);
@@ -1467,8 +1466,10 @@ impl<'a> PaymentFailedConditions<'a> {
 #[cfg(test)]
 macro_rules! expect_payment_failed_with_update {
        ($node: expr, $expected_payment_hash: expr, $rejected_by_dest: expr, $scid: expr, $chan_closed: expr) => {
-               expect_payment_failed_conditions!($node, $expected_payment_hash, $rejected_by_dest,
-                       $crate::ln::functional_test_utils::PaymentFailedConditions::new().blamed_scid($scid).blamed_chan_closed($chan_closed));
+               $crate::ln::functional_test_utils::expect_payment_failed_conditions(
+                       &$node, $expected_payment_hash, $rejected_by_dest,
+                       $crate::ln::functional_test_utils::PaymentFailedConditions::new()
+                               .blamed_scid($scid).blamed_chan_closed($chan_closed));
        }
 }
 
@@ -1480,64 +1481,72 @@ macro_rules! expect_payment_failed {
                $(
                        conditions = conditions.expected_htlc_error_data($expected_error_code, &$expected_error_data);
                )*
-               expect_payment_failed_conditions!($node, $expected_payment_hash, $rejected_by_dest, conditions);
+               $crate::ln::functional_test_utils::expect_payment_failed_conditions(&$node, $expected_payment_hash, $rejected_by_dest, conditions);
        };
 }
 
-#[cfg(test)]
-macro_rules! expect_payment_failed_conditions {
-       ($node: expr, $expected_payment_hash: expr, $rejected_by_dest: expr, $conditions: expr) => {
-               let events = $node.node.get_and_clear_pending_events();
-               assert_eq!(events.len(), 1);
-               let expected_payment_id = match events[0] {
-                       Event::PaymentPathFailed { ref payment_hash, rejected_by_dest, ref error_code, ref error_data, ref path, ref retry, ref payment_id, ref network_update, .. } => {
-                               assert_eq!(*payment_hash, $expected_payment_hash, "unexpected payment_hash");
-                               assert_eq!(rejected_by_dest, $rejected_by_dest, "unexpected rejected_by_dest value");
-                               assert!(retry.is_some(), "expected retry.is_some()");
-                               assert_eq!(retry.as_ref().unwrap().final_value_msat, path.last().unwrap().fee_msat, "Retry amount should match last hop in path");
-                               assert_eq!(retry.as_ref().unwrap().payment_params.payee_pubkey, path.last().unwrap().pubkey, "Retry payee node_id should match last hop in path");
-
+pub fn expect_payment_failed_conditions<'a, 'b, 'c, 'd, 'e>(
+       node: &'a Node<'b, 'c, 'd>, expected_payment_hash: PaymentHash, expected_rejected_by_dest: bool,
+       conditions: PaymentFailedConditions<'e>
+) {
+       let mut events = node.node.get_and_clear_pending_events();
+       assert_eq!(events.len(), 1);
+       let expected_payment_id = match events.pop().unwrap() {
+               Event::PaymentPathFailed { payment_hash, rejected_by_dest, path, retry, payment_id, network_update,
+                       #[cfg(test)]
+                       error_code,
+                       #[cfg(test)]
+                       error_data, .. } => {
+                       assert_eq!(payment_hash, expected_payment_hash, "unexpected payment_hash");
+                       assert_eq!(rejected_by_dest, expected_rejected_by_dest, "unexpected rejected_by_dest value");
+                       assert!(retry.is_some(), "expected retry.is_some()");
+                       assert_eq!(retry.as_ref().unwrap().final_value_msat, path.last().unwrap().fee_msat, "Retry amount should match last hop in path");
+                       assert_eq!(retry.as_ref().unwrap().payment_params.payee_pubkey, path.last().unwrap().pubkey, "Retry payee node_id should match last hop in path");
+
+                       #[cfg(test)]
+                       {
                                assert!(error_code.is_some(), "expected error_code.is_some() = true");
                                assert!(error_data.is_some(), "expected error_data.is_some() = true");
-                               if let Some((code, data)) = $conditions.expected_htlc_error_data {
+                               if let Some((code, data)) = conditions.expected_htlc_error_data {
                                        assert_eq!(error_code.unwrap(), code, "unexpected error code");
                                        assert_eq!(&error_data.as_ref().unwrap()[..], data, "unexpected error data");
                                }
+                       }
 
-                               if let Some(chan_closed) = $conditions.expected_blamed_chan_closed {
-                                       match network_update {
-                                               &Some($crate::routing::gossip::NetworkUpdate::ChannelUpdateMessage { ref msg }) if !chan_closed => {
-                                                       if let Some(scid) = $conditions.expected_blamed_scid {
-                                                               assert_eq!(msg.contents.short_channel_id, scid);
-                                                       }
-                                                       assert_eq!(msg.contents.flags & 2, 0);
-                                               },
-                                               &Some($crate::routing::gossip::NetworkUpdate::ChannelFailure { short_channel_id, is_permanent }) if chan_closed => {
-                                                       if let Some(scid) = $conditions.expected_blamed_scid {
-                                                               assert_eq!(short_channel_id, scid);
-                                                       }
-                                                       assert!(is_permanent);
-                                               },
-                                               Some(_) => panic!("Unexpected update type"),
-                                               None => panic!("Expected update"),
-                                       }
+                       if let Some(chan_closed) = conditions.expected_blamed_chan_closed {
+                               match network_update {
+                                       Some(NetworkUpdate::ChannelUpdateMessage { ref msg }) if !chan_closed => {
+                                               if let Some(scid) = conditions.expected_blamed_scid {
+                                                       assert_eq!(msg.contents.short_channel_id, scid);
+                                               }
+                                               const CHAN_DISABLED_FLAG: u8 = 2;
+                                               assert_eq!(msg.contents.flags & CHAN_DISABLED_FLAG, 0);
+                                       },
+                                       Some(NetworkUpdate::ChannelFailure { short_channel_id, is_permanent }) if chan_closed => {
+                                               if let Some(scid) = conditions.expected_blamed_scid {
+                                                       assert_eq!(short_channel_id, scid);
+                                               }
+                                               assert!(is_permanent);
+                                       },
+                                       Some(_) => panic!("Unexpected update type"),
+                                       None => panic!("Expected update"),
                                }
+                       }
 
-                               payment_id.unwrap()
-                       },
-                       _ => panic!("Unexpected event"),
-               };
-               if !$conditions.expected_mpp_parts_remain {
-                       $node.node.abandon_payment(expected_payment_id);
-                       let events = $node.node.get_and_clear_pending_events();
-                       assert_eq!(events.len(), 1);
-                       match events[0] {
-                               Event::PaymentFailed { ref payment_hash, ref payment_id } => {
-                                       assert_eq!(*payment_hash, $expected_payment_hash, "unexpected second payment_hash");
-                                       assert_eq!(*payment_id, expected_payment_id);
-                               }
-                               _ => panic!("Unexpected second event"),
+                       payment_id.unwrap()
+               },
+               _ => panic!("Unexpected event"),
+       };
+       if !conditions.expected_mpp_parts_remain {
+               node.node.abandon_payment(expected_payment_id);
+               let events = node.node.get_and_clear_pending_events();
+               assert_eq!(events.len(), 1);
+               match events[0] {
+                       Event::PaymentFailed { ref payment_hash, ref payment_id } => {
+                               assert_eq!(*payment_hash, expected_payment_hash, "unexpected second payment_hash");
+                               assert_eq!(*payment_id, expected_payment_id);
                        }
+                       _ => panic!("Unexpected second event"),
                }
        }
 }
@@ -1680,7 +1689,16 @@ pub fn do_claim_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>,
                        ($node: expr, $prev_node: expr, $next_node: expr, $new_msgs: expr) => {
                                {
                                        $node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0);
-                                       let fee = $node.node.channel_state.lock().unwrap().by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap().config.forwarding_fee_base_msat;
+                                       let fee = {
+                                               let channel_state = $node.node.channel_state.lock().unwrap();
+                                               let channel = channel_state
+                                                       .by_id.get(&next_msgs.as_ref().unwrap().0.channel_id).unwrap();
+                                               if let Some(prev_config) = channel.prev_config() {
+                                                       prev_config.forwarding_fee_base_msat
+                                               } else {
+                                                       channel.config().forwarding_fee_base_msat
+                                               }
+                                       };
                                        expect_payment_forwarded!($node, $next_node, $prev_node, Some(fee as u64), false, false);
                                        expected_total_fee_msat += fee as u64;
                                        check_added_monitors!($node, 1);
@@ -1923,9 +1941,8 @@ pub fn create_chanmon_cfgs(node_count: usize) -> Vec<TestChanMonCfg> {
                let persister = test_utils::TestPersister::new();
                let seed = [i as u8; 32];
                let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
-               let network_graph = NetworkGraph::new(chain_source.genesis_hash);
 
-               chan_mon_cfgs.push(TestChanMonCfg{ tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager, network_graph });
+               chan_mon_cfgs.push(TestChanMonCfg{ tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager });
        }
 
        chan_mon_cfgs
@@ -1946,7 +1963,7 @@ pub fn create_node_cfgs<'a>(node_count: usize, chanmon_cfgs: &'a Vec<TestChanMon
                        keys_manager: &chanmon_cfgs[i].keys_manager,
                        node_seed: seed,
                        features: InitFeatures::known(),
-                       network_graph: &chanmon_cfgs[i].network_graph,
+                       network_graph: NetworkGraph::new(chanmon_cfgs[i].chain_source.genesis_hash, &chanmon_cfgs[i].logger),
                });
        }
 
@@ -1957,15 +1974,15 @@ pub fn test_default_channel_config() -> UserConfig {
        let mut default_config = UserConfig::default();
        // Set cltv_expiry_delta slightly lower to keep the final CLTV values inside one byte in our
        // tests so that our script-length checks don't fail (see ACCEPTED_HTLC_SCRIPT_WEIGHT).
-       default_config.channel_options.cltv_expiry_delta = MIN_CLTV_EXPIRY_DELTA;
-       default_config.channel_options.announced_channel = true;
-       default_config.peer_channel_config_limits.force_announced_channel_preference = false;
+       default_config.channel_config.cltv_expiry_delta = MIN_CLTV_EXPIRY_DELTA;
+       default_config.channel_handshake_config.announced_channel = true;
+       default_config.channel_handshake_limits.force_announced_channel_preference = false;
        // When most of our tests were written, the default HTLC minimum was fixed at 1000.
        // It now defaults to 1, so we simply set it to the expected value here.
-       default_config.own_channel_config.our_htlc_minimum_msat = 1000;
+       default_config.channel_handshake_config.our_htlc_minimum_msat = 1000;
        // When most of our tests were written, we didn't have the notion of a `max_dust_htlc_exposure_msat`,
        // It now defaults to 5_000_000 msat; to avoid interfering with tests we bump it to 50_000_000 msat.
-       default_config.channel_options.max_dust_htlc_exposure_msat = 50_000_000;
+       default_config.channel_config.max_dust_htlc_exposure_msat = 50_000_000;
        default_config
 }
 
@@ -1992,7 +2009,7 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
        let connect_style = Rc::new(RefCell::new(ConnectStyle::random_style()));
 
        for i in 0..node_count {
-               let gossip_sync = P2PGossipSync::new(cfgs[i].network_graph, None, cfgs[i].logger);
+               let gossip_sync = P2PGossipSync::new(&cfgs[i].network_graph, None, cfgs[i].logger);
                nodes.push(Node{
                        chain_source: cfgs[i].chain_source, tx_broadcaster: cfgs[i].tx_broadcaster,
                        chain_monitor: &cfgs[i].chain_monitor, keys_manager: &cfgs[i].keys_manager,
index c7365452d67e5a7d80fb2661f48bcfb7adefbc67..02ef5f37b9b2866c182e1773968002a8851b94b1 100644 (file)
@@ -23,6 +23,7 @@ use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, PaymentId, RAAC
 use ln::channel::{Channel, ChannelError};
 use ln::{chan_utils, onion_utils};
 use ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
+use routing::gossip::NetworkGraph;
 use routing::router::{PaymentParameters, Route, RouteHop, RouteParameters, find_route, get_route};
 use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
 use ln::msgs;
@@ -40,6 +41,8 @@ use bitcoin::blockdata::script::Builder;
 use bitcoin::blockdata::opcodes;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::network::constants::Network;
+use bitcoin::{Transaction, TxIn, TxOut, Witness};
+use bitcoin::OutPoint as BitcoinOutPoint;
 
 use bitcoin::secp256k1::Secp256k1;
 use bitcoin::secp256k1::{PublicKey,SecretKey};
@@ -60,7 +63,7 @@ fn test_insane_channel_opens() {
        // Stand up a network of 2 nodes
        use ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
        let mut cfg = UserConfig::default();
-       cfg.peer_channel_config_limits.max_funding_satoshis = TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1;
+       cfg.channel_handshake_limits.max_funding_satoshis = TOTAL_BITCOIN_SUPPLY_SATOSHIS + 1;
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(cfg)]);
@@ -1789,7 +1792,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
        // When this test was written, the default base fee floated based on the HTLC count.
        // It is now fixed, so we simply set the fee to the expected value here.
        let mut config = test_default_channel_config();
-       config.channel_options.forwarding_fee_base_msat = 239;
+       config.channel_config.forwarding_fee_base_msat = 239;
        let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config.clone()), Some(config.clone()), Some(config.clone())]);
        let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
        let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 190000, 1001, InitFeatures::known(), InitFeatures::known());
@@ -2361,13 +2364,13 @@ fn channel_monitor_network_test() {
 fn test_justice_tx() {
        // Test justice txn built on revoked HTLC-Success tx, against both sides
        let mut alice_config = UserConfig::default();
-       alice_config.channel_options.announced_channel = true;
-       alice_config.peer_channel_config_limits.force_announced_channel_preference = false;
-       alice_config.own_channel_config.our_to_self_delay = 6 * 24 * 5;
+       alice_config.channel_handshake_config.announced_channel = true;
+       alice_config.channel_handshake_limits.force_announced_channel_preference = false;
+       alice_config.channel_handshake_config.our_to_self_delay = 6 * 24 * 5;
        let mut bob_config = UserConfig::default();
-       bob_config.channel_options.announced_channel = true;
-       bob_config.peer_channel_config_limits.force_announced_channel_preference = false;
-       bob_config.own_channel_config.our_to_self_delay = 6 * 24 * 3;
+       bob_config.channel_handshake_config.announced_channel = true;
+       bob_config.channel_handshake_limits.force_announced_channel_preference = false;
+       bob_config.channel_handshake_config.our_to_self_delay = 6 * 24 * 3;
        let user_cfgs = [Some(alice_config), Some(bob_config)];
        let mut chanmon_cfgs = create_chanmon_cfgs(2);
        chanmon_cfgs[0].keys_manager.disable_revocation_policy_check = true;
@@ -2514,10 +2517,10 @@ fn claim_htlc_outputs_shared_tx() {
        let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
 
        // Rebalance the network to generate htlc in the two directions
-       send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
+       send_payment(&nodes[0], &[&nodes[1]], 8_000_000);
        // node[0] is gonna to revoke an old state thus node[1] should be able to claim both offered/received HTLC outputs on top of commitment tx
-       let payment_preimage_1 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
-       let (_payment_preimage_2, payment_hash_2, _) = route_payment(&nodes[1], &vec!(&nodes[0])[..], 3000000);
+       let payment_preimage_1 = route_payment(&nodes[0], &[&nodes[1]], 3_000_000).0;
+       let (_payment_preimage_2, payment_hash_2, _) = route_payment(&nodes[1], &[&nodes[0]], 3_000_000);
 
        // Get the will-be-revoked local txn from node[0]
        let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan_1.2);
@@ -2540,9 +2543,9 @@ fn claim_htlc_outputs_shared_tx() {
                check_added_monitors!(nodes[1], 1);
                check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
                connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
-               expect_payment_failed!(nodes[1], payment_hash_2, true);
+               assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
 
-               let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
+               let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
                assert_eq!(node_txn.len(), 2); // ChannelMonitor: penalty tx, ChannelManager: local commitment
 
                assert_eq!(node_txn[0].input.len(), 3); // Claim the revoked output + both revoked HTLC outputs
@@ -2559,7 +2562,13 @@ fn claim_htlc_outputs_shared_tx() {
 
                // Next nodes[1] broadcasts its current local tx state:
                assert_eq!(node_txn[1].input.len(), 1);
-               assert_eq!(node_txn[1].input[0].previous_output.txid, chan_1.3.txid()); //Spending funding tx unique txouput, tx broadcasted by ChannelManager
+               check_spends!(node_txn[1], chan_1.3);
+
+               // Finally, mine the penalty transaction and check that we get an HTLC failure after
+               // ANTI_REORG_DELAY confirmations.
+               mine_transaction(&nodes[1], &node_txn[0]);
+               connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+               expect_payment_failed!(nodes[1], payment_hash_2, true);
        }
        get_announce_close_broadcast_events(&nodes, 0, 1);
        assert_eq!(nodes[0].node.list_channels().len(), 0);
@@ -2578,11 +2587,11 @@ fn claim_htlc_outputs_single_tx() {
        let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
 
        // Rebalance the network to generate htlc in the two directions
-       send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
+       send_payment(&nodes[0], &[&nodes[1]], 8_000_000);
        // node[0] is gonna to revoke an old state thus node[1] should be able to claim both offered/received HTLC outputs on top of commitment tx, but this
        // time as two different claim transactions as we're gonna to timeout htlc with given a high current height
-       let payment_preimage_1 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
-       let (_payment_preimage_2, payment_hash_2, _payment_secret_2) = route_payment(&nodes[1], &vec!(&nodes[0])[..], 3000000);
+       let payment_preimage_1 = route_payment(&nodes[0], &[&nodes[1]], 3_000_000).0;
+       let (_payment_preimage_2, payment_hash_2, _payment_secret_2) = route_payment(&nodes[1], &[&nodes[0]], 3_000_000);
 
        // Get the will-be-revoked local txn from node[0]
        let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan_1.2);
@@ -2604,9 +2613,9 @@ fn claim_htlc_outputs_single_tx() {
                }
 
                connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
-               expect_payment_failed!(nodes[1], payment_hash_2, true);
+               assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
 
-               let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
+               let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
                assert!(node_txn.len() == 9 || node_txn.len() == 10);
 
                // Check the pair local commitment and HTLC-timeout broadcast due to HTLC expiration
@@ -2634,6 +2643,14 @@ fn claim_htlc_outputs_single_tx() {
                assert_eq!(*witness_lens.iter().skip(0).next().unwrap(), 77); // revoked to_local
                assert_eq!(*witness_lens.iter().skip(1).next().unwrap(), OFFERED_HTLC_SCRIPT_WEIGHT); // revoked offered HTLC
                assert_eq!(*witness_lens.iter().skip(2).next().unwrap(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // revoked received HTLC
+
+               // Finally, mine the penalty transactions and check that we get an HTLC failure after
+               // ANTI_REORG_DELAY confirmations.
+               mine_transaction(&nodes[1], &node_txn[2]);
+               mine_transaction(&nodes[1], &node_txn[3]);
+               mine_transaction(&nodes[1], &node_txn[4]);
+               connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+               expect_payment_failed!(nodes[1], payment_hash_2, true);
        }
        get_announce_close_broadcast_events(&nodes, 0, 1);
        assert_eq!(nodes[0].node.list_channels().len(), 0);
@@ -5274,7 +5291,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
        // When this test was written, the default base fee floated based on the HTLC count.
        // It is now fixed, so we simply set the fee to the expected value here.
        let mut config = test_default_channel_config();
-       config.channel_options.forwarding_fee_base_msat = 196;
+       config.channel_config.forwarding_fee_base_msat = 196;
        let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs,
                &[Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone())]);
        let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
@@ -5486,7 +5503,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
        // When this test was written, the default base fee floated based on the HTLC count.
        // It is now fixed, so we simply set the fee to the expected value here.
        let mut config = test_default_channel_config();
-       config.channel_options.forwarding_fee_base_msat = 196;
+       config.channel_config.forwarding_fee_base_msat = 196;
        let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs,
                &[Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone()), Some(config.clone())]);
        let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
@@ -5802,7 +5819,8 @@ fn test_key_derivation_params() {
        let seed = [42; 32];
        let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
        let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &chanmon_cfgs[0].persister, &keys_manager);
-       let node = NodeCfg { chain_source: &chanmon_cfgs[0].chain_source, logger: &chanmon_cfgs[0].logger, tx_broadcaster: &chanmon_cfgs[0].tx_broadcaster, fee_estimator: &chanmon_cfgs[0].fee_estimator, chain_monitor, keys_manager: &keys_manager, network_graph: &chanmon_cfgs[0].network_graph, node_seed: seed, features: InitFeatures::known() };
+       let network_graph = NetworkGraph::new(chanmon_cfgs[0].chain_source.genesis_hash, &chanmon_cfgs[0].logger);
+       let node = NodeCfg { chain_source: &chanmon_cfgs[0].chain_source, logger: &chanmon_cfgs[0].logger, tx_broadcaster: &chanmon_cfgs[0].tx_broadcaster, fee_estimator: &chanmon_cfgs[0].fee_estimator, chain_monitor, keys_manager: &keys_manager, network_graph, node_seed: seed, features: InitFeatures::known() };
        let mut node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
        node_cfgs.remove(0);
        node_cfgs.insert(0, node);
@@ -6367,7 +6385,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
        // When this test was written, the default base fee floated based on the HTLC count.
        // It is now fixed, so we simply set the fee to the expected value here.
        let mut config = test_default_channel_config();
-       config.channel_options.forwarding_fee_base_msat = 196;
+       config.channel_config.forwarding_fee_base_msat = 196;
        let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config.clone()), Some(config.clone()), Some(config.clone())]);
        let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
        let chan_0_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::known(), InitFeatures::known());
@@ -7280,37 +7298,25 @@ fn do_test_sweep_outbound_htlc_failure_update(revoked: bool, local: bool) {
                check_added_monitors!(nodes[0], 1);
                check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
                assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
+
                connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
-               timeout_tx.push(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[1].clone());
+               timeout_tx = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().drain(..)
+                       .filter(|tx| tx.input[0].previous_output.txid == bs_commitment_tx[0].txid()).collect();
+               check_spends!(timeout_tx[0], bs_commitment_tx[0]);
+               // For both a revoked or non-revoked commitment transaction, after ANTI_REORG_DELAY the
+               // dust HTLC should have been failed.
+               expect_payment_failed!(nodes[0], dust_hash, true);
+
                if !revoked {
-                       expect_payment_failed!(nodes[0], dust_hash, true);
                        assert_eq!(timeout_tx[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
-                       // We fail non-dust-HTLC 2 by broadcast of local timeout tx on remote commitment tx
-                       mine_transaction(&nodes[0], &timeout_tx[0]);
-                       assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
-                       connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
-                       expect_payment_failed!(nodes[0], non_dust_hash, true);
                } else {
-                       // If revoked, both dust & non-dust HTLCs should have been failed after ANTI_REORG_DELAY confs of revoked
-                       // commitment tx
-                       let events = nodes[0].node.get_and_clear_pending_events();
-                       assert_eq!(events.len(), 2);
-                       let first;
-                       match events[0] {
-                               Event::PaymentPathFailed { payment_hash, .. } => {
-                                       if payment_hash == dust_hash { first = true; }
-                                       else { first = false; }
-                               },
-                               _ => panic!("Unexpected event"),
-                       }
-                       match events[1] {
-                               Event::PaymentPathFailed { payment_hash, .. } => {
-                                       if first { assert_eq!(payment_hash, non_dust_hash); }
-                                       else { assert_eq!(payment_hash, dust_hash); }
-                               },
-                               _ => panic!("Unexpected event"),
-                       }
+                       assert_eq!(timeout_tx[0].lock_time, 0);
                }
+               // We fail non-dust-HTLC 2 by broadcast of local timeout/revocation-claim tx
+               mine_transaction(&nodes[0], &timeout_tx[0]);
+               assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
+               connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
+               expect_payment_failed!(nodes[0], non_dust_hash, true);
        }
 }
 
@@ -7326,9 +7332,9 @@ fn test_user_configurable_csv_delay() {
        // We test our channel constructors yield errors when we pass them absurd csv delay
 
        let mut low_our_to_self_config = UserConfig::default();
-       low_our_to_self_config.own_channel_config.our_to_self_delay = 6;
+       low_our_to_self_config.channel_handshake_config.our_to_self_delay = 6;
        let mut high_their_to_self_config = UserConfig::default();
-       high_their_to_self_config.peer_channel_config_limits.their_to_self_delay = 100;
+       high_their_to_self_config.channel_handshake_limits.their_to_self_delay = 100;
        let user_cfgs = [Some(high_their_to_self_config.clone()), None];
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
@@ -8243,7 +8249,7 @@ fn test_override_channel_config() {
 
        // Node0 initiates a channel to node1 using the override config.
        let mut override_config = UserConfig::default();
-       override_config.own_channel_config.our_to_self_delay = 200;
+       override_config.channel_handshake_config.our_to_self_delay = 200;
 
        nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 16_000_000, 12_000_000, 42, Some(override_config)).unwrap();
 
@@ -8256,7 +8262,7 @@ fn test_override_channel_config() {
 #[test]
 fn test_override_0msat_htlc_minimum() {
        let mut zero_config = UserConfig::default();
-       zero_config.own_channel_config.our_htlc_minimum_msat = 0;
+       zero_config.channel_handshake_config.our_htlc_minimum_msat = 0;
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(zero_config.clone())]);
@@ -8280,17 +8286,17 @@ fn test_channel_update_has_correct_htlc_maximum_msat() {
        // 2. MUST be set to less than or equal to the `max_htlc_value_in_flight_msat` received from the peer.
 
        let mut config_30_percent = UserConfig::default();
-       config_30_percent.channel_options.announced_channel = true;
-       config_30_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 30;
+       config_30_percent.channel_handshake_config.announced_channel = true;
+       config_30_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 30;
        let mut config_50_percent = UserConfig::default();
-       config_50_percent.channel_options.announced_channel = true;
-       config_50_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 50;
+       config_50_percent.channel_handshake_config.announced_channel = true;
+       config_50_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 50;
        let mut config_95_percent = UserConfig::default();
-       config_95_percent.channel_options.announced_channel = true;
-       config_95_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 95;
+       config_95_percent.channel_handshake_config.announced_channel = true;
+       config_95_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 95;
        let mut config_100_percent = UserConfig::default();
-       config_100_percent.channel_options.announced_channel = true;
-       config_100_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100;
+       config_100_percent.channel_handshake_config.announced_channel = true;
+       config_100_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100;
 
        let chanmon_cfgs = create_chanmon_cfgs(4);
        let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
@@ -9725,7 +9731,7 @@ fn do_test_dup_htlc_second_rejected(test_for_second_fail_panic: bool) {
                nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_updates_1.update_fail_htlcs[0]);
                commitment_signed_dance!(nodes[0], nodes[1], fail_updates_1.commitment_signed, false);
 
-               expect_payment_failed_conditions!(nodes[0], our_payment_hash, true, PaymentFailedConditions::new().mpp_parts_remain());
+               expect_payment_failed_conditions(&nodes[0], our_payment_hash, true, PaymentFailedConditions::new().mpp_parts_remain());
 
                claim_payment(&nodes[0], &[&nodes[1]], our_payment_preimage);
        }
@@ -9830,7 +9836,7 @@ fn test_inconsistent_mpp_params() {
        nodes[0].node.handle_update_fail_htlc(&nodes[2].node.get_our_node_id(), &fail_updates_2.update_fail_htlcs[0]);
        commitment_signed_dance!(nodes[0], nodes[2], fail_updates_2.commitment_signed, false);
 
-       expect_payment_failed_conditions!(nodes[0], our_payment_hash, true, PaymentFailedConditions::new().mpp_parts_remain());
+       expect_payment_failed_conditions(&nodes[0], our_payment_hash, true, PaymentFailedConditions::new().mpp_parts_remain());
 
        nodes[0].node.send_payment_along_path(&route.paths[1], &payment_params_opt, &our_payment_hash, &Some(our_payment_secret), 15_000_000, cur_height, payment_id, &None).unwrap();
        check_added_monitors!(nodes[0], 1);
@@ -9860,7 +9866,7 @@ fn test_keysend_payments_to_public_node() {
        };
        let scorer = test_utils::TestScorer::with_penalty(0);
        let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
-       let route = find_route(&payer_pubkey, &route_params, network_graph, None, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
+       let route = find_route(&payer_pubkey, &route_params, &network_graph.read_only(), None, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
 
        let test_preimage = PaymentPreimage([42; 32]);
        let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(test_preimage)).unwrap();
@@ -9896,8 +9902,8 @@ fn test_keysend_payments_to_private_node() {
        let scorer = test_utils::TestScorer::with_penalty(0);
        let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
        let route = find_route(
-               &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
-               nodes[0].logger, &scorer, &random_seed_bytes
+               &payer_pubkey, &route_params, &network_graph.read_only(),
+               Some(&first_hops.iter().collect::<Vec<_>>()), nodes[0].logger, &scorer, &random_seed_bytes
        ).unwrap();
 
        let test_preimage = PaymentPreimage([42; 32]);
@@ -10180,7 +10186,7 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
 
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let mut config = test_default_channel_config();
-       config.channel_options.max_dust_htlc_exposure_msat = 5_000_000; // default setting value
+       config.channel_config.max_dust_htlc_exposure_msat = 5_000_000; // default setting value
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), None]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
@@ -10223,13 +10229,13 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
                chan.get_dust_buffer_feerate(None) as u64
        };
        let dust_outbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_timeout_tx_weight(opt_anchors) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000;
-       let dust_outbound_htlc_on_holder_tx: u64 = config.channel_options.max_dust_htlc_exposure_msat / dust_outbound_htlc_on_holder_tx_msat;
+       let dust_outbound_htlc_on_holder_tx: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_outbound_htlc_on_holder_tx_msat;
 
        let dust_inbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_success_tx_weight(opt_anchors) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000;
-       let dust_inbound_htlc_on_holder_tx: u64 = config.channel_options.max_dust_htlc_exposure_msat / dust_inbound_htlc_on_holder_tx_msat;
+       let dust_inbound_htlc_on_holder_tx: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_inbound_htlc_on_holder_tx_msat;
 
        let dust_htlc_on_counterparty_tx: u64 = 25;
-       let dust_htlc_on_counterparty_tx_msat: u64 = config.channel_options.max_dust_htlc_exposure_msat / dust_htlc_on_counterparty_tx;
+       let dust_htlc_on_counterparty_tx_msat: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_htlc_on_counterparty_tx;
 
        if on_holder_tx {
                if dust_outbound_balance {
@@ -10273,9 +10279,9 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
                if on_holder_tx {
                        let dust_outbound_overflow = dust_outbound_htlc_on_holder_tx_msat * (dust_outbound_htlc_on_holder_tx + 1);
                        let dust_inbound_overflow = dust_inbound_htlc_on_holder_tx_msat * dust_inbound_htlc_on_holder_tx + dust_outbound_htlc_on_holder_tx_msat;
-                       unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable { ref err }, assert_eq!(err, &format!("Cannot send value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_options.max_dust_htlc_exposure_msat)));
+                       unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable { ref err }, assert_eq!(err, &format!("Cannot send value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_config.max_dust_htlc_exposure_msat)));
                } else {
-                       unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable { ref err }, assert_eq!(err, &format!("Cannot send value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx", dust_overflow, config.channel_options.max_dust_htlc_exposure_msat)));
+                       unwrap_send_err!(nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable { ref err }, assert_eq!(err, &format!("Cannot send value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx", dust_overflow, config.channel_config.max_dust_htlc_exposure_msat)));
                }
        } else if exposure_breach_event == ExposureEvent::AtHTLCReception {
                let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], if on_holder_tx { dust_inbound_htlc_on_holder_tx_msat } else { dust_htlc_on_counterparty_tx_msat });
@@ -10290,10 +10296,10 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e
                        // Outbound dust balance: 6399 sats
                        let dust_inbound_overflow = dust_inbound_htlc_on_holder_tx_msat * (dust_inbound_htlc_on_holder_tx + 1);
                        let dust_outbound_overflow = dust_outbound_htlc_on_holder_tx_msat * dust_outbound_htlc_on_holder_tx + dust_inbound_htlc_on_holder_tx_msat;
-                       nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_options.max_dust_htlc_exposure_msat), 1);
+                       nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx", if dust_outbound_balance { dust_outbound_overflow } else { dust_inbound_overflow }, config.channel_config.max_dust_htlc_exposure_msat), 1);
                } else {
                        // Outbound dust balance: 5200 sats
-                       nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx", dust_overflow, config.channel_options.max_dust_htlc_exposure_msat), 1);
+                       nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx", dust_overflow, config.channel_config.max_dust_htlc_exposure_msat), 1);
                }
        } else if exposure_breach_event == ExposureEvent::AtUpdateFeeOutbound {
                let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 2_500_000);
@@ -10327,3 +10333,45 @@ fn test_max_dust_htlc_exposure() {
        do_test_max_dust_htlc_exposure(false, ExposureEvent::AtUpdateFeeOutbound, false);
        do_test_max_dust_htlc_exposure(false, ExposureEvent::AtUpdateFeeOutbound, true);
 }
+
+#[test]
+fn test_non_final_funding_tx() {
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+       let open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel_message);
+       let accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel_message);
+
+       let best_height = nodes[0].node.best_block.read().unwrap().height();
+
+       let chan_id = *nodes[0].network_chan_count.borrow();
+       let events = nodes[0].node.get_and_clear_pending_events();
+       let input = TxIn { previous_output: BitcoinOutPoint::null(), script_sig: bitcoin::Script::new(), sequence: 0x1, witness: Witness::from_vec(vec!(vec!(1))) };
+       assert_eq!(events.len(), 1);
+       let mut tx = match events[0] {
+               Event::FundingGenerationReady { ref channel_value_satoshis, ref output_script, .. } => {
+                       // Timelock the transaction _beyond_ the best client height + 2.
+                       Transaction { version: chan_id as i32, lock_time: best_height + 3, input: vec![input], output: vec![TxOut {
+                               value: *channel_value_satoshis, script_pubkey: output_script.clone(),
+                       }]}
+               },
+               _ => panic!("Unexpected event"),
+       };
+       // Transaction should fail as it's evaluated as non-final for propagation.
+       match nodes[0].node.funding_transaction_generated(&temp_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()) {
+               Err(APIError::APIMisuseError { err }) => {
+                       assert_eq!(format!("Funding transaction absolute timelock is non-final"), err);
+               },
+               _ => panic!()
+       }
+
+       // However, transaction should be accepted if it's in a +2 headroom from best block.
+       tx.lock_time -= 1;
+       assert!(nodes[0].node.funding_transaction_generated(&temp_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()).is_ok());
+       get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
+}
index 492a65537701750f7a97c56ac6cb287da395aac0..7c46f7b6d283a10d7ab4f5b97e45a611c1f2698b 100644 (file)
@@ -94,6 +94,55 @@ fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_t
        } else { panic!(); }
 }
 
+#[test]
+fn revoked_output_htlc_resolution_timing() {
+       // Tests that HTLCs which were present in a broadcasted remote revoked commitment transaction
+       // are resolved only after a spend of the HTLC output reaches six confirmations. Preivously
+       // they would resolve after the revoked commitment transaction itself reaches six
+       // confirmations.
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
+
+       let payment_hash_1 = route_payment(&nodes[1], &[&nodes[0]], 1_000_000).1;
+
+       // Get a commitment transaction which contains the HTLC we care about, but which we'll revoke
+       // before forwarding.
+       let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan.2);
+       assert_eq!(revoked_local_txn.len(), 1);
+
+       // Route a dust payment to revoke the above commitment transaction
+       route_payment(&nodes[0], &[&nodes[1]], 1_000);
+
+       // Confirm the revoked commitment transaction, closing the channel.
+       mine_transaction(&nodes[1], &revoked_local_txn[0]);
+       check_added_monitors!(nodes[1], 1);
+       check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
+       check_closed_broadcast!(nodes[1], true);
+
+       let bs_spend_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+       assert_eq!(bs_spend_txn.len(), 2);
+       check_spends!(bs_spend_txn[0], revoked_local_txn[0]);
+       check_spends!(bs_spend_txn[1], chan.3);
+
+       // After the commitment transaction confirms, we should still wait on the HTLC spend
+       // transaction to confirm before resolving the HTLC.
+       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+       assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+
+       // Spend the HTLC output, generating a HTLC failure event after ANTI_REORG_DELAY confirmations.
+       mine_transaction(&nodes[1], &bs_spend_txn[0]);
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+       assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+
+       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+       expect_payment_failed!(nodes[1], payment_hash_1, true);
+}
+
 #[test]
 fn chanmon_claim_value_coop_close() {
        // Tests `get_claimable_balances` returns the correct values across a simple cooperative claim.
index eabd2222078b5a73c7456db15d65ff453a45ab05..c66f45a44923b596e1e31ac0a08d2ee531826128 100644 (file)
 //! These tests work by standing up full nodes and route payments across the network, checking the
 //! returned errors decode to the correct thing.
 
-use chain::channelmonitor::{CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
+use chain::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
 use chain::keysinterface::{KeysInterface, Recipient};
 use ln::{PaymentHash, PaymentSecret};
-use ln::channelmanager::{HTLCForwardInfo, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
+use ln::channel::EXPIRE_PREV_CONFIG_TICKS;
+use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, HTLCForwardInfo, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
 use ln::onion_utils;
 use routing::gossip::{NetworkUpdate, RoutingFees, NodeId};
 use routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop};
@@ -23,9 +24,10 @@ use ln::msgs;
 use ln::msgs::{ChannelMessageHandler, ChannelUpdate, OptionalField};
 use ln::wire::Encode;
 use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
-use util::ser::{Writeable, Writer};
+use util::ser::{ReadableArgs, Writeable, Writer};
 use util::{byte_utils, test_utils};
-use util::config::UserConfig;
+use util::config::{UserConfig, ChannelConfig};
+use util::errors::APIError;
 
 use bitcoin::hash_types::BlockHash;
 
@@ -262,7 +264,7 @@ fn test_fee_failures() {
        // When this test was written, the default base fee floated based on the HTLC count.
        // It is now fixed, so we simply set the fee to the expected value here.
        let mut config = test_default_channel_config();
-       config.channel_options.forwarding_fee_base_msat = 196;
+       config.channel_config.forwarding_fee_base_msat = 196;
 
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
@@ -307,14 +309,14 @@ fn test_onion_failure() {
        // This exposed a previous bug because we were using the wrong value all the way down in
        // Channel::get_counterparty_htlc_minimum_msat().
        let mut node_2_cfg: UserConfig = Default::default();
-       node_2_cfg.own_channel_config.our_htlc_minimum_msat = 2000;
-       node_2_cfg.channel_options.announced_channel = true;
-       node_2_cfg.peer_channel_config_limits.force_announced_channel_preference = false;
+       node_2_cfg.channel_handshake_config.our_htlc_minimum_msat = 2000;
+       node_2_cfg.channel_handshake_config.announced_channel = true;
+       node_2_cfg.channel_handshake_limits.force_announced_channel_preference = false;
 
        // When this test was written, the default base fee floated based on the HTLC count.
        // It is now fixed, so we simply set the fee to the expected value here.
        let mut config = test_default_channel_config();
-       config.channel_options.forwarding_fee_base_msat = 196;
+       config.channel_config.forwarding_fee_base_msat = 196;
 
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
@@ -506,8 +508,6 @@ fn test_onion_failure() {
        let preimage = send_along_route(&nodes[0], bogus_route, &[&nodes[1], &nodes[2]], amt_to_forward+1).0;
        claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], preimage);
 
-       //TODO: with new config API, we will be able to generate both valid and
-       //invalid channel_update cases.
        let short_channel_id = channels[0].0.contents.short_channel_id;
        run_onion_failure_test("fee_insufficient", 0, &nodes, &route, &payment_hash, &payment_secret, |msg| {
                msg.amount_msat -= 1;
@@ -594,13 +594,209 @@ fn test_onion_failure() {
        }, true, Some(23), None, None);
 }
 
+fn do_test_onion_failure_stale_channel_update(announced_channel: bool) {
+       // Create a network of three nodes and two channels connecting them. We'll be updating the
+       // HTLC relay policy of the second channel, causing forwarding failures at the first hop.
+       let mut config = UserConfig::default();
+       config.channel_handshake_config.announced_channel = announced_channel;
+       config.channel_handshake_limits.force_announced_channel_preference = false;
+       config.accept_forwards_to_priv_channels = !announced_channel;
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(config), None]);
+       let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       let other_channel = create_chan_between_nodes(
+               &nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known(),
+       );
+       let channel_to_update = if announced_channel {
+               let channel = create_announced_chan_between_nodes(
+                       &nodes, 1, 2, InitFeatures::known(), InitFeatures::known(),
+               );
+               (channel.2, channel.0.contents.short_channel_id)
+       } else {
+               let channel = create_unannounced_chan_between_nodes_with_value(
+                       &nodes, 1, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known(),
+               );
+               (channel.0.channel_id, channel.0.short_channel_id_alias.unwrap())
+       };
+       let channel_to_update_counterparty = &nodes[2].node.get_our_node_id();
+
+       let default_config = ChannelConfig::default();
+
+       // A test payment should succeed as the ChannelConfig has not been changed yet.
+       const PAYMENT_AMT: u64 = 40000;
+       let (route, payment_hash, payment_preimage, payment_secret) = if announced_channel {
+               get_route_and_payment_hash!(nodes[0], nodes[2], PAYMENT_AMT)
+       } else {
+               let hop_hints = vec![RouteHint(vec![RouteHintHop {
+                       src_node_id: nodes[1].node.get_our_node_id(),
+                       short_channel_id: channel_to_update.1,
+                       fees: RoutingFees {
+                               base_msat: default_config.forwarding_fee_base_msat,
+                               proportional_millionths: default_config.forwarding_fee_proportional_millionths,
+                       },
+                       cltv_expiry_delta: default_config.cltv_expiry_delta,
+                       htlc_maximum_msat: None,
+                       htlc_minimum_msat: None,
+               }])];
+               let payment_params = PaymentParameters::from_node_id(*channel_to_update_counterparty)
+                       .with_features(InvoiceFeatures::known())
+                       .with_route_hints(hop_hints);
+               get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, PAYMENT_AMT, TEST_FINAL_CLTV)
+       };
+       send_along_route_with_secret(&nodes[0], route.clone(), &[&[&nodes[1], &nodes[2]]], PAYMENT_AMT,
+               payment_hash, payment_secret);
+       claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
+
+       // Closure to force expiry of a channel's previous config.
+       let expire_prev_config = || {
+               for _ in 0..EXPIRE_PREV_CONFIG_TICKS {
+                       nodes[1].node.timer_tick_occurred();
+               }
+       };
+
+       // Closure to update and retrieve the latest ChannelUpdate.
+       let update_and_get_channel_update = |config: &ChannelConfig, expect_new_update: bool,
+               prev_update: Option<&msgs::ChannelUpdate>, should_expire_prev_config: bool| -> Option<msgs::ChannelUpdate> {
+               nodes[1].node.update_channel_config(
+                       channel_to_update_counterparty, &[channel_to_update.0], config,
+               ).unwrap();
+               let events = nodes[1].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), expect_new_update as usize);
+               if !expect_new_update {
+                       return None;
+               }
+               let new_update = match &events[0] {
+                       MessageSendEvent::BroadcastChannelUpdate { msg } => {
+                               assert!(announced_channel);
+                               msg.clone()
+                       },
+                       MessageSendEvent::SendChannelUpdate { node_id, msg } => {
+                               assert_eq!(node_id, channel_to_update_counterparty);
+                               assert!(!announced_channel);
+                               msg.clone()
+                       },
+                       _ => panic!("expected Broadcast/SendChannelUpdate event"),
+               };
+               if prev_update.is_some() {
+                       assert!(new_update.contents.timestamp > prev_update.unwrap().contents.timestamp)
+               }
+               if should_expire_prev_config {
+                       expire_prev_config();
+               }
+               Some(new_update)
+       };
+
+       // We'll be attempting to route payments using the default ChannelUpdate for channels. This will
+       // lead to onion failures at the first hop once we update the ChannelConfig for the
+       // second hop.
+       let expect_onion_failure = |name: &str, error_code: u16, channel_update: &msgs::ChannelUpdate| {
+               let short_channel_id = channel_to_update.1;
+               let network_update = NetworkUpdate::ChannelUpdateMessage { msg: channel_update.clone() };
+               run_onion_failure_test(
+                       name, 0, &nodes, &route, &payment_hash, &payment_secret, |_| {}, || {}, true,
+                       Some(error_code), Some(network_update), Some(short_channel_id),
+               );
+       };
+
+       // Updates to cltv_expiry_delta below MIN_CLTV_EXPIRY_DELTA should fail with APIMisuseError.
+       let mut invalid_config = default_config.clone();
+       invalid_config.cltv_expiry_delta = 0;
+       match nodes[1].node.update_channel_config(
+               channel_to_update_counterparty, &[channel_to_update.0], &invalid_config,
+       ) {
+               Err(APIError::APIMisuseError{ .. }) => {},
+               _ => panic!("unexpected result applying invalid cltv_expiry_delta"),
+       }
+
+       // Increase the base fee which should trigger a new ChannelUpdate.
+       let mut config = nodes[1].node.list_usable_channels().iter()
+               .find(|channel| channel.channel_id == channel_to_update.0).unwrap()
+               .config.unwrap();
+       config.forwarding_fee_base_msat = u32::max_value();
+       let msg = update_and_get_channel_update(&config, true, None, false).unwrap();
+
+       // The old policy should still be in effect until a new block is connected.
+       send_along_route_with_secret(&nodes[0], route.clone(), &[&[&nodes[1], &nodes[2]]], PAYMENT_AMT,
+               payment_hash, payment_secret);
+       claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
+
+       // Connect a block, which should expire the previous config, leading to a failure when
+       // forwarding the HTLC.
+       expire_prev_config();
+       expect_onion_failure("fee_insufficient", UPDATE|12, &msg);
+
+       // Redundant updates should not trigger a new ChannelUpdate.
+       assert!(update_and_get_channel_update(&config, false, None, false).is_none());
+
+       // Similarly, updates that do not have an affect on ChannelUpdate should not trigger a new one.
+       config.force_close_avoidance_max_fee_satoshis *= 2;
+       assert!(update_and_get_channel_update(&config, false, None, false).is_none());
+
+       // Reset the base fee to the default and increase the proportional fee which should trigger a
+       // new ChannelUpdate.
+       config.forwarding_fee_base_msat = default_config.forwarding_fee_base_msat;
+       config.cltv_expiry_delta = u16::max_value();
+       let msg = update_and_get_channel_update(&config, true, Some(&msg), true).unwrap();
+       expect_onion_failure("incorrect_cltv_expiry", UPDATE|13, &msg);
+
+       // Reset the proportional fee and increase the CLTV expiry delta which should trigger a new
+       // ChannelUpdate.
+       config.cltv_expiry_delta = default_config.cltv_expiry_delta;
+       config.forwarding_fee_proportional_millionths = u32::max_value();
+       let msg = update_and_get_channel_update(&config, true, Some(&msg), true).unwrap();
+       expect_onion_failure("fee_insufficient", UPDATE|12, &msg);
+
+       // To test persistence of the updated config, we'll re-initialize the ChannelManager.
+       let config_after_restart = {
+               let persister = test_utils::TestPersister::new();
+               let chain_monitor = test_utils::TestChainMonitor::new(
+                       Some(nodes[1].chain_source), nodes[1].tx_broadcaster.clone(), nodes[1].logger,
+                       node_cfgs[1].fee_estimator, &persister, nodes[1].keys_manager,
+               );
+
+               let mut chanmon_1 = <(_, ChannelMonitor<_>)>::read(
+                       &mut &get_monitor!(nodes[1], other_channel.3).encode()[..], nodes[1].keys_manager,
+               ).unwrap().1;
+               let mut chanmon_2 = <(_, ChannelMonitor<_>)>::read(
+                       &mut &get_monitor!(nodes[1], channel_to_update.0).encode()[..], nodes[1].keys_manager,
+               ).unwrap().1;
+               let mut channel_monitors = HashMap::new();
+               channel_monitors.insert(chanmon_1.get_funding_txo().0, &mut chanmon_1);
+               channel_monitors.insert(chanmon_2.get_funding_txo().0, &mut chanmon_2);
+
+               let chanmgr = <(_, ChannelManager<_, _, _, _, _, _>)>::read(
+                       &mut &nodes[1].node.encode()[..], ChannelManagerReadArgs {
+                               default_config: *nodes[1].node.get_current_default_configuration(),
+                               keys_manager: nodes[1].keys_manager,
+                               fee_estimator: node_cfgs[1].fee_estimator,
+                               chain_monitor: &chain_monitor,
+                               tx_broadcaster: nodes[1].tx_broadcaster.clone(),
+                               logger: nodes[1].logger,
+                               channel_monitors: channel_monitors,
+                       },
+               ).unwrap().1;
+               chanmgr.list_channels().iter()
+                       .find(|channel| channel.channel_id == channel_to_update.0).unwrap()
+                       .config.unwrap()
+       };
+       assert_eq!(config, config_after_restart);
+}
+
+#[test]
+fn test_onion_failure_stale_channel_update() {
+       do_test_onion_failure_stale_channel_update(false);
+       do_test_onion_failure_stale_channel_update(true);
+}
+
 #[test]
 fn test_default_to_onion_payload_tlv_format() {
        // Tests that we default to creating tlv format onion payloads when no `NodeAnnouncementInfo`
        // `features` for a node in the `network_graph` exists, or when the node isn't in the
        // `network_graph`, and no other known `features` for the node exists.
        let mut priv_channels_conf = UserConfig::default();
-       priv_channels_conf.channel_options.announced_channel = false;
+       priv_channels_conf.channel_handshake_config.announced_channel = false;
        let chanmon_cfgs = create_chanmon_cfgs(5);
        let node_cfgs = create_node_cfgs(5, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(5, &node_cfgs, &[None, None, None, None, Some(priv_channels_conf)]);
@@ -854,7 +1050,7 @@ fn test_phantom_onion_hmac_failure() {
                .blamed_scid(phantom_scid)
                .blamed_chan_closed(true)
                .expected_htlc_error_data(0x8000 | 0x4000 | 5, &sha256_of_onion);
-       expect_payment_failed_conditions!(nodes[0], payment_hash, false, fail_conditions);
+       expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
 }
 
 #[test]
@@ -927,7 +1123,7 @@ fn test_phantom_invalid_onion_payload() {
                .blamed_scid(phantom_scid)
                .blamed_chan_closed(true)
                .expected_htlc_error_data(0x4000 | 22, &error_data);
-       expect_payment_failed_conditions!(nodes[0], payment_hash, true, fail_conditions);
+       expect_payment_failed_conditions(&nodes[0], payment_hash, true, fail_conditions);
 }
 
 #[test]
@@ -983,7 +1179,7 @@ fn test_phantom_final_incorrect_cltv_expiry() {
        let mut fail_conditions = PaymentFailedConditions::new()
                .blamed_scid(phantom_scid)
                .expected_htlc_error_data(18, &error_data);
-       expect_payment_failed_conditions!(nodes[0], payment_hash, false, fail_conditions);
+       expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
 }
 
 #[test]
@@ -1028,7 +1224,7 @@ fn test_phantom_failure_too_low_cltv() {
        let mut fail_conditions = PaymentFailedConditions::new()
                .blamed_scid(phantom_scid)
                .expected_htlc_error_data(17, &error_data);
-       expect_payment_failed_conditions!(nodes[0], payment_hash, false, fail_conditions);
+       expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
 }
 
 #[test]
@@ -1076,7 +1272,7 @@ fn test_phantom_failure_too_low_recv_amt() {
        let mut fail_conditions = PaymentFailedConditions::new()
                .blamed_scid(phantom_scid)
                .expected_htlc_error_data(0x4000 | 15, &error_data);
-       expect_payment_failed_conditions!(nodes[0], payment_hash, true, fail_conditions);
+       expect_payment_failed_conditions(&nodes[0], payment_hash, true, fail_conditions);
 }
 
 #[test]
@@ -1084,8 +1280,8 @@ fn test_phantom_dust_exposure_failure() {
        // Set the max dust exposure to the dust limit.
        let max_dust_exposure = 546;
        let mut receiver_config = UserConfig::default();
-       receiver_config.channel_options.max_dust_htlc_exposure_msat = max_dust_exposure;
-       receiver_config.channel_options.announced_channel = true;
+       receiver_config.channel_config.max_dust_htlc_exposure_msat = max_dust_exposure;
+       receiver_config.channel_handshake_config.announced_channel = true;
 
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
@@ -1123,7 +1319,7 @@ fn test_phantom_dust_exposure_failure() {
                .blamed_scid(channel.0.contents.short_channel_id)
                .blamed_chan_closed(false)
                .expected_htlc_error_data(0x1000 | 7, &err_data);
-               expect_payment_failed_conditions!(nodes[0], payment_hash, false, fail_conditions);
+               expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
 }
 
 #[test]
@@ -1174,5 +1370,5 @@ fn test_phantom_failure_reject_payment() {
        let mut fail_conditions = PaymentFailedConditions::new()
                .blamed_scid(phantom_scid)
                .expected_htlc_error_data(0x4000 | 15, &error_data);
-       expect_payment_failed_conditions!(nodes[0], payment_hash, true, fail_conditions);
+       expect_payment_failed_conditions(&nodes[0], payment_hash, true, fail_conditions);
 }
index 07e531c5b4b7e330b252414a89207ea70e698bc2..37ca25babe9eb48e48a443a143633d5996c467a1 100644 (file)
@@ -15,6 +15,7 @@ use chain::{ChannelMonitorUpdateErr, Confirm, Listen, Watch};
 use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor, LATENCY_GRACE_PERIOD_BLOCKS};
 use chain::transaction::OutPoint;
 use chain::keysinterface::KeysInterface;
+use ln::channel::EXPIRE_PREV_CONFIG_TICKS;
 use ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, ChannelManagerReadArgs, MPP_TIMEOUT_TICKS, PaymentId, PaymentSendFailure};
 use ln::features::{InitFeatures, InvoiceFeatures};
 use ln::msgs;
@@ -70,7 +71,7 @@ fn retry_single_path_payment() {
        check_added_monitors!(nodes[1], 1);
        nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_updates.update_fail_htlcs[0]);
        commitment_signed_dance!(nodes[0], nodes[1], htlc_updates.commitment_signed, false);
-       expect_payment_failed_conditions!(nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
+       expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
 
        // Rebalance the channel so the retry succeeds.
        send_payment(&nodes[2], &vec!(&nodes[1])[..], 3_000_000);
@@ -173,7 +174,7 @@ fn mpp_retry() {
        check_added_monitors!(nodes[2], 1);
        nodes[0].node.handle_update_fail_htlc(&nodes[2].node.get_our_node_id(), &htlc_updates.update_fail_htlcs[0]);
        commitment_signed_dance!(nodes[0], nodes[2], htlc_updates.commitment_signed, false);
-       expect_payment_failed_conditions!(nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
+       expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
 
        // Rebalance the channel so the second half of the payment can succeed.
        send_payment(&nodes[3], &vec!(&nodes[2])[..], 1_500_000);
@@ -251,7 +252,7 @@ fn do_mpp_receive_timeout(send_partial_mpp: bool) {
                check_added_monitors!(nodes[1], 1);
                commitment_signed_dance!(nodes[0], nodes[1], htlc_fail_updates_1_0.commitment_signed, false);
 
-               expect_payment_failed_conditions!(nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain().expected_htlc_error_data(23, &[][..]));
+               expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain().expected_htlc_error_data(23, &[][..]));
        } else {
                // Pass half of the payment along the second path.
                pass_along_path(&nodes[0], &[&nodes[2], &nodes[3]], 200_000, payment_hash, Some(payment_secret), events.remove(0), true, None);
@@ -521,7 +522,7 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
                confirm_transaction(&nodes[0], &first_htlc_timeout_tx);
        }
        nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
-       expect_payment_failed_conditions!(nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
+       expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
 
        // Finally, retry the payment (which was reloaded from the ChannelMonitor when nodes[0] was
        // reloaded) via a route over the new channel, which work without issue and eventually be
@@ -531,8 +532,19 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
        // Update the fee on the middle hop to ensure PaymentSent events have the correct (retried) fee
        // and not the original fee. We also update node[1]'s relevant config as
        // do_claim_payment_along_route expects us to never overpay.
-       nodes[1].node.channel_state.lock().unwrap().by_id.get_mut(&chan_id_2).unwrap().config.forwarding_fee_base_msat += 100_000;
-       new_route.paths[0][0].fee_msat += 100_000;
+       {
+               let mut channel_state = nodes[1].node.channel_state.lock().unwrap();
+               let mut channel = channel_state.by_id.get_mut(&chan_id_2).unwrap();
+               let mut new_config = channel.config();
+               new_config.forwarding_fee_base_msat += 100_000;
+               channel.update_config(&new_config);
+               new_route.paths[0][0].fee_msat += 100_000;
+       }
+
+       // Force expiration of the channel's previous config.
+       for _ in 0..EXPIRE_PREV_CONFIG_TICKS {
+               nodes[1].node.timer_tick_occurred();
+       }
 
        assert!(nodes[0].node.retry_payment(&new_route, payment_id_1).is_err()); // Shouldn't be allowed to retry a fulfilled payment
        nodes[0].node.retry_payment(&new_route, payment_id).unwrap();
index d86cddb13dbc66162c52af7128f0c3c180688532..2a026821f8adf91a9f0d2ba9bfdacbc861e1db48 100644 (file)
@@ -387,7 +387,7 @@ impl Peer {
 /// issues such as overly long function definitions.
 ///
 /// (C-not exported) as Arcs don't make sense in bindings
-pub type SimpleArcPeerManager<SD, M, T, F, C, L> = PeerManager<SD, Arc<SimpleArcChannelManager<M, T, F, L>>, Arc<P2PGossipSync<Arc<NetworkGraph>, Arc<C>, Arc<L>>>, Arc<L>, Arc<IgnoringMessageHandler>>;
+pub type SimpleArcPeerManager<SD, M, T, F, C, L> = PeerManager<SD, Arc<SimpleArcChannelManager<M, T, F, L>>, Arc<P2PGossipSync<Arc<NetworkGraph<Arc<L>>>, Arc<C>, Arc<L>>>, Arc<L>, Arc<IgnoringMessageHandler>>;
 
 /// SimpleRefPeerManager is a type alias for a PeerManager reference, and is the reference
 /// counterpart to the SimpleArcPeerManager type alias. Use this type by default when you don't
@@ -397,7 +397,7 @@ pub type SimpleArcPeerManager<SD, M, T, F, C, L> = PeerManager<SD, Arc<SimpleArc
 /// helps with issues such as long function definitions.
 ///
 /// (C-not exported) as Arcs don't make sense in bindings
-pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, SD, M, T, F, C, L> = PeerManager<SD, SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L>, &'e P2PGossipSync<&'g NetworkGraph, &'h C, &'f L>, &'f L, IgnoringMessageHandler>;
+pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, SD, M, T, F, C, L> = PeerManager<SD, SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L>, &'e P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>, &'f L, IgnoringMessageHandler>;
 
 /// A PeerManager manages a set of peers, described by their [`SocketDescriptor`] and marshalls
 /// socket events into messages which it passes on to its [`MessageHandler`].
index 051703a7fcc04b2121a82c207cb18bdd99829cb9..237a7fa316022f53f0a6e291cc8bef70ca5a1734 100644 (file)
@@ -170,13 +170,13 @@ fn do_test_1_conf_open(connect_style: ConnectStyle) {
        // Previously, if the minium_depth config was set to 1, we'd never send a channel_ready. This
        // tests that we properly send one in that case.
        let mut alice_config = UserConfig::default();
-       alice_config.own_channel_config.minimum_depth = 1;
-       alice_config.channel_options.announced_channel = true;
-       alice_config.peer_channel_config_limits.force_announced_channel_preference = false;
+       alice_config.channel_handshake_config.minimum_depth = 1;
+       alice_config.channel_handshake_config.announced_channel = true;
+       alice_config.channel_handshake_limits.force_announced_channel_preference = false;
        let mut bob_config = UserConfig::default();
-       bob_config.own_channel_config.minimum_depth = 1;
-       bob_config.channel_options.announced_channel = true;
-       bob_config.peer_channel_config_limits.force_announced_channel_preference = false;
+       bob_config.channel_handshake_config.minimum_depth = 1;
+       bob_config.channel_handshake_config.announced_channel = true;
+       bob_config.channel_handshake_limits.force_announced_channel_preference = false;
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(alice_config), Some(bob_config)]);
@@ -308,8 +308,8 @@ fn test_scid_privacy_on_pub_channel() {
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        let mut scid_privacy_cfg = test_default_channel_config();
-       scid_privacy_cfg.channel_options.announced_channel = true;
-       scid_privacy_cfg.own_channel_config.negotiate_scid_privacy = true;
+       scid_privacy_cfg.channel_handshake_config.announced_channel = true;
+       scid_privacy_cfg.channel_handshake_config.negotiate_scid_privacy = true;
        nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(scid_privacy_cfg)).unwrap();
        let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
@@ -332,8 +332,8 @@ fn test_scid_privacy_negotiation() {
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        let mut scid_privacy_cfg = test_default_channel_config();
-       scid_privacy_cfg.channel_options.announced_channel = false;
-       scid_privacy_cfg.own_channel_config.negotiate_scid_privacy = true;
+       scid_privacy_cfg.channel_handshake_config.announced_channel = false;
+       scid_privacy_cfg.channel_handshake_config.negotiate_scid_privacy = true;
        nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(scid_privacy_cfg)).unwrap();
 
        let init_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
@@ -378,8 +378,8 @@ fn test_inbound_scid_privacy() {
        create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
 
        let mut no_announce_cfg = test_default_channel_config();
-       no_announce_cfg.channel_options.announced_channel = false;
-       no_announce_cfg.own_channel_config.negotiate_scid_privacy = true;
+       no_announce_cfg.channel_handshake_config.announced_channel = false;
+       no_announce_cfg.channel_handshake_config.negotiate_scid_privacy = true;
        nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 100_000, 10_000, 42, Some(no_announce_cfg)).unwrap();
        let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[2].node.get_our_node_id());
 
@@ -460,7 +460,7 @@ fn test_inbound_scid_privacy() {
        nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
        commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false);
 
-       expect_payment_failed_conditions!(nodes[0], payment_hash_2, false,
+       expect_payment_failed_conditions(&nodes[0], payment_hash_2, false,
                PaymentFailedConditions::new().blamed_scid(last_hop[0].short_channel_id.unwrap())
                        .blamed_chan_closed(true).expected_htlc_error_data(0x4000|10, &[0; 0]));
 }
@@ -521,7 +521,7 @@ fn test_scid_alias_returned() {
                short_channel_id: last_hop[0].inbound_scid_alias.unwrap(),
                timestamp: 21,
                flags: 1,
-               cltv_expiry_delta: accept_forward_cfg.channel_options.cltv_expiry_delta,
+               cltv_expiry_delta: accept_forward_cfg.channel_config.cltv_expiry_delta,
                htlc_minimum_msat: 1_000,
                htlc_maximum_msat: OptionalField::Present(1_000_000), // Defaults to 10% of the channel value
                fee_base_msat: last_hop[0].counterparty.forwarding_info.as_ref().unwrap().fee_base_msat,
@@ -537,7 +537,7 @@ fn test_scid_alias_returned() {
        err_data.extend_from_slice(&ChannelUpdate::TYPE.to_be_bytes());
        err_data.extend_from_slice(&msg.encode());
 
-       expect_payment_failed_conditions!(nodes[0], payment_hash, false,
+       expect_payment_failed_conditions(&nodes[0], payment_hash, false,
                PaymentFailedConditions::new().blamed_scid(last_hop[0].inbound_scid_alias.unwrap())
                        .blamed_chan_closed(false).expected_htlc_error_data(0x1000|7, &err_data));
 
@@ -560,7 +560,7 @@ fn test_scid_alias_returned() {
        err_data.extend_from_slice(&(msg.serialized_length() as u16 + 2).to_be_bytes());
        err_data.extend_from_slice(&ChannelUpdate::TYPE.to_be_bytes());
        err_data.extend_from_slice(&msg.encode());
-       expect_payment_failed_conditions!(nodes[0], payment_hash, false,
+       expect_payment_failed_conditions(&nodes[0], payment_hash, false,
                PaymentFailedConditions::new().blamed_scid(last_hop[0].inbound_scid_alias.unwrap())
                        .blamed_chan_closed(false).expected_htlc_error_data(0x1000|12, &err_data));
 }
@@ -665,7 +665,7 @@ fn test_0conf_channel_with_async_monitor() {
 
        create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
 
-       chan_config.channel_options.announced_channel = false;
+       chan_config.channel_handshake_config.announced_channel = false;
        nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(chan_config)).unwrap();
        let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
@@ -811,7 +811,7 @@ fn test_0conf_close_no_early_chan_update() {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        // This is the default but we force it on anyway
-       chan_config.channel_options.announced_channel = true;
+       chan_config.channel_handshake_config.announced_channel = true;
        open_zero_conf_channel(&nodes[0], &nodes[1], Some(chan_config));
 
        // We can use the channel immediately, but won't generate a channel_update until we get confs
@@ -835,7 +835,7 @@ fn test_public_0conf_channel() {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        // This is the default but we force it on anyway
-       chan_config.channel_options.announced_channel = true;
+       chan_config.channel_handshake_config.announced_channel = true;
        let tx = open_zero_conf_channel(&nodes[0], &nodes[1], Some(chan_config));
 
        // We can use the channel immediately, but we can't announce it until we get 6+ confirmations
@@ -888,7 +888,7 @@ fn test_0conf_channel_reorg() {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        // This is the default but we force it on anyway
-       chan_config.channel_options.announced_channel = true;
+       chan_config.channel_handshake_config.announced_channel = true;
        let tx = open_zero_conf_channel(&nodes[0], &nodes[1], Some(chan_config));
 
        // We can use the channel immediately, but we can't announce it until we get 6+ confirmations
@@ -974,7 +974,7 @@ fn test_zero_conf_accept_reject() {
        assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
 
        let events = nodes[1].node.get_and_clear_pending_events();
-       
+
        match events[0] {
                Event::OpenChannelRequest { temporary_channel_id, .. } => {
                        // Assert we fail to accept via the non-0conf method
@@ -1004,7 +1004,7 @@ fn test_zero_conf_accept_reject() {
                &open_channel_msg);
 
        let events = nodes[1].node.get_and_clear_pending_events();
-       
+
        match events[0] {
                Event::OpenChannelRequest { temporary_channel_id, .. } => {
                        // Assert we can accept via the 0conf method
index 0025598e4c2400702503fe072b1d8b7459f58b39..a7090e4e7355508fb0a7fe10f1106a3a37e7ee78 100644 (file)
@@ -185,6 +185,77 @@ fn test_onchain_htlc_timeout_delay_remote_commitment() {
        do_test_onchain_htlc_reorg(false, false);
 }
 
+#[test]
+fn test_counterparty_revoked_reorg() {
+       // Test what happens when a revoked counterparty transaction is broadcast but then reorg'd out
+       // of the main chain. Specifically, HTLCs in the latest commitment transaction which are not
+       // included in the revoked commitment transaction should not be considered failed, and should
+       // still be claim-from-able after the reorg.
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
+
+       // Get the initial commitment transaction for broadcast, before any HTLCs are added at all.
+       let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan.2);
+       assert_eq!(revoked_local_txn.len(), 1);
+
+       // Now add two HTLCs in each direction, one dust and one not.
+       route_payment(&nodes[0], &[&nodes[1]], 5_000_000);
+       route_payment(&nodes[0], &[&nodes[1]], 5_000);
+       let (payment_preimage_3, payment_hash_3, ..) = route_payment(&nodes[1], &[&nodes[0]], 4_000_000);
+       let payment_hash_4 = route_payment(&nodes[1], &[&nodes[0]], 4_000).1;
+
+       nodes[0].node.claim_funds(payment_preimage_3);
+       let _ = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       check_added_monitors!(nodes[0], 1);
+       expect_payment_claimed!(nodes[0], payment_hash_3, 4_000_000);
+
+       let mut unrevoked_local_txn = get_local_commitment_txn!(nodes[0], chan.2);
+       assert_eq!(unrevoked_local_txn.len(), 3); // commitment + 2 HTLC txn
+       // Sort the unrevoked transactions in reverse order, ie commitment tx, then HTLC 1 then HTLC 3
+       unrevoked_local_txn.sort_unstable_by_key(|tx| 1_000_000 - tx.output.iter().map(|outp| outp.value).sum::<u64>());
+
+       // Now mine A's old commitment transaction, which should close the channel, but take no action
+       // on any of the HTLCs, at least until we get six confirmations (which we won't get).
+       mine_transaction(&nodes[1], &revoked_local_txn[0]);
+       check_added_monitors!(nodes[1], 1);
+       check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
+       check_closed_broadcast!(nodes[1], true);
+
+       // Connect up to one block before the revoked transaction would be considered final, then do a
+       // reorg that disconnects the full chain and goes up to the height at which the revoked
+       // transaction would be final.
+       let theoretical_conf_height = nodes[1].best_block_info().1 + ANTI_REORG_DELAY - 1;
+       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 2);
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+       assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+
+       disconnect_all_blocks(&nodes[1]);
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+       assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+
+       connect_blocks(&nodes[1], theoretical_conf_height);
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+       assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+
+       // Now connect A's latest commitment transaction instead and resolve the HTLCs
+       mine_transaction(&nodes[1], &unrevoked_local_txn[0]);
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+       assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+
+       // Connect the HTLC claim transaction for HTLC 3
+       mine_transaction(&nodes[1], &unrevoked_local_txn[2]);
+       expect_payment_sent!(nodes[1], payment_preimage_3);
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+
+       // Connect blocks to confirm the unrevoked commitment transaction
+       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 2);
+       expect_payment_failed!(nodes[1], payment_hash_4, true);
+}
+
 fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_unconfirmed: bool, connect_style: ConnectStyle) {
        // After creating a chan between nodes, we disconnect all blocks previously seen to force a
        // channel close on nodes[0] side. We also use this to provide very basic testing of logic
index 3dc245877e759fb8816ba0faa846f42386040f1a..3e9f7e343db01aa20a3d22332634cb5e18d112b4 100644 (file)
@@ -409,9 +409,9 @@ fn test_upfront_shutdown_script() {
        // enforce it at shutdown message
 
        let mut config = UserConfig::default();
-       config.channel_options.announced_channel = true;
-       config.peer_channel_config_limits.force_announced_channel_preference = false;
-       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       config.channel_handshake_config.announced_channel = true;
+       config.channel_handshake_limits.force_announced_channel_preference = false;
+       config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
        let user_cfgs = [None, Some(config), None];
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
@@ -574,9 +574,9 @@ fn test_invalid_upfront_shutdown_script() {
 #[test]
 fn test_segwit_v0_shutdown_script() {
        let mut config = UserConfig::default();
-       config.channel_options.announced_channel = true;
-       config.peer_channel_config_limits.force_announced_channel_preference = false;
-       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       config.channel_handshake_config.announced_channel = true;
+       config.channel_handshake_limits.force_announced_channel_preference = false;
+       config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
        let user_cfgs = [None, Some(config), None];
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
@@ -609,9 +609,9 @@ fn test_segwit_v0_shutdown_script() {
 #[test]
 fn test_anysegwit_shutdown_script() {
        let mut config = UserConfig::default();
-       config.channel_options.announced_channel = true;
-       config.peer_channel_config_limits.force_announced_channel_preference = false;
-       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       config.channel_handshake_config.announced_channel = true;
+       config.channel_handshake_limits.force_announced_channel_preference = false;
+       config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
        let user_cfgs = [None, Some(config), None];
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
@@ -644,9 +644,9 @@ fn test_anysegwit_shutdown_script() {
 #[test]
 fn test_unsupported_anysegwit_shutdown_script() {
        let mut config = UserConfig::default();
-       config.channel_options.announced_channel = true;
-       config.peer_channel_config_limits.force_announced_channel_preference = false;
-       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       config.channel_handshake_config.announced_channel = true;
+       config.channel_handshake_limits.force_announced_channel_preference = false;
+       config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
        let user_cfgs = [None, Some(config), None];
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let mut node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
@@ -686,9 +686,9 @@ fn test_unsupported_anysegwit_shutdown_script() {
 #[test]
 fn test_invalid_shutdown_script() {
        let mut config = UserConfig::default();
-       config.channel_options.announced_channel = true;
-       config.peer_channel_config_limits.force_announced_channel_preference = false;
-       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       config.channel_handshake_config.announced_channel = true;
+       config.channel_handshake_limits.force_announced_channel_preference = false;
+       config.channel_handshake_config.commit_upfront_shutdown_pubkey = false;
        let user_cfgs = [None, Some(config), None];
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
index 52cda7173ad486baa006747d97a809d8ab9cf8e8..736d2f0580002db9fed2957e99c6c22e4994b8ed 100644 (file)
@@ -28,7 +28,7 @@ use ln::msgs::{DecodeError, ErrorAction, Init, LightningError, RoutingMessageHan
 use ln::msgs::{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement, OptionalField, GossipTimestampFilter};
 use ln::msgs::{QueryChannelRange, ReplyChannelRange, QueryShortChannelIds, ReplyShortChannelIdsEnd};
 use ln::msgs;
-use util::ser::{Writeable, Readable, Writer};
+use util::ser::{Readable, ReadableArgs, Writeable, Writer};
 use util::logger::{Logger, Level};
 use util::events::{Event, EventHandler, MessageSendEvent, MessageSendEventsProvider};
 use util::scid_utils::{block_from_scid, scid_from_parts, MAX_SCID_BLOCK};
@@ -122,28 +122,16 @@ impl Readable for NodeId {
 }
 
 /// Represents the network as nodes and channels between them
-pub struct NetworkGraph {
+pub struct NetworkGraph<L: Deref> where L::Target: Logger {
+       secp_ctx: Secp256k1<secp256k1::VerifyOnly>,
        last_rapid_gossip_sync_timestamp: Mutex<Option<u32>>,
        genesis_hash: BlockHash,
+       logger: L,
        // Lock order: channels -> nodes
        channels: RwLock<BTreeMap<u64, ChannelInfo>>,
        nodes: RwLock<BTreeMap<NodeId, NodeInfo>>,
 }
 
-impl Clone for NetworkGraph {
-       fn clone(&self) -> Self {
-               let channels = self.channels.read().unwrap();
-               let nodes = self.nodes.read().unwrap();
-               let last_rapid_gossip_sync_timestamp = self.get_last_rapid_gossip_sync_timestamp();
-               Self {
-                       genesis_hash: self.genesis_hash.clone(),
-                       channels: RwLock::new(channels.clone()),
-                       nodes: RwLock::new(nodes.clone()),
-                       last_rapid_gossip_sync_timestamp: Mutex::new(last_rapid_gossip_sync_timestamp)
-               }
-       }
-}
-
 /// A read-only view of [`NetworkGraph`].
 pub struct ReadOnlyNetworkGraph<'a> {
        channels: RwLockReadGuard<'a, BTreeMap<u64, ChannelInfo>>,
@@ -196,17 +184,6 @@ impl_writeable_tlv_based_enum_upgradable!(NetworkUpdate,
        },
 );
 
-impl<G: Deref<Target=NetworkGraph>, C: Deref, L: Deref> EventHandler for P2PGossipSync<G, C, L>
-where C::Target: chain::Access, L::Target: Logger {
-       fn handle_event(&self, event: &Event) {
-               if let Event::PaymentPathFailed { payment_hash: _, rejected_by_dest: _, network_update, .. } = event {
-                       if let Some(network_update) = network_update {
-                               self.handle_network_update(network_update);
-                       }
-               }
-       }
-}
-
 /// Receives and validates network updates from peers,
 /// stores authentic and relevant data as a network graph.
 /// This network graph is then used for routing payments.
@@ -215,10 +192,9 @@ where C::Target: chain::Access, L::Target: Logger {
 ///
 /// Serves as an [`EventHandler`] for applying updates from [`Event::PaymentPathFailed`] to the
 /// [`NetworkGraph`].
-pub struct P2PGossipSync<G: Deref<Target=NetworkGraph>, C: Deref, L: Deref>
+pub struct P2PGossipSync<G: Deref<Target=NetworkGraph<L>>, C: Deref, L: Deref>
 where C::Target: chain::Access, L::Target: Logger
 {
-       secp_ctx: Secp256k1<secp256k1::VerifyOnly>,
        network_graph: G,
        chain_access: Option<C>,
        full_syncs_requested: AtomicUsize,
@@ -226,7 +202,7 @@ where C::Target: chain::Access, L::Target: Logger
        logger: L,
 }
 
-impl<G: Deref<Target=NetworkGraph>, C: Deref, L: Deref> P2PGossipSync<G, C, L>
+impl<G: Deref<Target=NetworkGraph<L>>, C: Deref, L: Deref> P2PGossipSync<G, C, L>
 where C::Target: chain::Access, L::Target: Logger
 {
        /// Creates a new tracker of the actual state of the network of channels and nodes,
@@ -236,7 +212,6 @@ where C::Target: chain::Access, L::Target: Logger
        /// channel owners' keys.
        pub fn new(network_graph: G, chain_access: Option<C>, logger: L) -> Self {
                P2PGossipSync {
-                       secp_ctx: Secp256k1::verification_only(),
                        network_graph,
                        full_syncs_requested: AtomicUsize::new(0),
                        chain_access,
@@ -271,27 +246,32 @@ where C::Target: chain::Access, L::Target: Logger
                        false
                }
        }
+}
 
-       /// Applies changes to the [`NetworkGraph`] from the given update.
-       fn handle_network_update(&self, update: &NetworkUpdate) {
-               match *update {
-                       NetworkUpdate::ChannelUpdateMessage { ref msg } => {
-                               let short_channel_id = msg.contents.short_channel_id;
-                               let is_enabled = msg.contents.flags & (1 << 1) != (1 << 1);
-                               let status = if is_enabled { "enabled" } else { "disabled" };
-                               log_debug!(self.logger, "Updating channel with channel_update from a payment failure. Channel {} is {}.", short_channel_id, status);
-                               let _ = self.network_graph.update_channel(msg, &self.secp_ctx);
-                       },
-                       NetworkUpdate::ChannelFailure { short_channel_id, is_permanent } => {
-                               let action = if is_permanent { "Removing" } else { "Disabling" };
-                               log_debug!(self.logger, "{} channel graph entry for {} due to a payment failure.", action, short_channel_id);
-                               self.network_graph.channel_failed(short_channel_id, is_permanent);
-                       },
-                       NetworkUpdate::NodeFailure { ref node_id, is_permanent } => {
-                               let action = if is_permanent { "Removing" } else { "Disabling" };
-                               log_debug!(self.logger, "{} node graph entry for {} due to a payment failure.", action, node_id);
-                               self.network_graph.node_failed(node_id, is_permanent);
-                       },
+impl<L: Deref> EventHandler for NetworkGraph<L> where L::Target: Logger {
+       fn handle_event(&self, event: &Event) {
+               if let Event::PaymentPathFailed { network_update, .. } = event {
+                       if let Some(network_update) = network_update {
+                               match *network_update {
+                                       NetworkUpdate::ChannelUpdateMessage { ref msg } => {
+                                               let short_channel_id = msg.contents.short_channel_id;
+                                               let is_enabled = msg.contents.flags & (1 << 1) != (1 << 1);
+                                               let status = if is_enabled { "enabled" } else { "disabled" };
+                                               log_debug!(self.logger, "Updating channel with channel_update from a payment failure. Channel {} is {}.", short_channel_id, status);
+                                               let _ = self.update_channel(msg);
+                                       },
+                                       NetworkUpdate::ChannelFailure { short_channel_id, is_permanent } => {
+                                               let action = if is_permanent { "Removing" } else { "Disabling" };
+                                               log_debug!(self.logger, "{} channel graph entry for {} due to a payment failure.", action, short_channel_id);
+                                               self.channel_failed(short_channel_id, is_permanent);
+                                       },
+                                       NetworkUpdate::NodeFailure { ref node_id, is_permanent } => {
+                                               let action = if is_permanent { "Removing" } else { "Disabling" };
+                                               log_debug!(self.logger, "{} node graph entry for {} due to a payment failure.", action, node_id);
+                                               self.node_failed(node_id, is_permanent);
+                                       },
+                               }
+                       }
                }
        }
 }
@@ -316,24 +296,24 @@ macro_rules! secp_verify_sig {
        };
 }
 
-impl<G: Deref<Target=NetworkGraph>, C: Deref, L: Deref> RoutingMessageHandler for P2PGossipSync<G, C, L>
+impl<G: Deref<Target=NetworkGraph<L>>, C: Deref, L: Deref> RoutingMessageHandler for P2PGossipSync<G, C, L>
 where C::Target: chain::Access, L::Target: Logger
 {
        fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<bool, LightningError> {
-               self.network_graph.update_node_from_announcement(msg, &self.secp_ctx)?;
+               self.network_graph.update_node_from_announcement(msg)?;
                Ok(msg.contents.excess_data.len() <=  MAX_EXCESS_BYTES_FOR_RELAY &&
                   msg.contents.excess_address_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY &&
                   msg.contents.excess_data.len() + msg.contents.excess_address_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY)
        }
 
        fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result<bool, LightningError> {
-               self.network_graph.update_channel_from_announcement(msg, &self.chain_access, &self.secp_ctx)?;
+               self.network_graph.update_channel_from_announcement(msg, &self.chain_access)?;
                log_gossip!(self.logger, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" });
                Ok(msg.contents.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY)
        }
 
        fn handle_channel_update(&self, msg: &msgs::ChannelUpdate) -> Result<bool, LightningError> {
-               self.network_graph.update_channel(msg, &self.secp_ctx)?;
+               self.network_graph.update_channel(msg)?;
                Ok(msg.contents.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY)
        }
 
@@ -605,7 +585,7 @@ where C::Target: chain::Access, L::Target: Logger
        }
 }
 
-impl<G: Deref<Target=NetworkGraph>, C: Deref, L: Deref> MessageSendEventsProvider for P2PGossipSync<G, C, L>
+impl<G: Deref<Target=NetworkGraph<L>>, C: Deref, L: Deref> MessageSendEventsProvider for P2PGossipSync<G, C, L>
 where
        C::Target: chain::Access,
        L::Target: Logger,
@@ -924,7 +904,7 @@ pub struct NodeAnnouncementInfo {
        /// Moniker assigned to the node.
        /// May be invalid or malicious (eg control chars),
        /// should not be exposed to the user.
-       pub alias: [u8; 32],
+       pub alias: NodeAlias,
        /// Internet-level addresses via which one can connect to the node
        pub addresses: Vec<NetAddress>,
        /// An initial announcement of the node
@@ -943,6 +923,51 @@ impl_writeable_tlv_based!(NodeAnnouncementInfo, {
        (10, addresses, vec_type),
 });
 
+/// A user-defined name for a node, which may be used when displaying the node in a graph.
+///
+/// Since node aliases are provided by third parties, they are a potential avenue for injection
+/// attacks. Care must be taken when processing.
+#[derive(Clone, Debug, PartialEq)]
+pub struct NodeAlias(pub [u8; 32]);
+
+impl fmt::Display for NodeAlias {
+       fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+               let control_symbol = core::char::REPLACEMENT_CHARACTER;
+               let first_null = self.0.iter().position(|b| *b == 0).unwrap_or(self.0.len());
+               let bytes = self.0.split_at(first_null).0;
+               match core::str::from_utf8(bytes) {
+                       Ok(alias) => {
+                               for c in alias.chars() {
+                                       let mut bytes = [0u8; 4];
+                                       let c = if !c.is_control() { c } else { control_symbol };
+                                       f.write_str(c.encode_utf8(&mut bytes))?;
+                               }
+                       },
+                       Err(_) => {
+                               for c in bytes.iter().map(|b| *b as char) {
+                                       // Display printable ASCII characters
+                                       let mut bytes = [0u8; 4];
+                                       let c = if c >= '\x20' && c <= '\x7e' { c } else { control_symbol };
+                                       f.write_str(c.encode_utf8(&mut bytes))?;
+                               }
+                       },
+               };
+               Ok(())
+       }
+}
+
+impl Writeable for NodeAlias {
+       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+               self.0.write(w)
+       }
+}
+
+impl Readable for NodeAlias {
+       fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
+               Ok(NodeAlias(Readable::read(r)?))
+       }
+}
+
 #[derive(Clone, Debug, PartialEq)]
 /// Details about a node in the network, known from the network announcement.
 pub struct NodeInfo {
@@ -975,7 +1000,7 @@ impl_writeable_tlv_based!(NodeInfo, {
 const SERIALIZATION_VERSION: u8 = 1;
 const MIN_SERIALIZATION_VERSION: u8 = 1;
 
-impl Writeable for NetworkGraph {
+impl<L: Deref> Writeable for NetworkGraph<L> where L::Target: Logger {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
                write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
 
@@ -1001,8 +1026,8 @@ impl Writeable for NetworkGraph {
        }
 }
 
-impl Readable for NetworkGraph {
-       fn read<R: io::Read>(reader: &mut R) -> Result<NetworkGraph, DecodeError> {
+impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
+       fn read<R: io::Read>(reader: &mut R, logger: L) -> Result<NetworkGraph<L>, DecodeError> {
                let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
 
                let genesis_hash: BlockHash = Readable::read(reader)?;
@@ -1027,7 +1052,9 @@ impl Readable for NetworkGraph {
                });
 
                Ok(NetworkGraph {
+                       secp_ctx: Secp256k1::verification_only(),
                        genesis_hash,
+                       logger,
                        channels: RwLock::new(channels),
                        nodes: RwLock::new(nodes),
                        last_rapid_gossip_sync_timestamp: Mutex::new(last_rapid_gossip_sync_timestamp),
@@ -1035,7 +1062,7 @@ impl Readable for NetworkGraph {
        }
 }
 
-impl fmt::Display for NetworkGraph {
+impl<L: Deref> fmt::Display for NetworkGraph<L> where L::Target: Logger {
        fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                writeln!(f, "Network map\n[Channels]")?;
                for (key, val) in self.channels.read().unwrap().iter() {
@@ -1049,7 +1076,7 @@ impl fmt::Display for NetworkGraph {
        }
 }
 
-impl PartialEq for NetworkGraph {
+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() &&
@@ -1057,11 +1084,13 @@ impl PartialEq for NetworkGraph {
        }
 }
 
-impl NetworkGraph {
+impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
        /// Creates a new, empty, network graph.
-       pub fn new(genesis_hash: BlockHash) -> NetworkGraph {
+       pub fn new(genesis_hash: BlockHash, logger: L) -> NetworkGraph<L> {
                Self {
+                       secp_ctx: Secp256k1::verification_only(),
                        genesis_hash,
+                       logger,
                        channels: RwLock::new(BTreeMap::new()),
                        nodes: RwLock::new(BTreeMap::new()),
                        last_rapid_gossip_sync_timestamp: Mutex::new(None),
@@ -1105,9 +1134,9 @@ impl NetworkGraph {
        /// You probably don't want to call this directly, instead relying on a P2PGossipSync's
        /// RoutingMessageHandler implementation to call it indirectly. This may be useful to accept
        /// routing messages from a source using a protocol other than the lightning P2P protocol.
-       pub fn update_node_from_announcement<T: secp256k1::Verification>(&self, msg: &msgs::NodeAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<(), LightningError> {
+       pub fn update_node_from_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<(), LightningError> {
                let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id, "node_announcement");
+               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id, "node_announcement");
                self.update_node_from_announcement_intern(&msg.contents, Some(&msg))
        }
 
@@ -1142,7 +1171,7 @@ impl NetworkGraph {
                                        features: msg.features.clone(),
                                        last_update: msg.timestamp,
                                        rgb: msg.rgb,
-                                       alias: msg.alias,
+                                       alias: NodeAlias(msg.alias),
                                        addresses: msg.addresses.clone(),
                                        announcement_message: if should_relay { full_msg.cloned() } else { None },
                                });
@@ -1160,17 +1189,17 @@ impl NetworkGraph {
        ///
        /// If a `chain::Access` object is provided via `chain_access`, it will be called to verify
        /// the corresponding UTXO exists on chain and is correctly-formatted.
-       pub fn update_channel_from_announcement<T: secp256k1::Verification, C: Deref>(
-               &self, msg: &msgs::ChannelAnnouncement, chain_access: &Option<C>, secp_ctx: &Secp256k1<T>
+       pub fn update_channel_from_announcement<C: Deref>(
+               &self, msg: &msgs::ChannelAnnouncement, chain_access: &Option<C>,
        ) -> Result<(), LightningError>
        where
                C::Target: chain::Access,
        {
                let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1, "channel_announcement");
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_2, &msg.contents.node_id_2, "channel_announcement");
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1, "channel_announcement");
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2, "channel_announcement");
+               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1, "channel_announcement");
+               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_2, &msg.contents.node_id_2, "channel_announcement");
+               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1, "channel_announcement");
+               secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2, "channel_announcement");
                self.update_channel_from_unsigned_announcement_intern(&msg.contents, Some(msg), chain_access)
        }
 
@@ -1432,8 +1461,8 @@ impl NetworkGraph {
        ///
        /// If built with `no-std`, any updates with a timestamp more than two weeks in the past or
        /// materially in the future will be rejected.
-       pub fn update_channel<T: secp256k1::Verification>(&self, msg: &msgs::ChannelUpdate, secp_ctx: &Secp256k1<T>) -> Result<(), LightningError> {
-               self.update_channel_intern(&msg.contents, Some(&msg), Some((&msg.signature, secp_ctx)))
+       pub fn update_channel(&self, msg: &msgs::ChannelUpdate) -> Result<(), LightningError> {
+               self.update_channel_intern(&msg.contents, Some(&msg), Some(&msg.signature))
        }
 
        /// For an already known (from announcement) channel, update info about one of the directions
@@ -1443,10 +1472,10 @@ impl NetworkGraph {
        /// If built with `no-std`, any updates with a timestamp more than two weeks in the past or
        /// materially in the future will be rejected.
        pub fn update_channel_unsigned(&self, msg: &msgs::UnsignedChannelUpdate) -> Result<(), LightningError> {
-               self.update_channel_intern(msg, None, None::<(&secp256k1::ecdsa::Signature, &Secp256k1<secp256k1::VerifyOnly>)>)
+               self.update_channel_intern(msg, None, None)
        }
 
-       fn update_channel_intern<T: secp256k1::Verification>(&self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>, sig_info: Option<(&secp256k1::ecdsa::Signature, &Secp256k1<T>)>) -> Result<(), LightningError> {
+       fn update_channel_intern(&self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>, sig: Option<&secp256k1::ecdsa::Signature>) -> Result<(), LightningError> {
                let dest_node_id;
                let chan_enabled = msg.flags & (1 << 1) != (1 << 1);
                let chan_was_enabled;
@@ -1527,8 +1556,8 @@ impl NetworkGraph {
                                if msg.flags & 1 == 1 {
                                        dest_node_id = channel.node_one.clone();
                                        check_update_latest!(channel.two_to_one);
-                                       if let Some((sig, ctx)) = sig_info {
-                                               secp_verify_sig!(ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_two.as_slice()).map_err(|_| LightningError{
+                                       if let Some(sig) = sig {
+                                               secp_verify_sig!(self.secp_ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_two.as_slice()).map_err(|_| LightningError{
                                                        err: "Couldn't parse source node pubkey".to_owned(),
                                                        action: ErrorAction::IgnoreAndLog(Level::Debug)
                                                })?, "channel_update");
@@ -1537,8 +1566,8 @@ impl NetworkGraph {
                                } else {
                                        dest_node_id = channel.node_two.clone();
                                        check_update_latest!(channel.one_to_two);
-                                       if let Some((sig, ctx)) = sig_info {
-                                               secp_verify_sig!(ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_one.as_slice()).map_err(|_| LightningError{
+                                       if let Some(sig) = sig {
+                                               secp_verify_sig!(self.secp_ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_one.as_slice()).map_err(|_| LightningError{
                                                        err: "Couldn't parse destination node pubkey".to_owned(),
                                                        action: ErrorAction::IgnoreAndLog(Level::Debug)
                                                })?, "channel_update");
@@ -1643,13 +1672,12 @@ mod tests {
        use chain;
        use ln::PaymentHash;
        use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
-       use routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate, MAX_EXCESS_BYTES_FOR_RELAY};
+       use routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate, NodeAlias, MAX_EXCESS_BYTES_FOR_RELAY};
        use ln::msgs::{Init, OptionalField, RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
                UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate,
                ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT};
        use util::test_utils;
-       use util::logger::Logger;
-       use util::ser::{Readable, Writeable};
+       use util::ser::{ReadableArgs, Writeable};
        use util::events::{Event, EventHandler, MessageSendEvent, MessageSendEventsProvider};
        use util::scid_utils::scid_from_parts;
 
@@ -1673,13 +1701,15 @@ mod tests {
        use prelude::*;
        use sync::Arc;
 
-       fn create_network_graph() -> NetworkGraph {
+       fn create_network_graph() -> NetworkGraph<Arc<test_utils::TestLogger>> {
                let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               NetworkGraph::new(genesis_hash)
+               let logger = Arc::new(test_utils::TestLogger::new());
+               NetworkGraph::new(genesis_hash, logger)
        }
 
-       fn create_gossip_sync(network_graph: &NetworkGraph) -> (
-               Secp256k1<All>, P2PGossipSync<&NetworkGraph, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>
+       fn create_gossip_sync(network_graph: &NetworkGraph<Arc<test_utils::TestLogger>>) -> (
+               Secp256k1<All>, P2PGossipSync<&NetworkGraph<Arc<test_utils::TestLogger>>,
+               Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>
        ) {
                let secp_ctx = Secp256k1::new();
                let logger = Arc::new(test_utils::TestLogger::new());
@@ -1843,7 +1873,7 @@ mod tests {
        #[test]
        fn handling_channel_announcements() {
                let secp_ctx = Secp256k1::new();
-               let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
+               let logger = test_utils::TestLogger::new();
 
                let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
                let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
@@ -1852,8 +1882,9 @@ mod tests {
                let valid_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
 
                // Test if the UTXO lookups were not supported
-               let network_graph = NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash());
-               let mut gossip_sync = P2PGossipSync::new(&network_graph, None, Arc::clone(&logger));
+               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
+               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let mut gossip_sync = P2PGossipSync::new(&network_graph, None, &logger);
                match gossip_sync.handle_channel_announcement(&valid_announcement) {
                        Ok(res) => assert!(res),
                        _ => panic!()
@@ -1874,10 +1905,10 @@ mod tests {
                };
 
                // Test if an associated transaction were not on-chain (or not confirmed).
-               let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
+               let chain_source = test_utils::TestChainSource::new(Network::Testnet);
                *chain_source.utxo_ret.lock().unwrap() = Err(chain::AccessError::UnknownTx);
-               let network_graph = NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash());
-               gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), Arc::clone(&logger));
+               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
 
                let valid_announcement = get_signed_channel_announcement(|unsigned_announcement| {
                        unsigned_announcement.short_channel_id += 1;
@@ -1958,10 +1989,11 @@ mod tests {
        #[test]
        fn handling_channel_update() {
                let secp_ctx = Secp256k1::new();
-               let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
-               let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
-               let network_graph = NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash());
-               let gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), Arc::clone(&logger));
+               let logger = test_utils::TestLogger::new();
+               let chain_source = test_utils::TestChainSource::new(Network::Testnet);
+               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
+               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
 
                let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
                let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
@@ -2061,10 +2093,8 @@ mod tests {
        #[test]
        fn handling_network_update() {
                let logger = test_utils::TestLogger::new();
-               let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
                let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let network_graph = NetworkGraph::new(genesis_hash);
-               let gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), &logger);
+               let network_graph = NetworkGraph::new(genesis_hash, &logger);
                let secp_ctx = Secp256k1::new();
 
                let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
@@ -2081,13 +2111,13 @@ mod tests {
                        let valid_channel_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
                        short_channel_id = valid_channel_announcement.contents.short_channel_id;
                        let chain_source: Option<&test_utils::TestChainSource> = None;
-                       assert!(network_graph.update_channel_from_announcement(&valid_channel_announcement, &chain_source, &secp_ctx).is_ok());
+                       assert!(network_graph.update_channel_from_announcement(&valid_channel_announcement, &chain_source).is_ok());
                        assert!(network_graph.read_only().channels().get(&short_channel_id).is_some());
 
                        let valid_channel_update = get_signed_channel_update(|_| {}, node_1_privkey, &secp_ctx);
                        assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_none());
 
-                       gossip_sync.handle_event(&Event::PaymentPathFailed {
+                       network_graph.handle_event(&Event::PaymentPathFailed {
                                payment_id: None,
                                payment_hash: PaymentHash([0; 32]),
                                rejected_by_dest: false,
@@ -2114,7 +2144,7 @@ mod tests {
                                }
                        };
 
-                       gossip_sync.handle_event(&Event::PaymentPathFailed {
+                       network_graph.handle_event(&Event::PaymentPathFailed {
                                payment_id: None,
                                payment_hash: PaymentHash([0; 32]),
                                rejected_by_dest: false,
@@ -2139,7 +2169,7 @@ mod tests {
                }
 
                // Permanent closing deletes a channel
-               gossip_sync.handle_event(&Event::PaymentPathFailed {
+               network_graph.handle_event(&Event::PaymentPathFailed {
                        payment_id: None,
                        payment_hash: PaymentHash([0; 32]),
                        rejected_by_dest: false,
@@ -2165,10 +2195,10 @@ mod tests {
        fn test_channel_timeouts() {
                // Test the removal of channels with `remove_stale_channels`.
                let logger = test_utils::TestLogger::new();
-               let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
+               let chain_source = test_utils::TestChainSource::new(Network::Testnet);
                let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let network_graph = NetworkGraph::new(genesis_hash);
-               let gossip_sync = P2PGossipSync::new(&network_graph, Some(chain_source.clone()), &logger);
+               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
                let secp_ctx = Secp256k1::new();
 
                let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
@@ -2177,7 +2207,7 @@ mod tests {
                let valid_channel_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
                let short_channel_id = valid_channel_announcement.contents.short_channel_id;
                let chain_source: Option<&test_utils::TestChainSource> = None;
-               assert!(network_graph.update_channel_from_announcement(&valid_channel_announcement, &chain_source, &secp_ctx).is_ok());
+               assert!(network_graph.update_channel_from_announcement(&valid_channel_announcement, &chain_source).is_ok());
                assert!(network_graph.read_only().channels().get(&short_channel_id).is_some());
 
                let valid_channel_update = get_signed_channel_update(|_| {}, node_1_privkey, &secp_ctx);
@@ -2380,7 +2410,9 @@ mod tests {
                assert!(!network_graph.read_only().nodes().is_empty());
                assert!(!network_graph.read_only().channels().is_empty());
                network_graph.write(&mut w).unwrap();
-               assert!(<NetworkGraph>::read(&mut io::Cursor::new(&w.0)).unwrap() == network_graph);
+
+               let logger = Arc::new(test_utils::TestLogger::new());
+               assert!(<NetworkGraph<_>>::read(&mut io::Cursor::new(&w.0), logger).unwrap() == network_graph);
        }
 
        #[test]
@@ -2390,7 +2422,9 @@ mod tests {
 
                let mut w = test_utils::TestVecWriter(Vec::new());
                network_graph.write(&mut w).unwrap();
-               let reassembled_network_graph: NetworkGraph = Readable::read(&mut io::Cursor::new(&w.0)).unwrap();
+
+               let logger = Arc::new(test_utils::TestLogger::new());
+               let reassembled_network_graph: NetworkGraph<_> = ReadableArgs::read(&mut io::Cursor::new(&w.0), logger).unwrap();
                assert!(reassembled_network_graph == network_graph);
                assert_eq!(reassembled_network_graph.get_last_rapid_gossip_sync_timestamp().unwrap(), 42);
        }
@@ -2679,7 +2713,7 @@ mod tests {
        }
 
        fn do_handling_query_channel_range(
-               gossip_sync: &P2PGossipSync<&NetworkGraph, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
+               gossip_sync: &P2PGossipSync<&NetworkGraph<Arc<test_utils::TestLogger>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
                test_node_id: &PublicKey,
                msg: QueryChannelRange,
                expected_ok: bool,
@@ -2741,6 +2775,29 @@ mod tests {
                });
                assert!(result.is_err());
        }
+
+       #[test]
+       fn displays_node_alias() {
+               let format_str_alias = |alias: &str| {
+                       let mut bytes = [0u8; 32];
+                       bytes[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes());
+                       format!("{}", NodeAlias(bytes))
+               };
+
+               assert_eq!(format_str_alias("I\u{1F496}LDK! \u{26A1}"), "I\u{1F496}LDK! \u{26A1}");
+               assert_eq!(format_str_alias("I\u{1F496}LDK!\0\u{26A1}"), "I\u{1F496}LDK!");
+               assert_eq!(format_str_alias("I\u{1F496}LDK!\t\u{26A1}"), "I\u{1F496}LDK!\u{FFFD}\u{26A1}");
+
+               let format_bytes_alias = |alias: &[u8]| {
+                       let mut bytes = [0u8; 32];
+                       bytes[..alias.len()].copy_from_slice(alias);
+                       format!("{}", NodeAlias(bytes))
+               };
+
+               assert_eq!(format_bytes_alias(b"\xFFI <heart> LDK!"), "\u{FFFD}I <heart> LDK!");
+               assert_eq!(format_bytes_alias(b"\xFFI <heart>\0LDK!"), "\u{FFFD}I <heart>");
+               assert_eq!(format_bytes_alias(b"\xFFI <heart>\tLDK!"), "\u{FFFD}I <heart>\u{FFFD}LDK!");
+       }
 }
 
 #[cfg(all(test, feature = "_bench_unstable"))]
@@ -2752,18 +2809,20 @@ mod benches {
 
        #[bench]
        fn read_network_graph(bench: &mut Bencher) {
+               let logger = ::util::test_utils::TestLogger::new();
                let mut d = ::routing::router::test_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)).unwrap();
+                       let _ = NetworkGraph::read(&mut std::io::Cursor::new(&v), &logger).unwrap();
                });
        }
 
        #[bench]
        fn write_network_graph(bench: &mut Bencher) {
+               let logger = ::util::test_utils::TestLogger::new();
                let mut d = ::routing::router::test_utils::get_route_file().unwrap();
-               let net_graph = NetworkGraph::read(&mut d).unwrap();
+               let net_graph = NetworkGraph::read(&mut d, &logger).unwrap();
                bench.iter(|| {
                        let _ = net_graph.encode();
                });
index 301ae76ddbb315e4aa02cec072e394f0bf87924f..634282d6c4b1f202fd0867312fc3dd83fc9b57fb 100644 (file)
@@ -17,7 +17,7 @@ use bitcoin::secp256k1::PublicKey;
 use ln::channelmanager::ChannelDetails;
 use ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
 use ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
-use routing::gossip::{DirectedChannelInfoWithUpdate, EffectiveCapacity, NetworkGraph, ReadOnlyNetworkGraph, NodeId, RoutingFees};
+use routing::gossip::{DirectedChannelInfoWithUpdate, EffectiveCapacity, ReadOnlyNetworkGraph, NodeId, RoutingFees};
 use routing::scoring::{ChannelUsage, Score};
 use util::ser::{Writeable, Readable, Writer};
 use util::logger::{Level, Logger};
@@ -176,6 +176,11 @@ impl_writeable_tlv_based!(RouteParameters, {
 /// Maximum total CTLV difference we allow for a full payment path.
 pub const DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA: u32 = 1008;
 
+/// Maximum number of paths we allow an MPP payment to have.
+// The default limit is currently set rather arbitrary - there aren't any real fundamental path-count
+// limits, but for now more than 10 paths likely carries too much one-path failure.
+pub const DEFAULT_MAX_MPP_PATH_COUNT: u8 = 10;
+
 // The median hop CLTV expiry delta currently seen in the network.
 const MEDIAN_HOP_CLTV_EXPIRY_DELTA: u32 = 40;
 
@@ -214,13 +219,19 @@ pub struct PaymentParameters {
        pub expiry_time: Option<u64>,
 
        /// The maximum total CLTV delta we accept for the route.
+       /// Defaults to [`DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA`].
        pub max_total_cltv_expiry_delta: u32,
+
+       /// The maximum number of paths that may be used by MPP payments.
+       /// Defaults to [`DEFAULT_MAX_MPP_PATH_COUNT`].
+       pub max_mpp_path_count: u8,
 }
 
 impl_writeable_tlv_based!(PaymentParameters, {
        (0, payee_pubkey, required),
        (1, max_total_cltv_expiry_delta, (default_value, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA)),
        (2, features, option),
+       (3, max_mpp_path_count, (default_value, DEFAULT_MAX_MPP_PATH_COUNT)),
        (4, route_hints, vec_type),
        (6, expiry_time, option),
 });
@@ -234,6 +245,7 @@ impl PaymentParameters {
                        route_hints: vec![],
                        expiry_time: None,
                        max_total_cltv_expiry_delta: DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
+                       max_mpp_path_count: DEFAULT_MAX_MPP_PATH_COUNT,
                }
        }
 
@@ -269,6 +281,13 @@ impl PaymentParameters {
        pub fn with_max_total_cltv_expiry_delta(self, max_total_cltv_expiry_delta: u32) -> Self {
                Self { max_total_cltv_expiry_delta, ..self }
        }
+
+       /// Includes a limit for the maximum number of payment paths that may be used by MPP.
+       ///
+       /// (C-not exported) since bindings don't support move semantics
+       pub fn with_max_mpp_path_count(self, max_mpp_path_count: u8) -> Self {
+               Self { max_mpp_path_count, ..self }
+       }
 }
 
 /// A list of hops along a payment path terminating with a channel to the recipient.
@@ -369,7 +388,7 @@ enum CandidateRouteHop<'a> {
        FirstHop {
                details: &'a ChannelDetails,
        },
-       /// A hop found in the [`NetworkGraph`], where the channel capacity may or may not be known.
+       /// A hop found in the [`ReadOnlyNetworkGraph`], where the channel capacity may be unknown.
        PublicHop {
                info: DirectedChannelInfoWithUpdate<'a>,
                short_channel_id: u64,
@@ -650,8 +669,8 @@ fn default_node_features() -> NodeFeatures {
 /// Private routing paths between a public node and the target may be included in `params.payee`.
 ///
 /// If some channels aren't announced, it may be useful to fill in `first_hops` with the results
-/// from [`ChannelManager::list_usable_channels`]. If it is filled in, the view of our local
-/// channels from [`NetworkGraph`] will be ignored, and only those in `first_hops` will be used.
+/// from [`ChannelManager::list_usable_channels`]. If it is filled in, the view of these channels
+/// from `network_graph` will be ignored, and only those in `first_hops` will be used.
 ///
 /// The fees on channels from us to the next hop are ignored as they are assumed to all be equal.
 /// However, the enabled/disabled bit on such channels as well as the `htlc_minimum_msat` /
@@ -670,16 +689,17 @@ fn default_node_features() -> NodeFeatures {
 ///
 /// [`ChannelManager::list_usable_channels`]: crate::ln::channelmanager::ChannelManager::list_usable_channels
 /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
+/// [`NetworkGraph`]: crate::routing::gossip::NetworkGraph
 pub fn find_route<L: Deref, S: Score>(
-       our_node_pubkey: &PublicKey, route_params: &RouteParameters, network: &NetworkGraph,
-       first_hops: Option<&[&ChannelDetails]>, logger: L, scorer: &S, random_seed_bytes: &[u8; 32]
+       our_node_pubkey: &PublicKey, route_params: &RouteParameters,
+       network_graph: &ReadOnlyNetworkGraph, first_hops: Option<&[&ChannelDetails]>, logger: L,
+       scorer: &S, random_seed_bytes: &[u8; 32]
 ) -> Result<Route, LightningError>
 where L::Target: Logger {
-       let network_graph = network.read_only();
-       let mut route = get_route(our_node_pubkey, &route_params.payment_params, &network_graph, first_hops,
+       let mut route = get_route(our_node_pubkey, &route_params.payment_params, network_graph, first_hops,
                route_params.final_value_msat, route_params.final_cltv_expiry_delta, logger, scorer,
                random_seed_bytes)?;
-       add_random_cltv_offset(&mut route, &route_params.payment_params, &network_graph, random_seed_bytes);
+       add_random_cltv_offset(&mut route, &route_params.payment_params, network_graph, random_seed_bytes);
        Ok(route)
 }
 
@@ -789,6 +809,11 @@ where L::Target: Logger {
                        node_info.features.supports_basic_mpp()
                } else { false }
        } else { false };
+
+       if allow_mpp && payment_params.max_mpp_path_count == 0 {
+               return Err(LightningError{err: "Can't find an MPP route with no paths allowed.".to_owned(), action: ErrorAction::IgnoreError});
+       }
+
        log_trace!(logger, "Searching for a route from payer {} to payee {} {} MPP and {} first hops {}overriding the network graph", our_node_pubkey,
                payment_params.payee_pubkey, if allow_mpp { "with" } else { "without" },
                first_hops.map(|hops| hops.len()).unwrap_or(0), if first_hops.is_some() { "" } else { "not " });
@@ -839,6 +864,21 @@ where L::Target: Logger {
        let recommended_value_msat = final_value_msat * ROUTE_CAPACITY_PROVISION_FACTOR as u64;
        let mut path_value_msat = final_value_msat;
 
+       // Routing Fragmentation Mitigation heuristic:
+       //
+       // Routing fragmentation across many payment paths increases the overall routing
+       // fees as you have irreducible routing fees per-link used (`fee_base_msat`).
+       // Taking too many smaller paths also increases the chance of payment failure.
+       // Thus to avoid this effect, we require from our collected links to provide
+       // at least a minimal contribution to the recommended value yet-to-be-fulfilled.
+       // This requirement is currently set to be 1/max_mpp_path_count of the payment
+       // value to ensure we only ever return routes that do not violate this limit.
+       let minimal_value_contribution_msat: u64 = if allow_mpp {
+               (final_value_msat + (payment_params.max_mpp_path_count as u64 - 1)) / payment_params.max_mpp_path_count as u64
+       } else {
+               final_value_msat
+       };
+
        // Keep track of how much liquidity has been used in selected channels. Used to determine
        // if the channel can be used by additional MPP paths or to inform path finding decisions. It is
        // aware of direction *only* to ensure that the correct htlc_maximum_msat value is used. Hence,
@@ -846,11 +886,8 @@ where L::Target: Logger {
        let mut used_channel_liquidities: HashMap<(u64, bool), u64> =
                HashMap::with_capacity(network_nodes.len());
 
-       // Keeping track of how much value we already collected across other paths. Helps to decide:
-       // - how much a new path should be transferring (upper bound);
-       // - whether a channel should be disregarded because
-       //   it's available liquidity is too small comparing to how much more we need to collect;
-       // - when we want to stop looking for new paths.
+       // Keeping track of how much value we already collected across other paths. Helps to decide
+       // when we want to stop looking for new paths.
        let mut already_collected_value_msat = 0;
 
        for (_, channels) in first_hop_targets.iter_mut() {
@@ -912,26 +949,6 @@ where L::Target: Logger {
                                                        *used_liquidity_msat
                                                });
 
-                                       // Routing Fragmentation Mitigation heuristic:
-                                       //
-                                       // Routing fragmentation across many payment paths increases the overall routing
-                                       // fees as you have irreducible routing fees per-link used (`fee_base_msat`).
-                                       // Taking too many smaller paths also increases the chance of payment failure.
-                                       // Thus to avoid this effect, we require from our collected links to provide
-                                       // at least a minimal contribution to the recommended value yet-to-be-fulfilled.
-                                       //
-                                       // This requirement is currently 5% of the remaining-to-be-collected value.
-                                       // This means as we successfully advance in our collection,
-                                       // the absolute liquidity contribution is lowered,
-                                       // thus increasing the number of potential channels to be selected.
-
-                                       // Derive the minimal liquidity contribution with a ratio of 20 (5%, rounded up)
-                                       // or 100% if we're not allowed to do multipath payments.
-                                       let minimal_value_contribution_msat: u64 = if allow_mpp {
-                                               (recommended_value_msat - already_collected_value_msat + 19) / 20
-                                       } else {
-                                               final_value_msat
-                                       };
                                        // Verify the liquidity offered by this channel complies to the minimal contribution.
                                        let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
                                        // Do not consider candidate hops that would exceed the maximum path length.
@@ -1503,10 +1520,8 @@ where L::Target: Logger {
                                        *used_channel_liquidities.entry((victim_scid, true)).or_default() = exhausted;
                                }
 
-                               // Track the total amount all our collected paths allow to send so that we:
-                               // - know when to stop looking for more paths
-                               // - know which of the hops are useless considering how much more sats we need
-                               //   (contributes_sufficient_value)
+                               // Track the total amount all our collected paths allow to send so that we know
+                               // when to stop looking for more paths
                                already_collected_value_msat += value_contribution_msat;
 
                                payment_paths.push(payment_path);
@@ -1677,6 +1692,8 @@ where L::Target: Logger {
                });
                selected_paths.push(path);
        }
+       // Make sure we would never create a route with more paths than we allow.
+       debug_assert!(selected_paths.len() <= payment_params.max_mpp_path_count.into());
 
        if let Some(features) = &payment_params.features {
                for path in selected_paths.iter_mut() {
@@ -1787,11 +1804,10 @@ fn add_random_cltv_offset(route: &mut Route, payment_params: &PaymentParameters,
 ///
 /// Re-uses logic from `find_route`, so the restrictions described there also apply here.
 pub fn build_route_from_hops<L: Deref>(
-       our_node_pubkey: &PublicKey, hops: &[PublicKey], route_params: &RouteParameters, network: &NetworkGraph,
-       logger: L, random_seed_bytes: &[u8; 32]
+       our_node_pubkey: &PublicKey, hops: &[PublicKey], route_params: &RouteParameters,
+       network_graph: &ReadOnlyNetworkGraph, logger: L, random_seed_bytes: &[u8; 32]
 ) -> Result<Route, LightningError>
 where L::Target: Logger {
-       let network_graph = network.read_only();
        let mut route = build_route_from_hops_internal(
                our_node_pubkey, hops, &route_params.payment_params, &network_graph,
                route_params.final_value_msat, route_params.final_cltv_expiry_delta, logger, random_seed_bytes)?;
@@ -1921,12 +1937,13 @@ mod tests {
                        is_usable: true, is_public: true,
                        inbound_htlc_minimum_msat: None,
                        inbound_htlc_maximum_msat: None,
+                       config: None,
                }
        }
 
        // Using the same keys for LN and BTC ids
        fn add_channel(
-               gossip_sync: &P2PGossipSync<Arc<NetworkGraph>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
+               gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
                secp_ctx: &Secp256k1<All>, node_1_privkey: &SecretKey, node_2_privkey: &SecretKey, features: ChannelFeatures, short_channel_id: u64
        ) {
                let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
@@ -1958,7 +1975,7 @@ mod tests {
        }
 
        fn update_channel(
-               gossip_sync: &P2PGossipSync<Arc<NetworkGraph>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
+               gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
                secp_ctx: &Secp256k1<All>, node_privkey: &SecretKey, update: UnsignedChannelUpdate
        ) {
                let msghash = hash_to_message!(&Sha256dHash::hash(&update.encode()[..])[..]);
@@ -1974,7 +1991,7 @@ mod tests {
        }
 
        fn add_or_update_node(
-               gossip_sync: &P2PGossipSync<Arc<NetworkGraph>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
+               gossip_sync: &P2PGossipSync<Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, Arc<test_utils::TestChainSource>, Arc<test_utils::TestLogger>>,
                secp_ctx: &Secp256k1<All>, node_privkey: &SecretKey, features: NodeFeatures, timestamp: u32
        ) {
                let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey);
@@ -2029,14 +2046,15 @@ mod tests {
        }
 
        fn build_line_graph() -> (
-               Secp256k1<All>, sync::Arc<NetworkGraph>, P2PGossipSync<sync::Arc<NetworkGraph>,
-               sync::Arc<test_utils::TestChainSource>, sync::Arc<crate::util::test_utils::TestLogger>>,
+               Secp256k1<All>, sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
+               P2PGossipSync<sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>>,
                sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>,
        ) {
                let secp_ctx = Secp256k1::new();
                let logger = Arc::new(test_utils::TestLogger::new());
                let chain_monitor = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
-               let network_graph = Arc::new(NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()));
+               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
+               let network_graph = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
                let gossip_sync = P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
 
                // Build network from our_id to node 19:
@@ -2081,15 +2099,16 @@ mod tests {
 
        fn build_graph() -> (
                Secp256k1<All>,
-               sync::Arc<NetworkGraph>,
-               P2PGossipSync<sync::Arc<NetworkGraph>, sync::Arc<test_utils::TestChainSource>, sync::Arc<crate::util::test_utils::TestLogger>>,
+               sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>,
+               P2PGossipSync<sync::Arc<NetworkGraph<Arc<test_utils::TestLogger>>>, sync::Arc<test_utils::TestChainSource>, sync::Arc<test_utils::TestLogger>>,
                sync::Arc<test_utils::TestChainSource>,
                sync::Arc<test_utils::TestLogger>,
        ) {
                let secp_ctx = Secp256k1::new();
                let logger = Arc::new(test_utils::TestLogger::new());
                let chain_monitor = Arc::new(test_utils::TestChainSource::new(Network::Testnet));
-               let network_graph = Arc::new(NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()));
+               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
+               let network_graph = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
                let gossip_sync = P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
                // Build network from our_id to node6:
                //
@@ -3489,8 +3508,12 @@ mod tests {
                let scorer = test_utils::TestScorer::with_penalty(0);
                let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
-               get_route(&source_node_id, &payment_params, &NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()).read_only(),
-                               Some(&our_chans.iter().collect::<Vec<_>>()), route_val, 42, &test_utils::TestLogger::new(), &scorer, &random_seed_bytes)
+               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
+               let logger = test_utils::TestLogger::new();
+               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let route = get_route(&source_node_id, &payment_params, &network_graph.read_only(),
+                               Some(&our_chans.iter().collect::<Vec<_>>()), route_val, 42, &logger, &scorer, &random_seed_bytes);
+               route
        }
 
        #[test]
@@ -3993,7 +4016,8 @@ mod tests {
                let scorer = test_utils::TestScorer::with_penalty(0);
                let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
-               let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
+               let payment_params = PaymentParameters::from_node_id(nodes[2])
+                       .with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 3 paths:
                // From our node to node2 via node0, node7, node1 (three paths one hop each).
@@ -4086,15 +4110,39 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph.read_only(), None, 300_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
-                               assert_eq!(err, "Failed to find a sufficient route to the given destination");
+                               &our_id, &payment_params, &network_graph.read_only(), None, 300_000, 42,
+                               Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       assert_eq!(err, "Failed to find a sufficient route to the given destination");
+                       } else { panic!(); }
+               }
+
+               {
+                       // Attempt to route while setting max_mpp_path_count to 0 results in a failure.
+                       let zero_payment_params = payment_params.clone().with_max_mpp_path_count(0);
+                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
+                               &our_id, &zero_payment_params, &network_graph.read_only(), None, 100, 42,
+                               Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       assert_eq!(err, "Can't find an MPP route with no paths allowed.");
+                       } else { panic!(); }
+               }
+
+               {
+                       // Attempt to route while setting max_mpp_path_count to 3 results in a failure.
+                       // This is the case because the minimal_value_contribution_msat would require each path
+                       // to account for 1/3 of the total value, which is violated by 2 out of 3 paths.
+                       let fail_payment_params = payment_params.clone().with_max_mpp_path_count(3);
+                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
+                               &our_id, &fail_payment_params, &network_graph.read_only(), None, 250_000, 42,
+                               Arc::clone(&logger), &scorer, &random_seed_bytes) {
+                                       assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
 
                {
                        // Now, attempt to route 250 sats (just a bit below the capacity).
                        // Our algorithm should provide us with these 3 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None,
+                               250_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4107,7 +4155,8 @@ mod tests {
 
                {
                        // Attempt to route an exact amount is also fine
-                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 290_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None,
+                               290_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4882,8 +4931,9 @@ mod tests {
                // payment) htlc_minimum_msat. In the original algorithm, this resulted in node4's
                // "previous hop" being set to node 3, creating a loop in the path.
                let secp_ctx = Secp256k1::new();
+               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
                let logger = Arc::new(test_utils::TestLogger::new());
-               let network = Arc::new(NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()));
+               let network = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
                let gossip_sync = P2PGossipSync::new(Arc::clone(&network), None, Arc::clone(&logger));
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
@@ -5148,8 +5198,9 @@ mod tests {
                // route over multiple channels with the same first hop.
                let secp_ctx = Secp256k1::new();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
                let logger = Arc::new(test_utils::TestLogger::new());
-               let network_graph = NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash());
+               let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger));
                let scorer = test_utils::TestScorer::with_penalty(0);
                let payment_params = PaymentParameters::from_node_id(nodes[0]).with_features(InvoiceFeatures::known());
                let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
@@ -5587,7 +5638,7 @@ mod tests {
                seed
        }
        #[cfg(not(feature = "no-std"))]
-       use util::ser::Readable;
+       use util::ser::ReadableArgs;
 
        #[test]
        #[cfg(not(feature = "no-std"))]
@@ -5601,7 +5652,8 @@ mod tests {
                                return;
                        },
                };
-               let graph = NetworkGraph::read(&mut d).unwrap();
+               let logger = test_utils::TestLogger::new();
+               let graph = NetworkGraph::read(&mut d, &logger).unwrap();
                let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
@@ -5617,7 +5669,6 @@ mod tests {
                                let payment_params = PaymentParameters::from_node_id(dst);
                                let amt = seed as u64 % 200_000_000;
                                let params = ProbabilisticScoringParameters::default();
-                               let logger = test_utils::TestLogger::new();
                                let scorer = ProbabilisticScorer::new(params, &graph, &logger);
                                if get_route(src, &payment_params, &graph.read_only(), None, amt, 42, &logger, &scorer, &random_seed_bytes).is_ok() {
                                        continue 'load_endpoints;
@@ -5638,7 +5689,8 @@ mod tests {
                                return;
                        },
                };
-               let graph = NetworkGraph::read(&mut d).unwrap();
+               let logger = test_utils::TestLogger::new();
+               let graph = NetworkGraph::read(&mut d, &logger).unwrap();
                let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
@@ -5654,7 +5706,6 @@ mod tests {
                                let payment_params = PaymentParameters::from_node_id(dst).with_features(InvoiceFeatures::known());
                                let amt = seed as u64 % 200_000_000;
                                let params = ProbabilisticScoringParameters::default();
-                               let logger = test_utils::TestLogger::new();
                                let scorer = ProbabilisticScorer::new(params, &graph, &logger);
                                if get_route(src, &payment_params, &graph.read_only(), None, amt, 42, &logger, &scorer, &random_seed_bytes).is_ok() {
                                        continue 'load_endpoints;
@@ -5700,9 +5751,10 @@ mod benches {
        use chain::keysinterface::{KeysManager,KeysInterface};
        use ln::channelmanager::{ChannelCounterparty, ChannelDetails};
        use ln::features::{InitFeatures, InvoiceFeatures};
+       use routing::gossip::NetworkGraph;
        use routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringParameters};
        use util::logger::{Logger, Record};
-       use util::test_utils::TestLogger;
+       use util::ser::ReadableArgs;
 
        use test::Bencher;
 
@@ -5711,9 +5763,9 @@ mod benches {
                fn log(&self, _record: &Record) {}
        }
 
-       fn read_network_graph() -> NetworkGraph {
+       fn read_network_graph(logger: &DummyLogger) -> NetworkGraph<&DummyLogger> {
                let mut d = test_utils::get_route_file().unwrap();
-               NetworkGraph::read(&mut d).unwrap()
+               NetworkGraph::read(&mut d, logger).unwrap()
        }
 
        fn payer_pubkey() -> PublicKey {
@@ -5755,27 +5807,30 @@ mod benches {
                        is_public: true,
                        inbound_htlc_minimum_msat: None,
                        inbound_htlc_maximum_msat: None,
+                       config: None,
                }
        }
 
        #[bench]
        fn generate_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
-               let network_graph = read_network_graph();
+               let logger = DummyLogger {};
+               let network_graph = read_network_graph(&logger);
                let scorer = FixedPenaltyScorer::with_penalty(0);
                generate_routes(bench, &network_graph, scorer, InvoiceFeatures::empty());
        }
 
        #[bench]
        fn generate_mpp_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
-               let network_graph = read_network_graph();
+               let logger = DummyLogger {};
+               let network_graph = read_network_graph(&logger);
                let scorer = FixedPenaltyScorer::with_penalty(0);
                generate_routes(bench, &network_graph, scorer, InvoiceFeatures::known());
        }
 
        #[bench]
        fn generate_routes_with_probabilistic_scorer(bench: &mut Bencher) {
-               let logger = TestLogger::new();
-               let network_graph = read_network_graph();
+               let logger = DummyLogger {};
+               let network_graph = read_network_graph(&logger);
                let params = ProbabilisticScoringParameters::default();
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                generate_routes(bench, &network_graph, scorer, InvoiceFeatures::empty());
@@ -5783,15 +5838,16 @@ mod benches {
 
        #[bench]
        fn generate_mpp_routes_with_probabilistic_scorer(bench: &mut Bencher) {
-               let logger = TestLogger::new();
-               let network_graph = read_network_graph();
+               let logger = DummyLogger {};
+               let network_graph = read_network_graph(&logger);
                let params = ProbabilisticScoringParameters::default();
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                generate_routes(bench, &network_graph, scorer, InvoiceFeatures::known());
        }
 
        fn generate_routes<S: Score>(
-               bench: &mut Bencher, graph: &NetworkGraph, mut scorer: S, features: InvoiceFeatures
+               bench: &mut Bencher, graph: &NetworkGraph<&DummyLogger>, mut scorer: S,
+               features: InvoiceFeatures
        ) {
                let nodes = graph.read_only().nodes().clone();
                let payer = payer_pubkey();
index 54400624dce63a30ec0e506bfc1c87800a6bac4a..f7fe5863838f2aefbab77e173fe7fe4ae72c4c0d 100644 (file)
@@ -28,7 +28,7 @@
 //! # impl Logger for FakeLogger {
 //! #     fn log(&self, record: &Record) { unimplemented!() }
 //! # }
-//! # fn find_scored_route(payer: PublicKey, route_params: RouteParameters, network_graph: NetworkGraph) {
+//! # fn find_scored_route(payer: PublicKey, route_params: RouteParameters, network_graph: NetworkGraph<&FakeLogger>) {
 //! # let logger = FakeLogger {};
 //! #
 //! // Use the default channel penalties.
@@ -43,7 +43,7 @@
 //! let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
 //! # let random_seed_bytes = [42u8; 32];
 //!
-//! let route = find_route(&payer, &route_params, &network_graph, None, &logger, &scorer, &random_seed_bytes);
+//! let route = find_route(&payer, &route_params, &network_graph.read_only(), None, &logger, &scorer, &random_seed_bytes);
 //! # }
 //! ```
 //!
@@ -293,7 +293,8 @@ pub type ProbabilisticScorer<G, L> = ProbabilisticScorerUsingTime::<G, L, Config
 /// Probabilistic [`Score`] implementation.
 ///
 /// (C-not exported) generally all users should use the [`ProbabilisticScorer`] type alias.
-pub struct ProbabilisticScorerUsingTime<G: Deref<Target = NetworkGraph>, L: Deref, T: Time> where L::Target: Logger {
+pub struct ProbabilisticScorerUsingTime<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time>
+where L::Target: Logger {
        params: ProbabilisticScoringParameters,
        network_graph: G,
        logger: L,
@@ -389,7 +390,7 @@ struct DirectedChannelLiquidity<L: Deref<Target = u64>, T: Time, U: Deref<Target
        half_life: Duration,
 }
 
-impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time> ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
        /// Creates a new scorer using the given scoring parameters for sending payments from a node
        /// through a network graph.
        pub fn new(params: ProbabilisticScoringParameters, network_graph: G, logger: L) -> Self {
@@ -433,6 +434,23 @@ impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time> ProbabilisticScorerUsin
                        }
                }
        }
+
+       /// Query the estimated minimum and maximum liquidity available for sending a payment over the
+       /// channel with `scid` towards the given `target` node.
+       pub fn estimated_channel_liquidity_range(&self, scid: u64, target: &NodeId) -> Option<(u64, u64)> {
+               let graph = self.network_graph.read_only();
+
+               if let Some(chan) = graph.channels().get(&scid) {
+                       if let Some(liq) = self.channel_liquidities.get(&scid) {
+                               if let Some((directed_info, source)) = chan.as_directed_to(target) {
+                                       let amt = directed_info.effective_capacity().as_msat();
+                                       let dir_liq = liq.as_directed(source, target, amt, self.params.liquidity_offset_half_life);
+                                       return Some((dir_liq.min_liquidity_msat(), dir_liq.max_liquidity_msat()));
+                               }
+                       }
+               }
+               None
+       }
 }
 
 impl ProbabilisticScoringParameters {
@@ -650,7 +668,7 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
        }
 }
 
-impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time> Score for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
        fn channel_penalty_msat(
                &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
        ) -> u64 {
@@ -1050,7 +1068,7 @@ mod approx {
        }
 }
 
-impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time> Writeable for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Writeable for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
        #[inline]
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
                write_tlv_fields!(w, {
@@ -1060,7 +1078,7 @@ impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time> Writeable for Probabili
        }
 }
 
-impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time>
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time>
 ReadableArgs<(ProbabilisticScoringParameters, G, L)> for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
        #[inline]
        fn read<R: Read>(
@@ -1163,7 +1181,7 @@ mod tests {
        // `ProbabilisticScorer` tests
 
        /// A probabilistic scorer for testing with time that can be manually advanced.
-       type ProbabilisticScorer<'a> = ProbabilisticScorerUsingTime::<&'a NetworkGraph, &'a TestLogger, SinceEpoch>;
+       type ProbabilisticScorer<'a> = ProbabilisticScorerUsingTime::<&'a NetworkGraph<&'a TestLogger>, &'a TestLogger, SinceEpoch>;
 
        fn sender_privkey() -> SecretKey {
                SecretKey::from_slice(&[41; 32]).unwrap()
@@ -1191,9 +1209,9 @@ mod tests {
                NodeId::from_pubkey(&recipient_pubkey())
        }
 
-       fn network_graph() -> NetworkGraph {
+       fn network_graph(logger: &TestLogger) -> NetworkGraph<&TestLogger> {
                let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let mut network_graph = NetworkGraph::new(genesis_hash);
+               let mut network_graph = NetworkGraph::new(genesis_hash, logger);
                add_channel(&mut network_graph, 42, source_privkey(), target_privkey());
                add_channel(&mut network_graph, 43, target_privkey(), recipient_privkey());
 
@@ -1201,7 +1219,7 @@ mod tests {
        }
 
        fn add_channel(
-               network_graph: &mut NetworkGraph, short_channel_id: u64, node_1_key: SecretKey,
+               network_graph: &mut NetworkGraph<&TestLogger>, short_channel_id: u64, node_1_key: SecretKey,
                node_2_key: SecretKey
        ) {
                let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
@@ -1228,13 +1246,14 @@ mod tests {
                };
                let chain_source: Option<&::util::test_utils::TestChainSource> = None;
                network_graph.update_channel_from_announcement(
-                       &signed_announcement, &chain_source, &secp_ctx).unwrap();
+                       &signed_announcement, &chain_source).unwrap();
                update_channel(network_graph, short_channel_id, node_1_key, 0);
                update_channel(network_graph, short_channel_id, node_2_key, 1);
        }
 
        fn update_channel(
-               network_graph: &mut NetworkGraph, short_channel_id: u64, node_key: SecretKey, flags: u8
+               network_graph: &mut NetworkGraph<&TestLogger>, short_channel_id: u64, node_key: SecretKey,
+               flags: u8
        ) {
                let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
                let secp_ctx = Secp256k1::new();
@@ -1255,7 +1274,7 @@ mod tests {
                        signature: secp_ctx.sign_ecdsa(&msghash, &node_key),
                        contents: unsigned_update,
                };
-               network_graph.update_channel(&signed_update, &secp_ctx).unwrap();
+               network_graph.update_channel(&signed_update).unwrap();
        }
 
        fn payment_path_for_amount(amount_msat: u64) -> Vec<RouteHop> {
@@ -1291,7 +1310,7 @@ mod tests {
        fn liquidity_bounds_directed_from_lowest_node_id() {
                let logger = TestLogger::new();
                let last_updated = SinceEpoch::now();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters::default();
                let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
                        .with_channel(42,
@@ -1366,7 +1385,7 @@ mod tests {
        fn resets_liquidity_upper_bound_when_crossed_by_lower_bound() {
                let logger = TestLogger::new();
                let last_updated = SinceEpoch::now();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters::default();
                let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
                        .with_channel(42,
@@ -1424,7 +1443,7 @@ mod tests {
        fn resets_liquidity_lower_bound_when_crossed_by_upper_bound() {
                let logger = TestLogger::new();
                let last_updated = SinceEpoch::now();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters::default();
                let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
                        .with_channel(42,
@@ -1481,7 +1500,7 @@ mod tests {
        #[test]
        fn increased_penalty_nearing_liquidity_upper_bound() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        ..ProbabilisticScoringParameters::zero_penalty()
@@ -1527,7 +1546,7 @@ mod tests {
        fn constant_penalty_outside_liquidity_bounds() {
                let logger = TestLogger::new();
                let last_updated = SinceEpoch::now();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        ..ProbabilisticScoringParameters::zero_penalty()
@@ -1556,7 +1575,7 @@ mod tests {
        #[test]
        fn does_not_further_penalize_own_channel() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        ..ProbabilisticScoringParameters::zero_penalty()
@@ -1584,7 +1603,7 @@ mod tests {
        #[test]
        fn sets_liquidity_lower_bound_on_downstream_failure() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        ..ProbabilisticScoringParameters::zero_penalty()
@@ -1618,7 +1637,7 @@ mod tests {
        #[test]
        fn sets_liquidity_upper_bound_on_failure() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        ..ProbabilisticScoringParameters::zero_penalty()
@@ -1652,7 +1671,7 @@ mod tests {
        #[test]
        fn reduces_liquidity_upper_bound_along_path_on_success() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        ..ProbabilisticScoringParameters::zero_penalty()
@@ -1683,7 +1702,7 @@ mod tests {
        #[test]
        fn decays_liquidity_bounds_over_time() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        liquidity_offset_half_life: Duration::from_secs(10),
@@ -1762,7 +1781,7 @@ mod tests {
        #[test]
        fn decays_liquidity_bounds_without_shift_overflow() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        liquidity_offset_half_life: Duration::from_secs(10),
@@ -1793,7 +1812,7 @@ mod tests {
        #[test]
        fn restricts_liquidity_bounds_after_decay() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        liquidity_offset_half_life: Duration::from_secs(10),
@@ -1837,7 +1856,7 @@ mod tests {
        #[test]
        fn restores_persisted_liquidity_bounds() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        liquidity_offset_half_life: Duration::from_secs(10),
@@ -1873,7 +1892,7 @@ mod tests {
        #[test]
        fn decays_persisted_liquidity_bounds() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        liquidity_offset_half_life: Duration::from_secs(10),
@@ -1913,7 +1932,7 @@ mod tests {
                // Shows the scores of "realistic" sends of 100k sats over channels of 1-10m sats (with a
                // 50k sat reserve).
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters::default();
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                let source = source_node_id();
@@ -1970,7 +1989,7 @@ mod tests {
        #[test]
        fn adds_base_penalty_to_liquidity_penalty() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let source = source_node_id();
                let target = target_node_id();
                let usage = ChannelUsage {
@@ -1996,7 +2015,7 @@ mod tests {
        #[test]
        fn adds_amount_penalty_to_liquidity_penalty() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let source = source_node_id();
                let target = target_node_id();
                let usage = ChannelUsage {
@@ -2025,7 +2044,7 @@ mod tests {
        #[test]
        fn calculates_log10_without_overflowing_u64_max_value() {
                let logger = TestLogger::new();
-               let network_graph = network_graph();
+               let network_graph = network_graph(&logger);
                let source = source_node_id();
                let target = target_node_id();
                let usage = ChannelUsage {
@@ -2044,8 +2063,8 @@ mod tests {
 
        #[test]
        fn accounts_for_inflight_htlc_usage() {
-               let network_graph = network_graph();
                let logger = TestLogger::new();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters::default();
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                let source = source_node_id();
@@ -2064,8 +2083,8 @@ mod tests {
 
        #[test]
        fn removes_uncertainity_when_exact_liquidity_known() {
-               let network_graph = network_graph();
                let logger = TestLogger::new();
+               let network_graph = network_graph(&logger);
                let params = ProbabilisticScoringParameters::default();
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                let source = source_node_id();
index bdd222e31c58f0ab921ae2f3f057d8264b68b560..be7accc18dacfc837d89bddcec937e0e9eb4b349 100644 (file)
@@ -87,21 +87,45 @@ pub struct ChannelHandshakeConfig {
        ///
        /// If this option is set, channels may be created that will not be readable by LDK versions
        /// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a
-       /// [`DecodeError:InvalidValue`].
+       /// [`DecodeError::InvalidValue`].
        ///
        /// Note that setting this to true does *not* prevent us from opening channels with
        /// counterparties that do not support the `scid_alias` option; we will simply fall back to a
        /// private channel without that option.
        ///
        /// Ignored if the channel is negotiated to be announced, see
-       /// [`ChannelConfig::announced_channel`] and
+       /// [`ChannelHandshakeConfig::announced_channel`] and
        /// [`ChannelHandshakeLimits::force_announced_channel_preference`] for more.
        ///
        /// Default value: false. This value is likely to change to true in the future.
        ///
        /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
-       /// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
+       /// [`DecodeError::InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
        pub negotiate_scid_privacy: bool,
+       /// Set to announce the channel publicly and notify all nodes that they can route via this
+       /// channel.
+       ///
+       /// This should only be set to true for nodes which expect to be online reliably.
+       ///
+       /// As the node which funds a channel picks this value this will only apply for new outbound
+       /// channels unless [`ChannelHandshakeLimits::force_announced_channel_preference`] is set.
+       ///
+       /// Default value: false.
+       pub announced_channel: bool,
+       /// When set, we commit to an upfront shutdown_pubkey at channel open. If our counterparty
+       /// supports it, they will then enforce the mutual-close output to us matches what we provided
+       /// at intialization, preventing us from closing to an alternate pubkey.
+       ///
+       /// This is set to true by default to provide a slight increase in security, though ultimately
+       /// any attacker who is able to take control of a channel can just as easily send the funds via
+       /// lightning payments, so we never require that our counterparties support this option.
+       ///
+       /// The upfront key committed is provided from [`KeysInterface::get_shutdown_scriptpubkey`].
+       ///
+       /// Default value: true.
+       ///
+       /// [`KeysInterface::get_shutdown_scriptpubkey`]: crate::chain::keysinterface::KeysInterface::get_shutdown_scriptpubkey
+       pub commit_upfront_shutdown_pubkey: bool,
 }
 
 impl Default for ChannelHandshakeConfig {
@@ -112,6 +136,8 @@ impl Default for ChannelHandshakeConfig {
                        our_htlc_minimum_msat: 1,
                        max_inbound_htlc_value_in_flight_percent_of_channel: 10,
                        negotiate_scid_privacy: false,
+                       announced_channel: false,
+                       commit_upfront_shutdown_pubkey: true,
                }
        }
 }
@@ -186,10 +212,10 @@ pub struct ChannelHandshakeLimits {
        /// Default value: true
        pub trust_own_funding_0conf: bool,
        /// Set to force an incoming channel to match our announced channel preference in
-       /// [`ChannelConfig::announced_channel`].
+       /// [`ChannelHandshakeConfig::announced_channel`].
        ///
        /// For a node which is not online reliably, this should be set to true and
-       /// [`ChannelConfig::announced_channel`] set to false, ensuring that no announced (aka public)
+       /// [`ChannelHandshakeConfig::announced_channel`] set to false, ensuring that no announced (aka public)
        /// channels will ever be opened.
        ///
        /// Default value: true.
@@ -223,7 +249,7 @@ impl Default for ChannelHandshakeLimits {
 
 /// Options which apply on a per-channel basis and may change at runtime or based on negotiation
 /// with our counterparty.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq)]
 pub struct ChannelConfig {
        /// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
        /// over the channel.
@@ -265,30 +291,6 @@ pub struct ChannelConfig {
        ///
        /// [`MIN_CLTV_EXPIRY_DELTA`]: crate::ln::channelmanager::MIN_CLTV_EXPIRY_DELTA
        pub cltv_expiry_delta: u16,
-       /// Set to announce the channel publicly and notify all nodes that they can route via this
-       /// channel.
-       ///
-       /// This should only be set to true for nodes which expect to be online reliably.
-       ///
-       /// As the node which funds a channel picks this value this will only apply for new outbound
-       /// channels unless [`ChannelHandshakeLimits::force_announced_channel_preference`] is set.
-       ///
-       /// This cannot be changed after the initial channel handshake.
-       ///
-       /// Default value: false.
-       pub announced_channel: bool,
-       /// When set, we commit to an upfront shutdown_pubkey at channel open. If our counterparty
-       /// supports it, they will then enforce the mutual-close output to us matches what we provided
-       /// at intialization, preventing us from closing to an alternate pubkey.
-       ///
-       /// This is set to true by default to provide a slight increase in security, though ultimately
-       /// any attacker who is able to take control of a channel can just as easily send the funds via
-       /// lightning payments, so we never require that our counterparties support this option.
-       ///
-       /// This cannot be changed after a channel has been initialized.
-       ///
-       /// Default value: true.
-       pub commit_upfront_shutdown_pubkey: bool,
        /// Limit our total exposure to in-flight HTLCs which are burned to fees as they are too
        /// small to claim on-chain.
        ///
@@ -337,8 +339,6 @@ impl Default for ChannelConfig {
                        forwarding_fee_proportional_millionths: 0,
                        forwarding_fee_base_msat: 1000,
                        cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
-                       announced_channel: false,
-                       commit_upfront_shutdown_pubkey: true,
                        max_dust_htlc_exposure_msat: 5_000_000,
                        force_close_avoidance_max_fee_satoshis: 1000,
                }
@@ -347,32 +347,105 @@ impl Default for ChannelConfig {
 
 impl_writeable_tlv_based!(ChannelConfig, {
        (0, forwarding_fee_proportional_millionths, required),
-       (1, max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
-       (2, cltv_expiry_delta, required),
-       (3, force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
-       (4, announced_channel, required),
-       (6, commit_upfront_shutdown_pubkey, required),
-       (8, forwarding_fee_base_msat, required),
+       (2, forwarding_fee_base_msat, required),
+       (4, cltv_expiry_delta, required),
+       (6, max_dust_htlc_exposure_msat, required),
+       // ChannelConfig serialized this field with a required type of 8 prior to the introduction of
+       // LegacyChannelConfig. To make sure that serialization is not compatible with this one, we use
+       // the next required type of 10, which if seen by the old serialization will always fail.
+       (10, force_close_avoidance_max_fee_satoshis, required),
 });
 
+/// Legacy version of [`ChannelConfig`] that stored the static
+/// [`ChannelHandshakeConfig::announced_channel`] and
+/// [`ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`] fields.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct LegacyChannelConfig {
+       pub(crate) options: ChannelConfig,
+       /// Deprecated but may still be read from. See [`ChannelHandshakeConfig::announced_channel`] to
+       /// set this when opening/accepting a channel.
+       pub(crate) announced_channel: bool,
+       /// Deprecated but may still be read from. See
+       /// [`ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`] to set this when
+       /// opening/accepting a channel.
+       pub(crate) commit_upfront_shutdown_pubkey: bool,
+}
+
+impl Default for LegacyChannelConfig {
+       fn default() -> Self {
+               Self {
+                       options: ChannelConfig::default(),
+                       announced_channel: false,
+                       commit_upfront_shutdown_pubkey: true,
+               }
+       }
+}
+
+impl ::util::ser::Writeable for LegacyChannelConfig {
+       fn write<W: ::util::ser::Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
+               write_tlv_fields!(writer, {
+                       (0, self.options.forwarding_fee_proportional_millionths, required),
+                       (1, self.options.max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
+                       (2, self.options.cltv_expiry_delta, required),
+                       (3, self.options.force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
+                       (4, self.announced_channel, required),
+                       (6, self.commit_upfront_shutdown_pubkey, required),
+                       (8, self.options.forwarding_fee_base_msat, required),
+               });
+               Ok(())
+       }
+}
+
+impl ::util::ser::Readable for LegacyChannelConfig {
+       fn read<R: ::io::Read>(reader: &mut R) -> Result<Self, ::ln::msgs::DecodeError> {
+               let mut forwarding_fee_proportional_millionths = 0;
+               let mut max_dust_htlc_exposure_msat = 5_000_000;
+               let mut cltv_expiry_delta = 0;
+               let mut force_close_avoidance_max_fee_satoshis = 1000;
+               let mut announced_channel = false;
+               let mut commit_upfront_shutdown_pubkey = false;
+               let mut forwarding_fee_base_msat = 0;
+               read_tlv_fields!(reader, {
+                       (0, forwarding_fee_proportional_millionths, required),
+                       (1, max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
+                       (2, cltv_expiry_delta, required),
+                       (3, force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
+                       (4, announced_channel, required),
+                       (6, commit_upfront_shutdown_pubkey, required),
+                       (8, forwarding_fee_base_msat, required),
+               });
+               Ok(Self {
+                       options: ChannelConfig {
+                               forwarding_fee_proportional_millionths,
+                               max_dust_htlc_exposure_msat,
+                               cltv_expiry_delta,
+                               force_close_avoidance_max_fee_satoshis,
+                               forwarding_fee_base_msat,
+                       },
+                       announced_channel,
+                       commit_upfront_shutdown_pubkey,
+               })
+       }
+}
+
 /// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
 ///
 /// Default::default() provides sane defaults for most configurations
 /// (but currently with 0 relay fees!)
 #[derive(Copy, Clone, Debug)]
 pub struct UserConfig {
-       /// Channel config that we propose to our counterparty.
-       pub own_channel_config: ChannelHandshakeConfig,
-       /// Limits applied to our counterparty's proposed channel config settings.
-       pub peer_channel_config_limits: ChannelHandshakeLimits,
+       /// Channel handshake config that we propose to our counterparty.
+       pub channel_handshake_config: ChannelHandshakeConfig,
+       /// Limits applied to our counterparty's proposed channel handshake config settings.
+       pub channel_handshake_limits: ChannelHandshakeLimits,
        /// Channel config which affects behavior during channel lifetime.
-       pub channel_options: ChannelConfig,
+       pub channel_config: ChannelConfig,
        /// If this is set to false, we will reject any HTLCs which were to be forwarded over private
        /// channels. This prevents us from taking on HTLC-forwarding risk when we intend to run as a
        /// node which is not online reliably.
        ///
        /// For nodes which are not online reliably, you should set all channels to *not* be announced
-       /// (using [`ChannelConfig::announced_channel`] and
+       /// (using [`ChannelHandshakeConfig::announced_channel`] and
        /// [`ChannelHandshakeLimits::force_announced_channel_preference`]) and set this to false to
        /// ensure you are not exposed to any forwarding risk.
        ///
@@ -406,9 +479,9 @@ pub struct UserConfig {
 impl Default for UserConfig {
        fn default() -> Self {
                UserConfig {
-                       own_channel_config: ChannelHandshakeConfig::default(),
-                       peer_channel_config_limits: ChannelHandshakeLimits::default(),
-                       channel_options: ChannelConfig::default(),
+                       channel_handshake_config: ChannelHandshakeConfig::default(),
+                       channel_handshake_limits: ChannelHandshakeLimits::default(),
+                       channel_config: ChannelConfig::default(),
                        accept_forwards_to_priv_channels: false,
                        accept_inbound_channels: true,
                        manually_accept_inbound_channels: false,
index a2794c329a26d827c214846d7cd571274e481b7e..14ab5ee3c4b83ebd3dff5e00d05daf5e597ea1e4 100644 (file)
@@ -337,10 +337,9 @@ pub enum Event {
                /// payment route.
                ///
                /// Should be applied to the [`NetworkGraph`] so that routing decisions can take into
-               /// account the update. [`P2PGossipSync`] is capable of doing this.
+               /// account the update.
                ///
                /// [`NetworkGraph`]: crate::routing::gossip::NetworkGraph
-               /// [`P2PGossipSync`]: crate::routing::gossip::P2PGossipSync
                network_update: Option<NetworkUpdate>,
                /// For both single-path and multi-path payments, this is set if all paths of the payment have
                /// failed. This will be set to false if (1) this is an MPP payment and (2) other parts of the
index 117eff491b343d4ae6cdfd0d0af7cd7a1df5ae91..522c1c92ac3460773436f0dd037eb24ee8018f03 100644 (file)
@@ -38,7 +38,7 @@ pub trait Persister<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L:
        fn persist_manager(&self, channel_manager: &ChannelManager<Signer, M, T, K, F, L>) -> Result<(), io::Error>;
 
        /// Persist the given [`NetworkGraph`] to disk, returning an error if persistence failed.
-       fn persist_graph(&self, network_graph: &NetworkGraph) -> Result<(), io::Error>;
+       fn persist_graph(&self, network_graph: &NetworkGraph<L>) -> Result<(), io::Error>;
 
        /// Persist the given [`WriteableScore`] to disk, returning an error if persistence failed.
        fn persist_scorer(&self, scorer: &S) -> Result<(), io::Error>;
@@ -58,7 +58,7 @@ impl<'a, A: KVStorePersister, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Der
        }
 
        /// Persist the given [`NetworkGraph`] to disk with the name "network_graph", returning an error if persistence failed.
-       fn persist_graph(&self, network_graph: &NetworkGraph) -> Result<(), io::Error> {
+       fn persist_graph(&self, network_graph: &NetworkGraph<L>) -> Result<(), io::Error> {
                self.persist("network_graph", network_graph)
        }