From: Matt Corallo <649246+TheBlueMatt@users.noreply.github.com> Date: Wed, 13 Apr 2022 14:51:35 +0000 (+0000) Subject: Merge pull request #1384 from valentinewallace/2022-03-chanmanless-phantom-invoices X-Git-Tag: v0.0.107~64 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=03f655003d4a70aeb0dc79c4007cba1a7195350a;hp=204dd42a7d6167d482cdb09f1fea5b12cd973c44;p=rust-lightning Merge pull request #1384 from valentinewallace/2022-03-chanmanless-phantom-invoices --- diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aaccb76a..cff17134 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -115,6 +115,9 @@ 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 that things still pass without grind_signatures + # note that outbound_commitment_test only runs in this mode, because of hardcoded signature values + cargo test --verbose --color always --no-default-features --features std # check if there is a conflict between no-std and the c_bindings cfg RUSTFLAGS="--cfg=c_bindings" cargo test --verbose --color always --no-default-features --features=no-std cd .. @@ -188,7 +191,7 @@ jobs: done - name: Upload coverage if: matrix.coverage - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v3 with: # Could you use this to fake the coverage report for your PR? Sure. # Will anyone be impressed by your amazing coverage? No @@ -236,9 +239,7 @@ jobs: check_commits: runs-on: ubuntu-latest env: - # rustc 1.53 regressed and panics when building our (perfectly fine) docs. - # See https://github.com/rust-lang/rust/issues/84738 - TOOLCHAIN: 1.52.1 + TOOLCHAIN: 1.57.0 steps: - name: Checkout source code uses: actions/checkout@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index c353a1bb..84d5529d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,113 @@ +# 0.0.106 - 2022-04-03 + +## API Updates + * Minimum supported rust version (MSRV) is now 1.41.1 (#1310). + * Lightning feature `option_scid_alias` is now supported and may be negotiated + when opening a channel with a peer. It can be configured via + `ChannelHandshakeConfig::negotiate_scid_privacy` and is off by default but + will be on by default in the future (#1351). + * `OpenChannelRequest` now has a `channel_type` field indicating the features + the channel will operate with and should be used to filter channels with + undesirable features (#1351). See the Serialization Compatibility section. + * `ChannelManager` supports sending and receiving short channel id aliases in + the `funding_locked` message. These are used when forwarding payments and + constructing invoice route hints for improved privacy. `ChannelDetails` has a + `inbound_scid_alias` field and a `get_inbound_payment_scid` method to support + the latter (#1311). + * `DefaultRouter` and `find_route` take an additional random seed to improve + privacy by adding a random CLTV expiry offset to each path's final hop. This + helps obscure the intended recipient from adversarial intermediate hops + (#1286). The seed is also used to randomize candidate paths during route + selection (#1359). + * The `lightning-block-sync` crate's `init::synchronize_listeners` method + interface has been relaxed to support multithreaded environments (#1349). + * `ChannelManager::create_inbound_payment_for_hash`'s documentation has been + corrected to remove the one-year restriction on `invoice_expiry_delta_secs`, + which is only applicable to the deprecated `create_inbound_payment_legacy` + and `create_inbound_payment_for_hash_legacy` methods (#1341). + * `Features` mutator methods now take `self` by reference instead of by value + (#1331). + * The CLTV of the last hop in a path is now included when comparing against + `RouteParameters::max_total_cltv_expiry_delta` (#1358). + * Invoice creation functions in `lightning-invoice` crate's `utils` module + include versions that accept a description hash instead of only a description + (#1361). + * `RoutingMessageHandler::sync_routing_table` has been renamed `peer_connected` + (#1368). + * `MessageSendEvent::SendGossipTimestampFilter` has been added to indicate that + a `gossip_timestamp_filter` should be sent (#1368). + * `PeerManager` takes an optional `NetAddress` in `new_outbound_connection` and + `new_inbound_connection`, which is used to report back the remote address to + the connecting peer in the `init` message (#1326). + * `ChannelManager::accept_inbound_channel` now takes a `user_channel_id`, which + is used in a similar manner as in outbound channels. (#1381). + * `BackgroundProcessor` now persists `NetworkGraph` on a timer and upon + shutdown as part of a new `Persister` trait, which also includes + `ChannelManager` persistence (#1376). + * `ProbabilisticScoringParameters` now has a `base_penalty_msat` option, which + default to 500 msats. It is applied at each hop to help avoid longer paths + (#1375). + * `ProbabilisticScoringParameters::liquidity_penalty_multiplier_msat`'s default + value is now 40,000 msats instead of 10,000 msats (#1375). + * The `lightning` crate has a `grind_signatures` feature used to produce + signatures with low r-values for more predictable transaction weight. This + feature is on by default (#1388). + * `ProbabilisticScoringParameters` now has a `amount_penalty_multiplier_msat` + option, which is used to further penalize large amounts (#1399). + * `PhantomRouteHints`, `FixedPenaltyScorer`, and `ScoringParameters` now + implement `Clone` (#1346). + +## Bug Fixes + * Fixed a compilation error in `ProbabilisticScorer` under `--feature=no-std` + (#1347). + * Invoice creation functions in `lightning-invoice` crate's `utils` module + filter invoice hints in order to limit the invoice size (#1325). + * Fixed a bug where a `funding_locked` message was delayed by a block if the + funding transaction was confirmed while offline, depending on the ordering + of `Confirm::transactions_confirmed` calls when brought back online (#1363). + * Fixed a bug in `NetGraphMsgHandler` where it didn't continue to receive + gossip messages from peers after initial connection (#1368, #1382). + * `ChannelManager::timer_tick_occurred` will now timeout a received multi-path + payment (MPP) after three ticks if not received in full instead of waiting + until near the HTLC timeout block(#1353). + * Fixed an issue with `find_route` causing it to be overly aggressive in using + MPP over channels to the same first hop (#1370). + * Reduced time spent processing `channel_update` messages by checking + signatures after checking if no newer messages have already been processed + (#1380). + * Fixed a few issues in `find_route` which caused preferring paths with a + higher cost (#1398). + * Fixed an issue in `ProbabilisticScorer` where a channel with not enough + liquidity could still be used when retrying a failed payment if it was on a + path with an overall lower cost (#1399). + +## Serialization Compatibility + * Channels open with `option_scid_alias` negotiated will be incompatible with + prior releases (#1351). This may occur in the following cases: + * Outbound channels when `ChannelHandshakeConfig::negotiate_scid_privacy` is + enabled. + * Inbound channels when automatically accepted from an `OpenChannel` message + with a `channel_type` that has `ChannelTypeFeatures::supports_scid_privacy` + return true. See `UserConfig::accept_inbound_channels`. + * Inbound channels when manually accepted from an `OpenChannelRequest` with a + `channel_type` that has `ChannelTypeFeatures::supports_scid_privacy` return + true. See `UserConfig::manually_accept_inbound_channels`. + +In total, this release features 43 files changed, 4052 insertions, 1274 +deletions in 75 commits from 11 authors, in alphabetical order: + * Devrandom + * Duncan Dean + * Elias Rohrer + * Jeffrey Czyz + * Jurvis Tan + * Luiz Parreira + * Matt Corallo + * Omar Shamardy + * Viktor Tigerström + * dependabot[bot] + * psycho-pirate + + # 0.0.105 - 2022-02-28 ## API Updates diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index 5494b26c..bff177b1 100644 --- a/fuzz/src/router.rs +++ b/fuzz/src/router.rs @@ -215,6 +215,7 @@ pub fn do_test(data: &[u8], out: Out) { forwarding_info: None, }, funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }), + channel_type: None, short_channel_id: Some(scid), inbound_scid_alias: None, channel_value_satoshis: slice_to_be64(get_slice!(8)), diff --git a/lightning-background-processor/Cargo.toml b/lightning-background-processor/Cargo.toml index edb1551e..bd6d54d8 100644 --- a/lightning-background-processor/Cargo.toml +++ b/lightning-background-processor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-background-processor" -version = "0.0.105" +version = "0.0.106" authors = ["Valentine Wallace "] license = "MIT OR Apache-2.0" repository = "http://github.com/lightningdevkit/rust-lightning" @@ -15,9 +15,9 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] bitcoin = "0.27" -lightning = { version = "0.0.105", path = "../lightning", features = ["std"] } -lightning-persister = { version = "0.0.105", path = "../lightning-persister" } +lightning = { version = "0.0.106", path = "../lightning", features = ["std"] } +lightning-persister = { version = "0.0.106", path = "../lightning-persister" } [dev-dependencies] -lightning = { version = "0.0.105", path = "../lightning", features = ["_test_utils"] } -lightning-invoice = { version = "0.13.0", path = "../lightning-invoice" } +lightning = { version = "0.0.106", path = "../lightning", features = ["_test_utils"] } +lightning-invoice = { version = "0.14.0", path = "../lightning-invoice" } diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 22fef266..73f420c9 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -75,10 +75,13 @@ const PING_TIMER: u64 = 1; /// Prune the network graph of stale entries hourly. const NETWORK_PRUNE_TIMER: u64 = 60 * 60; -/// Trait which handles persisting a [`ChannelManager`] to disk. -/// -/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager -pub trait ChannelManagerPersister +#[cfg(not(test))] +const FIRST_NETWORK_PRUNE_TIMER: u64 = 60; +#[cfg(test)] +const FIRST_NETWORK_PRUNE_TIMER: u64 = 1; + +/// Trait that handles persisting a [`ChannelManager`] and [`NetworkGraph`] to disk. +pub trait Persister where M::Target: 'static + chain::Watch, T::Target: 'static + BroadcasterInterface, @@ -87,24 +90,11 @@ where L::Target: 'static + Logger, { /// Persist the given [`ChannelManager`] to disk, returning an error if persistence failed - /// (which will cause the [`BackgroundProcessor`] which called this method to exit. - /// - /// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager + /// (which will cause the [`BackgroundProcessor`] which called this method to exit). fn persist_manager(&self, channel_manager: &ChannelManager) -> Result<(), std::io::Error>; -} -impl -ChannelManagerPersister for Fun where - M::Target: 'static + chain::Watch, - T::Target: 'static + BroadcasterInterface, - K::Target: 'static + KeysInterface, - F::Target: 'static + FeeEstimator, - L::Target: 'static + Logger, - Fun: Fn(&ChannelManager) -> Result<(), std::io::Error>, -{ - fn persist_manager(&self, channel_manager: &ChannelManager) -> Result<(), std::io::Error> { - self(channel_manager) - } + /// Persist the given [`NetworkGraph`] to disk, returning an error if persistence failed. + fn persist_graph(&self, network_graph: &NetworkGraph) -> Result<(), std::io::Error>; } /// Decorates an [`EventHandler`] with common functionality provided by standard [`EventHandler`]s. @@ -141,17 +131,21 @@ impl BackgroundProcessor { /// documentation]. /// /// The thread runs indefinitely unless the object is dropped, [`stop`] is called, or - /// `persist_manager` returns an error. In case of an error, the error is retrieved by calling + /// [`Persister::persist_manager`] returns an error. In case of an error, the error is retrieved by calling /// either [`join`] or [`stop`]. /// /// # Data Persistence /// - /// `persist_manager` is responsible for writing out the [`ChannelManager`] to disk, and/or + /// [`Persister::persist_manager`] is responsible for writing out the [`ChannelManager`] to disk, and/or /// uploading to one or more backup services. See [`ChannelManager::write`] for writing out a /// [`ChannelManager`]. See [`FilesystemPersister::persist_manager`] for Rust-Lightning's /// provided implementation. /// - /// Typically, users should either implement [`ChannelManagerPersister`] to never return an + /// [`Persister::persist_graph`] is responsible for writing out the [`NetworkGraph`] to disk. See + /// [`NetworkGraph::write`] for writing out a [`NetworkGraph`]. See [`FilesystemPersister::persist_network_graph`] + /// for Rust-Lightning's provided implementation. + /// + /// Typically, users should either implement [`Persister::persist_manager`] to never return an /// error or call [`join`] and handle any error that may arise. For the latter case, /// `BackgroundProcessor` must be restarted by calling `start` again after handling the error. /// @@ -168,7 +162,9 @@ impl BackgroundProcessor { /// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager /// [`ChannelManager::write`]: lightning::ln::channelmanager::ChannelManager#impl-Writeable /// [`FilesystemPersister::persist_manager`]: lightning_persister::FilesystemPersister::persist_manager + /// [`FilesystemPersister::persist_network_graph`]: lightning_persister::FilesystemPersister::persist_network_graph /// [`NetworkGraph`]: lightning::routing::network_graph::NetworkGraph + /// [`NetworkGraph::write`]: lightning::routing::network_graph::NetworkGraph#impl-Writeable pub fn start< Signer: 'static + Sign, CA: 'static + Deref + Send + Sync, @@ -184,14 +180,14 @@ impl BackgroundProcessor { CMH: 'static + Deref + Send + Sync, RMH: 'static + Deref + Send + Sync, EH: 'static + EventHandler + Send, - CMP: 'static + Send + ChannelManagerPersister, + PS: 'static + Send + Persister, M: 'static + Deref> + Send + Sync, CM: 'static + Deref> + Send + Sync, NG: 'static + Deref> + Send + Sync, UMH: 'static + Deref + Send + Sync, PM: 'static + Deref> + Send + Sync, >( - persister: CMP, event_handler: EH, chain_monitor: M, channel_manager: CM, + persister: PS, event_handler: EH, chain_monitor: M, channel_manager: CM, net_graph_msg_handler: Option, peer_manager: PM, logger: L ) -> Self where @@ -273,19 +269,29 @@ impl BackgroundProcessor { // falling back to our usual hourly prunes. This avoids short-lived clients never // pruning their network graph. We run once 60 seconds after startup before // continuing our normal cadence. - if last_prune_call.elapsed().as_secs() > if have_pruned { NETWORK_PRUNE_TIMER } else { 60 } { + if last_prune_call.elapsed().as_secs() > if have_pruned { NETWORK_PRUNE_TIMER } else { FIRST_NETWORK_PRUNE_TIMER } { if let Some(ref handler) = net_graph_msg_handler { log_trace!(logger, "Pruning network graph of stale entries"); handler.network_graph().remove_stale_channels(); + if let Err(e) = persister.persist_graph(handler.network_graph()) { + log_error!(logger, "Error: Failed to persist network graph, check your disk and permissions {}", e) + } last_prune_call = Instant::now(); have_pruned = true; } } } + // After we exit, ensure we persist the ChannelManager one final time - this avoids // some races where users quit while channel updates were in-flight, with // ChannelMonitor update(s) persisted without a corresponding ChannelManager update. - persister.persist_manager(&*channel_manager) + persister.persist_manager(&*channel_manager)?; + + // Persist NetworkGraph on exit + if let Some(ref handler) = net_graph_msg_handler { + persister.persist_graph(handler.network_graph())?; + } + Ok(()) }); Self { stop_thread: stop_thread_clone, thread_handle: Some(handle) } } @@ -343,9 +349,10 @@ mod tests { use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::transaction::{Transaction, TxOut}; use bitcoin::network::constants::Network; - use lightning::chain::{BestBlock, Confirm, chainmonitor}; + use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; + use lightning::chain::{BestBlock, Confirm, chainmonitor, self}; use lightning::chain::channelmonitor::ANTI_REORG_DELAY; - use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeysInterface, KeysManager}; + use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeysInterface, KeysManager, Sign}; use lightning::chain::transaction::OutPoint; use lightning::get_event_msg; use lightning::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChainParameters, ChannelManager, SimpleArcChannelManager}; @@ -355,12 +362,14 @@ mod tests { use lightning::routing::network_graph::{NetworkGraph, NetGraphMsgHandler}; use lightning::util::config::UserConfig; use lightning::util::events::{Event, MessageSendEventsProvider, MessageSendEvent}; + use lightning::util::logger::Logger; use lightning::util::ser::Writeable; use lightning::util::test_utils; use lightning_invoice::payment::{InvoicePayer, RetryAttempts}; use lightning_invoice::utils::DefaultRouter; use lightning_persister::FilesystemPersister; use std::fs; + use std::ops::Deref; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -402,6 +411,48 @@ mod tests { } } + struct Persister { + data_dir: String, + graph_error: Option<(std::io::ErrorKind, &'static str)>, + manager_error: Option<(std::io::ErrorKind, &'static str)> + } + + impl Persister { + fn new(data_dir: String) -> Self { + Self { data_dir, graph_error: None, manager_error: None } + } + + fn with_graph_error(self, error: std::io::ErrorKind, message: &'static str) -> Self { + Self { graph_error: Some((error, message)), ..self } + } + + fn with_manager_error(self, error: std::io::ErrorKind, message: &'static str) -> Self { + Self { manager_error: Some((error, message)), ..self } + } + } + + impl super::Persister for Persister where + M::Target: 'static + chain::Watch, + T::Target: 'static + BroadcasterInterface, + K::Target: 'static + KeysInterface, + F::Target: 'static + FeeEstimator, + L::Target: 'static + Logger, + { + fn persist_manager(&self, channel_manager: &ChannelManager) -> Result<(), std::io::Error> { + match self.manager_error { + None => FilesystemPersister::persist_manager(self.data_dir.clone(), channel_manager), + Some((error, message)) => Err(std::io::Error::new(error, message)), + } + } + + fn persist_graph(&self, network_graph: &NetworkGraph) -> Result<(), std::io::Error> { + match self.graph_error { + None => FilesystemPersister::persist_network_graph(self.data_dir.clone(), network_graph), + Some((error, message)) => Err(std::io::Error::new(error, message)), + } + } + } + fn get_full_filepath(filepath: String, filename: String) -> String { let mut path = PathBuf::from(filepath); path.push(filename); @@ -525,19 +576,20 @@ mod tests { // Initiate the background processors to watch each node. let data_dir = nodes[0].persister.get_data_dir(); - let persister = move |node: &ChannelManager, Arc, Arc, Arc, Arc>| FilesystemPersister::persist_manager(data_dir.clone(), node); + let persister = Persister::new(data_dir); let event_handler = |_: &_| {}; let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone()); macro_rules! check_persisted_data { - ($node: expr, $filepath: expr, $expected_bytes: expr) => { + ($node: expr, $filepath: expr) => { + let mut expected_bytes = Vec::new(); loop { - $expected_bytes.clear(); - match $node.write(&mut $expected_bytes) { + expected_bytes.clear(); + match $node.write(&mut expected_bytes) { Ok(()) => { match std::fs::read($filepath) { Ok(bytes) => { - if bytes == $expected_bytes { + if bytes == expected_bytes { break } else { continue @@ -554,8 +606,8 @@ mod tests { // Check that the initial channel manager data is persisted as expected. let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "manager".to_string()); - let mut expected_bytes = Vec::new(); - check_persisted_data!(nodes[0].node, filepath.clone(), expected_bytes); + check_persisted_data!(nodes[0].node, filepath.clone()); + loop { if !nodes[0].node.get_persistence_condvar_value() { break } } @@ -564,12 +616,18 @@ mod tests { nodes[0].node.force_close_channel(&OutPoint { txid: tx.txid(), index: 0 }.to_channel_id()).unwrap(); // Check that the force-close updates are persisted. - let mut expected_bytes = Vec::new(); - check_persisted_data!(nodes[0].node, filepath.clone(), expected_bytes); + check_persisted_data!(nodes[0].node, filepath.clone()); loop { if !nodes[0].node.get_persistence_condvar_value() { break } } + // Check network graph is persisted + let filepath = get_full_filepath("test_background_processor_persister_0".to_string(), "network_graph".to_string()); + if let Some(ref handler) = nodes[0].net_graph_msg_handler { + let network_graph = handler.network_graph(); + check_persisted_data!(network_graph, filepath.clone()); + } + assert!(bg_processor.stop().is_ok()); } @@ -579,7 +637,7 @@ mod tests { // `FRESHNESS_TIMER`. let nodes = create_nodes(1, "test_timer_tick_called".to_string()); let data_dir = nodes[0].persister.get_data_dir(); - let persister = move |node: &ChannelManager, Arc, Arc, Arc, Arc>| FilesystemPersister::persist_manager(data_dir.clone(), node); + let persister = Persister::new(data_dir); let event_handler = |_: &_| {}; let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone()); loop { @@ -596,12 +654,13 @@ mod tests { } #[test] - fn test_persist_error() { + fn test_channel_manager_persist_error() { // Test that if we encounter an error during manager persistence, the thread panics. let nodes = create_nodes(2, "test_persist_error".to_string()); open_channel!(nodes[0], nodes[1], 100000); - let persister = |_: &_| Err(std::io::Error::new(std::io::ErrorKind::Other, "test")); + let data_dir = nodes[0].persister.get_data_dir(); + let persister = Persister::new(data_dir).with_manager_error(std::io::ErrorKind::Other, "test"); let event_handler = |_: &_| {}; let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone()); match bg_processor.join() { @@ -613,19 +672,37 @@ mod tests { } } + #[test] + fn test_network_graph_persist_error() { + // Test that if we encounter an error during network graph persistence, an error gets returned. + let nodes = create_nodes(2, "test_persist_network_graph_error".to_string()); + let data_dir = nodes[0].persister.get_data_dir(); + let persister = Persister::new(data_dir).with_graph_error(std::io::ErrorKind::Other, "test"); + let event_handler = |_: &_| {}; + let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone()); + + match bg_processor.stop() { + Ok(_) => panic!("Expected error persisting network graph"), + Err(e) => { + assert_eq!(e.kind(), std::io::ErrorKind::Other); + assert_eq!(e.get_ref().unwrap().to_string(), "test"); + }, + } + } + #[test] fn test_background_event_handling() { let mut nodes = create_nodes(2, "test_background_event_handling".to_string()); let channel_value = 100000; let data_dir = nodes[0].persister.get_data_dir(); - let persister = move |node: &_| FilesystemPersister::persist_manager(data_dir.clone(), node); + let persister = Persister::new(data_dir.clone()); // Set up a background event handler for FundingGenerationReady events. let (sender, receiver) = std::sync::mpsc::sync_channel(1); let event_handler = move |event: &Event| { sender.send(handle_funding_generation_ready!(event, channel_value)).unwrap(); }; - let bg_processor = BackgroundProcessor::start(persister.clone(), 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()); + 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()); // Open a channel and check that the FundingGenerationReady event was handled. begin_open_channel!(nodes[0], nodes[1], channel_value); @@ -649,7 +726,7 @@ mod tests { // Set up a background event handler for SpendableOutputs events. let (sender, receiver) = std::sync::mpsc::sync_channel(1); let event_handler = move |event: &Event| sender.send(event.clone()).unwrap(); - 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()); + let bg_processor = BackgroundProcessor::start(Persister::new(data_dir), 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()); // Force close the channel and check that the SpendableOutputs event was handled. nodes[0].node.force_close_channel(&nodes[0].node.list_channels()[0].channel_id).unwrap(); @@ -675,7 +752,7 @@ mod tests { // Initiate the background processors to watch each node. let data_dir = nodes[0].persister.get_data_dir(); - let persister = move |node: &ChannelManager, Arc, Arc, Arc, Arc>| FilesystemPersister::persist_manager(data_dir.clone(), node); + let persister = Persister::new(data_dir); 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))); diff --git a/lightning-block-sync/Cargo.toml b/lightning-block-sync/Cargo.toml index cbc81c89..67303408 100644 --- a/lightning-block-sync/Cargo.toml +++ b/lightning-block-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-block-sync" -version = "0.0.105" +version = "0.0.106" authors = ["Jeffrey Czyz", "Matt Corallo"] license = "MIT OR Apache-2.0" repository = "http://github.com/lightningdevkit/rust-lightning" @@ -19,7 +19,8 @@ rpc-client = [ "serde", "serde_json", "chunked_transfer" ] [dependencies] bitcoin = "0.27" -lightning = { version = "0.0.105", path = "../lightning" } +lightning = { version = "0.0.106", path = "../lightning" } +futures = { version = "0.3" } tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true } serde = { version = "1.0", features = ["derive"], optional = true } serde_json = { version = "1.0", optional = true } diff --git a/lightning-block-sync/src/init.rs b/lightning-block-sync/src/init.rs index d971cadc..6611d185 100644 --- a/lightning-block-sync/src/init.rs +++ b/lightning-block-sync/src/init.rs @@ -16,7 +16,7 @@ use lightning::chain; /// start when there are no chain listeners to sync yet. /// /// [`SpvClient`]: crate::SpvClient -pub async fn validate_best_block_header(block_source: &mut B) -> +pub async fn validate_best_block_header(block_source: &B) -> BlockSourceResult { let (best_block_hash, best_block_height) = block_source.get_best_block().await?; block_source @@ -67,7 +67,7 @@ BlockSourceResult { /// C: chain::Filter, /// P: chainmonitor::Persist, /// >( -/// block_source: &mut B, +/// block_source: &B, /// chain_monitor: &ChainMonitor, /// config: UserConfig, /// keys_manager: &K, @@ -122,7 +122,7 @@ BlockSourceResult { /// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager /// [`ChannelMonitor`]: lightning::chain::channelmonitor::ChannelMonitor pub async fn synchronize_listeners<'a, B: BlockSource, C: Cache, L: chain::Listen + ?Sized>( - block_source: &mut B, + block_source: &B, network: Network, header_cache: &mut C, mut chain_listeners: Vec<(BlockHash, &'a L)>, diff --git a/lightning-block-sync/src/lib.rs b/lightning-block-sync/src/lib.rs index 8854aa3e..321dd57e 100644 --- a/lightning-block-sync/src/lib.rs +++ b/lightning-block-sync/src/lib.rs @@ -61,11 +61,11 @@ pub trait BlockSource : Sync + Send { /// /// Implementations that cannot find headers based on the hash should return a `Transient` error /// when `height_hint` is `None`. - fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, height_hint: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData>; + fn get_header<'a>(&'a self, header_hash: &'a BlockHash, height_hint: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData>; /// Returns the block for a given hash. A headers-only block source should return a `Transient` /// error. - fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block>; + fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block>; /// Returns the hash of the best block and, optionally, its height. /// @@ -73,7 +73,7 @@ pub trait BlockSource : Sync + Send { /// to allow for a more efficient lookup. /// /// [`get_header`]: Self::get_header - fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<(BlockHash, Option)>; + fn get_best_block<'a>(&'a self) -> AsyncBlockSourceResult<(BlockHash, Option)>; } /// Result type for `BlockSource` requests. diff --git a/lightning-block-sync/src/poll.rs b/lightning-block-sync/src/poll.rs index c59652ea..b32d2239 100644 --- a/lightning-block-sync/src/poll.rs +++ b/lightning-block-sync/src/poll.rs @@ -6,7 +6,7 @@ use bitcoin::blockdata::block::Block; use bitcoin::hash_types::BlockHash; use bitcoin::network::constants::Network; -use std::ops::DerefMut; +use std::ops::Deref; /// The `Poll` trait defines behavior for polling block sources for a chain tip and retrieving /// related chain data. It serves as an adapter for `BlockSource`. @@ -17,15 +17,15 @@ use std::ops::DerefMut; /// [`ChainPoller`]: ../struct.ChainPoller.html pub trait Poll { /// Returns a chain tip in terms of its relationship to the provided chain tip. - fn poll_chain_tip<'a>(&'a mut self, best_known_chain_tip: ValidatedBlockHeader) -> + fn poll_chain_tip<'a>(&'a self, best_known_chain_tip: ValidatedBlockHeader) -> AsyncBlockSourceResult<'a, ChainTip>; /// Returns the header that preceded the given header in the chain. - fn look_up_previous_header<'a>(&'a mut self, header: &'a ValidatedBlockHeader) -> + fn look_up_previous_header<'a>(&'a self, header: &'a ValidatedBlockHeader) -> AsyncBlockSourceResult<'a, ValidatedBlockHeader>; /// Returns the block associated with the given header. - fn fetch_block<'a>(&'a mut self, header: &'a ValidatedBlockHeader) -> + fn fetch_block<'a>(&'a self, header: &'a ValidatedBlockHeader) -> AsyncBlockSourceResult<'a, ValidatedBlock>; } @@ -170,12 +170,12 @@ mod sealed { /// /// Other `Poll` implementations should be built using `ChainPoller` as it provides the simplest way /// of validating chain data and checking consistency. -pub struct ChainPoller + Sized, T: BlockSource> { +pub struct ChainPoller + Sized, T: BlockSource> { block_source: B, network: Network, } -impl + Sized, T: BlockSource> ChainPoller { +impl + Sized, T: BlockSource> ChainPoller { /// Creates a new poller for the given block source. /// /// If the `network` parameter is mainnet, then the difficulty between blocks is checked for @@ -185,8 +185,8 @@ impl + Sized, T: BlockSource> ChainPoller { } } -impl + Sized + Send + Sync, T: BlockSource> Poll for ChainPoller { - fn poll_chain_tip<'a>(&'a mut self, best_known_chain_tip: ValidatedBlockHeader) -> +impl + Sized + Send + Sync, T: BlockSource> Poll for ChainPoller { + fn poll_chain_tip<'a>(&'a self, best_known_chain_tip: ValidatedBlockHeader) -> AsyncBlockSourceResult<'a, ChainTip> { Box::pin(async move { @@ -206,7 +206,7 @@ impl + Sized + Send + Sync, T: BlockSource> Poll for Chain }) } - fn look_up_previous_header<'a>(&'a mut self, header: &'a ValidatedBlockHeader) -> + fn look_up_previous_header<'a>(&'a self, header: &'a ValidatedBlockHeader) -> AsyncBlockSourceResult<'a, ValidatedBlockHeader> { Box::pin(async move { @@ -225,7 +225,7 @@ impl + Sized + Send + Sync, T: BlockSource> Poll for Chain }) } - fn fetch_block<'a>(&'a mut self, header: &'a ValidatedBlockHeader) -> + fn fetch_block<'a>(&'a self, header: &'a ValidatedBlockHeader) -> AsyncBlockSourceResult<'a, ValidatedBlock> { Box::pin(async move { @@ -249,7 +249,7 @@ mod tests { let best_known_chain_tip = chain.tip(); chain.disconnect_tip(); - let mut poller = ChainPoller::new(&mut chain, Network::Bitcoin); + let poller = ChainPoller::new(&chain, Network::Bitcoin); match poller.poll_chain_tip(best_known_chain_tip).await { Err(e) => { assert_eq!(e.kind(), BlockSourceErrorKind::Transient); @@ -261,10 +261,10 @@ mod tests { #[tokio::test] async fn poll_chain_without_headers() { - let mut chain = Blockchain::default().with_height(1).without_headers(); + let chain = Blockchain::default().with_height(1).without_headers(); let best_known_chain_tip = chain.at_height(0); - let mut poller = ChainPoller::new(&mut chain, Network::Bitcoin); + let poller = ChainPoller::new(&chain, Network::Bitcoin); match poller.poll_chain_tip(best_known_chain_tip).await { Err(e) => { assert_eq!(e.kind(), BlockSourceErrorKind::Persistent); @@ -283,7 +283,7 @@ mod tests { chain.blocks.last_mut().unwrap().header.bits = BlockHeader::compact_target_from_u256(&Uint256::from_be_bytes([0; 32])); - let mut poller = ChainPoller::new(&mut chain, Network::Bitcoin); + let poller = ChainPoller::new(&chain, Network::Bitcoin); match poller.poll_chain_tip(best_known_chain_tip).await { Err(e) => { assert_eq!(e.kind(), BlockSourceErrorKind::Persistent); @@ -295,10 +295,10 @@ mod tests { #[tokio::test] async fn poll_chain_with_malformed_headers() { - let mut chain = Blockchain::default().with_height(1).malformed_headers(); + let chain = Blockchain::default().with_height(1).malformed_headers(); let best_known_chain_tip = chain.at_height(0); - let mut poller = ChainPoller::new(&mut chain, Network::Bitcoin); + let poller = ChainPoller::new(&chain, Network::Bitcoin); match poller.poll_chain_tip(best_known_chain_tip).await { Err(e) => { assert_eq!(e.kind(), BlockSourceErrorKind::Persistent); @@ -310,10 +310,10 @@ mod tests { #[tokio::test] async fn poll_chain_with_common_tip() { - let mut chain = Blockchain::default().with_height(0); + let chain = Blockchain::default().with_height(0); let best_known_chain_tip = chain.tip(); - let mut poller = ChainPoller::new(&mut chain, Network::Bitcoin); + let poller = ChainPoller::new(&chain, Network::Bitcoin); match poller.poll_chain_tip(best_known_chain_tip).await { Err(e) => panic!("Unexpected error: {:?}", e), Ok(tip) => assert_eq!(tip, ChainTip::Common), @@ -330,7 +330,7 @@ mod tests { let worse_chain_tip = chain.tip(); assert_eq!(best_known_chain_tip.chainwork, worse_chain_tip.chainwork); - let mut poller = ChainPoller::new(&mut chain, Network::Bitcoin); + let poller = ChainPoller::new(&chain, Network::Bitcoin); match poller.poll_chain_tip(best_known_chain_tip).await { Err(e) => panic!("Unexpected error: {:?}", e), Ok(tip) => assert_eq!(tip, ChainTip::Worse(worse_chain_tip)), @@ -345,7 +345,7 @@ mod tests { chain.disconnect_tip(); let worse_chain_tip = chain.tip(); - let mut poller = ChainPoller::new(&mut chain, Network::Bitcoin); + let poller = ChainPoller::new(&chain, Network::Bitcoin); match poller.poll_chain_tip(best_known_chain_tip).await { Err(e) => panic!("Unexpected error: {:?}", e), Ok(tip) => assert_eq!(tip, ChainTip::Worse(worse_chain_tip)), @@ -354,12 +354,12 @@ mod tests { #[tokio::test] async fn poll_chain_with_better_tip() { - let mut chain = Blockchain::default().with_height(1); + let chain = Blockchain::default().with_height(1); let best_known_chain_tip = chain.at_height(0); let better_chain_tip = chain.tip(); - let mut poller = ChainPoller::new(&mut chain, Network::Bitcoin); + let poller = ChainPoller::new(&chain, Network::Bitcoin); match poller.poll_chain_tip(best_known_chain_tip).await { Err(e) => panic!("Unexpected error: {:?}", e), Ok(tip) => assert_eq!(tip, ChainTip::Better(better_chain_tip)), diff --git a/lightning-block-sync/src/rest.rs b/lightning-block-sync/src/rest.rs index e04bb86d..2ddfed7d 100644 --- a/lightning-block-sync/src/rest.rs +++ b/lightning-block-sync/src/rest.rs @@ -8,13 +8,15 @@ use bitcoin::blockdata::block::Block; use bitcoin::hash_types::BlockHash; use bitcoin::hashes::hex::ToHex; +use futures::lock::Mutex; + use std::convert::TryFrom; use std::convert::TryInto; /// A simple REST client for requesting resources using HTTP `GET`. pub struct RestClient { endpoint: HttpEndpoint, - client: HttpClient, + client: Mutex, } impl RestClient { @@ -22,35 +24,35 @@ impl RestClient { /// /// The endpoint should contain the REST path component (e.g., http://127.0.0.1:8332/rest). pub fn new(endpoint: HttpEndpoint) -> std::io::Result { - let client = HttpClient::connect(&endpoint)?; + let client = Mutex::new(HttpClient::connect(&endpoint)?); Ok(Self { endpoint, client }) } /// Requests a resource encoded in `F` format and interpreted as type `T`. - pub async fn request_resource(&mut self, resource_path: &str) -> std::io::Result + pub async fn request_resource(&self, resource_path: &str) -> std::io::Result where F: TryFrom, Error = std::io::Error> + TryInto { let host = format!("{}:{}", self.endpoint.host(), self.endpoint.port()); let uri = format!("{}/{}", self.endpoint.path().trim_end_matches("/"), resource_path); - self.client.get::(&uri, &host).await?.try_into() + self.client.lock().await.get::(&uri, &host).await?.try_into() } } impl BlockSource for RestClient { - fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, _height: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData> { + fn get_header<'a>(&'a self, header_hash: &'a BlockHash, _height: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData> { Box::pin(async move { let resource_path = format!("headers/1/{}.json", header_hash.to_hex()); Ok(self.request_resource::(&resource_path).await?) }) } - fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> { + fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> { Box::pin(async move { let resource_path = format!("block/{}.bin", header_hash.to_hex()); Ok(self.request_resource::(&resource_path).await?) }) } - fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<'a, (BlockHash, Option)> { + fn get_best_block<'a>(&'a self) -> AsyncBlockSourceResult<'a, (BlockHash, Option)> { Box::pin(async move { Ok(self.request_resource::("chaininfo.json").await?) }) @@ -81,7 +83,7 @@ mod tests { #[tokio::test] async fn request_unknown_resource() { let server = HttpServer::responding_with_not_found(); - let mut client = RestClient::new(server.endpoint()).unwrap(); + let client = RestClient::new(server.endpoint()).unwrap(); match client.request_resource::("/").await { Err(e) => assert_eq!(e.kind(), std::io::ErrorKind::Other), @@ -92,7 +94,7 @@ mod tests { #[tokio::test] async fn request_malformed_resource() { let server = HttpServer::responding_with_ok(MessageBody::Content("foo")); - let mut client = RestClient::new(server.endpoint()).unwrap(); + let client = RestClient::new(server.endpoint()).unwrap(); match client.request_resource::("/").await { Err(e) => assert_eq!(e.kind(), std::io::ErrorKind::InvalidData), @@ -103,7 +105,7 @@ mod tests { #[tokio::test] async fn request_valid_resource() { let server = HttpServer::responding_with_ok(MessageBody::Content(42)); - let mut client = RestClient::new(server.endpoint()).unwrap(); + let client = RestClient::new(server.endpoint()).unwrap(); match client.request_resource::("/").await { Err(e) => panic!("Unexpected error: {:?}", e), diff --git a/lightning-block-sync/src/rpc.rs b/lightning-block-sync/src/rpc.rs index 88199688..1e0aa9d9 100644 --- a/lightning-block-sync/src/rpc.rs +++ b/lightning-block-sync/src/rpc.rs @@ -8,6 +8,8 @@ use bitcoin::blockdata::block::Block; use bitcoin::hash_types::BlockHash; use bitcoin::hashes::hex::ToHex; +use futures::lock::Mutex; + use serde_json; use std::convert::TryFrom; @@ -18,7 +20,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; pub struct RpcClient { basic_auth: String, endpoint: HttpEndpoint, - client: HttpClient, + client: Mutex, id: AtomicUsize, } @@ -27,7 +29,7 @@ impl RpcClient { /// credentials should be a base64 encoding of a user name and password joined by a colon, as is /// required for HTTP basic access authentication. pub fn new(credentials: &str, endpoint: HttpEndpoint) -> std::io::Result { - let client = HttpClient::connect(&endpoint)?; + let client = Mutex::new(HttpClient::connect(&endpoint)?); Ok(Self { basic_auth: "Basic ".to_string() + credentials, endpoint, @@ -37,7 +39,7 @@ impl RpcClient { } /// Calls a method with the response encoded in JSON format and interpreted as type `T`. - pub async fn call_method(&mut self, method: &str, params: &[serde_json::Value]) -> std::io::Result + pub async fn call_method(&self, method: &str, params: &[serde_json::Value]) -> std::io::Result where JsonResponse: TryFrom, Error = std::io::Error> + TryInto { let host = format!("{}:{}", self.endpoint.host(), self.endpoint.port()); let uri = self.endpoint.path(); @@ -47,7 +49,7 @@ impl RpcClient { "id": &self.id.fetch_add(1, Ordering::AcqRel).to_string() }); - let mut response = match self.client.post::(&uri, &host, &self.basic_auth, content).await { + let mut response = match self.client.lock().await.post::(&uri, &host, &self.basic_auth, content).await { Ok(JsonResponse(response)) => response, Err(e) if e.kind() == std::io::ErrorKind::Other => { match e.get_ref().unwrap().downcast_ref::() { @@ -82,14 +84,14 @@ impl RpcClient { } impl BlockSource for RpcClient { - fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, _height: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData> { + fn get_header<'a>(&'a self, header_hash: &'a BlockHash, _height: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData> { Box::pin(async move { let header_hash = serde_json::json!(header_hash.to_hex()); Ok(self.call_method("getblockheader", &[header_hash]).await?) }) } - fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> { + fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> { Box::pin(async move { let header_hash = serde_json::json!(header_hash.to_hex()); let verbosity = serde_json::json!(0); @@ -97,7 +99,7 @@ impl BlockSource for RpcClient { }) } - fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<'a, (BlockHash, Option)> { + fn get_best_block<'a>(&'a self) -> AsyncBlockSourceResult<'a, (BlockHash, Option)> { Box::pin(async move { Ok(self.call_method("getblockchaininfo", &[]).await?) }) @@ -127,7 +129,7 @@ mod tests { #[tokio::test] async fn call_method_returning_unknown_response() { let server = HttpServer::responding_with_not_found(); - let mut client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); + let client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); match client.call_method::("getblockcount", &[]).await { Err(e) => assert_eq!(e.kind(), std::io::ErrorKind::Other), @@ -139,7 +141,7 @@ mod tests { async fn call_method_returning_malfomred_response() { let response = serde_json::json!("foo"); let server = HttpServer::responding_with_ok(MessageBody::Content(response)); - let mut client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); + let client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); match client.call_method::("getblockcount", &[]).await { Err(e) => { @@ -156,7 +158,7 @@ mod tests { "error": { "code": -8, "message": "invalid parameter" }, }); let server = HttpServer::responding_with_server_error(response); - let mut client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); + let client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); let invalid_block_hash = serde_json::json!("foo"); match client.call_method::("getblock", &[invalid_block_hash]).await { @@ -172,7 +174,7 @@ mod tests { async fn call_method_returning_missing_result() { let response = serde_json::json!({ "result": null }); let server = HttpServer::responding_with_ok(MessageBody::Content(response)); - let mut client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); + let client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); match client.call_method::("getblockcount", &[]).await { Err(e) => { @@ -187,7 +189,7 @@ mod tests { async fn call_method_returning_malformed_result() { let response = serde_json::json!({ "result": "foo" }); let server = HttpServer::responding_with_ok(MessageBody::Content(response)); - let mut client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); + let client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); match client.call_method::("getblockcount", &[]).await { Err(e) => { @@ -202,7 +204,7 @@ mod tests { async fn call_method_returning_valid_result() { let response = serde_json::json!({ "result": 654470 }); let server = HttpServer::responding_with_ok(MessageBody::Content(response)); - let mut client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); + let client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap(); match client.call_method::("getblockcount", &[]).await { Err(e) => panic!("Unexpected error: {:?}", e), diff --git a/lightning-block-sync/src/test_utils.rs b/lightning-block-sync/src/test_utils.rs index 8c37c94d..fe57c0c6 100644 --- a/lightning-block-sync/src/test_utils.rs +++ b/lightning-block-sync/src/test_utils.rs @@ -113,7 +113,7 @@ impl Blockchain { } impl BlockSource for Blockchain { - fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, _height_hint: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData> { + fn get_header<'a>(&'a self, header_hash: &'a BlockHash, _height_hint: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData> { Box::pin(async move { if self.without_headers { return Err(BlockSourceError::persistent("header not found")); @@ -133,7 +133,7 @@ impl BlockSource for Blockchain { }) } - fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> { + fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> { Box::pin(async move { for (height, block) in self.blocks.iter().enumerate() { if block.header.block_hash() == *header_hash { @@ -150,7 +150,7 @@ impl BlockSource for Blockchain { }) } - fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<'a, (BlockHash, Option)> { + fn get_best_block<'a>(&'a self) -> AsyncBlockSourceResult<'a, (BlockHash, Option)> { Box::pin(async move { match self.blocks.last() { None => Err(BlockSourceError::transient("empty chain")), diff --git a/lightning-invoice/Cargo.toml b/lightning-invoice/Cargo.toml index e41eb1cd..194f5f70 100644 --- a/lightning-invoice/Cargo.toml +++ b/lightning-invoice/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "lightning-invoice" description = "Data structures to parse and serialize BOLT11 lightning invoices" -version = "0.13.0" +version = "0.14.0" authors = ["Sebastian Geisler "] documentation = "https://docs.rs/lightning-invoice/" license = "MIT OR Apache-2.0" @@ -19,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.105", path = "../lightning", default-features = false } +lightning = { version = "0.0.106", 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 } @@ -27,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.105", path = "../lightning", default-features = false, features = ["_test_utils"] } +lightning = { version = "0.0.106", path = "../lightning", default-features = false, features = ["_test_utils"] } hex = "0.4" diff --git a/lightning-invoice/src/de.rs b/lightning-invoice/src/de.rs index 9e96849a..5de2b038 100644 --- a/lightning-invoice/src/de.rs +++ b/lightning-invoice/src/de.rs @@ -23,8 +23,8 @@ use secp256k1::recovery::{RecoveryId, RecoverableSignature}; use secp256k1::key::PublicKey; use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp, - SemanticError, PrivateRoute, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice, constants, SignedRawInvoice, - RawDataPart, InvoiceFeatures}; + SemanticError, PrivateRoute, ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice, + constants, SignedRawInvoice, RawDataPart, InvoiceFeatures}; use self::hrp_sm::parse_hrp; @@ -619,46 +619,6 @@ impl FromBase32 for PrivateRoute { } } -/// Errors that indicate what is wrong with the invoice. They have some granularity for debug -/// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user. -#[allow(missing_docs)] -#[derive(PartialEq, Debug, Clone)] -pub enum ParseError { - Bech32Error(bech32::Error), - ParseAmountError(ParseIntError), - MalformedSignature(secp256k1::Error), - BadPrefix, - UnknownCurrency, - UnknownSiPrefix, - MalformedHRP, - TooShortDataPart, - UnexpectedEndOfTaggedFields, - DescriptionDecodeError(str::Utf8Error), - PaddingError, - IntegerOverflowError, - InvalidSegWitProgramLength, - InvalidPubKeyHashLength, - InvalidScriptHashLength, - InvalidRecoveryId, - InvalidSliceLength(String), - - /// Not an error, but used internally to signal that a part of the invoice should be ignored - /// according to BOLT11 - Skip, -} - -/// Indicates that something went wrong while parsing or validating the invoice. Parsing errors -/// should be mostly seen as opaque and are only there for debugging reasons. Semantic errors -/// like wrong signatures, missing fields etc. could mean that someone tampered with the invoice. -#[derive(PartialEq, Debug, Clone)] -pub enum ParseOrSemanticError { - /// The invoice couldn't be decoded - ParseError(ParseError), - - /// The invoice could be decoded but violates the BOLT11 standard - SemanticError(::SemanticError), -} - impl Display for ParseError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index 1dd7123a..5784607d 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -53,9 +53,11 @@ use secp256k1::recovery::RecoverableSignature; use core::fmt::{Display, Formatter, self}; use core::iter::FilterMap; +use core::num::ParseIntError; use core::ops::Deref; use core::slice::Iter; use core::time::Duration; +use core::str; mod de; mod ser; @@ -86,7 +88,45 @@ mod sync { #[cfg(not(feature = "std"))] mod sync; -pub use de::{ParseError, ParseOrSemanticError}; +/// Errors that indicate what is wrong with the invoice. They have some granularity for debug +/// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user. +#[allow(missing_docs)] +#[derive(PartialEq, Debug, Clone)] +pub enum ParseError { + Bech32Error(bech32::Error), + ParseAmountError(ParseIntError), + MalformedSignature(secp256k1::Error), + BadPrefix, + UnknownCurrency, + UnknownSiPrefix, + MalformedHRP, + TooShortDataPart, + UnexpectedEndOfTaggedFields, + DescriptionDecodeError(str::Utf8Error), + PaddingError, + IntegerOverflowError, + InvalidSegWitProgramLength, + InvalidPubKeyHashLength, + InvalidScriptHashLength, + InvalidRecoveryId, + InvalidSliceLength(String), + + /// Not an error, but used internally to signal that a part of the invoice should be ignored + /// according to BOLT11 + Skip, +} + +/// Indicates that something went wrong while parsing or validating the invoice. Parsing errors +/// should be mostly seen as opaque and are only there for debugging reasons. Semantic errors +/// like wrong signatures, missing fields etc. could mean that someone tampered with the invoice. +#[derive(PartialEq, Debug, Clone)] +pub enum ParseOrSemanticError { + /// The invoice couldn't be decoded + ParseError(ParseError), + + /// The invoice could be decoded but violates the BOLT11 standard + SemanticError(::SemanticError), +} /// The number of bits used to represent timestamps as defined in BOLT 11. const TIMESTAMP_BITS: usize = 35; diff --git a/lightning-net-tokio/Cargo.toml b/lightning-net-tokio/Cargo.toml index 3f3703c6..40734ff2 100644 --- a/lightning-net-tokio/Cargo.toml +++ b/lightning-net-tokio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-net-tokio" -version = "0.0.105" +version = "0.0.106" authors = ["Matt Corallo"] license = "MIT OR Apache-2.0" repository = "https://github.com/lightningdevkit/rust-lightning/" @@ -16,7 +16,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] bitcoin = "0.27" -lightning = { version = "0.0.105", path = "../lightning" } +lightning = { version = "0.0.106", path = "../lightning" } tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "sync", "net", "time" ] } [dev-dependencies] diff --git a/lightning-persister/Cargo.toml b/lightning-persister/Cargo.toml index 0e786eb4..d97cd017 100644 --- a/lightning-persister/Cargo.toml +++ b/lightning-persister/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning-persister" -version = "0.0.105" +version = "0.0.106" authors = ["Valentine Wallace", "Matt Corallo"] license = "MIT OR Apache-2.0" repository = "https://github.com/lightningdevkit/rust-lightning/" @@ -17,11 +17,11 @@ _bench_unstable = ["lightning/_bench_unstable"] [dependencies] bitcoin = "0.27" -lightning = { version = "0.0.105", path = "../lightning" } +lightning = { version = "0.0.106", path = "../lightning" } libc = "0.2" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["winbase"] } [dev-dependencies] -lightning = { version = "0.0.105", path = "../lightning", features = ["_test_utils"] } +lightning = { version = "0.0.106", path = "../lightning", features = ["_test_utils"] } diff --git a/lightning-persister/src/lib.rs b/lightning-persister/src/lib.rs index ef914700..da64cb37 100644 --- a/lightning-persister/src/lib.rs +++ b/lightning-persister/src/lib.rs @@ -16,6 +16,7 @@ extern crate libc; use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::hashes::hex::{FromHex, ToHex}; +use lightning::routing::network_graph::NetworkGraph; use crate::util::DiskWriteable; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; @@ -66,6 +67,12 @@ where } } +impl DiskWriteable for NetworkGraph { + fn write_to_file(&self, writer: &mut fs::File) -> Result<(), std::io::Error> { + self.write(writer) + } +} + impl FilesystemPersister { /// Initialize a new FilesystemPersister and set the path to the individual channels' /// files. @@ -103,6 +110,13 @@ impl FilesystemPersister { util::write_to_file(path, "manager".to_string(), manager) } + /// Write the provided `NetworkGraph` to the path provided at `FilesystemPersister` + /// initialization, within a file called "network_graph" + pub fn persist_network_graph(data_dir: String, network_graph: &NetworkGraph) -> Result<(), std::io::Error> { + let path = PathBuf::from(data_dir); + util::write_to_file(path, "network_graph".to_string(), network_graph) + } + /// Read `ChannelMonitor`s from disk. pub fn read_channelmonitors ( &self, keys_manager: K diff --git a/lightning/Cargo.toml b/lightning/Cargo.toml index f38bb805..a9df7667 100644 --- a/lightning/Cargo.toml +++ b/lightning/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightning" -version = "0.0.105" +version = "0.0.106" authors = ["Matt Corallo"] license = "MIT OR Apache-2.0" repository = "https://github.com/lightningdevkit/rust-lightning/" @@ -32,7 +32,10 @@ _bench_unstable = [] no-std = ["hashbrown", "bitcoin/no-std", "core2/alloc"] std = ["bitcoin/std"] -default = ["std"] +# Generates low-r bitcoin signatures, which saves 1 byte in 50% of the cases +grind_signatures = [] + +default = ["std", "grind_signatures"] [dependencies] bitcoin = { version = "0.27", default-features = false, features = ["secp-recovery"] } diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 1daeec4e..be310362 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -31,7 +31,7 @@ use bitcoin::secp256k1::recovery::RecoverableSignature; use bitcoin::secp256k1; use util::{byte_utils, transaction_utils}; -use util::crypto::hkdf_extract_expand_twice; +use util::crypto::{hkdf_extract_expand_twice, sign}; use util::ser::{Writeable, Writer, Readable, ReadableArgs}; use chain::transaction::OutPoint; @@ -590,7 +590,7 @@ impl InMemorySigner { let remotepubkey = self.pubkeys().payment_point; let witness_script = bitcoin::Address::p2pkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Testnet).script_pubkey(); let sighash = hash_to_message!(&bip143::SigHashCache::new(spend_tx).signature_hash(input_idx, &witness_script, descriptor.output.value, SigHashType::All)[..]); - let remotesig = secp_ctx.sign(&sighash, &self.payment_key); + let remotesig = sign(secp_ctx, &sighash, &self.payment_key); let payment_script = bitcoin::Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Bitcoin).unwrap().script_pubkey(); if payment_script != descriptor.output.script_pubkey { return Err(()); } @@ -624,7 +624,7 @@ impl InMemorySigner { let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key); let witness_script = chan_utils::get_revokeable_redeemscript(&descriptor.revocation_pubkey, descriptor.to_self_delay, &delayed_payment_pubkey); let sighash = hash_to_message!(&bip143::SigHashCache::new(spend_tx).signature_hash(input_idx, &witness_script, descriptor.output.value, SigHashType::All)[..]); - let local_delayedsig = secp_ctx.sign(&sighash, &delayed_payment_key); + let local_delayedsig = sign(secp_ctx, &sighash, &delayed_payment_key); let payment_script = bitcoin::Address::p2wsh(&witness_script, Network::Bitcoin).script_pubkey(); if descriptor.output.script_pubkey != payment_script { return Err(()); } @@ -673,7 +673,7 @@ impl BaseSign for InMemorySigner { let htlc_sighashtype = if self.opt_anchors() { SigHashType::SinglePlusAnyoneCanPay } else { SigHashType::All }; let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype)[..]); let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key).map_err(|_| ())?; - htlc_sigs.push(secp_ctx.sign(&htlc_sighash, &holder_htlc_key)); + htlc_sigs.push(sign(secp_ctx, &htlc_sighash, &holder_htlc_key)); } Ok((commitment_sig, htlc_sigs)) @@ -714,7 +714,7 @@ impl BaseSign for InMemorySigner { }; let mut sighash_parts = bip143::SigHashCache::new(justice_tx); let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &revocation_key)) + return Ok(sign(secp_ctx, &sighash, &revocation_key)) } fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { @@ -728,7 +728,7 @@ impl BaseSign for InMemorySigner { }; let mut sighash_parts = bip143::SigHashCache::new(justice_tx); let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &revocation_key)) + return Ok(sign(secp_ctx, &sighash, &revocation_key)) } fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { @@ -742,7 +742,7 @@ impl BaseSign for InMemorySigner { } else { return Err(()) }; let mut sighash_parts = bip143::SigHashCache::new(htlc_tx); let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &htlc_key)) + return Ok(sign(secp_ctx, &sighash, &htlc_key)) } Err(()) } @@ -756,7 +756,7 @@ impl BaseSign for InMemorySigner { fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1) -> Result<(Signature, Signature), ()> { let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); - Ok((secp_ctx.sign(&msghash, &self.node_secret), secp_ctx.sign(&msghash, &self.funding_key))) + Ok((sign(secp_ctx, &msghash, &self.node_secret), sign(secp_ctx, &msghash, &self.funding_key))) } fn ready_channel(&mut self, channel_parameters: &ChannelTransactionParameters) { @@ -1102,7 +1102,7 @@ impl KeysManager { if payment_script != output.script_pubkey { return Err(()); }; let sighash = hash_to_message!(&bip143::SigHashCache::new(&spend_tx).signature_hash(input_idx, &witness_script, output.value, SigHashType::All)[..]); - let sig = secp_ctx.sign(&sighash, &secret.private_key.key); + let sig = sign(secp_ctx, &sighash, &secret.private_key.key); spend_tx.input[input_idx].witness.push(sig.serialize_der().to_vec()); spend_tx.input[input_idx].witness[0].push(SigHashType::All as u8); spend_tx.input[input_idx].witness.push(pubkey.key.serialize().to_vec()); diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 6dc05c2e..370c0cc8 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -39,6 +39,7 @@ use util::transaction_utils::sort_outputs; use ln::channel::{INITIAL_COMMITMENT_NUMBER, ANCHOR_OUTPUT_VALUE_SATOSHI}; use core::ops::Deref; use chain; +use util::crypto::sign; pub(crate) const MAX_HTLCS: u16 = 483; @@ -841,7 +842,7 @@ impl HolderCommitmentTransaction { pub fn dummy() -> Self { let secp_ctx = Secp256k1::new(); let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); - let dummy_sig = secp_ctx.sign(&secp256k1::Message::from_slice(&[42; 32]).unwrap(), &SecretKey::from_slice(&[42; 32]).unwrap()); + let dummy_sig = sign(&secp_ctx, &secp256k1::Message::from_slice(&[42; 32]).unwrap(), &SecretKey::from_slice(&[42; 32]).unwrap()); let keys = TxCreationKeys { per_commitment_point: dummy_key.clone(), @@ -936,7 +937,7 @@ impl BuiltCommitmentTransaction { /// because we are about to broadcast a holder transaction. pub fn sign(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1) -> Signature { let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis); - secp_ctx.sign(&sighash, funding_key) + sign(secp_ctx, &sighash, funding_key) } } @@ -1060,7 +1061,7 @@ impl<'a> TrustedClosingTransaction<'a> { /// because we are about to broadcast a holder transaction. pub fn sign(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1) -> Signature { let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis); - secp_ctx.sign(&sighash, funding_key) + sign(secp_ctx, &sighash, funding_key) } } @@ -1415,7 +1416,7 @@ impl<'a> TrustedCommitmentTransaction<'a> { let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); let sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, SigHashType::All)[..]); - ret.push(secp_ctx.sign(&sighash, &holder_htlc_key)); + ret.push(sign(secp_ctx, &sighash, &holder_htlc_key)); } Ok(ret) } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 71e0ea12..9ccdf816 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -810,6 +810,31 @@ impl Channel { self.channel_transaction_parameters.opt_anchors.is_some() } + fn get_initial_channel_type(config: &UserConfig) -> ChannelTypeFeatures { + // The default channel type (ie the first one we try) depends on whether the channel is + // public - if it is, we just go with `only_static_remotekey` as it's the only option + // available. If it's private, we first try `scid_privacy` as it provides better privacy + // with no other changes, and fall back to `only_static_remotekey` + let mut ret = ChannelTypeFeatures::only_static_remote_key(); + if !config.channel_options.announced_channel && config.own_channel_config.negotiate_scid_privacy { + ret.set_scid_privacy_required(); + } + ret + } + + /// If we receive an error message, it may only be a rejection of the channel type we tried, + /// not of our ability to open any channel at all. Thus, on error, we should first call this + /// and see if we get a new `OpenChannel` message, otherwise the channel is failed. + pub(crate) fn maybe_handle_error_without_close(&mut self, chain_hash: BlockHash) -> Result { + if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); } + if self.channel_type == ChannelTypeFeatures::only_static_remote_key() { + // We've exhausted our options + return Err(()); + } + self.channel_type = ChannelTypeFeatures::only_static_remote_key(); // We only currently support two types + Ok(self.get_open_channel(chain_hash)) + } + // Constructors: pub fn new_outbound( fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, @@ -967,10 +992,7 @@ impl Channel { #[cfg(any(test, fuzzing))] historical_inbound_htlc_fulfills: HashSet::new(), - // We currently only actually support one channel type, so don't retry with new types - // on error messages. When we support more we'll need fallback support (assuming we - // want to support old types). - channel_type: ChannelTypeFeatures::only_static_remote_key(), + channel_type: Self::get_initial_channel_type(&config), }) } @@ -1009,6 +1031,7 @@ impl Channel { L::Target: Logger, { let opt_anchors = false; // TODO - should be based on features + let announced_channel = if (msg.channel_flags & 1) == 1 { true } else { false }; // First check the channel type is known, failing before we do anything else if we don't // support this channel type. @@ -1016,8 +1039,18 @@ impl Channel { if channel_type.supports_any_optional_bits() { return Err(ChannelError::Close("Channel Type field contained optional bits - this is not allowed".to_owned())); } - if *channel_type != ChannelTypeFeatures::only_static_remote_key() { - return Err(ChannelError::Close("Channel Type was not understood".to_owned())); + // We currently only allow two channel types, so write it all out here - we allow + // `only_static_remote_key` in all contexts, and further allow + // `static_remote_key|scid_privacy` if the channel is not publicly announced. + let mut allowed_type = ChannelTypeFeatures::only_static_remote_key(); + if *channel_type != allowed_type { + allowed_type.set_scid_privacy_required(); + if *channel_type != allowed_type { + return Err(ChannelError::Close("Channel Type was not understood".to_owned())); + } + if announced_channel { + return Err(ChannelError::Close("SCID Alias/Privacy Channel Type cannot be set on a public channel".to_owned())); + } } channel_type.clone() } else { @@ -1098,14 +1131,13 @@ impl Channel { // Convert things into internal flags and prep our state: - let announce = if (msg.channel_flags & 1) == 1 { true } else { false }; if config.peer_channel_config_limits.force_announced_channel_preference { - if local_config.announced_channel != announce { + if local_config.announced_channel != announced_channel { return Err(ChannelError::Close("Peer tried to open channel but their announcement preference is different from ours".to_owned())); } } // we either accept their preference or the preferences match - local_config.announced_channel = announce; + local_config.announced_channel = announced_channel; let holder_selected_channel_reserve_satoshis = Channel::::get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis); if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS { @@ -4232,6 +4264,11 @@ impl Channel { self.user_id } + /// Gets the channel's type + pub fn get_channel_type(&self) -> &ChannelTypeFeatures { + &self.channel_type + } + /// Guaranteed to be Some after both FundingLocked messages have been exchanged (and, thus, /// is_usable() returns true). /// Allowed in any state (including after shutdown) @@ -4745,7 +4782,7 @@ impl Channel { /// should be sent back to the counterparty node. /// /// [`msgs::AcceptChannel`]: crate::ln::msgs::AcceptChannel - pub fn accept_inbound_channel(&mut self) -> msgs::AcceptChannel { + pub fn accept_inbound_channel(&mut self, user_id: u64) -> msgs::AcceptChannel { if self.is_outbound() { panic!("Tried to send accept_channel for an outbound channel?"); } @@ -4759,6 +4796,7 @@ impl Channel { panic!("The inbound channel has already been accepted"); } + self.user_id = user_id; self.inbound_awaiting_accept = false; self.generate_accept_channel_message() @@ -6251,44 +6289,39 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel #[cfg(test)] mod tests { - use bitcoin::util::bip143; - use bitcoin::consensus::encode::serialize; use bitcoin::blockdata::script::{Script, Builder}; - use bitcoin::blockdata::transaction::{Transaction, TxOut, SigHashType}; + use bitcoin::blockdata::transaction::{Transaction, TxOut}; use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::opcodes; use bitcoin::network::constants::Network; - use bitcoin::hashes::hex::FromHex; use hex; - use ln::{PaymentPreimage, PaymentHash}; + use ln::PaymentHash; use ln::channelmanager::{HTLCSource, PaymentId}; - use ln::channel::{Channel,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys}; + use ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator}; use ln::channel::MAX_FUNDING_SATOSHIS; use ln::features::InitFeatures; use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate}; use ln::script::ShutdownScript; use ln::chan_utils; - use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters, htlc_success_tx_weight, htlc_timeout_tx_weight}; + use ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight}; use chain::BestBlock; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; - use chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface, BaseSign}; + use chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface}; use chain::transaction::OutPoint; use util::config::UserConfig; use util::enforcing_trait_impls::EnforcingSigner; use util::errors::APIError; use util::test_utils; use util::test_utils::OnGetShutdownScriptpubkey; - use util::logger::Logger; - use bitcoin::secp256k1::{Secp256k1, Message, Signature, All}; + use bitcoin::secp256k1::{Secp256k1, Signature}; use bitcoin::secp256k1::ffi::Signature as FFISignature; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use bitcoin::secp256k1::recovery::RecoverableSignature; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; - use bitcoin::hash_types::{Txid, WPubkeyHash}; + use bitcoin::hash_types::WPubkeyHash; use core::num::NonZeroU8; use bitcoin::bech32::u5; - use sync::Arc; use prelude::*; struct TestFeeEstimator { @@ -6342,7 +6375,8 @@ mod tests { fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { panic!(); } } - fn public_from_secret_hex(secp_ctx: &Secp256k1, hex: &str) -> PublicKey { + #[cfg(not(feature = "grind_signatures"))] + fn public_from_secret_hex(secp_ctx: &Secp256k1, hex: &str) -> PublicKey { PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(hex).unwrap()[..]).unwrap()) } @@ -6420,7 +6454,7 @@ mod tests { let mut node_b_chan = Channel::::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(); + let mut accept_channel_msg = node_b_chan.accept_inbound_channel(0); accept_channel_msg.dust_limit_satoshis = 546; node_a_chan.accept_channel(&accept_channel_msg, &config.peer_channel_config_limits, &InitFeatures::known()).unwrap(); node_a_chan.holder_dust_limit_satoshis = 1560; @@ -6538,7 +6572,7 @@ mod tests { let mut node_b_chan = Channel::::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(); + let accept_channel_msg = node_b_chan.accept_inbound_channel(0); node_a_chan.accept_channel(&accept_channel_msg, &config.peer_channel_config_limits, &InitFeatures::known()).unwrap(); // Node A --> Node B: funding created @@ -6628,8 +6662,22 @@ mod tests { } } + #[cfg(not(feature = "grind_signatures"))] #[test] fn outbound_commitment_test() { + use bitcoin::util::bip143; + use bitcoin::consensus::encode::serialize; + use bitcoin::blockdata::transaction::SigHashType; + use bitcoin::hashes::hex::FromHex; + use bitcoin::hash_types::Txid; + use bitcoin::secp256k1::Message; + use chain::keysinterface::BaseSign; + use ln::PaymentPreimage; + use ln::channel::{HTLCOutputInCommitment ,TxCreationKeys}; + use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters}; + use util::logger::Logger; + use sync::Arc; + // Test vectors from BOLT 3 Appendices C and F (anchors): let feeest = TestFeeEstimator{fee_est: 15000}; let logger : Arc = Arc::new(test_utils::TestLogger::new()); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 2e53b274..7323930f 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -42,7 +42,7 @@ use chain::transaction::{OutPoint, TransactionData}; // construct one themselves. use ln::{inbound_payment, PaymentHash, PaymentPreimage, PaymentSecret}; use ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch}; -use ln::features::{InitFeatures, NodeFeatures}; +use ln::features::{ChannelTypeFeatures, InitFeatures, NodeFeatures}; use routing::router::{PaymentParameters, Route, RouteHop, RoutePath, RouteParameters}; use ln::msgs; use ln::msgs::NetAddress; @@ -53,7 +53,7 @@ use util::config::UserConfig; use util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason}; use util::{byte_utils, events}; use util::scid_utils::fake_scid; -use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer}; +use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer, VecWriter}; use util::logger::{Level, Logger}; use util::errors::APIError; @@ -69,6 +69,7 @@ use core::ops::Deref; #[cfg(any(test, feature = "std"))] use std::time::Instant; +use util::crypto::sign; // We hold various information about HTLC relay in the HTLC objects in Channel itself: // @@ -227,6 +228,7 @@ impl core::hash::Hash for HTLCSource { } } } +#[cfg(not(feature = "grind_signatures"))] #[cfg(test)] impl HTLCSource { pub fn dummy() -> Self { @@ -938,6 +940,10 @@ pub struct ChannelDetails { /// Note that, if this has been set, `channel_id` will be equivalent to /// `funding_txo.unwrap().to_channel_id()`. pub funding_txo: Option, + /// The features which this channel operates with. See individual features for more info. + /// + /// `None` until negotiation completes and the channel type is finalized. + pub channel_type: Option, /// The position of the funding transaction in the chain. None if the funding transaction has /// not yet been confirmed and the channel fully opened. /// @@ -952,6 +958,9 @@ pub struct ChannelDetails { /// counterparty will recognize the alias provided here in place of the [`short_channel_id`] /// when they see a payment to be routed to us. /// + /// Our counterparty may choose to rotate this value at any time, though will always recognize + /// previous values for inbound payment forwarding. + /// /// [`short_channel_id`]: Self::short_channel_id pub inbound_scid_alias: Option, /// The value, in satoshis, of this channel as appears in the funding output @@ -1040,9 +1049,12 @@ pub struct ChannelDetails { } 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. + /// Gets the current 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. + /// + /// This is either the [`ChannelDetails::inbound_scid_alias`], if set, or the + /// [`ChannelDetails::short_channel_id`]. See those for more information. pub fn get_inbound_payment_scid(&self) -> Option { self.inbound_scid_alias.or(self.short_channel_id) } @@ -1660,6 +1672,9 @@ impl ChannelMana forwarding_info: channel.counterparty_forwarding_info(), }, funding_txo: channel.get_funding_txo(), + // Note that accept_channel (or open_channel) is always the first message, so + // `have_received_message` indicates that type negotiation has completed. + channel_type: if channel.have_received_message() { Some(channel.get_channel_type().clone()) } else { None }, short_channel_id: channel.get_short_channel_id(), inbound_scid_alias: channel.latest_inbound_scid_alias(), channel_value_satoshis: channel.get_value_satoshis(), @@ -2144,15 +2159,19 @@ impl ChannelMana }; let (chan_update_opt, forwardee_cltv_expiry_delta) = if let Some(forwarding_id) = forwarding_id_opt { let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap(); - // Leave channel updates as None for private channels. - let chan_update_opt = if chan.should_announce() { - Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None }; if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels { // Note that the behavior here should be identical to the above block - we // should NOT reveal the existence or non-existence of a private channel if // we don't allow forwards outbound over them. - break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None)); + break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None)); + } + if chan.get_channel_type().supports_scid_privacy() && *short_channel_id != chan.outbound_scid_alias() { + // `option_scid_alias` (referred to in LDK as `scid_privacy`) means + // "refuse to forward unless the SCID alias was used", so we pretend + // we don't have the channel here. + break Some(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None)); } + let chan_update_opt = self.get_channel_update_for_onion(*short_channel_id, chan).ok(); // Note that we could technically not return an error yet here and just hope // that the connection is reestablished or monitor updated by the time we get @@ -2202,21 +2221,22 @@ impl ChannelMana break None; } { - let mut res = Vec::with_capacity(8 + 128); + let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 8 + 2)); if let Some(chan_update) = chan_update { if code == 0x1000 | 11 || code == 0x1000 | 12 { - res.extend_from_slice(&byte_utils::be64_to_array(msg.amount_msat)); + msg.amount_msat.write(&mut res).expect("Writes cannot fail"); } else if code == 0x1000 | 13 { - res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry)); + msg.cltv_expiry.write(&mut res).expect("Writes cannot fail"); } else if code == 0x1000 | 20 { // TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791 - res.extend_from_slice(&byte_utils::be16_to_array(0)); + 0u16.write(&mut res).expect("Writes cannot fail"); } - res.extend_from_slice(&chan_update.encode_with_len()[..]); + (chan_update.serialized_length() as u16).write(&mut res).expect("Writes cannot fail"); + chan_update.write(&mut res).expect("Writes cannot fail"); } - return_err!(err, code, &res[..]); + return_err!(err, code, &res.0[..]); } } } @@ -2252,6 +2272,10 @@ impl ChannelMana Some(id) => id, }; + self.get_channel_update_for_onion(short_channel_id, chan) + } + fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel) -> Result { + log_trace!(self.logger, "Generating channel update for channel {}", log_bytes!(chan.channel_id())); let were_node_one = PublicKey::from_secret_key(&self.secp_ctx, &self.our_network_key).serialize()[..] < chan.get_counterparty_node_id().serialize()[..]; let unsigned = msgs::UnsignedChannelUpdate { @@ -2790,7 +2814,7 @@ impl ChannelMana excess_data: Vec::new(), }; let msghash = hash_to_message!(&Sha256dHash::hash(&announcement.encode()[..])[..]); - let node_announce_sig = self.secp_ctx.sign(&msghash, &self.our_network_key); + let node_announce_sig = sign(&self.secp_ctx, &msghash, &self.our_network_key); let mut channel_state_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_state_lock; @@ -2941,9 +2965,9 @@ impl ChannelMana } else { panic!("Stated return value requirements in send_htlc() were not met"); } - let chan_update = self.get_channel_update_for_unicast(chan.get()).unwrap(); + let (failure_code, data) = self.get_htlc_temp_fail_err_and_data(0x1000|7, short_chan_id, chan.get()); failed_forwards.push((htlc_source, payment_hash, - HTLCFailReason::Reason { failure_code: 0x1000 | 7, data: chan_update.encode_with_len() } + HTLCFailReason::Reason { failure_code, data } )); continue; }, @@ -3467,6 +3491,51 @@ impl ChannelMana } else { false } } + /// Gets an HTLC onion failure code and error data for an `UPDATE` error, given the error code + /// that we want to return and a channel. + /// + /// This is for failures on the channel on which the HTLC was *received*, not failures + /// forwarding + fn get_htlc_inbound_temp_fail_err_and_data(&self, desired_err_code: u16, chan: &Channel) -> (u16, Vec) { + // We can't be sure what SCID was used when relaying inbound towards us, so we have to + // guess somewhat. If its a public channel, we figure best to just use the real SCID (as + // we're not leaking that we have a channel with the counterparty), otherwise we try to use + // an inbound SCID alias before the real SCID. + let scid_pref = if chan.should_announce() { + chan.get_short_channel_id().or(chan.latest_inbound_scid_alias()) + } else { + chan.latest_inbound_scid_alias().or(chan.get_short_channel_id()) + }; + if let Some(scid) = scid_pref { + self.get_htlc_temp_fail_err_and_data(desired_err_code, scid, chan) + } else { + (0x4000|10, Vec::new()) + } + } + + + /// Gets an HTLC onion failure code and error data for an `UPDATE` error, given the error code + /// that we want to return and a channel. + fn get_htlc_temp_fail_err_and_data(&self, desired_err_code: u16, scid: u64, chan: &Channel) -> (u16, Vec) { + debug_assert_eq!(desired_err_code & 0x1000, 0x1000); + if let Ok(upd) = self.get_channel_update_for_onion(scid, chan) { + let mut enc = VecWriter(Vec::with_capacity(upd.serialized_length() + 4)); + if desired_err_code == 0x1000 | 20 { + // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791 + 0u16.write(&mut enc).expect("Writes cannot fail"); + } + (upd.serialized_length() as u16).write(&mut enc).expect("Writes cannot fail"); + upd.write(&mut enc).expect("Writes cannot fail"); + (desired_err_code, enc.0) + } else { + // If we fail to get a unicast channel_update, it implies we don't yet have an SCID, + // which means we really shouldn't have gotten a payment to be forwarded over this + // channel yet, or if we did it's from a route hint. Either way, returning an error of + // PERM|no_such_channel should be fine. + (0x4000|10, Vec::new()) + } + } + // Fail a list of HTLCs that were just freed from the holding cell. The HTLCs need to be // failed backwards or, if they were one of our outgoing HTLCs, then their failure needs to // be surfaced to the user. @@ -3477,11 +3546,7 @@ impl ChannelMana let (failure_code, onion_failure_data) = match self.channel_state.lock().unwrap().by_id.entry(channel_id) { hash_map::Entry::Occupied(chan_entry) => { - if let Ok(upd) = self.get_channel_update_for_unicast(&chan_entry.get()) { - (0x1000|7, upd.encode_with_len()) - } else { - (0x4000|10, Vec::new()) - } + self.get_htlc_inbound_temp_fail_err_and_data(0x1000|7, &chan_entry.get()) }, hash_map::Entry::Vacant(_) => (0x4000|10, Vec::new()) }; @@ -3994,10 +4059,12 @@ impl ChannelMana // channel_update later through the announcement_signatures process for public // channels, but there's no reason not to just inform our counterparty of our fees // now. - Some(events::MessageSendEvent::SendChannelUpdate { - node_id: channel.get().get_counterparty_node_id(), - msg: self.get_channel_update_for_unicast(channel.get()).unwrap(), - }) + if let Ok(msg) = self.get_channel_update_for_unicast(channel.get()) { + Some(events::MessageSendEvent::SendChannelUpdate { + node_id: channel.get().get_counterparty_node_id(), + msg, + }) + } else { None } } else { None }; chan_restoration_res = handle_chan_restoration_locked!(self, channel_lock, channel_state, channel, updates.raa, updates.commitment_update, updates.order, None, updates.accepted_htlcs, updates.funding_broadcastable, updates.funding_locked, updates.announcement_sigs); if let Some(upd) = channel_update { @@ -4017,8 +4084,13 @@ impl ChannelMana /// /// The `temporary_channel_id` parameter indicates which inbound channel should be accepted. /// - /// [`Event::OpenChannelRequest`]: crate::util::events::Event::OpenChannelRequest - pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32]) -> Result<(), APIError> { + /// For inbound channels, the `user_channel_id` parameter will be provided back in + /// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond + /// with which `accept_inbound_channel` call. + /// + /// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest + /// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id + pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], user_channel_id: u64) -> Result<(), APIError> { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); let mut channel_state_lock = self.channel_state.lock().unwrap(); @@ -4030,7 +4102,7 @@ impl ChannelMana } channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel { node_id: channel.get().get_counterparty_node_id(), - msg: channel.get_mut().accept_inbound_channel(), + msg: channel.get_mut().accept_inbound_channel(user_channel_id), }); } hash_map::Entry::Vacant(_) => { @@ -4071,7 +4143,7 @@ impl ChannelMana if !self.default_configuration.manually_accept_inbound_channels { channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel { node_id: counterparty_node_id.clone(), - msg: channel.accept_inbound_channel(), + msg: channel.accept_inbound_channel(0), }); } else { let mut pending_events = self.pending_events.lock().unwrap(); @@ -4081,6 +4153,7 @@ impl ChannelMana counterparty_node_id: counterparty_node_id.clone(), funding_satoshis: msg.funding_satoshis, push_msat: msg.push_msat, + channel_type: channel.get_channel_type().clone(), } ); } @@ -4232,10 +4305,12 @@ impl ChannelMana // channel_update here if the channel is not public, i.e. we're not sending an // announcement_signatures. log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id())); - channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { - node_id: counterparty_node_id.clone(), - msg: self.get_channel_update_for_unicast(chan.get()).unwrap(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) { + channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { + node_id: counterparty_node_id.clone(), + msg, + }); + } } Ok(()) }, @@ -4366,28 +4441,8 @@ impl ChannelMana match pending_forward_info { PendingHTLCStatus::Forward(PendingHTLCInfo { ref incoming_shared_secret, .. }) => { let reason = if (error_code & 0x1000) != 0 { - if let Ok(upd) = self.get_channel_update_for_unicast(chan) { - 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 - if error_code == 0x1000 | 20 { - res.extend_from_slice(&byte_utils::be16_to_array(0)); - } - res.extend_from_slice(&upd.encode_with_len()[..]); - res - }[..]) - } else { - // The only case where we'd be unable to - // successfully get a channel update is if the - // channel isn't in the fully-funded state yet, - // implying our counterparty is trying to route - // payments over the channel back to themselves - // (because no one else should know the short_id - // is a lightning channel yet). We should have - // no problem just calling this - // unknown_next_peer (0x4000|10). - onion_utils::build_first_hop_failure_packet(incoming_shared_secret, 0x4000|10, &[]) - } + let (real_code, error_data) = self.get_htlc_inbound_temp_fail_err_and_data(error_code, chan); + onion_utils::build_first_hop_failure_packet(incoming_shared_secret, real_code, &error_data) } else { onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &[]) }; @@ -4709,10 +4764,12 @@ impl ChannelMana // If the channel is in a usable state (ie the channel is not being shut // down), send a unicast channel_update to our counterparty to make sure // they have the latest channel parameters. - channel_update = Some(events::MessageSendEvent::SendChannelUpdate { - node_id: chan.get().get_counterparty_node_id(), - msg: self.get_channel_update_for_unicast(chan.get()).unwrap(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) { + channel_update = Some(events::MessageSendEvent::SendChannelUpdate { + node_id: chan.get().get_counterparty_node_id(), + msg, + }); + } } let need_lnd_workaround = chan.get_mut().workaround_lnd_bug_4006.take(); chan_restoration_res = handle_chan_restoration_locked!( @@ -5383,20 +5440,21 @@ where let res = f(channel); if let Ok((funding_locked_opt, mut timed_out_pending_htlcs, announcement_sigs)) = res { for (source, payment_hash) in timed_out_pending_htlcs.drain(..) { - let chan_update = self.get_channel_update_for_unicast(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe - timed_out_htlcs.push((source, payment_hash, HTLCFailReason::Reason { - failure_code: 0x1000 | 14, // expiry_too_soon, or at least it is now - data: chan_update, + let (failure_code, data) = self.get_htlc_inbound_temp_fail_err_and_data(0x1000|14 /* expiry_too_soon */, &channel); + timed_out_htlcs.push((source, payment_hash, HTLCFailReason::Reason { + failure_code, data, })); } if let Some(funding_locked) = funding_locked_opt { 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 { - node_id: channel.get_counterparty_node_id(), - msg: self.get_channel_update_for_unicast(channel).unwrap(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(channel) { + pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { + node_id: channel.get_counterparty_node_id(), + msg, + }); + } } else { log_trace!(self.logger, "Sending funding_locked WITHOUT channel_update for {}", log_bytes!(channel.channel_id())); } @@ -5731,6 +5789,23 @@ impl } } } else { + { + // First check if we can advance the channel type and try again. + let mut channel_state = self.channel_state.lock().unwrap(); + if let Some(chan) = channel_state.by_id.get_mut(&msg.channel_id) { + if chan.get_counterparty_node_id() != *counterparty_node_id { + return; + } + if let Ok(msg) = chan.maybe_handle_error_without_close(self.genesis_hash) { + channel_state.pending_msg_events.push(events::MessageSendEvent::SendOpenChannel { + node_id: *counterparty_node_id, + msg, + }); + return; + } + } + } + // Untrusted messages from peer, we throw away the error if id points to a non-existent channel let _ = self.force_close_channel_with_peer(&msg.channel_id, Some(counterparty_node_id), Some(&msg.data)); } @@ -5827,6 +5902,7 @@ impl_writeable_tlv_based!(ChannelCounterparty, { impl_writeable_tlv_based!(ChannelDetails, { (1, inbound_scid_alias, option), (2, channel_id, required), + (3, channel_type, option), (4, counterparty, required), (6, funding_txo, option), (8, short_channel_id, option), diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index 7d7553df..4512ee80 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -143,7 +143,7 @@ mod sealed { // Byte 4 , // Byte 5 - ChannelType, + ChannelType | SCIDPrivacy, ], }); define_context!(NodeContext { @@ -175,7 +175,7 @@ mod sealed { // Byte 4 , // Byte 5 - ChannelType, + ChannelType | SCIDPrivacy, // Byte 6 Keysend, ], @@ -214,6 +214,10 @@ mod sealed { , // Byte 3 , + // Byte 4 + , + // Byte 5 + SCIDPrivacy, ], optional_features: [ // Byte 0 @@ -224,6 +228,10 @@ mod sealed { , // Byte 3 , + // Byte 4 + , + // Byte 5 + , ], }); @@ -388,6 +396,10 @@ mod sealed { define_feature!(45, ChannelType, [InitContext, NodeContext], "Feature flags for `option_channel_type`.", set_channel_type_optional, set_channel_type_required, supports_channel_type, requires_channel_type); + define_feature!(47, SCIDPrivacy, [InitContext, NodeContext, ChannelTypeContext], + "Feature flags for only forwarding with SCID aliasing. Called `option_scid_alias` in the BOLTs", + set_scid_privacy_optional, set_scid_privacy_required, supports_scid_privacy, requires_scid_privacy); + define_feature!(55, Keysend, [NodeContext], "Feature flags for keysend payments.", set_keysend_optional, set_keysend_required, supports_keysend, requires_keysend); @@ -826,6 +838,11 @@ mod tests { assert!(InitFeatures::known().supports_shutdown_anysegwit()); assert!(NodeFeatures::known().supports_shutdown_anysegwit()); + assert!(InitFeatures::known().supports_scid_privacy()); + assert!(NodeFeatures::known().supports_scid_privacy()); + assert!(!InitFeatures::known().requires_scid_privacy()); + assert!(!NodeFeatures::known().requires_scid_privacy()); + let mut init_features = InitFeatures::known(); assert!(init_features.initial_routing_sync()); init_features.clear_initial_routing_sync(); @@ -864,14 +881,14 @@ mod tests { // - basic_mpp // - opt_shutdown_anysegwit // - - // - option_channel_type + // - option_channel_type | option_scid_alias assert_eq!(node_features.flags.len(), 6); assert_eq!(node_features.flags[0], 0b00000010); assert_eq!(node_features.flags[1], 0b01010001); assert_eq!(node_features.flags[2], 0b00000010); assert_eq!(node_features.flags[3], 0b00001000); assert_eq!(node_features.flags[4], 0b00000000); - assert_eq!(node_features.flags[5], 0b00100000); + assert_eq!(node_features.flags[5], 0b10100000); } // Check that cleared flags are kept blank when converting back: diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 70881495..aa6fdc97 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -14,7 +14,7 @@ use chain::{BestBlock, Confirm, Listen, Watch, keysinterface::KeysInterface}; use chain::channelmonitor::ChannelMonitor; use chain::transaction::OutPoint; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; -use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId}; +use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId, MIN_CLTV_EXPIRY_DELTA}; use routing::network_graph::{NetGraphMsgHandler, NetworkGraph}; use routing::router::{PaymentParameters, Route, get_route}; use ln::features::{InitFeatures, InvoiceFeatures}; @@ -396,6 +396,26 @@ macro_rules! get_event_msg { } } +/// Get an error message from the pending events queue. +#[macro_export] +macro_rules! get_err_msg { + ($node: expr, $node_id: expr) => { + { + let events = $node.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + $crate::util::events::MessageSendEvent::HandleError { + action: $crate::ln::msgs::ErrorAction::SendErrorMessage { ref msg }, ref node_id + } => { + assert_eq!(*node_id, $node_id); + (*msg).clone() + }, + _ => panic!("Unexpected event"), + } + } + } +} + /// Get a specific event from the pending events queue. #[macro_export] macro_rules! get_event { @@ -1828,7 +1848,7 @@ pub fn test_default_channel_config() -> UserConfig { let mut default_config = UserConfig::default(); // Set cltv_expiry_delta slightly lower to keep the final CLTV values inside one byte in our // tests so that our script-length checks don't fail (see ACCEPTED_HTLC_SCRIPT_WEIGHT). - default_config.channel_options.cltv_expiry_delta = 6*6; + default_config.channel_options.cltv_expiry_delta = MIN_CLTV_EXPIRY_DELTA; default_config.channel_options.announced_channel = true; default_config.peer_channel_config_limits.force_announced_channel_preference = false; // When most of our tests were written, the default HTLC minimum was fixed at 1000. diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 05d42fba..525b4f33 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -8110,7 +8110,7 @@ fn test_manually_accept_inbound_channel_request() { let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_conf.clone())]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); - nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(manually_accept_conf)).unwrap(); + let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(manually_accept_conf)).unwrap(); let res = 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(), &res); @@ -8122,7 +8122,7 @@ fn test_manually_accept_inbound_channel_request() { let events = nodes[1].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - nodes[1].node.accept_inbound_channel(&temporary_channel_id).unwrap(); + nodes[1].node.accept_inbound_channel(&temporary_channel_id, 23).unwrap(); } _ => panic!("Unexpected event"), } @@ -8136,6 +8136,19 @@ fn test_manually_accept_inbound_channel_request() { } _ => panic!("Unexpected event"), } + + nodes[1].node.force_close_channel(&temp_channel_id).unwrap(); + + let close_msg_ev = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(close_msg_ev.len(), 1); + + let events = nodes[1].node.get_and_clear_pending_events(); + match events[0] { + Event::ChannelClosed { user_channel_id, .. } => { + assert_eq!(user_channel_id, 23); + } + _ => panic!("Unexpected event"), + } } #[test] @@ -8259,8 +8272,8 @@ fn test_can_not_accept_inbound_channel_twice() { let events = nodes[1].node.get_and_clear_pending_events(); match events[0] { Event::OpenChannelRequest { temporary_channel_id, .. } => { - nodes[1].node.accept_inbound_channel(&temporary_channel_id).unwrap(); - let api_res = nodes[1].node.accept_inbound_channel(&temporary_channel_id); + nodes[1].node.accept_inbound_channel(&temporary_channel_id, 0).unwrap(); + let api_res = nodes[1].node.accept_inbound_channel(&temporary_channel_id, 0); match api_res { Err(APIError::APIMisuseError { err }) => { assert_eq!(err, "The channel isn't currently awaiting to be accepted."); @@ -8292,7 +8305,7 @@ fn test_can_not_accept_unknown_inbound_channel() { let node = create_network(1, &node_cfg, &node_chanmgr)[0].node; let unknown_channel_id = [0; 32]; - let api_res = node.accept_inbound_channel(&unknown_channel_id); + let api_res = node.accept_inbound_channel(&unknown_channel_id, 0); match api_res { Err(APIError::ChannelUnavailable { err }) => { assert_eq!(err, "Can't accept a channel that doesn't exist"); diff --git a/lightning/src/ln/onion_route_tests.rs b/lightning/src/ln/onion_route_tests.rs index 070d88dd..706fcb6c 100644 --- a/lightning/src/ln/onion_route_tests.rs +++ b/lightning/src/ln/onion_route_tests.rs @@ -993,4 +993,3 @@ fn test_phantom_failure_reject_payment() { .expected_htlc_error_data(0x4000 | 15, &error_data); expect_payment_failed_conditions!(nodes[0], payment_hash, true, fail_conditions); } - diff --git a/lightning/src/ln/priv_short_conf_tests.rs b/lightning/src/ln/priv_short_conf_tests.rs index 66c1b20d..d3d54467 100644 --- a/lightning/src/ln/priv_short_conf_tests.rs +++ b/lightning/src/ln/priv_short_conf_tests.rs @@ -13,12 +13,13 @@ use chain::Watch; use chain::channelmonitor::ChannelMonitor; +use chain::keysinterface::{Recipient, KeysInterface}; 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 ln::msgs::{ChannelMessageHandler, RoutingMessageHandler, OptionalField}; use util::enforcing_trait_impls::EnforcingSigner; use util::events::{Event, MessageSendEvent, MessageSendEventsProvider}; use util::config::UserConfig; @@ -30,7 +31,12 @@ use core::default::Default; use ln::functional_test_utils::*; +use bitcoin::blockdata::constants::genesis_block; use bitcoin::hash_types::BlockHash; +use bitcoin::hashes::Hash; +use bitcoin::hashes::sha256d::Hash as Sha256dHash; +use bitcoin::network::constants::Network; +use bitcoin::secp256k1::Secp256k1; #[test] fn test_priv_forwarding_rejection() { @@ -284,3 +290,254 @@ fn test_routed_scid_alias() { // Note that because we never send a duplicate funding_locked we can't send a payment through // the 0xdeadbeef SCID alias. } + +#[test] +fn test_scid_privacy_on_pub_channel() { + // Tests rejecting the scid_privacy feature for public channels and that we don't ever try to + // send them. + 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 mut scid_privacy_cfg = test_default_channel_config(); + scid_privacy_cfg.channel_options.announced_channel = true; + scid_privacy_cfg.own_channel_config.negotiate_scid_privacy = true; + nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(scid_privacy_cfg)).unwrap(); + let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()); + + assert!(!open_channel.channel_type.as_ref().unwrap().supports_scid_privacy()); // we ignore `negotiate_scid_privacy` on pub channels + open_channel.channel_type.as_mut().unwrap().set_scid_privacy_required(); + assert_eq!(open_channel.channel_flags & 1, 1); // The `announce_channel` bit is set. + + nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel); + let err = get_err_msg!(nodes[1], nodes[0].node.get_our_node_id()); + assert_eq!(err.data, "SCID Alias/Privacy Channel Type cannot be set on a public channel"); +} + +#[test] +fn test_scid_privacy_negotiation() { + // Tests of the negotiation of SCID alias and falling back to non-SCID-alias if our + // counterparty doesn't support it. + 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 mut scid_privacy_cfg = test_default_channel_config(); + scid_privacy_cfg.channel_options.announced_channel = false; + scid_privacy_cfg.own_channel_config.negotiate_scid_privacy = true; + nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, Some(scid_privacy_cfg)).unwrap(); + + let init_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()); + assert!(init_open_channel.channel_type.as_ref().unwrap().supports_scid_privacy()); + assert!(nodes[0].node.list_channels()[0].channel_type.is_none()); // channel_type is none until counterparty accepts + + // now simulate nodes[1] responding with an Error message, indicating it doesn't understand + // SCID alias. + nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { + channel_id: init_open_channel.temporary_channel_id, + data: "Yo, no SCID aliases, no privacy here!".to_string() + }); + assert!(nodes[0].node.list_channels()[0].channel_type.is_none()); // channel_type is none until counterparty accepts + + let second_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()); + assert!(!second_open_channel.channel_type.as_ref().unwrap().supports_scid_privacy()); + nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &second_open_channel); + nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id())); + + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::FundingGenerationReady { .. } => {}, + _ => panic!("Unexpected event"), + } + + assert!(!nodes[0].node.list_channels()[0].channel_type.as_ref().unwrap().supports_scid_privacy()); + assert!(!nodes[1].node.list_channels()[0].channel_type.as_ref().unwrap().supports_scid_privacy()); +} + +#[test] +fn test_inbound_scid_privacy() { + // Tests accepting channels with the scid_privacy feature and rejecting forwards using the + // channel's real SCID as required by the channel feature. + let chanmon_cfgs = create_chanmon_cfgs(3); + let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); + let mut accept_forward_cfg = test_default_channel_config(); + accept_forward_cfg.accept_forwards_to_priv_channels = true; + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(accept_forward_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, 0, InitFeatures::known(), InitFeatures::known()); + + let mut no_announce_cfg = test_default_channel_config(); + no_announce_cfg.channel_options.announced_channel = false; + no_announce_cfg.own_channel_config.negotiate_scid_privacy = true; + nodes[1].node.create_channel(nodes[2].node.get_our_node_id(), 100_000, 10_000, 42, Some(no_announce_cfg)).unwrap(); + let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[2].node.get_our_node_id()); + + assert!(open_channel.channel_type.as_ref().unwrap().requires_scid_privacy()); + + 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], 100_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 bs_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())); + let bs_update = 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(), &bs_funding_locked); + let cs_update = get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id()); + + nodes[1].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &cs_update); + nodes[2].node.handle_channel_update(&nodes[1].node.get_our_node_id(), &bs_update); + + // Now we can pay just fine using the SCID alias nodes[2] gave to nodes[1]... + + let last_hop = nodes[2].node.list_usable_channels(); + let mut 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.clone(), 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); + + // ... but if we try to pay using the real SCID, nodes[1] will just tell us they don't know + // what channel we're talking about. + hop_hints[0].0[0].short_channel_id = last_hop[0].short_channel_id.unwrap(); + + let (route_2, payment_hash_2, _, payment_secret_2) = get_route_and_payment_hash!(nodes[0], nodes[2], hop_hints, 100_000, 42); + assert_eq!(route_2.paths[0][1].short_channel_id, last_hop[0].short_channel_id.unwrap()); + nodes[0].node.send_payment(&route_2, payment_hash_2, &Some(payment_secret_2)).unwrap(); + check_added_monitors!(nodes[0], 1); + + let payment_event = SendEvent::from_node(&nodes[0]); + assert_eq!(nodes[1].node.get_our_node_id(), payment_event.node_id); + 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, true, true); + + nodes[1].logger.assert_log_regex("lightning::ln::channelmanager".to_string(), regex::Regex::new(r"Refusing to forward over real channel SCID as our counterparty requested").unwrap(), 1); + + let mut updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); + nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]); + commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false); + + expect_payment_failed_conditions!(nodes[0], payment_hash_2, false, + PaymentFailedConditions::new().blamed_scid(last_hop[0].short_channel_id.unwrap()) + .blamed_chan_closed(true).expected_htlc_error_data(0x4000|10, &[0; 0])); +} + +#[test] +fn test_scid_alias_returned() { + // Tests that when we fail an HTLC (in this case due to attempting to forward more than the + // channel's available balance) we use the correct (in this case the aliased) SCID in the + // channel_update which is returned in the onion to the sender. + let chanmon_cfgs = create_chanmon_cfgs(3); + let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); + let mut accept_forward_cfg = test_default_channel_config(); + accept_forward_cfg.accept_forwards_to_priv_channels = true; + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(accept_forward_cfg), None]); + let nodes = create_network(3, &node_cfgs, &node_chanmgrs); + + create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0, InitFeatures::known(), InitFeatures::known()); + create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000, 0, InitFeatures::known(), InitFeatures::known()); + + let last_hop = nodes[2].node.list_usable_channels(); + let mut 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 (mut route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], hop_hints, 10_000, 42); + assert_eq!(route.paths[0][1].short_channel_id, nodes[2].node.list_usable_channels()[0].inbound_scid_alias.unwrap()); + + route.paths[0][1].fee_msat = 10_000_000; // Overshoot the last channel's value + + // Route the HTLC through to the destination. + nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap(); + check_added_monitors!(nodes[0], 1); + let as_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(), &as_updates.update_add_htlcs[0]); + commitment_signed_dance!(nodes[1], nodes[0], &as_updates.commitment_signed, false, true); + + expect_pending_htlcs_forwardable!(nodes[1]); + expect_pending_htlcs_forwardable!(nodes[1]); + check_added_monitors!(nodes[1], 1); + + let bs_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); + nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &bs_updates.update_fail_htlcs[0]); + commitment_signed_dance!(nodes[0], nodes[1], bs_updates.commitment_signed, false, true); + + // Build the expected channel update + let contents = msgs::UnsignedChannelUpdate { + chain_hash: genesis_block(Network::Testnet).header.block_hash(), + short_channel_id: last_hop[0].inbound_scid_alias.unwrap(), + timestamp: 21, + flags: 1, + cltv_expiry_delta: accept_forward_cfg.channel_options.cltv_expiry_delta, + htlc_minimum_msat: 1_000, + htlc_maximum_msat: OptionalField::Present(1_000_000), // Defaults to 10% of the channel value + fee_base_msat: last_hop[0].counterparty.forwarding_info.as_ref().unwrap().fee_base_msat, + fee_proportional_millionths: last_hop[0].counterparty.forwarding_info.as_ref().unwrap().fee_proportional_millionths, + excess_data: Vec::new(), + }; + let msg_hash = Sha256dHash::hash(&contents.encode()[..]); + let signature = Secp256k1::new().sign(&hash_to_message!(&msg_hash[..]), &nodes[1].keys_manager.get_node_secret(Recipient::Node).unwrap()); + let msg = msgs::ChannelUpdate { signature, contents }; + + expect_payment_failed_conditions!(nodes[0], payment_hash, false, + PaymentFailedConditions::new().blamed_scid(last_hop[0].inbound_scid_alias.unwrap()) + .blamed_chan_closed(false).expected_htlc_error_data(0x1000|7, &msg.encode_with_len())); + + route.paths[0][1].fee_msat = 10_000; // Reset to the correct payment amount + route.paths[0][0].fee_msat = 0; // But set fee paid to the middle hop to 0 + + // Route the HTLC through to the destination. + nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap(); + check_added_monitors!(nodes[0], 1); + let as_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(), &as_updates.update_add_htlcs[0]); + commitment_signed_dance!(nodes[1], nodes[0], &as_updates.commitment_signed, false, true); + + let bs_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); + nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &bs_updates.update_fail_htlcs[0]); + commitment_signed_dance!(nodes[0], nodes[1], bs_updates.commitment_signed, false, true); + + let mut err_data = Vec::new(); + err_data.extend_from_slice(&10_000u64.to_be_bytes()); + err_data.extend_from_slice(&msg.encode_with_len()); + expect_payment_failed_conditions!(nodes[0], payment_hash, false, + PaymentFailedConditions::new().blamed_scid(last_hop[0].inbound_scid_alias.unwrap()) + .blamed_chan_closed(false).expected_htlc_error_data(0x1000|12, &err_data)); +} diff --git a/lightning/src/routing/network_graph.rs b/lightning/src/routing/network_graph.rs index 012357df..282c8705 100644 --- a/lightning/src/routing/network_graph.rs +++ b/lightning/src/routing/network_graph.rs @@ -401,82 +401,91 @@ where C::Target: chain::Access, L::Target: Logger return (); } - // Send a gossip_timestamp_filter to enable gossip message receipt. Note that we have to - // use a "all timestamps" filter as sending the current timestamp would result in missing - // gossip messages that are simply sent late. We could calculate the intended filter time - // by looking at the current time and subtracting two weeks (before which we'll reject - // messages), but there's not a lot of reason to bother - our peers should be discarding - // the same messages. + // The lightning network's gossip sync system is completely broken in numerous ways. + // + // Given no broadly-available set-reconciliation protocol, the only reasonable approach is + // to do a full sync from the first few peers we connect to, and then receive gossip + // updates from all our peers normally. + // + // Originally, we could simply tell a peer to dump us the entire gossip table on startup, + // wasting lots of bandwidth but ensuring we have the full network graph. After the initial + // dump peers would always send gossip and we'd stay up-to-date with whatever our peer has + // seen. + // + // In order to reduce the bandwidth waste, "gossip queries" were introduced, allowing you + // to ask for the SCIDs of all channels in your peer's routing graph, and then only request + // channel data which you are missing. Except there was no way at all to identify which + // `channel_update`s you were missing, so you still had to request everything, just in a + // very complicated way with some queries instead of just getting the dump. + // + // Later, an option was added to fetch the latest timestamps of the `channel_update`s to + // make efficient sync possible, however it has yet to be implemented in lnd, which makes + // relying on it useless. + // + // After gossip queries were introduced, support for receiving a full gossip table dump on + // connection was removed from several nodes, making it impossible to get a full sync + // without using the "gossip queries" messages. + // + // Once you opt into "gossip queries" the only way to receive any gossip updates that a + // peer receives after you connect, you must send a `gossip_timestamp_filter` message. This + // message, as the name implies, tells the peer to not forward any gossip messages with a + // timestamp older than a given value (not the time the peer received the filter, but the + // timestamp in the update message, which is often hours behind when the peer received the + // message). + // + // Obnoxiously, `gossip_timestamp_filter` isn't *just* a filter, but its also a request for + // your peer to send you the full routing graph (subject to the filter). Thus, in order to + // tell a peer to send you any updates as it sees them, you have to also ask for the full + // routing graph to be synced. If you set a timestamp filter near the current time, peers + // will simply not forward any new updates they see to you which were generated some time + // ago (which is not uncommon). If you instead set a timestamp filter near 0 (or two weeks + // ago), you will always get the full routing graph from all your peers. + // + // Most lightning nodes today opt to simply turn off receiving gossip data which only + // propagated some time after it was generated, and, worse, often disable gossiping with + // several peers after their first connection. The second behavior can cause gossip to not + // propagate fully if there are cuts in the gossiping subgraph. + // + // In an attempt to cut a middle ground between always fetching the full graph from all of + // our peers and never receiving gossip from peers at all, we send all of our peers a + // `gossip_timestamp_filter`, with the filter time set either two weeks ago or an hour ago. + // + // For no-std builds, we bury our head in the sand and do a full sync on each connection. + let should_request_full_sync = self.should_request_full_sync(&their_node_id); + #[allow(unused_mut, unused_assignments)] + let mut gossip_start_time = 0; + #[cfg(feature = "std")] + { + gossip_start_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs(); + if should_request_full_sync { + gossip_start_time -= 60 * 60 * 24 * 7 * 2; // 2 weeks ago + } else { + gossip_start_time -= 60 * 60; // an hour ago + } + } + let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push(MessageSendEvent::SendGossipTimestampFilter { node_id: their_node_id.clone(), msg: GossipTimestampFilter { chain_hash: self.network_graph.genesis_hash, - first_timestamp: 0, + first_timestamp: gossip_start_time as u32, // 2106 issue! timestamp_range: u32::max_value(), }, }); - - // Check if we need to perform a full synchronization with this peer - if !self.should_request_full_sync(&their_node_id) { - return (); - } - - let first_blocknum = 0; - let number_of_blocks = 0xffffffff; - log_debug!(self.logger, "Sending query_channel_range peer={}, first_blocknum={}, number_of_blocks={}", log_pubkey!(their_node_id), first_blocknum, number_of_blocks); - pending_events.push(MessageSendEvent::SendChannelRangeQuery { - node_id: their_node_id.clone(), - msg: QueryChannelRange { - chain_hash: self.network_graph.genesis_hash, - first_blocknum, - number_of_blocks, - }, - }); } - /// Statelessly processes a reply to a channel range query by immediately - /// sending an SCID query with SCIDs in the reply. To keep this handler - /// stateless, it does not validate the sequencing of replies for multi- - /// reply ranges. It does not validate whether the reply(ies) cover the - /// queried range. It also does not filter SCIDs to only those in the - /// original query range. We also do not validate that the chain_hash - /// matches the chain_hash of the NetworkGraph. Any chan_ann message that - /// does not match our chain_hash will be rejected when the announcement is - /// processed. - fn handle_reply_channel_range(&self, their_node_id: &PublicKey, msg: ReplyChannelRange) -> Result<(), LightningError> { - log_debug!(self.logger, "Handling reply_channel_range peer={}, first_blocknum={}, number_of_blocks={}, sync_complete={}, scids={}", log_pubkey!(their_node_id), msg.first_blocknum, msg.number_of_blocks, msg.sync_complete, msg.short_channel_ids.len(),); - - log_debug!(self.logger, "Sending query_short_channel_ids peer={}, batch_size={}", log_pubkey!(their_node_id), msg.short_channel_ids.len()); - let mut pending_events = self.pending_events.lock().unwrap(); - pending_events.push(MessageSendEvent::SendShortIdsQuery { - node_id: their_node_id.clone(), - msg: QueryShortChannelIds { - chain_hash: msg.chain_hash, - short_channel_ids: msg.short_channel_ids, - } - }); - + fn handle_reply_channel_range(&self, _their_node_id: &PublicKey, _msg: ReplyChannelRange) -> Result<(), LightningError> { + // We don't make queries, so should never receive replies. If, in the future, the set + // reconciliation extensions to gossip queries become broadly supported, we should revert + // this code to its state pre-0.0.106. Ok(()) } - /// When an SCID query is initiated the remote peer will begin streaming - /// gossip messages. In the event of a failure, we may have received - /// some channel information. Before trying with another peer, the - /// caller should update its set of SCIDs that need to be queried. - fn handle_reply_short_channel_ids_end(&self, their_node_id: &PublicKey, msg: ReplyShortChannelIdsEnd) -> Result<(), LightningError> { - log_debug!(self.logger, "Handling reply_short_channel_ids_end peer={}, full_information={}", log_pubkey!(their_node_id), msg.full_information); - - // If the remote node does not have up-to-date information for the - // chain_hash they will set full_information=false. We can fail - // the result and try again with a different peer. - if !msg.full_information { - return Err(LightningError { - err: String::from("Received reply_short_channel_ids_end with no information"), - action: ErrorAction::IgnoreError - }); - } - + fn handle_reply_short_channel_ids_end(&self, _their_node_id: &PublicKey, _msg: ReplyShortChannelIdsEnd) -> Result<(), LightningError> { + // We don't make queries, so should never receive replies. If, in the future, the set + // reconciliation extensions to gossip queries become broadly supported, we should revert + // this code to its state pre-0.0.106. Ok(()) } @@ -1376,8 +1385,8 @@ impl NetworkGraph { } } } - macro_rules! maybe_update_channel_info { - ( $target: expr, $src_node: expr) => { + macro_rules! check_update_latest { + ($target: expr) => { if let Some(existing_chan_info) = $target.as_ref() { // The timestamp field is somewhat of a misnomer - the BOLTs use it to // order updates to ensure you always have the latest one, only @@ -1394,7 +1403,11 @@ impl NetworkGraph { } else { chan_was_enabled = false; } + } + } + macro_rules! get_new_channel_info { + () => { { let last_update_message = if msg.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY { full_msg.cloned() } else { None }; @@ -1410,29 +1423,31 @@ impl NetworkGraph { }, last_update_message }; - $target = Some(updated_channel_update_info); - } + Some(updated_channel_update_info) + } } } let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); if msg.flags & 1 == 1 { dest_node_id = channel.node_one.clone(); + check_update_latest!(channel.two_to_one); if let Some((sig, ctx)) = sig_info { secp_verify_sig!(ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_two.as_slice()).map_err(|_| LightningError{ err: "Couldn't parse source node pubkey".to_owned(), action: ErrorAction::IgnoreAndLog(Level::Debug) })?, "channel_update"); } - maybe_update_channel_info!(channel.two_to_one, channel.node_two); + channel.two_to_one = get_new_channel_info!(); } else { dest_node_id = channel.node_two.clone(); + check_update_latest!(channel.one_to_two); if let Some((sig, ctx)) = sig_info { secp_verify_sig!(ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_one.as_slice()).map_err(|_| LightningError{ err: "Couldn't parse destination node pubkey".to_owned(), action: ErrorAction::IgnoreAndLog(Level::Debug) })?, "channel_update"); } - maybe_update_channel_info!(channel.one_to_two, channel.node_one); + channel.one_to_two = get_new_channel_info!(); } } } @@ -1535,7 +1550,7 @@ mod tests { use routing::network_graph::{NetGraphMsgHandler, NetworkGraph, NetworkUpdate, MAX_EXCESS_BYTES_FOR_RELAY}; use ln::msgs::{Init, OptionalField, RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement, UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, - ReplyChannelRange, ReplyShortChannelIdsEnd, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT}; + ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT}; use util::test_utils; use util::logger::Logger; use util::ser::{Readable, Writeable}; @@ -2272,15 +2287,16 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn calling_sync_routing_table() { + use std::time::{SystemTime, UNIX_EPOCH}; + let network_graph = create_network_graph(); let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler(&network_graph); let node_privkey_1 = &SecretKey::from_slice(&[42; 32]).unwrap(); let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_privkey_1); let chain_hash = genesis_block(Network::Testnet).header.block_hash(); - let first_blocknum = 0; - let number_of_blocks = 0xffff_ffff; // It should ignore if gossip_queries feature is not enabled { @@ -2290,132 +2306,23 @@ mod tests { assert_eq!(events.len(), 0); } - // It should send a query_channel_message with the correct information + // It should send a gossip_timestamp_filter with the correct information { let init_msg = Init { features: InitFeatures::known(), remote_network_address: None }; net_graph_msg_handler.peer_connected(&node_id_1, &init_msg); let events = net_graph_msg_handler.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 2); + assert_eq!(events.len(), 1); match &events[0] { MessageSendEvent::SendGossipTimestampFilter{ node_id, msg } => { assert_eq!(node_id, &node_id_1); assert_eq!(msg.chain_hash, chain_hash); - assert_eq!(msg.first_timestamp, 0); + let expected_timestamp = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs(); + assert!((msg.first_timestamp as u64) >= expected_timestamp - 60*60*24*7*2); + assert!((msg.first_timestamp as u64) < expected_timestamp - 60*60*24*7*2 + 10); assert_eq!(msg.timestamp_range, u32::max_value()); }, _ => panic!("Expected MessageSendEvent::SendChannelRangeQuery") }; - match &events[1] { - MessageSendEvent::SendChannelRangeQuery{ node_id, msg } => { - assert_eq!(node_id, &node_id_1); - assert_eq!(msg.chain_hash, chain_hash); - assert_eq!(msg.first_blocknum, first_blocknum); - assert_eq!(msg.number_of_blocks, number_of_blocks); - }, - _ => panic!("Expected MessageSendEvent::SendChannelRangeQuery") - }; - } - - // It should not enqueue a query when should_request_full_sync return false. - // The initial implementation allows syncing with the first 5 peers after - // which should_request_full_sync will return false - { - let network_graph = create_network_graph(); - let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler(&network_graph); - let init_msg = Init { features: InitFeatures::known(), remote_network_address: None }; - for n in 1..7 { - let node_privkey = &SecretKey::from_slice(&[n; 32]).unwrap(); - let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey); - net_graph_msg_handler.peer_connected(&node_id, &init_msg); - let events = net_graph_msg_handler.get_and_clear_pending_msg_events(); - if n <= 5 { - assert_eq!(events.len(), 2); - } else { - // Even after the we stop sending the explicit query, we should still send a - // gossip_timestamp_filter on each new connection. - assert_eq!(events.len(), 1); - } - - } - } - } - - #[test] - fn handling_reply_channel_range() { - let network_graph = create_network_graph(); - let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler(&network_graph); - let node_privkey_1 = &SecretKey::from_slice(&[42; 32]).unwrap(); - let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_privkey_1); - - let chain_hash = genesis_block(Network::Testnet).header.block_hash(); - - // Test receipt of a single reply that should enqueue an SCID query - // matching the SCIDs in the reply - { - let result = net_graph_msg_handler.handle_reply_channel_range(&node_id_1, ReplyChannelRange { - chain_hash, - sync_complete: true, - first_blocknum: 0, - number_of_blocks: 2000, - short_channel_ids: vec![ - 0x0003e0_000000_0000, // 992x0x0 - 0x0003e8_000000_0000, // 1000x0x0 - 0x0003e9_000000_0000, // 1001x0x0 - 0x0003f0_000000_0000, // 1008x0x0 - 0x00044c_000000_0000, // 1100x0x0 - 0x0006e0_000000_0000, // 1760x0x0 - ], - }); - assert!(result.is_ok()); - - // We expect to emit a query_short_channel_ids message with the received scids - let events = net_graph_msg_handler.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 1); - match &events[0] { - MessageSendEvent::SendShortIdsQuery { node_id, msg } => { - assert_eq!(node_id, &node_id_1); - assert_eq!(msg.chain_hash, chain_hash); - assert_eq!(msg.short_channel_ids, vec![ - 0x0003e0_000000_0000, // 992x0x0 - 0x0003e8_000000_0000, // 1000x0x0 - 0x0003e9_000000_0000, // 1001x0x0 - 0x0003f0_000000_0000, // 1008x0x0 - 0x00044c_000000_0000, // 1100x0x0 - 0x0006e0_000000_0000, // 1760x0x0 - ]); - }, - _ => panic!("expected MessageSendEvent::SendShortIdsQuery"), - } - } - } - - #[test] - fn handling_reply_short_channel_ids() { - let network_graph = create_network_graph(); - let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler(&network_graph); - let node_privkey = &SecretKey::from_slice(&[41; 32]).unwrap(); - let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey); - - let chain_hash = genesis_block(Network::Testnet).header.block_hash(); - - // Test receipt of a successful reply - { - let result = net_graph_msg_handler.handle_reply_short_channel_ids_end(&node_id, ReplyShortChannelIdsEnd { - chain_hash, - full_information: true, - }); - assert!(result.is_ok()); - } - - // Test receipt of a reply that indicates the peer does not maintain up-to-date information - // for the chain_hash requested in the query. - { - let result = net_graph_msg_handler.handle_reply_short_channel_ids_end(&node_id, ReplyShortChannelIdsEnd { - chain_hash, - full_information: false, - }); - assert!(result.is_err()); - assert_eq!(result.err().unwrap().err, "Received reply_short_channel_ids_end with no information"); } } diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 677a5716..6584eb5f 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -332,11 +332,9 @@ struct RouteGraphNode { impl cmp::Ord for RouteGraphNode { fn cmp(&self, other: &RouteGraphNode) -> cmp::Ordering { let other_score = cmp::max(other.lowest_fee_to_peer_through_node, other.path_htlc_minimum_msat) - .checked_add(other.path_penalty_msat) - .unwrap_or_else(|| u64::max_value()); + .saturating_add(other.path_penalty_msat); let self_score = cmp::max(self.lowest_fee_to_peer_through_node, self.path_htlc_minimum_msat) - .checked_add(self.path_penalty_msat) - .unwrap_or_else(|| u64::max_value()); + .saturating_add(self.path_penalty_msat); other_score.cmp(&self_score).then_with(|| other.node_id.cmp(&self.node_id)) } } @@ -495,6 +493,10 @@ impl<'a> PaymentPath<'a> { self.hops.last().unwrap().0.fee_msat } + fn get_path_penalty_msat(&self) -> u64 { + self.hops.first().map(|h| h.0.path_penalty_msat).unwrap_or(u64::max_value()) + } + fn get_total_fee_paid_msat(&self) -> u64 { if self.hops.len() < 1 { return 0; @@ -509,6 +511,10 @@ impl<'a> PaymentPath<'a> { return result; } + fn get_cost_msat(&self) -> u64 { + self.get_total_fee_paid_msat().saturating_add(self.get_path_penalty_msat()) + } + // If the amount transferred by the path is updated, the fees should be adjusted. Any other way // to change fees may result in an inconsistency. // @@ -645,7 +651,7 @@ where L::Target: Logger { pub(crate) fn get_route( 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] + logger: L, scorer: &S, random_seed_bytes: &[u8; 32] ) -> Result where L::Target: Logger { let payee_node_id = NodeId::from_pubkey(&payment_params.payee_pubkey); @@ -856,7 +862,7 @@ where L::Target: Logger { .entry(short_channel_id) .or_insert_with(|| $candidate.effective_capacity().as_msat()); - // It is tricky to substract $next_hops_fee_msat from available liquidity here. + // It is tricky to subtract $next_hops_fee_msat from available liquidity here. // It may be misleading because we might later choose to reduce the value transferred // over these channels, and the channel which was insufficient might become sufficient. // Worst case: we drop a good channel here because it can't cover the high following @@ -896,8 +902,7 @@ where L::Target: Logger { .checked_sub(2*MEDIAN_HOP_CLTV_EXPIRY_DELTA) .unwrap_or(payment_params.max_total_cltv_expiry_delta - final_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()); + .saturating_add($candidate.cltv_expiry_delta()); let doesnt_exceed_cltv_delta_limit = hop_total_cltv_delta <= max_total_cltv_expiry_delta; let value_contribution_msat = cmp::min(available_value_contribution_msat, $next_hops_value_contribution); @@ -911,14 +916,20 @@ where L::Target: Logger { let over_path_minimum_msat = amount_to_transfer_over_msat >= $candidate.htlc_minimum_msat() && amount_to_transfer_over_msat >= $next_hops_path_htlc_minimum_msat; + #[allow(unused_comparisons)] // $next_hops_path_htlc_minimum_msat is 0 in some calls so rustc complains + let may_overpay_to_meet_path_minimum_msat = + ((amount_to_transfer_over_msat < $candidate.htlc_minimum_msat() && + recommended_value_msat > $candidate.htlc_minimum_msat()) || + (amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat && + recommended_value_msat > $next_hops_path_htlc_minimum_msat)); + // If HTLC minimum is larger than the amount we're going to transfer, we shouldn't - // bother considering this channel. - // Since we're choosing amount_to_transfer_over_msat as maximum possible, it can - // be only reduced later (not increased), so this channel should just be skipped - // as not sufficient. - if !over_path_minimum_msat && doesnt_exceed_cltv_delta_limit { + // bother considering this channel. If retrying with recommended_value_msat may + // allow us to hit the HTLC minimum limit, set htlc_minimum_limit so that we go + // around again with a higher amount. + if contributes_sufficient_value && doesnt_exceed_cltv_delta_limit && may_overpay_to_meet_path_minimum_msat { hit_minimum_limit = true; - } else if contributes_sufficient_value && doesnt_exceed_cltv_delta_limit { + } else if contributes_sufficient_value && doesnt_exceed_cltv_delta_limit && over_path_minimum_msat { // Note that low contribution here (limited by available_liquidity_msat) // might violate htlc_minimum_msat on the hops which are next along the // payment path (upstream to the payee). To avoid that, we recompute @@ -1004,9 +1015,9 @@ where L::Target: Logger { } } - let path_penalty_msat = $next_hops_path_penalty_msat.checked_add( - scorer.channel_penalty_msat(short_channel_id, amount_to_transfer_over_msat, *available_liquidity_msat, - &$src_node_id, &$dest_node_id)).unwrap_or_else(|| u64::max_value()); + let path_penalty_msat = $next_hops_path_penalty_msat.saturating_add( + scorer.channel_penalty_msat(short_channel_id, amount_to_transfer_over_msat, + *available_liquidity_msat, &$src_node_id, &$dest_node_id)); let new_graph_node = RouteGraphNode { node_id: $src_node_id, lowest_fee_to_peer_through_node: total_fee_msat, @@ -1034,11 +1045,9 @@ where L::Target: Logger { // the fees included in $next_hops_path_htlc_minimum_msat, but also // can't use something that may decrease on future hops. let old_cost = cmp::max(old_entry.total_fee_msat, old_entry.path_htlc_minimum_msat) - .checked_add(old_entry.path_penalty_msat) - .unwrap_or_else(|| u64::max_value()); + .saturating_add(old_entry.path_penalty_msat); let new_cost = cmp::max(total_fee_msat, path_htlc_minimum_msat) - .checked_add(path_penalty_msat) - .unwrap_or_else(|| u64::max_value()); + .saturating_add(path_penalty_msat); if !old_entry.was_processed && new_cost < old_cost { targets.push(new_graph_node); @@ -1222,12 +1231,10 @@ where L::Target: Logger { .unwrap_or_else(|| CandidateRouteHop::PrivateHop { hint: hop }); let capacity_msat = candidate.effective_capacity().as_msat(); aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat - .checked_add(scorer.channel_penalty_msat(hop.short_channel_id, final_value_msat, capacity_msat, &source, &target)) - .unwrap_or_else(|| u64::max_value()); + .saturating_add(scorer.channel_penalty_msat(hop.short_channel_id, final_value_msat, capacity_msat, &source, &target)); aggregate_next_hops_cltv_delta = aggregate_next_hops_cltv_delta - .checked_add(hop.cltv_expiry_delta as u32) - .unwrap_or_else(|| u32::max_value()); + .saturating_add(hop.cltv_expiry_delta as u32); if !add_entry!(candidate, source, target, aggregate_next_hops_fee_msat, path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat, aggregate_next_hops_cltv_delta) { // If this hop was not used then there is no use checking the preceding hops @@ -1393,7 +1400,7 @@ where L::Target: Logger { // If we weren't capped by hitting a liquidity limit on a channel in the path, // we'll probably end up picking the same path again on the next iteration. // Decrease the available liquidity of a hop in the middle of the path. - let victim_scid = payment_path.hops[(payment_path.hops.len() - 1) / 2].0.candidate.short_channel_id(); + let victim_scid = payment_path.hops[(payment_path.hops.len()) / 2].0.candidate.short_channel_id(); log_trace!(logger, "Disabling channel {} for future path building iterations to avoid duplicates.", victim_scid); let victim_liquidity = bookkept_channels_liquidity_available_msat.get_mut(&victim_scid).unwrap(); *victim_liquidity = 0; @@ -1465,24 +1472,31 @@ where L::Target: Logger { } // Sort by total fees and take the best paths. - payment_paths.sort_by_key(|path| path.get_total_fee_paid_msat()); + payment_paths.sort_unstable_by_key(|path| path.get_total_fee_paid_msat()); if payment_paths.len() > 50 { payment_paths.truncate(50); } // Draw multiple sufficient routes by randomly combining the selected paths. let mut drawn_routes = Vec::new(); - for i in 0..payment_paths.len() { + let mut prng = ChaCha20::new(random_seed_bytes, &[0u8; 12]); + let mut random_index_bytes = [0u8; ::core::mem::size_of::()]; + + let num_permutations = payment_paths.len(); + for _ in 0..num_permutations { let mut cur_route = Vec::::new(); let mut aggregate_route_value_msat = 0; // Step (6). - // TODO: real random shuffle - // Currently just starts with i_th and goes up to i-1_th in a looped way. - let cur_payment_paths = [&payment_paths[i..], &payment_paths[..i]].concat(); + // Do a Fisher-Yates shuffle to create a random permutation of the payment paths + for cur_index in (1..payment_paths.len()).rev() { + prng.process_in_place(&mut random_index_bytes); + let random_index = usize::from_be_bytes(random_index_bytes).wrapping_rem(cur_index+1); + payment_paths.swap(cur_index, random_index); + } // Step (7). - for payment_path in cur_payment_paths { + for payment_path in &payment_paths { cur_route.push(payment_path.clone()); aggregate_route_value_msat += payment_path.get_value_msat(); if aggregate_route_value_msat > final_value_msat { @@ -1492,12 +1506,16 @@ where L::Target: Logger { // also makes routing more reliable. let mut overpaid_value_msat = aggregate_route_value_msat - final_value_msat; - // First, drop some expensive low-value paths entirely if possible. - // Sort by value so that we drop many really-low values first, since - // fewer paths is better: the payment is less likely to fail. - // TODO: this could also be optimized by also sorting by feerate_per_sat_routed, - // so that the sender pays less fees overall. And also htlc_minimum_msat. - cur_route.sort_by_key(|path| path.get_value_msat()); + // First, we drop some expensive low-value paths entirely if possible, since fewer + // paths is better: the payment is less likely to fail. In order to do so, we sort + // by value and fall back to total fees paid, i.e., in case of equal values we + // prefer lower cost paths. + cur_route.sort_unstable_by(|a, b| { + a.get_value_msat().cmp(&b.get_value_msat()) + // Reverse ordering for cost, so we drop higher-cost paths first + .then_with(|| b.get_cost_msat().cmp(&a.get_cost_msat())) + }); + // We should make sure that at least 1 path left. let mut paths_left = cur_route.len(); cur_route.retain(|path| { @@ -1521,13 +1539,14 @@ where L::Target: Logger { assert!(cur_route.len() > 0); // Step (8). - // Now, substract the overpaid value from the most-expensive path. + // Now, subtract the overpaid value from the most-expensive path. // TODO: this could also be optimized by also sorting by feerate_per_sat_routed, // so that the sender pays less fees overall. And also htlc_minimum_msat. - cur_route.sort_by_key(|path| { path.hops.iter().map(|hop| hop.0.candidate.fees().proportional_millionths as u64).sum::() }); + cur_route.sort_unstable_by_key(|path| { path.hops.iter().map(|hop| hop.0.candidate.fees().proportional_millionths as u64).sum::() }); let expensive_payment_path = cur_route.first_mut().unwrap(); - // We already dropped all the small channels above, meaning all the - // remaining channels are larger than remaining overpaid_value_msat. + + // We already dropped all the small value paths above, meaning all the + // remaining paths are larger than remaining overpaid_value_msat. // Thus, this can't be negative. let expensive_path_new_value_msat = expensive_payment_path.get_value_msat() - overpaid_value_msat; expensive_payment_path.update_value_and_recompute_fees(expensive_path_new_value_msat); @@ -1538,8 +1557,8 @@ where L::Target: Logger { } // Step (9). - // Select the best route by lowest total fee. - drawn_routes.sort_by_key(|paths| paths.iter().map(|path| path.get_total_fee_paid_msat()).sum::()); + // Select the best route by lowest total cost. + drawn_routes.sort_unstable_by_key(|paths| paths.iter().map(|path| path.get_cost_msat()).sum::()); let mut selected_paths = Vec::>>::new(); for payment_path in drawn_routes.first().unwrap() { let mut path = payment_path.hops.iter().map(|(payment_hop, node_features)| { @@ -1706,6 +1725,7 @@ mod tests { forwarding_info: None, }, funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }), + channel_type: None, short_channel_id, inbound_scid_alias: None, channel_value_satoshis: 0, @@ -5428,6 +5448,7 @@ mod benches { funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }), + channel_type: None, short_channel_id: Some(1), inbound_scid_alias: None, channel_value_satoshis: 10_000_000, diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index d8b1740c..206cc0a8 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -197,10 +197,6 @@ pub struct FixedPenaltyScorer { penalty_msat: u64, } -impl_writeable_tlv_based!(FixedPenaltyScorer, { - (0, penalty_msat, required), -}); - impl FixedPenaltyScorer { /// Creates a new scorer using `penalty_msat`. pub fn with_penalty(penalty_msat: u64) -> Self { @@ -218,6 +214,22 @@ impl Score for FixedPenaltyScorer { fn payment_path_successful(&mut self, _path: &[&RouteHop]) {} } +impl Writeable for FixedPenaltyScorer { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + write_tlv_fields!(w, {}); + Ok(()) + } +} + +impl ReadableArgs for FixedPenaltyScorer { + #[inline] + fn read(r: &mut R, penalty_msat: u64) -> Result { + read_tlv_fields!(r, {}); + Ok(Self { penalty_msat }) + } +} + /// [`Score`] implementation that provides reasonable default behavior. /// /// Used to apply a fixed penalty to each channel, thus avoiding long paths when shorter paths with @@ -504,19 +516,27 @@ pub struct ProbabilisticScorerUsingTime, T: Time } /// Parameters for configuring [`ProbabilisticScorer`]. +/// +/// Used to configure base, liquidity, and amount penalties, the sum of which comprises the channel +/// penalty (i.e., the amount in msats willing to be paid to avoid routing through the channel). #[derive(Clone, Copy)] pub struct ProbabilisticScoringParameters { - /// A multiplier used to determine the amount in msats willing to be paid to avoid routing - /// through a channel, as per multiplying by the negative `log10` of the channel's success - /// probability for a payment. + /// A fixed penalty in msats to apply to each channel. /// - /// The success probability is determined by the effective channel capacity, the payment amount, - /// and knowledge learned from prior successful and unsuccessful payments. The lower bound of - /// the success probability is 0.01, effectively limiting the penalty to the range - /// `0..=2*liquidity_penalty_multiplier_msat`. The knowledge learned is decayed over time based - /// on [`liquidity_offset_half_life`]. + /// Default value: 500 msat + pub base_penalty_msat: u64, + + /// A multiplier used in conjunction with the negative `log10` of the channel's success + /// probability for a payment to determine the liquidity penalty. + /// + /// The penalty is based in part on the knowledge learned from prior successful and unsuccessful + /// payments. This knowledge is decayed over time based on [`liquidity_offset_half_life`]. The + /// penalty is effectively limited to `2 * liquidity_penalty_multiplier_msat` (corresponding to + /// lower bounding the success probability to `0.01`) when the amount falls within the + /// uncertainty bounds of the channel liquidity balance. Amounts above the upper bound will + /// result in a `u64::max_value` penalty, however. /// - /// Default value: 10,000 msat + /// Default value: 40,000 msat /// /// [`liquidity_offset_half_life`]: Self::liquidity_offset_half_life pub liquidity_penalty_multiplier_msat: u64, @@ -535,12 +555,26 @@ pub struct ProbabilisticScoringParameters { /// When built with the `no-std` feature, time will never elapse. Therefore, the channel /// liquidity knowledge will never decay except when the bounds cross. pub liquidity_offset_half_life: Duration, -} -impl_writeable_tlv_based!(ProbabilisticScoringParameters, { - (0, liquidity_penalty_multiplier_msat, required), - (2, liquidity_offset_half_life, required), -}); + /// A multiplier used in conjunction with a payment amount and the negative `log10` of the + /// channel's success probability for the payment to determine the amount penalty. + /// + /// The purpose of the amount penalty is to avoid having fees dominate the channel cost (i.e., + /// fees plus penalty) for large payments. The penalty is computed as the product of this + /// multiplier and `2^20`ths of the payment amount, weighted by the negative `log10` of the + /// success probability. + /// + /// `-log10(success_probability) * amount_penalty_multiplier_msat * amount_msat / 2^20` + /// + /// In practice, this means for 0.1 success probability (`-log10(0.1) == 1`) each `2^20`th of + /// the amount will result in a penalty of the multiplier. And, as the success probability + /// decreases, the negative `log10` weighting will increase dramatically. For higher success + /// probabilities, the multiplier will have a decreasing effect as the negative `log10` will + /// fall below `1`. + /// + /// Default value: 256 msat + pub amount_penalty_multiplier_msat: u64, +} /// Accounting for channel liquidity balance uncertainty. /// @@ -587,11 +621,25 @@ impl, T: Time> ProbabilisticScorerUsingTime Self { + Self { + base_penalty_msat: 0, + liquidity_penalty_multiplier_msat: 0, + liquidity_offset_half_life: Duration::from_secs(3600), + amount_penalty_multiplier_msat: 0, + } + } +} + impl Default for ProbabilisticScoringParameters { fn default() -> Self { Self { - liquidity_penalty_multiplier_msat: 10_000, + base_penalty_msat: 500, + liquidity_penalty_multiplier_msat: 40_000, liquidity_offset_half_life: Duration::from_secs(3600), + amount_penalty_multiplier_msat: 256, } } } @@ -649,24 +697,72 @@ impl ChannelLiquidity { } } +/// Bounds `-log10` to avoid excessive liquidity penalties for payments with low success +/// probabilities. +const NEGATIVE_LOG10_UPPER_BOUND: u64 = 2; + +/// The rough cutoff at which our precision falls off and we should stop bothering to try to log a +/// ratio, as X in 1/X. +const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND; + +/// The divisor used when computing the amount penalty. +const AMOUNT_PENALTY_DIVISOR: u64 = 1 << 20; + impl, T: Time, U: Deref> DirectedChannelLiquidity { /// 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 { + fn penalty_msat(&self, amount_msat: u64, params: ProbabilisticScoringParameters) -> 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 { - u64::max_value() - } else if amount_msat <= min_liquidity_msat { + if amount_msat <= min_liquidity_msat { 0 + } else if amount_msat >= max_liquidity_msat { + if amount_msat > max_liquidity_msat { + u64::max_value() + } else if max_liquidity_msat != self.capacity_msat { + // Avoid using the failed channel on retry. + u64::max_value() + } else { + // Equivalent to hitting the else clause below with the amount equal to the + // effective capacity and without any certainty on the liquidity upper bound. + let negative_log10_times_2048 = NEGATIVE_LOG10_UPPER_BOUND * 2048; + self.combined_penalty_msat(amount_msat, negative_log10_times_2048, params) + } } else { - let numerator = max_liquidity_msat + 1 - amount_msat; - let denominator = max_liquidity_msat + 1 - min_liquidity_msat; - approx::negative_log10_times_1024(numerator, denominator) - .saturating_mul(liquidity_penalty_multiplier_msat) / 1024 + let numerator = (max_liquidity_msat - amount_msat).saturating_add(1); + let denominator = (max_liquidity_msat - min_liquidity_msat).saturating_add(1); + if amount_msat - min_liquidity_msat < denominator / PRECISION_LOWER_BOUND_DENOMINATOR { + // If the failure probability is < 1.5625% (as 1 - numerator/denominator < 1/64), + // don't bother trying to use the log approximation as it gets too noisy to be + // particularly helpful, instead just round down to 0 and return the base penalty. + params.base_penalty_msat + } else { + let negative_log10_times_2048 = + approx::negative_log10_times_2048(numerator, denominator); + self.combined_penalty_msat(amount_msat, negative_log10_times_2048, params) + } } - // Upper bound the penalty to ensure some channel is selected. - .min(2 * liquidity_penalty_multiplier_msat) + } + + /// Computes the liquidity and amount penalties and adds them to the base penalty. + #[inline(always)] + fn combined_penalty_msat( + &self, amount_msat: u64, negative_log10_times_2048: u64, + params: ProbabilisticScoringParameters + ) -> u64 { + let liquidity_penalty_msat = { + // Upper bound the liquidity penalty to ensure some channel is selected. + let multiplier_msat = params.liquidity_penalty_multiplier_msat; + let max_penalty_msat = multiplier_msat.saturating_mul(NEGATIVE_LOG10_UPPER_BOUND); + (negative_log10_times_2048.saturating_mul(multiplier_msat) / 2048).min(max_penalty_msat) + }; + let amount_penalty_msat = negative_log10_times_2048 + .saturating_mul(params.amount_penalty_multiplier_msat) + .saturating_mul(amount_msat) / 2048 / AMOUNT_PENALTY_DIVISOR; + + params.base_penalty_msat + .saturating_add(liquidity_penalty_msat) + .saturating_add(amount_penalty_msat) } /// Returns the lower bound of the channel liquidity balance in this direction. @@ -738,13 +834,12 @@ impl, T: Time> Score for ProbabilisticScorerUsin &self, short_channel_id: u64, amount_msat: u64, capacity_msat: u64, source: &NodeId, target: &NodeId ) -> u64 { - let liquidity_penalty_multiplier_msat = self.params.liquidity_penalty_multiplier_msat; let liquidity_offset_half_life = self.params.liquidity_offset_half_life; self.channel_liquidities .get(&short_channel_id) .unwrap_or(&ChannelLiquidity::new()) .as_directed(source, target, capacity_msat, liquidity_offset_half_life) - .penalty_msat(amount_msat, liquidity_penalty_multiplier_msat) + .penalty_msat(amount_msat, self.params) } fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) { @@ -804,92 +899,284 @@ impl, 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_BITS: u32 = 6; + pub(super) 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 + /// Look-up table for `log10(x) * 2048` 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], + const LOG10_TIMES_2048: [[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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, + 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, + 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, + 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977], + [1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, + 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, + 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731], + [1850, 1850, 1850, 1850, 1850, 1850, 1850, 1850, 1954, 1954, 1954, 1954, 1954, 1954, 1954, 1954, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2133, 2133, 2133, 2133, 2133, 2133, 2133, 2133, + 2210, 2210, 2210, 2210, 2210, 2210, 2210, 2210, 2281, 2281, 2281, 2281, 2281, 2281, 2281, 2281, + 2347, 2347, 2347, 2347, 2347, 2347, 2347, 2347, 2409, 2409, 2409, 2409, 2409, 2409, 2409, 2409], + [2466, 2466, 2466, 2466, 2520, 2520, 2520, 2520, 2571, 2571, 2571, 2571, 2619, 2619, 2619, 2619, + 2665, 2665, 2665, 2665, 2708, 2708, 2708, 2708, 2749, 2749, 2749, 2749, 2789, 2789, 2789, 2789, + 2827, 2827, 2827, 2827, 2863, 2863, 2863, 2863, 2898, 2898, 2898, 2898, 2931, 2931, 2931, 2931, + 2964, 2964, 2964, 2964, 2995, 2995, 2995, 2995, 3025, 3025, 3025, 3025, 3054, 3054, 3054, 3054], + [3083, 3083, 3110, 3110, 3136, 3136, 3162, 3162, 3187, 3187, 3212, 3212, 3235, 3235, 3259, 3259, + 3281, 3281, 3303, 3303, 3324, 3324, 3345, 3345, 3366, 3366, 3386, 3386, 3405, 3405, 3424, 3424, + 3443, 3443, 3462, 3462, 3479, 3479, 3497, 3497, 3514, 3514, 3531, 3531, 3548, 3548, 3564, 3564, + 3580, 3580, 3596, 3596, 3612, 3612, 3627, 3627, 3642, 3642, 3656, 3656, 3671, 3671, 3685, 3685], + [3699, 3713, 3726, 3740, 3753, 3766, 3779, 3791, 3804, 3816, 3828, 3840, 3852, 3864, 3875, 3886, + 3898, 3909, 3919, 3930, 3941, 3951, 3962, 3972, 3982, 3992, 4002, 4012, 4022, 4031, 4041, 4050, + 4060, 4069, 4078, 4087, 4096, 4105, 4114, 4122, 4131, 4139, 4148, 4156, 4164, 4173, 4181, 4189, + 4197, 4205, 4213, 4220, 4228, 4236, 4243, 4251, 4258, 4266, 4273, 4280, 4287, 4294, 4302, 4309], + [4316, 4329, 4343, 4356, 4369, 4382, 4395, 4408, 4420, 4433, 4445, 4457, 4468, 4480, 4492, 4503, + 4514, 4525, 4536, 4547, 4557, 4568, 4578, 4589, 4599, 4609, 4619, 4629, 4638, 4648, 4657, 4667, + 4676, 4685, 4695, 4704, 4713, 4721, 4730, 4739, 4747, 4756, 4764, 4773, 4781, 4789, 4797, 4805, + 4813, 4821, 4829, 4837, 4845, 4852, 4860, 4867, 4875, 4882, 4889, 4897, 4904, 4911, 4918, 4925], + [4932, 4946, 4959, 4973, 4986, 4999, 5012, 5024, 5037, 5049, 5061, 5073, 5085, 5097, 5108, 5119, + 5131, 5142, 5153, 5163, 5174, 5184, 5195, 5205, 5215, 5225, 5235, 5245, 5255, 5264, 5274, 5283, + 5293, 5302, 5311, 5320, 5329, 5338, 5347, 5355, 5364, 5372, 5381, 5389, 5397, 5406, 5414, 5422, + 5430, 5438, 5446, 5453, 5461, 5469, 5476, 5484, 5491, 5499, 5506, 5513, 5520, 5527, 5535, 5542], + [5549, 5562, 5576, 5589, 5603, 5615, 5628, 5641, 5653, 5666, 5678, 5690, 5701, 5713, 5725, 5736, + 5747, 5758, 5769, 5780, 5790, 5801, 5811, 5822, 5832, 5842, 5852, 5862, 5871, 5881, 5890, 5900, + 5909, 5918, 5928, 5937, 5946, 5954, 5963, 5972, 5980, 5989, 5997, 6006, 6014, 6022, 6030, 6038, + 6046, 6054, 6062, 6070, 6078, 6085, 6093, 6100, 6108, 6115, 6122, 6130, 6137, 6144, 6151, 6158], + [6165, 6179, 6192, 6206, 6219, 6232, 6245, 6257, 6270, 6282, 6294, 6306, 6318, 6330, 6341, 6352, + 6364, 6375, 6386, 6396, 6407, 6417, 6428, 6438, 6448, 6458, 6468, 6478, 6488, 6497, 6507, 6516, + 6526, 6535, 6544, 6553, 6562, 6571, 6580, 6588, 6597, 6605, 6614, 6622, 6630, 6639, 6647, 6655, + 6663, 6671, 6679, 6686, 6694, 6702, 6709, 6717, 6724, 6732, 6739, 6746, 6753, 6761, 6768, 6775], + [6782, 6795, 6809, 6822, 6836, 6849, 6861, 6874, 6886, 6899, 6911, 6923, 6934, 6946, 6958, 6969, + 6980, 6991, 7002, 7013, 7023, 7034, 7044, 7055, 7065, 7075, 7085, 7095, 7104, 7114, 7124, 7133, + 7142, 7151, 7161, 7170, 7179, 7187, 7196, 7205, 7213, 7222, 7230, 7239, 7247, 7255, 7263, 7271, + 7279, 7287, 7295, 7303, 7311, 7318, 7326, 7333, 7341, 7348, 7355, 7363, 7370, 7377, 7384, 7391], + [7398, 7412, 7425, 7439, 7452, 7465, 7478, 7490, 7503, 7515, 7527, 7539, 7551, 7563, 7574, 7585, + 7597, 7608, 7619, 7629, 7640, 7651, 7661, 7671, 7681, 7691, 7701, 7711, 7721, 7731, 7740, 7749, + 7759, 7768, 7777, 7786, 7795, 7804, 7813, 7821, 7830, 7838, 7847, 7855, 7864, 7872, 7880, 7888, + 7896, 7904, 7912, 7919, 7927, 7935, 7942, 7950, 7957, 7965, 7972, 7979, 7986, 7994, 8001, 8008], + [8015, 8028, 8042, 8055, 8069, 8082, 8094, 8107, 8119, 8132, 8144, 8156, 8167, 8179, 8191, 8202, + 8213, 8224, 8235, 8246, 8256, 8267, 8277, 8288, 8298, 8308, 8318, 8328, 8337, 8347, 8357, 8366, + 8375, 8384, 8394, 8403, 8412, 8420, 8429, 8438, 8446, 8455, 8463, 8472, 8480, 8488, 8496, 8504, + 8512, 8520, 8528, 8536, 8544, 8551, 8559, 8566, 8574, 8581, 8588, 8596, 8603, 8610, 8617, 8624], + [8631, 8645, 8659, 8672, 8685, 8698, 8711, 8723, 8736, 8748, 8760, 8772, 8784, 8796, 8807, 8818, + 8830, 8841, 8852, 8862, 8873, 8884, 8894, 8904, 8914, 8924, 8934, 8944, 8954, 8964, 8973, 8982, + 8992, 9001, 9010, 9019, 9028, 9037, 9046, 9054, 9063, 9071, 9080, 9088, 9097, 9105, 9113, 9121, + 9129, 9137, 9145, 9152, 9160, 9168, 9175, 9183, 9190, 9198, 9205, 9212, 9219, 9227, 9234, 9241], + [9248, 9261, 9275, 9288, 9302, 9315, 9327, 9340, 9352, 9365, 9377, 9389, 9400, 9412, 9424, 9435, + 9446, 9457, 9468, 9479, 9490, 9500, 9510, 9521, 9531, 9541, 9551, 9561, 9570, 9580, 9590, 9599, + 9608, 9617, 9627, 9636, 9645, 9653, 9662, 9671, 9679, 9688, 9696, 9705, 9713, 9721, 9729, 9737, + 9745, 9753, 9761, 9769, 9777, 9784, 9792, 9799, 9807, 9814, 9821, 9829, 9836, 9843, 9850, 9857], + [9864, 9878, 9892, 9905, 9918, 9931, 9944, 9956, 9969, 9981, 9993, 10005, 10017, 10029, 10040, 10051, + 10063, 10074, 10085, 10095, 10106, 10117, 10127, 10137, 10147, 10157, 10167, 10177, 10187, 10197, 10206, 10215, + 10225, 10234, 10243, 10252, 10261, 10270, 10279, 10287, 10296, 10304, 10313, 10321, 10330, 10338, 10346, 10354, + 10362, 10370, 10378, 10385, 10393, 10401, 10408, 10416, 10423, 10431, 10438, 10445, 10452, 10460, 10467, 10474], + [10481, 10494, 10508, 10521, 10535, 10548, 10560, 10573, 10585, 10598, 10610, 10622, 10634, 10645, 10657, 10668, + 10679, 10690, 10701, 10712, 10723, 10733, 10743, 10754, 10764, 10774, 10784, 10794, 10803, 10813, 10823, 10832, + 10841, 10851, 10860, 10869, 10878, 10886, 10895, 10904, 10912, 10921, 10929, 10938, 10946, 10954, 10962, 10970, + 10978, 10986, 10994, 11002, 11010, 11017, 11025, 11032, 11040, 11047, 11054, 11062, 11069, 11076, 11083, 11090], + [11097, 11111, 11125, 11138, 11151, 11164, 11177, 11189, 11202, 11214, 11226, 11238, 11250, 11262, 11273, 11284, + 11296, 11307, 11318, 11328, 11339, 11350, 11360, 11370, 11380, 11390, 11400, 11410, 11420, 11430, 11439, 11448, + 11458, 11467, 11476, 11485, 11494, 11503, 11512, 11520, 11529, 11538, 11546, 11554, 11563, 11571, 11579, 11587, + 11595, 11603, 11611, 11618, 11626, 11634, 11641, 11649, 11656, 11664, 11671, 11678, 11685, 11693, 11700, 11707], + [11714, 11727, 11741, 11754, 11768, 11781, 11793, 11806, 11818, 11831, 11843, 11855, 11867, 11878, 11890, 11901, + 11912, 11923, 11934, 11945, 11956, 11966, 11976, 11987, 11997, 12007, 12017, 12027, 12036, 12046, 12056, 12065, + 12074, 12084, 12093, 12102, 12111, 12119, 12128, 12137, 12146, 12154, 12162, 12171, 12179, 12187, 12195, 12203, + 12211, 12219, 12227, 12235, 12243, 12250, 12258, 12265, 12273, 12280, 12287, 12295, 12302, 12309, 12316, 12323], + [12330, 12344, 12358, 12371, 12384, 12397, 12410, 12423, 12435, 12447, 12459, 12471, 12483, 12495, 12506, 12517, + 12529, 12540, 12551, 12561, 12572, 12583, 12593, 12603, 12613, 12623, 12633, 12643, 12653, 12663, 12672, 12682, + 12691, 12700, 12709, 12718, 12727, 12736, 12745, 12753, 12762, 12771, 12779, 12787, 12796, 12804, 12812, 12820, + 12828, 12836, 12844, 12851, 12859, 12867, 12874, 12882, 12889, 12897, 12904, 12911, 12918, 12926, 12933, 12940], + [12947, 12960, 12974, 12987, 13001, 13014, 13026, 13039, 13051, 13064, 13076, 13088, 13100, 13111, 13123, 13134, + 13145, 13156, 13167, 13178, 13189, 13199, 13209, 13220, 13230, 13240, 13250, 13260, 13269, 13279, 13289, 13298, + 13307, 13317, 13326, 13335, 13344, 13352, 13361, 13370, 13379, 13387, 13395, 13404, 13412, 13420, 13428, 13436, + 13444, 13452, 13460, 13468, 13476, 13483, 13491, 13498, 13506, 13513, 13521, 13528, 13535, 13542, 13549, 13556], + [13563, 13577, 13591, 13604, 13617, 13630, 13643, 13656, 13668, 13680, 13692, 13704, 13716, 13728, 13739, 13750, + 13762, 13773, 13784, 13794, 13805, 13816, 13826, 13836, 13846, 13857, 13866, 13876, 13886, 13896, 13905, 13915, + 13924, 13933, 13942, 13951, 13960, 13969, 13978, 13986, 13995, 14004, 14012, 14020, 14029, 14037, 14045, 14053, + 14061, 14069, 14077, 14084, 14092, 14100, 14107, 14115, 14122, 14130, 14137, 14144, 14151, 14159, 14166, 14173], + [14180, 14194, 14207, 14220, 14234, 14247, 14259, 14272, 14284, 14297, 14309, 14321, 14333, 14344, 14356, 14367, + 14378, 14389, 14400, 14411, 14422, 14432, 14443, 14453, 14463, 14473, 14483, 14493, 14502, 14512, 14522, 14531, + 14540, 14550, 14559, 14568, 14577, 14586, 14594, 14603, 14612, 14620, 14628, 14637, 14645, 14653, 14661, 14669, + 14677, 14685, 14693, 14701, 14709, 14716, 14724, 14731, 14739, 14746, 14754, 14761, 14768, 14775, 14782, 14789], + [14796, 14810, 14824, 14837, 14850, 14863, 14876, 14889, 14901, 14913, 14925, 14937, 14949, 14961, 14972, 14984, + 14995, 15006, 15017, 15027, 15038, 15049, 15059, 15069, 15079, 15090, 15099, 15109, 15119, 15129, 15138, 15148, + 15157, 15166, 15175, 15184, 15193, 15202, 15211, 15219, 15228, 15237, 15245, 15253, 15262, 15270, 15278, 15286, + 15294, 15302, 15310, 15317, 15325, 15333, 15340, 15348, 15355, 15363, 15370, 15377, 15384, 15392, 15399, 15406], + [15413, 15427, 15440, 15453, 15467, 15480, 15492, 15505, 15517, 15530, 15542, 15554, 15566, 15577, 15589, 15600, + 15611, 15622, 15633, 15644, 15655, 15665, 15676, 15686, 15696, 15706, 15716, 15726, 15736, 15745, 15755, 15764, + 15773, 15783, 15792, 15801, 15810, 15819, 15827, 15836, 15845, 15853, 15862, 15870, 15878, 15886, 15894, 15903, + 15910, 15918, 15926, 15934, 15942, 15949, 15957, 15964, 15972, 15979, 15987, 15994, 16001, 16008, 16015, 16022], + [16029, 16043, 16057, 16070, 16083, 16096, 16109, 16122, 16134, 16146, 16158, 16170, 16182, 16194, 16205, 16217, + 16228, 16239, 16250, 16260, 16271, 16282, 16292, 16302, 16312, 16323, 16332, 16342, 16352, 16362, 16371, 16381, + 16390, 16399, 16408, 16417, 16426, 16435, 16444, 16452, 16461, 16470, 16478, 16486, 16495, 16503, 16511, 16519, + 16527, 16535, 16543, 16550, 16558, 16566, 16573, 16581, 16588, 16596, 16603, 16610, 16618, 16625, 16632, 16639], + [16646, 16660, 16673, 16686, 16700, 16713, 16725, 16738, 16751, 16763, 16775, 16787, 16799, 16810, 16822, 16833, + 16844, 16855, 16866, 16877, 16888, 16898, 16909, 16919, 16929, 16939, 16949, 16959, 16969, 16978, 16988, 16997, + 17006, 17016, 17025, 17034, 17043, 17052, 17060, 17069, 17078, 17086, 17095, 17103, 17111, 17119, 17127, 17136, + 17143, 17151, 17159, 17167, 17175, 17182, 17190, 17197, 17205, 17212, 17220, 17227, 17234, 17241, 17248, 17255], + [17262, 17276, 17290, 17303, 17316, 17329, 17342, 17355, 17367, 17379, 17391, 17403, 17415, 17427, 17438, 17450, + 17461, 17472, 17483, 17493, 17504, 17515, 17525, 17535, 17546, 17556, 17565, 17575, 17585, 17595, 17604, 17614, + 17623, 17632, 17641, 17650, 17659, 17668, 17677, 17685, 17694, 17703, 17711, 17719, 17728, 17736, 17744, 17752, + 17760, 17768, 17776, 17784, 17791, 17799, 17806, 17814, 17821, 17829, 17836, 17843, 17851, 17858, 17865, 17872], + [17879, 17893, 17906, 17920, 17933, 17946, 17958, 17971, 17984, 17996, 18008, 18020, 18032, 18043, 18055, 18066, + 18077, 18088, 18099, 18110, 18121, 18131, 18142, 18152, 18162, 18172, 18182, 18192, 18202, 18211, 18221, 18230, + 18239, 18249, 18258, 18267, 18276, 18285, 18293, 18302, 18311, 18319, 18328, 18336, 18344, 18352, 18360, 18369, + 18377, 18384, 18392, 18400, 18408, 18415, 18423, 18430, 18438, 18445, 18453, 18460, 18467, 18474, 18481, 18488], + [18495, 18509, 18523, 18536, 18549, 18562, 18575, 18588, 18600, 18612, 18624, 18636, 18648, 18660, 18671, 18683, + 18694, 18705, 18716, 18726, 18737, 18748, 18758, 18768, 18779, 18789, 18799, 18808, 18818, 18828, 18837, 18847, + 18856, 18865, 18874, 18883, 18892, 18901, 18910, 18919, 18927, 18936, 18944, 18952, 18961, 18969, 18977, 18985, + 18993, 19001, 19009, 19017, 19024, 19032, 19039, 19047, 19054, 19062, 19069, 19076, 19084, 19091, 19098, 19105], + [19112, 19126, 19139, 19153, 19166, 19179, 19191, 19204, 19217, 19229, 19241, 19253, 19265, 19276, 19288, 19299, + 19310, 19321, 19332, 19343, 19354, 19364, 19375, 19385, 19395, 19405, 19415, 19425, 19435, 19444, 19454, 19463, + 19472, 19482, 19491, 19500, 19509, 19518, 19526, 19535, 19544, 19552, 19561, 19569, 19577, 19585, 19594, 19602, + 19610, 19617, 19625, 19633, 19641, 19648, 19656, 19663, 19671, 19678, 19686, 19693, 19700, 19707, 19714, 19721], + [19728, 19742, 19756, 19769, 19782, 19795, 19808, 19821, 19833, 19845, 19857, 19869, 19881, 19893, 19904, 19916, + 19927, 19938, 19949, 19960, 19970, 19981, 19991, 20001, 20012, 20022, 20032, 20041, 20051, 20061, 20070, 20080, + 20089, 20098, 20107, 20116, 20125, 20134, 20143, 20152, 20160, 20169, 20177, 20185, 20194, 20202, 20210, 20218, + 20226, 20234, 20242, 20250, 20257, 20265, 20272, 20280, 20287, 20295, 20302, 20309, 20317, 20324, 20331, 20338], + [20345, 20359, 20372, 20386, 20399, 20412, 20425, 20437, 20450, 20462, 20474, 20486, 20498, 20509, 20521, 20532, + 20543, 20554, 20565, 20576, 20587, 20597, 20608, 20618, 20628, 20638, 20648, 20658, 20668, 20677, 20687, 20696, + 20705, 20715, 20724, 20733, 20742, 20751, 20759, 20768, 20777, 20785, 20794, 20802, 20810, 20818, 20827, 20835, + 20843, 20850, 20858, 20866, 20874, 20881, 20889, 20896, 20904, 20911, 20919, 20926, 20933, 20940, 20947, 20954], + [20961, 20975, 20989, 21002, 21015, 21028, 21041, 21054, 21066, 21078, 21090, 21102, 21114, 21126, 21137, 21149, + 21160, 21171, 21182, 21193, 21203, 21214, 21224, 21234, 21245, 21255, 21265, 21274, 21284, 21294, 21303, 21313, + 21322, 21331, 21340, 21349, 21358, 21367, 21376, 21385, 21393, 21402, 21410, 21418, 21427, 21435, 21443, 21451, + 21459, 21467, 21475, 21483, 21490, 21498, 21505, 21513, 21520, 21528, 21535, 21542, 21550, 21557, 21564, 21571], + [21578, 21592, 21605, 21619, 21632, 21645, 21658, 21670, 21683, 21695, 21707, 21719, 21731, 21742, 21754, 21765, + 21776, 21787, 21798, 21809, 21820, 21830, 21841, 21851, 21861, 21871, 21881, 21891, 21901, 21910, 21920, 21929, + 21938, 21948, 21957, 21966, 21975, 21984, 21992, 22001, 22010, 22018, 22027, 22035, 22043, 22051, 22060, 22068, + 22076, 22083, 22091, 22099, 22107, 22114, 22122, 22129, 22137, 22144, 22152, 22159, 22166, 22173, 22180, 22187], + [22194, 22208, 22222, 22235, 22248, 22261, 22274, 22287, 22299, 22311, 22323, 22335, 22347, 22359, 22370, 22382, + 22393, 22404, 22415, 22426, 22436, 22447, 22457, 22467, 22478, 22488, 22498, 22507, 22517, 22527, 22536, 22546, + 22555, 22564, 22573, 22582, 22591, 22600, 22609, 22618, 22626, 22635, 22643, 22651, 22660, 22668, 22676, 22684, + 22692, 22700, 22708, 22716, 22723, 22731, 22738, 22746, 22753, 22761, 22768, 22775, 22783, 22790, 22797, 22804], + [22811, 22825, 22838, 22852, 22865, 22878, 22891, 22903, 22916, 22928, 22940, 22952, 22964, 22975, 22987, 22998, + 23009, 23020, 23031, 23042, 23053, 23063, 23074, 23084, 23094, 23104, 23114, 23124, 23134, 23143, 23153, 23162, + 23171, 23181, 23190, 23199, 23208, 23217, 23225, 23234, 23243, 23251, 23260, 23268, 23276, 23284, 23293, 23301, + 23309, 23316, 23324, 23332, 23340, 23347, 23355, 23363, 23370, 23377, 23385, 23392, 23399, 23406, 23413, 23420], + [23427, 23441, 23455, 23468, 23481, 23494, 23507, 23520, 23532, 23544, 23556, 23568, 23580, 23592, 23603, 23615, + 23626, 23637, 23648, 23659, 23669, 23680, 23690, 23700, 23711, 23721, 23731, 23740, 23750, 23760, 23769, 23779, + 23788, 23797, 23806, 23815, 23824, 23833, 23842, 23851, 23859, 23868, 23876, 23884, 23893, 23901, 23909, 23917, + 23925, 23933, 23941, 23949, 23956, 23964, 23972, 23979, 23986, 23994, 24001, 24008, 24016, 24023, 24030, 24037], + [24044, 24058, 24071, 24085, 24098, 24111, 24124, 24136, 24149, 24161, 24173, 24185, 24197, 24208, 24220, 24231, + 24242, 24253, 24264, 24275, 24286, 24296, 24307, 24317, 24327, 24337, 24347, 24357, 24367, 24376, 24386, 24395, + 24405, 24414, 24423, 24432, 24441, 24450, 24458, 24467, 24476, 24484, 24493, 24501, 24509, 24517, 24526, 24534, + 24542, 24550, 24557, 24565, 24573, 24580, 24588, 24596, 24603, 24610, 24618, 24625, 24632, 24639, 24646, 24653], + [24660, 24674, 24688, 24701, 24714, 24727, 24740, 24753, 24765, 24777, 24790, 24801, 24813, 24825, 24836, 24848, + 24859, 24870, 24881, 24892, 24902, 24913, 24923, 24933, 24944, 24954, 24964, 24973, 24983, 24993, 25002, 25012, + 25021, 25030, 25039, 25048, 25057, 25066, 25075, 25084, 25092, 25101, 25109, 25117, 25126, 25134, 25142, 25150, + 25158, 25166, 25174, 25182, 25189, 25197, 25205, 25212, 25219, 25227, 25234, 25241, 25249, 25256, 25263, 25270], + [25277, 25291, 25304, 25318, 25331, 25344, 25357, 25369, 25382, 25394, 25406, 25418, 25430, 25441, 25453, 25464, + 25475, 25486, 25497, 25508, 25519, 25529, 25540, 25550, 25560, 25570, 25580, 25590, 25600, 25609, 25619, 25628, + 25638, 25647, 25656, 25665, 25674, 25683, 25691, 25700, 25709, 25717, 25726, 25734, 25742, 25750, 25759, 25767, + 25775, 25783, 25790, 25798, 25806, 25813, 25821, 25829, 25836, 25843, 25851, 25858, 25865, 25872, 25879, 25886], + [25893, 25907, 25921, 25934, 25947, 25960, 25973, 25986, 25998, 26010, 26023, 26034, 26046, 26058, 26069, 26081, + 26092, 26103, 26114, 26125, 26135, 26146, 26156, 26166, 26177, 26187, 26197, 26206, 26216, 26226, 26235, 26245, + 26254, 26263, 26272, 26281, 26290, 26299, 26308, 26317, 26325, 26334, 26342, 26351, 26359, 26367, 26375, 26383, + 26391, 26399, 26407, 26415, 26422, 26430, 26438, 26445, 26453, 26460, 26467, 26474, 26482, 26489, 26496, 26503], + [26510, 26524, 26537, 26551, 26564, 26577, 26590, 26602, 26615, 26627, 26639, 26651, 26663, 26674, 26686, 26697, + 26708, 26719, 26730, 26741, 26752, 26762, 26773, 26783, 26793, 26803, 26813, 26823, 26833, 26842, 26852, 26861, + 26871, 26880, 26889, 26898, 26907, 26916, 26924, 26933, 26942, 26950, 26959, 26967, 26975, 26983, 26992, 27000, + 27008, 27016, 27023, 27031, 27039, 27046, 27054, 27062, 27069, 27076, 27084, 27091, 27098, 27105, 27112, 27119], + [27126, 27140, 27154, 27167, 27180, 27193, 27206, 27219, 27231, 27243, 27256, 27267, 27279, 27291, 27302, 27314, + 27325, 27336, 27347, 27358, 27368, 27379, 27389, 27399, 27410, 27420, 27430, 27439, 27449, 27459, 27468, 27478, + 27487, 27496, 27505, 27514, 27523, 27532, 27541, 27550, 27558, 27567, 27575, 27584, 27592, 27600, 27608, 27616, + 27624, 27632, 27640, 27648, 27655, 27663, 27671, 27678, 27686, 27693, 27700, 27707, 27715, 27722, 27729, 27736], + [27743, 27757, 27770, 27784, 27797, 27810, 27823, 27835, 27848, 27860, 27872, 27884, 27896, 27907, 27919, 27930, + 27941, 27952, 27963, 27974, 27985, 27995, 28006, 28016, 28026, 28036, 28046, 28056, 28066, 28075, 28085, 28094, + 28104, 28113, 28122, 28131, 28140, 28149, 28157, 28166, 28175, 28183, 28192, 28200, 28208, 28217, 28225, 28233, + 28241, 28249, 28256, 28264, 28272, 28280, 28287, 28295, 28302, 28309, 28317, 28324, 28331, 28338, 28345, 28352], + [28359, 28373, 28387, 28400, 28413, 28426, 28439, 28452, 28464, 28476, 28489, 28501, 28512, 28524, 28535, 28547, + 28558, 28569, 28580, 28591, 28601, 28612, 28622, 28633, 28643, 28653, 28663, 28672, 28682, 28692, 28701, 28711, + 28720, 28729, 28738, 28747, 28756, 28765, 28774, 28783, 28791, 28800, 28808, 28817, 28825, 28833, 28841, 28849, + 28857, 28865, 28873, 28881, 28888, 28896, 28904, 28911, 28919, 28926, 28933, 28941, 28948, 28955, 28962, 28969], + [28976, 28990, 29003, 29017, 29030, 29043, 29056, 29068, 29081, 29093, 29105, 29117, 29129, 29140, 29152, 29163, + 29174, 29185, 29196, 29207, 29218, 29228, 29239, 29249, 29259, 29269, 29279, 29289, 29299, 29308, 29318, 29327, + 29337, 29346, 29355, 29364, 29373, 29382, 29390, 29399, 29408, 29416, 29425, 29433, 29441, 29450, 29458, 29466, + 29474, 29482, 29489, 29497, 29505, 29513, 29520, 29528, 29535, 29542, 29550, 29557, 29564, 29571, 29578, 29585], + [29592, 29606, 29620, 29633, 29646, 29659, 29672, 29685, 29697, 29709, 29722, 29734, 29745, 29757, 29768, 29780, + 29791, 29802, 29813, 29824, 29834, 29845, 29855, 29866, 29876, 29886, 29896, 29906, 29915, 29925, 29934, 29944, + 29953, 29962, 29971, 29980, 29989, 29998, 30007, 30016, 30024, 30033, 30041, 30050, 30058, 30066, 30074, 30082, + 30090, 30098, 30106, 30114, 30121, 30129, 30137, 30144, 30152, 30159, 30166, 30174, 30181, 30188, 30195, 30202], + [30209, 30223, 30236, 30250, 30263, 30276, 30289, 30301, 30314, 30326, 30338, 30350, 30362, 30373, 30385, 30396, + 30407, 30418, 30429, 30440, 30451, 30461, 30472, 30482, 30492, 30502, 30512, 30522, 30532, 30541, 30551, 30560, + 30570, 30579, 30588, 30597, 30606, 30615, 30624, 30632, 30641, 30649, 30658, 30666, 30674, 30683, 30691, 30699, + 30707, 30715, 30722, 30730, 30738, 30746, 30753, 30761, 30768, 30775, 30783, 30790, 30797, 30804, 30811, 30818], + [30825, 30839, 30853, 30866, 30879, 30892, 30905, 30918, 30930, 30943, 30955, 30967, 30978, 30990, 31001, 31013, + 31024, 31035, 31046, 31057, 31067, 31078, 31088, 31099, 31109, 31119, 31129, 31139, 31148, 31158, 31167, 31177, + 31186, 31195, 31204, 31213, 31222, 31231, 31240, 31249, 31257, 31266, 31274, 31283, 31291, 31299, 31307, 31315, + 31323, 31331, 31339, 31347, 31354, 31362, 31370, 31377, 31385, 31392, 31399, 31407, 31414, 31421, 31428, 31435], + [31442, 31456, 31469, 31483, 31496, 31509, 31522, 31534, 31547, 31559, 31571, 31583, 31595, 31606, 31618, 31629, + 31640, 31652, 31662, 31673, 31684, 31694, 31705, 31715, 31725, 31735, 31745, 31755, 31765, 31774, 31784, 31793, + 31803, 31812, 31821, 31830, 31839, 31848, 31857, 31865, 31874, 31882, 31891, 31899, 31907, 31916, 31924, 31932, + 31940, 31948, 31955, 31963, 31971, 31979, 31986, 31994, 32001, 32008, 32016, 32023, 32030, 32037, 32044, 32052], + [32058, 32072, 32086, 32099, 32112, 32125, 32138, 32151, 32163, 32176, 32188, 32200, 32211, 32223, 32234, 32246, + 32257, 32268, 32279, 32290, 32300, 32311, 32321, 32332, 32342, 32352, 32362, 32372, 32381, 32391, 32400, 32410, + 32419, 32428, 32437, 32446, 32455, 32464, 32473, 32482, 32490, 32499, 32507, 32516, 32524, 32532, 32540, 32548, + 32556, 32564, 32572, 32580, 32587, 32595, 32603, 32610, 32618, 32625, 32632, 32640, 32647, 32654, 32661, 32668], + [32675, 32689, 32702, 32716, 32729, 32742, 32755, 32767, 32780, 32792, 32804, 32816, 32828, 32839, 32851, 32862, + 32873, 32885, 32895, 32906, 32917, 32927, 32938, 32948, 32958, 32968, 32978, 32988, 32998, 33007, 33017, 33026, + 33036, 33045, 33054, 33063, 33072, 33081, 33090, 33098, 33107, 33115, 33124, 33132, 33140, 33149, 33157, 33165, + 33173, 33181, 33188, 33196, 33204, 33212, 33219, 33227, 33234, 33241, 33249, 33256, 33263, 33270, 33278, 33285], + [33292, 33305, 33319, 33332, 33345, 33358, 33371, 33384, 33396, 33409, 33421, 33433, 33444, 33456, 33467, 33479, + 33490, 33501, 33512, 33523, 33533, 33544, 33554, 33565, 33575, 33585, 33595, 33605, 33614, 33624, 33633, 33643, + 33652, 33661, 33670, 33680, 33688, 33697, 33706, 33715, 33723, 33732, 33740, 33749, 33757, 33765, 33773, 33781, + 33789, 33797, 33805, 33813, 33820, 33828, 33836, 33843, 33851, 33858, 33865, 33873, 33880, 33887, 33894, 33901], + [33908, 33922, 33935, 33949, 33962, 33975, 33988, 34000, 34013, 34025, 34037, 34049, 34061, 34072, 34084, 34095, + 34106, 34118, 34128, 34139, 34150, 34160, 34171, 34181, 34191, 34201, 34211, 34221, 34231, 34240, 34250, 34259, + 34269, 34278, 34287, 34296, 34305, 34314, 34323, 34331, 34340, 34348, 34357, 34365, 34373, 34382, 34390, 34398, + 34406, 34414, 34422, 34429, 34437, 34445, 34452, 34460, 34467, 34475, 34482, 34489, 34496, 34503, 34511, 34518], + [34525, 34538, 34552, 34565, 34578, 34591, 34604, 34617, 34629, 34642, 34654, 34666, 34677, 34689, 34700, 34712, + 34723, 34734, 34745, 34756, 34766, 34777, 34787, 34798, 34808, 34818, 34828, 34838, 34847, 34857, 34866, 34876, + 34885, 34894, 34904, 34913, 34921, 34930, 34939, 34948, 34956, 34965, 34973, 34982, 34990, 34998, 35006, 35014, + 35022, 35030, 35038, 35046, 35053, 35061, 35069, 35076, 35084, 35091, 35098, 35106, 35113, 35120, 35127, 35134], + [35141, 35155, 35168, 35182, 35195, 35208, 35221, 35233, 35246, 35258, 35270, 35282, 35294, 35306, 35317, 35328, + 35340, 35351, 35361, 35372, 35383, 35393, 35404, 35414, 35424, 35434, 35444, 35454, 35464, 35473, 35483, 35492, + 35502, 35511, 35520, 35529, 35538, 35547, 35556, 35564, 35573, 35581, 35590, 35598, 35606, 35615, 35623, 35631, + 35639, 35647, 35655, 35662, 35670, 35678, 35685, 35693, 35700, 35708, 35715, 35722, 35729, 35736, 35744, 35751], + [35758, 35771, 35785, 35798, 35811, 35824, 35837, 35850, 35862, 35875, 35887, 35899, 35910, 35922, 35934, 35945, + 35956, 35967, 35978, 35989, 35999, 36010, 36020, 36031, 36041, 36051, 36061, 36071, 36080, 36090, 36099, 36109, + 36118, 36127, 36137, 36146, 36154, 36163, 36172, 36181, 36189, 36198, 36206, 36215, 36223, 36231, 36239, 36247, + 36255, 36263, 36271, 36279, 36287, 36294, 36302, 36309, 36317, 36324, 36331, 36339, 36346, 36353, 36360, 36367], + [36374, 36388, 36401, 36415, 36428, 36441, 36454, 36466, 36479, 36491, 36503, 36515, 36527, 36539, 36550, 36561, + 36573, 36584, 36594, 36605, 36616, 36626, 36637, 36647, 36657, 36667, 36677, 36687, 36697, 36706, 36716, 36725, + 36735, 36744, 36753, 36762, 36771, 36780, 36789, 36797, 36806, 36814, 36823, 36831, 36839, 36848, 36856, 36864, + 36872, 36880, 36888, 36895, 36903, 36911, 36918, 36926, 36933, 36941, 36948, 36955, 36962, 36969, 36977, 36984], + [36991, 37004, 37018, 37031, 37044, 37057, 37070, 37083, 37095, 37108, 37120, 37132, 37143, 37155, 37167, 37178, + 37189, 37200, 37211, 37222, 37232, 37243, 37253, 37264, 37274, 37284, 37294, 37304, 37313, 37323, 37332, 37342, + 37351, 37360, 37370, 37379, 37388, 37396, 37405, 37414, 37422, 37431, 37439, 37448, 37456, 37464, 37472, 37480, + 37488, 37496, 37504, 37512, 37520, 37527, 37535, 37542, 37550, 37557, 37564, 37572, 37579, 37586, 37593, 37600], + [37607, 37621, 37634, 37648, 37661, 37674, 37687, 37699, 37712, 37724, 37736, 37748, 37760, 37772, 37783, 37794, + 37806, 37817, 37828, 37838, 37849, 37859, 37870, 37880, 37890, 37900, 37910, 37920, 37930, 37939, 37949, 37958, + 37968, 37977, 37986, 37995, 38004, 38013, 38022, 38030, 38039, 38047, 38056, 38064, 38072, 38081, 38089, 38097, + 38105, 38113, 38121, 38128, 38136, 38144, 38151, 38159, 38166, 38174, 38181, 38188, 38195, 38202, 38210, 38217], + [38224, 38237, 38251, 38264, 38278, 38290, 38303, 38316, 38328, 38341, 38353, 38365, 38376, 38388, 38400, 38411, + 38422, 38433, 38444, 38455, 38465, 38476, 38486, 38497, 38507, 38517, 38527, 38537, 38546, 38556, 38565, 38575, + 38584, 38593, 38603, 38612, 38621, 38629, 38638, 38647, 38655, 38664, 38672, 38681, 38689, 38697, 38705, 38713, + 38721, 38729, 38737, 38745, 38753, 38760, 38768, 38775, 38783, 38790, 38797, 38805, 38812, 38819, 38826, 38833], + [38840, 38854, 38867, 38881, 38894, 38907, 38920, 38932, 38945, 38957, 38969, 38981, 38993, 39005, 39016, 39027, + 39039, 39050, 39061, 39071, 39082, 39092, 39103, 39113, 39123, 39133, 39143, 39153, 39163, 39172, 39182, 39191, + 39201, 39210, 39219, 39228, 39237, 39246, 39255, 39263, 39272, 39280, 39289, 39297, 39305, 39314, 39322, 39330, + 39338, 39346, 39354, 39361, 39369, 39377, 39384, 39392, 39399, 39407, 39414, 39421, 39428, 39436, 39443, 39450], ]; - /// Approximate `log10(numerator / denominator) * 1024` using a look-up table. + /// Approximate `log10(numerator / denominator) * 2048` using a look-up table. #[inline] - pub fn negative_log10_times_1024(numerator: u64, denominator: u64) -> u64 { + pub fn negative_log10_times_2048(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 + (log10_times_2048(denominator) - log10_times_2048(numerator)) as u64 } #[inline] - fn log10_times_1024(x: u64) -> u16 { + fn log10_times_2048(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] + LOG10_TIMES_2048[most_significant_bit as usize][lower_bits as usize] } #[cfg(test)] @@ -897,19 +1184,21 @@ mod approx { use super::*; #[test] - fn prints_negative_log10_times_1024_lookup_table() { + fn prints_negative_log10_times_2048_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]); + let log10_times_2048 = ((x as f64).log10() * 2048.0).round() as u16; + assert_eq!(log10_times_2048, LOG10_TIMES_2048[msb as usize][i as usize]); if i % LOWER_BITS_BOUND == 0 { - print!("\t\t[{}, ", log10_times_1024); + print!("\t\t[{}, ", log10_times_2048); } else if i % LOWER_BITS_BOUND == LOWER_BITS_BOUND - 1 { - println!("{}],", log10_times_1024); + println!("{}],", log10_times_2048); + } else if i % (LOWER_BITS_BOUND/4) == LOWER_BITS_BOUND/4 - 1 { + print!("{},\n\t\t\t", log10_times_2048); } else { - print!("{}, ", log10_times_1024); + print!("{}, ", log10_times_2048); } } } @@ -1722,24 +2011,25 @@ mod tests { fn increased_penalty_nearing_liquidity_upper_bound() { let network_graph = network_graph(); let params = ProbabilisticScoringParameters { - liquidity_penalty_multiplier_msat: 1_000, ..Default::default() + liquidity_penalty_multiplier_msat: 1_000, + ..ProbabilisticScoringParameters::zero_penalty() }; let scorer = ProbabilisticScorer::new(params, &network_graph); let source = source_node_id(); let target = target_node_id(); 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, 10_240, 1_024_000, &source, &target), 0); + assert_eq!(scorer.channel_penalty_msat(42, 102_400, 1_024_000, &source, &target), 47); assert_eq!(scorer.channel_penalty_msat(42, 1_024_000, 1_024_000, &source, &target), 2_000); 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, 374, 1_024, &source, &target), 198); + assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 300); + assert_eq!(scorer.channel_penalty_msat(42, 640, 1_024, &source, &target), 425); 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); + assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 902); } #[test] @@ -1747,7 +2037,8 @@ mod tests { let last_updated = SinceEpoch::now(); let network_graph = network_graph(); let params = ProbabilisticScoringParameters { - liquidity_penalty_multiplier_msat: 1_000, ..Default::default() + liquidity_penalty_multiplier_msat: 1_000, + ..ProbabilisticScoringParameters::zero_penalty() }; let scorer = ProbabilisticScorer::new(params, &network_graph) .with_channel(42, @@ -1759,15 +2050,16 @@ mod tests { assert_eq!(scorer.channel_penalty_msat(42, 39, 100, &source, &target), 0); assert_ne!(scorer.channel_penalty_msat(42, 50, 100, &source, &target), 0); - assert_ne!(scorer.channel_penalty_msat(42, 50, 100, &source, &target), 2_000); - assert_eq!(scorer.channel_penalty_msat(42, 61, 100, &source, &target), 2_000); + assert_ne!(scorer.channel_penalty_msat(42, 50, 100, &source, &target), u64::max_value()); + assert_eq!(scorer.channel_penalty_msat(42, 61, 100, &source, &target), u64::max_value()); } #[test] fn does_not_further_penalize_own_channel() { let network_graph = network_graph(); let params = ProbabilisticScoringParameters { - liquidity_penalty_multiplier_msat: 1_000, ..Default::default() + liquidity_penalty_multiplier_msat: 1_000, + ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph); let sender = sender_node_id(); @@ -1775,20 +2067,21 @@ mod tests { let failed_path = payment_path_for_amount(500); let successful_path = payment_path_for_amount(200); - assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 300); + assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 301); scorer.payment_path_failed(&failed_path.iter().collect::>(), 41); - assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 300); + assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 301); scorer.payment_path_successful(&successful_path.iter().collect::>()); - assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 300); + assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 301); } #[test] fn sets_liquidity_lower_bound_on_downstream_failure() { let network_graph = network_graph(); let params = ProbabilisticScoringParameters { - liquidity_penalty_multiplier_msat: 1_000, ..Default::default() + liquidity_penalty_multiplier_msat: 1_000, + ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph); let source = source_node_id(); @@ -1796,8 +2089,8 @@ mod tests { let path = payment_path_for_amount(500); 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), 601); + assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 301); + assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 602); scorer.payment_path_failed(&path.iter().collect::>(), 43); @@ -1810,7 +2103,8 @@ mod tests { fn sets_liquidity_upper_bound_on_failure() { let network_graph = network_graph(); let params = ProbabilisticScoringParameters { - liquidity_penalty_multiplier_msat: 1_000, ..Default::default() + liquidity_penalty_multiplier_msat: 1_000, + ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph); let source = source_node_id(); @@ -1818,21 +2112,22 @@ mod tests { let path = payment_path_for_amount(500); 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), 601); + assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 301); + assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 602); scorer.payment_path_failed(&path.iter().collect::>(), 42); assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 300); - assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 2_000); - assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 2_000); + assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value()); + assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), u64::max_value()); } #[test] fn reduces_liquidity_upper_bound_along_path_on_success() { let network_graph = network_graph(); let params = ProbabilisticScoringParameters { - liquidity_penalty_multiplier_msat: 1_000, ..Default::default() + liquidity_penalty_multiplier_msat: 1_000, + ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph); let sender = sender_node_id(); @@ -1858,6 +2153,7 @@ mod tests { let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, liquidity_offset_half_life: Duration::from_secs(10), + ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph); let source = source_node_id(); @@ -1870,21 +2166,21 @@ mod tests { scorer.payment_path_failed(&payment_path_for_amount(128).iter().collect::>(), 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), 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); + assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 93); + assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_479); + assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), u64::max_value()); 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), 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); + assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 93); + assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_479); + assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), u64::max_value()); 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_773); - assert_eq!(scorer.channel_penalty_msat(42, 960, 1_024, &source, &target), 2_000); + assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 1_970); + assert_eq!(scorer.channel_penalty_msat(42, 960, 1_024, &source, &target), u64::max_value()); // Fully decay liquidity lower bound. SinceEpoch::advance(Duration::from_secs(10 * 7)); @@ -1909,6 +2205,7 @@ mod tests { let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, liquidity_offset_half_life: Duration::from_secs(10), + ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph); let source = source_node_id(); @@ -1916,7 +2213,7 @@ mod tests { assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125); scorer.payment_path_failed(&payment_path_for_amount(512).iter().collect::>(), 42); - assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 274); + assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 281); // An unchecked right shift 64 bits or more in DirectedChannelLiquidity::decayed_offset_msat // would cause an overflow. @@ -1933,35 +2230,36 @@ mod tests { let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, liquidity_offset_half_life: Duration::from_secs(10), + ..ProbabilisticScoringParameters::zero_penalty() }; 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, 512, 1_024, &source, &target), 301); + assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 300); // More knowledge gives higher confidence (256, 768), meaning a lower penalty. scorer.payment_path_failed(&payment_path_for_amount(768).iter().collect::>(), 42); scorer.payment_path_failed(&payment_path_for_amount(256).iter().collect::>(), 43); - assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 274); + assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 281); // Decaying knowledge gives less confidence (128, 896), meaning a higher penalty. SinceEpoch::advance(Duration::from_secs(10)); - assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 301); + assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 291); // Reducing the upper bound gives more confidence (128, 832) that the payment amount (512) // is closer to the upper bound, meaning a higher penalty. scorer.payment_path_successful(&payment_path_for_amount(64).iter().collect::>()); - assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 342); + assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 331); // Increasing the lower bound gives more confidence (256, 832) that the payment amount (512) // is closer to the lower bound, meaning a lower penalty. scorer.payment_path_failed(&payment_path_for_amount(256).iter().collect::>(), 43); - assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 255); + assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 245); // Further decaying affects the lower bound more than the upper bound (128, 928). SinceEpoch::advance(Duration::from_secs(10)); - assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 284); + assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 280); } #[test] @@ -1970,16 +2268,17 @@ mod tests { let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, liquidity_offset_half_life: Duration::from_secs(10), + ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph); let source = source_node_id(); let target = target_node_id(); scorer.payment_path_failed(&payment_path_for_amount(500).iter().collect::>(), 42); - assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 2_000); + assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value()); SinceEpoch::advance(Duration::from_secs(10)); - assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 472); + assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 473); scorer.payment_path_failed(&payment_path_for_amount(250).iter().collect::>(), 43); assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300); @@ -1999,13 +2298,14 @@ mod tests { let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, liquidity_offset_half_life: Duration::from_secs(10), + ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph); let source = source_node_id(); let target = target_node_id(); scorer.payment_path_failed(&payment_path_for_amount(500).iter().collect::>(), 42); - assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 2_000); + assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value()); let mut serialized_scorer = Vec::new(); scorer.write(&mut serialized_scorer).unwrap(); @@ -2015,12 +2315,95 @@ mod tests { let mut serialized_scorer = io::Cursor::new(&serialized_scorer); let deserialized_scorer = ::read(&mut serialized_scorer, (params, &network_graph)).unwrap(); - assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 472); + assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 473); scorer.payment_path_failed(&payment_path_for_amount(250).iter().collect::>(), 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), 371); + assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 365); + } + + #[test] + fn scores_realistic_payments() { + // Shows the scores of "realistic" sends of 100k sats over channels of 1-10m sats (with a + // 50k sat reserve). + let network_graph = network_graph(); + let params = ProbabilisticScoringParameters::default(); + let scorer = ProbabilisticScorer::new(params, &network_graph); + let source = source_node_id(); + let target = target_node_id(); + + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 950_000_000, &source, &target), 3613); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 1_950_000_000, &source, &target), 1977); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 2_950_000_000, &source, &target), 1474); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 3_950_000_000, &source, &target), 1223); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 4_950_000_000, &source, &target), 877); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 5_950_000_000, &source, &target), 845); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 6_950_000_000, &source, &target), 500); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 7_450_000_000, &source, &target), 500); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 7_950_000_000, &source, &target), 500); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 8_950_000_000, &source, &target), 500); + assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 9_950_000_000, &source, &target), 500); + } + + #[test] + fn adds_base_penalty_to_liquidity_penalty() { + let network_graph = network_graph(); + let source = source_node_id(); + let target = target_node_id(); + + let params = ProbabilisticScoringParameters { + liquidity_penalty_multiplier_msat: 1_000, + ..ProbabilisticScoringParameters::zero_penalty() + }; + let scorer = ProbabilisticScorer::new(params, &network_graph); + assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 58); + + let params = ProbabilisticScoringParameters { + base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000, ..Default::default() + }; + let scorer = ProbabilisticScorer::new(params, &network_graph); + assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 558); + } + + #[test] + fn adds_amount_penalty_to_liquidity_penalty() { + let network_graph = network_graph(); + let source = source_node_id(); + let target = target_node_id(); + + let params = ProbabilisticScoringParameters { + liquidity_penalty_multiplier_msat: 1_000, + amount_penalty_multiplier_msat: 0, + ..ProbabilisticScoringParameters::zero_penalty() + }; + let scorer = ProbabilisticScorer::new(params, &network_graph); + assert_eq!(scorer.channel_penalty_msat(42, 512_000, 1_024_000, &source, &target), 300); + + let params = ProbabilisticScoringParameters { + liquidity_penalty_multiplier_msat: 1_000, + amount_penalty_multiplier_msat: 256, + ..ProbabilisticScoringParameters::zero_penalty() + }; + let scorer = ProbabilisticScorer::new(params, &network_graph); + assert_eq!(scorer.channel_penalty_msat(42, 512_000, 1_024_000, &source, &target), 337); + } + + #[test] + fn calculates_log10_without_overflowing_u64_max_value() { + let network_graph = network_graph(); + let source = source_node_id(); + let target = target_node_id(); + + let params = ProbabilisticScoringParameters { + liquidity_penalty_multiplier_msat: 40_000, + ..ProbabilisticScoringParameters::zero_penalty() + }; + let scorer = ProbabilisticScorer::new(params, &network_graph); + assert_eq!( + scorer.channel_penalty_msat(42, u64::max_value(), u64::max_value(), &source, &target), + 80_000, + ); } } diff --git a/lightning/src/util/config.rs b/lightning/src/util/config.rs index 55d506e7..bd8b40b6 100644 --- a/lightning/src/util/config.rs +++ b/lightning/src/util/config.rs @@ -47,6 +47,28 @@ pub struct ChannelHandshakeConfig { /// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required /// by the protocol. pub our_htlc_minimum_msat: u64, + /// If set, we attempt to negotiate the `scid_privacy` (referred to as `scid_alias` in the + /// BOLTs) option for outbound private channels. This provides better privacy by not including + /// our real on-chain channel UTXO in each invoice and requiring that our counterparty only + /// relay HTLCs to us using the channel's SCID alias. + /// + /// If this option is set, channels may be created that will not be readable by LDK versions + /// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a + /// [`DecodeError:InvalidValue`]. + /// + /// Note that setting this to true does *not* prevent us from opening channels with + /// counterparties that do not support the `scid_alias` option; we will simply fall back to a + /// private channel without that option. + /// + /// Ignored if the channel is negotiated to be announced, see + /// [`ChannelConfig::announced_channel`] and + /// [`ChannelHandshakeLimits::force_announced_channel_preference`] for more. + /// + /// Default value: false. This value is likely to change to true in the future. + /// + /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager + /// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue + pub negotiate_scid_privacy: bool, } impl Default for ChannelHandshakeConfig { @@ -55,6 +77,7 @@ impl Default for ChannelHandshakeConfig { minimum_depth: 6, our_to_self_delay: BREAKDOWN_TIMEOUT, our_htlc_minimum_msat: 1, + negotiate_scid_privacy: false, } } } diff --git a/lightning/src/util/crypto.rs b/lightning/src/util/crypto.rs index f8a3f847..300ddacb 100644 --- a/lightning/src/util/crypto.rs +++ b/lightning/src/util/crypto.rs @@ -1,6 +1,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::secp256k1::{Message, Secp256k1, SecretKey, Signature, Signing}; macro_rules! hkdf_extract_expand { ($salt: expr, $ikm: expr) => {{ @@ -36,3 +37,12 @@ pub fn hkdf_extract_expand_twice(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32] pub fn hkdf_extract_expand_thrice(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32], [u8; 32]) { hkdf_extract_expand!(salt, ikm, 3) } + +#[inline] +pub fn sign(ctx: &Secp256k1, msg: &Message, sk: &SecretKey) -> Signature { + #[cfg(feature = "grind_signatures")] + let sig = ctx.sign_low_r(msg, sk); + #[cfg(not(feature = "grind_signatures"))] + let sig = ctx.sign(msg, sk); + sig +} diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index 623b2ea0..ea50398b 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -17,6 +17,7 @@ use chain::keysinterface::SpendableOutputDescriptor; use ln::channelmanager::PaymentId; use ln::channel::FUNDING_CONF_DEADLINE_BLOCKS; +use ln::features::ChannelTypeFeatures; use ln::msgs; use ln::msgs::DecodeError; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; @@ -365,11 +366,15 @@ pub enum Event { /// The channel_id of the channel which has been closed. Note that on-chain transactions /// resolving the channel are likely still awaiting confirmation. channel_id: [u8; 32], - /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`], or 0 for - /// an inbound channel. This will always be zero for objects serialized with LDK versions - /// prior to 0.0.102. + /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound + /// channels, or to [`ChannelManager::accept_inbound_channel`] for inbound channels if + /// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise + /// `user_channel_id` will be 0 for an inbound channel. + /// This will always be zero for objects serialized with LDK versions prior to 0.0.102. /// /// [`ChannelManager::create_channel`]: crate::ln::channelmanager::ChannelManager::create_channel + /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel + /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels user_channel_id: u64, /// The reason the channel was closed. reason: ClosureReason @@ -429,6 +434,16 @@ pub enum Event { funding_satoshis: u64, /// Our starting balance in the channel if the request is accepted, in milli-satoshi. push_msat: u64, + /// The features that this channel will operate with. If you reject the channel, a + /// well-behaved counterparty may automatically re-attempt the channel with a new set of + /// feature flags. + /// + /// Note that if [`ChannelTypeFeatures::supports_scid_privacy`] returns true on this type, + /// the resulting [`ChannelManager`] will not be readable by versions of LDK prior to + /// 0.0.106. + /// + /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager + channel_type: ChannelTypeFeatures, }, } diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 6a52e5e1..de12d850 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -174,6 +174,7 @@ pub trait Writeable { } /// Writes self out to a Vec + #[cfg(test)] fn encode_with_len(&self) -> Vec { let mut msg = VecWriter(Vec::new()); 0u16.write(&mut msg).unwrap();