Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16717,10 +16717,10 @@ impl<'a, 'b, 'c, ES: EntropySource, SP: SignerProvider>
}

fn duration_since_epoch() -> Option<Duration> {
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let now = None;

#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let now = Some(
std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
Expand Down
12 changes: 6 additions & 6 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8936,11 +8936,11 @@ impl<
let _ = self.handle_error(err, counterparty_node_id);
}

#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let duration_since_epoch = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let duration_since_epoch = Duration::from_secs(
self.highest_seen_timestamp.load(Ordering::Acquire).saturating_sub(7200) as u64,
);
Expand Down Expand Up @@ -14129,7 +14129,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
let currency =
Network::from_chain_hash(self.chain_hash).map(Into::into).unwrap_or(Currency::Bitcoin);

#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let duration_since_epoch = {
use std::time::SystemTime;
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
Expand All @@ -14139,7 +14139,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
// This may be up to 2 hours in the future because of bitcoin's block time rule or about
// 10-30 minutes in the past if a block hasn't been found recently. This should be fine as
// the default invoice expiration is 2 hours, though shorter expirations may be problematic.
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let duration_since_epoch =
Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);

Expand Down Expand Up @@ -14996,9 +14996,9 @@ impl<
}

pub(super) fn duration_since_epoch(&self) -> Duration {
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let now = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let now = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
Expand Down
20 changes: 14 additions & 6 deletions lightning/src/ln/outbound_payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,14 +446,16 @@ impl Retry {
(Retry::Attempts(max_retry_count), PaymentAttempts { count, .. }) => {
max_retry_count > count
},
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
(Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) =>
*max_duration >= Instant::now().duration_since(*first_attempted_at),
#[cfg(all(feature = "std", fuzzing))]
(Retry::Timeout(_), _) => true,
Comment on lines +452 to +453
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug (latent): Under std + fuzzing, Retry::Timeout is always retryable. But OptionalBolt11PaymentParams::default() and OptionalOfferPaymentParams::default() (channelmanager.rs lines ~709 and ~747) still use Retry::Timeout(2s) when std is enabled — they aren't gated on not(fuzzing).

This means any code path that uses the default retry strategy during fuzzing will retry payments indefinitely (never hitting RetriesExhausted). Current fuzz targets explicitly use Retry::Attempts(2) so they're unaffected, but this is a footgun for future fuzz targets.

Consider updating those defaults to also use Retry::Attempts(3) under fuzzing:

#[cfg(all(feature = "std", not(fuzzing)))]
retry_strategy: Retry::Timeout(core::time::Duration::from_secs(2)),
#[cfg(any(not(feature = "std"), fuzzing))]
retry_strategy: Retry::Attempts(3),

}
}
}

#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
#[rustfmt::skip]
pub(super) fn has_expired(route_params: &RouteParameters) -> bool {
if let Some(expiry_time) = route_params.payment_params.expiry_time {
Expand All @@ -464,32 +466,38 @@ pub(super) fn has_expired(route_params: &RouteParameters) -> bool {
false
}

#[cfg(all(feature = "std", fuzzing))]
#[rustfmt::skip]
pub(super) fn has_expired(_route_params: &RouteParameters) -> bool {
false
}

/// Storing minimal payment attempts information required for determining if a outbound payment can
/// be retried.
pub(crate) struct PaymentAttempts {
/// This count will be incremented only after the result of the attempt is known. When it's 0,
/// it means the result of the first attempt is not known yet.
pub(crate) count: u32,
/// This field is only used when retry is `Retry::Timeout` which is only build with feature std
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
first_attempted_at: Instant,
}

impl PaymentAttempts {
pub(crate) fn new() -> Self {
PaymentAttempts {
count: 0,
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
first_attempted_at: Instant::now(),
}
}
}

impl Display for PaymentAttempts {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
return write!(f, "attempts: {}", self.count);
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
return write!(
f,
"attempts: {}, duration: {}s",
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/peer_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2327,7 +2327,7 @@ impl<

#[allow(unused_mut)]
let mut should_do_full_sync = true;
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
{
// Forward ad-hoc gossip if the timestamp range is less than six hours ago.
// Otherwise, do a full sync.
Expand Down
18 changes: 9 additions & 9 deletions lightning/src/offers/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ impl<MR: MessageRouter, L: Logger> OffersMessageFlow<MR, L> {
}

fn duration_since_epoch(&self) -> Duration {
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let now = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let now = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
Expand Down Expand Up @@ -942,17 +942,17 @@ impl<MR: MessageRouter, L: Logger> OffersMessageFlow<MR, L> {
)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let builder = refund.respond_using_derived_keys(
payment_paths,
payment_hash,
expanded_key,
entropy,
)?;

#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let created_at = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let builder = refund.respond_using_derived_keys_no_std(
payment_paths,
payment_hash,
Expand Down Expand Up @@ -1008,9 +1008,9 @@ impl<MR: MessageRouter, L: Logger> OffersMessageFlow<MR, L> {
)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let builder = invoice_request.respond_using_derived_keys(payment_paths, payment_hash);
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let builder = invoice_request.respond_using_derived_keys_no_std(
payment_paths,
payment_hash,
Expand Down Expand Up @@ -1067,9 +1067,9 @@ impl<MR: MessageRouter, L: Logger> OffersMessageFlow<MR, L> {
)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let builder = invoice_request.respond_with(payment_paths, payment_hash);
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let builder = invoice_request.respond_with_no_std(
payment_paths,
payment_hash,
Expand Down
5 changes: 3 additions & 2 deletions lightning/src/onion_message/dns_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ impl OMNameResolver {
if let Ok(validated_rrs) = validated_rrs {
#[allow(unused_assignments, unused_mut)]
let mut time = self.latest_block_time.load(Ordering::Acquire) as u64;
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
{
use std::time::{SystemTime, UNIX_EPOCH};
let now = SystemTime::now().duration_since(UNIX_EPOCH);
Expand All @@ -512,7 +512,8 @@ impl OMNameResolver {
// (we assume no more than two hours, though the actual limits are rather
// complicated).
// Thus, we have to let the proof times be rather fuzzy.
let max_time_offset = if cfg!(feature = "std") { 0 } else { 60 * 2 };
let max_time_offset =
if cfg!(all(feature = "std", not(fuzzing))) { 0 } else { 60 * 2 };
if validated_rrs.valid_from > time + max_time_offset {
return None;
}
Expand Down
18 changes: 9 additions & 9 deletions lightning/src/routing/gossip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, U: UtxoLookup, L: Logger> BaseMessageHa
let mut gossip_start_time = 0;
#[allow(unused)]
let should_sync = self.should_request_full_sync();
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
{
gossip_start_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
Expand Down Expand Up @@ -2195,7 +2195,7 @@ impl<L: Logger> NetworkGraph<L> {

#[allow(unused_mut, unused_assignments)]
let mut announcement_received_time = 0;
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
{
announcement_received_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
Expand Down Expand Up @@ -2235,11 +2235,11 @@ impl<L: Logger> NetworkGraph<L> {
///
/// The channel and any node for which this was their last channel are removed from the graph.
pub fn channel_failed_permanent(&self, short_channel_id: u64) {
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let current_time_unix = Some(
SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs(),
);
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let current_time_unix = None;

self.channel_failed_permanent_with_time(short_channel_id, current_time_unix)
Expand All @@ -2262,11 +2262,11 @@ impl<L: Logger> NetworkGraph<L> {
/// Marks a node in the graph as permanently failed, effectively removing it and its channels
/// from local storage.
pub fn node_failed_permanent(&self, node_id: &PublicKey) {
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(fuzzing)))]
let current_time_unix = Some(
SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs(),
);
#[cfg(not(feature = "std"))]
#[cfg(any(not(feature = "std"), fuzzing))]
let current_time_unix = None;

let node_id = NodeId::from_pubkey(node_id);
Expand Down Expand Up @@ -2303,7 +2303,6 @@ impl<L: Logger> NetworkGraph<L> {
}
}

#[cfg(feature = "std")]
/// Removes information about channels that we haven't heard any updates about in some time.
/// This can be used regularly to prune the network graph of channels that likely no longer
/// exist.
Expand All @@ -2318,8 +2317,9 @@ impl<L: Logger> NetworkGraph<L> {
/// This method will also cause us to stop tracking removed nodes and channels if they have been
/// in the map for a while so that these can be resynced from gossip in the future.
///
/// This method is only available with the `std` feature. See
/// This method is only available with the `std` feature (and not during fuzzing). See
/// [`NetworkGraph::remove_stale_channels_and_tracking_with_time`] for non-`std` use.
#[cfg(all(feature = "std", not(fuzzing)))]
pub fn remove_stale_channels_and_tracking(&self) {
let time =
SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs();
Expand Down Expand Up @@ -2476,7 +2476,7 @@ impl<L: Logger> NetworkGraph<L> {
});
}

#[cfg(all(feature = "std", not(test), not(feature = "_test_utils")))]
#[cfg(all(feature = "std", not(test), not(feature = "_test_utils"), not(fuzzing)))]
{
// Note that many tests rely on being able to set arbitrarily old timestamps, thus we
// disable this check during tests!
Expand Down
9 changes: 6 additions & 3 deletions lightning/src/util/hash_tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
pub use hashbrown::hash_map;

mod hashbrown_tables {
#[cfg(all(feature = "std", not(test)))]
#[cfg(all(feature = "std", not(test), not(fuzzing)))]
mod hasher {
pub use std::collections::hash_map::RandomState;
}
#[cfg(all(feature = "std", test))]
#[cfg(all(feature = "std", any(test, fuzzing)))]
mod hasher {
#![allow(deprecated)] // hash::SipHasher was deprecated in favor of something only in std.
use core::hash::{BuildHasher, Hasher};
Expand All @@ -27,7 +27,10 @@ mod hashbrown_tables {

impl RandomState {
pub fn new() -> RandomState {
if std::env::var("LDK_TEST_DETERMINISTIC_HASHES").map(|v| v == "1").unwrap_or(false)
if cfg!(fuzzing)
|| std::env::var("LDK_TEST_DETERMINISTIC_HASHES")
.map(|v| v == "1")
.unwrap_or(false)
{
RandomState::Deterministic
} else {
Expand Down
Loading