]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Add BOLT 12 sends to `full_stack_target` fuzzer
authorMatt Corallo <git@bluematt.me>
Tue, 30 Jul 2024 16:20:31 +0000 (16:20 +0000)
committerMatt Corallo <git@bluematt.me>
Mon, 4 Nov 2024 15:49:22 +0000 (15:49 +0000)
fuzz/src/full_stack.rs

index 59f1275a600d40d4f9e700af200652e4c71f29fc..be40af501d65d1756d277c8f366b4548b8ab180f 100644 (file)
@@ -49,9 +49,11 @@ use lightning::ln::peer_handler::{
 };
 use lightning::ln::script::ShutdownScript;
 use lightning::ln::types::ChannelId;
-use lightning::offers::invoice::UnsignedBolt12Invoice;
-use lightning::offers::invoice_request::UnsignedInvoiceRequest;
+use lightning::offers::invoice::{Bolt12Invoice, UnsignedBolt12Invoice};
+use lightning::offers::invoice_request::{InvoiceRequest, UnsignedInvoiceRequest};
+use lightning::offers::offer::{self, Offer};
 use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
+use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler};
 use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
 use lightning::routing::router::{
        InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router,
@@ -148,7 +150,7 @@ impl FeeEstimator for FuzzEstimator {
        }
 }
 
-struct FuzzRouter {}
+struct FuzzRouter(Arc<KeyProvider>);
 
 impl Router for FuzzRouter {
        fn find_route(
@@ -177,10 +179,12 @@ impl MessageRouter for FuzzRouter {
        }
 
        fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
-               &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
-               _secp_ctx: &Secp256k1<T>,
+               &self, recipient: PublicKey, ctx: MessageContext, _peers: Vec<PublicKey>,
+               secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedMessagePath>, ()> {
-               unreachable!()
+               let es = &*self.0;
+               let path = BlindedMessagePath::one_hop(recipient, ctx, es, secp_ctx).unwrap();
+               Ok(vec![path])
        }
 }
 
@@ -596,7 +600,6 @@ pub fn do_test(mut data: &[u8], logger: &Arc<dyn Logger>) {
                halt_fee_est_reads: AtomicBool::new(false),
        });
        let fee_est = Arc::new(FuzzEstimator { input: input.clone() });
-       let router = FuzzRouter {};
 
        macro_rules! get_slice {
                ($len: expr) => {
@@ -647,6 +650,7 @@ pub fn do_test(mut data: &[u8], logger: &Arc<dyn Logger>) {
                counter: AtomicU64::new(0),
                signer_state: RefCell::new(new_hash_map()),
        });
+       let router = FuzzRouter(Arc::clone(&keys_manager));
        let network = Network::Bitcoin;
        let best_block_timestamp = genesis_block(network).header.time;
        let params = ChainParameters { network, best_block: BestBlock::from_network(network) };
@@ -1039,6 +1043,60 @@ pub fn do_test(mut data: &[u8], logger: &Arc<dyn Logger>) {
                                        );
                                }
                        },
+                       0x30 => {
+                               let offer_len = u16::from_be_bytes(get_bytes!(2));
+                               let offer_opt = input
+                                       .get_slice(offer_len as usize)
+                                       .and_then(|slice| Offer::try_from(slice.to_vec()).ok());
+                               let offer = if let Some(offer) = offer_opt { offer } else { return };
+                               let quantity = if offer.expects_quantity() { Some(1) } else { None };
+                               let amount = if let Some(amt) = offer.amount() {
+                                       match amt {
+                                               offer::Amount::Bitcoin { amount_msats } => Some(amount_msats),
+                                               offer::Amount::Currency { .. } => Some(1_000),
+                                       }
+                               } else {
+                                       Some(1_000)
+                               };
+                               let idx = (get_bytes!(1)[0] as u16) % cmp::max(payments_sent, 1);
+                               let mut payment_id = PaymentId([0; 32]);
+                               payment_id.0[0..2].copy_from_slice(&idx.to_be_bytes());
+                               let _ = channelmanager.pay_for_offer(
+                                       &offer,
+                                       quantity,
+                                       amount,
+                                       None,
+                                       payment_id,
+                                       Retry::Attempts(2),
+                                       Some(100),
+                               );
+                       },
+                       0x31 => {
+                               let inv_len = u16::from_be_bytes(get_bytes!(2));
+                               let inv_opt = input
+                                       .get_slice((inv_len & 0x7fff) as usize)
+                                       .and_then(|slice| Bolt12Invoice::try_from(slice.to_vec()).ok());
+                               let inv = if let Some(inv) = inv_opt { inv } else { return };
+                               let context = if let Ok(c) = Readable::read(&mut &*input) { c } else { return };
+                               if inv_len & 0x8000 != 0 {
+                                       let _ = channelmanager.send_payment_for_bolt12_invoice(&inv, Some(&context));
+                               } else {
+                                       let msg = OffersMessage::Invoice(inv);
+                                       let _ = channelmanager.handle_message(msg, Some(context), None);
+                               }
+                       },
+                       0x32 => {
+                               let invreq_len = u16::from_be_bytes(get_bytes!(2));
+                               let invreq_opt = input
+                                       .get_slice(invreq_len as usize)
+                                       .and_then(|slice| InvoiceRequest::try_from(slice.to_vec()).ok());
+                               let invreq = if let Some(invreq) = invreq_opt { invreq } else { return };
+                               let context = if let Ok(c) = Readable::read(&mut &*input) { c } else { return };
+                               let response_path =
+                                       if let Ok(p) = Readable::read(&mut &*input) { Some(p) } else { return };
+                               let msg = OffersMessage::InvoiceRequest(invreq);
+                               let _ = channelmanager.handle_message(msg, context, response_path);
+                       },
                        _ => return,
                }
                loss_detector.handler.process_events();