Merge pull request #1331 from TheBlueMatt/2022-02-no-copy-invoice-fields
authorJeffrey Czyz <jkczyz@gmail.com>
Fri, 11 Mar 2022 20:26:02 +0000 (14:26 -0600)
committerGitHub <noreply@github.com>
Fri, 11 Mar 2022 20:26:02 +0000 (14:26 -0600)
Use &mut self in invoice updaters, not take-self-return-Self

44 files changed:
.github/workflows/build.yml
.gitignore
CHANGELOG.md
CONTRIBUTING.md
Cargo.toml
fuzz/src/full_stack.rs
fuzz/src/router.rs
lightning-background-processor/Cargo.toml
lightning-background-processor/src/lib.rs
lightning-block-sync/Cargo.toml
lightning-block-sync/src/convert.rs
lightning-block-sync/src/init.rs
lightning-block-sync/src/lib.rs
lightning-invoice/Cargo.toml
lightning-invoice/src/lib.rs
lightning-invoice/src/utils.rs
lightning-net-tokio/Cargo.toml
lightning-net-tokio/src/lib.rs
lightning-persister/Cargo.toml
lightning-persister/src/lib.rs
lightning/Cargo.toml
lightning/src/chain/channelmonitor.rs
lightning/src/lib.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/mod.rs
lightning/src/ln/monitor_tests.rs
lightning/src/ln/msgs.rs
lightning/src/ln/onion_route_tests.rs
lightning/src/ln/payment_tests.rs
lightning/src/ln/peer_handler.rs
lightning/src/ln/priv_short_conf_tests.rs [new file with mode: 0644]
lightning/src/ln/reorg_tests.rs
lightning/src/ln/shutdown_tests.rs
lightning/src/routing/network_graph.rs
lightning/src/routing/router.rs
lightning/src/routing/scoring.rs
lightning/src/util/events.rs
lightning/src/util/scid_utils.rs
lightning/src/util/test_utils.rs
no-std-check/Cargo.toml [new file with mode: 0644]
no-std-check/src/lib.rs [new file with mode: 0644]

index c982060a8c5cab14c7d077ff123314e4607d91ab..d25e9a43c19ab4682e4ab75105c372d3ab35b9df 100644 (file)
@@ -10,10 +10,8 @@ jobs:
         platform: [ ubuntu-latest ]
         toolchain: [ stable,
                      beta,
-                     # 1.36.0 is MSRV for Rust-Lightning, lightning-invoice, and lightning-persister
-                     1.36.0,
-                     # 1.41.0 is Debian stable
-                     1.41.0,
+                     # 1.41.1 is MSRV for Rust-Lightning, lightning-invoice, and lightning-persister
+                     1.41.1,
                      # 1.45.2 is MSRV for lightning-net-tokio, lightning-block-sync, and coverage generation
                      1.45.2,
                      # 1.47.0 will be the MSRV for no-std builds using hashbrown once core2 is updated
@@ -41,11 +39,9 @@ jobs:
           - toolchain: beta
             build-net-tokio: true
             build-no-std: true
-          - toolchain: 1.36.0
+          - toolchain: 1.41.1
             build-no-std: false
             test-log-variants: true
-          - toolchain: 1.41.0
-            build-no-std: false
           - toolchain: 1.45.2
             build-net-old-tokio: true
             build-net-tokio: true
@@ -56,7 +52,7 @@ jobs:
     runs-on: ${{ matrix.platform }}
     steps:
       - name: Checkout source code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Install Rust ${{ matrix.toolchain }} toolchain
         uses: actions-rs/toolchain@v1
         with:
@@ -126,6 +122,10 @@ jobs:
           cargo test --verbose --color always --no-default-features --features no-std
           # check if there is a conflict between no-std and the default std feature
           cargo test --verbose --color always --features no-std
+          # check no-std compatibility across dependencies
+          cd ..
+          cd no-std-check
+          cargo check --verbose --color always
           cd ..
       - name: Test on no-std builds Rust ${{ matrix.toolchain }} and full code-linking for coverage generation
         if: "matrix.build-no-std && matrix.coverage"
@@ -202,7 +202,7 @@ jobs:
       TOOLCHAIN: nightly
     steps:
       - name: Checkout source code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
         uses: actions-rs/toolchain@v1
         with:
@@ -241,7 +241,7 @@ jobs:
       TOOLCHAIN: 1.52.1
     steps:
       - name: Checkout source code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           fetch-depth: 0
       - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
@@ -266,11 +266,11 @@ jobs:
       TOOLCHAIN: stable
     steps:
       - name: Checkout source code
-        uses: actions/checkout@v2
-      - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
+        uses: actions/checkout@v3
+      - name: Install Rust 1.58 toolchain
         uses: actions-rs/toolchain@v1
         with:
-          toolchain: ${{ env.TOOLCHAIN }}
+          toolchain: 1.58
           override: true
           profile: minimal
       - name: Install dependencies for honggfuzz
@@ -290,7 +290,7 @@ jobs:
       TOOLCHAIN: 1.47.0
     steps:
       - name: Checkout source code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Install Rust ${{ env.TOOLCHAIN }} toolchain
         uses: actions-rs/toolchain@v1
         with:
index a108267c2fd1d725aa0e6d8bb1b8f0371b7eea51..10e905af5145fbae9e0c61afa82f3beeeeb9d0c9 100644 (file)
@@ -8,3 +8,4 @@ lightning-c-bindings/a.out
 Cargo.lock
 .idea
 lightning/target
+no-std-check/target
index df1204e9bc727305d1527822adb16f5a66bdb843..c353a1bb99365ab82ae2e5767a13c8aa2654b637 100644 (file)
@@ -1,3 +1,113 @@
+# 0.0.105 - 2022-02-28
+
+## API Updates
+ * `Phantom node` payments are now supported, allowing receipt of a payment on
+   any one of multiple nodes without any coordination across the nodes being
+   required. See the new `PhantomKeysManager`'s docs for more, as well as
+   requirements on `KeysInterface::get_inbound_payment_key_material` and
+   `lightning_invoice::utils::create_phantom_invoice` (#1199).
+ * In order to support phantom node payments, several `KeysInterface` methods
+   now accept a `Recipient` parameter to select between the local `node_id` and
+   a phantom-specific one.
+ * `ProbabilisticScorer`, a `Score` based on learning the current balances of
+   channels in the network, was added. It attempts to better capture payment
+   success probability than the existing `Scorer`, though may underperform on
+   nodes with low payment volume. We welcome feedback on performance (#1227).
+ * `Score::channel_penalty_msat` now always takes the channel value, instead of
+   an `Option` (#1227).
+ * `UserConfig::manually_accept_inbound_channels` was added which, when set,
+   generates a new `Event::OpenChannelRequest`, which allows manual acceptance
+   or rejection of incoming channels on a per-channel basis (#1281).
+ * `Payee` has been renamed to `PaymentParameters` (#1271).
+ * `PaymentParameters` now has a `max_total_cltv_expiry_delta` field. This
+   defaults to 1008 and limits the maximum amount of time an HTLC can be pending
+   before it will either fail or be claimed (#1234).
+ * The `lightning-invoice` crate now supports no-std environments. This required
+   numerous API changes around timestamp handling and std+no-std versions of
+   several methods that previously assumed knowledge of the time (#1223, #1230).
+ * `lightning-invoice` now supports parsing invoices with expiry times of more
+   than one year. This required changing the semantics of `ExpiryTime` (#1273).
+ * The `CounterpartyCommitmentSecrets` is now public, allowing external uses of
+   the `BOLT 3` secret storage scheme (#1299).
+ * Several `Sign` methods now receive HTLC preimages as proof of state
+   transition, see new documentation for more (#1251).
+ * `KeysInterface::sign_invoice` now provides the HRP and other invoice data
+   separately to make it simpler for external signers to parse (#1272).
+ * `Sign::sign_channel_announcement` now returns both the node's signature and
+   the per-channel signature. `InMemorySigner` now requires the node's secret
+   key in order to implement this (#1179).
+ * `ChannelManager` deserialization will now fail if the `KeysInterface` used
+   has a different `node_id` than the `ChannelManager` expects (#1250).
+ * A new `ErrorAction` variant was added to send `warning` messages (#1013).
+ * Several references to `chain::Listen` objects in `lightning-block-sync` no
+   longer require a mutable reference (#1304).
+
+## Bug Fixes
+ * Fixed a regression introduced in 0.0.104 where `ChannelManager`'s internal
+   locks could have an order violation leading to a deadlock (#1238).
+ * Fixed cases where slow code (including user I/O) could cause us to
+   disconnect peers with ping timeouts in `BackgroundProcessor` (#1269).
+ * Now persist the `ChannelManager` prior to `BackgroundProcessor` stopping,
+   preventing race conditions where channels are closed on startup even with a
+   clean shutdown. This requires that users stop network processing and
+   disconnect peers prior to `BackgroundProcessor` shutdown (#1253).
+ * Fields in `ChannelHandshakeLimits` provided via the `override_config` to
+   `create_channel` are now applied instead of the default config (#1292).
+ * Fixed the generation of documentation on docs.rs to include API surfaces
+   which are hidden behind feature flags (#1303).
+ * Added the `channel_type` field to `accept_channel` messages we send, which
+   may avoid some future compatibility issues with other nodes (#1314).
+ * Fixed a bug where, if a previous LDK run using `lightning-persister` crashed
+   while persisting updated data, we may have failed to initialize (#1332).
+ * Fixed a rare bug where having both pending inbound and outbound HTLCs on a
+   just-opened inbound channel could cause `ChannelDetails::balance_msat` to
+   underflow and be reported as large, or cause panics in debug mode (#1268).
+ * Moved more instances of verbose gossip logging from the `Trace` level to the
+   `Gossip` level (#1220).
+ * Delayed `announcement_signatures` until the channel has six confirmations,
+   slightly improving propagation of channel announcements (#1179).
+ * Several fixes in script and transaction weight calculations when anchor
+   outputs are enabled (#1229).
+
+## Serialization Compatibility
+ * Using `ChannelManager` data written by versions prior to 0.0.105 will result
+   in preimages for HTLCs that were pending at startup to be missing in calls
+   to `KeysInterface` methods (#1251).
+ * Any phantom invoice payments received on a node that is not upgraded to
+   0.0.105 will fail with an "unknown channel" error. Further, downgrading to
+   0.0.104 or before and then upgrading again will invalidate existing phantom
+   SCIDs which may be included in invoices (#1199).
+
+## Security
+0.0.105 fixes two denial-of-service vulnerabilities which may be reachable from
+untrusted input in certain application designs.
+
+ * Route calculation spuriously panics when a routing decision is made for a
+   path where the second-to-last hop is a private channel, included due to a
+   multi-hop route hint in an invoice.
+ * `ChannelMonitor::get_claimable_balances` spuriously panics in some scenarios
+   when the LDK application's local commitment transaction is confirmed while
+   HTLCs are still pending resolution.
+
+In total, this release features 109 files changed, 7270 insertions, 2131
+deletions in 108 commits from 15 authors, in alphabetical order:
+ * Conor Okus
+ * Devrandom
+ * Elias Rohrer
+ * Jeffrey Czyz
+ * Jurvis Tan
+ * Ken Sedgwick
+ * Matt Corallo
+ * Naveen
+ * Tibo-lg
+ * Valentine Wallace
+ * Viktor Tigerström
+ * dependabot[bot]
+ * hackerrdave
+ * naveen
+ * vss96
+
+
 # 0.0.104 - 2021-12-17
 
 ## API Updates
index 2c1fb0d8a7376db6a0b7624fa8d0c0583423c64c..ab6ba2a410fb245c13fc1c7a6157a36448e9d07f 100644 (file)
@@ -75,7 +75,7 @@ be covered by functional tests.
 When refactoring, structure your PR to make it easy to review and don't
 hestitate to split it into multiple small, focused PRs.
 
-The Minimal Supported Rust Version is 1.36.0 (enforced by our GitHub Actions).
+The Minimum Supported Rust Version is 1.41.1 (enforced by our GitHub Actions).
 
 Commits should cover both the issue fixed and the solution's rationale.
 These [guidelines](https://chris.beams.io/posts/git-commit/) should be kept in mind.
index df32ac5d9cf047ea597a75a0736de6f0a3537ce5..6e03fc1ac4cfc4bab1feed65368651bc5135cb9e 100644 (file)
@@ -9,6 +9,10 @@ members = [
     "lightning-background-processor",
 ]
 
+exclude = [
+    "no-std-check",
+]
+
 # Our tests do actual crypo and lots of work, the tradeoff for -O1 is well worth it.
 # Ideally we would only do this in profile.test, but profile.test only applies to
 # the test binary, not dependencies, which means most of the critical code still
index 19ec541b942592a00ba93fe1687eba2e95559952..a4e1a08648f3aac50413659f0a2bcea7985ca006 100644 (file)
@@ -390,6 +390,9 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
                best_block: BestBlock::from_genesis(network),
        };
        let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, params));
+       // Adding new calls to `KeysInterface::get_secure_random_bytes` during startup can change all the
+       // keys subsequently generated in this test. Rather than regenerating all the messages manually,
+       // 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()));
@@ -456,7 +459,8 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
                                        final_value_msat,
                                        final_cltv_expiry_delta: 42,
                                };
-                               let route = match find_route(&our_id, &params, &network_graph, None, Arc::clone(&logger), &scorer) {
+                               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) {
                                        Ok(route) => route,
                                        Err(_) => return,
                                };
@@ -479,7 +483,8 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
                                        final_value_msat,
                                        final_cltv_expiry_delta: 42,
                                };
-                               let mut route = match find_route(&our_id, &params, &network_graph, None, Arc::clone(&logger), &scorer) {
+                               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) {
                                        Ok(route) => route,
                                        Err(_) => return,
                                };
index 095059c5183676232c48b36093a244a9fe69ba3b..5494b26c7a300e5cb99d1056cd9054a9d626a8ac 100644 (file)
@@ -216,6 +216,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                                },
                                                                funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
                                                                short_channel_id: Some(scid),
+                                                               inbound_scid_alias: None,
                                                                channel_value_satoshis: slice_to_be64(get_slice!(8)),
                                                                user_channel_id: 0, inbound_capacity_msat: 0,
                                                                unspendable_punishment_reserve: None,
@@ -250,6 +251,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                        }
                                }
                                let scorer = FixedPenaltyScorer::with_penalty(0);
+                               let random_seed_bytes: [u8; 32] = [get_slice!(1)[0]; 32];
                                for target in node_pks.iter() {
                                        let route_params = RouteParameters {
                                                payment_params: PaymentParameters::from_node_id(*target).with_route_hints(last_hops.clone()),
@@ -258,7 +260,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                        };
                                        let _ = find_route(&our_pubkey, &route_params, &net_graph,
                                                first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),
-                                               Arc::clone(&logger), &scorer);
+                                               Arc::clone(&logger), &scorer, &random_seed_bytes);
                                }
                        },
                }
index 1837cb17e664839de009f2c01ba2a2ac3055d6dd..edb1551edee75428c9a3c4c35a3a3377d5cccdce 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-background-processor"
-version = "0.0.104"
+version = "0.0.105"
 authors = ["Valentine Wallace <vwallace@protonmail.com>"]
 license = "MIT OR Apache-2.0"
 repository = "http://github.com/lightningdevkit/rust-lightning"
@@ -9,11 +9,15 @@ Utilities to perform required background tasks for Rust Lightning.
 """
 edition = "2018"
 
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
+
 [dependencies]
 bitcoin = "0.27"
-lightning = { version = "0.0.104", path = "../lightning", features = ["std"] }
-lightning-persister = { version = "0.0.104", path = "../lightning-persister" }
+lightning = { version = "0.0.105", path = "../lightning", features = ["std"] }
+lightning-persister = { version = "0.0.105", path = "../lightning-persister" }
 
 [dev-dependencies]
-lightning = { version = "0.0.104", path = "../lightning", features = ["_test_utils"] }
-lightning-invoice = { version = "0.12.0", path = "../lightning-invoice" }
+lightning = { version = "0.0.105", path = "../lightning", features = ["_test_utils"] }
+lightning-invoice = { version = "0.13.0", path = "../lightning-invoice" }
index 8ed0014a72dbc94fda3dd8e2d311120ee23e234f..084ea62efb6faf51f0ff67b0b5fb01fc61f965ef 100644 (file)
@@ -6,6 +6,8 @@
 #![deny(missing_docs)]
 #![deny(unsafe_code)]
 
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+
 #[macro_use] extern crate lightning;
 
 use lightning::chain;
@@ -667,13 +669,15 @@ mod tests {
 
        #[test]
        fn test_invoice_payer() {
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let nodes = create_nodes(2, "test_invoice_payer".to_string());
 
                // Initiate the background processors to watch each node.
                let data_dir = nodes[0].persister.get_data_dir();
                let persister = move |node: &ChannelManager<InMemorySigner, Arc<ChainMonitor>, Arc<test_utils::TestBroadcaster>, Arc<KeysManager>, Arc<test_utils::TestFeeEstimator>, Arc<test_utils::TestLogger>>| FilesystemPersister::persist_manager(data_dir.clone(), node);
-               let router = DefaultRouter::new(Arc::clone(&nodes[0].network_graph), Arc::clone(&nodes[0].logger));
                let scorer = Arc::new(Mutex::new(test_utils::TestScorer::with_penalty(0)));
+               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, scorer, Arc::clone(&nodes[0].logger), |_: &_| {}, RetryAttempts(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].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone());
index 0a395e8b99da0f557f14a0379494faa1d36242b3..cbc81c89d93e4118ad3809411942d137f3e00d11 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-block-sync"
-version = "0.0.104"
+version = "0.0.105"
 authors = ["Jeffrey Czyz", "Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "http://github.com/lightningdevkit/rust-lightning"
@@ -9,13 +9,17 @@ Utilities to fetch the chain data from a block source and feed them into Rust Li
 """
 edition = "2018"
 
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
+
 [features]
 rest-client = [ "serde", "serde_json", "chunked_transfer" ]
 rpc-client = [ "serde", "serde_json", "chunked_transfer" ]
 
 [dependencies]
 bitcoin = "0.27"
-lightning = { version = "0.0.104", path = "../lightning" }
+lightning = { version = "0.0.105", path = "../lightning" }
 tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true }
 serde = { version = "1.0", features = ["derive"], optional = true }
 serde_json = { version = "1.0", optional = true }
index 358076f4c25a883f5e571b421f9d3ff1ebe20f27..8023c83751920647caecb9ecb67288cc0cfc6506 100644 (file)
@@ -182,7 +182,7 @@ impl TryInto<Txid> for JsonResponse {
 }
 
 /// Converts a JSON value into a transaction. WATCH OUT! this cannot be used for zero-input transactions
-/// (e.g. createrawtransaction). See https://github.com/rust-bitcoin/rust-bitcoincore-rpc/issues/197
+/// (e.g. createrawtransaction). See <https://github.com/rust-bitcoin/rust-bitcoincore-rpc/issues/197>
 impl TryInto<Transaction> for JsonResponse {
        type Error = std::io::Error;
        fn try_into(self) -> std::io::Result<Transaction> {
index c0e37ac0b9dadf809365b012c9d195f6dcda57b1..d971cadcf8aea0d47a400a7a87cb4d20aaa213eb 100644 (file)
@@ -121,11 +121,11 @@ BlockSourceResult<ValidatedBlockHeader> {
 /// [`SpvClient`]: crate::SpvClient
 /// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
 /// [`ChannelMonitor`]: lightning::chain::channelmonitor::ChannelMonitor
-pub async fn synchronize_listeners<B: BlockSource, C: Cache>(
+pub async fn synchronize_listeners<'a, B: BlockSource, C: Cache, L: chain::Listen + ?Sized>(
        block_source: &mut B,
        network: Network,
        header_cache: &mut C,
-       mut chain_listeners: Vec<(BlockHash, &dyn chain::Listen)>,
+       mut chain_listeners: Vec<(BlockHash, &'a L)>,
 ) -> BlockSourceResult<ValidatedBlockHeader> {
        let best_header = validate_best_block_header(block_source).await?;
 
@@ -198,9 +198,9 @@ impl<'a, C: Cache> Cache for ReadOnlyCache<'a, C> {
 }
 
 /// Wrapper for supporting dynamically sized chain listeners.
-struct DynamicChainListener<'a>(&'a dyn chain::Listen);
+struct DynamicChainListener<'a, L: chain::Listen + ?Sized>(&'a L);
 
-impl<'a> chain::Listen for DynamicChainListener<'a> {
+impl<'a, L: chain::Listen + ?Sized> chain::Listen for DynamicChainListener<'a, L> {
        fn block_connected(&self, _block: &Block, _height: u32) {
                unreachable!()
        }
@@ -211,9 +211,9 @@ impl<'a> chain::Listen for DynamicChainListener<'a> {
 }
 
 /// A set of dynamically sized chain listeners, each paired with a starting block height.
-struct ChainListenerSet<'a>(Vec<(u32, &'a dyn chain::Listen)>);
+struct ChainListenerSet<'a, L: chain::Listen + ?Sized>(Vec<(u32, &'a L)>);
 
-impl<'a> chain::Listen for ChainListenerSet<'a> {
+impl<'a, L: chain::Listen + ?Sized> chain::Listen for ChainListenerSet<'a, L> {
        fn block_connected(&self, block: &Block, height: u32) {
                for (starting_height, chain_listener) in self.0.iter() {
                        if height > *starting_height {
index ac031132a71946f8706954d49138ff3f7b1e574e..8854aa3e8e4bf8186b6cc119451e62ddc6710fae 100644 (file)
@@ -17,6 +17,8 @@
 #![deny(missing_docs)]
 #![deny(unsafe_code)]
 
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+
 #[cfg(any(feature = "rest-client", feature = "rpc-client"))]
 pub mod http;
 
index e1f33f0fa2662ce9ecb772595dfa537e3d4b9993..e41eb1cd24b85748f82afd691f63a9d44f8e71fe 100644 (file)
@@ -1,13 +1,17 @@
 [package]
 name = "lightning-invoice"
 description = "Data structures to parse and serialize BOLT11 lightning invoices"
-version = "0.12.0"
+version = "0.13.0"
 authors = ["Sebastian Geisler <sgeisler@wh2.tu-dresden.de>"]
 documentation = "https://docs.rs/lightning-invoice/"
 license = "MIT OR Apache-2.0"
 keywords = [ "lightning", "bitcoin", "invoice", "BOLT11" ]
 readme = "README.md"
 
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
+
 [features]
 default = ["std"]
 no-std = ["hashbrown", "lightning/no-std", "core2/alloc"]
@@ -15,7 +19,7 @@ std = ["bitcoin_hashes/std", "num-traits/std", "lightning/std", "bech32/std"]
 
 [dependencies]
 bech32 = { version = "0.8", default-features = false }
-lightning = { version = "0.0.104", path = "../lightning", default-features = false }
+lightning = { version = "0.0.105", path = "../lightning", default-features = false }
 secp256k1 = { version = "0.20", default-features = false, features = ["recovery", "alloc"] }
 num-traits = { version = "0.2.8", default-features = false }
 bitcoin_hashes = { version = "0.10", default-features = false }
@@ -23,5 +27,5 @@ hashbrown = { version = "0.11", optional = true }
 core2 = { version = "0.3.0", default-features = false, optional = true }
 
 [dev-dependencies]
-lightning = { version = "0.0.104", path = "../lightning", default-features = false, features = ["_test_utils"] }
+lightning = { version = "0.0.105", path = "../lightning", default-features = false, features = ["_test_utils"] }
 hex = "0.4"
index dddc0d734f405330a0c84ab6b35fe5892596c727..1dd7123a486d1077f1295b7655b1fac497cfb57f 100644 (file)
@@ -5,6 +5,8 @@
 #![deny(unused_mut)]
 #![deny(broken_intra_doc_links)]
 
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+
 #![cfg_attr(feature = "strict", deny(warnings))]
 #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
 
index fc82541a564e8cbd82c64f75fd37d4fa87ecd8af..630411f03af6243115cc69357eeecc264e9bb018 100644 (file)
@@ -4,13 +4,15 @@ use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, Sign
 use payment::{Payer, Router};
 
 use bech32::ToBase32;
-use bitcoin_hashes::Hash;
+use bitcoin_hashes::{Hash, sha256};
 use crate::prelude::*;
 use lightning::chain;
 use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
 use lightning::chain::keysinterface::{Recipient, KeysInterface, Sign};
 use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
-use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY, MIN_CLTV_EXPIRY_DELTA};
+use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY};
+#[cfg(feature = "std")]
+use lightning::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA};
 use lightning::ln::msgs::LightningError;
 use lightning::routing::scoring::Score;
 use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
@@ -20,6 +22,7 @@ use secp256k1::key::PublicKey;
 use core::convert::TryInto;
 use core::ops::Deref;
 use core::time::Duration;
+use sync::Mutex;
 
 #[cfg(feature = "std")]
 /// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
@@ -65,7 +68,7 @@ pub fn create_phantom_invoice<Signer: Sign, K: Deref>(
 
        for hint in phantom_route_hints {
                for channel in &hint.channels {
-                       let short_channel_id = match channel.short_channel_id {
+                       let short_channel_id = match channel.get_inbound_payment_scid() {
                                Some(id) => id,
                                None => continue,
                        };
@@ -162,7 +165,7 @@ where
        let our_channels = channelmanager.list_usable_channels();
        let mut route_hints = vec![];
        for channel in our_channels {
-               let short_channel_id = match channel.short_channel_id {
+               let short_channel_id = match channel.get_inbound_payment_scid() {
                        Some(id) => id,
                        None => continue,
                };
@@ -222,12 +225,15 @@ where
 pub struct DefaultRouter<G: Deref<Target = NetworkGraph>, 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 {
-       /// Creates a new router using the given [`NetworkGraph`] and  [`Logger`].
-       pub fn new(network_graph: G, logger: L) -> Self {
-               Self { network_graph, 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 {
+               let random_seed_bytes = Mutex::new(random_seed_bytes);
+               Self { network_graph, logger, random_seed_bytes }
        }
 }
 
@@ -237,7 +243,12 @@ where L::Target: Logger {
                &self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
                first_hops: Option<&[&ChannelDetails]>, scorer: &S
        ) -> Result<Route, LightningError> {
-               find_route(payer, params, &*self.network_graph, first_hops, &*self.logger, scorer)
+               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)
        }
 }
 
@@ -297,6 +308,7 @@ mod test {
        use lightning::util::enforcing_trait_impls::EnforcingSigner;
        use lightning::util::events::{MessageSendEvent, MessageSendEventsProvider, Event};
        use lightning::util::test_utils;
+       use lightning::chain::keysinterface::KeysInterface;
        use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
 
        #[test]
@@ -313,6 +325,13 @@ mod test {
                assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
                assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
 
+               // Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
+               // available.
+               assert_eq!(invoice.route_hints().len(), 1);
+               assert_eq!(invoice.route_hints()[0].0.len(), 1);
+               assert_eq!(invoice.route_hints()[0].0[0].short_channel_id,
+                       nodes[1].node.list_usable_channels()[0].inbound_scid_alias.unwrap());
+
                let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
                        .with_features(invoice.features().unwrap().clone())
                        .with_route_hints(invoice.route_hints());
@@ -325,9 +344,10 @@ mod test {
                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,
-                       Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer,
+                       Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer, &random_seed_bytes
                ).unwrap();
 
                let payment_event = {
@@ -413,9 +433,10 @@ mod test {
                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,
-                       Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer,
+                       Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer, &random_seed_bytes
                ).unwrap();
                let (payment_event, fwd_idx) = {
                        let mut payment_hash = PaymentHash([0; 32]);
index 370e3cc4261d0eaa3fc11ccc34a4d25e4d683e01..3f3703c6cb12b92b01c5207c30bcc72276192e76 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-net-tokio"
-version = "0.0.104"
+version = "0.0.105"
 authors = ["Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
@@ -10,9 +10,13 @@ For Rust-Lightning clients which wish to make direct connections to Lightning P2
 """
 edition = "2018"
 
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
+
 [dependencies]
 bitcoin = "0.27"
-lightning = { version = "0.0.104", path = "../lightning" }
+lightning = { version = "0.0.105", path = "../lightning" }
 tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "sync", "net", "time" ] }
 
 [dev-dependencies]
index 62c036b9796c96f2f812e8eb162835ca9ffd57ba..2582cc597f20d361906271811e8d523f5977516e 100644 (file)
@@ -69,6 +69,8 @@
 #![deny(broken_intra_doc_links)]
 #![deny(missing_docs)]
 
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+
 use bitcoin::secp256k1::key::PublicKey;
 
 use tokio::net::TcpStream;
index 79ffeeeb281ad1e28ef190212c5185b56225f4a3..0e786eb48ce04c719e1de413c0e2f95b6cdacc0c 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning-persister"
-version = "0.0.104"
+version = "0.0.105"
 authors = ["Valentine Wallace", "Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
@@ -8,16 +8,20 @@ description = """
 Utilities to manage Rust-Lightning channel data persistence and retrieval.
 """
 
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
+
 [features]
 _bench_unstable = ["lightning/_bench_unstable"]
 
 [dependencies]
 bitcoin = "0.27"
-lightning = { version = "0.0.104", path = "../lightning" }
+lightning = { version = "0.0.105", path = "../lightning" }
 libc = "0.2"
 
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["winbase"] }
 
 [dev-dependencies]
-lightning = { version = "0.0.104", path = "../lightning", features = ["_test_utils"] }
+lightning = { version = "0.0.105", path = "../lightning", features = ["_test_utils"] }
index 558f4b8fe3cee9d56b75b2230f203ccca6608e9c..ef914700a16302c0e5dacad1414d3e0e8c1eb03c 100644 (file)
@@ -3,6 +3,8 @@
 #![deny(broken_intra_doc_links)]
 #![deny(missing_docs)]
 
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+
 #![cfg_attr(all(test, feature = "_bench_unstable"), feature(test))]
 #[cfg(all(test, feature = "_bench_unstable"))] extern crate test;
 
@@ -122,6 +124,12 @@ impl FilesystemPersister {
                                        "Invalid ChannelMonitor file name",
                                ));
                        }
+                       if filename.unwrap().ends_with(".tmp") {
+                               // If we were in the middle of committing an new update and crashed, it should be
+                               // safe to ignore the update - we should never have returned to the caller and
+                               // irrevocably committed to the new state in any way.
+                               continue;
+                       }
 
                        let txid = Txid::from_hex(filename.unwrap().split_at(64).0);
                        if txid.is_err() {
index 5f6f2ef655da402c77c132dd1d8061c9658ece9f..f38bb80511189ccaf92cce9bbb4a734949ff0e3b 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "lightning"
-version = "0.0.104"
+version = "0.0.105"
 authors = ["Matt Corallo"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/lightningdevkit/rust-lightning/"
@@ -10,6 +10,10 @@ Does most of the hard work, without implying a specific runtime, requiring clien
 Still missing tons of error-handling. See GitHub issues for suggested projects if you want to contribute. Don't have to bother telling you not to use this for anything serious, because you'd have to build a client around it to even try.
 """
 
+[package.metadata.docs.rs]
+features = ["std"]
+rustdoc-args = ["--cfg", "docsrs"]
+
 [features]
 # Internal test utilities exposed to other repo crates
 _test_utils = ["hex", "regex", "bitcoin/bitcoinconsensus"]
@@ -37,14 +41,14 @@ secp256k1 = { version = "0.20.2", default-features = false, features = ["alloc"]
 
 hashbrown = { version = "0.11", optional = true }
 hex = { version = "0.4", optional = true }
-regex = { version = "0.1.80", optional = true }
+regex = { version = "0.2.11", optional = true }
 backtrace = { version = "0.3", optional = true }
 
 core2 = { version = "0.3.0", optional = true, default-features = false }
 
 [dev-dependencies]
 hex = "0.4"
-regex = "0.1.80"
+regex = "0.2.11"
 # TODO remove this once rust-bitcoin PR #637 is released
 secp256k1 = { version = "0.20.2", default-features = false, features = ["alloc"] }
 
index 96caaad27636acdfe5ebc18044e9a74ff69ce080..fb2cbaddf533a9aa56cbc8586ba7f68f997345f7 100644 (file)
@@ -473,6 +473,19 @@ pub(crate) enum ChannelMonitorUpdateStep {
        },
 }
 
+impl ChannelMonitorUpdateStep {
+       fn variant_name(&self) -> &'static str {
+               match self {
+                       ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { .. } => "LatestHolderCommitmentTXInfo",
+                       ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. } => "LatestCounterpartyCommitmentTXInfo",
+                       ChannelMonitorUpdateStep::PaymentPreimage { .. } => "PaymentPreimage",
+                       ChannelMonitorUpdateStep::CommitmentSecret { .. } => "CommitmentSecret",
+                       ChannelMonitorUpdateStep::ChannelForceClosed { .. } => "ChannelForceClosed",
+                       ChannelMonitorUpdateStep::ShutdownScript { .. } => "ShutdownScript",
+               }
+       }
+}
+
 impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
        (0, LatestHolderCommitmentTXInfo) => {
                (0, commitment_tx, required),
@@ -1379,8 +1392,23 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
                        ($holder_commitment: expr, $htlc_iter: expr) => {
                                for htlc in $htlc_iter {
                                        if let Some(htlc_input_idx) = htlc.transaction_output_index {
-                                               if us.htlcs_resolved_on_chain.iter().any(|v| v.input_idx == htlc_input_idx) {
-                                                       assert!(us.funding_spend_confirmed.is_some());
+                                               if let Some(conf_thresh) = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
+                                                       if let OnchainEvent::MaturingOutput { descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) } = &event.event {
+                                                               if descriptor.outpoint.index as u32 == htlc_input_idx { Some(event.confirmation_threshold()) } else { None }
+                                                       } else { None }
+                                               }) {
+                                                       debug_assert!($holder_commitment);
+                                                       res.push(Balance::ClaimableAwaitingConfirmations {
+                                                               claimable_amount_satoshis: htlc.amount_msat / 1000,
+                                                               confirmation_height: conf_thresh,
+                                                       });
+                                               } else if us.htlcs_resolved_on_chain.iter().any(|v| v.input_idx == htlc_input_idx) {
+                                                       // Funding transaction spends should be fully confirmed by the time any
+                                                       // HTLC transactions are resolved, unless we're talking about a holder
+                                                       // commitment tx, whose resolution is delayed until the CSV timeout is
+                                                       // reached, even though HTLCs may be resolved after only
+                                                       // ANTI_REORG_DELAY confirmations.
+                                                       debug_assert!($holder_commitment || us.funding_spend_confirmed.is_some());
                                                } else if htlc.offered == $holder_commitment {
                                                        // If the payment was outbound, check if there's an HTLCUpdate
                                                        // indicating we have spent this HTLC with a timeout, claiming it back
@@ -1871,16 +1899,21 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                    F::Target: FeeEstimator,
                    L::Target: Logger,
        {
+               log_info!(logger, "Applying update to monitor {}, bringing update_id from {} to {} with {} changes.",
+                       log_funding_info!(self), self.latest_update_id, updates.update_id, updates.updates.len());
                // ChannelMonitor updates may be applied after force close if we receive a
                // preimage for a broadcasted commitment transaction HTLC output that we'd
                // like to claim on-chain. If this is the case, we no longer have guaranteed
                // access to the monitor's update ID, so we use a sentinel value instead.
                if updates.update_id == CLOSED_CHANNEL_UPDATE_ID {
+                       assert_eq!(updates.updates.len(), 1);
                        match updates.updates[0] {
                                ChannelMonitorUpdateStep::PaymentPreimage { .. } => {},
-                               _ => panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage"),
+                               _ => {
+                                       log_error!(logger, "Attempted to apply post-force-close ChannelMonitorUpdate of type {}", updates.updates[0].variant_name());
+                                       panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage");
+                               },
                        }
-                       assert_eq!(updates.updates.len(), 1);
                } else if self.latest_update_id + 1 != updates.update_id {
                        panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
                }
index 2798f78adf23aa0a52cde63fa86fb30270600b34..6d4cc50a920cad4cde49b91d0329e227c6ad6379 100644 (file)
@@ -28,6 +28,8 @@
 #![allow(bare_trait_objects)]
 #![allow(ellipsis_inclusive_range_patterns)]
 
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+
 #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
 
 #![cfg_attr(all(any(test, feature = "_test_utils"), feature = "_bench_unstable"), feature(test))]
index dd9fcbea9a8fa2bf05c21c9cf34c04b5e8698660..71e0ea121a929f2533c3af47714a50264e83b962 100644 (file)
@@ -695,6 +695,19 @@ pub(super) struct Channel<Signer: Sign> {
 
        /// This channel's type, as negotiated during channel open
        channel_type: ChannelTypeFeatures,
+
+       // Our counterparty can offer us SCID aliases which they will map to this channel when routing
+       // outbound payments. These can be used in invoice route hints to avoid explicitly revealing
+       // the channel's funding UTXO.
+       // We only bother storing the most recent SCID alias at any time, though our counterparty has
+       // to store all of them.
+       latest_inbound_scid_alias: Option<u64>,
+
+       // We always offer our counterparty a static SCID alias, which we recognize as for this channel
+       // if we see it in HTLC forwarding instructions. We don't bother rotating the alias given we
+       // don't currently support node id aliases and eventually privacy should be provided with
+       // blinded paths instead of simple scid+node_id aliases.
+       outbound_scid_alias: u64,
 }
 
 #[cfg(any(test, fuzzing))]
@@ -800,7 +813,8 @@ impl<Signer: Sign> Channel<Signer> {
        // Constructors:
        pub fn new_outbound<K: Deref, F: Deref>(
                fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures,
-               channel_value_satoshis: u64, push_msat: u64, user_id: u64, config: &UserConfig, current_chain_height: u32
+               channel_value_satoshis: u64, push_msat: u64, user_id: u64, config: &UserConfig, current_chain_height: u32,
+               outbound_scid_alias: u64
        ) -> Result<Channel<Signer>, APIError>
        where K::Target: KeysInterface<Signer = Signer>,
              F::Target: FeeEstimator,
@@ -947,6 +961,9 @@ impl<Signer: Sign> Channel<Signer> {
 
                        workaround_lnd_bug_4006: None,
 
+                       latest_inbound_scid_alias: None,
+                       outbound_scid_alias,
+
                        #[cfg(any(test, fuzzing))]
                        historical_inbound_htlc_fulfills: HashSet::new(),
 
@@ -984,7 +1001,8 @@ impl<Signer: Sign> Channel<Signer> {
        /// Assumes chain_hash has already been checked and corresponds with what we expect!
        pub fn new_from_req<K: Deref, F: Deref, L: Deref>(
                fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures,
-               msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig, current_chain_height: u32, logger: &L
+               msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig, current_chain_height: u32, logger: &L,
+               outbound_scid_alias: u64
        ) -> Result<Channel<Signer>, ChannelError>
                where K::Target: KeysInterface<Signer = Signer>,
                      F::Target: FeeEstimator,
@@ -1252,6 +1270,9 @@ impl<Signer: Sign> Channel<Signer> {
 
                        workaround_lnd_bug_4006: None,
 
+                       latest_inbound_scid_alias: None,
+                       outbound_scid_alias,
+
                        #[cfg(any(test, fuzzing))]
                        historical_inbound_htlc_fulfills: HashSet::new(),
 
@@ -2151,6 +2172,15 @@ impl<Signer: Sign> Channel<Signer> {
                        return Err(ChannelError::Ignore("Peer sent funding_locked when we needed a channel_reestablish. The peer is likely lnd, see https://github.com/lightningnetwork/lnd/issues/4006".to_owned()));
                }
 
+               if let Some(scid_alias) = msg.short_channel_id_alias {
+                       if Some(scid_alias) != self.short_channel_id {
+                               // The scid alias provided can be used to route payments *from* our counterparty,
+                               // i.e. can be used for inbound payments and provided in invoices, but is not used
+                               // when routing outbound payments.
+                               self.latest_inbound_scid_alias = Some(scid_alias);
+                       }
+               }
+
                let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
 
                if non_shutdown_state == ChannelState::FundingSent as u32 {
@@ -2158,17 +2188,28 @@ impl<Signer: Sign> Channel<Signer> {
                } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
                        self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
                        self.update_time_counter += 1;
-               } else if (self.channel_state & (ChannelState::ChannelFunded as u32) != 0 &&
-                                // Note that funding_signed/funding_created will have decremented both by 1!
-                                self.cur_holder_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 &&
-                                self.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1) ||
-                               // If we reconnected before sending our funding locked they may still resend theirs:
-                               (self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) ==
-                                                     (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32)) {
-                       if self.counterparty_cur_commitment_point != Some(msg.next_per_commitment_point) {
+               } else if self.channel_state & (ChannelState::ChannelFunded as u32) != 0 ||
+                       // If we reconnected before sending our funding locked they may still resend theirs:
+                       (self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) ==
+                                             (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32))
+               {
+                       // They probably disconnected/reconnected and re-sent the funding_locked, which is
+                       // required, or they're sending a fresh SCID alias.
+                       let expected_point =
+                               if self.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 {
+                                       // If they haven't ever sent an updated point, the point they send should match
+                                       // the current one.
+                                       self.counterparty_cur_commitment_point
+                               } else {
+                                       // If they have sent updated points, funding_locked is always supposed to match
+                                       // their "first" point, which we re-derive here.
+                                       Some(PublicKey::from_secret_key(&self.secp_ctx, &SecretKey::from_slice(
+                                                       &self.commitment_secrets.get_secret(INITIAL_COMMITMENT_NUMBER - 1).expect("We should have all prev secrets available")
+                                               ).expect("We already advanced, so previous secret keys should have been validated already")))
+                               };
+                       if expected_point != Some(msg.next_per_commitment_point) {
                                return Err(ChannelError::Close("Peer sent a reconnect funding_locked with a different point".to_owned()));
                        }
-                       // They probably disconnected/reconnected and re-sent the funding_locked, which is required
                        return Ok(None);
                } else {
                        return Err(ChannelError::Close("Peer sent a funding_locked at a strange time".to_owned()));
@@ -3457,6 +3498,7 @@ impl<Signer: Sign> Channel<Signer> {
                        Some(msgs::FundingLocked {
                                channel_id: self.channel_id(),
                                next_per_commitment_point,
+                               short_channel_id_alias: Some(self.outbound_scid_alias),
                        })
                } else { None };
 
@@ -3678,6 +3720,7 @@ impl<Signer: Sign> Channel<Signer> {
                                funding_locked: Some(msgs::FundingLocked {
                                        channel_id: self.channel_id(),
                                        next_per_commitment_point,
+                                       short_channel_id_alias: Some(self.outbound_scid_alias),
                                }),
                                raa: None, commitment_update: None, mon_update: None,
                                order: RAACommitmentOrder::CommitmentFirst,
@@ -3713,6 +3756,7 @@ impl<Signer: Sign> Channel<Signer> {
                        Some(msgs::FundingLocked {
                                channel_id: self.channel_id(),
                                next_per_commitment_point,
+                               short_channel_id_alias: Some(self.outbound_scid_alias),
                        })
                } else { None };
 
@@ -4195,6 +4239,22 @@ impl<Signer: Sign> Channel<Signer> {
                self.short_channel_id
        }
 
+       /// Allowed in any state (including after shutdown)
+       pub fn latest_inbound_scid_alias(&self) -> Option<u64> {
+               self.latest_inbound_scid_alias
+       }
+
+       /// Allowed in any state (including after shutdown)
+       pub fn outbound_scid_alias(&self) -> u64 {
+               self.outbound_scid_alias
+       }
+       /// Only allowed immediately after deserialization if get_outbound_scid_alias returns 0,
+       /// indicating we were written by LDK prior to 0.0.106 which did not set outbound SCID aliases.
+       pub fn set_outbound_scid_alias(&mut self, outbound_scid_alias: u64) {
+               assert_eq!(self.outbound_scid_alias, 0);
+               self.outbound_scid_alias = outbound_scid_alias;
+       }
+
        /// Returns the funding_txo we either got from our peer, or were given by
        /// get_outbound_funding_created.
        pub fn get_funding_txo(&self) -> Option<OutPoint> {
@@ -4443,10 +4503,12 @@ impl<Signer: Sign> Channel<Signer> {
                if need_commitment_update {
                        if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 {
                                if self.channel_state & (ChannelState::PeerDisconnected as u32) == 0 {
-                                       let next_per_commitment_point = self.holder_signer.get_per_commitment_point(self.cur_holder_commitment_transaction_number, &self.secp_ctx);
+                                       let next_per_commitment_point =
+                                               self.holder_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, &self.secp_ctx);
                                        return Some(msgs::FundingLocked {
                                                channel_id: self.channel_id,
                                                next_per_commitment_point,
+                                               short_channel_id_alias: Some(self.outbound_scid_alias),
                                        });
                                }
                        } else {
@@ -5765,6 +5827,8 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
                        (13, self.channel_creation_height, required),
                        (15, preimages, vec_type),
                        (17, self.announcement_sigs_state, required),
+                       (19, self.latest_inbound_scid_alias, option),
+                       (21, self.outbound_scid_alias, required),
                });
 
                Ok(())
@@ -6020,6 +6084,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
                // If we read an old Channel, for simplicity we just treat it as "we never sent an
                // AnnouncementSignatures" which implies we'll re-send it on reconnect, but that's fine.
                let mut announcement_sigs_state = Some(AnnouncementSigsState::NotSent);
+               let mut latest_inbound_scid_alias = None;
+               let mut outbound_scid_alias = None;
 
                read_tlv_fields!(reader, {
                        (0, announcement_sigs, option),
@@ -6035,6 +6101,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
                        (13, channel_creation_height, option),
                        (15, preimages_opt, vec_type),
                        (17, announcement_sigs_state, option),
+                       (19, latest_inbound_scid_alias, option),
+                       (21, outbound_scid_alias, option),
                });
 
                if let Some(preimages) = preimages_opt {
@@ -6169,6 +6237,10 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
 
                        workaround_lnd_bug_4006: None,
 
+                       latest_inbound_scid_alias,
+                       // Later in the ChannelManager deserialization phase we scan for channels and assign scid aliases if its missing
+                       outbound_scid_alias: outbound_scid_alias.unwrap_or(0),
+
                        #[cfg(any(test, fuzzing))]
                        historical_inbound_htlc_fulfills,
 
@@ -6291,7 +6363,7 @@ mod tests {
                let secp_ctx = Secp256k1::new();
                let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               match Channel::<EnforcingSigner>::new_outbound(&&fee_estimator, &&keys_provider, node_id, &features, 10000000, 100000, 42, &config, 0) {
+               match Channel::<EnforcingSigner>::new_outbound(&&fee_estimator, &&keys_provider, node_id, &features, 10000000, 100000, 42, &config, 0, 42) {
                        Err(APIError::IncompatibleShutdownScript { script }) => {
                                assert_eq!(script.into_inner(), non_v0_segwit_shutdown_script.into_inner());
                        },
@@ -6313,7 +6385,7 @@ mod tests {
 
                let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
+               let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
 
                // Now change the fee so we can check that the fee in the open_channel message is the
                // same as the old fee.
@@ -6339,13 +6411,13 @@ mod tests {
                // Create Node A's channel pointing to Node B's pubkey
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
+               let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
 
                // Create Node B's channel by receiving Node A's open_channel message
                // Make sure A's dust limit is as we expect.
                let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash());
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
-               let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger).unwrap();
+               let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger, 42).unwrap();
 
                // Node B --> Node A: accept channel, explicitly setting B's dust limit.
                let mut accept_channel_msg = node_b_chan.accept_inbound_channel();
@@ -6409,7 +6481,7 @@ mod tests {
 
                let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
+               let mut chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
 
                let commitment_tx_fee_0_htlcs = Channel::<EnforcingSigner>::commit_tx_fee_msat(chan.feerate_per_kw, 0, chan.opt_anchors());
                let commitment_tx_fee_1_htlc = Channel::<EnforcingSigner>::commit_tx_fee_msat(chan.feerate_per_kw, 1, chan.opt_anchors());
@@ -6458,12 +6530,12 @@ mod tests {
                // Create Node A's channel pointing to Node B's pubkey
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
+               let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
 
                // Create Node B's channel by receiving Node A's open_channel message
                let open_channel_msg = node_a_chan.get_open_channel(chain_hash);
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
-               let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger).unwrap();
+               let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger, 42).unwrap();
 
                // Node B --> Node A: accept channel
                let accept_channel_msg = node_b_chan.accept_inbound_channel();
@@ -6520,7 +6592,7 @@ mod tests {
                // Create a channel.
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap();
+               let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap();
                assert!(node_a_chan.counterparty_forwarding_info.is_none());
                assert_eq!(node_a_chan.holder_htlc_minimum_msat, 1); // the default
                assert!(node_a_chan.counterparty_forwarding_info().is_none());
@@ -6585,7 +6657,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;
-               let mut chan = Channel::<InMemorySigner>::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config, 0).unwrap(); // Nothing uses their network key in this test
+               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 b47caa6aec42d10b54e2526c64c64699b6a11dd7..f3913c5167c8ebc70d0b1cfadb20568908555133 100644 (file)
@@ -358,7 +358,7 @@ mod inbound_payment {
 // our payment, which we can use to decode errors or inform the user that the payment was sent.
 
 #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
-enum PendingHTLCRouting {
+pub(super) enum PendingHTLCRouting {
        Forward {
                onion_packet: msgs::OnionPacket,
                short_channel_id: u64, // This should be NonZero<u64> eventually when we bump MSRV
@@ -366,6 +366,7 @@ enum PendingHTLCRouting {
        Receive {
                payment_data: msgs::FinalOnionHopData,
                incoming_cltv_expiry: u32, // Used to track when we should expire pending HTLCs that go unclaimed
+               phantom_shared_secret: Option<[u8; 32]>,
        },
        ReceiveKeysend {
                payment_preimage: PaymentPreimage,
@@ -375,8 +376,8 @@ enum PendingHTLCRouting {
 
 #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
 pub(super) struct PendingHTLCInfo {
-       routing: PendingHTLCRouting,
-       incoming_shared_secret: [u8; 32],
+       pub(super) routing: PendingHTLCRouting,
+       pub(super) incoming_shared_secret: [u8; 32],
        payment_hash: PaymentHash,
        pub(super) amt_to_forward: u64,
        pub(super) outgoing_cltv_value: u32,
@@ -419,6 +420,7 @@ pub(crate) struct HTLCPreviousHopData {
        short_channel_id: u64,
        htlc_id: u64,
        incoming_packet_shared_secret: [u8; 32],
+       phantom_shared_secret: Option<[u8; 32]>,
 
        // This field is consumed by `claim_funds_from_hop()` when updating a force-closed backwards
        // channel with a preimage provided by the forward channel.
@@ -658,8 +660,16 @@ pub(super) enum RAACommitmentOrder {
 // Note this is only exposed in cfg(test):
 pub(super) struct ChannelHolder<Signer: Sign> {
        pub(super) by_id: HashMap<[u8; 32], Channel<Signer>>,
+       /// SCIDs (and outbound SCID aliases) to the real channel id. Outbound SCID aliases are added
+       /// here once the channel is available for normal use, with SCIDs being added once the funding
+       /// transaction is confirmed at the channel's required confirmation depth.
        pub(super) short_to_id: HashMap<u64, [u8; 32]>,
-       /// short channel id -> forward infos. Key of 0 means payments received
+       /// SCID/SCID Alias -> forward infos. Key of 0 means payments received.
+       ///
+       /// Note that because we may have an SCID Alias as the key we can have two entries per channel,
+       /// though in practice we probably won't be receiving HTLCs for a channel both via the alias
+       /// and via the classic SCID.
+       ///
        /// Note that while this is held in the same mutex as the channels themselves, no consistency
        /// guarantees are made about the existence of a channel with the short id here, nor the short
        /// ids in the PendingHTLCInfo!
@@ -969,6 +979,12 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
        /// Locked *after* channel_state.
        pending_outbound_payments: Mutex<HashMap<PaymentId, PendingOutboundPayment>>,
 
+       /// The set of outbound SCID aliases across all our channels, including unconfirmed channels
+       /// and some closed channels which reached a usable state prior to being closed. This is used
+       /// only to avoid duplicates, and is not persisted explicitly to disk, but rebuilt from the
+       /// active channel list on load.
+       outbound_scid_aliases: Mutex<HashSet<u64>>,
+
        our_network_key: SecretKey,
        our_network_pubkey: PublicKey,
 
@@ -1186,7 +1202,20 @@ pub struct ChannelDetails {
        pub funding_txo: Option<OutPoint>,
        /// The position of the funding transaction in the chain. None if the funding transaction has
        /// not yet been confirmed and the channel fully opened.
+       ///
+       /// Note that if [`inbound_scid_alias`] is set, it must be used for invoices and inbound
+       /// payments instead of this. See [`get_inbound_payment_scid`].
+       ///
+       /// [`inbound_scid_alias`]: Self::inbound_scid_alias
+       /// [`get_inbound_payment_scid`]: Self::get_inbound_payment_scid
        pub short_channel_id: Option<u64>,
+       /// An optional [`short_channel_id`] alias for this channel, randomly generated by our
+       /// counterparty and usable in place of [`short_channel_id`] in invoice route hints. Our
+       /// counterparty will recognize the alias provided here in place of the [`short_channel_id`]
+       /// when they see a payment to be routed to us.
+       ///
+       /// [`short_channel_id`]: Self::short_channel_id
+       pub inbound_scid_alias: Option<u64>,
        /// The value, in satoshis, of this channel as appears in the funding output
        pub channel_value_satoshis: u64,
        /// The value, in satoshis, that must always be held in the channel for us. This value ensures
@@ -1272,6 +1301,15 @@ pub struct ChannelDetails {
        pub is_public: bool,
 }
 
+impl ChannelDetails {
+       /// Gets the SCID which should be used to identify this channel for inbound payments. This
+       /// should be used for providing invoice hints or in any other context where our counterparty
+       /// will forward a payment to us.
+       pub fn get_inbound_payment_scid(&self) -> Option<u64> {
+               self.inbound_scid_alias.or(self.short_channel_id)
+       }
+}
+
 /// If a payment fails to send, it can be in one of several states. This enum is returned as the
 /// Err() type describing which state the payment is in, see the description of individual enum
 /// states for more.
@@ -1320,6 +1358,7 @@ pub enum PaymentSendFailure {
 /// Route hints used in constructing invoices for [phantom node payents].
 ///
 /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager
+#[derive(Clone)]
 pub struct PhantomRouteHints {
        /// The list of channels to be included in the invoice route hints.
        pub channels: Vec<ChannelDetails>,
@@ -1380,6 +1419,24 @@ macro_rules! handle_error {
        }
 }
 
+macro_rules! update_maps_on_chan_removal {
+       ($self: expr, $short_to_id: expr, $channel: expr) => {
+               if let Some(short_id) = $channel.get_short_channel_id() {
+                       $short_to_id.remove(&short_id);
+               } else {
+                       // If the channel was never confirmed on-chain prior to its closure, remove the
+                       // outbound SCID alias we used for it from the collision-prevention set. While we
+                       // generally want to avoid ever re-using an outbound SCID alias across all channels, we
+                       // also don't want a counterparty to be able to trivially cause a memory leak by simply
+                       // opening a million channels with us which are closed before we ever reach the funding
+                       // stage.
+                       let alias_removed = $self.outbound_scid_aliases.lock().unwrap().remove(&$channel.outbound_scid_alias());
+                       debug_assert!(alias_removed);
+               }
+               $short_to_id.remove(&$channel.outbound_scid_alias());
+       }
+}
+
 /// Returns (boolean indicating if we should remove the Channel object from memory, a mapped error)
 macro_rules! convert_chan_err {
        ($self: ident, $err: expr, $short_to_id: expr, $channel: expr, $channel_id: expr) => {
@@ -1392,18 +1449,14 @@ macro_rules! convert_chan_err {
                        },
                        ChannelError::Close(msg) => {
                                log_error!($self.logger, "Closing channel {} due to close-required error: {}", log_bytes!($channel_id[..]), msg);
-                               if let Some(short_id) = $channel.get_short_channel_id() {
-                                       $short_to_id.remove(&short_id);
-                               }
+                               update_maps_on_chan_removal!($self, $short_to_id, $channel);
                                let shutdown_res = $channel.force_shutdown(true);
                                (true, MsgHandleErrInternal::from_finish_shutdown(msg, *$channel_id, $channel.get_user_id(),
                                        shutdown_res, $self.get_channel_update_for_broadcast(&$channel).ok()))
                        },
                        ChannelError::CloseDelayBroadcast(msg) => {
                                log_error!($self.logger, "Channel {} need to be shutdown but closing transactions not broadcast due to {}", log_bytes!($channel_id[..]), msg);
-                               if let Some(short_id) = $channel.get_short_channel_id() {
-                                       $short_to_id.remove(&short_id);
-                               }
+                               update_maps_on_chan_removal!($self, $short_to_id, $channel);
                                let shutdown_res = $channel.force_shutdown(false);
                                (true, MsgHandleErrInternal::from_finish_shutdown(msg, *$channel_id, $channel.get_user_id(),
                                        shutdown_res, $self.get_channel_update_for_broadcast(&$channel).ok()))
@@ -1443,28 +1496,21 @@ macro_rules! try_chan_entry {
 }
 
 macro_rules! remove_channel {
-       ($channel_state: expr, $entry: expr) => {
+       ($self: expr, $channel_state: expr, $entry: expr) => {
                {
                        let channel = $entry.remove_entry().1;
-                       if let Some(short_id) = channel.get_short_channel_id() {
-                               $channel_state.short_to_id.remove(&short_id);
-                       }
+                       update_maps_on_chan_removal!($self, $channel_state.short_to_id, channel);
                        channel
                }
        }
 }
 
 macro_rules! handle_monitor_err {
-       ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr) => {
-               handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, Vec::new(), Vec::new())
-       };
        ($self: ident, $err: expr, $short_to_id: expr, $chan: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr, $failed_forwards: expr, $failed_fails: expr, $failed_finalized_fulfills: expr, $chan_id: expr) => {
                match $err {
                        ChannelMonitorUpdateErr::PermanentFailure => {
                                log_error!($self.logger, "Closing channel {} due to monitor update ChannelMonitorUpdateErr::PermanentFailure", log_bytes!($chan_id[..]));
-                               if let Some(short_id) = $chan.get_short_channel_id() {
-                                       $short_to_id.remove(&short_id);
-                               }
+                               update_maps_on_chan_removal!($self, $short_to_id, $chan);
                                // TODO: $failed_fails is dropped here, which will cause other channels to hit the
                                // chain in a confused state! We need to move them into the ChannelMonitor which
                                // will be responsible for failing backwards once things confirm on-chain.
@@ -1510,9 +1556,19 @@ macro_rules! handle_monitor_err {
                }
                res
        } };
+       ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $chan_id: expr, COMMITMENT_UPDATE_ONLY) => { {
+               debug_assert!($action_type == RAACommitmentOrder::CommitmentFirst);
+               handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, false, true, Vec::new(), Vec::new(), Vec::new(), $chan_id)
+       } };
+       ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $chan_id: expr, NO_UPDATE) => {
+               handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, false, false, Vec::new(), Vec::new(), Vec::new(), $chan_id)
+       };
+       ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr) => {
+               handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, Vec::new(), Vec::new(), Vec::new())
+       };
        ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr, $failed_forwards: expr, $failed_fails: expr) => {
                handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, $failed_forwards, $failed_fails, Vec::new())
-       }
+       };
 }
 
 macro_rules! return_monitor_err {
@@ -1536,15 +1592,34 @@ macro_rules! maybe_break_monitor_err {
        }
 }
 
+macro_rules! send_funding_locked {
+       ($short_to_id: expr, $pending_msg_events: expr, $channel: expr, $funding_locked_msg: expr) => {
+               $pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
+                       node_id: $channel.get_counterparty_node_id(),
+                       msg: $funding_locked_msg,
+               });
+               // Note that we may send a funding locked multiple times for a channel if we reconnect, so
+               // we allow collisions, but we shouldn't ever be updating the channel ID pointed to.
+               let outbound_alias_insert = $short_to_id.insert($channel.outbound_scid_alias(), $channel.channel_id());
+               assert!(outbound_alias_insert.is_none() || outbound_alias_insert.unwrap() == $channel.channel_id(),
+                       "SCIDs should never collide - ensure you weren't behind the chain tip by a full month when creating channels");
+               if let Some(real_scid) = $channel.get_short_channel_id() {
+                       let scid_insert = $short_to_id.insert(real_scid, $channel.channel_id());
+                       assert!(scid_insert.is_none() || scid_insert.unwrap() == $channel.channel_id(),
+                               "SCIDs should never collide - ensure you weren't behind the chain tip by a full month when creating channels");
+               }
+       }
+}
+
 macro_rules! handle_chan_restoration_locked {
        ($self: ident, $channel_lock: expr, $channel_state: expr, $channel_entry: expr,
         $raa: expr, $commitment_update: expr, $order: expr, $chanmon_update: expr,
         $pending_forwards: expr, $funding_broadcastable: expr, $funding_locked: expr, $announcement_sigs: expr) => { {
                let mut htlc_forwards = None;
-               let counterparty_node_id = $channel_entry.get().get_counterparty_node_id();
 
                let chanmon_update: Option<ChannelMonitorUpdate> = $chanmon_update; // Force type-checking to resolve
                let chanmon_update_is_none = chanmon_update.is_none();
+               let counterparty_node_id = $channel_entry.get().get_counterparty_node_id();
                let res = loop {
                        let forwards: Vec<(PendingHTLCInfo, u64)> = $pending_forwards; // Force type-checking to resolve
                        if !forwards.is_empty() {
@@ -1570,11 +1645,7 @@ macro_rules! handle_chan_restoration_locked {
                                // Similar to the above, this implies that we're letting the funding_locked fly
                                // before it should be allowed to.
                                assert!(chanmon_update.is_none());
-                               $channel_state.pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
-                                       node_id: counterparty_node_id,
-                                       msg,
-                               });
-                               $channel_state.short_to_id.insert($channel_entry.get().get_short_channel_id().unwrap(), $channel_entry.get().channel_id());
+                               send_funding_locked!($channel_state.short_to_id, $channel_state.pending_msg_events, $channel_entry.get(), msg);
                        }
                        if let Some(msg) = $announcement_sigs {
                                $channel_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
@@ -1703,6 +1774,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                claimable_htlcs: HashMap::new(),
                                pending_msg_events: Vec::new(),
                        }),
+                       outbound_scid_aliases: Mutex::new(HashSet::new()),
                        pending_inbound_payments: Mutex::new(HashMap::new()),
                        pending_outbound_payments: Mutex::new(HashMap::new()),
 
@@ -1734,6 +1806,25 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                &self.default_configuration
        }
 
+       fn create_and_insert_outbound_scid_alias(&self) -> u64 {
+               let height = self.best_block.read().unwrap().height();
+               let mut outbound_scid_alias = 0;
+               let mut i = 0;
+               loop {
+                       if cfg!(fuzzing) { // fuzzing chacha20 doesn't use the key at all so we always get the same alias
+                               outbound_scid_alias += 1;
+                       } else {
+                               outbound_scid_alias = fake_scid::Namespace::OutboundAlias.get_fake_scid(height, &self.genesis_hash, &self.fake_scid_rand_bytes, &self.keys_manager);
+                       }
+                       if outbound_scid_alias != 0 && self.outbound_scid_aliases.lock().unwrap().insert(outbound_scid_alias) {
+                               break;
+                       }
+                       i += 1;
+                       if i > 1_000_000 { panic!("Your RNG is busted or we ran out of possible outbound SCID aliases (which should never happen before we run out of memory to store channels"); }
+               }
+               outbound_scid_alias
+       }
+
        /// Creates a new outbound channel to the given remote node and with the given value.
        ///
        /// `user_channel_id` will be provided back as in
@@ -1769,11 +1860,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                        let per_peer_state = self.per_peer_state.read().unwrap();
                        match per_peer_state.get(&their_network_key) {
                                Some(peer_state) => {
+                                       let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
                                        let peer_state = peer_state.lock().unwrap();
                                        let their_features = &peer_state.latest_features;
                                        let config = if override_config.is_some() { override_config.as_ref().unwrap() } else { &self.default_configuration };
-                                       Channel::new_outbound(&self.fee_estimator, &self.keys_manager, their_network_key, their_features,
-                                               channel_value_satoshis, push_msat, user_channel_id, config, self.best_block.read().unwrap().height())?
+                                       match Channel::new_outbound(&self.fee_estimator, &self.keys_manager, their_network_key,
+                                               their_features, channel_value_satoshis, push_msat, user_channel_id, config,
+                                               self.best_block.read().unwrap().height(), outbound_scid_alias)
+                                       {
+                                               Ok(res) => res,
+                                               Err(e) => {
+                                                       self.outbound_scid_aliases.lock().unwrap().remove(&outbound_scid_alias);
+                                                       return Err(e);
+                                               },
+                                       }
                                },
                                None => return Err(APIError::ChannelUnavailable { err: format!("Not connected to node: {}", their_network_key) }),
                        }
@@ -1823,6 +1923,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        },
                                        funding_txo: channel.get_funding_txo(),
                                        short_channel_id: channel.get_short_channel_id(),
+                                       inbound_scid_alias: channel.latest_inbound_scid_alias(),
                                        channel_value_satoshis: channel.get_value_satoshis(),
                                        unspendable_punishment_reserve: to_self_reserve_satoshis,
                                        balance_msat,
@@ -1908,9 +2009,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        if let Some(monitor_update) = monitor_update {
                                                if let Err(e) = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), monitor_update) {
                                                        let (result, is_permanent) =
-                                                               handle_monitor_err!(self, e, channel_state.short_to_id, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, false, false, Vec::new(), Vec::new(), Vec::new(), chan_entry.key());
+                                                               handle_monitor_err!(self, e, channel_state.short_to_id, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE);
                                                        if is_permanent {
-                                                               remove_channel!(channel_state, chan_entry);
+                                                               remove_channel!(self, channel_state, chan_entry);
                                                                break result;
                                                        }
                                                }
@@ -1922,7 +2023,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        });
 
                                        if chan_entry.get().is_shutdown() {
-                                               let channel = remove_channel!(channel_state, chan_entry);
+                                               let channel = remove_channel!(self, channel_state, chan_entry);
                                                if let Ok(channel_update) = self.get_channel_update_for_broadcast(&channel) {
                                                        channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                                                msg: channel_update
@@ -2016,9 +2117,6 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                return Err(APIError::ChannelUnavailable{err: "No such channel".to_owned()});
                                        }
                                }
-                               if let Some(short_id) = chan.get().get_short_channel_id() {
-                                       channel_state.short_to_id.remove(&short_id);
-                               }
                                if peer_node_id.is_some() {
                                        if let Some(peer_msg) = peer_msg {
                                                self.issue_channel_close_events(chan.get(),ClosureReason::CounterpartyForceClosed { peer_msg: peer_msg.to_string() });
@@ -2026,7 +2124,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                } else {
                                        self.issue_channel_close_events(chan.get(),ClosureReason::HolderForceClosed);
                                }
-                               chan.remove_entry().1
+                               remove_channel!(self, channel_state, chan)
                        } else {
                                return Err(APIError::ChannelUnavailable{err: "No such channel".to_owned()});
                        }
@@ -2072,7 +2170,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        }
 
        fn construct_recv_pending_htlc_info(&self, hop_data: msgs::OnionHopData, shared_secret: [u8; 32],
-               payment_hash: PaymentHash, amt_msat: u64, cltv_expiry: u32) -> Result<PendingHTLCInfo, ReceiveError>
+               payment_hash: PaymentHash, amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>) -> Result<PendingHTLCInfo, ReceiveError>
        {
                // final_incorrect_cltv_expiry
                if hop_data.outgoing_cltv_value != cltv_expiry {
@@ -2129,6 +2227,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        PendingHTLCRouting::Receive {
                                                payment_data: data,
                                                incoming_cltv_expiry: hop_data.outgoing_cltv_value,
+                                               phantom_shared_secret,
                                        }
                                } else if let Some(payment_preimage) = keysend_preimage {
                                        // We need to check that the sender knows the keysend preimage before processing this
@@ -2232,7 +2331,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                let pending_forward_info = match next_hop {
                        onion_utils::Hop::Receive(next_hop_data) => {
                                // OUR PAYMENT!
-                               match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry) {
+                               match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry, None) {
                                        Ok(info) => {
                                                // Note that we could obviously respond immediately with an update_fulfill_htlc
                                                // message, however that would leak that we are the recipient of this payment, so
@@ -3012,17 +3111,18 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                                                routing, incoming_shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value },
                                                                                prev_funding_outpoint } => {
                                                                                        macro_rules! fail_forward {
-                                                                                               ($msg: expr, $err_code: expr, $err_data: expr) => {
+                                                                                               ($msg: expr, $err_code: expr, $err_data: expr, $phantom_ss: expr) => {
                                                                                                        {
                                                                                                                log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
                                                                                                                let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
-                                                                                                                       short_channel_id: short_chan_id,
+                                                                                                                       short_channel_id: prev_short_channel_id,
                                                                                                                        outpoint: prev_funding_outpoint,
                                                                                                                        htlc_id: prev_htlc_id,
                                                                                                                        incoming_packet_shared_secret: incoming_shared_secret,
+                                                                                                                       phantom_shared_secret: $phantom_ss,
                                                                                                                });
                                                                                                                failed_forwards.push((htlc_source, payment_hash,
-                                                                                                                               HTLCFailReason::Reason { failure_code: $err_code, data: $err_data }
+                                                                                                                       HTLCFailReason::Reason { failure_code: $err_code, data: $err_data }
                                                                                                                ));
                                                                                                                continue;
                                                                                                        }
@@ -3031,34 +3131,39 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                                                        if let PendingHTLCRouting::Forward { onion_packet, .. } = routing {
                                                                                                let phantom_secret_res = self.keys_manager.get_node_secret(Recipient::PhantomNode);
                                                                                                if phantom_secret_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id) {
-                                                                                                       let shared_secret = {
+                                                                                                       let phantom_shared_secret = {
                                                                                                                let mut arr = [0; 32];
                                                                                                                arr.copy_from_slice(&SharedSecret::new(&onion_packet.public_key.unwrap(), &phantom_secret_res.unwrap())[..]);
                                                                                                                arr
                                                                                                        };
-                                                                                                       let next_hop = match onion_utils::decode_next_hop(shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
+                                                                                                       let next_hop = match onion_utils::decode_next_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
                                                                                                                Ok(res) => res,
                                                                                                                Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
-                                                                                                                       fail_forward!(err_msg, err_code, Vec::new());
+                                                                                                                       let sha256_of_onion = Sha256::hash(&onion_packet.hop_data).into_inner();
+                                                                                                                       // In this scenario, the phantom would have sent us an
+                                                                                                                       // `update_fail_malformed_htlc`, meaning here we encrypt the error as
+                                                                                                                       // if it came from us (the second-to-last hop) but contains the sha256
+                                                                                                                       // of the onion.
+                                                                                                                       fail_forward!(err_msg, err_code, sha256_of_onion.to_vec(), None);
                                                                                                                },
                                                                                                                Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
-                                                                                                                       fail_forward!(err_msg, err_code, Vec::new());
+                                                                                                                       fail_forward!(err_msg, err_code, Vec::new(), Some(phantom_shared_secret));
                                                                                                                },
                                                                                                        };
                                                                                                        match next_hop {
                                                                                                                onion_utils::Hop::Receive(hop_data) => {
-                                                                                                                       match self.construct_recv_pending_htlc_info(hop_data, shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value) {
+                                                                                                                       match self.construct_recv_pending_htlc_info(hop_data, incoming_shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value, Some(phantom_shared_secret)) {
                                                                                                                                Ok(info) => phantom_receives.push((prev_short_channel_id, prev_funding_outpoint, vec![(info, prev_htlc_id)])),
-                                                                                                                               Err(ReceiveError { err_code, err_data, msg }) => fail_forward!(msg, err_code, err_data)
+                                                                                                                               Err(ReceiveError { err_code, err_data, msg }) => fail_forward!(msg, err_code, err_data, Some(phantom_shared_secret))
                                                                                                                        }
                                                                                                                },
                                                                                                                _ => panic!(),
                                                                                                        }
                                                                                                } else {
-                                                                                                       fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new());
+                                                                                                       fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new(), None);
                                                                                                }
                                                                                        } else {
-                                                                                               fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new());
+                                                                                               fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new(), None);
                                                                                        }
                                                                                },
                                                                        HTLCForwardInfo::FailHTLC { .. } => {
@@ -3066,9 +3171,6 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                                                // the channel is now on chain and our counterparty is
                                                                                // trying to broadcast the HTLC-Timeout, but that's their
                                                                                // problem, not ours.
-                                                                               //
-                                                                               // `fail_htlc_backwards_internal` is never called for
-                                                                               // phantom payments, so this is unreachable for them.
                                                                        }
                                                                }
                                                        }
@@ -3091,6 +3193,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                                                outpoint: prev_funding_outpoint,
                                                                                htlc_id: prev_htlc_id,
                                                                                incoming_packet_shared_secret: incoming_shared_secret,
+                                                                               // Phantom payments are only PendingHTLCRouting::Receive.
+                                                                               phantom_shared_secret: None,
                                                                        });
                                                                        match chan.get_mut().send_htlc(amt_to_forward, payment_hash, outgoing_cltv_value, htlc_source.clone(), onion_packet, &self.logger) {
                                                                                Err(e) => {
@@ -3167,12 +3271,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                                                }
                                                                                ChannelError::Close(msg) => {
                                                                                        log_trace!(self.logger, "Closing channel {} due to Close-required error: {}", log_bytes!(chan.key()[..]), msg);
-                                                                                       let (channel_id, mut channel) = chan.remove_entry();
-                                                                                       if let Some(short_id) = channel.get_short_channel_id() {
-                                                                                               channel_state.short_to_id.remove(&short_id);
-                                                                                       }
+                                                                                       let mut channel = remove_channel!(self, channel_state, chan);
                                                                                        // ChannelClosed event is generated by handle_error for us.
-                                                                                       Err(MsgHandleErrInternal::from_finish_shutdown(msg, channel_id, channel.get_user_id(), channel.force_shutdown(true), self.get_channel_update_for_broadcast(&channel).ok()))
+                                                                                       Err(MsgHandleErrInternal::from_finish_shutdown(msg, channel.channel_id(), channel.get_user_id(), channel.force_shutdown(true), self.get_channel_update_for_broadcast(&channel).ok()))
                                                                                },
                                                                                ChannelError::CloseDelayBroadcast(_) => { panic!("Wait is only generated on receipt of channel_reestablish, which is handled by try_chan_entry, we don't bother to support it here"); }
                                                                        };
@@ -3207,11 +3308,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                        HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_htlc_id, forward_info: PendingHTLCInfo {
                                                                        routing, incoming_shared_secret, payment_hash, amt_to_forward, .. },
                                                                        prev_funding_outpoint } => {
-                                                               let (cltv_expiry, onion_payload) = match routing {
-                                                                       PendingHTLCRouting::Receive { payment_data, incoming_cltv_expiry } =>
-                                                                               (incoming_cltv_expiry, OnionPayload::Invoice(payment_data)),
+                                                               let (cltv_expiry, onion_payload, phantom_shared_secret) = match routing {
+                                                                       PendingHTLCRouting::Receive { payment_data, incoming_cltv_expiry, phantom_shared_secret } =>
+                                                                               (incoming_cltv_expiry, OnionPayload::Invoice(payment_data), phantom_shared_secret),
                                                                        PendingHTLCRouting::ReceiveKeysend { payment_preimage, incoming_cltv_expiry } =>
-                                                                               (incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage)),
+                                                                               (incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage), None),
                                                                        _ => {
                                                                                panic!("short_channel_id == 0 should imply any pending_forward entries are of type Receive");
                                                                        }
@@ -3222,6 +3323,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                                                outpoint: prev_funding_outpoint,
                                                                                htlc_id: prev_htlc_id,
                                                                                incoming_packet_shared_secret: incoming_shared_secret,
+                                                                               phantom_shared_secret,
                                                                        },
                                                                        value: amt_to_forward,
                                                                        cltv_expiry,
@@ -3239,6 +3341,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                                                                outpoint: prev_funding_outpoint,
                                                                                                htlc_id: $htlc.prev_hop.htlc_id,
                                                                                                incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret,
+                                                                                               phantom_shared_secret,
                                                                                        }), payment_hash,
                                                                                        HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: htlc_msat_height_data }
                                                                                ));
@@ -3444,7 +3547,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                let ret_err = match res {
                        Ok(Some((update_fee, commitment_signed, monitor_update))) => {
                                if let Err(e) = self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) {
-                                       let (res, drop) = handle_monitor_err!(self, e, short_to_id, chan, RAACommitmentOrder::CommitmentFirst, false, true, Vec::new(), Vec::new(), Vec::new(), chan_id);
+                                       let (res, drop) = handle_monitor_err!(self, e, short_to_id, chan, RAACommitmentOrder::CommitmentFirst, chan_id, COMMITMENT_UPDATE_ONLY);
                                        if drop { retain_channel = false; }
                                        res
                                } else {
@@ -3778,12 +3881,18 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                pending_events.push(path_failure);
                                if let Some(ev) = full_failure_ev { pending_events.push(ev); }
                        },
-                       HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id, htlc_id, incoming_packet_shared_secret, .. }) => {
+                       HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id, htlc_id, incoming_packet_shared_secret, phantom_shared_secret, .. }) => {
                                let err_packet = match onion_error {
                                        HTLCFailReason::Reason { failure_code, data } => {
                                                log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards from us with code {}", log_bytes!(payment_hash.0), failure_code);
-                                               let packet = onion_utils::build_failure_packet(&incoming_packet_shared_secret, failure_code, &data[..]).encode();
-                                               onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &packet)
+                                               if let Some(phantom_ss) = phantom_shared_secret {
+                                                       let phantom_packet = onion_utils::build_failure_packet(&phantom_ss, failure_code, &data[..]).encode();
+                                                       let encrypted_phantom_packet = onion_utils::encrypt_failure_packet(&phantom_ss, &phantom_packet);
+                                                       onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &encrypted_phantom_packet.data[..])
+                                               } else {
+                                                       let packet = onion_utils::build_failure_packet(&incoming_packet_shared_secret, failure_code, &data[..]).encode();
+                                                       onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &packet)
+                                               }
                                        },
                                        HTLCFailReason::LightningError { err } => {
                                                log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards with pre-built LightningError", log_bytes!(payment_hash.0));
@@ -4174,13 +4283,24 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                        return Err(MsgHandleErrInternal::send_err_msg_no_close("No inbound channels accepted".to_owned(), msg.temporary_channel_id.clone()));
                }
 
-               let mut channel = Channel::new_from_req(&self.fee_estimator, &self.keys_manager, counterparty_node_id.clone(),
-                               &their_features, msg, 0, &self.default_configuration, self.best_block.read().unwrap().height(), &self.logger)
-                       .map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id))?;
+               let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
+               let mut channel = match Channel::new_from_req(&self.fee_estimator, &self.keys_manager,
+                       counterparty_node_id.clone(), &their_features, msg, 0, &self.default_configuration,
+                       self.best_block.read().unwrap().height(), &self.logger, outbound_scid_alias)
+               {
+                       Err(e) => {
+                               self.outbound_scid_aliases.lock().unwrap().remove(&outbound_scid_alias);
+                               return Err(MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id));
+                       },
+                       Ok(res) => res
+               };
                let mut channel_state_lock = self.channel_state.lock().unwrap();
                let channel_state = &mut *channel_state_lock;
                match channel_state.by_id.entry(channel.channel_id()) {
-                       hash_map::Entry::Occupied(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision!".to_owned(), msg.temporary_channel_id.clone())),
+                       hash_map::Entry::Occupied(_) => {
+                               self.outbound_scid_aliases.lock().unwrap().remove(&outbound_scid_alias);
+                               return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision!".to_owned(), msg.temporary_channel_id.clone()))
+                       },
                        hash_map::Entry::Vacant(entry) => {
                                if !self.default_configuration.manually_accept_inbound_channels {
                                        channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
@@ -4382,9 +4502,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        if let Some(monitor_update) = monitor_update {
                                                if let Err(e) = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), monitor_update) {
                                                        let (result, is_permanent) =
-                                                               handle_monitor_err!(self, e, channel_state.short_to_id, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, false, false, Vec::new(), Vec::new(), Vec::new(), chan_entry.key());
+                                                               handle_monitor_err!(self, e, channel_state.short_to_id, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE);
                                                        if is_permanent {
-                                                               remove_channel!(channel_state, chan_entry);
+                                                               remove_channel!(self, channel_state, chan_entry);
                                                                break result;
                                                        }
                                                }
@@ -4432,10 +4552,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                // also implies there are no pending HTLCs left on the channel, so we can
                                                // fully delete it from tracking (the channel monitor is still around to
                                                // watch for old state broadcasts)!
-                                               if let Some(short_id) = chan_entry.get().get_short_channel_id() {
-                                                       channel_state.short_to_id.remove(&short_id);
-                                               }
-                                               (tx, Some(chan_entry.remove_entry().1))
+                                               (tx, Some(remove_channel!(self, channel_state, chan_entry)))
                                        } else { (tx, None) }
                                },
                                hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
@@ -4487,7 +4604,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                                        onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
                                                                                let mut res = Vec::with_capacity(8 + 128);
                                                                                // TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
-                                                                               res.extend_from_slice(&byte_utils::be16_to_array(0));
+                                                                               if error_code == 0x1000 | 20 {
+                                                                                       res.extend_from_slice(&byte_utils::be16_to_array(0));
+                                                                               }
                                                                                res.extend_from_slice(&upd.encode_with_len()[..]);
                                                                                res
                                                                        }[..])
@@ -4871,12 +4990,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        let mut channel_lock = self.channel_state.lock().unwrap();
                                        let channel_state = &mut *channel_lock;
                                        let by_id = &mut channel_state.by_id;
-                                       let short_to_id = &mut channel_state.short_to_id;
                                        let pending_msg_events = &mut channel_state.pending_msg_events;
-                                       if let Some(mut chan) = by_id.remove(&funding_outpoint.to_channel_id()) {
-                                               if let Some(short_id) = chan.get_short_channel_id() {
-                                                       short_to_id.remove(&short_id);
-                                               }
+                                       if let hash_map::Entry::Occupied(chan_entry) = by_id.entry(funding_outpoint.to_channel_id()) {
+                                               let mut chan = remove_channel!(self, channel_state, chan_entry);
                                                failed_channels.push(chan.force_shutdown(false));
                                                if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
                                                        pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
@@ -4946,7 +5062,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                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) {
                                                                has_monitor_update = true;
-                                                               let (res, close_channel) = handle_monitor_err!(self, e, short_to_id, chan, RAACommitmentOrder::CommitmentFirst, false, true, Vec::new(), Vec::new(), Vec::new(), channel_id);
+                                                               let (res, close_channel) = handle_monitor_err!(self, e, short_to_id, chan, RAACommitmentOrder::CommitmentFirst, channel_id, COMMITMENT_UPDATE_ONLY);
                                                                handle_errors.push((chan.get_counterparty_node_id(), res));
                                                                if close_channel { return false; }
                                                        } else {
@@ -5005,10 +5121,6 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                if let Some(tx) = tx_opt {
                                                        // We're done with this channel. We got a closing_signed and sent back
                                                        // a closing_signed with a closing transaction to broadcast.
-                                                       if let Some(short_id) = chan.get_short_channel_id() {
-                                                               short_to_id.remove(&short_id);
-                                                       }
-
                                                        if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
                                                                pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                                                        msg: update
@@ -5019,6 +5131,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
 
                                                        log_info!(self.logger, "Broadcasting {}", log_tx!(tx));
                                                        self.tx_broadcaster.broadcast_transaction(&tx);
+                                                       update_maps_on_chan_removal!(self, short_to_id, chan);
                                                        false
                                                } else { true }
                                        },
@@ -5126,6 +5239,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        /// Legacy version of [`create_inbound_payment`]. Use this method if you wish to share
        /// serialized state with LDK node(s) running 0.0.103 and earlier.
        ///
+       /// May panic if `invoice_expiry_delta_secs` is greater than one year.
+       ///
        /// # Note
        /// This method is deprecated and will be removed soon.
        ///
@@ -5166,8 +5281,6 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        /// If you need exact expiry semantics, you should enforce them upon receipt of
        /// [`PaymentReceived`].
        ///
-       /// May panic if `invoice_expiry_delta_secs` is greater than one year.
-       ///
        /// Note that invoices generated for inbound payments should have their `min_final_cltv_expiry`
        /// set to at least [`MIN_FINAL_CLTV_EXPIRY`].
        ///
@@ -5190,6 +5303,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        /// Legacy version of [`create_inbound_payment_for_hash`]. Use this method if you wish to share
        /// serialized state with LDK node(s) running 0.0.103 and earlier.
        ///
+       /// May panic if `invoice_expiry_delta_secs` is greater than one year.
+       ///
        /// # Note
        /// This method is deprecated and will be removed soon.
        ///
@@ -5215,7 +5330,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                let mut channel_state = self.channel_state.lock().unwrap();
                let best_block = self.best_block.read().unwrap();
                loop {
-                       let scid_candidate = fake_scid::get_phantom_scid(&self.fake_scid_rand_bytes, best_block.height(), &self.genesis_hash, &self.keys_manager);
+                       let scid_candidate = fake_scid::Namespace::Phantom.get_fake_scid(best_block.height(), &self.genesis_hash, &self.fake_scid_rand_bytes, &self.keys_manager);
                        // Ensure the generated scid doesn't conflict with a real channel.
                        match channel_state.short_to_id.entry(scid_candidate) {
                                hash_map::Entry::Occupied(_) => continue,
@@ -5503,10 +5618,7 @@ where
                                                }));
                                        }
                                        if let Some(funding_locked) = funding_locked_opt {
-                                               pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
-                                                       node_id: channel.get_counterparty_node_id(),
-                                                       msg: funding_locked,
-                                               });
+                                               send_funding_locked!(short_to_id, pending_msg_events, channel, funding_locked);
                                                if channel.is_usable() {
                                                        log_trace!(self.logger, "Sending funding_locked with private initial channel_update for our counterparty on channel {}", log_bytes!(channel.channel_id()));
                                                        pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
@@ -5516,7 +5628,6 @@ where
                                                } else {
                                                        log_trace!(self.logger, "Sending funding_locked WITHOUT channel_update for {}", log_bytes!(channel.channel_id()));
                                                }
-                                               short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id());
                                        }
                                        if let Some(announcement_sigs) = announcement_sigs {
                                                log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(channel.channel_id()));
@@ -5536,9 +5647,7 @@ where
                                                }
                                        }
                                } else if let Err(reason) = res {
-                                       if let Some(short_id) = channel.get_short_channel_id() {
-                                               short_to_id.remove(&short_id);
-                                       }
+                                       update_maps_on_chan_removal!(self, short_to_id, channel);
                                        // It looks like our counterparty went on-chain or funding transaction was
                                        // reorged out of the main chain. Close the channel.
                                        failed_channels.push(channel.force_shutdown(true));
@@ -5728,15 +5837,13 @@ impl<Signer: Sign, M: Deref , T: Deref , K: Deref , F: Deref , L: Deref >
                {
                        let mut channel_state_lock = self.channel_state.lock().unwrap();
                        let channel_state = &mut *channel_state_lock;
-                       let short_to_id = &mut channel_state.short_to_id;
                        let pending_msg_events = &mut channel_state.pending_msg_events;
+                       let short_to_id = &mut channel_state.short_to_id;
                        if no_connection_possible {
                                log_debug!(self.logger, "Failing all channels with {} due to no_connection_possible", log_pubkey!(counterparty_node_id));
                                channel_state.by_id.retain(|_, chan| {
                                        if chan.get_counterparty_node_id() == *counterparty_node_id {
-                                               if let Some(short_id) = chan.get_short_channel_id() {
-                                                       short_to_id.remove(&short_id);
-                                               }
+                                               update_maps_on_chan_removal!(self, short_to_id, chan);
                                                failed_channels.push(chan.force_shutdown(true));
                                                if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
                                                        pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
@@ -5755,9 +5862,7 @@ impl<Signer: Sign, M: Deref , T: Deref , K: Deref , F: Deref , L: Deref >
                                        if chan.get_counterparty_node_id() == *counterparty_node_id {
                                                chan.remove_uncommitted_htlcs_and_mark_paused(&self.logger);
                                                if chan.is_shutdown() {
-                                                       if let Some(short_id) = chan.get_short_channel_id() {
-                                                               short_to_id.remove(&short_id);
-                                                       }
+                                                       update_maps_on_chan_removal!(self, short_to_id, chan);
                                                        self.issue_channel_close_events(chan, ClosureReason::DisconnectedPeer);
                                                        return false;
                                                } else {
@@ -5947,6 +6052,7 @@ impl_writeable_tlv_based!(ChannelCounterparty, {
 });
 
 impl_writeable_tlv_based!(ChannelDetails, {
+       (1, inbound_scid_alias, option),
        (2, channel_id, required),
        (4, counterparty, required),
        (6, funding_txo, option),
@@ -5978,6 +6084,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
        },
        (1, Receive) => {
                (0, payment_data, required),
+               (1, phantom_shared_secret, option),
                (2, incoming_cltv_expiry, required),
        },
        (2, ReceiveKeysend) => {
@@ -6069,6 +6176,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCStatus, ;
 
 impl_writeable_tlv_based!(HTLCPreviousHopData, {
        (0, short_channel_id, required),
+       (1, phantom_shared_secret, option),
        (2, outpoint, required),
        (4, htlc_id, required),
        (6, incoming_packet_shared_secret, required)
@@ -6754,6 +6862,32 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
                        }
                }
 
+               let mut outbound_scid_aliases = HashSet::new();
+               for (chan_id, chan) in by_id.iter_mut() {
+                       if chan.outbound_scid_alias() == 0 {
+                               let mut outbound_scid_alias;
+                               loop {
+                                       outbound_scid_alias = fake_scid::Namespace::OutboundAlias
+                                               .get_fake_scid(best_block_height, &genesis_hash, fake_scid_rand_bytes.as_ref().unwrap(), &args.keys_manager);
+                                       if outbound_scid_aliases.insert(outbound_scid_alias) { break; }
+                               }
+                               chan.set_outbound_scid_alias(outbound_scid_alias);
+                       } else if !outbound_scid_aliases.insert(chan.outbound_scid_alias()) {
+                               // Note that in rare cases its possible to hit this while reading an older
+                               // channel if we just happened to pick a colliding outbound alias above.
+                               log_error!(args.logger, "Got duplicate outbound SCID alias; {}", chan.outbound_scid_alias());
+                               return Err(DecodeError::InvalidValue);
+                       }
+                       if chan.is_usable() {
+                               if short_to_id.insert(chan.outbound_scid_alias(), *chan_id).is_some() {
+                                       // Note that in rare cases its possible to hit this while reading an older
+                                       // channel if we just happened to pick a colliding outbound alias above.
+                                       log_error!(args.logger, "Got duplicate outbound SCID alias; {}", chan.outbound_scid_alias());
+                                       return Err(DecodeError::InvalidValue);
+                               }
+                       }
+               }
+
                let inbound_pmt_key_material = args.keys_manager.get_inbound_payment_key_material();
                let expanded_inbound_key = inbound_payment::ExpandedKey::new(&inbound_pmt_key_material);
                let channel_manager = ChannelManager {
@@ -6774,6 +6908,8 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
                        inbound_payment_key: expanded_inbound_key,
                        pending_inbound_payments: Mutex::new(pending_inbound_payments),
                        pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()),
+
+                       outbound_scid_aliases: Mutex::new(outbound_scid_aliases),
                        fake_scid_rand_bytes: fake_scid_rand_bytes.unwrap(),
 
                        our_network_key,
@@ -6823,6 +6959,7 @@ mod tests {
        use util::errors::APIError;
        use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
        use util::test_utils;
+       use chain::keysinterface::KeysInterface;
 
        #[cfg(feature = "std")]
        #[test]
@@ -7076,6 +7213,7 @@ mod tests {
                let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
                create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
 
                // To start (1), send a regular payment but don't claim it.
                let expected_route = [&nodes[1]];
@@ -7089,7 +7227,7 @@ mod tests {
                };
                let route = find_route(
                        &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
-                       nodes[0].logger, &scorer
+                       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);
@@ -7120,7 +7258,7 @@ mod tests {
                let payment_preimage = PaymentPreimage([42; 32]);
                let route = find_route(
                        &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
-                       nodes[0].logger, &scorer
+                       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);
@@ -7181,9 +7319,10 @@ mod tests {
                let network_graph = nodes[0].network_graph;
                let first_hops = nodes[0].node.list_usable_channels();
                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
+                       nodes[0].logger, &scorer, &random_seed_bytes
                ).unwrap();
 
                let test_preimage = PaymentPreimage([42; 32]);
@@ -7224,9 +7363,10 @@ mod tests {
                let network_graph = nodes[0].network_graph;
                let first_hops = nodes[0].node.list_usable_channels();
                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
+                       nodes[0].logger, &scorer, &random_seed_bytes
                ).unwrap();
 
                let test_preimage = PaymentPreimage([42; 32]);
@@ -7310,7 +7450,7 @@ mod tests {
 pub mod bench {
        use chain::Listen;
        use chain::chainmonitor::{ChainMonitor, Persist};
-       use chain::keysinterface::{KeysManager, InMemorySigner};
+       use chain::keysinterface::{KeysManager, KeysInterface, InMemorySigner};
        use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage};
        use ln::features::{InitFeatures, InvoiceFeatures};
        use ln::functional_test_utils::*;
@@ -7319,7 +7459,7 @@ pub mod bench {
        use routing::router::{PaymentParameters, get_route};
        use util::test_utils;
        use util::config::UserConfig;
-       use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
+       use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
 
        use bitcoin::hashes::Hash;
        use bitcoin::hashes::sha256::Hash as Sha256;
@@ -7427,8 +7567,11 @@ pub mod bench {
                                let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id())
                                        .with_features(InvoiceFeatures::known());
                                let scorer = test_utils::TestScorer::with_penalty(0);
-                               let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph,
-                                       Some(&usable_channels.iter().map(|r| r).collect::<Vec<_>>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer).unwrap();
+                               let seed = [3u8; 32];
+                               let keys_manager = KeysManager::new(&seed, 42, 42);
+                               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+                               let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph.read_only(),
+                                       Some(&usable_channels.iter().map(|r| r).collect::<Vec<_>>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer, &random_seed_bytes).unwrap();
 
                                let mut payment_preimage = PaymentPreimage([0; 32]);
                                payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes());
index 1d9e5afc46eecb7c66abac96528aa763a4030bbb..5901efbf95cf47fbceabb97d77dcd94abfcd543f 100644 (file)
@@ -10,7 +10,7 @@
 //! A bunch of useful utilities for building networks of nodes and exchanging messages between
 //! nodes for functional tests.
 
-use chain::{BestBlock, Confirm, Listen, Watch};
+use chain::{BestBlock, Confirm, Listen, Watch, keysinterface::KeysInterface};
 use chain::channelmonitor::ChannelMonitor;
 use chain::transaction::OutPoint;
 use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
@@ -123,19 +123,29 @@ pub fn connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block)
        do_connect_block(node, block, false);
 }
 
+fn call_claimable_balances<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>) {
+       // Ensure `get_claimable_balances`' self-tests never panic
+       for funding_outpoint in node.chain_monitor.chain_monitor.list_monitors() {
+               node.chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances();
+       }
+}
+
 fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block, skip_intermediaries: bool) {
+       call_claimable_balances(node);
        let height = node.best_block_info().1 + 1;
        if !skip_intermediaries {
                let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
                match *node.connect_style.borrow() {
                        ConnectStyle::BestBlockFirst|ConnectStyle::BestBlockFirstSkippingBlocks => {
                                node.chain_monitor.chain_monitor.best_block_updated(&block.header, height);
+                               call_claimable_balances(node);
                                node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height);
                                node.node.best_block_updated(&block.header, height);
                                node.node.transactions_confirmed(&block.header, &txdata, height);
                        },
                        ConnectStyle::TransactionsFirst|ConnectStyle::TransactionsFirstSkippingBlocks => {
                                node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height);
+                               call_claimable_balances(node);
                                node.chain_monitor.chain_monitor.best_block_updated(&block.header, height);
                                node.node.transactions_confirmed(&block.header, &txdata, height);
                                node.node.best_block_updated(&block.header, height);
@@ -146,11 +156,13 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block, s
                        }
                }
        }
+       call_claimable_balances(node);
        node.node.test_process_background_events();
        node.blocks.lock().unwrap().push((block.header, height));
 }
 
 pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) {
+       call_claimable_balances(node);
        for i in 0..count {
                let orig_header = node.blocks.lock().unwrap().pop().unwrap();
                assert!(orig_header.1 > 0); // Cannot disconnect genesis
@@ -172,6 +184,7 @@ pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32)
                                node.node.best_block_updated(&prev_header.0, prev_header.1);
                        },
                }
+               call_claimable_balances(node);
        }
 }
 
@@ -680,6 +693,61 @@ pub fn create_announced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a
        (chan_announcement.1, chan_announcement.2, chan_announcement.3, chan_announcement.4)
 }
 
+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::FundingLocked, Transaction) {
+       let mut no_announce_cfg = test_default_channel_config();
+       no_announce_cfg.channel_options.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);
+       let accept_channel = get_event_msg!(nodes[b], MessageSendEvent::SendAcceptChannel, nodes[a].node.get_our_node_id());
+       nodes[a].node.handle_accept_channel(&nodes[b].node.get_our_node_id(), b_flags, &accept_channel);
+
+       let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[a], channel_value, 42);
+       nodes[a].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
+       nodes[b].node.handle_funding_created(&nodes[a].node.get_our_node_id(), &get_event_msg!(nodes[a], MessageSendEvent::SendFundingCreated, nodes[b].node.get_our_node_id()));
+       check_added_monitors!(nodes[b], 1);
+
+       let cs_funding_signed = get_event_msg!(nodes[b], MessageSendEvent::SendFundingSigned, nodes[a].node.get_our_node_id());
+       nodes[a].node.handle_funding_signed(&nodes[b].node.get_our_node_id(), &cs_funding_signed);
+       check_added_monitors!(nodes[a], 1);
+
+       let conf_height = core::cmp::max(nodes[a].best_block_info().1 + 1, nodes[b].best_block_info().1 + 1);
+       confirm_transaction_at(&nodes[a], &tx, conf_height);
+       connect_blocks(&nodes[a], CHAN_CONFIRM_DEPTH - 1);
+       confirm_transaction_at(&nodes[b], &tx, conf_height);
+       connect_blocks(&nodes[b], CHAN_CONFIRM_DEPTH - 1);
+       let as_funding_locked = get_event_msg!(nodes[a], MessageSendEvent::SendFundingLocked, nodes[b].node.get_our_node_id());
+       nodes[a].node.handle_funding_locked(&nodes[b].node.get_our_node_id(), &get_event_msg!(nodes[b], MessageSendEvent::SendFundingLocked, nodes[a].node.get_our_node_id()));
+       let as_update = get_event_msg!(nodes[a], MessageSendEvent::SendChannelUpdate, nodes[b].node.get_our_node_id());
+       nodes[b].node.handle_funding_locked(&nodes[a].node.get_our_node_id(), &as_funding_locked);
+       let bs_update = get_event_msg!(nodes[b], MessageSendEvent::SendChannelUpdate, nodes[a].node.get_our_node_id());
+
+       nodes[a].node.handle_channel_update(&nodes[b].node.get_our_node_id(), &bs_update);
+       nodes[b].node.handle_channel_update(&nodes[a].node.get_our_node_id(), &as_update);
+
+       let mut found_a = false;
+       for chan in nodes[a].node.list_usable_channels() {
+               if chan.channel_id == as_funding_locked.channel_id {
+                       assert!(!found_a);
+                       found_a = true;
+                       assert!(!chan.is_public);
+               }
+       }
+       assert!(found_a);
+
+       let mut found_b = false;
+       for chan in nodes[b].node.list_usable_channels() {
+               if chan.channel_id == as_funding_locked.channel_id {
+                       assert!(!found_b);
+                       found_b = true;
+                       assert!(!chan.is_public);
+               }
+       }
+       assert!(found_b);
+
+       (as_funding_locked, tx)
+}
+
 pub fn update_nodes_with_chan_announce<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize, ann: &msgs::ChannelAnnouncement, upd_1: &msgs::ChannelUpdate, upd_2: &msgs::ChannelUpdate) {
        nodes[a].node.broadcast_node_announcement([0, 0, 0], [0; 32], Vec::new());
        let a_events = nodes[a].node.get_and_clear_pending_msg_events();
@@ -735,6 +803,11 @@ pub fn update_nodes_with_chan_announce<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, '
                node.net_graph_msg_handler.handle_channel_update(upd_2).unwrap();
                node.net_graph_msg_handler.handle_node_announcement(&a_node_announcement).unwrap();
                node.net_graph_msg_handler.handle_node_announcement(&b_node_announcement).unwrap();
+
+               // Note that channel_updates are also delivered to ChannelManagers to ensure we have
+               // forwarding info for local channels even if its not accepted in the network graph.
+               node.node.handle_channel_update(&nodes[a].node.get_our_node_id(), &upd_1);
+               node.node.handle_channel_update(&nodes[b].node.get_our_node_id(), &upd_2);
        }
 }
 
@@ -1081,15 +1154,18 @@ macro_rules! get_route_and_payment_hash {
                $crate::get_route_and_payment_hash!($send_node, $recv_node, vec![], $recv_value, TEST_FINAL_CLTV)
        }};
        ($send_node: expr, $recv_node: expr, $last_hops: expr, $recv_value: expr, $cltv: expr) => {{
+               use $crate::chain::keysinterface::KeysInterface;
                let (payment_preimage, payment_hash, payment_secret) = $crate::get_payment_preimage_hash!($recv_node, Some($recv_value));
                let payment_params = $crate::routing::router::PaymentParameters::from_node_id($recv_node.node.get_our_node_id())
                        .with_features($crate::ln::features::InvoiceFeatures::known())
                        .with_route_hints($last_hops);
                let scorer = $crate::util::test_utils::TestScorer::with_penalty(0);
+               let keys_manager = $crate::util::test_utils::TestKeysInterface::new(&[0u8; 32], bitcoin::network::constants::Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let route = $crate::routing::router::get_route(
-                       &$send_node.node.get_our_node_id(), &payment_params, $send_node.network_graph,
+                       &$send_node.node.get_our_node_id(), &payment_params, &$send_node.network_graph.read_only(),
                        Some(&$send_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
-                       $recv_value, $cltv, $send_node.logger, &scorer
+                       $recv_value, $cltv, $send_node.logger, &scorer, &random_seed_bytes
                ).unwrap();
                (route, payment_hash, payment_preimage, payment_secret)
        }}
@@ -1544,11 +1620,15 @@ pub const TEST_FINAL_CLTV: u32 = 70;
 pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) -> (PaymentPreimage, PaymentHash, PaymentSecret) {
        let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id())
                .with_features(InvoiceFeatures::known());
+       let network_graph = origin_node.network_graph.read_only();
        let scorer = test_utils::TestScorer::with_penalty(0);
+       let seed = [0u8; 32];
+       let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
+       let random_seed_bytes = keys_manager.get_secure_random_bytes();
        let route = get_route(
-               &origin_node.node.get_our_node_id(), &payment_params, &origin_node.network_graph,
+               &origin_node.node.get_our_node_id(), &payment_params, &network_graph,
                Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
-               recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer).unwrap();
+               recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
        assert_eq!(route.paths.len(), 1);
        assert_eq!(route.paths[0].len(), expected_route.len());
        for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
@@ -1562,10 +1642,14 @@ pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route:
 pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64)  {
        let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id())
                .with_features(InvoiceFeatures::known());
+       let network_graph = origin_node.network_graph.read_only();
        let scorer = test_utils::TestScorer::with_penalty(0);
+       let seed = [0u8; 32];
+       let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
+       let random_seed_bytes = keys_manager.get_secure_random_bytes();
        let route = get_route(
-               &origin_node.node.get_our_node_id(), &payment_params, origin_node.network_graph,
-               None, recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer).unwrap();
+               &origin_node.node.get_our_node_id(), &payment_params, &network_graph,
+               None, recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
        assert_eq!(route.paths.len(), 1);
        assert_eq!(route.paths[0].len(), expected_route.len());
        for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
index 3c7174a9d71a63a8f74116229ee46f6da5f42f4a..1f64ef0a920efc27a644fb69ee5aacb7e87e45fe 100644 (file)
@@ -16,15 +16,14 @@ use chain::{Confirm, Listen, Watch};
 use chain::channelmonitor;
 use chain::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
 use chain::transaction::OutPoint;
-use chain::keysinterface::BaseSign;
+use chain::keysinterface::{BaseSign, KeysInterface};
 use ln::{PaymentPreimage, PaymentSecret, PaymentHash};
 use ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT};
 use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, PaymentId, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, PAYMENT_EXPIRY_BLOCKS };
 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::network_graph::RoutingFees;
-use routing::router::{PaymentParameters, Route, RouteHop, RouteHint, RouteHintHop, RouteParameters, find_route, get_route};
+use routing::router::{PaymentParameters, Route, RouteHop, RouteParameters, find_route, get_route};
 use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
 use ln::msgs;
 use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, ErrorAction};
@@ -463,88 +462,6 @@ fn test_multi_flight_update_fee() {
        check_added_monitors!(nodes[1], 1);
 }
 
-fn do_test_1_conf_open(connect_style: ConnectStyle) {
-       // Previously, if the minium_depth config was set to 1, we'd never send a funding_locked. 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;
-       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;
-       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)]);
-       let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
-       *nodes[0].connect_style.borrow_mut() = connect_style;
-
-       let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::known(), InitFeatures::known());
-       mine_transaction(&nodes[1], &tx);
-       nodes[0].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingLocked, nodes[0].node.get_our_node_id()));
-       assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
-
-       mine_transaction(&nodes[0], &tx);
-       let as_msg_events = nodes[0].node.get_and_clear_pending_msg_events();
-       assert_eq!(as_msg_events.len(), 2);
-       let as_funding_locked = if let MessageSendEvent::SendFundingLocked { ref node_id, ref msg } = as_msg_events[0] {
-               assert_eq!(*node_id, nodes[1].node.get_our_node_id());
-               msg.clone()
-       } else { panic!("Unexpected event"); };
-       if let MessageSendEvent::SendChannelUpdate { ref node_id, msg: _ } = as_msg_events[1] {
-               assert_eq!(*node_id, nodes[1].node.get_our_node_id());
-       } else { panic!("Unexpected event"); }
-
-       nodes[1].node.handle_funding_locked(&nodes[0].node.get_our_node_id(), &as_funding_locked);
-       let bs_msg_events = nodes[1].node.get_and_clear_pending_msg_events();
-       assert_eq!(bs_msg_events.len(), 1);
-       if let MessageSendEvent::SendChannelUpdate { ref node_id, msg: _ } = bs_msg_events[0] {
-               assert_eq!(*node_id, nodes[0].node.get_our_node_id());
-       } else { panic!("Unexpected event"); }
-
-       send_payment(&nodes[0], &[&nodes[1]], 100_000);
-
-       // After 6 confirmations, as required by the spec, we'll send announcement_signatures and
-       // broadcast the channel_announcement (but not before exactly 6 confirmations).
-       connect_blocks(&nodes[0], 4);
-       assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
-       connect_blocks(&nodes[0], 1);
-       nodes[1].node.handle_announcement_signatures(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendAnnouncementSignatures, nodes[1].node.get_our_node_id()));
-       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
-
-       connect_blocks(&nodes[1], 5);
-       let bs_announce_events = nodes[1].node.get_and_clear_pending_msg_events();
-       assert_eq!(bs_announce_events.len(), 2);
-       let bs_announcement_sigs = if let MessageSendEvent::SendAnnouncementSignatures { ref node_id, ref msg } = bs_announce_events[0] {
-               assert_eq!(*node_id, nodes[0].node.get_our_node_id());
-               msg.clone()
-       } else { panic!("Unexpected event"); };
-       let (bs_announcement, bs_update) = if let MessageSendEvent::BroadcastChannelAnnouncement { ref msg, ref update_msg } = bs_announce_events[1] {
-               (msg.clone(), update_msg.clone())
-       } else { panic!("Unexpected event"); };
-
-       nodes[0].node.handle_announcement_signatures(&nodes[1].node.get_our_node_id(), &bs_announcement_sigs);
-       let as_announce_events = nodes[0].node.get_and_clear_pending_msg_events();
-       assert_eq!(as_announce_events.len(), 1);
-       let (announcement, as_update) = if let MessageSendEvent::BroadcastChannelAnnouncement { ref msg, ref update_msg } = as_announce_events[0] {
-               (msg.clone(), update_msg.clone())
-       } else { panic!("Unexpected event"); };
-       assert_eq!(announcement, bs_announcement);
-
-       for node in nodes {
-               assert!(node.net_graph_msg_handler.handle_channel_announcement(&announcement).unwrap());
-               node.net_graph_msg_handler.handle_channel_update(&as_update).unwrap();
-               node.net_graph_msg_handler.handle_channel_update(&bs_update).unwrap();
-       }
-}
-#[test]
-fn test_1_conf_open() {
-       do_test_1_conf_open(ConnectStyle::BestBlockFirst);
-       do_test_1_conf_open(ConnectStyle::TransactionsFirst);
-       do_test_1_conf_open(ConnectStyle::FullBlockViaListen);
-}
-
 fn do_test_sanity_on_in_flight_opens(steps: u8) {
        // Previously, we had issues deserializing channels when we hadn't connected the first block
        // after creation. To catch that and similar issues, we lean on the Node::drop impl to test
@@ -5999,9 +5916,9 @@ fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on i
        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);
-       //Force duplicate channel ids
+       // Force duplicate randomness for every get-random call
        for node in nodes.iter() {
-               *node.keys_manager.override_channel_id_priv.lock().unwrap() = Some([0; 32]);
+               *node.keys_manager.override_random_bytes.lock().unwrap() = Some([0; 32]);
        }
 
        // BOLT #2 spec: Sending node must ensure temporary_channel_id is unique from any other channel ID with the same peer.
@@ -6010,9 +5927,11 @@ fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on i
        nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).unwrap();
        let node0_to_1_send_open_channel = 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(), &node0_to_1_send_open_channel);
+       get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
 
-       //Create a second channel with a channel_id collision
-       assert!(nodes[0].node.create_channel(nodes[0].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).is_err());
+       // Create a second channel with the same random values. This used to panic due to a colliding
+       // channel_id, but now panics due to a colliding outbound SCID alias.
+       assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).is_err());
 }
 
 #[test]
@@ -7261,7 +7180,10 @@ fn test_user_configurable_csv_delay() {
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        // We test config.our_to_self > BREAKDOWN_TIMEOUT is enforced in Channel::new_outbound()
-       if let Err(error) = Channel::new_outbound(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), 1000000, 1000000, 0, &low_our_to_self_config, 0) {
+       if let Err(error) = Channel::new_outbound(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) },
+               &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), 1000000, 1000000, 0,
+               &low_our_to_self_config, 0, 42)
+       {
                match error {
                        APIError::APIMisuseError { err } => { assert!(regex::Regex::new(r"Configured with an unreasonable our_to_self_delay \(\d+\) putting user funds at risks").unwrap().is_match(err.as_str())); },
                        _ => panic!("Unexpected event"),
@@ -7272,7 +7194,10 @@ fn test_user_configurable_csv_delay() {
        nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
        let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
        open_channel.to_self_delay = 200;
-       if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0, &low_our_to_self_config, 0, &nodes[0].logger) {
+       if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) },
+               &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0,
+               &low_our_to_self_config, 0, &nodes[0].logger, 42)
+       {
                match error {
                        ChannelError::Close(err) => { assert!(regex::Regex::new(r"Configured with an unreasonable our_to_self_delay \(\d+\) putting user funds at risks").unwrap().is_match(err.as_str()));  },
                        _ => panic!("Unexpected event"),
@@ -7301,7 +7226,10 @@ fn test_user_configurable_csv_delay() {
        nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
        let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
        open_channel.to_self_delay = 200;
-       if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0, &high_their_to_self_config, 0, &nodes[0].logger) {
+       if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) },
+               &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0,
+               &high_their_to_self_config, 0, &nodes[0].logger, 42)
+       {
                match error {
                        ChannelError::Close(err) => { assert!(regex::Regex::new(r"They wanted our payments to be delayed by a needlessly long period\. Upper limit: \d+\. Actual: \d+").unwrap().is_match(err.as_str())); },
                        _ => panic!("Unexpected event"),
@@ -7440,8 +7368,9 @@ fn test_check_htlc_underpaying() {
        create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
 
        let scorer = test_utils::TestScorer::with_penalty(0);
+       let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
        let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(InvoiceFeatures::known());
-       let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, nodes[0].network_graph, None, 10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer).unwrap();
+       let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None, 10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
        let (_, our_payment_hash, _) = get_payment_preimage_hash!(nodes[0]);
        let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200).unwrap();
        nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
@@ -7568,162 +7497,6 @@ fn test_announce_disable_channels() {
        assert!(chans_disabled.is_empty());
 }
 
-#[test]
-fn test_priv_forwarding_rejection() {
-       // If we have a private channel with outbound liquidity, and
-       // UserConfig::accept_forwards_to_priv_channels is set to false, we should reject any attempts
-       // to forward through that channel.
-       let chanmon_cfgs = create_chanmon_cfgs(3);
-       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
-       let mut no_announce_cfg = test_default_channel_config();
-       no_announce_cfg.channel_options.announced_channel = false;
-       no_announce_cfg.accept_forwards_to_priv_channels = false;
-       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(no_announce_cfg), None]);
-       let persister: test_utils::TestPersister;
-       let new_chain_monitor: test_utils::TestChainMonitor;
-       let nodes_1_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
-       let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
-
-       let chan_id_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).2;
-
-       // Note that the create_*_chan functions in utils requires announcement_signatures, which we do
-       // not send for private channels.
-       nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None).unwrap();
-       let open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[2].node.get_our_node_id());
-       nodes[2].node.handle_open_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &open_channel);
-       let accept_channel = get_event_msg!(nodes[2], MessageSendEvent::SendAcceptChannel, nodes[1].node.get_our_node_id());
-       nodes[1].node.handle_accept_channel(&nodes[2].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
-
-       let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[1], 1_000_000, 42);
-       nodes[1].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
-       nodes[2].node.handle_funding_created(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingCreated, nodes[2].node.get_our_node_id()));
-       check_added_monitors!(nodes[2], 1);
-
-       let cs_funding_signed = get_event_msg!(nodes[2], MessageSendEvent::SendFundingSigned, nodes[1].node.get_our_node_id());
-       nodes[1].node.handle_funding_signed(&nodes[2].node.get_our_node_id(), &cs_funding_signed);
-       check_added_monitors!(nodes[1], 1);
-
-       let conf_height = core::cmp::max(nodes[1].best_block_info().1 + 1, nodes[2].best_block_info().1 + 1);
-       confirm_transaction_at(&nodes[1], &tx, conf_height);
-       connect_blocks(&nodes[1], CHAN_CONFIRM_DEPTH - 1);
-       confirm_transaction_at(&nodes[2], &tx, conf_height);
-       connect_blocks(&nodes[2], CHAN_CONFIRM_DEPTH - 1);
-       let as_funding_locked = get_event_msg!(nodes[1], MessageSendEvent::SendFundingLocked, nodes[2].node.get_our_node_id());
-       nodes[1].node.handle_funding_locked(&nodes[2].node.get_our_node_id(), &get_event_msg!(nodes[2], MessageSendEvent::SendFundingLocked, nodes[1].node.get_our_node_id()));
-       get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[2].node.get_our_node_id());
-       nodes[2].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &as_funding_locked);
-       get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
-
-       assert!(nodes[0].node.list_usable_channels()[0].is_public);
-       assert_eq!(nodes[1].node.list_usable_channels().len(), 2);
-       assert!(!nodes[2].node.list_usable_channels()[0].is_public);
-
-       // We should always be able to forward through nodes[1] as long as its out through a public
-       // channel:
-       send_payment(&nodes[2], &[&nodes[1], &nodes[0]], 10_000);
-
-       // ... however, if we send to nodes[2], we will have to pass the private channel from nodes[1]
-       // to nodes[2], which should be rejected:
-       let route_hint = RouteHint(vec![RouteHintHop {
-               src_node_id: nodes[1].node.get_our_node_id(),
-               short_channel_id: nodes[2].node.list_channels()[0].short_channel_id.unwrap(),
-               fees: RoutingFees { base_msat: 1000, proportional_millionths: 0 },
-               cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
-               htlc_minimum_msat: None,
-               htlc_maximum_msat: None,
-       }]);
-       let last_hops = vec![route_hint];
-       let (route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], last_hops, 10_000, TEST_FINAL_CLTV);
-
-       nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
-       check_added_monitors!(nodes[0], 1);
-       let payment_event = SendEvent::from_event(nodes[0].node.get_and_clear_pending_msg_events().remove(0));
-       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
-       commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false, true);
-
-       let htlc_fail_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
-       assert!(htlc_fail_updates.update_add_htlcs.is_empty());
-       assert_eq!(htlc_fail_updates.update_fail_htlcs.len(), 1);
-       assert!(htlc_fail_updates.update_fail_malformed_htlcs.is_empty());
-       assert!(htlc_fail_updates.update_fee.is_none());
-
-       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_fail_updates.update_fail_htlcs[0]);
-       commitment_signed_dance!(nodes[0], nodes[1], htlc_fail_updates.commitment_signed, true, true);
-       expect_payment_failed_with_update!(nodes[0], our_payment_hash, false, nodes[2].node.list_channels()[0].short_channel_id.unwrap(), true);
-
-       // Now disconnect nodes[1] from its peers and restart with accept_forwards_to_priv_channels set
-       // to true. Sadly there is currently no way to change it at runtime.
-
-       nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
-       nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
-
-       let nodes_1_serialized = nodes[1].node.encode();
-       let mut monitor_a_serialized = test_utils::TestVecWriter(Vec::new());
-       let mut monitor_b_serialized = test_utils::TestVecWriter(Vec::new());
-       get_monitor!(nodes[1], chan_id_1).write(&mut monitor_a_serialized).unwrap();
-       get_monitor!(nodes[1], cs_funding_signed.channel_id).write(&mut monitor_b_serialized).unwrap();
-
-       persister = test_utils::TestPersister::new();
-       let keys_manager = &chanmon_cfgs[1].keys_manager;
-       new_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, keys_manager);
-       nodes[1].chain_monitor = &new_chain_monitor;
-
-       let mut monitor_a_read = &monitor_a_serialized.0[..];
-       let mut monitor_b_read = &monitor_b_serialized.0[..];
-       let (_, mut monitor_a) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut monitor_a_read, keys_manager).unwrap();
-       let (_, mut monitor_b) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut monitor_b_read, keys_manager).unwrap();
-       assert!(monitor_a_read.is_empty());
-       assert!(monitor_b_read.is_empty());
-
-       no_announce_cfg.accept_forwards_to_priv_channels = true;
-
-       let mut nodes_1_read = &nodes_1_serialized[..];
-       let (_, nodes_1_deserialized_tmp) = {
-               let mut channel_monitors = HashMap::new();
-               channel_monitors.insert(monitor_a.get_funding_txo().0, &mut monitor_a);
-               channel_monitors.insert(monitor_b.get_funding_txo().0, &mut monitor_b);
-               <(BlockHash, ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut nodes_1_read, ChannelManagerReadArgs {
-                       default_config: no_announce_cfg,
-                       keys_manager,
-                       fee_estimator: node_cfgs[1].fee_estimator,
-                       chain_monitor: nodes[1].chain_monitor,
-                       tx_broadcaster: nodes[1].tx_broadcaster.clone(),
-                       logger: nodes[1].logger,
-                       channel_monitors,
-               }).unwrap()
-       };
-       assert!(nodes_1_read.is_empty());
-       nodes_1_deserialized = nodes_1_deserialized_tmp;
-
-       assert!(nodes[1].chain_monitor.watch_channel(monitor_a.get_funding_txo().0, monitor_a).is_ok());
-       assert!(nodes[1].chain_monitor.watch_channel(monitor_b.get_funding_txo().0, monitor_b).is_ok());
-       check_added_monitors!(nodes[1], 2);
-       nodes[1].node = &nodes_1_deserialized;
-
-       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() });
-       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
-       let as_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
-       let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
-       nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_reestablish);
-       nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
-       get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
-       get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id());
-
-       nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() });
-       nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
-       let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[2].node.get_our_node_id());
-       let cs_reestablish = get_event_msg!(nodes[2], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
-       nodes[2].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
-       nodes[1].node.handle_channel_reestablish(&nodes[2].node.get_our_node_id(), &cs_reestablish);
-       get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[2].node.get_our_node_id());
-       get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
-
-       nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
-       check_added_monitors!(nodes[0], 1);
-       pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], 10_000, our_payment_hash, our_payment_secret);
-       claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], our_payment_preimage);
-}
-
 #[test]
 fn test_bump_penalty_txn_on_revoked_commitment() {
        // In case of penalty txn with too low feerates for getting into mempools, RBF-bump them to be sure
@@ -7843,12 +7616,13 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
        // Lock HTLC in both directions (using a slightly lower CLTV delay to provide timely RBF bumps)
        let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(InvoiceFeatures::known());
        let scorer = test_utils::TestScorer::with_penalty(0);
-       let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph, None,
-               3_000_000, 50, nodes[0].logger, &scorer).unwrap();
+       let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
+       let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None,
+               3_000_000, 50, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
        let payment_preimage = send_along_route(&nodes[0], route, &[&nodes[1]], 3_000_000).0;
        let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id()).with_features(InvoiceFeatures::known());
-       let route = get_route(&nodes[1].node.get_our_node_id(), &payment_params, nodes[1].network_graph, None,
-               3_000_000, 50, nodes[0].logger, &scorer).unwrap();
+       let route = get_route(&nodes[1].node.get_our_node_id(), &payment_params, &nodes[1].network_graph.read_only(), None,
+               3_000_000, 50, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
        send_along_route(&nodes[1], route, &[&nodes[0]], 3_000_000);
 
        let revoked_local_txn = get_local_commitment_txn!(nodes[1], chan.2);
@@ -9617,10 +9391,11 @@ fn test_dup_htlc_second_fail_panic() {
        let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
                .with_features(InvoiceFeatures::known());
        let scorer = test_utils::TestScorer::with_penalty(0);
+       let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
        let route = get_route(
-               &nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph,
+               &nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(),
                Some(&nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()),
-               10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer).unwrap();
+               10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
 
        let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(&nodes[1]);
 
@@ -9689,7 +9464,8 @@ fn test_keysend_payments_to_public_node() {
                final_cltv_expiry_delta: 40,
        };
        let scorer = test_utils::TestScorer::with_penalty(0);
-       let route = find_route(&payer_pubkey, &route_params, network_graph, None, nodes[0].logger, &scorer).unwrap();
+       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 test_preimage = PaymentPreimage([42; 32]);
        let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(test_preimage)).unwrap();
@@ -9723,9 +9499,10 @@ fn test_keysend_payments_to_private_node() {
        let network_graph = nodes[0].network_graph;
        let first_hops = nodes[0].node.list_usable_channels();
        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
+               nodes[0].logger, &scorer, &random_seed_bytes
        ).unwrap();
 
        let test_preimage = PaymentPreimage([42; 32]);
index 44704ae5040f44ee58e21b853be05a41252a1e2e..444c9685fdda6979708fdee6eb26797b0ddfe040 100644 (file)
@@ -54,6 +54,9 @@ mod functional_tests;
 mod payment_tests;
 #[cfg(test)]
 #[allow(unused_mut)]
+mod priv_short_conf_tests;
+#[cfg(test)]
+#[allow(unused_mut)]
 mod chanmon_update_fail_tests;
 #[cfg(test)]
 #[allow(unused_mut)]
index 2b582fe877bc663ea2df7677684b575a48b2edf2..6fa0aab9d311fb2ed5f9dff09ac3b487b2298051 100644 (file)
@@ -536,3 +536,193 @@ fn test_claim_value_force_close() {
        do_test_claim_value_force_close(true);
        do_test_claim_value_force_close(false);
 }
+
+#[test]
+fn test_balances_on_local_commitment_htlcs() {
+       // Previously, when handling the broadcast of a local commitment transactions (with associated
+       // CSV delays prior to spendability), we incorrectly handled the CSV delays on HTLC
+       // transactions. This caused us to miss spendable outputs for HTLCs which were awaiting a CSV
+       // delay prior to spendability.
+       //
+       // Further, because of this, we could hit an assertion as `get_claimable_balances` asserted
+       // that HTLCs were resolved after the funding spend was resolved, which was not true if the
+       // HTLC did not have a CSV delay attached (due to the above bug or due to it being an HTLC
+       // claim by our counterparty).
+       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 mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       // Create a single channel with two pending HTLCs from nodes[0] to nodes[1], one which nodes[1]
+       // knows the preimage for, one which it does not.
+       let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
+       let funding_outpoint = OutPoint { txid: funding_tx.txid(), index: 0 };
+
+       let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 10_000_000);
+       let htlc_cltv_timeout = nodes[0].best_block_info().1 + TEST_FINAL_CLTV + 1; // Note ChannelManager adds one to CLTV timeouts for safety
+       nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+
+       let updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &updates.update_add_htlcs[0]);
+       commitment_signed_dance!(nodes[1], nodes[0], updates.commitment_signed, false);
+
+       expect_pending_htlcs_forwardable!(nodes[1]);
+       expect_payment_received!(nodes[1], payment_hash, payment_secret, 10_000_000);
+
+       let (route_2, payment_hash_2, payment_preimage_2, payment_secret_2) = get_route_and_payment_hash!(nodes[0], nodes[1], 20_000_000);
+       nodes[0].node.send_payment(&route_2, payment_hash_2, &Some(payment_secret_2)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+
+       let updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &updates.update_add_htlcs[0]);
+       commitment_signed_dance!(nodes[1], nodes[0], updates.commitment_signed, false);
+
+       expect_pending_htlcs_forwardable!(nodes[1]);
+       expect_payment_received!(nodes[1], payment_hash_2, payment_secret_2, 20_000_000);
+       assert!(nodes[1].node.claim_funds(payment_preimage_2));
+       get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       check_added_monitors!(nodes[1], 1);
+
+       let chan_feerate = get_feerate!(nodes[0], chan_id) as u64;
+       let opt_anchors = get_opt_anchors!(nodes[0], chan_id);
+
+       // Get nodes[0]'s commitment transaction and HTLC-Timeout transactions
+       let as_txn = get_local_commitment_txn!(nodes[0], chan_id);
+       assert_eq!(as_txn.len(), 3);
+       check_spends!(as_txn[1], as_txn[0]);
+       check_spends!(as_txn[2], as_txn[0]);
+       check_spends!(as_txn[0], funding_tx);
+
+       // First confirm the commitment transaction on nodes[0], which should leave us with three
+       // claimable balances.
+       let node_a_commitment_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32;
+       mine_transaction(&nodes[0], &as_txn[0]);
+       check_added_monitors!(nodes[0], 1);
+       check_closed_broadcast!(nodes[0], true);
+       check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
+
+       assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
+                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       confirmation_height: node_a_commitment_claimable,
+               }, Balance::MaybeClaimableHTLCAwaitingTimeout {
+                       claimable_amount_satoshis: 10_000,
+                       claimable_height: htlc_cltv_timeout,
+               }, Balance::MaybeClaimableHTLCAwaitingTimeout {
+                       claimable_amount_satoshis: 20_000,
+                       claimable_height: htlc_cltv_timeout,
+               }]),
+               sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
+
+       // Get nodes[1]'s HTLC claim tx for the second HTLC
+       mine_transaction(&nodes[1], &as_txn[0]);
+       check_added_monitors!(nodes[1], 1);
+       check_closed_broadcast!(nodes[1], true);
+       check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
+       let bs_htlc_claim_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+       assert_eq!(bs_htlc_claim_txn.len(), 3);
+       check_spends!(bs_htlc_claim_txn[0], as_txn[0]);
+       check_spends!(bs_htlc_claim_txn[1], funding_tx);
+       check_spends!(bs_htlc_claim_txn[2], bs_htlc_claim_txn[1]);
+
+       // Connect blocks until the HTLCs expire, allowing us to (validly) broadcast the HTLC-Timeout
+       // transaction.
+       connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1);
+       assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
+                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       confirmation_height: node_a_commitment_claimable,
+               }, Balance::MaybeClaimableHTLCAwaitingTimeout {
+                       claimable_amount_satoshis: 10_000,
+                       claimable_height: htlc_cltv_timeout,
+               }, Balance::MaybeClaimableHTLCAwaitingTimeout {
+                       claimable_amount_satoshis: 20_000,
+                       claimable_height: htlc_cltv_timeout,
+               }]),
+               sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
+       assert_eq!(as_txn[1].lock_time, nodes[0].best_block_info().1 + 1); // as_txn[1] can be included in the next block
+
+       // Now confirm nodes[0]'s HTLC-Timeout transaction, which changes the claimable balance to an
+       // "awaiting confirmations" one.
+       let node_a_htlc_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32;
+       mine_transaction(&nodes[0], &as_txn[1]);
+       // Note that prior to the fix in the commit which introduced this test, this (and the next
+       // balance) check failed. With this check removed, the code panicked in the `connect_blocks`
+       // call, as described, two hunks down.
+       assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
+                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       confirmation_height: node_a_commitment_claimable,
+               }, Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 10_000,
+                       confirmation_height: node_a_htlc_claimable,
+               }, Balance::MaybeClaimableHTLCAwaitingTimeout {
+                       claimable_amount_satoshis: 20_000,
+                       claimable_height: htlc_cltv_timeout,
+               }]),
+               sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
+
+       // Now confirm nodes[1]'s HTLC claim, giving nodes[0] the preimage. Note that the "maybe
+       // claimable" balance remains until we see ANTI_REORG_DELAY blocks.
+       mine_transaction(&nodes[0], &bs_htlc_claim_txn[0]);
+       expect_payment_sent!(nodes[0], payment_preimage_2);
+       assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
+                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       confirmation_height: node_a_commitment_claimable,
+               }, Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 10_000,
+                       confirmation_height: node_a_htlc_claimable,
+               }, Balance::MaybeClaimableHTLCAwaitingTimeout {
+                       claimable_amount_satoshis: 20_000,
+                       claimable_height: htlc_cltv_timeout,
+               }]),
+               sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
+
+       // Finally make the HTLC transactions have ANTI_REORG_DELAY blocks. This call previously
+       // panicked as described in the test introduction. This will remove the "maybe claimable"
+       // spendable output as nodes[1] has fully claimed the second HTLC.
+       connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
+       expect_payment_failed!(nodes[0], payment_hash, true);
+
+       assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
+                               (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       confirmation_height: node_a_commitment_claimable,
+               }, Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 10_000,
+                       confirmation_height: node_a_htlc_claimable,
+               }]),
+               sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
+
+       // Connect blocks until the commitment transaction's CSV expires, providing us the relevant
+       // `SpendableOutputs` event and removing the claimable balance entry.
+       connect_blocks(&nodes[0], node_a_commitment_claimable - nodes[0].best_block_info().1);
+       assert_eq!(vec![Balance::ClaimableAwaitingConfirmations {
+                       claimable_amount_satoshis: 10_000,
+                       confirmation_height: node_a_htlc_claimable,
+               }],
+               nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
+       let mut node_a_spendable = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
+       assert_eq!(node_a_spendable.len(), 1);
+       if let Event::SpendableOutputs { outputs } = node_a_spendable.pop().unwrap() {
+               assert_eq!(outputs.len(), 1);
+               let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
+                       Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
+               check_spends!(spend_tx, as_txn[0]);
+       }
+
+       // Connect blocks until the HTLC-Timeout's CSV expires, providing us the relevant
+       // `SpendableOutputs` event and removing the claimable balance entry.
+       connect_blocks(&nodes[0], node_a_htlc_claimable - nodes[0].best_block_info().1);
+       assert!(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances().is_empty());
+       let mut node_a_spendable = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
+       assert_eq!(node_a_spendable.len(), 1);
+       if let Event::SpendableOutputs { outputs } = node_a_spendable.pop().unwrap() {
+               assert_eq!(outputs.len(), 1);
+               let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
+                       Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
+               check_spends!(spend_tx, as_txn[1]);
+       }
+}
index ffca10dbb6de009ed2b5bfa53f1a88f2324ce453..fab396e3c7112af934021041abfcf2e1f4d609af 100644 (file)
@@ -241,6 +241,9 @@ pub struct FundingLocked {
        pub channel_id: [u8; 32],
        /// The per-commitment point of the second commitment transaction
        pub next_per_commitment_point: PublicKey,
+       /// If set, provides a short_channel_id alias for this channel. The sender will accept payments
+       /// to be forwarded over this SCID and forward them to this messages' recipient.
+       pub short_channel_id_alias: Option<u64>,
 }
 
 /// A shutdown message to be sent or received from a peer
@@ -1155,7 +1158,9 @@ impl_writeable_msg!(FundingSigned, {
 impl_writeable_msg!(FundingLocked, {
        channel_id,
        next_per_commitment_point,
-}, {});
+}, {
+       (1, short_channel_id_alias, option),
+});
 
 impl Writeable for Init {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
@@ -1299,10 +1304,6 @@ impl Readable for FinalOnionHopData {
 
 impl Writeable for OnionHopData {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               // Note that this should never be reachable if Rust-Lightning generated the message, as we
-               // check values are sane long before we get here, though its possible in the future
-               // user-generated messages may hit this.
-               if self.amt_to_forward > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
                match self.format {
                        OnionHopDataFormat::Legacy { short_channel_id } => {
                                0u8.write(w)?;
@@ -1319,9 +1320,6 @@ impl Writeable for OnionHopData {
                                });
                        },
                        OnionHopDataFormat::FinalNode { ref payment_data, ref keysend_preimage } => {
-                               if let Some(final_data) = payment_data {
-                                       if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
-                               }
                                encode_varint_length_prefixed_tlv!(w, {
                                        (2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required),
                                        (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required),
@@ -2253,6 +2251,7 @@ mod tests {
                let funding_locked = msgs::FundingLocked {
                        channel_id: [2; 32],
                        next_per_commitment_point: pubkey_1,
+                       short_channel_id_alias: None,
                };
                let encoded_value = funding_locked.encode();
                let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f").unwrap();
index 4feae104d759a11fb47ee0b21b1f8f4be20b2311..070d88dda9a3432f9eb4672a369ff2fcc774c652 100644 (file)
 //! returned errors decode to the correct thing.
 
 use chain::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};
+use ln::channelmanager::{HTLCForwardInfo, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
 use ln::onion_utils;
-use routing::network_graph::NetworkUpdate;
-use routing::router::Route;
-use ln::features::InitFeatures;
+use routing::network_graph::{NetworkUpdate, RoutingFees};
+use routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop};
+use ln::features::{InitFeatures, InvoiceFeatures};
 use ln::msgs;
 use ln::msgs::{ChannelMessageHandler, ChannelUpdate, OptionalField};
 use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
 use util::ser::{Writeable, Writer};
+use util::{byte_utils, test_utils};
 use util::config::UserConfig;
 
 use bitcoin::hash_types::BlockHash;
 
 use bitcoin::hashes::Hash;
+use bitcoin::hashes::sha256::Hash as Sha256;
 
 use bitcoin::secp256k1;
 use bitcoin::secp256k1::Secp256k1;
-use bitcoin::secp256k1::key::SecretKey;
+use bitcoin::secp256k1::key::{PublicKey, SecretKey};
 
 use io;
 use prelude::*;
@@ -316,10 +319,10 @@ fn test_onion_failure() {
        let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config), Some(config), Some(node_2_cfg)]);
        let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+       let channels = [create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()), create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known())];
        for node in nodes.iter() {
-               *node.keys_manager.override_session_priv.lock().unwrap() = Some([3; 32]);
+               *node.keys_manager.override_random_bytes.lock().unwrap() = Some([3; 32]);
        }
-       let channels = [create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()), create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known())];
        let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 40000);
        // positive case
        send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 40000);
@@ -573,3 +576,421 @@ fn test_onion_failure() {
                nodes[2].node.fail_htlc_backwards(&payment_hash);
        }, true, Some(23), None, None);
 }
+
+macro_rules! get_phantom_route {
+       ($nodes: expr, $amt: expr, $channel: expr) => {{
+               let secp_ctx = Secp256k1::new();
+               let phantom_secret = $nodes[1].keys_manager.get_node_secret(Recipient::PhantomNode).unwrap();
+               let phantom_pubkey = PublicKey::from_secret_key(&secp_ctx, &phantom_secret);
+               let phantom_route_hint = $nodes[1].node.get_phantom_route_hints();
+               let payment_params = PaymentParameters::from_node_id(phantom_pubkey)
+                       .with_features(InvoiceFeatures::known())
+                       .with_route_hints(vec![RouteHint(vec![
+                                       RouteHintHop {
+                                               src_node_id: $nodes[0].node.get_our_node_id(),
+                                               short_channel_id: $channel.0.contents.short_channel_id,
+                                               fees: RoutingFees {
+                                                       base_msat: $channel.0.contents.fee_base_msat,
+                                                       proportional_millionths: $channel.0.contents.fee_proportional_millionths,
+                                               },
+                                               cltv_expiry_delta: $channel.0.contents.cltv_expiry_delta,
+                                               htlc_minimum_msat: None,
+                                               htlc_maximum_msat: None,
+                                       },
+                                       RouteHintHop {
+                                               src_node_id: phantom_route_hint.real_node_pubkey,
+                                               short_channel_id: phantom_route_hint.phantom_scid,
+                                               fees: RoutingFees {
+                                                       base_msat: 0,
+                                                       proportional_millionths: 0,
+                                               },
+                                               cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
+                                               htlc_minimum_msat: None,
+                                               htlc_maximum_msat: None,
+                                       }
+               ])]);
+               let scorer = test_utils::TestScorer::with_penalty(0);
+               let network_graph = $nodes[0].network_graph.read_only();
+               (get_route(
+                       &$nodes[0].node.get_our_node_id(), &payment_params, &network_graph,
+                       Some(&$nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()),
+                       $amt, TEST_FINAL_CLTV, $nodes[0].logger, &scorer, &[0u8; 32]
+               ).unwrap(), phantom_route_hint.phantom_scid)
+       }
+}}
+
+#[test]
+fn test_phantom_onion_hmac_failure() {
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+
+       // Get the route.
+       let recv_value_msat = 10_000;
+       let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_value_msat));
+       let (route, phantom_scid) = get_phantom_route!(nodes, recv_value_msat, channel);
+
+       // Route the HTLC through to the destination.
+       nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       let mut update_add = update_0.update_add_htlcs[0].clone();
+
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add);
+       commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
+
+       // Modify the payload so the phantom hop's HMAC is bogus.
+       let sha256_of_onion = {
+               let mut channel_state = nodes[1].node.channel_state.lock().unwrap();
+               let mut pending_forward = channel_state.forward_htlcs.get_mut(&phantom_scid).unwrap();
+               match pending_forward[0] {
+                       HTLCForwardInfo::AddHTLC {
+                               forward_info: PendingHTLCInfo {
+                                       routing: PendingHTLCRouting::Forward { ref mut onion_packet, .. },
+                                       ..
+                               }, ..
+                       } => {
+                               onion_packet.hmac[onion_packet.hmac.len() - 1] ^= 1;
+                               Sha256::hash(&onion_packet.hop_data).into_inner().to_vec()
+                       },
+                       _ => panic!("Unexpected forward"),
+               }
+       };
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       check_added_monitors!(&nodes[1], 1);
+       assert!(update_1.update_fail_htlcs.len() == 1);
+       let fail_msg = update_1.update_fail_htlcs[0].clone();
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
+       commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
+
+       // Ensure the payment fails with the expected error.
+       let mut fail_conditions = PaymentFailedConditions::new()
+               .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);
+}
+
+#[test]
+fn test_phantom_invalid_onion_payload() {
+       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 mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+
+       // Get the route.
+       let recv_value_msat = 10_000;
+       let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_value_msat));
+       let (route, phantom_scid) = get_phantom_route!(nodes, recv_value_msat, channel);
+
+       // We'll use the session priv later when constructing an invalid onion packet.
+       let session_priv = [3; 32];
+       *nodes[0].keys_manager.override_random_bytes.lock().unwrap() = Some(session_priv);
+       nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       let mut update_add = update_0.update_add_htlcs[0].clone();
+
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add);
+       commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
+
+       // Modify the onion packet to have an invalid payment amount.
+       for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() {
+               for f in pending_forwards.iter_mut() {
+                       match f {
+                               &mut HTLCForwardInfo::AddHTLC {
+                                       forward_info: PendingHTLCInfo {
+                                               routing: PendingHTLCRouting::Forward { ref mut onion_packet, .. },
+                                               ..
+                                       }, ..
+                               } => {
+                                       // Construct the onion payloads for the entire route and an invalid amount.
+                                       let height = nodes[0].best_block_info().1;
+                                       let session_priv = SecretKey::from_slice(&session_priv).unwrap();
+                                       let mut onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
+                                       let (mut onion_payloads, _, _) = onion_utils::build_onion_payloads(&route.paths[0], msgs::MAX_VALUE_MSAT + 1, &Some(payment_secret), height + 1, &None).unwrap();
+                                       // We only want to construct the onion packet for the last hop, not the entire route, so
+                                       // remove the first hop's payload and its keys.
+                                       onion_keys.remove(0);
+                                       onion_payloads.remove(0);
+
+                                       let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
+                                       onion_packet.hop_data = new_onion_packet.hop_data;
+                                       onion_packet.hmac = new_onion_packet.hmac;
+                               },
+                               _ => panic!("Unexpected forward"),
+                       }
+               }
+       }
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       check_added_monitors!(&nodes[1], 1);
+       assert!(update_1.update_fail_htlcs.len() == 1);
+       let fail_msg = update_1.update_fail_htlcs[0].clone();
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
+       commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
+
+       // Ensure the payment fails with the expected error.
+       let error_data = Vec::new();
+       let mut fail_conditions = PaymentFailedConditions::new()
+               .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);
+}
+
+#[test]
+fn test_phantom_final_incorrect_cltv_expiry() {
+       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 channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+
+       // Get the route.
+       let recv_value_msat = 10_000;
+       let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_value_msat));
+       let (route, phantom_scid) = get_phantom_route!(nodes, recv_value_msat, channel);
+
+       // Route the HTLC through to the destination.
+       nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       let mut update_add = update_0.update_add_htlcs[0].clone();
+
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add);
+       commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
+
+       // Modify the payload so the phantom hop's HMAC is bogus.
+       for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() {
+               for f in pending_forwards.iter_mut() {
+                       match f {
+                               &mut HTLCForwardInfo::AddHTLC {
+                                       forward_info: PendingHTLCInfo { ref mut outgoing_cltv_value, .. }, ..
+                               } => {
+                                       *outgoing_cltv_value += 1;
+                               },
+                               _ => panic!("Unexpected forward"),
+                       }
+               }
+       }
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       check_added_monitors!(&nodes[1], 1);
+       assert!(update_1.update_fail_htlcs.len() == 1);
+       let fail_msg = update_1.update_fail_htlcs[0].clone();
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
+       commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
+
+       // Ensure the payment fails with the expected error.
+       let expected_cltv = 82;
+       let error_data = byte_utils::be32_to_array(expected_cltv).to_vec();
+       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);
+}
+
+#[test]
+fn test_phantom_failure_too_low_cltv() {
+       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 channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+
+       // Get the route.
+       let recv_value_msat = 10_000;
+       let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_value_msat));
+       let (mut route, phantom_scid) = get_phantom_route!(nodes, recv_value_msat, channel);
+
+       // Modify the route to have a too-low cltv.
+       route.paths[0][1].cltv_expiry_delta = 5;
+
+       // Route the HTLC through to the destination.
+       nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       let mut update_add = update_0.update_add_htlcs[0].clone();
+
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add);
+       commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
+
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       check_added_monitors!(&nodes[1], 1);
+       assert!(update_1.update_fail_htlcs.len() == 1);
+       let fail_msg = update_1.update_fail_htlcs[0].clone();
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
+       commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
+
+       // Ensure the payment fails with the expected error.
+       let error_data = Vec::new();
+       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);
+}
+
+#[test]
+fn test_phantom_failure_too_low_recv_amt() {
+       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 channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+
+       // Get the route with a too-low amount.
+       let recv_amt_msat = 10_000;
+       let bad_recv_amt_msat = recv_amt_msat - 10;
+       let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_amt_msat));
+       let (mut route, phantom_scid) = get_phantom_route!(nodes, bad_recv_amt_msat, channel);
+
+       // Route the HTLC through to the destination.
+       nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       let mut update_add = update_0.update_add_htlcs[0].clone();
+
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add);
+       commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
+
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       check_added_monitors!(&nodes[1], 1);
+       assert!(update_1.update_fail_htlcs.len() == 1);
+       let fail_msg = update_1.update_fail_htlcs[0].clone();
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
+       commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
+
+       // Ensure the payment fails with the expected error.
+       let mut error_data = byte_utils::be64_to_array(bad_recv_amt_msat).to_vec();
+       error_data.extend_from_slice(
+               &byte_utils::be32_to_array(nodes[1].node.best_block.read().unwrap().height()),
+       );
+       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);
+}
+
+#[test]
+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;
+
+       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(receiver_config)]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+
+       // Get the route with an amount exceeding the dust exposure threshold of nodes[1].
+       let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(max_dust_exposure + 1));
+       let (mut route, _) = get_phantom_route!(nodes, max_dust_exposure + 1, channel);
+
+       // Route the HTLC through to the destination.
+       nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       let mut update_add = update_0.update_add_htlcs[0].clone();
+
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add);
+       commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
+
+       let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       assert!(update_1.update_fail_htlcs.len() == 1);
+       let fail_msg = update_1.update_fail_htlcs[0].clone();
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
+       commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
+
+       // Ensure the payment fails with the expected error.
+       let mut error_data = channel.1.encode_with_len();
+       let mut fail_conditions = PaymentFailedConditions::new()
+               .blamed_scid(channel.0.contents.short_channel_id)
+               .blamed_chan_closed(false)
+               .expected_htlc_error_data(0x1000 | 7, &error_data);
+               expect_payment_failed_conditions!(nodes[0], payment_hash, false, fail_conditions);
+}
+
+#[test]
+fn test_phantom_failure_reject_payment() {
+       // Test that the user can successfully fail back a phantom node payment.
+       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 channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+
+       // Get the route with a too-low amount.
+       let recv_amt_msat = 10_000;
+       let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_amt_msat));
+       let (mut route, phantom_scid) = get_phantom_route!(nodes, recv_amt_msat, channel);
+
+       // Route the HTLC through to the destination.
+       nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+       let mut update_add = update_0.update_add_htlcs[0].clone();
+
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add);
+       commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
+
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+       expect_payment_received!(nodes[1], payment_hash, payment_secret, recv_amt_msat);
+       assert!(nodes[1].node.fail_htlc_backwards(&payment_hash));
+       expect_pending_htlcs_forwardable_ignore!(nodes[1]);
+       nodes[1].node.process_pending_htlc_forwards();
+
+       let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       check_added_monitors!(&nodes[1], 1);
+       assert!(update_1.update_fail_htlcs.len() == 1);
+       let fail_msg = update_1.update_fail_htlcs[0].clone();
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
+       commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
+
+       // Ensure the payment fails with the expected error.
+       let mut error_data = byte_utils::be64_to_array(recv_amt_msat).to_vec();
+       error_data.extend_from_slice(
+               &byte_utils::be32_to_array(nodes[1].node.best_block.read().unwrap().height()),
+       );
+       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);
+}
+
index 2435c3b7a970fcd4f75140ca96c731ed9db495a5..bae9a2914fa8014a87b8a97015bc010d5580a366 100644 (file)
@@ -14,6 +14,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::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, ChannelManagerReadArgs, PaymentId, PaymentSendFailure};
 use ln::features::{InitFeatures, InvoiceFeatures};
 use ln::msgs;
@@ -27,6 +28,7 @@ use util::ser::{ReadableArgs, Writeable};
 use io;
 
 use bitcoin::{Block, BlockHeader, BlockHash};
+use bitcoin::network::constants::Network;
 
 use prelude::*;
 
@@ -423,7 +425,9 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) {
        check_spends!(bs_htlc_claim_txn[0], as_commitment_tx);
        expect_payment_forwarded!(nodes[1], None, false);
 
-       mine_transaction(&nodes[0], &as_commitment_tx);
+       if !confirm_before_reload {
+               mine_transaction(&nodes[0], &as_commitment_tx);
+       }
        mine_transaction(&nodes[0], &bs_htlc_claim_txn[0]);
        expect_payment_sent!(nodes[0], payment_preimage_1);
        connect_blocks(&nodes[0], TEST_FINAL_CLTV*4 + 20);
@@ -515,6 +519,10 @@ fn do_test_dup_htlc_onchain_fails_on_reload(persist_manager_post_event: bool, co
        check_added_monitors!(nodes[1], 1);
        check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
        let claim_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+       assert_eq!(claim_txn.len(), 3);
+       check_spends!(claim_txn[0], node_txn[1]);
+       check_spends!(claim_txn[1], funding_tx);
+       check_spends!(claim_txn[2], claim_txn[1]);
 
        header.prev_blockhash = nodes[0].best_block_hash();
        connect_block(&nodes[0], &Block { header, txdata: vec![node_txn[1].clone()]});
@@ -524,7 +532,7 @@ fn do_test_dup_htlc_onchain_fails_on_reload(persist_manager_post_event: bool, co
        }
 
        header.prev_blockhash = nodes[0].best_block_hash();
-       let claim_block = Block { header, txdata: if payment_timeout { timeout_txn } else { claim_txn } };
+       let claim_block = Block { header, txdata: if payment_timeout { timeout_txn } else { vec![claim_txn[0].clone()] } };
 
        if payment_timeout {
                assert!(confirm_commitment_tx); // Otherwise we're spending below our CSV!
@@ -724,10 +732,12 @@ fn get_ldk_payment_preimage() {
        let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
                .with_features(InvoiceFeatures::known());
        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 route = get_route(
-               &nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph,
+               &nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(),
                Some(&nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()),
-               amt_msat, TEST_FINAL_CLTV, nodes[0].logger, &scorer).unwrap();
+               amt_msat, TEST_FINAL_CLTV, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
        let _payment_id = nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
        check_added_monitors!(nodes[0], 1);
 
index b910d4bf7798135ec08d8e84fc550fb907e318fb..d3ac2ebe9a39bf2e918f58dbf4d012ac0434ae99 100644 (file)
@@ -307,12 +307,12 @@ const OUTBOUND_BUFFER_LIMIT_DROP_GOSSIP: usize = OUTBOUND_BUFFER_LIMIT_READ_PAUS
 /// Thus, to avoid needlessly disconnecting a peer, we allow a peer to take this many timer ticks
 /// per connected peer to respond to a ping, as long as they send us at least one message during
 /// each tick, ensuring we aren't actually just disconnected.
-/// With a timer tick interval of five seconds, this translates to about 30 seconds per connected
+/// With a timer tick interval of ten seconds, this translates to about 40 seconds per connected
 /// peer.
 ///
 /// When we improve parallelism somewhat we should reduce this to e.g. this many timer ticks per
 /// two connected peers, assuming most LDK-running systems have at least two cores.
-const MAX_BUFFER_DRAIN_TICK_INTERVALS_PER_PEER: i8 = 6;
+const MAX_BUFFER_DRAIN_TICK_INTERVALS_PER_PEER: i8 = 4;
 
 /// This is the minimum number of messages we expect a peer to be able to handle within one timer
 /// tick. Once we have sent this many messages since the last ping, we send a ping right away to
@@ -1572,9 +1572,9 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref, CMH: Deref> P
        /// Send pings to each peer and disconnect those which did not respond to the last round of
        /// pings.
        ///
-       /// This may be called on any timescale you want, however, roughly once every five to ten
-       /// seconds is preferred. The call rate determines both how often we send a ping to our peers
-       /// and how much time they have to respond before we disconnect them.
+       /// This may be called on any timescale you want, however, roughly once every ten seconds is
+       /// preferred. The call rate determines both how often we send a ping to our peers and how much
+       /// time they have to respond before we disconnect them.
        ///
        /// May call [`send_data`] on all [`SocketDescriptor`]s. Thus, be very careful with reentrancy
        /// issues!
diff --git a/lightning/src/ln/priv_short_conf_tests.rs b/lightning/src/ln/priv_short_conf_tests.rs
new file mode 100644 (file)
index 0000000..a6f5a1b
--- /dev/null
@@ -0,0 +1,286 @@
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Tests that test ChannelManager behavior with fewer confirmations required than the default and
+//! other behavior that exists only on private channels or with a semi-trusted counterparty (eg
+//! LSP).
+
+use chain::Watch;
+use chain::channelmonitor::ChannelMonitor;
+use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, MIN_CLTV_EXPIRY_DELTA};
+use routing::network_graph::RoutingFees;
+use routing::router::{RouteHint, RouteHintHop};
+use ln::features::InitFeatures;
+use ln::msgs;
+use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler};
+use util::enforcing_trait_impls::EnforcingSigner;
+use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
+use util::config::UserConfig;
+use util::ser::{Writeable, ReadableArgs};
+use util::test_utils;
+
+use prelude::*;
+use core::default::Default;
+
+use ln::functional_test_utils::*;
+
+use bitcoin::hash_types::BlockHash;
+
+#[test]
+fn test_priv_forwarding_rejection() {
+       // If we have a private channel with outbound liquidity, and
+       // UserConfig::accept_forwards_to_priv_channels is set to false, we should reject any attempts
+       // to forward through that channel.
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let mut no_announce_cfg = test_default_channel_config();
+       no_announce_cfg.accept_forwards_to_priv_channels = false;
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(no_announce_cfg), None]);
+       let persister: test_utils::TestPersister;
+       let new_chain_monitor: test_utils::TestChainMonitor;
+       let nodes_1_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
+       let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       let chan_id_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).2;
+       let chan_id_2 = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).0.channel_id;
+
+       // We should always be able to forward through nodes[1] as long as its out through a public
+       // channel:
+       send_payment(&nodes[2], &[&nodes[1], &nodes[0]], 10_000);
+
+       // ... however, if we send to nodes[2], we will have to pass the private channel from nodes[1]
+       // to nodes[2], which should be rejected:
+       let route_hint = RouteHint(vec![RouteHintHop {
+               src_node_id: nodes[1].node.get_our_node_id(),
+               short_channel_id: nodes[2].node.list_channels()[0].short_channel_id.unwrap(),
+               fees: RoutingFees { base_msat: 1000, proportional_millionths: 0 },
+               cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
+               htlc_minimum_msat: None,
+               htlc_maximum_msat: None,
+       }]);
+       let last_hops = vec![route_hint];
+       let (route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], last_hops, 10_000, TEST_FINAL_CLTV);
+
+       nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let payment_event = SendEvent::from_event(nodes[0].node.get_and_clear_pending_msg_events().remove(0));
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
+       commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false, true);
+
+       let htlc_fail_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       assert!(htlc_fail_updates.update_add_htlcs.is_empty());
+       assert_eq!(htlc_fail_updates.update_fail_htlcs.len(), 1);
+       assert!(htlc_fail_updates.update_fail_malformed_htlcs.is_empty());
+       assert!(htlc_fail_updates.update_fee.is_none());
+
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_fail_updates.update_fail_htlcs[0]);
+       commitment_signed_dance!(nodes[0], nodes[1], htlc_fail_updates.commitment_signed, true, true);
+       expect_payment_failed_with_update!(nodes[0], our_payment_hash, false, nodes[2].node.list_channels()[0].short_channel_id.unwrap(), true);
+
+       // Now disconnect nodes[1] from its peers and restart with accept_forwards_to_priv_channels set
+       // to true. Sadly there is currently no way to change it at runtime.
+
+       nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
+       nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
+
+       let nodes_1_serialized = nodes[1].node.encode();
+       let mut monitor_a_serialized = test_utils::TestVecWriter(Vec::new());
+       let mut monitor_b_serialized = test_utils::TestVecWriter(Vec::new());
+       get_monitor!(nodes[1], chan_id_1).write(&mut monitor_a_serialized).unwrap();
+       get_monitor!(nodes[1], chan_id_2).write(&mut monitor_b_serialized).unwrap();
+
+       persister = test_utils::TestPersister::new();
+       let keys_manager = &chanmon_cfgs[1].keys_manager;
+       new_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, keys_manager);
+       nodes[1].chain_monitor = &new_chain_monitor;
+
+       let mut monitor_a_read = &monitor_a_serialized.0[..];
+       let mut monitor_b_read = &monitor_b_serialized.0[..];
+       let (_, mut monitor_a) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut monitor_a_read, keys_manager).unwrap();
+       let (_, mut monitor_b) = <(BlockHash, ChannelMonitor<EnforcingSigner>)>::read(&mut monitor_b_read, keys_manager).unwrap();
+       assert!(monitor_a_read.is_empty());
+       assert!(monitor_b_read.is_empty());
+
+       no_announce_cfg.accept_forwards_to_priv_channels = true;
+
+       let mut nodes_1_read = &nodes_1_serialized[..];
+       let (_, nodes_1_deserialized_tmp) = {
+               let mut channel_monitors = HashMap::new();
+               channel_monitors.insert(monitor_a.get_funding_txo().0, &mut monitor_a);
+               channel_monitors.insert(monitor_b.get_funding_txo().0, &mut monitor_b);
+               <(BlockHash, ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut nodes_1_read, ChannelManagerReadArgs {
+                       default_config: no_announce_cfg,
+                       keys_manager,
+                       fee_estimator: node_cfgs[1].fee_estimator,
+                       chain_monitor: nodes[1].chain_monitor,
+                       tx_broadcaster: nodes[1].tx_broadcaster.clone(),
+                       logger: nodes[1].logger,
+                       channel_monitors,
+               }).unwrap()
+       };
+       assert!(nodes_1_read.is_empty());
+       nodes_1_deserialized = nodes_1_deserialized_tmp;
+
+       assert!(nodes[1].chain_monitor.watch_channel(monitor_a.get_funding_txo().0, monitor_a).is_ok());
+       assert!(nodes[1].chain_monitor.watch_channel(monitor_b.get_funding_txo().0, monitor_b).is_ok());
+       check_added_monitors!(nodes[1], 2);
+       nodes[1].node = &nodes_1_deserialized;
+
+       nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() });
+       nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
+       let as_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
+       let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
+       nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_reestablish);
+       nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
+       get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
+       get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id());
+
+       nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() });
+       nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() });
+       let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[2].node.get_our_node_id());
+       let cs_reestablish = get_event_msg!(nodes[2], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id());
+       nodes[2].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish);
+       nodes[1].node.handle_channel_reestablish(&nodes[2].node.get_our_node_id(), &cs_reestablish);
+       get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[2].node.get_our_node_id());
+       get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
+
+       nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], 10_000, our_payment_hash, our_payment_secret);
+       claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], our_payment_preimage);
+}
+
+fn do_test_1_conf_open(connect_style: ConnectStyle) {
+       // Previously, if the minium_depth config was set to 1, we'd never send a funding_locked. 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;
+       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;
+       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)]);
+       let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+       *nodes[0].connect_style.borrow_mut() = connect_style;
+
+       let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::known(), InitFeatures::known());
+       mine_transaction(&nodes[1], &tx);
+       nodes[0].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingLocked, nodes[0].node.get_our_node_id()));
+       assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
+
+       mine_transaction(&nodes[0], &tx);
+       let as_msg_events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(as_msg_events.len(), 2);
+       let as_funding_locked = if let MessageSendEvent::SendFundingLocked { ref node_id, ref msg } = as_msg_events[0] {
+               assert_eq!(*node_id, nodes[1].node.get_our_node_id());
+               msg.clone()
+       } else { panic!("Unexpected event"); };
+       if let MessageSendEvent::SendChannelUpdate { ref node_id, msg: _ } = as_msg_events[1] {
+               assert_eq!(*node_id, nodes[1].node.get_our_node_id());
+       } else { panic!("Unexpected event"); }
+
+       nodes[1].node.handle_funding_locked(&nodes[0].node.get_our_node_id(), &as_funding_locked);
+       let bs_msg_events = nodes[1].node.get_and_clear_pending_msg_events();
+       assert_eq!(bs_msg_events.len(), 1);
+       if let MessageSendEvent::SendChannelUpdate { ref node_id, msg: _ } = bs_msg_events[0] {
+               assert_eq!(*node_id, nodes[0].node.get_our_node_id());
+       } else { panic!("Unexpected event"); }
+
+       send_payment(&nodes[0], &[&nodes[1]], 100_000);
+
+       // After 6 confirmations, as required by the spec, we'll send announcement_signatures and
+       // broadcast the channel_announcement (but not before exactly 6 confirmations).
+       connect_blocks(&nodes[0], 4);
+       assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
+       connect_blocks(&nodes[0], 1);
+       nodes[1].node.handle_announcement_signatures(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendAnnouncementSignatures, nodes[1].node.get_our_node_id()));
+       assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+
+       connect_blocks(&nodes[1], 5);
+       let bs_announce_events = nodes[1].node.get_and_clear_pending_msg_events();
+       assert_eq!(bs_announce_events.len(), 2);
+       let bs_announcement_sigs = if let MessageSendEvent::SendAnnouncementSignatures { ref node_id, ref msg } = bs_announce_events[0] {
+               assert_eq!(*node_id, nodes[0].node.get_our_node_id());
+               msg.clone()
+       } else { panic!("Unexpected event"); };
+       let (bs_announcement, bs_update) = if let MessageSendEvent::BroadcastChannelAnnouncement { ref msg, ref update_msg } = bs_announce_events[1] {
+               (msg.clone(), update_msg.clone())
+       } else { panic!("Unexpected event"); };
+
+       nodes[0].node.handle_announcement_signatures(&nodes[1].node.get_our_node_id(), &bs_announcement_sigs);
+       let as_announce_events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(as_announce_events.len(), 1);
+       let (announcement, as_update) = if let MessageSendEvent::BroadcastChannelAnnouncement { ref msg, ref update_msg } = as_announce_events[0] {
+               (msg.clone(), update_msg.clone())
+       } else { panic!("Unexpected event"); };
+       assert_eq!(announcement, bs_announcement);
+
+       for node in nodes {
+               assert!(node.net_graph_msg_handler.handle_channel_announcement(&announcement).unwrap());
+               node.net_graph_msg_handler.handle_channel_update(&as_update).unwrap();
+               node.net_graph_msg_handler.handle_channel_update(&bs_update).unwrap();
+       }
+}
+#[test]
+fn test_1_conf_open() {
+       do_test_1_conf_open(ConnectStyle::BestBlockFirst);
+       do_test_1_conf_open(ConnectStyle::TransactionsFirst);
+       do_test_1_conf_open(ConnectStyle::FullBlockViaListen);
+}
+
+#[test]
+fn test_routed_scid_alias() {
+       // Trivially test sending a payment which is routed through an SCID alias.
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let mut no_announce_cfg = test_default_channel_config();
+       no_announce_cfg.accept_forwards_to_priv_channels = true;
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(no_announce_cfg), None]);
+       let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).2;
+       let mut as_funding_locked = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known()).0;
+
+       let last_hop = nodes[2].node.list_usable_channels();
+       let hop_hints = vec![RouteHint(vec![RouteHintHop {
+               src_node_id: nodes[1].node.get_our_node_id(),
+               short_channel_id: last_hop[0].inbound_scid_alias.unwrap(),
+               fees: RoutingFees {
+                       base_msat: last_hop[0].counterparty.forwarding_info.as_ref().unwrap().fee_base_msat,
+                       proportional_millionths: last_hop[0].counterparty.forwarding_info.as_ref().unwrap().fee_proportional_millionths,
+               },
+               cltv_expiry_delta: last_hop[0].counterparty.forwarding_info.as_ref().unwrap().cltv_expiry_delta,
+               htlc_maximum_msat: None,
+               htlc_minimum_msat: None,
+       }])];
+       let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], hop_hints, 100_000, 42);
+       assert_eq!(route.paths[0][1].short_channel_id, last_hop[0].inbound_scid_alias.unwrap());
+       nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+
+       pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], 100_000, payment_hash, payment_secret);
+       claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
+
+       // Now test that if a peer sends us a second funding_locked after the channel is operational we
+       // will use the new alias.
+       as_funding_locked.short_channel_id_alias = Some(0xdeadbeef);
+       nodes[2].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &as_funding_locked);
+       // Note that we always respond to a funding_locked with a channel_update. Not a lot of reason
+       // to bother updating that code, so just drop the message here.
+       get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
+       let updated_channel_info = nodes[2].node.list_usable_channels();
+       assert_eq!(updated_channel_info.len(), 1);
+       assert_eq!(updated_channel_info[0].inbound_scid_alias.unwrap(), 0xdeadbeef);
+       // Note that because we never send a duplicate funding_locked we can't send a payment through
+       // the 0xdeadbeef SCID alias.
+}
index fe8fd68274bd4ab90f50e860a699dc2f0fdf0973..8eb39cfe92a98cacc6ab0bd854d85334a8ded939 100644 (file)
@@ -98,7 +98,7 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) {
                vec![node_1_commitment_txn[0].clone(), node_2_commitment_txn[0].clone()]
        } else {
                // Broadcast node 2 commitment txn
-               let node_2_commitment_txn = get_local_commitment_txn!(nodes[2], chan_2.2);
+               let mut node_2_commitment_txn = get_local_commitment_txn!(nodes[2], chan_2.2);
                assert_eq!(node_2_commitment_txn.len(), 2); // 1 local commitment tx, 1 Received HTLC-Claim
                assert_eq!(node_2_commitment_txn[0].output.len(), 2); // to-remote and Received HTLC (to-self is dust)
                check_spends!(node_2_commitment_txn[0], chan_2.3);
@@ -113,12 +113,10 @@ fn do_test_onchain_htlc_reorg(local_commitment: bool, claim: bool) {
                check_spends!(node_1_commitment_txn[0], chan_2.3);
                check_spends!(node_1_commitment_txn[1], node_2_commitment_txn[0]);
 
-               // Confirm node 2's commitment txn (and node 1's HTLC-Timeout) on node 1
-               header.prev_blockhash = nodes[1].best_block_hash();
-               let block = Block { header, txdata: vec![node_2_commitment_txn[0].clone(), node_1_commitment_txn[1].clone()] };
-               connect_block(&nodes[1], &block);
+               // Confirm node 1's HTLC-Timeout on node 1
+               mine_transaction(&nodes[1], &node_1_commitment_txn[1]);
                // ...but return node 2's commitment tx (and claim) in case claim is set and we're preparing to reorg
-               node_2_commitment_txn
+               vec![node_2_commitment_txn.pop().unwrap()]
        };
        check_added_monitors!(nodes[1], 1);
        check_closed_broadcast!(nodes[1], true); // We should get a BroadcastChannelUpdate (and *only* a BroadcstChannelUpdate)
@@ -203,7 +201,7 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_
 
        let channel_state = nodes[0].node.channel_state.lock().unwrap();
        assert_eq!(channel_state.by_id.len(), 1);
-       assert_eq!(channel_state.short_to_id.len(), 1);
+       assert_eq!(channel_state.short_to_id.len(), 2);
        mem::drop(channel_state);
 
        if !reorg_after_reload {
index a687df8886ca3f7193339e8120618152cd0722b6..cd0f77448a5d5c2c587286dcc7ec9612d5c9ad8c 100644 (file)
@@ -25,6 +25,7 @@ use util::config::UserConfig;
 
 use bitcoin::blockdata::script::Builder;
 use bitcoin::blockdata::opcodes;
+use bitcoin::network::constants::Network;
 
 use regex;
 
@@ -77,6 +78,8 @@ fn updates_shutdown_wait() {
        let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
        let logger = test_utils::TestLogger::new();
        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_preimage, _, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 100000);
 
@@ -92,9 +95,9 @@ fn updates_shutdown_wait() {
        let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[0]);
 
        let payment_params_1 = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(InvoiceFeatures::known());
-       let route_1 = get_route(&nodes[0].node.get_our_node_id(), &payment_params_1, nodes[0].network_graph, None, 100000, TEST_FINAL_CLTV, &logger, &scorer).unwrap();
+       let route_1 = get_route(&nodes[0].node.get_our_node_id(), &payment_params_1, &nodes[0].network_graph.read_only(), None, 100000, TEST_FINAL_CLTV, &logger, &scorer, &random_seed_bytes).unwrap();
        let payment_params_2 = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id()).with_features(InvoiceFeatures::known());
-       let route_2 = get_route(&nodes[1].node.get_our_node_id(), &payment_params_2, nodes[1].network_graph, None, 100000, TEST_FINAL_CLTV, &logger, &scorer).unwrap();
+       let route_2 = get_route(&nodes[1].node.get_our_node_id(), &payment_params_2, &nodes[1].network_graph.read_only(), None, 100000, TEST_FINAL_CLTV, &logger, &scorer, &random_seed_bytes).unwrap();
        unwrap_send_err!(nodes[0].node.send_payment(&route_1, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable {..}, {});
        unwrap_send_err!(nodes[1].node.send_payment(&route_2, payment_hash, &Some(payment_secret)), true, APIError::ChannelUnavailable {..}, {});
 
index 5a84f35c28dd4f1990ef0eda4611c53a139cb615..a5e497bb1cf0f279137fd3f5e923e8972317181d 100644 (file)
@@ -674,6 +674,21 @@ impl ChannelInfo {
                };
                Some((DirectedChannelInfo { channel: self, direction }, source))
        }
+
+       /// Returns a [`DirectedChannelInfo`] for the channel directed from the given `source` to a
+       /// returned `target`, or `None` if `source` is not one of the channel's counterparties.
+       pub fn as_directed_from(&self, source: &NodeId) -> Option<(DirectedChannelInfo, &NodeId)> {
+               let (direction, target) = {
+                       if source == &self.node_one {
+                               (self.one_to_two.as_ref(), &self.node_two)
+                       } else if source == &self.node_two {
+                               (self.two_to_one.as_ref(), &self.node_one)
+                       } else {
+                               return None;
+                       }
+               };
+               Some((DirectedChannelInfo { channel: self, direction }, target))
+       }
 }
 
 impl fmt::Display for ChannelInfo {
index 740fd691e75c85e41f1f3ae06c5a1e18f41c82fa..62cbda9a76ddd097710d897537e11f104c1ec408 100644 (file)
@@ -18,9 +18,10 @@ use ln::channelmanager::ChannelDetails;
 use ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
 use ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
 use routing::scoring::Score;
-use routing::network_graph::{DirectedChannelInfoWithUpdate, EffectiveCapacity, NetworkGraph, NodeId, RoutingFees};
+use routing::network_graph::{DirectedChannelInfoWithUpdate, EffectiveCapacity, NetworkGraph, ReadOnlyNetworkGraph, NodeId, RoutingFees};
 use util::ser::{Writeable, Readable};
 use util::logger::{Level, Logger};
+use util::chacha20::ChaCha20;
 
 use io;
 use prelude::*;
@@ -176,6 +177,9 @@ 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;
 
+/// The median hop CLTV expiry delta currently seen in the network.
+const MEDIAN_HOP_CLTV_EXPIRY_DELTA: u32 = 40;
+
 /// The recipient of a payment.
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub struct PaymentParameters {
@@ -258,7 +262,6 @@ impl PaymentParameters {
 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
 pub struct RouteHint(pub Vec<RouteHintHop>);
 
-
 impl Writeable for RouteHint {
        fn write<W: ::util::ser::Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
                (self.0.len() as u64).write(writer)?;
@@ -423,7 +426,7 @@ impl<'a> CandidateRouteHop<'a> {
 /// so that we can choose cheaper paths (as per Dijkstra's algorithm).
 /// Fee values should be updated only in the context of the whole path, see update_value_and_recompute_fees.
 /// These fee values are useful to choose hops as we traverse the graph "payee-to-payer".
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 struct PathBuildingHop<'a> {
        // Note that this should be dropped in favor of loading it from CandidateRouteHop, but doing so
        // is a larger refactor and will require careful performance analysis.
@@ -463,6 +466,22 @@ struct PathBuildingHop<'a> {
        value_contribution_msat: u64,
 }
 
+impl<'a> core::fmt::Debug for PathBuildingHop<'a> {
+       fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
+               f.debug_struct("PathBuildingHop")
+                       .field("node_id", &self.node_id)
+                       .field("short_channel_id", &self.candidate.short_channel_id())
+                       .field("total_fee_msat", &self.total_fee_msat)
+                       .field("next_hops_fee_msat", &self.next_hops_fee_msat)
+                       .field("hop_use_fee_msat", &self.hop_use_fee_msat)
+                       .field("total_fee_msat - (next_hops_fee_msat + hop_use_fee_msat)", &(&self.total_fee_msat - (&self.next_hops_fee_msat + &self.hop_use_fee_msat)))
+                       .field("path_penalty_msat", &self.path_penalty_msat)
+                       .field("path_htlc_minimum_msat", &self.path_htlc_minimum_msat)
+                       .field("cltv_expiry_delta", &self.candidate.cltv_expiry_delta())
+                       .finish()
+       }
+}
+
 // Instantiated with a list of hops with correct data in them collected during path finding,
 // an instance of this struct should be further modified only via given methods.
 #[derive(Clone)]
@@ -607,19 +626,26 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
 /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
 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
+       first_hops: Option<&[&ChannelDetails]>, logger: L, scorer: &S, random_seed_bytes: &[u8; 32]
 ) -> Result<Route, LightningError>
 where L::Target: Logger {
-       get_route(
-               our_node_pubkey, &route_params.payment_params, network, first_hops, route_params.final_value_msat,
-               route_params.final_cltv_expiry_delta, logger, scorer
-       )
+       let network_graph = network.read_only();
+       match 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
+       ) {
+               Ok(mut route) => {
+                       add_random_cltv_offset(&mut route, &route_params.payment_params, &network_graph, random_seed_bytes);
+                       Ok(route)
+               },
+               Err(err) => Err(err),
+       }
 }
 
 pub(crate) fn get_route<L: Deref, S: Score>(
-       our_node_pubkey: &PublicKey, payment_params: &PaymentParameters, network: &NetworkGraph,
-       first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, final_cltv_expiry_delta: u32, 
-       logger: L, scorer: &S
+       our_node_pubkey: &PublicKey, payment_params: &PaymentParameters, network_graph: &ReadOnlyNetworkGraph,
+       first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, final_cltv_expiry_delta: u32,
+       logger: L, scorer: &S, _random_seed_bytes: &[u8; 32]
 ) -> Result<Route, LightningError>
 where L::Target: Logger {
        let payee_node_id = NodeId::from_pubkey(&payment_params.payee_pubkey);
@@ -656,12 +682,13 @@ where L::Target: Logger {
        //    - OR if we could not construct a new path. Any next attempt will fail too.
        //    Otherwise, repeat step 2.
        // 4. See if we managed to collect paths which aggregately are able to transfer target value
-       //    (not recommended value). If yes, proceed. If not, fail routing.
-       // 5. Randomly combine paths into routes having enough to fulfill the payment. (TODO: knapsack)
-       // 6. Of all the found paths, select only those with the lowest total fee.
-       // 7. The last path in every selected route is likely to be more than we need.
+       //    (not recommended value).
+       // 5. If yes, proceed. If not, fail routing.
+       // 6. Randomly combine paths into routes having enough to fulfill the payment. (TODO: knapsack)
+       // 7. Of all the found paths, select only those with the lowest total fee.
+       // 8. The last path in every selected route is likely to be more than we need.
        //    Reduce its value-to-transfer and recompute fees.
-       // 8. Choose the best route by the lowest total fee.
+       // 9. Choose the best route by the lowest total fee.
 
        // As for the actual search algorithm,
        // we do a payee-to-payer pseudo-Dijkstra's sorting by each node's distance from the payee
@@ -705,7 +732,6 @@ where L::Target: Logger {
        // to use as the A* heuristic beyond just the cost to get one node further than the current
        // one.
 
-       let network_graph = network.read_only();
        let network_channels = network_graph.channels();
        let network_nodes = network_graph.nodes();
 
@@ -719,8 +745,9 @@ where L::Target: Logger {
                        node_info.features.supports_basic_mpp()
                } else { false }
        } else { false };
-       log_trace!(logger, "Searching for a route from payer {} to payee {} {} MPP", our_node_pubkey,
-               payment_params.payee_pubkey, if allow_mpp { "with" } else { "without" });
+       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 " });
 
        // Step (1).
        // Prepare the data we'll use for payee-to-payer search by
@@ -836,7 +863,12 @@ where L::Target: Logger {
                                        let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
 
                                        // Do not consider candidates that exceed the maximum total cltv expiry limit.
-                                       let max_total_cltv_expiry_delta = payment_params.max_total_cltv_expiry_delta;
+                                       // In order to already account for some of the privacy enhancing random CLTV
+                                       // expiry delta offset we add on top later, we subtract a rough estimate
+                                       // (2*MEDIAN_HOP_CLTV_EXPIRY_DELTA) here.
+                                       let max_total_cltv_expiry_delta = payment_params.max_total_cltv_expiry_delta
+                                               .checked_sub(2*MEDIAN_HOP_CLTV_EXPIRY_DELTA)
+                                               .unwrap_or(payment_params.max_total_cltv_expiry_delta);
                                        let hop_total_cltv_delta = ($next_hops_cltv_delta as u32)
                                                .checked_add($candidate.cltv_expiry_delta())
                                                .unwrap_or(u32::max_value());
@@ -876,8 +908,8 @@ where L::Target: Logger {
                                                        // semi-dummy record just to compute the fees to reach the source node.
                                                        // This will affect our decision on selecting short_channel_id
                                                        // as a way to reach the $dest_node_id.
-                                                       let mut fee_base_msat = u32::max_value();
-                                                       let mut fee_proportional_millionths = u32::max_value();
+                                                       let mut fee_base_msat = 0;
+                                                       let mut fee_proportional_millionths = 0;
                                                        if let Some(Some(fees)) = network_nodes.get(&$src_node_id).map(|node| node.lowest_inbound_channel_fees) {
                                                                fee_base_msat = fees.base_msat;
                                                                fee_proportional_millionths = fees.proportional_millionths;
@@ -1268,11 +1300,9 @@ where L::Target: Logger {
                                                                ordered_hops.last_mut().unwrap().1 = NodeFeatures::empty();
                                                        }
                                                } else {
-                                                       // We should be able to fill in features for everything except the last
-                                                       // hop, if the last hop was provided via a BOLT 11 invoice (though we
-                                                       // should be able to extend it further as BOLT 11 does have feature
-                                                       // flags for the last hop node itself).
-                                                       assert!(ordered_hops.last().unwrap().0.node_id == payee_node_id);
+                                                       // We can fill in features for everything except hops which were
+                                                       // provided via the invoice we're paying. We could guess based on the
+                                                       // recipient's features but for now we simply avoid guessing at all.
                                                }
                                        }
 
@@ -1299,8 +1329,8 @@ where L::Target: Logger {
                                ordered_hops.last_mut().unwrap().0.fee_msat = value_contribution_msat;
                                ordered_hops.last_mut().unwrap().0.hop_use_fee_msat = 0;
 
-                               log_trace!(logger, "Found a path back to us from the target with {} hops contributing up to {} msat: {:?}",
-                                       ordered_hops.len(), value_contribution_msat, ordered_hops);
+                               log_trace!(logger, "Found a path back to us from the target with {} hops contributing up to {} msat: \n {:#?}",
+                                       ordered_hops.len(), value_contribution_msat, ordered_hops.iter().map(|h| &(h.0)).collect::<Vec<&PathBuildingHop>>());
 
                                let mut payment_path = PaymentPath {hops: ordered_hops};
 
@@ -1520,17 +1550,92 @@ where L::Target: Logger {
        Ok(route)
 }
 
+// When an adversarial intermediary node observes a payment, it may be able to infer its
+// destination, if the remaining CLTV expiry delta exactly matches a feasible path in the network
+// graph. In order to improve privacy, this method obfuscates the CLTV expiry deltas along the
+// payment path by adding a randomized 'shadow route' offset to the final hop.
+fn add_random_cltv_offset(route: &mut Route, payment_params: &PaymentParameters, network_graph: &ReadOnlyNetworkGraph, random_seed_bytes: &[u8; 32]) {
+       let network_channels = network_graph.channels();
+       let network_nodes = network_graph.nodes();
+
+       for path in route.paths.iter_mut() {
+               let mut shadow_ctlv_expiry_delta_offset: u32 = 0;
+
+               // Choose the last publicly known node as the starting point for the random walk
+               if let Some(starting_hop) = path.iter().rev().find(|h| network_nodes.contains_key(&NodeId::from_pubkey(&h.pubkey))) {
+                       let mut cur_node_id = NodeId::from_pubkey(&starting_hop.pubkey);
+
+                       // Init PRNG with path nonce
+                       let mut path_nonce = [0u8; 12];
+                       path_nonce.copy_from_slice(&cur_node_id.as_slice()[..12]);
+                       let mut prng = ChaCha20::new(random_seed_bytes, &path_nonce);
+                       let mut random_path_bytes = [0u8; ::core::mem::size_of::<usize>()];
+
+                       // Pick a random path length in [1 .. 3]
+                       prng.process_in_place(&mut random_path_bytes);
+                       let random_walk_length = usize::from_be_bytes(random_path_bytes).wrapping_rem(3).wrapping_add(1);
+
+                       for _random_hop in 0..random_walk_length {
+                               if let Some(cur_node) = network_nodes.get(&cur_node_id) {
+                                       // Randomly choose the next hop
+                                       prng.process_in_place(&mut random_path_bytes);
+                                       if let Some(random_channel) = usize::from_be_bytes(random_path_bytes).checked_rem(cur_node.channels.len())
+                                               .and_then(|index| cur_node.channels.get(index))
+                                               .and_then(|id| network_channels.get(id)) {
+                                                       random_channel.as_directed_from(&cur_node_id).map(|(dir_info, next_id)| {
+                                                               dir_info.direction().map(|channel_update_info|
+                                                                       shadow_ctlv_expiry_delta_offset = shadow_ctlv_expiry_delta_offset
+                                                                               .checked_add(channel_update_info.cltv_expiry_delta.into())
+                                                                               .unwrap_or(shadow_ctlv_expiry_delta_offset));
+                                                               cur_node_id = *next_id;
+                                                       });
+                                               }
+                               }
+                       }
+               } else {
+                       // If the entire path is private, choose a random offset from multiples of
+                       // MEDIAN_HOP_CLTV_EXPIRY_DELTA
+                       let mut prng = ChaCha20::new(random_seed_bytes, &[0u8; 8]);
+                       let mut random_bytes = [0u8; 4];
+                       prng.process_in_place(&mut random_bytes);
+                       let random_walk_length = u32::from_be_bytes(random_bytes).wrapping_rem(3).wrapping_add(1);
+                       shadow_ctlv_expiry_delta_offset = random_walk_length * MEDIAN_HOP_CLTV_EXPIRY_DELTA;
+               }
+
+               // Limit the total offset to reduce the worst-case locked liquidity timevalue
+               const MAX_SHADOW_CLTV_EXPIRY_DELTA_OFFSET: u32 = 3*144;
+               shadow_ctlv_expiry_delta_offset = cmp::min(shadow_ctlv_expiry_delta_offset, MAX_SHADOW_CLTV_EXPIRY_DELTA_OFFSET);
+
+               // Limit the offset so we never exceed the max_total_cltv_expiry_delta. To improve plausibility,
+               // we choose the limit to be the largest possible multiple of MEDIAN_HOP_CLTV_EXPIRY_DELTA.
+               let path_total_cltv_expiry_delta: u32 = path.iter().map(|h| h.cltv_expiry_delta).sum();
+               let mut max_path_offset = payment_params.max_total_cltv_expiry_delta - path_total_cltv_expiry_delta;
+               max_path_offset = cmp::max(
+                       max_path_offset - (max_path_offset % MEDIAN_HOP_CLTV_EXPIRY_DELTA),
+                       max_path_offset % MEDIAN_HOP_CLTV_EXPIRY_DELTA);
+               shadow_ctlv_expiry_delta_offset = cmp::min(shadow_ctlv_expiry_delta_offset, max_path_offset);
+
+               // Add 'shadow' CLTV offset to the final hop
+               if let Some(last_hop) = path.last_mut() {
+                       last_hop.cltv_expiry_delta = last_hop.cltv_expiry_delta
+                               .checked_add(shadow_ctlv_expiry_delta_offset).unwrap_or(last_hop.cltv_expiry_delta);
+               }
+       }
+}
+
 #[cfg(test)]
 mod tests {
-       use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters, Score};
        use routing::network_graph::{NetworkGraph, NetGraphMsgHandler, NodeId};
-       use routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees};
+       use routing::router::{get_route, add_random_cltv_offset, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA};
+       use routing::scoring::Score;
        use chain::transaction::OutPoint;
+       use chain::keysinterface::KeysInterface;
        use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
        use ln::msgs::{ErrorAction, LightningError, OptionalField, UnsignedChannelAnnouncement, ChannelAnnouncement, RoutingMessageHandler,
           NodeAnnouncement, UnsignedNodeAnnouncement, ChannelUpdate, UnsignedChannelUpdate};
        use ln::channelmanager;
        use util::test_utils;
+       use util::chacha20::ChaCha20;
        use util::ser::Writeable;
        #[cfg(c_bindings)]
        use util::ser::Writer;
@@ -1563,6 +1668,7 @@ mod tests {
                        },
                        funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
                        short_channel_id,
+                       inbound_scid_alias: None,
                        channel_value_satoshis: 0,
                        user_channel_id: 0,
                        balance_msat: 0,
@@ -1654,7 +1760,7 @@ mod tests {
 
        fn get_nodes(secp_ctx: &Secp256k1<All>) -> (SecretKey, PublicKey, Vec<SecretKey>, Vec<PublicKey>) {
                let privkeys: Vec<SecretKey> = (2..10).map(|i| {
-                       SecretKey::from_slice(&hex::decode(format!("{:02}", i).repeat(32)).unwrap()[..]).unwrap()
+                       SecretKey::from_slice(&hex::decode(format!("{:02x}", i).repeat(32)).unwrap()[..]).unwrap()
                }).collect();
 
                let pubkeys = privkeys.iter().map(|secret| PublicKey::from_secret_key(&secp_ctx, secret)).collect();
@@ -1998,14 +2104,16 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                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();
 
                // Simple route to 2 via 1
 
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 0, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 0, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "Cannot send a payment of 0 msat");
                } else { panic!(); }
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2029,16 +2137,19 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                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();
 
                // Simple route to 2 via 1
 
                let our_chans = vec![get_channel_details(Some(2), our_id, InitFeatures::from_le_bytes(vec![0b11]), 100000)];
 
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) =
+                       get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "First hop cannot have our_node_pubkey as a destination.");
                } else { panic!(); }
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
        }
 
@@ -2048,6 +2159,8 @@ mod tests {
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                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();
 
                // Simple route to 2 via 1
 
@@ -2144,7 +2257,7 @@ mod tests {
                });
 
                // Not possible to send 199_999_999, because the minimum on channel=2 is 200_000_000.
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 199_999_999, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
@@ -2163,7 +2276,7 @@ mod tests {
                });
 
                // A payment above the minimum should pass
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 199_999_999, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
        }
 
@@ -2173,6 +2286,8 @@ mod tests {
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
                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();
 
                // A route to node#2 via two paths.
                // One path allows transferring 35-40 sats, another one also allows 35-40 sats.
@@ -2242,7 +2357,7 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 60_000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                // Overpay fees to hit htlc_minimum_msat.
                let overpaid_fees = route.paths[0][0].fee_msat + route.paths[1][0].fee_msat;
                // TODO: this could be better balanced to overpay 10k and not 15k.
@@ -2287,14 +2402,14 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 60_000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                // Fine to overpay for htlc_minimum_msat if it allows us to save fee.
                assert_eq!(route.paths.len(), 1);
                assert_eq!(route.paths[0][0].short_channel_id, 12);
                let fees = route.paths[0][0].fee_msat;
                assert_eq!(fees, 5_000);
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 50_000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                // Not fine to overpay for htlc_minimum_msat if it requires paying more than fee on
                // the other channel.
                assert_eq!(route.paths.len(), 1);
@@ -2309,6 +2424,8 @@ mod tests {
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                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();
 
                // // Disable channels 4 and 12 by flags=2
                update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
@@ -2337,13 +2454,13 @@ mod tests {
                });
 
                // If all the channels require some features we don't understand, route should fail
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[7]);
@@ -2367,6 +2484,8 @@ mod tests {
                let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                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();
 
                // Disable nodes 1, 2, and 8 by requiring unknown feature bits
                let mut unknown_features = NodeFeatures::known();
@@ -2376,13 +2495,13 @@ mod tests {
                add_or_update_node(&net_graph_msg_handler, &secp_ctx, &privkeys[7], unknown_features.clone(), 1);
 
                // If all nodes require some features we don't understand, route should fail
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[7]);
@@ -2409,10 +2528,12 @@ mod tests {
                let (secp_ctx, network_graph, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                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();
 
                // Route to 1 via 2 and 3 because our channel to 1 is disabled
                let payment_params = PaymentParameters::from_node_id(nodes[0]);
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 3);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2439,7 +2560,7 @@ mod tests {
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[7]);
@@ -2538,6 +2659,8 @@ mod tests {
                let (secp_ctx, network_graph, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                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();
 
                // Simple test across 2, 3, 5, and 4 via a last_hop channel
                // Tests the behaviour when the RouteHint contains a suboptimal hop.
@@ -2560,13 +2683,13 @@ mod tests {
                invalid_last_hops.push(invalid_last_hop);
                {
                        let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(invalid_last_hops);
-                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer) {
+                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                assert_eq!(err, "Route hint cannot have the payee as the source.");
                        } else { panic!(); }
                }
 
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops_multi_private_channels(&nodes));
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 5);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2637,10 +2760,12 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(empty_last_hop(&nodes));
                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();
 
                // Test handling of an empty RouteHint passed in Invoice.
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 5);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2681,14 +2806,16 @@ mod tests {
                assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
        }
 
-       fn multi_hint_last_hops(nodes: &Vec<PublicKey>) -> Vec<RouteHint> {
+       /// Builds a trivial last-hop hint that passes through the two nodes given, with channel 0xff00
+       /// and 0xff01.
+       fn multi_hop_last_hops_hint(hint_hops: [PublicKey; 2]) -> Vec<RouteHint> {
                let zero_fees = RoutingFees {
                        base_msat: 0,
                        proportional_millionths: 0,
                };
                vec![RouteHint(vec![RouteHintHop {
-                       src_node_id: nodes[2],
-                       short_channel_id: 5,
+                       src_node_id: hint_hops[0],
+                       short_channel_id: 0xff00,
                        fees: RoutingFees {
                                base_msat: 100,
                                proportional_millionths: 0,
@@ -2697,19 +2824,12 @@ mod tests {
                        htlc_minimum_msat: None,
                        htlc_maximum_msat: None,
                }, RouteHintHop {
-                       src_node_id: nodes[3],
-                       short_channel_id: 8,
+                       src_node_id: hint_hops[1],
+                       short_channel_id: 0xff01,
                        fees: zero_fees,
                        cltv_expiry_delta: (8 << 4) | 1,
                        htlc_minimum_msat: None,
                        htlc_maximum_msat: None,
-               }]), RouteHint(vec![RouteHintHop {
-                       src_node_id: nodes[5],
-                       short_channel_id: 10,
-                       fees: zero_fees,
-                       cltv_expiry_delta: (10 << 4) | 1,
-                       htlc_minimum_msat: None,
-                       htlc_maximum_msat: None,
                }])]
        }
 
@@ -2717,9 +2837,12 @@ mod tests {
        fn multi_hint_last_hops_test() {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(multi_hint_last_hops(&nodes));
+               let last_hops = multi_hop_last_hops_hint([nodes[2], nodes[3]]);
+               let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
                let scorer = test_utils::TestScorer::with_penalty(0);
-               // Test through channels 2, 3, 5, 8.
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+               // Test through channels 2, 3, 0xff00, 0xff01.
                // Test shows that multiple hop hints are considered.
 
                // Disabling channels 6 & 7 by flags=2
@@ -2748,7 +2871,7 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 4);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2766,14 +2889,86 @@ mod tests {
                assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(4));
 
                assert_eq!(route.paths[0][2].pubkey, nodes[3]);
-               assert_eq!(route.paths[0][2].short_channel_id, 5);
+               assert_eq!(route.paths[0][2].short_channel_id, last_hops[0].0[0].short_channel_id);
                assert_eq!(route.paths[0][2].fee_msat, 0);
                assert_eq!(route.paths[0][2].cltv_expiry_delta, 129);
                assert_eq!(route.paths[0][2].node_features.le_flags(), &id_to_feature_flags(4));
-               assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new());
+               assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
 
                assert_eq!(route.paths[0][3].pubkey, nodes[6]);
-               assert_eq!(route.paths[0][3].short_channel_id, 8);
+               assert_eq!(route.paths[0][3].short_channel_id, last_hops[0].0[1].short_channel_id);
+               assert_eq!(route.paths[0][3].fee_msat, 100);
+               assert_eq!(route.paths[0][3].cltv_expiry_delta, 42);
+               assert_eq!(route.paths[0][3].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][3].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
+       }
+
+       #[test]
+       fn private_multi_hint_last_hops_test() {
+               let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
+               let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
+
+               let non_announced_privkey = SecretKey::from_slice(&hex::decode(format!("{:02x}", 0xf0).repeat(32)).unwrap()[..]).unwrap();
+               let non_announced_pubkey = PublicKey::from_secret_key(&secp_ctx, &non_announced_privkey);
+
+               let last_hops = multi_hop_last_hops_hint([nodes[2], non_announced_pubkey]);
+               let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
+               let scorer = test_utils::TestScorer::with_penalty(0);
+               // Test through channels 2, 3, 0xff00, 0xff01.
+               // Test shows that multiple hop hints are considered.
+
+               // Disabling channels 6 & 7 by flags=2
+               update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+                       chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+                       short_channel_id: 6,
+                       timestamp: 2,
+                       flags: 2, // to disable
+                       cltv_expiry_delta: 0,
+                       htlc_minimum_msat: 0,
+                       htlc_maximum_msat: OptionalField::Absent,
+                       fee_base_msat: 0,
+                       fee_proportional_millionths: 0,
+                       excess_data: Vec::new()
+               });
+               update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+                       chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+                       short_channel_id: 7,
+                       timestamp: 2,
+                       flags: 2, // to disable
+                       cltv_expiry_delta: 0,
+                       htlc_minimum_msat: 0,
+                       htlc_maximum_msat: OptionalField::Absent,
+                       fee_base_msat: 0,
+                       fee_proportional_millionths: 0,
+                       excess_data: Vec::new()
+               });
+
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &[42u8; 32]).unwrap();
+               assert_eq!(route.paths[0].len(), 4);
+
+               assert_eq!(route.paths[0][0].pubkey, nodes[1]);
+               assert_eq!(route.paths[0][0].short_channel_id, 2);
+               assert_eq!(route.paths[0][0].fee_msat, 200);
+               assert_eq!(route.paths[0][0].cltv_expiry_delta, 65);
+               assert_eq!(route.paths[0][0].node_features.le_flags(), &id_to_feature_flags(2));
+               assert_eq!(route.paths[0][0].channel_features.le_flags(), &id_to_feature_flags(2));
+
+               assert_eq!(route.paths[0][1].pubkey, nodes[2]);
+               assert_eq!(route.paths[0][1].short_channel_id, 4);
+               assert_eq!(route.paths[0][1].fee_msat, 100);
+               assert_eq!(route.paths[0][1].cltv_expiry_delta, 81);
+               assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags(3));
+               assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(4));
+
+               assert_eq!(route.paths[0][2].pubkey, non_announced_pubkey);
+               assert_eq!(route.paths[0][2].short_channel_id, last_hops[0].0[0].short_channel_id);
+               assert_eq!(route.paths[0][2].fee_msat, 0);
+               assert_eq!(route.paths[0][2].cltv_expiry_delta, 129);
+               assert_eq!(route.paths[0][2].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
+
+               assert_eq!(route.paths[0][3].pubkey, nodes[6]);
+               assert_eq!(route.paths[0][3].short_channel_id, last_hops[0].0[1].short_channel_id);
                assert_eq!(route.paths[0][3].fee_msat, 100);
                assert_eq!(route.paths[0][3].cltv_expiry_delta, 42);
                assert_eq!(route.paths[0][3].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
@@ -2825,10 +3020,12 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops_with_public_channel(&nodes));
                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();
                // This test shows that public routes can be present in the invoice
                // which would be handled in the same manner.
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 5);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2874,12 +3071,14 @@ mod tests {
                let (secp_ctx, network_graph, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                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();
 
                // Simple test with outbound channel to 4 to test that last_hops and first_hops connect
                let our_chans = vec![get_channel_details(Some(42), nodes[3].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
                let mut last_hops = last_hops(&nodes);
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
-               let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[3]);
@@ -2900,7 +3099,7 @@ mod tests {
 
                // Revert to via 6 as the fee on 8 goes up
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops);
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 4);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2934,7 +3133,7 @@ mod tests {
                assert_eq!(route.paths[0][3].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
 
                // ...but still use 8 for larger payments as 6 has a variable feerate
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 2000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 2000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 5);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2995,7 +3194,10 @@ mod tests {
                let payment_params = PaymentParameters::from_node_id(target_node_id).with_route_hints(vec![last_hops]);
                let our_chans = vec![get_channel_details(Some(42), middle_node_id, InitFeatures::from_le_bytes(vec![0b11]), outbound_capacity_msat)];
                let scorer = test_utils::TestScorer::with_penalty(0);
-               get_route(&source_node_id, &payment_params, &NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()), Some(&our_chans.iter().collect::<Vec<_>>()), route_val, 42, &test_utils::TestLogger::new(), &scorer)
+               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)
        }
 
        #[test]
@@ -3049,6 +3251,8 @@ mod tests {
                let (secp_ctx, network_graph, mut net_graph_msg_handler, chain_monitor, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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());
 
                // We will use a simple single-path route from
@@ -3113,14 +3317,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 250_000_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 250_000_001, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 250_000_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3149,14 +3353,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_001, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3196,14 +3400,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 15_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 15_001, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 15_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3266,14 +3470,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 15_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 15_001, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 15_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3298,14 +3502,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 10_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 10_001, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 10_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 10_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3321,6 +3525,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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[3]).with_features(InvoiceFeatures::known());
 
                // Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
@@ -3407,14 +3613,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 60_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 60_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 49 sats (just a bit below the capacity).
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 49_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 49_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -3427,7 +3633,7 @@ mod tests {
 
                {
                        // Attempt to route an exact amount is also fine
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 50_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -3444,6 +3650,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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]);
 
                // Path via node0 is channels {1, 3}. Limit them to 100 and 50 sats (total limit 50).
@@ -3473,7 +3681,7 @@ mod tests {
                });
 
                {
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 50_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -3490,6 +3698,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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());
 
                // We need a route consisting of 3 paths:
@@ -3583,7 +3793,7 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 300_000, 42, Arc::clone(&logger), &scorer) {
+                                       &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!(); }
                }
@@ -3591,7 +3801,7 @@ mod tests {
                {
                        // Now, attempt to route 250 sats (just a bit below the capacity).
                        // Our algorithm should provide us with these 3 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 250_000, 42, Arc::clone(&logger), &scorer).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 {
@@ -3604,7 +3814,7 @@ mod tests {
 
                {
                        // Attempt to route an exact amount is also fine
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 290_000, 42, Arc::clone(&logger), &scorer).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 {
@@ -3621,6 +3831,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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[3]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 3 paths:
@@ -3757,7 +3969,7 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 350_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 350_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -3765,7 +3977,7 @@ mod tests {
                {
                        // Now, attempt to route 300 sats (exact amount we can route).
                        // Our algorithm should provide us with these 3 paths, 100 sats each.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 300_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 300_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
 
                        let mut total_amount_paid_msat = 0;
@@ -3783,6 +3995,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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[3]).with_features(InvoiceFeatures::known());
 
                // This test checks that if we have two cheaper paths and one more expensive path,
@@ -3923,7 +4137,7 @@ mod tests {
                {
                        // Now, attempt to route 180 sats.
                        // Our algorithm should provide us with these 2 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 180_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 180_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
 
                        let mut total_value_transferred_msat = 0;
@@ -3950,6 +4164,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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[3]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 2 paths:
@@ -4091,14 +4307,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 210_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 210_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 200 sats (exact amount we can route).
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 200_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 200_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
 
                        let mut total_amount_paid_msat = 0;
@@ -4129,6 +4345,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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(PublicKey::from_slice(&[02; 33]).unwrap()).with_features(InvoiceFeatures::known())
                        .with_route_hints(vec![RouteHint(vec![RouteHintHop {
                                src_node_id: nodes[2],
@@ -4195,7 +4413,7 @@ mod tests {
 
                // Get a route for 100 sats and check that we found the MPP route no problem and didn't
                // overpay at all.
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100_000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths.len(), 2);
                // Paths are somewhat randomly ordered, but:
                // * the first is channel 2 (1 msat fee) -> channel 4 -> channel 42
@@ -4217,6 +4435,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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());
 
                // We need a route consisting of 3 paths:
@@ -4309,7 +4529,7 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 150_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 150_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -4317,7 +4537,7 @@ mod tests {
                {
                        // Now, attempt to route 125 sats (just a bit below the capacity of 3 channels).
                        // Our algorithm should provide us with these 3 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 125_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 125_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 {
@@ -4330,7 +4550,7 @@ mod tests {
 
                {
                        // Attempt to route without the last small cheap channel
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 90_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4370,10 +4590,12 @@ mod tests {
                // "previous hop" being set to node 3, creating a loop in the path.
                let secp_ctx = Secp256k1::new();
                let logger = Arc::new(test_utils::TestLogger::new());
-               let network_graph = Arc::new(NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()));
-               let net_graph_msg_handler = NetGraphMsgHandler::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
+               let network = Arc::new(NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()));
+               let net_graph_msg_handler = NetGraphMsgHandler::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);
+               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[6]);
 
                add_channel(&net_graph_msg_handler, &secp_ctx, &our_privkey, &privkeys[1], ChannelFeatures::from_le_bytes(id_to_feature_flags(6)), 6);
@@ -4467,7 +4689,7 @@ mod tests {
 
                {
                        // Now ensure the route flows simply over nodes 1 and 4 to 6.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 10_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network.read_only(), None, 10_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].len(), 3);
 
@@ -4503,6 +4725,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, _, nodes) = get_nodes(&secp_ctx);
                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]);
 
                // We modify the graph to set the htlc_maximum of channel 2 to below the value we wish to
@@ -4536,7 +4760,7 @@ mod tests {
                {
                        // Now, attempt to route 90 sats, which is exactly 90 sats at the last hop, plus the
                        // 200% fee charged channel 13 in the 1-to-2 direction.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 90_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].len(), 2);
 
@@ -4565,6 +4789,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                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());
 
                // We modify the graph to set the htlc_minimum of channel 2 and 4 as needed - channel 2
@@ -4599,7 +4825,7 @@ mod tests {
                        // Now, attempt to route 90 sats, hitting the htlc_minimum on channel 4, but
                        // overshooting the htlc_maximum on channel 2. Thus, we should pick the (absurdly
                        // expensive) channels 12-13 path.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 90_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].len(), 2);
 
@@ -4633,12 +4859,14 @@ mod tests {
                let network_graph = NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash());
                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);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                {
-                       let route = get_route(&our_id, &payment_params, &network_graph, Some(&[
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
                                &get_channel_details(Some(3), nodes[0], InitFeatures::known(), 200_000),
                                &get_channel_details(Some(2), nodes[0], InitFeatures::known(), 10_000),
-                       ]), 100_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       ]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].len(), 1);
 
@@ -4647,10 +4875,10 @@ mod tests {
                        assert_eq!(route.paths[0][0].fee_msat, 100_000);
                }
                {
-                       let route = get_route(&our_id, &payment_params, &network_graph, Some(&[
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
                                &get_channel_details(Some(3), nodes[0], InitFeatures::known(), 50_000),
                                &get_channel_details(Some(2), nodes[0], InitFeatures::known(), 50_000),
-                       ]), 100_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       ]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
                        assert_eq!(route.paths[0].len(), 1);
                        assert_eq!(route.paths[1].len(), 1);
@@ -4673,9 +4901,11 @@ mod tests {
 
                // Without penalizing each hop 100 msats, a longer path with lower fees is chosen.
                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 route = get_route(
-                       &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       &our_id, &payment_params, &network_graph.read_only(), None, 100, 42,
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -4687,8 +4917,8 @@ mod tests {
                // from nodes[2] rather than channel 6, 11, and 8, even though the longer path is cheaper.
                let scorer = test_utils::TestScorer::with_penalty(100);
                let route = get_route(
-                       &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       &our_id, &payment_params, &network_graph.read_only(), None, 100, 42,
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -4734,15 +4964,18 @@ mod tests {
 
        #[test]
        fn avoids_routing_through_bad_channels_and_nodes() {
-               let (secp_ctx, network_graph, _, _, logger) = build_graph();
+               let (secp_ctx, network, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes));
+               let network_graph = network.read_only();
 
                // A path to nodes[6] exists when no penalties are applied to any channel.
                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 route = get_route(
                        &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -4754,7 +4987,7 @@ mod tests {
                let scorer = BadChannelScorer { short_channel_id: 6 };
                let route = get_route(
                        &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -4766,7 +4999,7 @@ mod tests {
                let scorer = BadNodeScorer { node_id: NodeId::from_pubkey(&nodes[2]) };
                match get_route(
                        &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ) {
                        Err(LightningError { err, .. } ) => {
                                assert_eq!(err, "Failed to find a path to the given destination");
@@ -4848,8 +5081,9 @@ mod tests {
 
        #[test]
        fn limits_total_cltv_delta() {
-               let (secp_ctx, network_graph, _, _, logger) = build_graph();
+               let (secp_ctx, network, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+               let network_graph = network.read_only();
 
                let scorer = test_utils::TestScorer::with_penalty(0);
 
@@ -4857,7 +5091,9 @@ mod tests {
                let feasible_max_total_cltv_delta = 1008;
                let feasible_payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
                        .with_max_total_cltv_expiry_delta(feasible_max_total_cltv_delta);
-               let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+               let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
                assert_ne!(path.len(), 0);
 
@@ -4865,7 +5101,7 @@ mod tests {
                let fail_max_total_cltv_delta = 23;
                let fail_payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
                        .with_max_total_cltv_expiry_delta(fail_max_total_cltv_delta);
-               match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer)
+               match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes)
                {
                        Err(LightningError { err, .. } ) => {
                                assert_eq!(err, "Failed to find a path to the given destination");
@@ -4874,6 +5110,106 @@ mod tests {
                }
        }
 
+       #[test]
+       fn adds_and_limits_cltv_offset() {
+               let (secp_ctx, network_graph, _, _, logger) = build_graph();
+               let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+
+               let scorer = test_utils::TestScorer::with_penalty(0);
+
+               let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes));
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               assert_eq!(route.paths.len(), 1);
+
+               let cltv_expiry_deltas_before = route.paths[0].iter().map(|h| h.cltv_expiry_delta).collect::<Vec<u32>>();
+
+               // Check whether the offset added to the last hop by default is in [1 .. DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA]
+               let mut route_default = route.clone();
+               add_random_cltv_offset(&mut route_default, &payment_params, &network_graph.read_only(), &random_seed_bytes);
+               let cltv_expiry_deltas_default = route_default.paths[0].iter().map(|h| h.cltv_expiry_delta).collect::<Vec<u32>>();
+               assert_eq!(cltv_expiry_deltas_before.split_last().unwrap().1, cltv_expiry_deltas_default.split_last().unwrap().1);
+               assert!(cltv_expiry_deltas_default.last() > cltv_expiry_deltas_before.last());
+               assert!(cltv_expiry_deltas_default.last().unwrap() <= &DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA);
+
+               // Check that no offset is added when we restrict the max_total_cltv_expiry_delta
+               let mut route_limited = route.clone();
+               let limited_max_total_cltv_expiry_delta = cltv_expiry_deltas_before.iter().sum();
+               let limited_payment_params = payment_params.with_max_total_cltv_expiry_delta(limited_max_total_cltv_expiry_delta);
+               add_random_cltv_offset(&mut route_limited, &limited_payment_params, &network_graph.read_only(), &random_seed_bytes);
+               let cltv_expiry_deltas_limited = route_limited.paths[0].iter().map(|h| h.cltv_expiry_delta).collect::<Vec<u32>>();
+               assert_eq!(cltv_expiry_deltas_before, cltv_expiry_deltas_limited);
+       }
+
+       #[test]
+       fn adds_plausible_cltv_offset() {
+               let (secp_ctx, network, _, _, logger) = build_graph();
+               let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+               let network_graph = network.read_only();
+               let network_nodes = network_graph.nodes();
+               let network_channels = network_graph.channels();
+               let scorer = test_utils::TestScorer::with_penalty(0);
+               let payment_params = PaymentParameters::from_node_id(nodes[3]);
+               let keys_manager = test_utils::TestKeysInterface::new(&[4u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+
+               let mut route = get_route(&our_id, &payment_params, &network_graph, None, 100, 0,
+                                                                 Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               add_random_cltv_offset(&mut route, &payment_params, &network_graph, &random_seed_bytes);
+
+               let mut path_plausibility = vec![];
+
+               for p in route.paths {
+                       // 1. Select random observation point
+                       let mut prng = ChaCha20::new(&random_seed_bytes, &[0u8; 12]);
+                       let mut random_bytes = [0u8; ::core::mem::size_of::<usize>()];
+
+                       prng.process_in_place(&mut random_bytes);
+                       let random_path_index = usize::from_be_bytes(random_bytes).wrapping_rem(p.len());
+                       let observation_point = NodeId::from_pubkey(&p.get(random_path_index).unwrap().pubkey);
+
+                       // 2. Calculate what CLTV expiry delta we would observe there
+                       let observed_cltv_expiry_delta: u32 = p[random_path_index..].iter().map(|h| h.cltv_expiry_delta).sum();
+
+                       // 3. Starting from the observation point, find candidate paths
+                       let mut candidates: VecDeque<(NodeId, Vec<u32>)> = VecDeque::new();
+                       candidates.push_back((observation_point, vec![]));
+
+                       let mut found_plausible_candidate = false;
+
+                       'candidate_loop: while let Some((cur_node_id, cur_path_cltv_deltas)) = candidates.pop_front() {
+                               if let Some(remaining) = observed_cltv_expiry_delta.checked_sub(cur_path_cltv_deltas.iter().sum::<u32>()) {
+                                       if remaining == 0 || remaining.wrapping_rem(40) == 0 || remaining.wrapping_rem(144) == 0 {
+                                               found_plausible_candidate = true;
+                                               break 'candidate_loop;
+                                       }
+                               }
+
+                               if let Some(cur_node) = network_nodes.get(&cur_node_id) {
+                                       for channel_id in &cur_node.channels {
+                                               if let Some(channel_info) = network_channels.get(&channel_id) {
+                                                       if let Some((dir_info, next_id)) = channel_info.as_directed_from(&cur_node_id) {
+                                                               if let Some(channel_update_info) = dir_info.direction() {
+                                                                       let next_cltv_expiry_delta = channel_update_info.cltv_expiry_delta as u32;
+                                                                       if cur_path_cltv_deltas.iter().sum::<u32>()
+                                                                               .saturating_add(next_cltv_expiry_delta) <= observed_cltv_expiry_delta {
+                                                                               let mut new_path_cltv_deltas = cur_path_cltv_deltas.clone();
+                                                                               new_path_cltv_deltas.push(next_cltv_expiry_delta);
+                                                                               candidates.push_back((*next_id, new_path_cltv_deltas));
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       path_plausibility.push(found_plausible_candidate);
+               }
+               assert!(path_plausibility.iter().all(|x| *x));
+       }
+
        #[cfg(not(feature = "no-std"))]
        pub(super) fn random_init_seed() -> u64 {
                // Because the default HashMap in std pulls OS randomness, we can use it as a (bad) RNG.
@@ -4888,6 +5224,8 @@ mod tests {
        #[test]
        #[cfg(not(feature = "no-std"))]
        fn generate_routes() {
+               use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+
                let mut d = match super::test_utils::get_route_file() {
                        Ok(f) => f,
                        Err(e) => {
@@ -4896,6 +5234,8 @@ mod tests {
                        },
                };
                let graph = NetworkGraph::read(&mut d).unwrap();
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut seed = random_init_seed() as usize;
@@ -4910,7 +5250,7 @@ mod tests {
                                let amt = seed as u64 % 200_000_000;
                                let params = ProbabilisticScoringParameters::default();
                                let scorer = ProbabilisticScorer::new(params, &graph);
-                               if get_route(src, &payment_params, &graph, None, amt, 42, &test_utils::TestLogger::new(), &scorer).is_ok() {
+                               if get_route(src, &payment_params, &graph.read_only(), None, amt, 42, &test_utils::TestLogger::new(), &scorer, &random_seed_bytes).is_ok() {
                                        continue 'load_endpoints;
                                }
                        }
@@ -4920,6 +5260,8 @@ mod tests {
        #[test]
        #[cfg(not(feature = "no-std"))]
        fn generate_routes_mpp() {
+               use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+
                let mut d = match super::test_utils::get_route_file() {
                        Ok(f) => f,
                        Err(e) => {
@@ -4928,6 +5270,8 @@ mod tests {
                        },
                };
                let graph = NetworkGraph::read(&mut d).unwrap();
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut seed = random_init_seed() as usize;
@@ -4942,7 +5286,7 @@ mod tests {
                                let amt = seed as u64 % 200_000_000;
                                let params = ProbabilisticScoringParameters::default();
                                let scorer = ProbabilisticScorer::new(params, &graph);
-                               if get_route(src, &payment_params, &graph, None, amt, 42, &test_utils::TestLogger::new(), &scorer).is_ok() {
+                               if get_route(src, &payment_params, &graph.read_only(), None, amt, 42, &test_utils::TestLogger::new(), &scorer, &random_seed_bytes).is_ok() {
                                        continue 'load_endpoints;
                                }
                        }
@@ -4983,6 +5327,7 @@ mod benches {
        use bitcoin::hashes::Hash;
        use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
        use chain::transaction::OutPoint;
+       use chain::keysinterface::{KeysManager,KeysInterface};
        use ln::channelmanager::{ChannelCounterparty, ChannelDetails};
        use ln::features::{InitFeatures, InvoiceFeatures};
        use routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringParameters, Scorer};
@@ -5019,6 +5364,7 @@ mod benches {
                                txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0
                        }),
                        short_channel_id: Some(1),
+                       inbound_scid_alias: None,
                        channel_value_satoshis: 10_000_000,
                        user_channel_id: 0,
                        balance_msat: 10_000_000,
@@ -5083,6 +5429,8 @@ mod benches {
        ) {
                let nodes = graph.read_only().nodes().clone();
                let payer = payer_pubkey();
+               let keys_manager = KeysManager::new(&[0u8; 32], 42, 42);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut routes = Vec::new();
@@ -5097,7 +5445,7 @@ mod benches {
                                let params = PaymentParameters::from_node_id(dst).with_features(features.clone());
                                let first_hop = first_hop(src);
                                let amt = seed as u64 % 1_000_000;
-                               if let Ok(route) = get_route(&payer, &params, &graph, Some(&[&first_hop]), amt, 42, &DummyLogger{}, &scorer) {
+                               if let Ok(route) = get_route(&payer, &params, &graph.read_only(), Some(&[&first_hop]), amt, 42, &DummyLogger{}, &scorer, &random_seed_bytes) {
                                        routes.push(route);
                                        route_endpoints.push((first_hop, params, amt));
                                        continue 'load_endpoints;
@@ -5124,7 +5472,7 @@ mod benches {
                let mut idx = 0;
                bench.iter(|| {
                        let (first_hop, params, amt) = &route_endpoints[idx % route_endpoints.len()];
-                       assert!(get_route(&payer, params, &graph, Some(&[first_hop]), *amt, 42, &DummyLogger{}, &scorer).is_ok());
+                       assert!(get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, 42, &DummyLogger{}, &scorer, &random_seed_bytes).is_ok());
                        idx += 1;
                });
        }
index b02b61fa9f6c0381fe9fd7ffcad4eedd23656be5..c39abd1d0ff71d2f613935959007b333204371b2 100644 (file)
@@ -20,6 +20,7 @@
 //! # use lightning::routing::network_graph::NetworkGraph;
 //! # use lightning::routing::router::{RouteParameters, find_route};
 //! # use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters, Scorer, ScoringParameters};
+//! # use lightning::chain::keysinterface::{KeysManager, KeysInterface};
 //! # use lightning::util::logger::{Logger, Record};
 //! # use secp256k1::key::PublicKey;
 //! #
@@ -40,8 +41,9 @@
 //!     ..ProbabilisticScoringParameters::default()
 //! };
 //! let scorer = ProbabilisticScorer::new(params, &network_graph);
+//! # let random_seed_bytes = [42u8; 32];
 //!
-//! let route = find_route(&payer, &route_params, &network_graph, None, &logger, &scorer);
+//! let route = find_route(&payer, &route_params, &network_graph, None, &logger, &scorer, &random_seed_bytes);
 //! # }
 //! ```
 //!
@@ -189,6 +191,7 @@ impl<'a, S: Writeable> Writeable for MutexGuard<'a, S> {
        }
 }
 
+#[derive(Clone)]
 /// [`Score`] implementation that uses a fixed penalty.
 pub struct FixedPenaltyScorer {
        penalty_msat: u64,
@@ -246,13 +249,13 @@ type ConfiguredTime = time::Eternity;
 /// [`Score`] implementation.
 ///
 /// (C-not exported) generally all users should use the [`Scorer`] type alias.
-#[doc(hidden)]
 pub struct ScorerUsingTime<T: Time> {
        params: ScoringParameters,
        // TODO: Remove entries of closed channels.
        channel_failures: HashMap<u64, ChannelFailure<T>>,
 }
 
+#[derive(Clone)]
 /// Parameters for configuring [`Scorer`].
 pub struct ScoringParameters {
        /// A fixed penalty in msats to apply to each channel.
@@ -493,7 +496,6 @@ pub type ProbabilisticScorer<G> = ProbabilisticScorerUsingTime::<G, ConfiguredTi
 /// Probabilistic [`Score`] implementation.
 ///
 /// (C-not exported) generally all users should use the [`ProbabilisticScorer`] type alias.
-#[doc(hidden)]
 pub struct ProbabilisticScorerUsingTime<G: Deref<Target = NetworkGraph>, T: Time> {
        params: ProbabilisticScoringParameters,
        network_graph: G,
@@ -648,20 +650,23 @@ impl<T: Time> ChannelLiquidity<T> {
 }
 
 impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<L, T, U> {
-       /// Returns the success probability of routing the given HTLC `amount_msat` through the channel
-       /// in this direction.
-       fn success_probability(&self, amount_msat: u64) -> f64 {
+       /// Returns a penalty for routing the given HTLC `amount_msat` through the channel in this
+       /// direction.
+       fn penalty_msat(&self, amount_msat: u64, liquidity_penalty_multiplier_msat: u64) -> u64 {
                let max_liquidity_msat = self.max_liquidity_msat();
                let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
                if amount_msat > max_liquidity_msat {
-                       0.0
+                       u64::max_value()
                } else if amount_msat <= min_liquidity_msat {
-                       1.0
+                       0
                } else {
                        let numerator = max_liquidity_msat + 1 - amount_msat;
                        let denominator = max_liquidity_msat + 1 - min_liquidity_msat;
-                       numerator as f64 / denominator as f64
-               }.max(0.01) // Lower bound the success probability to ensure some channel is selected.
+                       approx::negative_log10_times_1024(numerator, denominator)
+                               .saturating_mul(liquidity_penalty_multiplier_msat) / 1024
+               }
+               // Upper bound the penalty to ensure some channel is selected.
+               .min(2 * liquidity_penalty_multiplier_msat)
        }
 
        /// Returns the lower bound of the channel liquidity balance in this direction.
@@ -735,15 +740,11 @@ impl<G: Deref<Target = NetworkGraph>, T: Time> Score for ProbabilisticScorerUsin
        ) -> u64 {
                let liquidity_penalty_multiplier_msat = self.params.liquidity_penalty_multiplier_msat;
                let liquidity_offset_half_life = self.params.liquidity_offset_half_life;
-               let success_probability = self.channel_liquidities
+               self.channel_liquidities
                        .get(&short_channel_id)
                        .unwrap_or(&ChannelLiquidity::new())
                        .as_directed(source, target, capacity_msat, liquidity_offset_half_life)
-                       .success_probability(amount_msat);
-               // NOTE: If success_probability is ever changed to return 0.0, log10 is undefined so return
-               // u64::max_value instead.
-               debug_assert!(success_probability > core::f64::EPSILON);
-               (-(success_probability.log10()) * liquidity_penalty_multiplier_msat as f64) as u64
+                       .penalty_msat(amount_msat, liquidity_penalty_multiplier_msat)
        }
 
        fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
@@ -800,6 +801,122 @@ impl<G: Deref<Target = NetworkGraph>, T: Time> Score for ProbabilisticScorerUsin
        }
 }
 
+mod approx {
+       const BITS: u32 = 64;
+       const HIGHEST_BIT: u32 = BITS - 1;
+       const LOWER_BITS: u32 = 4;
+       const LOWER_BITS_BOUND: u64 = 1 << LOWER_BITS;
+       const LOWER_BITMASK: u64 = (1 << LOWER_BITS) - 1;
+
+       /// Look-up table for `log10(x) * 1024` where row `i` is used for each `x` having `i` as the
+       /// most significant bit. The next 4 bits of `x`, if applicable, are used for the second index.
+       const LOG10_TIMES_1024: [[u16; LOWER_BITS_BOUND as usize]; BITS as usize] = [
+               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+               [308, 308, 308, 308, 308, 308, 308, 308, 489, 489, 489, 489, 489, 489, 489, 489],
+               [617, 617, 617, 617, 716, 716, 716, 716, 797, 797, 797, 797, 865, 865, 865, 865],
+               [925, 925, 977, 977, 1024, 1024, 1066, 1066, 1105, 1105, 1141, 1141, 1174, 1174, 1204, 1204],
+               [1233, 1260, 1285, 1309, 1332, 1354, 1375, 1394, 1413, 1431, 1449, 1466, 1482, 1497, 1513, 1527],
+               [1541, 1568, 1594, 1618, 1641, 1662, 1683, 1703, 1722, 1740, 1757, 1774, 1790, 1806, 1821, 1835],
+               [1850, 1876, 1902, 1926, 1949, 1970, 1991, 2011, 2030, 2048, 2065, 2082, 2098, 2114, 2129, 2144],
+               [2158, 2185, 2210, 2234, 2257, 2279, 2299, 2319, 2338, 2356, 2374, 2390, 2407, 2422, 2437, 2452],
+               [2466, 2493, 2518, 2542, 2565, 2587, 2608, 2627, 2646, 2665, 2682, 2699, 2715, 2731, 2746, 2760],
+               [2774, 2801, 2827, 2851, 2874, 2895, 2916, 2936, 2955, 2973, 2990, 3007, 3023, 3039, 3054, 3068],
+               [3083, 3110, 3135, 3159, 3182, 3203, 3224, 3244, 3263, 3281, 3298, 3315, 3331, 3347, 3362, 3377],
+               [3391, 3418, 3443, 3467, 3490, 3512, 3532, 3552, 3571, 3589, 3607, 3623, 3640, 3655, 3670, 3685],
+               [3699, 3726, 3751, 3775, 3798, 3820, 3841, 3860, 3879, 3898, 3915, 3932, 3948, 3964, 3979, 3993],
+               [4007, 4034, 4060, 4084, 4107, 4128, 4149, 4169, 4188, 4206, 4223, 4240, 4256, 4272, 4287, 4301],
+               [4316, 4343, 4368, 4392, 4415, 4436, 4457, 4477, 4496, 4514, 4531, 4548, 4564, 4580, 4595, 4610],
+               [4624, 4651, 4676, 4700, 4723, 4745, 4765, 4785, 4804, 4822, 4840, 4857, 4873, 4888, 4903, 4918],
+               [4932, 4959, 4984, 5009, 5031, 5053, 5074, 5093, 5112, 5131, 5148, 5165, 5181, 5197, 5212, 5226],
+               [5240, 5267, 5293, 5317, 5340, 5361, 5382, 5402, 5421, 5439, 5456, 5473, 5489, 5505, 5520, 5534],
+               [5549, 5576, 5601, 5625, 5648, 5670, 5690, 5710, 5729, 5747, 5764, 5781, 5797, 5813, 5828, 5843],
+               [5857, 5884, 5909, 5933, 5956, 5978, 5998, 6018, 6037, 6055, 6073, 6090, 6106, 6121, 6136, 6151],
+               [6165, 6192, 6217, 6242, 6264, 6286, 6307, 6326, 6345, 6364, 6381, 6398, 6414, 6430, 6445, 6459],
+               [6473, 6500, 6526, 6550, 6573, 6594, 6615, 6635, 6654, 6672, 6689, 6706, 6722, 6738, 6753, 6767],
+               [6782, 6809, 6834, 6858, 6881, 6903, 6923, 6943, 6962, 6980, 6998, 7014, 7030, 7046, 7061, 7076],
+               [7090, 7117, 7142, 7166, 7189, 7211, 7231, 7251, 7270, 7288, 7306, 7323, 7339, 7354, 7369, 7384],
+               [7398, 7425, 7450, 7475, 7497, 7519, 7540, 7560, 7578, 7597, 7614, 7631, 7647, 7663, 7678, 7692],
+               [7706, 7733, 7759, 7783, 7806, 7827, 7848, 7868, 7887, 7905, 7922, 7939, 7955, 7971, 7986, 8001],
+               [8015, 8042, 8067, 8091, 8114, 8136, 8156, 8176, 8195, 8213, 8231, 8247, 8263, 8279, 8294, 8309],
+               [8323, 8350, 8375, 8399, 8422, 8444, 8464, 8484, 8503, 8521, 8539, 8556, 8572, 8587, 8602, 8617],
+               [8631, 8658, 8684, 8708, 8730, 8752, 8773, 8793, 8811, 8830, 8847, 8864, 8880, 8896, 8911, 8925],
+               [8939, 8966, 8992, 9016, 9039, 9060, 9081, 9101, 9120, 9138, 9155, 9172, 9188, 9204, 9219, 9234],
+               [9248, 9275, 9300, 9324, 9347, 9369, 9389, 9409, 9428, 9446, 9464, 9480, 9497, 9512, 9527, 9542],
+               [9556, 9583, 9608, 9632, 9655, 9677, 9698, 9717, 9736, 9754, 9772, 9789, 9805, 9820, 9835, 9850],
+               [9864, 9891, 9917, 9941, 9963, 9985, 10006, 10026, 10044, 10063, 10080, 10097, 10113, 10129, 10144, 10158],
+               [10172, 10199, 10225, 10249, 10272, 10293, 10314, 10334, 10353, 10371, 10388, 10405, 10421, 10437, 10452, 10467],
+               [10481, 10508, 10533, 10557, 10580, 10602, 10622, 10642, 10661, 10679, 10697, 10713, 10730, 10745, 10760, 10775],
+               [10789, 10816, 10841, 10865, 10888, 10910, 10931, 10950, 10969, 10987, 11005, 11022, 11038, 11053, 11068, 11083],
+               [11097, 11124, 11150, 11174, 11196, 11218, 11239, 11259, 11277, 11296, 11313, 11330, 11346, 11362, 11377, 11391],
+               [11405, 11432, 11458, 11482, 11505, 11526, 11547, 11567, 11586, 11604, 11621, 11638, 11654, 11670, 11685, 11700],
+               [11714, 11741, 11766, 11790, 11813, 11835, 11855, 11875, 11894, 11912, 11930, 11946, 11963, 11978, 11993, 12008],
+               [12022, 12049, 12074, 12098, 12121, 12143, 12164, 12183, 12202, 12220, 12238, 12255, 12271, 12286, 12301, 12316],
+               [12330, 12357, 12383, 12407, 12429, 12451, 12472, 12492, 12511, 12529, 12546, 12563, 12579, 12595, 12610, 12624],
+               [12638, 12665, 12691, 12715, 12738, 12759, 12780, 12800, 12819, 12837, 12854, 12871, 12887, 12903, 12918, 12933],
+               [12947, 12974, 12999, 13023, 13046, 13068, 13088, 13108, 13127, 13145, 13163, 13179, 13196, 13211, 13226, 13241],
+               [13255, 13282, 13307, 13331, 13354, 13376, 13397, 13416, 13435, 13453, 13471, 13488, 13504, 13519, 13535, 13549],
+               [13563, 13590, 13616, 13640, 13662, 13684, 13705, 13725, 13744, 13762, 13779, 13796, 13812, 13828, 13843, 13857],
+               [13871, 13898, 13924, 13948, 13971, 13992, 14013, 14033, 14052, 14070, 14087, 14104, 14120, 14136, 14151, 14166],
+               [14180, 14207, 14232, 14256, 14279, 14301, 14321, 14341, 14360, 14378, 14396, 14412, 14429, 14444, 14459, 14474],
+               [14488, 14515, 14540, 14564, 14587, 14609, 14630, 14649, 14668, 14686, 14704, 14721, 14737, 14752, 14768, 14782],
+               [14796, 14823, 14849, 14873, 14895, 14917, 14938, 14958, 14977, 14995, 15012, 15029, 15045, 15061, 15076, 15090],
+               [15104, 15131, 15157, 15181, 15204, 15225, 15246, 15266, 15285, 15303, 15320, 15337, 15353, 15369, 15384, 15399],
+               [15413, 15440, 15465, 15489, 15512, 15534, 15554, 15574, 15593, 15611, 15629, 15645, 15662, 15677, 15692, 15707],
+               [15721, 15748, 15773, 15797, 15820, 15842, 15863, 15882, 15901, 15919, 15937, 15954, 15970, 15985, 16001, 16015],
+               [16029, 16056, 16082, 16106, 16128, 16150, 16171, 16191, 16210, 16228, 16245, 16262, 16278, 16294, 16309, 16323],
+               [16337, 16364, 16390, 16414, 16437, 16458, 16479, 16499, 16518, 16536, 16553, 16570, 16586, 16602, 16617, 16632],
+               [16646, 16673, 16698, 16722, 16745, 16767, 16787, 16807, 16826, 16844, 16862, 16878, 16895, 16910, 16925, 16940],
+               [16954, 16981, 17006, 17030, 17053, 17075, 17096, 17115, 17134, 17152, 17170, 17187, 17203, 17218, 17234, 17248],
+               [17262, 17289, 17315, 17339, 17361, 17383, 17404, 17424, 17443, 17461, 17478, 17495, 17511, 17527, 17542, 17556],
+               [17571, 17597, 17623, 17647, 17670, 17691, 17712, 17732, 17751, 17769, 17786, 17803, 17819, 17835, 17850, 17865],
+               [17879, 17906, 17931, 17955, 17978, 18000, 18020, 18040, 18059, 18077, 18095, 18111, 18128, 18143, 18158, 18173],
+               [18187, 18214, 18239, 18263, 18286, 18308, 18329, 18348, 18367, 18385, 18403, 18420, 18436, 18452, 18467, 18481],
+               [18495, 18522, 18548, 18572, 18595, 18616, 18637, 18657, 18676, 18694, 18711, 18728, 18744, 18760, 18775, 18789],
+               [18804, 18830, 18856, 18880, 18903, 18924, 18945, 18965, 18984, 19002, 19019, 19036, 19052, 19068, 19083, 19098],
+               [19112, 19139, 19164, 19188, 19211, 19233, 19253, 19273, 19292, 19310, 19328, 19344, 19361, 19376, 19391, 19406],
+               [19420, 19447, 19472, 19496, 19519, 19541, 19562, 19581, 19600, 19619, 19636, 19653, 19669, 19685, 19700, 19714],
+       ];
+
+       /// Approximate `log10(numerator / denominator) * 1024` using a look-up table.
+       #[inline]
+       pub fn negative_log10_times_1024(numerator: u64, denominator: u64) -> u64 {
+               // Multiply the -1 through to avoid needing to use signed numbers.
+               (log10_times_1024(denominator) - log10_times_1024(numerator)) as u64
+       }
+
+       #[inline]
+       fn log10_times_1024(x: u64) -> u16 {
+               debug_assert_ne!(x, 0);
+               let most_significant_bit = HIGHEST_BIT - x.leading_zeros();
+               let lower_bits = (x >> most_significant_bit.saturating_sub(LOWER_BITS)) & LOWER_BITMASK;
+               LOG10_TIMES_1024[most_significant_bit as usize][lower_bits as usize]
+       }
+
+       #[cfg(test)]
+       mod tests {
+               use super::*;
+
+               #[test]
+               fn prints_negative_log10_times_1024_lookup_table() {
+                       for msb in 0..BITS {
+                               for i in 0..LOWER_BITS_BOUND {
+                                       let x = ((LOWER_BITS_BOUND + i) << (HIGHEST_BIT - LOWER_BITS)) >> (HIGHEST_BIT - msb);
+                                       let log10_times_1024 = ((x as f64).log10() * 1024.0).round() as u16;
+                                       assert_eq!(log10_times_1024, LOG10_TIMES_1024[msb as usize][i as usize]);
+
+                                       if i % LOWER_BITS_BOUND == 0 {
+                                               print!("\t\t[{}, ", log10_times_1024);
+                                       } else if i % LOWER_BITS_BOUND == LOWER_BITS_BOUND - 1 {
+                                               println!("{}],", log10_times_1024);
+                                       } else {
+                                               print!("{}, ", log10_times_1024);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
 impl<G: Deref<Target = NetworkGraph>, T: Time> Writeable for ProbabilisticScorerUsingTime<G, T> {
        #[inline]
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
@@ -1614,18 +1731,18 @@ mod tests {
                let source = source_node_id();
                let target = target_node_id();
 
-               assert_eq!(scorer.channel_penalty_msat(42, 100, 100_000, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 1_000, 100_000, &source, &target), 4);
-               assert_eq!(scorer.channel_penalty_msat(42, 10_000, 100_000, &source, &target), 45);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000, 100_000, &source, &target), 2_000);
+               assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024_000, &source, &target), 0);
+               assert_eq!(scorer.channel_penalty_msat(42, 10_240, 1_024_000, &source, &target), 14);
+               assert_eq!(scorer.channel_penalty_msat(42, 102_400, 1_024_000, &source, &target), 43);
+               assert_eq!(scorer.channel_penalty_msat(42, 1_024_000, 1_024_000, &source, &target), 2_000);
 
-               assert_eq!(scorer.channel_penalty_msat(42, 125, 1_000, &source, &target), 57);
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 124);
-               assert_eq!(scorer.channel_penalty_msat(42, 375, 1_000, &source, &target), 203);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300);
-               assert_eq!(scorer.channel_penalty_msat(42, 625, 1_000, &source, &target), 425);
-               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 600);
-               assert_eq!(scorer.channel_penalty_msat(42, 875, 1_000, &source, &target), 900);
+               assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 58);
+               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125);
+               assert_eq!(scorer.channel_penalty_msat(42, 374, 1_024, &source, &target), 204);
+               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 301);
+               assert_eq!(scorer.channel_penalty_msat(42, 640, 1_024, &source, &target), 426);
+               assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 602);
+               assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 903);
        }
 
        #[test]
@@ -1681,9 +1798,9 @@ mod tests {
                let target = target_node_id();
                let path = payment_path_for_amount(500);
 
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 124);
+               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 128);
                assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300);
-               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 600);
+               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 601);
 
                scorer.payment_path_failed(&path.iter().collect::<Vec<_>>(), 43);
 
@@ -1703,9 +1820,9 @@ mod tests {
                let target = target_node_id();
                let path = payment_path_for_amount(500);
 
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 124);
+               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 128);
                assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300);
-               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 600);
+               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 601);
 
                scorer.payment_path_failed(&path.iter().collect::<Vec<_>>(), 42);
 
@@ -1727,13 +1844,13 @@ mod tests {
                let recipient = recipient_node_id();
                let path = payment_path_for_amount(500);
 
-               assert_eq!(scorer.channel_penalty_msat(41, 250, 1_000, &sender, &source), 124);
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 124);
-               assert_eq!(scorer.channel_penalty_msat(43, 250, 1_000, &target, &recipient), 124);
+               assert_eq!(scorer.channel_penalty_msat(41, 250, 1_000, &sender, &source), 128);
+               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 128);
+               assert_eq!(scorer.channel_penalty_msat(43, 250, 1_000, &target, &recipient), 128);
 
                scorer.payment_path_successful(&path.iter().collect::<Vec<_>>());
 
-               assert_eq!(scorer.channel_penalty_msat(41, 250, 1_000, &sender, &source), 124);
+               assert_eq!(scorer.channel_penalty_msat(41, 250, 1_000, &sender, &source), 128);
                assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 300);
                assert_eq!(scorer.channel_penalty_msat(43, 250, 1_000, &target, &recipient), 300);
        }
@@ -1756,20 +1873,20 @@ mod tests {
                scorer.payment_path_failed(&payment_path_for_amount(128).iter().collect::<Vec<_>>(), 43);
 
                assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 92);
-               assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_424);
+               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 97);
+               assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_409);
                assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 2_000);
 
                SinceEpoch::advance(Duration::from_secs(9));
                assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 92);
-               assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_424);
+               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 97);
+               assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_409);
                assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 2_000);
 
                SinceEpoch::advance(Duration::from_secs(1));
                assert_eq!(scorer.channel_penalty_msat(42, 64, 1_024, &source, &target), 0);
                assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 34);
-               assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 1_812);
+               assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 1_773);
                assert_eq!(scorer.channel_penalty_msat(42, 960, 1_024, &source, &target), 2_000);
 
                // Fully decay liquidity lower bound.
@@ -1799,18 +1916,18 @@ mod tests {
                let mut scorer = ProbabilisticScorer::new(params, &network_graph);
                let source = source_node_id();
                let target = target_node_id();
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 124);
+               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125);
 
                scorer.payment_path_failed(&payment_path_for_amount(512).iter().collect::<Vec<_>>(), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 281);
+               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 274);
 
                // An unchecked right shift 64 bits or more in DirectedChannelLiquidity::decayed_offset_msat
                // would cause an overflow.
                SinceEpoch::advance(Duration::from_secs(10 * 64));
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 124);
+               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 124);
+               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125);
        }
 
        #[test]
@@ -1824,30 +1941,30 @@ mod tests {
                let source = source_node_id();
                let target = target_node_id();
 
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 301);
 
                // More knowledge gives higher confidence (256, 768), meaning a lower penalty.
                scorer.payment_path_failed(&payment_path_for_amount(768).iter().collect::<Vec<_>>(), 42);
                scorer.payment_path_failed(&payment_path_for_amount(256).iter().collect::<Vec<_>>(), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 281);
+               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 274);
 
                // Decaying knowledge gives less confidence (128, 896), meaning a higher penalty.
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 293);
+               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 301);
 
                // Reducing the upper bound gives more confidence (128, 832) that the payment amount (512)
                // is closer to the upper bound, meaning a higher penalty.
                scorer.payment_path_successful(&payment_path_for_amount(64).iter().collect::<Vec<_>>());
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 333);
+               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 342);
 
                // Increasing the lower bound gives more confidence (256, 832) that the payment amount (512)
                // is closer to the lower bound, meaning a lower penalty.
                scorer.payment_path_failed(&payment_path_for_amount(256).iter().collect::<Vec<_>>(), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 247);
+               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 255);
 
                // Further decaying affects the lower bound more than the upper bound (128, 928).
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 280);
+               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 284);
        }
 
        #[test]
@@ -1865,7 +1982,7 @@ mod tests {
                assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 2_000);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 475);
+               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 472);
 
                scorer.payment_path_failed(&payment_path_for_amount(250).iter().collect::<Vec<_>>(), 43);
                assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300);
@@ -1901,12 +2018,12 @@ mod tests {
                let mut serialized_scorer = io::Cursor::new(&serialized_scorer);
                let deserialized_scorer =
                        <ProbabilisticScorer>::read(&mut serialized_scorer, (params, &network_graph)).unwrap();
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 475);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 472);
 
                scorer.payment_path_failed(&payment_path_for_amount(250).iter().collect::<Vec<_>>(), 43);
                assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 367);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 371);
        }
 }
index 8c9f5af4c0bf52cd9c2ea51cb2432373bea3b457..3b90015cab901bd0ba72586ffad37dd65d3be711 100644 (file)
@@ -235,7 +235,7 @@ pub enum Event {
        /// Note that this does *not* indicate that all paths for an MPP payment have failed, see
        /// [`Event::PaymentFailed`] and [`all_paths_failed`].
        ///
-       /// [`all_paths_failed`]: Self::all_paths_failed
+       /// [`all_paths_failed`]: Self::PaymentPathFailed::all_paths_failed
        PaymentPathFailed {
                /// The id returned by [`ChannelManager::send_payment`] and used with
                /// [`ChannelManager::retry_payment`] and [`ChannelManager::abandon_payment`].
index f9dfd1b0320cb8308d91489928f3bdc1503504e0..8552358c35ae8d8fe8532f66cd9346409405c2c5 100644 (file)
@@ -61,7 +61,7 @@ pub fn scid_from_parts(block: u64, tx_index: u64, vout_index: u64) -> Result<u64
 }
 
 /// LDK has multiple reasons to generate fake short channel ids:
-/// 1) zero-conf channels that don't have a confirmed channel id yet
+/// 1) outbound SCID aliases we use for private channels
 /// 2) phantom node payments, to get an scid for the phantom node's phantom channel
 pub(crate) mod fake_scid {
        use bitcoin::hash_types::BlockHash;
@@ -84,9 +84,9 @@ pub(crate) mod fake_scid {
        /// receipt, and handle the HTLC accordingly. The namespace identifier is encrypted when encoded
        /// into the fake scid.
        #[derive(Copy, Clone)]
-       pub(super) enum Namespace {
+       pub(crate) enum Namespace {
                Phantom,
-               // Coming soon: a variant for the zero-conf scid namespace
+               OutboundAlias,
        }
 
        impl Namespace {
@@ -94,7 +94,7 @@ pub(crate) mod fake_scid {
                /// between segwit activation and the current best known height, and the tx index and output
                /// index are also selected from a "reasonable" range. We add this logic because it makes it
                /// non-obvious at a glance that the scid is fake, e.g. if it appears in invoice route hints.
-               pub(super) fn get_fake_scid<Signer: Sign, K: Deref>(&self, highest_seen_blockheight: u32, genesis_hash: &BlockHash, fake_scid_rand_bytes: &[u8; 32], keys_manager: &K) -> u64
+               pub(crate) fn get_fake_scid<Signer: Sign, K: Deref>(&self, highest_seen_blockheight: u32, genesis_hash: &BlockHash, fake_scid_rand_bytes: &[u8; 32], keys_manager: &K) -> u64
                        where K::Target: KeysInterface<Signer = Signer>,
                {
                        // Ensure we haven't created a namespace that doesn't fit into the 3 bits we've allocated for
@@ -104,18 +104,15 @@ pub(crate) mod fake_scid {
                        let rand_bytes = keys_manager.get_secure_random_bytes();
 
                        let segwit_activation_height = segwit_activation_height(genesis_hash);
-                       let mut valid_block_range = if highest_seen_blockheight > segwit_activation_height {
-                               highest_seen_blockheight - segwit_activation_height
-                       } else {
-                               1
-                       };
+                       let mut blocks_since_segwit_activation = highest_seen_blockheight.saturating_sub(segwit_activation_height);
+
                        // We want to ensure that this fake channel won't conflict with any transactions we haven't
                        // seen yet, in case `highest_seen_blockheight` is updated before we get full information
                        // about transactions confirmed in the given block.
-                       if valid_block_range > BLOCKS_PER_MONTH { valid_block_range -= BLOCKS_PER_MONTH; }
+                       blocks_since_segwit_activation = blocks_since_segwit_activation.saturating_sub(BLOCKS_PER_MONTH);
 
                        let rand_for_height = u32::from_be_bytes(rand_bytes[..4].try_into().unwrap());
-                       let fake_scid_height = segwit_activation_height + rand_for_height % valid_block_range;
+                       let fake_scid_height = segwit_activation_height + rand_for_height % (blocks_since_segwit_activation + 1);
 
                        let rand_for_tx_index = u32::from_be_bytes(rand_bytes[4..8].try_into().unwrap());
                        let fake_scid_tx_index = rand_for_tx_index % MAX_TX_INDEX;
@@ -141,13 +138,6 @@ pub(crate) mod fake_scid {
                }
        }
 
-       pub fn get_phantom_scid<Signer: Sign, K: Deref>(fake_scid_rand_bytes: &[u8; 32], highest_seen_blockheight: u32, genesis_hash: &BlockHash, keys_manager: &K) -> u64
-               where K::Target: KeysInterface<Signer = Signer>,
-       {
-               let namespace = Namespace::Phantom;
-               namespace.get_fake_scid(highest_seen_blockheight, genesis_hash, fake_scid_rand_bytes, keys_manager)
-       }
-
        fn segwit_activation_height(genesis: &BlockHash) -> u32 {
                const MAINNET_GENESIS_STR: &'static str = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
                if BlockHash::from_hex(MAINNET_GENESIS_STR).unwrap() == *genesis {
index 9cd2f9ec13e8bd49de15be2fc0f283fe34660eee..27c2d9de874ed45abca03dabe171ca238d7288ff 100644 (file)
@@ -411,7 +411,10 @@ impl events::MessageSendEventsProvider for TestRoutingMessageHandler {
 
 pub struct TestLogger {
        level: Level,
+       #[cfg(feature = "std")]
        id: String,
+       #[cfg(not(feature = "std"))]
+       _id: String,
        pub lines: Mutex<HashMap<(String, String), usize>>,
 }
 
@@ -422,7 +425,10 @@ impl TestLogger {
        pub fn with_id(id: String) -> TestLogger {
                TestLogger {
                        level: Level::Trace,
+                       #[cfg(feature = "std")]
                        id,
+                       #[cfg(not(feature = "std"))]
+                       _id: id,
                        lines: Mutex::new(HashMap::new())
                }
        }
@@ -471,8 +477,7 @@ impl Logger for TestLogger {
 
 pub struct TestKeysInterface {
        pub backing: keysinterface::PhantomKeysManager,
-       pub override_session_priv: Mutex<Option<[u8; 32]>>,
-       pub override_channel_id_priv: Mutex<Option<[u8; 32]>>,
+       pub override_random_bytes: Mutex<Option<[u8; 32]>>,
        pub disable_revocation_policy_check: bool,
        enforcement_states: Mutex<HashMap<[u8;32], Arc<Mutex<EnforcementState>>>>,
        expectations: Mutex<Option<VecDeque<OnGetShutdownScriptpubkey>>>,
@@ -506,16 +511,9 @@ impl keysinterface::KeysInterface for TestKeysInterface {
        }
 
        fn get_secure_random_bytes(&self) -> [u8; 32] {
-               let override_channel_id = self.override_channel_id_priv.lock().unwrap();
-               let override_session_key = self.override_session_priv.lock().unwrap();
-               if override_channel_id.is_some() && override_session_key.is_some() {
-                       panic!("We don't know which override key to use!");
-               }
-               if let Some(key) = &*override_channel_id {
-                       return *key;
-               }
-               if let Some(key) = &*override_session_key {
-                       return *key;
+               let override_random_bytes = self.override_random_bytes.lock().unwrap();
+               if let Some(bytes) = &*override_random_bytes {
+                       return *bytes;
                }
                self.backing.get_secure_random_bytes()
        }
@@ -543,8 +541,7 @@ impl TestKeysInterface {
                let now = Duration::from_secs(genesis_block(network).header.time as u64);
                Self {
                        backing: keysinterface::PhantomKeysManager::new(seed, now.as_secs(), now.subsec_nanos(), seed),
-                       override_session_priv: Mutex::new(None),
-                       override_channel_id_priv: Mutex::new(None),
+                       override_random_bytes: Mutex::new(None),
                        disable_revocation_policy_check: false,
                        enforcement_states: Mutex::new(HashMap::new()),
                        expectations: Mutex::new(None),
diff --git a/no-std-check/Cargo.toml b/no-std-check/Cargo.toml
new file mode 100644 (file)
index 0000000..15d2c19
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name = "no-std-check"
+version = "0.1.0"
+edition = "2018"
+
+[features]
+default = ["lightning/no-std", "lightning-invoice/no-std"]
+
+[dependencies]
+lightning = { path = "../lightning", default-features = false }
+lightning-invoice = { path = "../lightning-invoice", default-features = false }
diff --git a/no-std-check/src/lib.rs b/no-std-check/src/lib.rs
new file mode 100644 (file)
index 0000000..e69de29