# Sadly the log crate is always a dependency of tokio until 1.20, and has no reasonable MSRV guarantees
[ "$RUSTC_MINOR_VERSION" -lt 49 ] && cargo update -p log --precise "0.4.18" --verbose
+# The addr2line v0.20 crate (a dependency of `backtrace` starting with 0.3.68) relies on 1.55+
+[ "$RUSTC_MINOR_VERSION" -lt 55 ] && cargo update -p backtrace --precise "0.3.67" --verbose
+
[ "$LDK_COVERAGE_BUILD" != "" ] && export RUSTFLAGS="-C link-dead-code"
export RUST_BACKTRACE=1
config.channel_config.forwarding_fee_proportional_millionths = 0;
config.channel_handshake_config.announced_channel = true;
let network = Network::Bitcoin;
+ let best_block_timestamp = genesis_block(network).header.time;
let params = ChainParameters {
network,
best_block: BestBlock::from_network(network),
};
- (ChannelManager::new($fee_estimator.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params),
+ (ChannelManager::new($fee_estimator.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params, best_block_timestamp),
monitor, keys_manager)
} }
}
config.channel_config.forwarding_fee_proportional_millionths = slice_to_be32(get_slice!(4));
config.channel_handshake_config.announced_channel = get_slice!(1)[0] != 0;
let network = Network::Bitcoin;
+ let best_block_timestamp = genesis_block(network).header.time;
let params = ChainParameters {
network,
best_block: BestBlock::from_network(network),
};
- let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params));
+ let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params, best_block_timestamp));
// Adding new calls to `EntropySource::get_secure_random_bytes` during startup can change all the
// keys subsequently generated in this test. Rather than regenerating all the messages manually,
// it's easier to just increment the counter here so the keys don't change.
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_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 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, genesis_block.header.time));
let p2p_gossip_sync = Arc::new(P2PGossipSync::new(network_graph.clone(), Some(chain_source.clone()), logger.clone()));
let rapid_gossip_sync = Arc::new(RapidGossipSync::new(network_graph.clone(), logger.clone()));
let msg_handler = MessageHandler {
} else {
None
};
+ let genesis_timestamp = bitcoin::blockdata::constants::genesis_block(bitcoin::Network::Testnet).header.time as u64;
let non_default_invoice_expiry_secs = 4200;
let invoice =
crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestLogger>(
Some(payment_amt), payment_hash, "test".to_string(), non_default_invoice_expiry_secs,
route_hints, nodes[1].keys_manager, nodes[1].keys_manager, nodes[1].logger,
- Currency::BitcoinTestnet, None, Duration::from_secs(1234567)
+ Currency::BitcoinTestnet, None, Duration::from_secs(genesis_timestamp)
).unwrap();
let (payment_hash, payment_secret) = (PaymentHash(invoice.payment_hash().into_inner()), *invoice.payment_secret());
let payment_preimage = if user_generated_pmt_hash {
let mut counterparty_htlc_base_key = RequiredWrapper(None);
let mut preimage = RequiredWrapper(None);
let mut htlc = RequiredWrapper(None);
- let mut legacy_deserialization_prevention_marker: Option<()> = None;
+ let mut _legacy_deserialization_prevention_marker: Option<()> = None;
let mut channel_type_features = None;
read_tlv_fields!(reader, {
(4, counterparty_htlc_base_key, required),
(6, preimage, required),
(8, htlc, required),
- (10, legacy_deserialization_prevention_marker, option),
+ (10, _legacy_deserialization_prevention_marker, option),
(11, channel_type_features, option),
});
let mut counterparty_delayed_payment_base_key = RequiredWrapper(None);
let mut counterparty_htlc_base_key = RequiredWrapper(None);
let mut htlc = RequiredWrapper(None);
- let mut legacy_deserialization_prevention_marker: Option<()> = None;
+ let mut _legacy_deserialization_prevention_marker: Option<()> = None;
let mut channel_type_features = None;
read_tlv_fields!(reader, {
(2, counterparty_delayed_payment_base_key, required),
(4, counterparty_htlc_base_key, required),
(6, htlc, required),
- (8, legacy_deserialization_prevention_marker, option),
+ (8, _legacy_deserialization_prevention_marker, option),
(9, channel_type_features, option),
});
let mut amount_msat = RequiredWrapper(None);
let mut cltv_expiry = RequiredWrapper(None);
let mut preimage = None;
- let mut legacy_deserialization_prevention_marker: Option<()> = None;
+ let mut _legacy_deserialization_prevention_marker: Option<()> = None;
let mut channel_type_features = None;
read_tlv_fields!(reader, {
(0, amount_msat, required),
(2, cltv_expiry, required),
(4, preimage, option),
- (6, legacy_deserialization_prevention_marker, option),
+ (6, _legacy_deserialization_prevention_marker, option),
(7, channel_type_features, option),
});
impl Readable for HolderFundingOutput {
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
let mut funding_redeemscript = RequiredWrapper(None);
- let mut legacy_deserialization_prevention_marker: Option<()> = None;
+ let mut _legacy_deserialization_prevention_marker: Option<()> = None;
let mut channel_type_features = None;
let mut funding_amount = None;
read_tlv_fields!(reader, {
(0, funding_redeemscript, required),
(1, channel_type_features, option),
- (2, legacy_deserialization_prevention_marker, option),
+ (2, _legacy_deserialization_prevention_marker, option),
(3, funding_amount, option)
});
let mut is_outbound_from_holder = RequiredWrapper(None);
let mut counterparty_parameters = None;
let mut funding_outpoint = None;
- let mut legacy_deserialization_prevention_marker: Option<()> = None;
+ let mut _legacy_deserialization_prevention_marker: Option<()> = None;
let mut channel_type_features = None;
read_tlv_fields!(reader, {
(4, is_outbound_from_holder, required),
(6, counterparty_parameters, option),
(8, funding_outpoint, option),
- (10, legacy_deserialization_prevention_marker, option),
+ (10, _legacy_deserialization_prevention_marker, option),
(11, channel_type_features, option),
});
let mut keys = RequiredWrapper(None);
let mut built = RequiredWrapper(None);
_init_tlv_field_var!(htlcs, vec_type);
- let mut legacy_deserialization_prevention_marker: Option<()> = None;
+ let mut _legacy_deserialization_prevention_marker: Option<()> = None;
let mut channel_type_features = None;
read_tlv_fields!(reader, {
(8, keys, required),
(10, built, required),
(12, htlcs, vec_type),
- (14, legacy_deserialization_prevention_marker, option),
+ (14, _legacy_deserialization_prevention_marker, option),
(15, channel_type_features, option),
});
}
}
- #[cfg(not(feature = "grind_signatures"))]
+ #[cfg(all(feature = "_test_vectors", not(feature = "grind_signatures")))]
fn public_from_secret_hex(secp_ctx: &Secp256k1<bitcoin::secp256k1::All>, hex: &str) -> PublicKey {
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(hex).unwrap()[..]).unwrap())
}
}
}
impl HTLCSource {
- #[cfg(not(feature = "grind_signatures"))]
+ #[cfg(all(feature = "_test_vectors", not(feature = "grind_signatures")))]
#[cfg(test)]
pub fn dummy() -> Self {
HTLCSource::OutboundRoute {
{
/// Constructs a new `ChannelManager` to hold several channels and route between them.
///
+ /// The current time or latest block header time can be provided as the `current_timestamp`.
+ ///
/// This is the main "logic hub" for all channel-related actions, and implements
/// [`ChannelMessageHandler`].
///
/// [`block_connected`]: chain::Listen::block_connected
/// [`block_disconnected`]: chain::Listen::block_disconnected
/// [`params.best_block.block_hash`]: chain::BestBlock::block_hash
- pub fn new(fee_est: F, chain_monitor: M, tx_broadcaster: T, router: R, logger: L, entropy_source: ES, node_signer: NS, signer_provider: SP, config: UserConfig, params: ChainParameters) -> Self {
+ pub fn new(
+ fee_est: F, chain_monitor: M, tx_broadcaster: T, router: R, logger: L, entropy_source: ES,
+ node_signer: NS, signer_provider: SP, config: UserConfig, params: ChainParameters,
+ current_timestamp: u32,
+ ) -> Self {
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
let inbound_pmt_key_material = node_signer.get_inbound_payment_key_material();
probing_cookie_secret: entropy_source.get_secure_random_bytes(),
- highest_seen_timestamp: AtomicUsize::new(0),
+ highest_seen_timestamp: AtomicUsize::new(current_timestamp as usize),
per_peer_state: FairRwLock::new(HashMap::new()),
// 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_block = bitcoin::blockdata::constants::genesis_block(network);
let tx_broadcaster = test_utils::TestBroadcaster::new(network);
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
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_network(network),
- });
+ }, genesis_block.header.time);
let node_a_holder = ANodeHolder { node: &node_a };
let logger_b = test_utils::TestLogger::with_id("node a".to_owned());
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_network(network),
- });
+ }, genesis_block.header.time);
let node_b_holder = ANodeHolder { node: &node_b };
node_a.peer_connected(&node_b.get_our_node_id(), &Init {
let mut chanmgrs = Vec::new();
for i in 0..node_count {
let network = Network::Testnet;
+ let genesis_block = bitcoin::blockdata::constants::genesis_block(network);
let params = ChainParameters {
network,
best_block: BestBlock::from_network(network),
};
let node = ChannelManager::new(cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, &cfgs[i].router, cfgs[i].logger, cfgs[i].keys_manager,
- cfgs[i].keys_manager, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { test_default_channel_config() }, params);
+ cfgs[i].keys_manager, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { test_default_channel_config() }, params, genesis_block.header.time);
chanmgrs.push(node);
}
},
#[cfg(all(not(feature = "no-std"), not(test)))]
(Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) =>
- *max_duration >= std::time::Instant::now().duration_since(*first_attempted_at),
+ *max_duration >= crate::util::time::MonotonicTime::now().duration_since(*first_attempted_at),
#[cfg(all(not(feature = "no-std"), test))]
(Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) =>
*max_duration >= SinceEpoch::now().duration_since(*first_attempted_at),
}
#[cfg(not(any(feature = "no-std", test)))]
-type ConfiguredTime = std::time::Instant;
+type ConfiguredTime = crate::util::time::MonotonicTime;
#[cfg(feature = "no-std")]
type ConfiguredTime = crate::util::time::Eternity;
#[cfg(all(not(feature = "no-std"), test))]
fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
persister = test_utils::TestPersister::new();
let keys_manager = &chanmon_cfgs[0].keys_manager;
- new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster.clone(), &logger, &fee_estimator, &persister, keys_manager);
+ new_chain_monitor = test_utils::TestChainMonitor::new(Some(nodes[0].chain_source), nodes[0].tx_broadcaster, &logger, &fee_estimator, &persister, keys_manager);
nodes[0].chain_monitor = &new_chain_monitor;
let blinded_tails = blinded_tails.unwrap_or(Vec::new());
if blinded_tails.len() != 0 {
if blinded_tails.len() != paths.len() { return Err(DecodeError::InvalidValue) }
- for (mut path, blinded_tail_opt) in paths.iter_mut().zip(blinded_tails.into_iter()) {
+ for (path, blinded_tail_opt) in paths.iter_mut().zip(blinded_tails.into_iter()) {
path.blinded_tail = blinded_tail_opt;
}
}
cur_hop_fees_msat = self.hops.get(i + 1).unwrap().0.hop_use_fee_msat;
}
- let mut cur_hop = &mut self.hops.get_mut(i).unwrap().0;
+ let cur_hop = &mut self.hops.get_mut(i).unwrap().0;
cur_hop.next_hops_fee_msat = total_fee_paid_msat;
// Overpay in fees if we can't save these funds due to htlc_minimum_msat.
// We try to account for htlc_minimum_msat in scoring (add_entry!), so that nodes don't
}
#[cfg(not(feature = "no-std"))]
-type ConfiguredTime = std::time::Instant;
+type ConfiguredTime = crate::util::time::MonotonicTime;
#[cfg(feature = "no-std")]
use crate::util::time::Eternity;
#[cfg(feature = "no-std")]
}
}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[cfg(not(feature = "no-std"))]
+pub struct MonotonicTime(std::time::Instant);
+
+/// The amount of time to shift `Instant` forward to prevent overflow when subtracting a `Duration`
+/// from `Instant::now` on some operating systems (e.g., iOS representing `Instance` as `u64`).
+#[cfg(not(feature = "no-std"))]
+const SHIFT: Duration = Duration::from_secs(10 * 365 * 24 * 60 * 60); // 10 years.
+
#[cfg(not(feature = "no-std"))]
-impl Time for std::time::Instant {
+impl Time for MonotonicTime {
fn now() -> Self {
- std::time::Instant::now()
+ let instant = std::time::Instant::now().checked_add(SHIFT).expect("Overflow on MonotonicTime instantiation");
+ Self(instant)
}
fn duration_since(&self, earlier: Self) -> Duration {
// clocks" that go backwards in practice (likely relatively ancient kernels/etc). Thus, we
// manually check for time going backwards here and return a duration of zero in that case.
let now = Self::now();
- if now > earlier { now - earlier } else { Duration::from_secs(0) }
+ if now.0 > earlier.0 { now.0 - earlier.0 } else { Duration::from_secs(0) }
}
fn duration_since_epoch() -> Duration {
use std::time::SystemTime;
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
}
+
fn elapsed(&self) -> Duration {
- std::time::Instant::elapsed(self)
+ Self::now().0 - self.0
+ }
+}
+
+#[cfg(not(feature = "no-std"))]
+impl Sub<Duration> for MonotonicTime {
+ type Output = Self;
+
+ fn sub(self, other: Duration) -> Self {
+ let instant = self.0.checked_sub(other).expect("MonotonicTime is not supposed to go backward futher than 10 years");
+ Self(instant)
}
}
assert_eq!(now.elapsed(), Duration::from_secs(0));
assert_eq!(later - elapsed, now);
}
+
+ #[test]
+ #[cfg(not(feature = "no-std"))]
+ fn monotonic_time_subtracts() {
+ let now = super::MonotonicTime::now();
+ assert!(now.elapsed() < Duration::from_secs(10));
+
+ let ten_years = Duration::from_secs(10 * 365 * 24 * 60 * 60);
+ let past = now - ten_years;
+ assert!(past.elapsed() >= ten_years);
+ }
}