Merge pull request #2025 from TheBlueMatt/2023-02-no-pub-genesis-hashes
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Mon, 27 Feb 2023 17:50:22 +0000 (17:50 +0000)
committerGitHub <noreply@github.com>
Mon, 27 Feb 2023 17:50:22 +0000 (17:50 +0000)
Remove genesis block hash from public API

1  2 
lightning-background-processor/src/lib.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/outbound_payment.rs
lightning/src/routing/gossip.rs

index c471555d782113b659ec8a41b3cd273456e47632,67493c23333696b31e84e3240cc31e78369b35c5..f2b6814fc2ebd64452a0f75711d078996c9e95f5
@@@ -37,6 -37,7 +37,6 @@@ use lightning::util::events::{Event, Ev
  use lightning::util::logger::Logger;
  use lightning::util::persist::Persister;
  use lightning_rapid_gossip_sync::RapidGossipSync;
 -use lightning::io;
  
  use core::ops::Deref;
  use core::time::Duration;
@@@ -430,7 -431,7 +430,7 @@@ pub async fn process_events_async
        persister: PS, event_handler: EventHandler, chain_monitor: M, channel_manager: CM,
        gossip_sync: GossipSync<PGS, RGS, G, UL, L>, peer_manager: PM, logger: L, scorer: Option<S>,
        sleeper: Sleeper,
 -) -> Result<(), io::Error>
 +) -> Result<(), lightning::io::Error>
  where
        UL::Target: 'static + UtxoLookup,
        CF::Target: 'static + chain::Filter,
@@@ -940,7 -941,7 +940,7 @@@ mod tests 
                        let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i)));
                        let network = Network::Testnet;
                        let genesis_block = genesis_block(network);
-                       let network_graph = Arc::new(NetworkGraph::new(genesis_block.header.block_hash(), logger.clone()));
+                       let network_graph = Arc::new(NetworkGraph::new(network, logger.clone()));
                        let scorer = Arc::new(Mutex::new(TestScorer::new()));
                        let seed = [i as u8; 32];
                        let router = Arc::new(DefaultRouter::new(network_graph.clone(), logger.clone(), seed, scorer.clone()));
                        let now = Duration::from_secs(genesis_block.header.time as u64);
                        let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos()));
                        let chain_monitor = Arc::new(chainmonitor::ChainMonitor::new(Some(chain_source.clone()), tx_broadcaster.clone(), logger.clone(), fee_estimator.clone(), persister.clone()));
-                       let best_block = BestBlock::from_genesis(network);
+                       let best_block = BestBlock::from_network(network);
                        let params = ChainParameters { network, best_block };
                        let manager = Arc::new(ChannelManager::new(fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster.clone(), router.clone(), logger.clone(), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), UserConfig::default(), params));
                        let p2p_gossip_sync = Arc::new(P2PGossipSync::new(network_graph.clone(), Some(chain_source.clone()), logger.clone()));
index 577e0984448a257a2ff9a23f305aa2684ef968dc,d938e37102094679915841afb0c59c0a317a1a50..7ef9ba754a9c4722b3302d63f7acf110e3a4bcbb
@@@ -78,7 -78,7 +78,7 @@@ use core::time::Duration
  use core::ops::Deref;
  
  // Re-export this for use in the public API.
 -pub use crate::ln::outbound_payment::{PaymentSendFailure, Retry};
 +pub use crate::ln::outbound_payment::{PaymentSendFailure, Retry, RetryableSendFailure};
  
  // We hold various information about HTLC relay in the HTLC objects in Channel itself:
  //
@@@ -2437,7 -2437,7 +2437,7 @@@ wher
  
                        let per_peer_state = self.per_peer_state.read().unwrap();
                        let peer_state_mutex = per_peer_state.get(&counterparty_node_id)
 -                              .ok_or_else(|| APIError::InvalidRoute{err: "No peer matching the path's first hop found!" })?;
 +                              .ok_or_else(|| APIError::ChannelUnavailable{err: "No peer matching the path's first hop found!".to_owned() })?;
                        let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                        let peer_state = &mut *peer_state_lock;
                        if let hash_map::Entry::Occupied(mut chan) = peer_state.channel_by_id.entry(id) {
  
        /// Similar to [`ChannelManager::send_payment`], but will automatically find a route based on
        /// `route_params` and retry failed payment paths based on `retry_strategy`.
 -      pub fn send_payment_with_retry(&self, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<(), PaymentSendFailure> {
 +      pub fn send_payment_with_retry(&self, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<(), RetryableSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
                self.pending_outbound_payments
                        .send_payment(payment_hash, payment_secret, payment_id, retry_strategy, route_params,
                                &self.router, self.list_usable_channels(), || self.compute_inflight_htlcs(),
                                &self.entropy_source, &self.node_signer, best_block_height, &self.logger,
 +                              &self.pending_events,
                                |path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
                                self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv))
        }
        /// payments.
        ///
        /// [`PaymentParameters::for_keysend`]: crate::routing::router::PaymentParameters::for_keysend
 -      pub fn send_spontaneous_payment_with_retry(&self, payment_preimage: Option<PaymentPreimage>, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<PaymentHash, PaymentSendFailure> {
 +      pub fn send_spontaneous_payment_with_retry(&self, payment_preimage: Option<PaymentPreimage>, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<PaymentHash, RetryableSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
                self.pending_outbound_payments.send_spontaneous_payment(payment_preimage, payment_id,
                        retry_strategy, route_params, &self.router, self.list_usable_channels(),
                        || self.compute_inflight_htlcs(),  &self.entropy_source, &self.node_signer, best_block_height,
 -                      &self.logger,
 +                      &self.logger, &self.pending_events,
                        |path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
                        self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv))
        }
@@@ -8673,13 -8672,12 +8673,12 @@@ pub mod bench 
                // Note that this is unrealistic as each payment send will require at least two fsync
                // calls per node.
                let network = bitcoin::Network::Testnet;
-               let genesis_hash = bitcoin::blockdata::constants::genesis_block(network).header.block_hash();
  
                let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))};
                let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
                let logger_a = test_utils::TestLogger::with_id("node a".to_owned());
                let scorer = Mutex::new(test_utils::TestScorer::new());
-               let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(genesis_hash, &logger_a)), &scorer);
+               let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &scorer);
  
                let mut config: UserConfig = Default::default();
                config.channel_handshake_config.minimum_depth = 1;
                let keys_manager_a = KeysManager::new(&seed_a, 42, 42);
                let node_a = ChannelManager::new(&fee_estimator, &chain_monitor_a, &tx_broadcaster, &router, &logger_a, &keys_manager_a, &keys_manager_a, &keys_manager_a, config.clone(), ChainParameters {
                        network,
-                       best_block: BestBlock::from_genesis(network),
+                       best_block: BestBlock::from_network(network),
                });
                let node_a_holder = NodeHolder { node: &node_a };
  
                let keys_manager_b = KeysManager::new(&seed_b, 42, 42);
                let node_b = ChannelManager::new(&fee_estimator, &chain_monitor_b, &tx_broadcaster, &router, &logger_b, &keys_manager_b, &keys_manager_b, &keys_manager_b, config.clone(), ChainParameters {
                        network,
-                       best_block: BestBlock::from_genesis(network),
+                       best_block: BestBlock::from_network(network),
                });
                let node_b_holder = NodeHolder { node: &node_b };
  
                assert_eq!(&tx_broadcaster.txn_broadcasted.lock().unwrap()[..], &[tx.clone()]);
  
                let block = Block {
-                       header: BlockHeader { version: 0x20000000, prev_blockhash: genesis_hash, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
+                       header: BlockHeader { version: 0x20000000, prev_blockhash: BestBlock::from_network(network).block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 },
                        txdata: vec![tx],
                };
                Listen::block_connected(&node_a, &block, 1);
                        _ => panic!("Unexpected event"),
                }
  
-               let dummy_graph = NetworkGraph::new(genesis_hash, &logger_a);
+               let dummy_graph = NetworkGraph::new(network, &logger_a);
  
                let mut payment_count: u64 = 0;
                macro_rules! send_payment {
index 1d8d46a916a01cfdfa1cd783df48c7023a6c39e4,361adfaf66c3eab2b4a78678a6d7b5ffe5dfb81c..81b95f1ce07230ccd7b46339fd7c28ea6bcaba8e
@@@ -64,8 -64,13 +64,8 @@@ pub(crate) enum PendingOutboundPayment 
                payment_hash: Option<PaymentHash>,
                timer_ticks_without_htlcs: u8,
        },
 -      /// When a payer gives up trying to retry a payment, they inform us, letting us generate a
 -      /// `PaymentFailed` event when all HTLCs have irrevocably failed. This avoids a number of race
 -      /// conditions in MPP-aware payment retriers (1), where the possibility of multiple
 -      /// `PaymentPathFailed` events with `all_paths_failed` can be pending at once, confusing a
 -      /// downstream event handler as to when a payment has actually failed.
 -      ///
 -      /// (1) <https://github.com/lightningdevkit/rust-lightning/issues/1164>
 +      /// When we've decided to give up retrying a payment, we mark it as abandoned so we can eventually
 +      /// generate a `PaymentFailed` event when all HTLCs have irrevocably failed.
        Abandoned {
                session_privs: HashSet<[u8; 32]>,
                payment_hash: PaymentHash,
@@@ -235,10 -240,7 +235,10 @@@ pub enum Retry 
        /// were retried along a route from a single call to [`Router::find_route`].
        Attempts(usize),
        #[cfg(not(feature = "no-std"))]
 -      /// Time elapsed before abandoning retries for a payment.
 +      /// Time elapsed before abandoning retries for a payment. At least one attempt at payment is made;
 +      /// see [`PaymentParameters::expiry_time`] to avoid any attempt at payment after a specific time.
 +      ///
 +      /// [`PaymentParameters::expiry_time`]: crate::routing::router::PaymentParameters::expiry_time
        Timeout(core::time::Duration),
  }
  
@@@ -310,35 -312,9 +310,35 @@@ impl<T: Time> Display for PaymentAttemp
        }
  }
  
 -/// If a payment fails to send, it can be in one of several states. This enum is returned as the
 -/// Err() type describing which state the payment is in, see the description of individual enum
 -/// states for more.
 +/// Indicates an immediate error on [`ChannelManager::send_payment_with_retry`]. Further errors
 +/// may be surfaced later via [`Event::PaymentPathFailed`] and [`Event::PaymentFailed`].
 +///
 +/// [`ChannelManager::send_payment_with_retry`]: crate::ln::channelmanager::ChannelManager::send_payment_with_retry
 +/// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
 +/// [`Event::PaymentFailed`]: crate::util::events::Event::PaymentFailed
 +#[derive(Clone, Debug)]
 +pub enum RetryableSendFailure {
 +      /// The provided [`PaymentParameters::expiry_time`] indicated that the payment has expired. Note
 +      /// that this error is *not* caused by [`Retry::Timeout`].
 +      ///
 +      /// [`PaymentParameters::expiry_time`]: crate::routing::router::PaymentParameters::expiry_time
 +      PaymentExpired,
 +      /// We were unable to find a route to the destination.
 +      RouteNotFound,
 +      /// Indicates that a payment for the provided [`PaymentId`] is already in-flight and has not
 +      /// yet completed (i.e. generated an [`Event::PaymentSent`] or [`Event::PaymentFailed`]).
 +      ///
 +      /// [`PaymentId`]: crate::ln::channelmanager::PaymentId
 +      /// [`Event::PaymentSent`]: crate::util::events::Event::PaymentSent
 +      /// [`Event::PaymentFailed`]: crate::util::events::Event::PaymentFailed
 +      DuplicatePayment,
 +}
 +
 +/// If a payment fails to send with [`ChannelManager::send_payment`], it can be in one of several
 +/// states. This enum is returned as the Err() type describing which state the payment is in, see
 +/// the description of individual enum states for more.
 +///
 +/// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
  #[derive(Clone, Debug)]
  pub enum PaymentSendFailure {
        /// A parameter which was passed to send_payment was invalid, preventing us from attempting to
@@@ -421,9 -397,8 +421,9 @@@ impl OutboundPayments 
                &self, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_id: PaymentId,
                retry_strategy: Retry, route_params: RouteParameters, router: &R,
                first_hops: Vec<ChannelDetails>, compute_inflight_htlcs: IH, entropy_source: &ES,
 -              node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: SP,
 -      ) -> Result<(), PaymentSendFailure>
 +              node_signer: &NS, best_block_height: u32, logger: &L,
 +              pending_events: &Mutex<Vec<events::Event>>, send_payment_along_path: SP,
 +      ) -> Result<(), RetryableSendFailure>
        where
                R::Target: Router,
                ES::Target: EntropySource,
                SP: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
                         u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>,
        {
 -              self.pay_internal(payment_id, Some((payment_hash, payment_secret, None, retry_strategy)),
 +              self.send_payment_internal(payment_id, payment_hash, payment_secret, None, retry_strategy,
                        route_params, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer,
 -                      best_block_height, logger, &send_payment_along_path)
 -                      .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
 +                      best_block_height, logger, pending_events, &send_payment_along_path)
        }
  
        pub(super) fn send_payment_with_route<ES: Deref, NS: Deref, F>(
                &self, payment_preimage: Option<PaymentPreimage>, payment_id: PaymentId,
                retry_strategy: Retry, route_params: RouteParameters, router: &R,
                first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
 -              node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: SP
 -      ) -> Result<PaymentHash, PaymentSendFailure>
 +              node_signer: &NS, best_block_height: u32, logger: &L,
 +              pending_events: &Mutex<Vec<events::Event>>, send_payment_along_path: SP
 +      ) -> Result<PaymentHash, RetryableSendFailure>
        where
                R::Target: Router,
                ES::Target: EntropySource,
                let preimage = payment_preimage
                        .unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
                let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
 -              self.pay_internal(payment_id, Some((payment_hash, &None, Some(preimage), retry_strategy)),
 -                      route_params, router, first_hops, &inflight_htlcs, entropy_source, node_signer,
 -                      best_block_height, logger, &send_payment_along_path)
 +              self.send_payment_internal(payment_id, payment_hash, &None, Some(preimage), retry_strategy,
 +                      route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer,
 +                      best_block_height, logger, pending_events, send_payment_along_path)
                        .map(|()| payment_hash)
 -                      .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
        }
  
        pub(super) fn send_spontaneous_payment_with_route<ES: Deref, NS: Deref, F>(
                        }
                        core::mem::drop(outbounds);
                        if let Some((payment_id, route_params)) = retry_id_route_params {
 -                              if let Err(e) = self.pay_internal(payment_id, None, route_params, router, first_hops(), &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, &send_payment_along_path) {
 -                                      log_info!(logger, "Errored retrying payment: {:?}", e);
 -                                      // If we error on retry, there is no chance of the payment succeeding and no HTLCs have
 -                                      // been irrevocably committed to, so we can safely abandon.
 -                                      self.abandon_payment(payment_id, pending_events);
 -                              }
 +                              self.retry_payment_internal(payment_id, route_params, router, first_hops(), &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, &send_payment_along_path)
                        } else { break }
                }
  
                        !pmt.is_auto_retryable_now() && pmt.remaining_parts() == 0 && !pmt.is_fulfilled())
        }
  
 -      /// Will return `Ok(())` iff at least one HTLC is sent for the payment.
 -      fn pay_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
 -              &self, payment_id: PaymentId,
 -              initial_send_info: Option<(PaymentHash, &Option<PaymentSecret>, Option<PaymentPreimage>, Retry)>,
 -              route_params: RouteParameters, router: &R, first_hops: Vec<ChannelDetails>,
 -              inflight_htlcs: &IH, entropy_source: &ES, node_signer: &NS, best_block_height: u32,
 -              logger: &L, send_payment_along_path: &SP,
 -      ) -> Result<(), PaymentSendFailure>
 +      /// Errors immediately on [`RetryableSendFailure`] error conditions. Otherwise, further errors may
 +      /// be surfaced asynchronously via [`Event::PaymentPathFailed`] and [`Event::PaymentFailed`].
 +      ///
 +      /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
 +      /// [`Event::PaymentFailed`]: crate::util::events::Event::PaymentFailed
 +      fn send_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
 +              &self, payment_id: PaymentId, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>,
 +              keysend_preimage: Option<PaymentPreimage>, retry_strategy: Retry, route_params: RouteParameters,
 +              router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
 +              node_signer: &NS, best_block_height: u32, logger: &L,
 +              pending_events: &Mutex<Vec<events::Event>>, send_payment_along_path: SP,
 +      ) -> Result<(), RetryableSendFailure>
        where
                R::Target: Router,
                ES::Target: EntropySource,
                L::Target: Logger,
                IH: Fn() -> InFlightHtlcs,
                SP: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
 -                 u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>
 +                  u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>
        {
                #[cfg(feature = "std")] {
                        if has_expired(&route_params) {
 -                              return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                                      err: format!("Invoice expired for payment id {}", log_bytes!(payment_id.0)),
 -                              }))
 +                              return Err(RetryableSendFailure::PaymentExpired)
                        }
                }
  
                let route = router.find_route(
                        &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
 -                      Some(&first_hops.iter().collect::<Vec<_>>()), &inflight_htlcs(),
 -              ).map_err(|e| PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                      err: format!("Failed to find a route for payment {}: {:?}", log_bytes!(payment_id.0), e), // TODO: add APIError::RouteNotFound
 -              }))?;
 -
 -              let res = if let Some((payment_hash, payment_secret, keysend_preimage, retry_strategy)) = initial_send_info {
 -                      let onion_session_privs = self.add_new_pending_payment(payment_hash, *payment_secret, payment_id, keysend_preimage, &route, Some(retry_strategy), Some(route_params.payment_params.clone()), entropy_source, best_block_height)?;
 -                      self.pay_route_internal(&route, payment_hash, payment_secret, None, payment_id, None, onion_session_privs, node_signer, best_block_height, send_payment_along_path)
 -              } else {
 -                      self.retry_payment_with_route(&route, payment_id, entropy_source, node_signer, best_block_height, send_payment_along_path)
 -              };
 -              match res {
 -                      Err(PaymentSendFailure::AllFailedResendSafe(_)) => {
 -                              let retry_res = self.pay_internal(payment_id, None, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, send_payment_along_path);
 -                              log_info!(logger, "Result retrying payment id {}: {:?}", log_bytes!(payment_id.0), retry_res);
 -                              if let Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError { err })) = &retry_res {
 -                                      if err.starts_with("Retries exhausted ") { return res; }
 -                              }
 -                              retry_res
 -                      },
 -                      Err(PaymentSendFailure::PartialFailure { failed_paths_retry: Some(retry), .. }) => {
 -                              // Some paths were sent, even if we failed to send the full MPP value our recipient may
 -                              // misbehave and claim the funds, at which point we have to consider the payment sent, so
 -                              // return `Ok()` here, ignoring any retry errors.
 -                              let retry_res = self.pay_internal(payment_id, None, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, send_payment_along_path);
 -                              log_info!(logger, "Result retrying payment id {}: {:?}", log_bytes!(payment_id.0), retry_res);
 -                              Ok(())
 -                      },
 -                      Err(PaymentSendFailure::PartialFailure { failed_paths_retry: None, .. }) => {
 -                              // This may happen if we send a payment and some paths fail, but only due to a temporary
 -                              // monitor failure or the like, implying they're really in-flight, but we haven't sent the
 -                              // initial HTLC-Add messages yet.
 -                              Ok(())
 -                      },
 -                      res => res,
 +                      Some(&first_hops.iter().collect::<Vec<_>>()), &inflight_htlcs()
 +              ).map_err(|_| RetryableSendFailure::RouteNotFound)?;
 +
 +              let onion_session_privs = self.add_new_pending_payment(payment_hash, *payment_secret,
 +                      payment_id, keysend_preimage, &route, Some(retry_strategy),
 +                      Some(route_params.payment_params.clone()), entropy_source, best_block_height)
 +                      .map_err(|_| RetryableSendFailure::DuplicatePayment)?;
 +
 +              let res = self.pay_route_internal(&route, payment_hash, payment_secret, None, payment_id, None,
 +                      onion_session_privs, node_signer, best_block_height, &send_payment_along_path);
 +              log_info!(logger, "Result sending payment with id {}: {:?}", log_bytes!(payment_id.0), res);
 +              if let Err(e) = res {
 +                      self.handle_pay_route_err(e, payment_id, payment_hash, route, route_params, router, first_hops, &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, &send_payment_along_path);
                }
 +              Ok(())
        }
  
 -      pub(super) fn retry_payment_with_route<ES: Deref, NS: Deref, F>(
 -              &self, route: &Route, payment_id: PaymentId, entropy_source: &ES, node_signer: &NS, best_block_height: u32,
 -              send_payment_along_path: F
 -      ) -> Result<(), PaymentSendFailure>
 +      fn retry_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
 +              &self, payment_id: PaymentId, route_params: RouteParameters, router: &R,
 +              first_hops: Vec<ChannelDetails>, inflight_htlcs: &IH, entropy_source: &ES, node_signer: &NS,
 +              best_block_height: u32, logger: &L, pending_events: &Mutex<Vec<events::Event>>,
 +              send_payment_along_path: &SP,
 +      )
        where
 +              R::Target: Router,
                ES::Target: EntropySource,
                NS::Target: NodeSigner,
 -              F: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
 -                 u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>
 +              L::Target: Logger,
 +              IH: Fn() -> InFlightHtlcs,
 +              SP: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
 +                  u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>
        {
 -              const RETRY_OVERFLOW_PERCENTAGE: u64 = 10;
 +              #[cfg(feature = "std")] {
 +                      if has_expired(&route_params) {
 +                              log_error!(logger, "Payment params expired on retry, abandoning payment {}", log_bytes!(payment_id.0));
 +                              self.abandon_payment(payment_id, pending_events);
 +                              return
 +                      }
 +              }
 +
 +              let route = match router.find_route(
 +                      &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
 +                      Some(&first_hops.iter().collect::<Vec<_>>()), &inflight_htlcs()
 +              ) {
 +                      Ok(route) => route,
 +                      Err(e) => {
 +                              log_error!(logger, "Failed to find a route on retry, abandoning payment {}: {:#?}", log_bytes!(payment_id.0), e);
 +                              self.abandon_payment(payment_id, pending_events);
 +                              return
 +                      }
 +              };
                for path in route.paths.iter() {
                        if path.len() == 0 {
 -                              return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                                      err: "length-0 path in route".to_string()
 -                              }))
 +                              log_error!(logger, "length-0 path in route");
 +                              self.abandon_payment(payment_id, pending_events);
 +                              return
                        }
                }
  
 +              const RETRY_OVERFLOW_PERCENTAGE: u64 = 10;
                let mut onion_session_privs = Vec::with_capacity(route.paths.len());
                for _ in 0..route.paths.len() {
                        onion_session_privs.push(entropy_source.get_secure_random_bytes());
                }
  
 +              macro_rules! abandon_with_entry {
 +                      ($payment_id: expr, $payment_hash: expr, $payment: expr, $pending_events: expr) => {
 +                              if $payment.get_mut().mark_abandoned().is_ok() && $payment.get().remaining_parts() == 0 {
 +                                      $pending_events.lock().unwrap().push(events::Event::PaymentFailed {
 +                                              payment_id: $payment_id,
 +                                              payment_hash: $payment_hash,
 +                                      });
 +                                      $payment.remove();
 +                              }
 +                      }
 +              }
                let (total_msat, payment_hash, payment_secret, keysend_preimage) = {
                        let mut outbounds = self.pending_outbound_payments.lock().unwrap();
 -                      match outbounds.get_mut(&payment_id) {
 -                              Some(payment) => {
 -                                      let res = match payment {
 +                      match outbounds.entry(payment_id) {
 +                              hash_map::Entry::Occupied(mut payment) => {
 +                                      let res = match payment.get() {
                                                PendingOutboundPayment::Retryable {
                                                        total_msat, payment_hash, keysend_preimage, payment_secret, pending_amt_msat, ..
                                                } => {
                                                        let retry_amt_msat: u64 = route.paths.iter().map(|path| path.last().unwrap().fee_msat).sum();
                                                        if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
 -                                                              return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                                                                      err: format!("retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}", retry_amt_msat, pending_amt_msat, total_msat).to_string()
 -                                                              }))
 +                                                              log_error!(logger, "retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}", retry_amt_msat, pending_amt_msat, total_msat);
 +                                                              let payment_hash = *payment_hash;
 +                                                              abandon_with_entry!(payment_id, payment_hash, payment, pending_events);
 +                                                              return
                                                        }
                                                        (*total_msat, *payment_hash, *payment_secret, *keysend_preimage)
                                                },
                                                PendingOutboundPayment::Legacy { .. } => {
 -                                                      return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                                                              err: "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102".to_string()
 -                                                      }))
 +                                                      log_error!(logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102");
 +                                                      return
                                                },
                                                PendingOutboundPayment::Fulfilled { .. } => {
 -                                                      return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                                                              err: "Payment already completed".to_owned()
 -                                                      }));
 +                                                      log_error!(logger, "Payment already completed");
 +                                                      return
                                                },
                                                PendingOutboundPayment::Abandoned { .. } => {
 -                                                      return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                                                              err: "Payment already abandoned (with some HTLCs still pending)".to_owned()
 -                                                      }));
 +                                                      log_error!(logger, "Payment already abandoned (with some HTLCs still pending)");
 +                                                      return
                                                },
                                        };
 -                                      if !payment.is_retryable_now() {
 -                                              return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                                                      err: format!("Retries exhausted for payment id {}", log_bytes!(payment_id.0)),
 -                                              }))
 +                                      if !payment.get().is_retryable_now() {
 +                                              log_error!(logger, "Retries exhausted for payment id {}", log_bytes!(payment_id.0));
 +                                              abandon_with_entry!(payment_id, res.1, payment, pending_events);
 +                                              return
                                        }
 -                                      payment.increment_attempts();
 +                                      payment.get_mut().increment_attempts();
                                        for (path, session_priv_bytes) in route.paths.iter().zip(onion_session_privs.iter()) {
 -                                              assert!(payment.insert(*session_priv_bytes, path));
 +                                              assert!(payment.get_mut().insert(*session_priv_bytes, path));
                                        }
                                        res
                                },
 -                              None =>
 -                                      return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
 -                                              err: format!("Payment with ID {} not found", log_bytes!(payment_id.0)),
 -                                      })),
 +                              hash_map::Entry::Vacant(_) => {
 +                                      log_error!(logger, "Payment with ID {} not found", log_bytes!(payment_id.0));
 +                                      return
 +                              }
                        }
                };
 -              self.pay_route_internal(route, payment_hash, &payment_secret, keysend_preimage, payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height, &send_payment_along_path)
 +              let res = self.pay_route_internal(&route, payment_hash, &payment_secret, keysend_preimage,
 +                      payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height,
 +                      &send_payment_along_path);
 +              log_info!(logger, "Result retrying payment id {}: {:?}", log_bytes!(payment_id.0), res);
 +              if let Err(e) = res {
 +                      self.handle_pay_route_err(e, payment_id, payment_hash, route, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
 +              }
 +      }
 +
 +      fn handle_pay_route_err<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
 +              &self, err: PaymentSendFailure, payment_id: PaymentId, payment_hash: PaymentHash, route: Route,
 +              mut route_params: RouteParameters, router: &R, first_hops: Vec<ChannelDetails>,
 +              inflight_htlcs: &IH, entropy_source: &ES, node_signer: &NS, best_block_height: u32, logger: &L,
 +              pending_events: &Mutex<Vec<events::Event>>, send_payment_along_path: &SP,
 +      )
 +      where
 +              R::Target: Router,
 +              ES::Target: EntropySource,
 +              NS::Target: NodeSigner,
 +              L::Target: Logger,
 +              IH: Fn() -> InFlightHtlcs,
 +              SP: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
 +                  u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>
 +      {
 +              match err {
 +                      PaymentSendFailure::AllFailedResendSafe(errs) => {
 +                              Self::push_path_failed_evs_and_scids(payment_id, payment_hash, &mut route_params, route.paths, errs.into_iter().map(|e| Err(e)), pending_events);
 +                              self.retry_payment_internal(payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
 +                      },
 +                      PaymentSendFailure::PartialFailure { failed_paths_retry: Some(mut retry), results, .. } => {
 +                              Self::push_path_failed_evs_and_scids(payment_id, payment_hash, &mut retry, route.paths, results.into_iter(), pending_events);
 +                              // Some paths were sent, even if we failed to send the full MPP value our recipient may
 +                              // misbehave and claim the funds, at which point we have to consider the payment sent, so
 +                              // return `Ok()` here, ignoring any retry errors.
 +                              self.retry_payment_internal(payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
 +                      },
 +                      PaymentSendFailure::PartialFailure { failed_paths_retry: None, .. } => {
 +                              // This may happen if we send a payment and some paths fail, but only due to a temporary
 +                              // monitor failure or the like, implying they're really in-flight, but we haven't sent the
 +                              // initial HTLC-Add messages yet.
 +                      },
 +                      PaymentSendFailure::PathParameterError(results) => {
 +                              Self::push_path_failed_evs_and_scids(payment_id, payment_hash, &mut route_params, route.paths, results.into_iter(), pending_events);
 +                              self.abandon_payment(payment_id, pending_events);
 +                      },
 +                      PaymentSendFailure::ParameterError(e) => {
 +                              log_error!(logger, "Failed to send to route due to parameter error: {:?}. Your router is buggy", e);
 +                              self.abandon_payment(payment_id, pending_events);
 +                      },
 +                      PaymentSendFailure::DuplicatePayment => debug_assert!(false), // unreachable
 +              }
 +      }
 +
 +      fn push_path_failed_evs_and_scids<I: ExactSizeIterator + Iterator<Item = Result<(), APIError>>>(
 +              payment_id: PaymentId, payment_hash: PaymentHash, route_params: &mut RouteParameters,
 +              paths: Vec<Vec<RouteHop>>, path_results: I, pending_events: &Mutex<Vec<events::Event>>
 +      ) {
 +              let mut events = pending_events.lock().unwrap();
 +              debug_assert_eq!(paths.len(), path_results.len());
 +              for (path, path_res) in paths.into_iter().zip(path_results) {
 +                      if let Err(e) = path_res {
 +                              let failed_scid = if let APIError::InvalidRoute { .. } = e {
 +                                      None
 +                              } else {
 +                                      let scid = path[0].short_channel_id;
 +                                      route_params.payment_params.previously_failed_channels.push(scid);
 +                                      Some(scid)
 +                              };
 +                              events.push(events::Event::PaymentPathFailed {
 +                                      payment_id: Some(payment_id),
 +                                      payment_hash,
 +                                      payment_failed_permanently: false,
 +                                      network_update: None,
 +                                      all_paths_failed: false,
 +                                      path,
 +                                      short_channel_id: failed_scid,
 +                                      retry: None,
 +                                      #[cfg(test)]
 +                                      error_code: None,
 +                                      #[cfg(test)]
 +                                      error_data: None,
 +                              });
 +                      }
 +              }
        }
  
        pub(super) fn send_probe<ES: Deref, NS: Deref, F>(
@@@ -1352,18 -1236,17 +1352,17 @@@ impl_writeable_tlv_based_enum_upgradabl
  
  #[cfg(test)]
  mod tests {
-       use bitcoin::blockdata::constants::genesis_block;
        use bitcoin::network::constants::Network;
        use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
  
        use crate::ln::PaymentHash;
 -      use crate::ln::channelmanager::{PaymentId, PaymentSendFailure};
 +      use crate::ln::channelmanager::PaymentId;
        use crate::ln::msgs::{ErrorAction, LightningError};
 -      use crate::ln::outbound_payment::{OutboundPayments, Retry};
 +      use crate::ln::outbound_payment::{OutboundPayments, Retry, RetryableSendFailure};
        use crate::routing::gossip::NetworkGraph;
        use crate::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteParameters};
        use crate::sync::{Arc, Mutex};
 -      use crate::util::errors::APIError;
 +      use crate::util::events::Event;
        use crate::util::test_utils;
  
        #[test]
        fn do_fails_paying_after_expiration(on_retry: bool) {
                let outbound_payments = OutboundPayments::new();
                let logger = test_utils::TestLogger::new();
-               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let network_graph = Arc::new(NetworkGraph::new(genesis_hash, &logger));
+               let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = Mutex::new(test_utils::TestScorer::new());
                let router = test_utils::TestRouter::new(network_graph, &scorer);
                let secp_ctx = Secp256k1::new();
                        final_value_msat: 0,
                        final_cltv_expiry_delta: 0,
                };
 -              let err = if on_retry {
 -                      outbound_payments.pay_internal(
 -                              PaymentId([0; 32]), None, expired_route_params, &&router, vec![], &|| InFlightHtlcs::new(),
 -                              &&keys_manager, &&keys_manager, 0, &&logger, &|_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err()
 +              let pending_events = Mutex::new(Vec::new());
 +              if on_retry {
 +                      outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), None, PaymentId([0; 32]), None,
 +                      &Route { paths: vec![], payment_params: None }, Some(Retry::Attempts(1)),
 +                      Some(expired_route_params.payment_params.clone()), &&keys_manager, 0).unwrap();
 +                      outbound_payments.retry_payment_internal(
 +                              PaymentId([0; 32]), expired_route_params, &&router, vec![], &|| InFlightHtlcs::new(),
 +                              &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
 +                              &|_, _, _, _, _, _, _, _, _| Ok(()));
 +                      let events = pending_events.lock().unwrap();
 +                      assert_eq!(events.len(), 1);
 +                      if let Event::PaymentFailed { .. } = events[0] { } else { panic!("Unexpected event"); }
                } else {
 -                      outbound_payments.send_payment(
 +                      let err = outbound_payments.send_payment(
                                PaymentHash([0; 32]), &None, PaymentId([0; 32]), Retry::Attempts(0), expired_route_params,
                                &&router, vec![], || InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger,
 -                              |_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err()
 -              };
 -              if let PaymentSendFailure::ParameterError(APIError::APIMisuseError { err }) = err {
 -                      assert!(err.contains("Invoice expired"));
 -              } else { panic!("Unexpected error"); }
 +                              &pending_events, |_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err();
 +                      if let RetryableSendFailure::PaymentExpired = err { } else { panic!("Unexpected error"); }
 +              }
        }
  
        #[test]
        fn do_find_route_error(on_retry: bool) {
                let outbound_payments = OutboundPayments::new();
                let logger = test_utils::TestLogger::new();
-               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let network_graph = Arc::new(NetworkGraph::new(genesis_hash, &logger));
+               let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = Mutex::new(test_utils::TestScorer::new());
                let router = test_utils::TestRouter::new(network_graph, &scorer);
                let secp_ctx = Secp256k1::new();
                router.expect_find_route(route_params.clone(),
                        Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError }));
  
 -              let err = if on_retry {
 +              let pending_events = Mutex::new(Vec::new());
 +              if on_retry {
                        outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), None, PaymentId([0; 32]), None,
                                &Route { paths: vec![], payment_params: None }, Some(Retry::Attempts(1)),
                                Some(route_params.payment_params.clone()), &&keys_manager, 0).unwrap();
 -                      outbound_payments.pay_internal(
 -                              PaymentId([0; 32]), None, route_params, &&router, vec![], &|| InFlightHtlcs::new(),
 -                              &&keys_manager, &&keys_manager, 0, &&logger, &|_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err()
 +                      outbound_payments.retry_payment_internal(
 +                              PaymentId([0; 32]), route_params, &&router, vec![], &|| InFlightHtlcs::new(),
 +                              &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
 +                              &|_, _, _, _, _, _, _, _, _| Ok(()));
 +                      let events = pending_events.lock().unwrap();
 +                      assert_eq!(events.len(), 1);
 +                      if let Event::PaymentFailed { .. } = events[0] { } else { panic!("Unexpected event"); }
                } else {
 -                      outbound_payments.send_payment(
 +                      let err = outbound_payments.send_payment(
                                PaymentHash([0; 32]), &None, PaymentId([0; 32]), Retry::Attempts(0), route_params,
                                &&router, vec![], || InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger,
 -                              |_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err()
 -              };
 -              if let PaymentSendFailure::ParameterError(APIError::APIMisuseError { err }) = err {
 -                      assert!(err.contains("Failed to find a route"));
 -              } else { panic!("Unexpected error"); }
 +                              &pending_events, |_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err();
 +                      if let RetryableSendFailure::RouteNotFound = err {
 +                      } else { panic!("Unexpected error"); }
 +              }
        }
  }
index 957aecb09486568efe1486342ce0695994e4aa41,2b4ece0ba6bd02d523acd234468f6277d0c73c8e..3d95368d64ed282f11a378f86814a816e88ed1d5
@@@ -18,6 -18,9 +18,9 @@@ use bitcoin::hashes::sha256d::Hash as S
  use bitcoin::hashes::Hash;
  use bitcoin::hash_types::BlockHash;
  
+ use bitcoin::network::constants::Network;
+ use bitcoin::blockdata::constants::genesis_block;
  use crate::ln::features::{ChannelFeatures, NodeFeatures, InitFeatures};
  use crate::ln::msgs::{DecodeError, ErrorAction, Init, LightningError, RoutingMessageHandler, NetAddress, MAX_VALUE_MSAT};
  use crate::ln::msgs::{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement, GossipTimestampFilter};
@@@ -1017,7 -1020,7 +1020,7 @@@ impl EffectiveCapacity 
  /// Fees for routing via a given channel or a node
  #[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
  pub struct RoutingFees {
 -      /// Flat routing fee in satoshis
 +      /// Flat routing fee in millisatoshis.
        pub base_msat: u32,
        /// Liquidity-based routing fee in millionths of a routed amount.
        /// In other words, 10000 is 1%.
@@@ -1265,10 -1268,10 +1268,10 @@@ impl<L: Deref> PartialEq for NetworkGra
  
  impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
        /// Creates a new, empty, network graph.
-       pub fn new(genesis_hash: BlockHash, logger: L) -> NetworkGraph<L> {
+       pub fn new(network: Network, logger: L) -> NetworkGraph<L> {
                Self {
                        secp_ctx: Secp256k1::verification_only(),
-                       genesis_hash,
+                       genesis_hash: genesis_block(network).header.block_hash(),
                        logger,
                        channels: RwLock::new(IndexedMap::new()),
                        nodes: RwLock::new(IndexedMap::new()),
@@@ -1960,9 -1963,8 +1963,8 @@@ pub(crate) mod tests 
        use crate::sync::Arc;
  
        fn create_network_graph() -> NetworkGraph<Arc<test_utils::TestLogger>> {
-               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
                let logger = Arc::new(test_utils::TestLogger::new());
-               NetworkGraph::new(genesis_hash, logger)
+               NetworkGraph::new(Network::Testnet, logger)
        }
  
        fn create_gossip_sync(network_graph: &NetworkGraph<Arc<test_utils::TestLogger>>) -> (
                let valid_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
  
                // Test if the UTXO lookups were not supported
-               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let network_graph = NetworkGraph::new(Network::Testnet, &logger);
                let mut gossip_sync = P2PGossipSync::new(&network_graph, None, &logger);
                match gossip_sync.handle_channel_announcement(&valid_announcement) {
                        Ok(res) => assert!(res),
                // Test if an associated transaction were not on-chain (or not confirmed).
                let chain_source = test_utils::TestChainSource::new(Network::Testnet);
                *chain_source.utxo_ret.lock().unwrap() = UtxoResult::Sync(Err(UtxoLookupError::UnknownTx));
-               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let network_graph = NetworkGraph::new(Network::Testnet, &logger);
                gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
  
                let valid_announcement = get_signed_channel_announcement(|unsigned_announcement| {
                let secp_ctx = Secp256k1::new();
                let logger = test_utils::TestLogger::new();
                let chain_source = test_utils::TestChainSource::new(Network::Testnet);
-               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let network_graph = NetworkGraph::new(Network::Testnet, &logger);
                let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
  
                let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
        #[test]
        fn handling_network_update() {
                let logger = test_utils::TestLogger::new();
-               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let network_graph = NetworkGraph::new(Network::Testnet, &logger);
                let secp_ctx = Secp256k1::new();
  
                let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
  
                {
                        // Get a new network graph since we don't want to track removed nodes in this test with "std"
-                       let network_graph = NetworkGraph::new(genesis_hash, &logger);
+                       let network_graph = NetworkGraph::new(Network::Testnet, &logger);
  
                        // Announce a channel to test permanent node failure
                        let valid_channel_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
                // Test the removal of channels with `remove_stale_channels_and_tracking`.
                let logger = test_utils::TestLogger::new();
                let chain_source = test_utils::TestChainSource::new(Network::Testnet);
-               let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
-               let network_graph = NetworkGraph::new(genesis_hash, &logger);
+               let network_graph = NetworkGraph::new(Network::Testnet, &logger);
                let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
                let secp_ctx = Secp256k1::new();