X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=4a67d244f196694888477b45e00561b1ff016498;hb=7d8dc7ac1a05606e6422e0b4126b95717adc075d;hp=0360f8a69a8649dcb72e03fcf295ed2f2e9daa59;hpb=eb42caf8a0608ab004b8d3ae179015702ea8a64d;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 0360f8a6..4a67d244 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -36,6 +36,7 @@ use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1; use chain; +use chain::Confirm; use chain::Watch; use chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, ChannelMonitorUpdateErr, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID}; @@ -352,6 +353,22 @@ struct PeerState { latest_features: InitFeatures, } +/// Stores a PaymentSecret and any other data we may need to validate an inbound payment is +/// actually ours and not some duplicate HTLC sent to us by a node along the route. +/// +/// For users who don't want to bother doing their own payment preimage storage, we also store that +/// here. +struct PendingInboundPayment { + /// The payment secret that the sender must use for us to accept this payment + payment_secret: PaymentSecret, + /// Time at which this HTLC expires - blocks with a header time above this value will result in + /// this payment being removed. + expiry_time: u64, + // Other required attributes of the payment, optionally enforced: + payment_preimage: Option, + min_value_msat: Option, +} + /// SimpleArcChannelManager is useful when you need a ChannelManager with a static lifetime, e.g. /// when you're using lightning-net-tokio (since tokio::spawn requires parameters with static /// lifetimes). Other times you can afford a reference, which is more efficient, in which case @@ -430,6 +447,14 @@ pub struct ChannelManager>, #[cfg(not(any(test, feature = "_test_utils")))] channel_state: Mutex>, + + /// Storage for PaymentSecrets and any requirements on future inbound payments before we will + /// expose them to users via a PaymentReceived event. HTLCs which do not meet the requirements + /// here are failed when we process them as pending-forwardable-HTLCs, and entries are removed + /// after we generate a PaymentReceived upon receipt of all MPP parts. + /// Locked *after* channel_state. + pending_inbound_payments: Mutex>, + our_network_key: SecretKey, our_network_pubkey: PublicKey, @@ -437,6 +462,11 @@ pub struct ChannelManager ChannelMana claimable_htlcs: HashMap::new(), pending_msg_events: Vec::new(), }), + pending_inbound_payments: Mutex::new(HashMap::new()), + our_network_key: keys_manager.get_node_secret(), our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()), secp_ctx, last_node_announcement_serial: AtomicUsize::new(0), + highest_seen_timestamp: AtomicUsize::new(0), per_peer_state: RwLock::new(HashMap::new()), @@ -3320,6 +3353,85 @@ impl ChannelMana self.finish_force_close_channel(failure); } } + + fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { + assert!(invoice_expiry_delta_secs <= 60*60*24*365); // Sadly bitcoin timestamps are u32s, so panic before 2106 + + let payment_secret = PaymentSecret(self.keys_manager.get_secure_random_bytes()); + + let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + let mut payment_secrets = self.pending_inbound_payments.lock().unwrap(); + match payment_secrets.entry(payment_hash) { + hash_map::Entry::Vacant(e) => { + e.insert(PendingInboundPayment { + payment_secret, min_value_msat, payment_preimage, + // We assume that highest_seen_timestamp is pretty close to the current time - + // its updated when we receive a new block with the maximum time we've seen in + // a header. It should never be more than two hours in the future. + // Thus, we add two hours here as a buffer to ensure we absolutely + // never fail a payment too early. + // Note that we assume that received blocks have reasonably up-to-date + // timestamps. + expiry_time: self.highest_seen_timestamp.load(Ordering::Acquire) as u64 + invoice_expiry_delta_secs as u64 + 7200, + }); + }, + hash_map::Entry::Occupied(_) => return Err(APIError::APIMisuseError { err: "Duplicate payment hash".to_owned() }), + } + Ok(payment_secret) + } + + /// Gets a payment secret and payment hash for use in an invoice given to a third party wishing + /// to pay us. + /// + /// This differs from [`create_inbound_payment_for_hash`] only in that it generates the + /// [`PaymentHash`] and [`PaymentPreimage`] for you, returning the first and storing the second. + /// + /// See [`create_inbound_payment_for_hash`] for detailed documentation on behavior and requirements. + /// + /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash + pub fn create_inbound_payment(&self, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> (PaymentHash, PaymentSecret) { + let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes()); + let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); + + (payment_hash, + self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs) + .expect("RNG Generated Duplicate PaymentHash")) + } + + /// Gets a [`PaymentSecret`] for a given [`PaymentHash`], for which the payment preimage is + /// stored external to LDK. + /// + /// A [`PaymentReceived`] event will only be generated if the [`PaymentSecret`] matches a + /// payment secret fetched via this method or [`create_inbound_payment`], and which is at least + /// the `min_value_msat` provided here, if one is provided. + /// + /// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) must be globally unique. This + /// method may return an Err if another payment with the same payment_hash is still pending. + /// + /// `min_value_msat` should be set if the invoice being generated contains a value. Any payment + /// received for the returned [`PaymentHash`] will be required to be at least `min_value_msat` + /// before a [`PaymentReceived`] event will be generated, ensuring that we do not provide the + /// sender "proof-of-payment" unless they have paid the required amount. + /// + /// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for + /// in excess of the current time. This should roughly match the expiry time set in the invoice. + /// After this many seconds, we will remove the inbound payment, resulting in any attempts to + /// pay the invoice failing. The BOLT spec suggests 7,200 secs as a default validity time for + /// invoices when no timeout is set. + /// + /// Note that we use block header time to time-out pending inbound payments (with some margin + /// to compensate for the inaccuracy of block header timestamps). Thus, in practice we will + /// accept a payment and generate a [`PaymentReceived`] event for some time after the expiry. + /// If you need exact expiry semantics, you should enforce them upon receipt of + /// [`PaymentReceived`]. + /// + /// May panic if `invoice_expiry_delta_secs` is greater than one year. + /// + /// [`create_inbound_payment`]: Self::create_inbound_payment + /// [`PaymentReceived`]: events::Event::PaymentReceived + pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { + self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs) + } } impl MessageSendEventsProvider for ChannelManager @@ -3378,8 +3490,8 @@ where } let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); - self.transactions_confirmed(&block.header, height, &txdata); - self.update_best_block(&block.header, height); + self.transactions_confirmed(&block.header, &txdata, height); + self.best_block_updated(&block.header, height); } fn block_disconnected(&self, header: &BlockHeader, height: u32) { @@ -3394,16 +3506,94 @@ where *best_block = BestBlock::new(header.prev_blockhash, new_height) } - self.do_chain_event(Some(new_height), |channel| channel.update_best_block(new_height, header.time)); + self.do_chain_event(Some(new_height), |channel| channel.best_block_updated(new_height, header.time)); + } +} + +impl chain::Confirm for ChannelManager +where + M::Target: chain::Watch, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, +{ + fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { + // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called + // during initialization prior to the chain_monitor being fully configured in some cases. + // See the docs for `ChannelManagerReadArgs` for more. + + let block_hash = header.block_hash(); + log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height); + + let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new()))); + } + + fn best_block_updated(&self, header: &BlockHeader, height: u32) { + // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called + // during initialization prior to the chain_monitor being fully configured in some cases. + // See the docs for `ChannelManagerReadArgs` for more. + + let block_hash = header.block_hash(); + log_trace!(self.logger, "New best block: {} at height {}", block_hash, height); + + let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + + *self.best_block.write().unwrap() = BestBlock::new(block_hash, height); + + self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time)); + + macro_rules! max_time { + ($timestamp: expr) => { + loop { + // Update $timestamp to be the max of its current value and the block + // timestamp. This should keep us close to the current time without relying on + // having an explicit local time source. + // Just in case we end up in a race, we loop until we either successfully + // update $timestamp or decide we don't need to. + let old_serial = $timestamp.load(Ordering::Acquire); + if old_serial >= header.time as usize { break; } + if $timestamp.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() { + break; + } + } + } + } + max_time!(self.last_node_announcement_serial); + max_time!(self.highest_seen_timestamp); + } + + fn get_relevant_txids(&self) -> Vec { + let channel_state = self.channel_state.lock().unwrap(); + let mut res = Vec::with_capacity(channel_state.short_to_id.len()); + for chan in channel_state.by_id.values() { + if let Some(funding_txo) = chan.get_funding_txo() { + res.push(funding_txo.txid); + } + } + res + } + + fn transaction_unconfirmed(&self, txid: &Txid) { + let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + self.do_chain_event(None, |channel| { + if let Some(funding_txo) = channel.get_funding_txo() { + if funding_txo.txid == *txid { + channel.funding_transaction_unconfirmed().map(|_| (None, Vec::new())) + } else { Ok((None, Vec::new())) } + } else { Ok((None, Vec::new())) } + }); } } impl ChannelManager - where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, - L::Target: Logger, +where + M::Target: chain::Watch, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, { /// Calls a function which handles an on-chain event (blocks dis/connected, transactions /// un/confirmed, etc) on each channel, handling any resulting errors or messages generated by @@ -3497,131 +3687,6 @@ impl ChannelMana } } - /// Updates channel state to take note of transactions which were confirmed in the given block - /// at the given height. - /// - /// Note that you must still call (or have called) [`update_best_block`] with the block - /// information which is included here. - /// - /// This method may be called before or after [`update_best_block`] for a given block's - /// transaction data and may be called multiple times with additional transaction data for a - /// given block. - /// - /// This method may be called for a previous block after an [`update_best_block`] call has - /// been made for a later block, however it must *not* be called with transaction data from a - /// block which is no longer in the best chain (ie where [`update_best_block`] has already - /// been informed about a blockchain reorganization which no longer includes the block which - /// corresponds to `header`). - /// - /// [`update_best_block`]: `Self::update_best_block` - pub fn transactions_confirmed(&self, header: &BlockHeader, height: u32, txdata: &TransactionData) { - // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called - // during initialization prior to the chain_monitor being fully configured in some cases. - // See the docs for `ChannelManagerReadArgs` for more. - - let block_hash = header.block_hash(); - log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height); - - let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); - self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new()))); - } - - /// Updates channel state with the current best blockchain tip. You should attempt to call this - /// quickly after a new block becomes available, however if multiple new blocks become - /// available at the same time, only a single `update_best_block()` call needs to be made. - /// - /// This method should also be called immediately after any block disconnections, once at the - /// reorganization fork point, and once with the new chain tip. Calling this method at the - /// blockchain reorganization fork point ensures we learn when a funding transaction which was - /// previously confirmed is reorganized out of the blockchain, ensuring we do not continue to - /// accept payments which cannot be enforced on-chain. - /// - /// In both the block-connection and block-disconnection case, this method may be called either - /// once per block connected or disconnected, or simply at the fork point and new tip(s), - /// skipping any intermediary blocks. - pub fn update_best_block(&self, header: &BlockHeader, height: u32) { - // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called - // during initialization prior to the chain_monitor being fully configured in some cases. - // See the docs for `ChannelManagerReadArgs` for more. - - let block_hash = header.block_hash(); - log_trace!(self.logger, "New best block: {} at height {}", block_hash, height); - - let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); - - *self.best_block.write().unwrap() = BestBlock::new(block_hash, height); - - self.do_chain_event(Some(height), |channel| channel.update_best_block(height, header.time)); - - loop { - // Update last_node_announcement_serial to be the max of its current value and the - // block timestamp. This should keep us close to the current time without relying on - // having an explicit local time source. - // Just in case we end up in a race, we loop until we either successfully update - // last_node_announcement_serial or decide we don't need to. - let old_serial = self.last_node_announcement_serial.load(Ordering::Acquire); - if old_serial >= header.time as usize { break; } - if self.last_node_announcement_serial.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() { - break; - } - } - } - - /// Gets the set of txids which should be monitored for their confirmation state. - /// - /// If you're providing information about reorganizations via [`transaction_unconfirmed`], this - /// is the set of transactions which you may need to call [`transaction_unconfirmed`] for. - /// - /// This may be useful to poll to determine the set of transactions which must be registered - /// with an Electrum server or for which an Electrum server needs to be polled to determine - /// transaction confirmation state. - /// - /// This may update after any [`transactions_confirmed`] or [`block_connected`] call. - /// - /// Note that this is NOT the set of transactions which must be included in calls to - /// [`transactions_confirmed`] if they are confirmed, but a small subset of it. - /// - /// [`transactions_confirmed`]: Self::transactions_confirmed - /// [`transaction_unconfirmed`]: Self::transaction_unconfirmed - /// [`block_connected`]: chain::Listen::block_connected - pub fn get_relevant_txids(&self) -> Vec { - let channel_state = self.channel_state.lock().unwrap(); - let mut res = Vec::with_capacity(channel_state.short_to_id.len()); - for chan in channel_state.by_id.values() { - if let Some(funding_txo) = chan.get_funding_txo() { - res.push(funding_txo.txid); - } - } - res - } - - /// Marks a transaction as having been reorganized out of the blockchain. - /// - /// If a transaction is included in [`get_relevant_txids`], and is no longer in the main branch - /// of the blockchain, this function should be called to indicate that the transaction should - /// be considered reorganized out. - /// - /// Once this is called, the given transaction will no longer appear on [`get_relevant_txids`], - /// though this may be called repeatedly for a given transaction without issue. - /// - /// Note that if the transaction is confirmed on the main chain in a different block (indicated - /// via a call to [`transactions_confirmed`]), it may re-appear in [`get_relevant_txids`], thus - /// be very wary of race-conditions wherein the final state of a transaction indicated via - /// these APIs is not the same as its state on the blockchain. - /// - /// [`transactions_confirmed`]: Self::transactions_confirmed - /// [`get_relevant_txids`]: Self::get_relevant_txids - pub fn transaction_unconfirmed(&self, txid: &Txid) { - let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); - self.do_chain_event(None, |channel| { - if let Some(funding_txo) = channel.get_funding_txo() { - if funding_txo.txid == *txid { - channel.funding_transaction_unconfirmed().map(|_| (None, Vec::new())) - } else { Ok((None, Vec::new())) } - } else { Ok((None, Vec::new())) } - }); - } - /// Blocks until ChannelManager needs to be persisted or a timeout is reached. It returns a bool /// indicating whether persistence is necessary. Only one listener on /// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken @@ -4168,6 +4233,13 @@ impl Readable for HTLCForwardInfo { } } +impl_writeable!(PendingInboundPayment, 0, { + payment_secret, + expiry_time, + payment_preimage, + min_value_msat +}); + impl Writeable for ChannelManager where M::Target: chain::Watch, T::Target: BroadcasterInterface, @@ -4247,6 +4319,14 @@ impl Writeable f } (self.last_node_announcement_serial.load(Ordering::Acquire) as u32).write(writer)?; + (self.highest_seen_timestamp.load(Ordering::Acquire) as u32).write(writer)?; + + let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap(); + (pending_inbound_payments.len() as u64).write(writer)?; + for (hash, pending_payment) in pending_inbound_payments.iter() { + hash.write(writer)?; + pending_payment.write(writer)?; + } Ok(()) } @@ -4477,6 +4557,15 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> } let last_node_announcement_serial: u32 = Readable::read(reader)?; + let highest_seen_timestamp: u32 = Readable::read(reader)?; + + let pending_inbound_payment_count: u64 = Readable::read(reader)?; + let mut pending_inbound_payments: HashMap = HashMap::with_capacity(cmp::min(pending_inbound_payment_count as usize, MAX_ALLOC_SIZE/(3*32))); + for _ in 0..pending_inbound_payment_count { + if pending_inbound_payments.insert(Readable::read(reader)?, Readable::read(reader)?).is_some() { + return Err(DecodeError::InvalidValue); + } + } let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&args.keys_manager.get_secure_random_bytes()); @@ -4496,11 +4585,14 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> claimable_htlcs, pending_msg_events: Vec::new(), }), + pending_inbound_payments: Mutex::new(pending_inbound_payments), + our_network_key: args.keys_manager.get_node_secret(), our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret()), secp_ctx, last_node_announcement_serial: AtomicUsize::new(last_node_announcement_serial as usize), + highest_seen_timestamp: AtomicUsize::new(highest_seen_timestamp as usize), per_peer_state: RwLock::new(per_peer_state),