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
18 changes: 18 additions & 0 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ use lightning::ln::peer_handler::{
};
use lightning::ln::script::ShutdownScript;
use lightning::ln::types::ChannelId;
use lightning::offers::currency::CurrencyConversion;
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::offer::CurrencyCode;
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
use lightning::routing::router::{
Expand Down Expand Up @@ -184,6 +186,18 @@ impl MessageRouter for FuzzRouter {
}
}

struct FuzzCurrencyConversion;

impl CurrencyConversion for FuzzCurrencyConversion {
fn msats_per_minor_unit(&self, _iso4217_code: CurrencyCode) -> Result<u64, ()> {
Err(())
}

fn tolerance_percent(&self) -> u8 {
0
}
}

struct TestBroadcaster {
txn_broadcasted: Mutex<Vec<Transaction>>,
}
Expand Down Expand Up @@ -239,6 +253,7 @@ type ChannelMan<'a> = ChannelManager<
Arc<FuzzEstimator>,
&'a FuzzRouter,
&'a FuzzRouter,
&'a FuzzCurrencyConversion,
Arc<dyn Logger + MaybeSend + MaybeSync>,
>;
type PeerMan<'a> = PeerManager<
Expand Down Expand Up @@ -551,6 +566,8 @@ pub fn do_test(mut data: &[u8], logger: &Arc<dyn Logger + MaybeSend + MaybeSync>
let fee_est = Arc::new(FuzzEstimator { input: input.clone() });
let router = FuzzRouter {};

let conversion = FuzzCurrencyConversion;

macro_rules! get_slice {
($len: expr) => {
match input.get_slice($len as usize) {
Expand Down Expand Up @@ -614,6 +631,7 @@ pub fn do_test(mut data: &[u8], logger: &Arc<dyn Logger + MaybeSend + MaybeSync>
broadcast.clone(),
&router,
&router,
&conversion,
Arc::clone(&logger),
keys_manager.clone(),
keys_manager.clone(),
Expand Down
15 changes: 14 additions & 1 deletion fuzz/src/invoice_request_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ use lightning::blinded_path::payment::{
};
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
use lightning::ln::inbound_payment::ExpandedKey;
use lightning::offers::currency::CurrencyConversion;
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
use lightning::offers::offer::OfferId;
use lightning::offers::offer::{CurrencyCode, OfferId};
use lightning::offers::parse::Bolt12SemanticError;
use lightning::sign::{EntropySource, ReceiveAuthKey};
use lightning::types::features::BlindedHopFeatures;
Expand Down Expand Up @@ -61,6 +62,18 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
}
}

struct FuzzCurrencyConversion;

impl CurrencyConversion for FuzzCurrencyConversion {
fn msats_per_minor_unit(&self, _iso4217_code: CurrencyCode) -> Result<u64, ()> {
unreachable!()
}

fn tolerance_percent(&self) -> u8 {
unreachable!()
}
}

struct Randomness;

impl EntropySource for Randomness {
Expand Down
7 changes: 4 additions & 3 deletions fuzz/src/offer_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ use bitcoin::secp256k1::Secp256k1;
use core::convert::TryFrom;
use lightning::ln::channelmanager::PaymentId;
use lightning::ln::inbound_payment::ExpandedKey;
use lightning::offers::currency::DefaultCurrencyConversion;
use lightning::offers::invoice_request::InvoiceRequest;
use lightning::offers::nonce::Nonce;
use lightning::offers::offer::{Amount, Offer, Quantity};
use lightning::offers::offer::{Offer, Quantity};
use lightning::offers::parse::Bolt12SemanticError;
use lightning::sign::EntropySource;
use lightning::util::ser::Writeable;
Expand Down Expand Up @@ -48,13 +49,13 @@ fn build_request(offer: &Offer) -> Result<InvoiceRequest, Bolt12SemanticError> {
let nonce = Nonce::from_entropy_source(&entropy);
let secp_ctx = Secp256k1::new();
let payment_id = PaymentId([1; 32]);
let conversion = DefaultCurrencyConversion;

let mut builder = offer.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)?;

builder = match offer.amount() {
None => builder.amount_msats(1000).unwrap(),
Some(Amount::Bitcoin { amount_msats }) => builder.amount_msats(amount_msats + 1)?,
Some(Amount::Currency { .. }) => return Err(Bolt12SemanticError::UnsupportedCurrency),
Some(amount) => builder.amount_msats(amount.into_msats(&conversion)?)?,
Comment on lines +52 to +58
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use a conversion that can actually resolve fiat amounts in this fuzzer.

DefaultCurrencyConversion rejects every fiat code, so amount.into_msats(&conversion)? still bails out on all Amount::Currency inputs. That means fiat-denominated offers never reach invoice-request serialization in this target, which leaves the new currency-aware path effectively unfuzzed here. A small fuzz-local conversion implementation would keep those cases in scope.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@fuzz/src/offer_deser.rs` around lines 52 - 58, The fuzzer uses
DefaultCurrencyConversion which rejects all fiat codes, so replace it with a
fuzz-local conversion that resolves fiat amounts (e.g., implement a
SimpleFuzzCurrencyConversion used in this file) and instantiate that instead of
DefaultCurrencyConversion; ensure the new type implements the same trait/trait
methods used by amount.into_msats(&conversion) (accept common ISO codes or
return a deterministic fixed-rate conversion) so Amount::Currency paths succeed
and reach offer.request_invoice/amount.into_msats rather than early-returning.

};

builder = match offer.supported_quantity() {
Expand Down
8 changes: 8 additions & 0 deletions lightning-background-processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,9 @@ type DynMessageRouter = lightning::onion_message::messenger::DefaultMessageRoute
&'static (dyn EntropySource + Send + Sync),
>;

#[cfg(not(c_bindings))]
type DynCurrencyConversion = lightning::offers::currency::DefaultCurrencyConversion;

#[cfg(all(not(c_bindings), not(taproot)))]
type DynSignerProvider = dyn lightning::sign::SignerProvider<EcdsaSigner = lightning::sign::InMemorySigner>
+ Send
Expand All @@ -400,6 +403,7 @@ type DynChannelManager = lightning::ln::channelmanager::ChannelManager<
&'static (dyn FeeEstimator + Send + Sync),
&'static DynRouter,
&'static DynMessageRouter,
&'static DynCurrencyConversion,
&'static (dyn Logger + Send + Sync),
>;

Expand Down Expand Up @@ -1910,6 +1914,7 @@ mod tests {
IgnoringMessageHandler, MessageHandler, PeerManager, SocketDescriptor,
};
use lightning::ln::types::ChannelId;
use lightning::offers::currency::DefaultCurrencyConversion;
use lightning::onion_message::messenger::{DefaultMessageRouter, OnionMessenger};
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
use lightning::routing::router::{CandidateRouteHop, DefaultRouter, Path, RouteHop};
Expand Down Expand Up @@ -2005,6 +2010,7 @@ mod tests {
Arc<KeysManager>,
>,
>,
Arc<DefaultCurrencyConversion>,
Arc<test_utils::TestLogger>,
>;

Expand Down Expand Up @@ -2430,6 +2436,7 @@ mod tests {
Arc::clone(&network_graph),
Arc::clone(&keys_manager),
));
let conversion = Arc::new(DefaultCurrencyConversion);
let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Bitcoin));
let kv_store =
Arc::new(Persister::new(format!("{}_persister_{}", &persist_dir, i).into()));
Expand All @@ -2455,6 +2462,7 @@ mod tests {
Arc::clone(&tx_broadcaster),
Arc::clone(&router),
Arc::clone(&msg_router),
Arc::clone(&conversion),
Arc::clone(&logger),
Arc::clone(&keys_manager),
Arc::clone(&keys_manager),
Expand Down
6 changes: 5 additions & 1 deletion lightning-block-sync/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ where
/// use lightning::chain::chaininterface::BroadcasterInterface;
/// use lightning::chain::chaininterface::FeeEstimator;
/// use lightning::ln::channelmanager::{ChannelManager, ChannelManagerReadArgs};
/// use lightning::offers::currency::CurrencyConversion;
/// use lightning::onion_message::messenger::MessageRouter;
/// use lightning::routing::router::Router;
/// use lightning::sign;
Expand All @@ -72,6 +73,7 @@ where
/// F: FeeEstimator,
/// R: Router,
/// MR: MessageRouter,
/// CC: CurrencyConversion,
/// L: Logger,
/// C: chain::Filter,
/// P: chainmonitor::Persist<SP::EcdsaSigner>,
Expand All @@ -86,6 +88,7 @@ where
/// fee_estimator: &F,
/// router: &R,
/// message_router: &MR,
/// currency_conversion: &CC,
/// logger: &L,
/// persister: &P,
/// ) {
Expand All @@ -106,11 +109,12 @@ where
/// tx_broadcaster,
/// router,
/// message_router,
/// currency_conversion,
/// logger,
/// config,
/// vec![&mut monitor],
/// );
/// <(BlockHash, ChannelManager<&ChainMonitor<SP::EcdsaSigner, &C, &T, &F, &L, &P, &ES>, &T, &ES, &NS, &SP, &F, &R, &MR, &L>)>::read(
/// <(BlockHash, ChannelManager<&ChainMonitor<SP::EcdsaSigner, &C, &T, &F, &L, &P, &ES>, &T, &ES, &NS, &SP, &F, &R, &MR, &CC, &L>)>::read(
/// &mut Cursor::new(&serialized_manager), read_args).unwrap()
/// };
///
Expand Down
2 changes: 1 addition & 1 deletion lightning-dns-resolver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ mod test {

let name = HumanReadableName::from_encoded("matt@mattcorallo.com").unwrap();

let bs_offer = nodes[1].node.create_offer_builder().unwrap().build().unwrap();
let bs_offer = nodes[1].node.create_offer_builder().unwrap().build();
let resolvers = vec![Destination::Node(resolver_id)];

pay_offer_flow(
Expand Down
10 changes: 7 additions & 3 deletions lightning/src/ln/async_payments_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ use crate::types::features::Bolt12InvoiceFeatures;
use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
use crate::util::config::{HTLCInterceptionFlags, UserConfig};
use crate::util::ser::Writeable;
use crate::util::test_utils::TestCurrencyConversion;
use bitcoin::constants::ChainHash;
use bitcoin::network::Network;
use bitcoin::secp256k1;
Expand Down Expand Up @@ -324,7 +325,7 @@ fn create_static_invoice<T: secp256k1::Signing + secp256k1::Verification>(
.flow
.create_async_receive_offer_builder(entropy_source, blinded_paths_to_always_online_node)
.unwrap();
let offer = offer_builder.build().unwrap();
let offer = offer_builder.build();
let static_invoice =
create_static_invoice_builder(recipient, &offer, offer_nonce, relative_expiry)
.build_and_sign(&secp_ctx)
Expand Down Expand Up @@ -692,7 +693,7 @@ fn static_invoice_unknown_required_features() {
.flow
.create_async_receive_offer_builder(entropy_source, blinded_paths_to_always_online_node)
.unwrap();
let offer = offer_builder.build().unwrap();
let offer = offer_builder.build();
let static_invoice_unknown_req_features =
create_static_invoice_builder(&nodes[2], &offer, nonce, None)
.features_unchecked(Bolt12InvoiceFeatures::unknown())
Expand Down Expand Up @@ -1448,6 +1449,8 @@ fn amount_doesnt_match_invreq() {

let amt_msat = 5000;
let payment_id = PaymentId([1; 32]);
let conversion = TestCurrencyConversion;

nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
let release_held_htlc_om_3_0 = pass_async_payments_oms(
static_invoice,
Expand All @@ -1471,6 +1474,7 @@ fn amount_doesnt_match_invreq() {
Nonce::from_entropy_source(nodes[0].keys_manager),
&secp_ctx,
payment_id,
&conversion,
)
.unwrap()
.amount_msats(amt_msat + 1)
Expand Down Expand Up @@ -1672,7 +1676,7 @@ fn invalid_async_receive_with_retry<F1, F2>(
.flow
.create_async_receive_offer_builder(entropy_source, blinded_paths_to_always_online_node)
.unwrap();
let offer = offer_builder.build().unwrap();
let offer = offer_builder.build();
let amt_msat = 5000;
let payment_id = PaymentId([1; 32]);

Expand Down
Loading
Loading