X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fmain.rs;h=73a6ddf3356e7d2aabfa9c32ea9debfbef379250;hb=b61dae03855accbafcbbc68c69692cbe1797b195;hp=69f0981ca4091403f827f5861258166a2087c5ce;hpb=da2cd163e859532afedf32719ae7e19ae852680d;p=ldk-sample diff --git a/src/main.rs b/src/main.rs index 69f0981..73a6ddf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,19 +20,19 @@ use lightning::events::bump_transaction::{BumpTransactionEventHandler, Wallet}; use lightning::events::{Event, PaymentFailureReason, PaymentPurpose}; use lightning::ln::channelmanager::{self, RecentPaymentDetails}; use lightning::ln::channelmanager::{ - ChainParameters, ChannelManagerReadArgs, SimpleArcChannelManager, + ChainParameters, ChannelManagerReadArgs, PaymentId, SimpleArcChannelManager, }; use lightning::ln::msgs::DecodeError; use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler, SimpleArcPeerManager}; use lightning::ln::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret}; -use lightning::onion_message::{DefaultMessageRouter, SimpleArcOnionMessenger}; +use lightning::onion_message::messenger::{DefaultMessageRouter, SimpleArcOnionMessenger}; use lightning::routing::gossip; use lightning::routing::gossip::{NodeId, P2PGossipSync}; use lightning::routing::router::DefaultRouter; use lightning::routing::scoring::ProbabilisticScoringFeeParameters; use lightning::sign::{EntropySource, InMemorySigner, KeysManager, SpendableOutputDescriptor}; use lightning::util::config::UserConfig; -use lightning::util::persist::{self, read_channel_monitors, KVStore}; +use lightning::util::persist::{self, KVStore, MonitorUpdatingPersister}; use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer}; use lightning::{chain, impl_writeable_tlv_based, impl_writeable_tlv_based_enum}; use lightning_background_processor::{process_events_async, GossipSync}; @@ -109,11 +109,19 @@ impl_writeable_tlv_based!(PaymentInfo, { (6, amt_msat, required), }); -pub(crate) struct PaymentInfoStorage { +pub(crate) struct InboundPaymentInfoStorage { payments: HashMap, } -impl_writeable_tlv_based!(PaymentInfoStorage, { +impl_writeable_tlv_based!(InboundPaymentInfoStorage, { + (0, payments, required), +}); + +pub(crate) struct OutboundPaymentInfoStorage { + payments: HashMap, +} + +impl_writeable_tlv_based!(OutboundPaymentInfoStorage, { (0, payments, required), }); @@ -123,7 +131,20 @@ type ChainMonitor = chainmonitor::ChainMonitor< Arc, Arc, Arc, - Arc, + Arc< + MonitorUpdatingPersister< + Arc, + Arc, + Arc, + Arc, + >, + >, +>; + +pub(crate) type GossipVerifier = lightning_block_sync::gossip::GossipVerifier< + lightning_block_sync::gossip::TokioSpawner, + Arc, + Arc, >; pub(crate) type PeerManager = SimpleArcPeerManager< @@ -131,7 +152,7 @@ pub(crate) type PeerManager = SimpleArcPeerManager< ChainMonitor, BitcoindClient, BitcoindClient, - Arc, + GossipVerifier, FilesystemLogger, >; @@ -140,7 +161,8 @@ pub(crate) type ChannelManager = pub(crate) type NetworkGraph = gossip::NetworkGraph>; -type OnionMessenger = SimpleArcOnionMessenger; +type OnionMessenger = + SimpleArcOnionMessenger; pub(crate) type BumpTxEventHandler = BumpTransactionEventHandler< Arc, @@ -152,8 +174,9 @@ pub(crate) type BumpTxEventHandler = BumpTransactionEventHandler< async fn handle_ldk_events( channel_manager: &Arc, bitcoind_client: &BitcoindClient, network_graph: &NetworkGraph, keys_manager: &KeysManager, - bump_tx_event_handler: &BumpTxEventHandler, inbound_payments: Arc>, - outbound_payments: Arc>, persister: &Arc, + bump_tx_event_handler: &BumpTxEventHandler, + inbound_payments: Arc>, + outbound_payments: Arc>, fs_store: &Arc, network: Network, event: Event, ) { match event { @@ -167,12 +190,12 @@ async fn handle_ldk_events( // Construct the raw transaction with one output, that is paid the amount of the // channel. let addr = WitnessProgram::from_scriptpubkey( - &output_script[..], + &output_script.as_bytes(), match network { Network::Bitcoin => bitcoin_bech32::constants::Network::Bitcoin, - Network::Testnet => bitcoin_bech32::constants::Network::Testnet, Network::Regtest => bitcoin_bech32::constants::Network::Regtest, Network::Signet => bitcoin_bech32::constants::Network::Signet, + Network::Testnet | _ => bitcoin_bech32::constants::Network::Testnet, }, ) .expect("Lightning funding tx should always be to a SegWit output") @@ -185,7 +208,7 @@ async fn handle_ldk_events( // satisfied. let funded_tx = bitcoind_client.fund_raw_transaction(raw_tx).await; - // Sign the final funding transaction and broadcast it. + // Sign the final funding transaction and give it to LDK, who will eventually broadcast it. let signed_tx = bitcoind_client.sign_raw_transaction_with_wallet(funded_tx.hex).await; assert_eq!(signed_tx.complete, true); let final_tx: Transaction = @@ -218,8 +241,7 @@ async fn handle_ldk_events( } => { println!( "\nEVENT: received payment from payment hash {} of {} millisatoshis", - hex_utils::hex_str(&payment_hash.0), - amount_msat, + payment_hash, amount_msat, ); print!("> "); io::stdout().flush().unwrap(); @@ -239,8 +261,7 @@ async fn handle_ldk_events( } => { println!( "\nEVENT: claimed payment from payment hash {} of {} millisatoshis", - hex_utils::hex_str(&payment_hash.0), - amount_msat, + payment_hash, amount_msat, ); print!("> "); io::stdout().flush().unwrap(); @@ -267,31 +288,33 @@ async fn handle_ldk_events( }); } } - persister.write("", "", INBOUND_PAYMENTS_FNAME, &inbound.encode()).unwrap(); + fs_store.write("", "", INBOUND_PAYMENTS_FNAME, &inbound.encode()).unwrap(); } - Event::PaymentSent { payment_preimage, payment_hash, fee_paid_msat, .. } => { + Event::PaymentSent { + payment_preimage, payment_hash, fee_paid_msat, payment_id, .. + } => { let mut outbound = outbound_payments.lock().unwrap(); - for (hash, payment) in outbound.payments.iter_mut() { - if *hash == payment_hash { + for (id, payment) in outbound.payments.iter_mut() { + if *id == payment_id.unwrap() { payment.preimage = Some(payment_preimage); payment.status = HTLCStatus::Succeeded; println!( "\nEVENT: successfully sent payment of {} millisatoshis{} from \ - payment hash {:?} with preimage {:?}", + payment hash {} with preimage {}", payment.amt_msat, if let Some(fee) = fee_paid_msat { format!(" (fee {} msat)", fee) } else { "".to_string() }, - hex_utils::hex_str(&payment_hash.0), - hex_utils::hex_str(&payment_preimage.0) + payment_hash, + payment_preimage ); print!("> "); io::stdout().flush().unwrap(); } } - persister.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); } Event::OpenChannelRequest { ref temporary_channel_id, ref counterparty_node_id, .. @@ -326,21 +349,33 @@ async fn handle_ldk_events( Event::PaymentPathFailed { .. } => {} Event::ProbeSuccessful { .. } => {} Event::ProbeFailed { .. } => {} - Event::PaymentFailed { payment_hash, reason, .. } => { + Event::PaymentFailed { payment_hash, reason, payment_id, .. } => { print!( - "\nEVENT: Failed to send payment to payment hash {:?}: {:?}", - hex_utils::hex_str(&payment_hash.0), + "\nEVENT: Failed to send payment to payment hash {}: {:?}", + payment_hash, if let Some(r) = reason { r } else { PaymentFailureReason::RetriesExhausted } ); print!("> "); io::stdout().flush().unwrap(); let mut outbound = outbound_payments.lock().unwrap(); - if outbound.payments.contains_key(&payment_hash) { - let payment = outbound.payments.get_mut(&payment_hash).unwrap(); + if outbound.payments.contains_key(&payment_id) { + let payment = outbound.payments.get_mut(&payment_id).unwrap(); + payment.status = HTLCStatus::Failed; + } + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); + } + Event::InvoiceRequestFailed { payment_id } => { + print!("\nEVENT: Failed to request invoice to send payment with id {}", payment_id); + print!("> "); + io::stdout().flush().unwrap(); + + let mut outbound = outbound_payments.lock().unwrap(); + if outbound.payments.contains_key(&payment_id) { + let payment = outbound.payments.get_mut(&payment_id).unwrap(); payment.status = HTLCStatus::Failed; } - persister.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); } Event::PaymentForwarded { prev_channel_id, @@ -428,7 +463,7 @@ async fn handle_ldk_events( let key = hex_utils::hex_str(&keys_manager.get_secure_random_bytes()); // Note that if the type here changes our read code needs to change as well. let output: SpendableOutputDescriptor = output; - persister.write(PENDING_SPENDABLE_OUTPUT_DIR, "", &key, &output.encode()).unwrap(); + fs_store.write(PENDING_SPENDABLE_OUTPUT_DIR, "", &key, &output.encode()).unwrap(); } } Event::ChannelPending { channel_id, counterparty_node_id, .. } => { @@ -460,6 +495,7 @@ async fn handle_ldk_events( user_channel_id: _, counterparty_node_id, channel_capacity_sats: _, + channel_funding_txo: _, } => { println!( "\nEVENT: Channel {} with counterparty {} closed due to: {:?}", @@ -476,6 +512,7 @@ async fn handle_ldk_events( } Event::HTLCIntercepted { .. } => {} Event::BumpTransaction(event) => bump_tx_event_handler.handle_event(&event), + Event::ConnectionNeeded { .. } => {} } } @@ -499,6 +536,7 @@ async fn start_ldk() { args.bitcoind_rpc_port, args.bitcoind_rpc_username.clone(), args.bitcoind_rpc_password.clone(), + args.network, tokio::runtime::Handle::current(), Arc::clone(&logger), ) @@ -516,9 +554,9 @@ async fn start_ldk() { if bitcoind_chain != match args.network { bitcoin::Network::Bitcoin => "main", - bitcoin::Network::Testnet => "test", bitcoin::Network::Regtest => "regtest", bitcoin::Network::Signet => "signet", + bitcoin::Network::Testnet | _ => "test", } { println!( "Chain argument ({}) didn't match bitcoind chain ({})", @@ -538,19 +576,7 @@ async fn start_ldk() { // broadcaster. let broadcaster = bitcoind_client.clone(); - // Step 4: Initialize Persist - let persister = Arc::new(FilesystemStore::new(ldk_data_dir.clone().into())); - - // Step 5: Initialize the ChainMonitor - let chain_monitor: Arc = Arc::new(chainmonitor::ChainMonitor::new( - None, - broadcaster.clone(), - logger.clone(), - fee_estimator.clone(), - persister.clone(), - )); - - // Step 6: Initialize the KeysManager + // Step 4: Initialize the KeysManager // The key seed that we use to derive the node privkey (that corresponds to the node pubkey) and // other secret key material. @@ -585,10 +611,35 @@ async fn start_ldk() { Arc::clone(&logger), )); + // Step 5: Initialize Persistence + let fs_store = Arc::new(FilesystemStore::new(ldk_data_dir.clone().into())); + let persister = Arc::new(MonitorUpdatingPersister::new( + Arc::clone(&fs_store), + Arc::clone(&logger), + 1000, + Arc::clone(&keys_manager), + Arc::clone(&keys_manager), + )); + // Alternatively, you can use the `FilesystemStore` as a `Persist` directly, at the cost of + // larger `ChannelMonitor` update writes (but no deletion or cleanup): + //let persister = Arc::clone(&fs_store); + + // Step 6: Initialize the ChainMonitor + let chain_monitor: Arc = Arc::new(chainmonitor::ChainMonitor::new( + None, + Arc::clone(&broadcaster), + Arc::clone(&logger), + Arc::clone(&fee_estimator), + Arc::clone(&persister), + )); + // Step 7: Read ChannelMonitor state from disk - let mut channelmonitors = - read_channel_monitors(Arc::clone(&persister), keys_manager.clone(), keys_manager.clone()) - .unwrap(); + let mut channelmonitors = persister + .read_all_channel_monitors_with_updates(&bitcoind_client, &bitcoind_client) + .unwrap(); + // If you are using the `FilesystemStore` as a `Persist` directly, use + // `lightning::util::persist::read_channel_monitors` like this: + //read_channel_monitors(Arc::clone(&persister), Arc::clone(&keys_manager), Arc::clone(&keys_manager)).unwrap(); // Step 8: Poll for the best chain tip, which may be used by the channel manager & spv client let polled_chain_tip = init::validate_best_block_header(bitcoind_client.as_ref()) @@ -715,11 +766,8 @@ async fn start_ldk() { } // Step 14: Optional: Initialize the P2PGossipSync - let gossip_sync = Arc::new(P2PGossipSync::new( - Arc::clone(&network_graph), - None::>, - logger.clone(), - )); + let gossip_sync = + Arc::new(P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger))); // Step 15: Initialize the PeerManager let channel_manager: Arc = Arc::new(channel_manager); @@ -727,8 +775,8 @@ async fn start_ldk() { Arc::clone(&keys_manager), Arc::clone(&keys_manager), Arc::clone(&logger), - Arc::new(DefaultMessageRouter {}), - IgnoringMessageHandler {}, + Arc::new(DefaultMessageRouter::new(Arc::clone(&network_graph))), + Arc::clone(&channel_manager), IgnoringMessageHandler {}, )); let mut ephemeral_bytes = [0; 32]; @@ -748,6 +796,15 @@ async fn start_ldk() { Arc::clone(&keys_manager), )); + // Install a GossipVerifier in in the P2PGossipSync + let utxo_lookup = GossipVerifier::new( + Arc::clone(&bitcoind_client.bitcoind_rpc_client), + lightning_block_sync::gossip::TokioSpawner, + Arc::clone(&gossip_sync), + Arc::clone(&peer_manager), + ); + gossip_sync.add_utxo_lookup(Some(utxo_lookup)); + // ## Running LDK // Step 16: Initialize networking @@ -790,36 +847,34 @@ async fn start_ldk() { } }); - let inbound_payments = Arc::new(Mutex::new(disk::read_payment_info(Path::new(&format!( - "{}/{}", - ldk_data_dir, INBOUND_PAYMENTS_FNAME - ))))); - let outbound_payments = Arc::new(Mutex::new(disk::read_payment_info(Path::new(&format!( - "{}/{}", - ldk_data_dir, OUTBOUND_PAYMENTS_FNAME - ))))); - let recent_payments_payment_hashes = channel_manager + let inbound_payments = Arc::new(Mutex::new(disk::read_inbound_payment_info(Path::new( + &format!("{}/{}", ldk_data_dir, INBOUND_PAYMENTS_FNAME), + )))); + let outbound_payments = Arc::new(Mutex::new(disk::read_outbound_payment_info(Path::new( + &format!("{}/{}", ldk_data_dir, OUTBOUND_PAYMENTS_FNAME), + )))); + let recent_payments_payment_ids = channel_manager .list_recent_payments() .into_iter() .filter_map(|p| match p { - RecentPaymentDetails::Pending { payment_hash, .. } => Some(payment_hash), - RecentPaymentDetails::Fulfilled { payment_hash, .. } => payment_hash, - RecentPaymentDetails::Abandoned { payment_hash, .. } => Some(payment_hash), - RecentPaymentDetails::AwaitingInvoice { payment_id: _ } => todo!(), + RecentPaymentDetails::Pending { payment_id, .. } => Some(payment_id), + RecentPaymentDetails::Fulfilled { payment_id, .. } => Some(payment_id), + RecentPaymentDetails::Abandoned { payment_id, .. } => Some(payment_id), + RecentPaymentDetails::AwaitingInvoice { payment_id } => Some(payment_id), }) - .collect::>(); - for (payment_hash, payment_info) in outbound_payments + .collect::>(); + for (payment_id, payment_info) in outbound_payments .lock() .unwrap() .payments .iter_mut() .filter(|(_, i)| matches!(i.status, HTLCStatus::Pending)) { - if !recent_payments_payment_hashes.contains(payment_hash) { + if !recent_payments_payment_ids.contains(payment_id) { payment_info.status = HTLCStatus::Failed; } } - persister + fs_store .write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.lock().unwrap().encode()) .unwrap(); @@ -830,7 +885,7 @@ async fn start_ldk() { let keys_manager_event_listener = Arc::clone(&keys_manager); let inbound_payments_event_listener = Arc::clone(&inbound_payments); let outbound_payments_event_listener = Arc::clone(&outbound_payments); - let persister_event_listener = Arc::clone(&persister); + let fs_store_event_listener = Arc::clone(&fs_store); let network = args.network; let event_handler = move |event: Event| { let channel_manager_event_listener = Arc::clone(&channel_manager_event_listener); @@ -840,7 +895,7 @@ async fn start_ldk() { let bump_tx_event_handler = Arc::clone(&bump_tx_event_handler); let inbound_payments_event_listener = Arc::clone(&inbound_payments_event_listener); let outbound_payments_event_listener = Arc::clone(&outbound_payments_event_listener); - let persister_event_listener = Arc::clone(&persister_event_listener); + let fs_store_event_listener = Arc::clone(&fs_store_event_listener); async move { handle_ldk_events( &channel_manager_event_listener, @@ -850,7 +905,7 @@ async fn start_ldk() { &bump_tx_event_handler, inbound_payments_event_listener, outbound_payments_event_listener, - &persister_event_listener, + &fs_store_event_listener, network, event, ) @@ -882,6 +937,7 @@ async fn start_ldk() { }) }, false, + || Some(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()), )); // Regularly reconnect to channel peers.