Merge pull request #2969 from TheBlueMatt/2024-03-fix-upgradable-enum
authorvalentinewallace <valentinewallace@users.noreply.github.com>
Mon, 8 Apr 2024 14:34:14 +0000 (16:34 +0200)
committerGitHub <noreply@github.com>
Mon, 8 Apr 2024 14:34:14 +0000 (16:34 +0200)
74 files changed:
fuzz/src/router.rs
lightning-block-sync/src/init.rs
lightning-invoice/src/de.rs
lightning-invoice/src/utils.rs
lightning-invoice/tests/ser_de.rs
lightning-net-tokio/src/lib.rs
lightning-persister/src/fs_store.rs
lightning-rapid-gossip-sync/src/processing.rs
lightning/src/blinded_path/message.rs
lightning/src/blinded_path/payment.rs
lightning/src/blinded_path/utils.rs
lightning/src/chain/chaininterface.rs
lightning/src/chain/channelmonitor.rs
lightning/src/chain/mod.rs
lightning/src/chain/package.rs
lightning/src/crypto/chacha20.rs
lightning/src/crypto/poly1305.rs
lightning/src/crypto/streams.rs
lightning/src/events/mod.rs
lightning/src/lib.rs
lightning/src/ln/blinded_payment_tests.rs
lightning/src/ln/chan_utils.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/features.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/inbound_payment.rs
lightning/src/ln/mod.rs
lightning/src/ln/msgs.rs
lightning/src/ln/onion_payment.rs
lightning/src/ln/onion_route_tests.rs
lightning/src/ln/onion_utils.rs
lightning/src/ln/payment_tests.rs
lightning/src/ln/peer_handler.rs
lightning/src/ln/priv_short_conf_tests.rs
lightning/src/ln/reload_tests.rs
lightning/src/ln/script.rs
lightning/src/ln/shutdown_tests.rs
lightning/src/ln/wire.rs
lightning/src/offers/invoice.rs
lightning/src/offers/invoice_error.rs
lightning/src/offers/invoice_request.rs
lightning/src/offers/merkle.rs
lightning/src/offers/offer.rs
lightning/src/offers/parse.rs
lightning/src/offers/payer.rs
lightning/src/offers/refund.rs
lightning/src/offers/signer.rs
lightning/src/offers/test_utils.rs
lightning/src/onion_message/offers.rs
lightning/src/routing/gossip.rs
lightning/src/routing/router.rs
lightning/src/routing/scoring.rs
lightning/src/routing/test_utils.rs
lightning/src/routing/utxo.rs
lightning/src/sign/ecdsa.rs
lightning/src/sign/mod.rs
lightning/src/sync/debug_sync.rs
lightning/src/util/base32.rs
lightning/src/util/errors.rs
lightning/src/util/indexed_map.rs
lightning/src/util/invoice.rs
lightning/src/util/message_signing.rs
lightning/src/util/persist.rs
lightning/src/util/scid_utils.rs
lightning/src/util/ser.rs
lightning/src/util/ser_macros.rs
lightning/src/util/string.rs
lightning/src/util/test_channel_signer.rs
lightning/src/util/test_utils.rs
lightning/src/util/time.rs
lightning/src/util/transaction_utils.rs
lightning/src/util/wakers.rs

index bf94c910531573335f2db2594ce1df41304b0f3d..ad4373c4793bc704f66d6cc095b83a5e82013cf7 100644 (file)
@@ -157,6 +157,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                        msgs::DecodeError::ShortRead => panic!("We picked the length..."),
                                        msgs::DecodeError::Io(e) => panic!("{:?}", e),
                                        msgs::DecodeError::UnsupportedCompression => return,
+                                       msgs::DecodeError::DangerousValue => return,
                                }
                        }
                }}
index 8cb0ff70a2e67ee1dee3330ffa77532b8bd68b83..ba93d12f5bcd7ff49d703e530c448b27707bd1a5 100644 (file)
@@ -252,8 +252,6 @@ mod tests {
        use crate::test_utils::{Blockchain, MockChainListener};
        use super::*;
 
-       use bitcoin::network::constants::Network;
-
        #[tokio::test]
        async fn sync_from_same_chain() {
                let chain = Blockchain::default().with_height(4);
index 9284999b1884474a51a82a7637ce237fbf7fae65..56e5c53ba1f281e01fb274914b108b0f026ff660 100644 (file)
@@ -1,5 +1,6 @@
 #[cfg(feature = "std")]
 use std::error;
+#[cfg(not(feature = "std"))]
 use core::convert::TryFrom;
 use core::fmt;
 use core::fmt::{Display, Formatter};
index d45a4e8e6462b4256333ea9f6973367b1d586c10..1d6b9210afd967f58c79e7453f53a3eda856a9ee 100644 (file)
@@ -19,6 +19,7 @@ use secp256k1::PublicKey;
 use alloc::collections::{btree_map, BTreeMap};
 use core::ops::Deref;
 use core::time::Duration;
+#[cfg(not(feature = "std"))]
 use core::iter::Iterator;
 
 /// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
index 92bc87bef63e86e98c7678b88dc2ce251352c874..e5e311fe669277b955ccf23e372478fd8386560b 100644 (file)
@@ -8,9 +8,6 @@ use bitcoin::address::WitnessVersion;
 use bitcoin::{PubkeyHash, ScriptHash};
 use bitcoin::hashes::hex::FromHex;
 use bitcoin::hashes::{sha256, Hash};
-use lightning::ln::PaymentSecret;
-use lightning::routing::gossip::RoutingFees;
-use lightning::routing::router::{RouteHint, RouteHintHop};
 use lightning_invoice::*;
 use secp256k1::PublicKey;
 use secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
index be41a2401244f0bff743e44b9e7ec26482d95227..71d63ecadcfa96e3b7fbd4a2c7c1076af2470e25 100644 (file)
@@ -208,7 +208,12 @@ impl Connection {
                                                break Disconnect::CloseConnection;
                                        }
                                },
-                               SelectorOutput::B(_) => {},
+                               SelectorOutput::B(some) => {
+                                       // The mpsc Receiver should only return `None` if the write side has been
+                                       // dropped, but that shouldn't be possible since its referenced by the Self in
+                                       // `us`.
+                                       debug_assert!(some.is_some());
+                               },
                                SelectorOutput::C(res) => {
                                        if res.is_err() { break Disconnect::PeerDisconnected; }
                                        match reader.try_read(&mut buf) {
@@ -556,7 +561,6 @@ mod tests {
        use lightning::ln::features::*;
        use lightning::ln::msgs::*;
        use lightning::ln::peer_handler::{MessageHandler, PeerManager};
-       use lightning::ln::features::NodeFeatures;
        use lightning::routing::gossip::NodeId;
        use lightning::events::*;
        use lightning::util::test_utils::TestNodeSigner;
index 350b1cdd195636f937cd32a700da9464508fee8e..364a3ee706f5288fd61dc52df53d6c135799f1cd 100644 (file)
@@ -379,7 +379,6 @@ mod tests {
        use lightning::ln::functional_test_utils::*;
        use lightning::util::test_utils;
        use lightning::util::persist::read_channel_monitors;
-       use std::fs;
        use std::str::FromStr;
 
        impl Drop for FilesystemStore {
index 9023b9ba38ca52c16d003bebaa21e1511c946d2e..b3fae0ffd8bea8e19822c5a2cf9bc19d3fe33939 100644 (file)
@@ -19,7 +19,7 @@ use crate::{GraphSyncError, RapidGossipSync};
 #[cfg(all(feature = "std", not(test)))]
 use std::time::{SystemTime, UNIX_EPOCH};
 
-#[cfg(not(feature = "std"))]
+#[cfg(all(not(feature = "std"), not(test)))]
 use alloc::{vec::Vec, borrow::ToOwned};
 
 /// The purpose of this prefix is to identify the serialization format, should other rapid gossip
index 3a5541fa1468272f3859972bca2cdfb4f8053ee8..bdcbd7726f71189175407bc3dd125aad2c1db199 100644 (file)
@@ -1,12 +1,14 @@
 use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
 
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 use crate::blinded_path::{BlindedHop, BlindedPath};
 use crate::blinded_path::utils;
 use crate::io;
 use crate::io::Cursor;
 use crate::ln::onion_utils;
 use crate::onion_message::packet::ControlTlvs;
-use crate::prelude::*;
 use crate::sign::{NodeSigner, Recipient};
 use crate::crypto::streams::ChaChaPolyReadAdapter;
 use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Writeable, Writer};
index 6467af568886bd1891a7e8c52ae6b5956736f6bd..3d56020a626d68cd1e233f53a905cfdfa8acf21c 100644 (file)
@@ -12,10 +12,10 @@ use crate::ln::channelmanager::CounterpartyForwardingInfo;
 use crate::ln::features::BlindedHopFeatures;
 use crate::ln::msgs::DecodeError;
 use crate::offers::invoice::BlindedPayInfo;
-use crate::prelude::*;
 use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, Writeable, Writer};
 
-use core::convert::TryFrom;
+#[allow(unused_imports)]
+use crate::prelude::*;
 
 /// An intermediate node, its outbound channel, and relay parameters.
 #[derive(Clone, Debug)]
index d4894a86aa1a9069abdc9b2e073cd0a31c789048..7e43f31453637a6fdea2309d4713f2b34567693f 100644 (file)
@@ -23,6 +23,8 @@ use crate::crypto::streams::ChaChaPolyWriteAdapter;
 use crate::util::ser::{Readable, Writeable};
 
 use crate::io;
+
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 // TODO: DRY with onion_utils::construct_onion_keys_callback
index 1f42dc2fe4251a26be3c7b659bae89505893b6e3..2bf6d6130e1123eef41a77fd3e5ffd1e5e3b72be 100644 (file)
@@ -14,7 +14,8 @@
 //! disconnections, transaction broadcasting, and feerate information requests.
 
 use core::{cmp, ops::Deref};
-use core::convert::TryInto;
+
+use crate::prelude::*;
 
 use bitcoin::blockdata::transaction::Transaction;
 
index 4352076e94d009928689dfd524c6214e5c3d06de..c2d3a43b1f4bd40d65ea041478313a878d49d7ca 100644 (file)
@@ -53,10 +53,11 @@ use crate::util::byte_utils;
 use crate::events::{ClosureReason, Event, EventHandler};
 use crate::events::bump_transaction::{AnchorDescriptor, BumpTransactionEvent};
 
+#[allow(unused_imports)]
 use crate::prelude::*;
+
 use core::{cmp, mem};
 use crate::io::{self, Error};
-use core::convert::TryInto;
 use core::ops::Deref;
 use crate::sync::{Mutex, LockTestExt};
 
@@ -4765,6 +4766,8 @@ mod tests {
        use crate::sync::{Arc, Mutex};
        use crate::io;
        use crate::ln::features::ChannelTypeFeatures;
+
+       #[allow(unused_imports)]
        use crate::prelude::*;
 
        use std::str::FromStr;
index 356520b5cba86e647acdec77fd0cb86b683e7d58..e22ccca986aacf622778c7c4c3c5320b3815e341 100644 (file)
@@ -21,6 +21,7 @@ use crate::ln::ChannelId;
 use crate::sign::ecdsa::WriteableEcdsaChannelSigner;
 use crate::chain::transaction::{OutPoint, TransactionData};
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 pub mod chaininterface;
index e304b16ef3e4fb1d42630cf9b568cc2014034200..3023be604d3f9d0f47fd3538ea5bcb8aaf3c640c 100644 (file)
@@ -35,12 +35,13 @@ use crate::util::logger::Logger;
 use crate::util::ser::{Readable, Writer, Writeable, RequiredWrapper};
 
 use crate::io;
-use crate::prelude::*;
 use core::cmp;
-use core::convert::TryInto;
 use core::mem;
 use core::ops::Deref;
 
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 use super::chaininterface::LowerBoundedFeeEstimator;
 
 const MAX_ALLOC_SIZE: usize = 64*1024;
index d6fd3a7dee0013c1bbbfb466737e3fae16a415da..0c51d4562febf12168f9971f4f43d7a94cd875c2 100644 (file)
@@ -12,7 +12,6 @@
 #[cfg(not(fuzzing))]
 mod real_chacha {
        use core::cmp;
-       use core::convert::TryInto;
 
        #[derive(Clone, Copy, PartialEq, Eq)]
        #[allow(non_camel_case_types)]
@@ -335,11 +334,10 @@ pub use self::fuzzy_chacha::ChaCha20;
 
 #[cfg(test)]
 mod test {
-       use alloc::vec;
-       use alloc::vec::{Vec};
-       use core::convert::TryInto;
        use core::iter::repeat;
 
+       use crate::prelude::*;
+
        use super::ChaCha20;
 
        #[test]
index a1b9fbac5160c5ddd8d090e63844f92e6da744ae..593200210055e32605c9ab4822a9f32fd54a9e44 100644 (file)
@@ -8,7 +8,8 @@
 // https://github.com/floodyberry/poly1305-donna
 
 use core::cmp::min;
-use core::convert::TryInto;
+
+use crate::prelude::*;
 
 #[derive(Clone, Copy)]
 pub struct Poly1305 {
@@ -206,7 +207,6 @@ impl Poly1305 {
 #[cfg(test)]
 mod test {
        use core::iter::repeat;
-       use alloc::vec::Vec;
 
        use super::Poly1305;
 
index 14921a386126e1c5c18f36d7f32c0410390dd0aa..e8217b8d9d3999a1feb647fbb1e9d5456bed5ea8 100644 (file)
@@ -151,7 +151,7 @@ mod tests {
                                let writeable_len = $obj.serialized_length() as u64 + 16;
                                let write_adapter = ChaChaPolyWriteAdapter::new(rho, &$obj);
                                let encrypted_writeable_bytes = write_adapter.encode();
-                               let encrypted_writeable = &encrypted_writeable_bytes[..];
+                               let encrypted_writeable = &mut &encrypted_writeable_bytes[..];
 
                                // Now deserialize the object back and make sure it matches the original.
                                let mut rd = FixedLengthReader::new(encrypted_writeable, writeable_len);
index d4fa90c6a73e0c6ab200292d6764f1a6e5443f3a..f6e7f7164874f0de97fb56a8dc3c4294d2206c94 100644 (file)
@@ -38,11 +38,13 @@ use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::secp256k1::PublicKey;
 use crate::io;
-use crate::prelude::*;
 use core::time::Duration;
 use core::ops::Deref;
 use crate::sync::Arc;
 
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 /// Some information provided on receipt of payment depends on whether the payment received is a
 /// spontaneous payment or a "conventional" lightning payment that's paying an invoice.
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -302,6 +304,8 @@ pub enum HTLCDestination {
                /// Short channel id we are requesting to forward an HTLC to.
                requested_forward_scid: u64
        },
+       /// We couldn't decode the incoming onion to obtain the forwarding details.
+       InvalidOnion,
        /// Failure scenario where an HTLC may have been forwarded to be intended for us,
        /// but is invalid for some reason, so we reject it.
        ///
@@ -329,6 +333,7 @@ impl_writeable_tlv_based_enum_upgradable!(HTLCDestination,
        (2, UnknownNextHop) => {
                (0, requested_forward_scid, required),
        },
+       (3, InvalidOnion) => {},
        (4, FailedPayment) => {
                (0, payment_hash, required),
        },
@@ -1294,7 +1299,7 @@ impl MaybeReadable for Event {
                        // Note that we do not write a length-prefixed TLV for FundingGenerationReady events.
                        0u8 => Ok(None),
                        1u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut payment_hash = PaymentHash([0; 32]);
                                        let mut payment_preimage = None;
                                        let mut payment_secret = None;
@@ -1342,7 +1347,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        2u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut payment_preimage = PaymentPreimage([0; 32]);
                                        let mut payment_hash = None;
                                        let mut payment_id = None;
@@ -1366,7 +1371,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        3u8 => {
-                               let f = || {
+                               let mut f = || {
                                        #[cfg(test)]
                                        let error_code = Readable::read(reader)?;
                                        #[cfg(test)]
@@ -1409,7 +1414,7 @@ impl MaybeReadable for Event {
                        },
                        4u8 => Ok(None),
                        5u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut outputs = WithoutLength(Vec::new());
                                        let mut channel_id: Option<ChannelId> = None;
                                        read_tlv_fields!(reader, {
@@ -1445,7 +1450,7 @@ impl MaybeReadable for Event {
                                }))
                        },
                        7u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut prev_channel_id = None;
                                        let mut next_channel_id = None;
                                        let mut prev_user_channel_id = None;
@@ -1473,7 +1478,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        9u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut channel_id = ChannelId::new_zero();
                                        let mut reason = UpgradableRequired(None);
                                        let mut user_channel_id_low_opt: Option<u64> = None;
@@ -1503,7 +1508,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        11u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut channel_id = ChannelId::new_zero();
                                        let mut transaction = Transaction{ version: 2, lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() };
                                        read_tlv_fields!(reader, {
@@ -1515,7 +1520,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        13u8 => {
-                               let f = || {
+                               let mut f = || {
                                        _init_and_read_len_prefixed_tlv_fields!(reader, {
                                                (0, payment_id, required),
                                                (2, payment_hash, option),
@@ -1531,7 +1536,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        15u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut payment_hash = PaymentHash([0; 32]);
                                        let mut payment_id = PaymentId([0; 32]);
                                        let mut reason = None;
@@ -1553,7 +1558,7 @@ impl MaybeReadable for Event {
                                Ok(None)
                        },
                        19u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut payment_hash = PaymentHash([0; 32]);
                                        let mut purpose = UpgradableRequired(None);
                                        let mut amount_msat = 0;
@@ -1580,7 +1585,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        21u8 => {
-                               let f = || {
+                               let mut f = || {
                                        _init_and_read_len_prefixed_tlv_fields!(reader, {
                                                (0, payment_id, required),
                                                (2, payment_hash, required),
@@ -1596,7 +1601,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        23u8 => {
-                               let f = || {
+                               let mut f = || {
                                        _init_and_read_len_prefixed_tlv_fields!(reader, {
                                                (0, payment_id, required),
                                                (2, payment_hash, required),
@@ -1614,7 +1619,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        25u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut prev_channel_id = ChannelId::new_zero();
                                        let mut failed_next_destination_opt = UpgradableRequired(None);
                                        read_tlv_fields!(reader, {
@@ -1630,7 +1635,7 @@ impl MaybeReadable for Event {
                        },
                        27u8 => Ok(None),
                        29u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut channel_id = ChannelId::new_zero();
                                        let mut user_channel_id: u128 = 0;
                                        let mut counterparty_node_id = RequiredWrapper(None);
@@ -1652,7 +1657,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        31u8 => {
-                               let f = || {
+                               let mut f = || {
                                        let mut channel_id = ChannelId::new_zero();
                                        let mut user_channel_id: u128 = 0;
                                        let mut former_temporary_channel_id = None;
@@ -1680,7 +1685,7 @@ impl MaybeReadable for Event {
                                f()
                        },
                        33u8 => {
-                               let f = || {
+                               let mut f = || {
                                        _init_and_read_len_prefixed_tlv_fields!(reader, {
                                                (0, payment_id, required),
                                        });
index c9ae3f26eeb9ca460eb11b2f06da249dfeed4dec..3bcd5d72c64e19c3adf89d5c8580016582e2462c 100644 (file)
@@ -169,11 +169,17 @@ mod io_extras {
 }
 
 mod prelude {
+       #![allow(unused_imports)]
+
        pub use alloc::{vec, vec::Vec, string::String, collections::VecDeque, boxed::Box};
 
        pub use alloc::borrow::ToOwned;
        pub use alloc::string::ToString;
 
+       pub use core::convert::{AsMut, AsRef, TryFrom, TryInto};
+       pub use core::default::Default;
+       pub use core::marker::Sized;
+
        pub(crate) use crate::util::hash_tables::*;
 }
 
index 198ded1cb4421aa8afbee8848f22c4381f2b7b3d..eb31be9eecf334ead7ece1d1d6ecd7b587534f61 100644 (file)
@@ -1264,3 +1264,50 @@ fn blinded_mpp_keysend() {
                Some(payment_secret), ev.clone(), true, Some(keysend_preimage));
        claim_payment_along_route(&nodes[0], expected_route, false, keysend_preimage);
 }
+
+#[test]
+fn custom_tlvs_to_blinded_path() {
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+       let chan_upd = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0).0.contents;
+
+       let amt_msat = 5000;
+       let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None);
+       let payee_tlvs = ReceiveTlvs {
+               payment_secret,
+               payment_constraints: PaymentConstraints {
+                       max_cltv_expiry: u32::max_value(),
+                       htlc_minimum_msat: chan_upd.htlc_minimum_msat,
+               },
+       };
+       let mut secp_ctx = Secp256k1::new();
+       let blinded_path = BlindedPath::one_hop_for_payment(
+               nodes[1].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
+               &chanmon_cfgs[1].keys_manager, &secp_ctx
+       ).unwrap();
+
+       let route_params = RouteParameters::from_payment_params_and_value(
+               PaymentParameters::blinded(vec![blinded_path]),
+               amt_msat,
+       );
+
+       let recipient_onion_fields = RecipientOnionFields::spontaneous_empty()
+               .with_custom_tlvs(vec![((1 << 16) + 1, vec![42, 42])])
+               .unwrap();
+       nodes[0].node.send_payment(payment_hash, recipient_onion_fields.clone(),
+               PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap();
+       check_added_monitors(&nodes[0], 1);
+
+       let mut events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(events.len(), 1);
+       let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
+
+       let path = &[&nodes[1]];
+       let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, ev)
+               .with_payment_secret(payment_secret)
+               .with_custom_tlvs(recipient_onion_fields.custom_tlvs.clone());
+       do_pass_along_path(args);
+       claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
+}
index 18c4d83406c1bdbcdb673b0461062de62f400b0a..c002dfaea25f62297518d9f8b94dcc898004c7da 100644 (file)
@@ -37,7 +37,6 @@ use bitcoin::{secp256k1, Sequence, Witness};
 use bitcoin::PublicKey as BitcoinPublicKey;
 
 use crate::io;
-use crate::prelude::*;
 use core::cmp;
 use crate::ln::chan_utils;
 use crate::util::transaction_utils::sort_outputs;
@@ -48,6 +47,9 @@ use crate::ln::features::ChannelTypeFeatures;
 use crate::crypto::utils::{sign, sign_with_aux_rand};
 use super::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint};
 
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 /// Maximum number of one-way in-flight HTLC (protocol-level value).
 pub const MAX_HTLCS: u16 = 483;
 /// The weight of a BIP141 witnessScript for a BOLT3's "offered HTLC output" on a commitment transaction, non-anchor variant.
@@ -1812,7 +1814,6 @@ pub fn get_commitment_transaction_number_obscure_factor(
 mod tests {
        use super::{CounterpartyCommitmentSecrets, ChannelPublicKeys};
        use crate::chain;
-       use crate::prelude::*;
        use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment};
        use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1};
        use crate::util::test_utils;
@@ -1825,6 +1826,9 @@ mod tests {
        use bitcoin::PublicKey as BitcoinPublicKey;
        use crate::ln::features::ChannelTypeFeatures;
 
+       #[allow(unused_imports)]
+       use crate::prelude::*;
+
        struct TestCommitmentTxBuilder {
                commitment_number: u64,
                holder_funding_pubkey: PublicKey,
index 33df5303814da439f5f83fd33a2acf53963b115f..2698abee2d7db271c0e8a0a2c11d7e77ca976930 100644 (file)
@@ -50,7 +50,6 @@ use crate::util::scid_utils::scid_from_parts;
 use crate::io;
 use crate::prelude::*;
 use core::{cmp,mem,fmt};
-use core::convert::TryInto;
 use core::ops::Deref;
 #[cfg(any(test, fuzzing, debug_assertions))]
 use crate::sync::Mutex;
@@ -104,10 +103,38 @@ enum InboundHTLCRemovalReason {
        Fulfill(PaymentPreimage),
 }
 
+/// Represents the resolution status of an inbound HTLC.
+#[derive(Clone)]
+enum InboundHTLCResolution {
+       /// Resolved implies the action we must take with the inbound HTLC has already been determined,
+       /// i.e., we already know whether it must be failed back or forwarded.
+       //
+       // TODO: Once this variant is removed, we should also clean up
+       // [`MonitorRestoreUpdates::accepted_htlcs`] as the path will be unreachable.
+       Resolved {
+               pending_htlc_status: PendingHTLCStatus,
+       },
+       /// Pending implies we will attempt to resolve the inbound HTLC once it has been fully committed
+       /// to by both sides of the channel, i.e., once a `revoke_and_ack` has been processed by both
+       /// nodes for the state update in which it was proposed.
+       Pending {
+               update_add_htlc: msgs::UpdateAddHTLC,
+       },
+}
+
+impl_writeable_tlv_based_enum!(InboundHTLCResolution,
+       (0, Resolved) => {
+               (0, pending_htlc_status, required),
+       },
+       (2, Pending) => {
+               (0, update_add_htlc, required),
+       };
+);
+
 enum InboundHTLCState {
        /// Offered by remote, to be included in next local commitment tx. I.e., the remote sent an
        /// update_add_htlc message for this HTLC.
-       RemoteAnnounced(PendingHTLCStatus),
+       RemoteAnnounced(InboundHTLCResolution),
        /// Included in a received commitment_signed message (implying we've
        /// revoke_and_ack'd it), but the remote hasn't yet revoked their previous
        /// state (see the example below). We have not yet included this HTLC in a
@@ -137,13 +164,13 @@ enum InboundHTLCState {
        /// Implies AwaitingRemoteRevoke.
        ///
        /// [BOLT #2]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md
-       AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus),
+       AwaitingRemoteRevokeToAnnounce(InboundHTLCResolution),
        /// Included in a received commitment_signed message (implying we've revoke_and_ack'd it).
        /// We have also included this HTLC in our latest commitment_signed and are now just waiting
        /// on the remote's revoke_and_ack to make this HTLC an irrevocable part of the state of the
        /// channel (before it can then get forwarded and/or removed).
        /// Implies AwaitingRemoteRevoke.
-       AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus),
+       AwaitingAnnouncedRemoteRevoke(InboundHTLCResolution),
        Committed,
        /// Removed by us and a new commitment_signed was sent (if we were AwaitingRemoteRevoke when we
        /// created it we would have put it in the holding cell instead). When they next revoke_and_ack
@@ -1044,6 +1071,7 @@ pub(super) struct MonitorRestoreUpdates {
        pub accepted_htlcs: Vec<(PendingHTLCInfo, u64)>,
        pub failed_htlcs: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
        pub finalized_claimed_htlcs: Vec<HTLCSource>,
+       pub pending_update_adds: Vec<msgs::UpdateAddHTLC>,
        pub funding_broadcastable: Option<Transaction>,
        pub channel_ready: Option<msgs::ChannelReady>,
        pub announcement_sigs: Option<msgs::AnnouncementSignatures>,
@@ -1291,6 +1319,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
        monitor_pending_forwards: Vec<(PendingHTLCInfo, u64)>,
        monitor_pending_failures: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
        monitor_pending_finalized_fulfills: Vec<HTLCSource>,
+       monitor_pending_update_adds: Vec<msgs::UpdateAddHTLC>,
 
        /// If we went to send a commitment update (ie some messages then [`msgs::CommitmentSigned`])
        /// but our signer (initially) refused to give us a signature, we should retry at some point in
@@ -1755,6 +1784,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                        monitor_pending_forwards: Vec::new(),
                        monitor_pending_failures: Vec::new(),
                        monitor_pending_finalized_fulfills: Vec::new(),
+                       monitor_pending_update_adds: Vec::new(),
 
                        signer_pending_commitment_update: false,
                        signer_pending_funding: false,
@@ -1976,6 +2006,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                        monitor_pending_forwards: Vec::new(),
                        monitor_pending_failures: Vec::new(),
                        monitor_pending_finalized_fulfills: Vec::new(),
+                       monitor_pending_update_adds: Vec::new(),
 
                        signer_pending_commitment_update: false,
                        signer_pending_funding: false,
@@ -4089,20 +4120,12 @@ impl<SP: Deref> Channel<SP> where
                Ok(self.get_announcement_sigs(node_signer, chain_hash, user_config, best_block.height, logger))
        }
 
-       pub fn update_add_htlc<F, FE: Deref, L: Deref>(
-               &mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus,
-               create_pending_htlc_status: F, fee_estimator: &LowerBoundedFeeEstimator<FE>, logger: &L
-       ) -> Result<(), ChannelError>
-       where F: for<'a> Fn(&'a Self, PendingHTLCStatus, u16) -> PendingHTLCStatus,
-               FE::Target: FeeEstimator, L::Target: Logger,
-       {
+       pub fn update_add_htlc(
+               &mut self, msg: &msgs::UpdateAddHTLC, pending_forward_status: PendingHTLCStatus,
+       ) -> Result<(), ChannelError> {
                if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
                        return Err(ChannelError::Close("Got add HTLC message when channel was not in an operational state".to_owned()));
                }
-               // We can't accept HTLCs sent after we've sent a shutdown.
-               if self.context.channel_state.is_local_shutdown_sent() {
-                       pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x4000|8);
-               }
                // If the remote has sent a shutdown prior to adding this HTLC, then they are in violation of the spec.
                if self.context.channel_state.is_remote_shutdown_sent() {
                        return Err(ChannelError::Close("Got add HTLC message when channel was not in an operational state".to_owned()));
@@ -4121,7 +4144,6 @@ impl<SP: Deref> Channel<SP> where
                }
 
                let inbound_stats = self.context.get_inbound_pending_htlc_stats(None);
-               let outbound_stats = self.context.get_outbound_pending_htlc_stats(None);
                if inbound_stats.pending_htlcs + 1 > self.context.holder_max_accepted_htlcs as u32 {
                        return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", self.context.holder_max_accepted_htlcs)));
                }
@@ -4150,34 +4172,6 @@ impl<SP: Deref> Channel<SP> where
                        }
                }
 
-               let max_dust_htlc_exposure_msat = self.context.get_max_dust_htlc_exposure_msat(fee_estimator);
-               let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
-                       (0, 0)
-               } else {
-                       let dust_buffer_feerate = self.context.get_dust_buffer_feerate(None) as u64;
-                       (dust_buffer_feerate * htlc_timeout_tx_weight(self.context.get_channel_type()) / 1000,
-                               dust_buffer_feerate * htlc_success_tx_weight(self.context.get_channel_type()) / 1000)
-               };
-               let exposure_dust_limit_timeout_sats = htlc_timeout_dust_limit + self.context.counterparty_dust_limit_satoshis;
-               if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats {
-                       let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + msg.amount_msat;
-                       if on_counterparty_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
-                               log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx",
-                                       on_counterparty_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
-                               pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
-                       }
-               }
-
-               let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.context.holder_dust_limit_satoshis;
-               if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
-                       let on_holder_tx_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + msg.amount_msat;
-                       if on_holder_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
-                               log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx",
-                                       on_holder_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
-                               pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
-                       }
-               }
-
                let pending_value_to_self_msat =
                        self.context.value_to_self_msat + inbound_stats.pending_htlcs_value_msat - removed_outbound_total_msat;
                let pending_remote_value_msat =
@@ -4211,23 +4205,7 @@ impl<SP: Deref> Channel<SP> where
                } else {
                        0
                };
-               if !self.context.is_outbound() {
-                       // `Some(())` is for the fee spike buffer we keep for the remote. This deviates from
-                       // the spec because the fee spike buffer requirement doesn't exist on the receiver's
-                       // side, only on the sender's. Note that with anchor outputs we are no longer as
-                       // sensitive to fee spikes, so we need to account for them.
-                       let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
-                       let mut remote_fee_cost_incl_stuck_buffer_msat = self.context.next_remote_commit_tx_fee_msat(htlc_candidate, Some(()));
-                       if !self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
-                               remote_fee_cost_incl_stuck_buffer_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
-                       }
-                       if pending_remote_value_msat.saturating_sub(msg.amount_msat).saturating_sub(self.context.holder_selected_channel_reserve_satoshis * 1000).saturating_sub(anchor_outputs_value_msat) < remote_fee_cost_incl_stuck_buffer_msat {
-                               // Note that if the pending_forward_status is not updated here, then it's because we're already failing
-                               // the HTLC, i.e. its status is already set to failing.
-                               log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", &self.context.channel_id());
-                               pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
-                       }
-               } else {
+               if self.context.is_outbound() {
                        // Check that they won't violate our local required channel reserve by adding this HTLC.
                        let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
                        let local_commit_tx_fee_msat = self.context.next_local_commit_tx_fee_msat(htlc_candidate, None);
@@ -4255,7 +4233,9 @@ impl<SP: Deref> Channel<SP> where
                        amount_msat: msg.amount_msat,
                        payment_hash: msg.payment_hash,
                        cltv_expiry: msg.cltv_expiry,
-                       state: InboundHTLCState::RemoteAnnounced(pending_forward_status),
+                       state: InboundHTLCState::RemoteAnnounced(InboundHTLCResolution::Resolved {
+                               pending_htlc_status: pending_forward_status
+                       }),
                });
                Ok(())
        }
@@ -4461,13 +4441,13 @@ impl<SP: Deref> Channel<SP> where
                }
 
                for htlc in self.context.pending_inbound_htlcs.iter_mut() {
-                       let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
-                               Some(forward_info.clone())
+                       let htlc_resolution = if let &InboundHTLCState::RemoteAnnounced(ref resolution) = &htlc.state {
+                               Some(resolution.clone())
                        } else { None };
-                       if let Some(forward_info) = new_forward {
+                       if let Some(htlc_resolution) = htlc_resolution {
                                log_trace!(logger, "Updating HTLC {} to AwaitingRemoteRevokeToAnnounce due to commitment_signed in channel {}.",
                                        &htlc.payment_hash, &self.context.channel_id);
-                               htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info);
+                               htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce(htlc_resolution);
                                need_commitment = true;
                        }
                }
@@ -4777,6 +4757,7 @@ impl<SP: Deref> Channel<SP> where
 
                log_trace!(logger, "Updating HTLCs on receipt of RAA in channel {}...", &self.context.channel_id());
                let mut to_forward_infos = Vec::new();
+               let mut pending_update_adds = Vec::new();
                let mut revoked_htlcs = Vec::new();
                let mut finalized_claimed_htlcs = Vec::new();
                let mut update_fail_htlcs = Vec::new();
@@ -4824,29 +4805,37 @@ impl<SP: Deref> Channel<SP> where
                                        let mut state = InboundHTLCState::Committed;
                                        mem::swap(&mut state, &mut htlc.state);
 
-                                       if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state {
+                                       if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(resolution) = state {
                                                log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce {} to AwaitingAnnouncedRemoteRevoke", &htlc.payment_hash);
-                                               htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info);
+                                               htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(resolution);
                                                require_commitment = true;
-                                       } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state {
-                                               match forward_info {
-                                                       PendingHTLCStatus::Fail(fail_msg) => {
-                                                               log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to LocalRemoved due to PendingHTLCStatus indicating failure", &htlc.payment_hash);
-                                                               require_commitment = true;
-                                                               match fail_msg {
-                                                                       HTLCFailureMsg::Relay(msg) => {
-                                                                               htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone()));
-                                                                               update_fail_htlcs.push(msg)
-                                                                       },
-                                                                       HTLCFailureMsg::Malformed(msg) => {
-                                                                               htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code)));
-                                                                               update_fail_malformed_htlcs.push(msg)
+                                       } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(resolution) = state {
+                                               match resolution {
+                                                       InboundHTLCResolution::Resolved { pending_htlc_status } =>
+                                                               match pending_htlc_status {
+                                                                       PendingHTLCStatus::Fail(fail_msg) => {
+                                                                               log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to LocalRemoved due to PendingHTLCStatus indicating failure", &htlc.payment_hash);
+                                                                               require_commitment = true;
+                                                                               match fail_msg {
+                                                                                       HTLCFailureMsg::Relay(msg) => {
+                                                                                               htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone()));
+                                                                                               update_fail_htlcs.push(msg)
+                                                                                       },
+                                                                                       HTLCFailureMsg::Malformed(msg) => {
+                                                                                               htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code)));
+                                                                                               update_fail_malformed_htlcs.push(msg)
+                                                                                       },
+                                                                               }
                                                                        },
+                                                                       PendingHTLCStatus::Forward(forward_info) => {
+                                                                               log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed, attempting to forward", &htlc.payment_hash);
+                                                                               to_forward_infos.push((forward_info, htlc.htlc_id));
+                                                                               htlc.state = InboundHTLCState::Committed;
+                                                                       }
                                                                }
-                                                       },
-                                                       PendingHTLCStatus::Forward(forward_info) => {
+                                                       InboundHTLCResolution::Pending { update_add_htlc } => {
                                                                log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", &htlc.payment_hash);
-                                                               to_forward_infos.push((forward_info, htlc.htlc_id));
+                                                               pending_update_adds.push(update_add_htlc);
                                                                htlc.state = InboundHTLCState::Committed;
                                                        }
                                                }
@@ -4907,6 +4896,8 @@ impl<SP: Deref> Channel<SP> where
                        }
                }
 
+               self.context.monitor_pending_update_adds.append(&mut pending_update_adds);
+
                if self.context.channel_state.is_monitor_update_in_progress() {
                        // We can't actually generate a new commitment transaction (incl by freeing holding
                        // cells) while we can't update the monitor, so we just return what we have.
@@ -5207,13 +5198,16 @@ impl<SP: Deref> Channel<SP> where
                mem::swap(&mut failed_htlcs, &mut self.context.monitor_pending_failures);
                let mut finalized_claimed_htlcs = Vec::new();
                mem::swap(&mut finalized_claimed_htlcs, &mut self.context.monitor_pending_finalized_fulfills);
+               let mut pending_update_adds = Vec::new();
+               mem::swap(&mut pending_update_adds, &mut self.context.monitor_pending_update_adds);
 
                if self.context.channel_state.is_peer_disconnected() {
                        self.context.monitor_pending_revoke_and_ack = false;
                        self.context.monitor_pending_commitment_signed = false;
                        return MonitorRestoreUpdates {
                                raa: None, commitment_update: None, order: RAACommitmentOrder::RevokeAndACKFirst,
-                               accepted_htlcs, failed_htlcs, finalized_claimed_htlcs, funding_broadcastable, channel_ready, announcement_sigs
+                               accepted_htlcs, failed_htlcs, finalized_claimed_htlcs, pending_update_adds,
+                               funding_broadcastable, channel_ready, announcement_sigs
                        };
                }
 
@@ -5235,7 +5229,8 @@ impl<SP: Deref> Channel<SP> where
                        if commitment_update.is_some() { "a" } else { "no" }, if raa.is_some() { "an" } else { "no" },
                        match order { RAACommitmentOrder::CommitmentFirst => "commitment", RAACommitmentOrder::RevokeAndACKFirst => "RAA"});
                MonitorRestoreUpdates {
-                       raa, commitment_update, order, accepted_htlcs, failed_htlcs, finalized_claimed_htlcs, funding_broadcastable, channel_ready, announcement_sigs
+                       raa, commitment_update, order, accepted_htlcs, failed_htlcs, finalized_claimed_htlcs,
+                       pending_update_adds, funding_broadcastable, channel_ready, announcement_sigs
                }
        }
 
@@ -6099,6 +6094,86 @@ impl<SP: Deref> Channel<SP> where
                        })
        }
 
+       pub fn can_accept_incoming_htlc<F: Deref, L: Deref>(
+               &self, msg: &msgs::UpdateAddHTLC, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: L
+       ) -> Result<(), (&'static str, u16)>
+       where
+               F::Target: FeeEstimator,
+               L::Target: Logger
+       {
+               if self.context.channel_state.is_local_shutdown_sent() {
+                       return Err(("Shutdown was already sent", 0x4000|8))
+               }
+
+               let inbound_stats = self.context.get_inbound_pending_htlc_stats(None);
+               let outbound_stats = self.context.get_outbound_pending_htlc_stats(None);
+               let max_dust_htlc_exposure_msat = self.context.get_max_dust_htlc_exposure_msat(fee_estimator);
+               let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                       (0, 0)
+               } else {
+                       let dust_buffer_feerate = self.context.get_dust_buffer_feerate(None) as u64;
+                       (dust_buffer_feerate * htlc_timeout_tx_weight(self.context.get_channel_type()) / 1000,
+                               dust_buffer_feerate * htlc_success_tx_weight(self.context.get_channel_type()) / 1000)
+               };
+               let exposure_dust_limit_timeout_sats = htlc_timeout_dust_limit + self.context.counterparty_dust_limit_satoshis;
+               if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats {
+                       let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + msg.amount_msat;
+                       if on_counterparty_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
+                               log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx",
+                                       on_counterparty_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
+                               return Err(("Exceeded our dust exposure limit on counterparty commitment tx", 0x1000|7))
+                       }
+               }
+
+               let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.context.holder_dust_limit_satoshis;
+               if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
+                       let on_holder_tx_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + msg.amount_msat;
+                       if on_holder_tx_dust_htlc_exposure_msat > max_dust_htlc_exposure_msat {
+                               log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx",
+                                       on_holder_tx_dust_htlc_exposure_msat, max_dust_htlc_exposure_msat);
+                               return Err(("Exceeded our dust exposure limit on holder commitment tx", 0x1000|7))
+                       }
+               }
+
+               let anchor_outputs_value_msat = if self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                       ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000
+               } else {
+                       0
+               };
+
+               let mut removed_outbound_total_msat = 0;
+               for ref htlc in self.context.pending_outbound_htlcs.iter() {
+                       if let OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_)) = htlc.state {
+                               removed_outbound_total_msat += htlc.amount_msat;
+                       } else if let OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) = htlc.state {
+                               removed_outbound_total_msat += htlc.amount_msat;
+                       }
+               }
+
+               let pending_value_to_self_msat =
+                       self.context.value_to_self_msat + inbound_stats.pending_htlcs_value_msat - removed_outbound_total_msat;
+               let pending_remote_value_msat =
+                       self.context.channel_value_satoshis * 1000 - pending_value_to_self_msat;
+
+               if !self.context.is_outbound() {
+                       // `Some(())` is for the fee spike buffer we keep for the remote. This deviates from
+                       // the spec because the fee spike buffer requirement doesn't exist on the receiver's
+                       // side, only on the sender's. Note that with anchor outputs we are no longer as
+                       // sensitive to fee spikes, so we need to account for them.
+                       let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
+                       let mut remote_fee_cost_incl_stuck_buffer_msat = self.context.next_remote_commit_tx_fee_msat(htlc_candidate, Some(()));
+                       if !self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                               remote_fee_cost_incl_stuck_buffer_msat *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
+                       }
+                       if pending_remote_value_msat.saturating_sub(msg.amount_msat).saturating_sub(self.context.holder_selected_channel_reserve_satoshis * 1000).saturating_sub(anchor_outputs_value_msat) < remote_fee_cost_incl_stuck_buffer_msat {
+                               log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", &self.context.channel_id());
+                               return Err(("Fee spike buffer violation", 0x1000|7));
+                       }
+               }
+
+               Ok(())
+       }
+
        pub fn get_cur_holder_commitment_transaction_number(&self) -> u64 {
                self.context.cur_holder_commitment_transaction_number + 1
        }
@@ -8232,7 +8307,7 @@ fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures)
        ret
 }
 
-const SERIALIZATION_VERSION: u8 = 3;
+const SERIALIZATION_VERSION: u8 = 4;
 const MIN_SERIALIZATION_VERSION: u8 = 3;
 
 impl_writeable_tlv_based_enum!(InboundHTLCRemovalReason,;
@@ -8294,7 +8369,18 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
                // Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
                // called.
 
-               write_ver_prefix!(writer, MIN_SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
+               let version_to_write = if self.context.pending_inbound_htlcs.iter().any(|htlc| match htlc.state {
+                       InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_resolution)|
+                               InboundHTLCState::AwaitingAnnouncedRemoteRevoke(ref htlc_resolution) => {
+                               matches!(htlc_resolution, InboundHTLCResolution::Pending { .. })
+                       },
+                       _ => false,
+               }) {
+                       SERIALIZATION_VERSION
+               } else {
+                       MIN_SERIALIZATION_VERSION
+               };
+               write_ver_prefix!(writer, version_to_write, MIN_SERIALIZATION_VERSION);
 
                // `user_id` used to be a single u64 value. In order to remain backwards compatible with
                // versions prior to 0.0.113, the u128 is serialized as two separate u64 values. We write
@@ -8350,13 +8436,29 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
                        htlc.payment_hash.write(writer)?;
                        match &htlc.state {
                                &InboundHTLCState::RemoteAnnounced(_) => unreachable!(),
-                               &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_state) => {
+                               &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_resolution) => {
                                        1u8.write(writer)?;
-                                       htlc_state.write(writer)?;
+                                       if version_to_write <= 3 {
+                                               if let InboundHTLCResolution::Resolved { pending_htlc_status } = htlc_resolution {
+                                                       pending_htlc_status.write(writer)?;
+                                               } else {
+                                                       panic!();
+                                               }
+                                       } else {
+                                               htlc_resolution.write(writer)?;
+                                       }
                                },
-                               &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(ref htlc_state) => {
+                               &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(ref htlc_resolution) => {
                                        2u8.write(writer)?;
-                                       htlc_state.write(writer)?;
+                                       if version_to_write <= 3 {
+                                               if let InboundHTLCResolution::Resolved { pending_htlc_status } = htlc_resolution {
+                                                       pending_htlc_status.write(writer)?;
+                                               } else {
+                                                       panic!();
+                                               }
+                                       } else {
+                                               htlc_resolution.write(writer)?;
+                                       }
                                },
                                &InboundHTLCState::Committed => {
                                        3u8.write(writer)?;
@@ -8582,6 +8684,11 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
 
                let holder_max_accepted_htlcs = if self.context.holder_max_accepted_htlcs == DEFAULT_MAX_HTLCS { None } else { Some(self.context.holder_max_accepted_htlcs) };
 
+               let mut monitor_pending_update_adds = None;
+               if !self.context.monitor_pending_update_adds.is_empty() {
+                       monitor_pending_update_adds = Some(&self.context.monitor_pending_update_adds);
+               }
+
                write_tlv_fields!(writer, {
                        (0, self.context.announcement_sigs, option),
                        // minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
@@ -8599,6 +8706,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
                        (7, self.context.shutdown_scriptpubkey, option),
                        (8, self.context.blocked_monitor_updates, optional_vec),
                        (9, self.context.target_closing_feerate_sats_per_kw, option),
+                       (10, monitor_pending_update_adds, option), // Added in 0.0.122
                        (11, self.context.monitor_pending_finalized_fulfills, required_vec),
                        (13, self.context.channel_creation_height, required),
                        (15, preimages, required_vec),
@@ -8617,7 +8725,8 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
                        (39, pending_outbound_blinding_points, optional_vec),
                        (41, holding_cell_blinding_points, optional_vec),
                        (43, malformed_htlcs, optional_vec), // Added in 0.0.119
-                       (45, self.context.local_initiated_shutdown, option), // Added in 0.0.122
+                       // 45 and 47 are reserved for async signing
+                       (49, self.context.local_initiated_shutdown, option), // Added in 0.0.122
                });
 
                Ok(())
@@ -8693,8 +8802,22 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                                cltv_expiry: Readable::read(reader)?,
                                payment_hash: Readable::read(reader)?,
                                state: match <u8 as Readable>::read(reader)? {
-                                       1 => InboundHTLCState::AwaitingRemoteRevokeToAnnounce(Readable::read(reader)?),
-                                       2 => InboundHTLCState::AwaitingAnnouncedRemoteRevoke(Readable::read(reader)?),
+                                       1 => {
+                                               let resolution = if ver <= 3 {
+                                                       InboundHTLCResolution::Resolved { pending_htlc_status: Readable::read(reader)? }
+                                               } else {
+                                                       Readable::read(reader)?
+                                               };
+                                               InboundHTLCState::AwaitingRemoteRevokeToAnnounce(resolution)
+                                       },
+                                       2 => {
+                                               let resolution = if ver <= 3 {
+                                                       InboundHTLCResolution::Resolved { pending_htlc_status: Readable::read(reader)? }
+                                               } else {
+                                                       Readable::read(reader)?
+                                               };
+                                               InboundHTLCState::AwaitingAnnouncedRemoteRevoke(resolution)
+                                       },
                                        3 => InboundHTLCState::Committed,
                                        4 => InboundHTLCState::LocalRemoved(Readable::read(reader)?),
                                        _ => return Err(DecodeError::InvalidValue),
@@ -8911,6 +9034,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                let mut holding_cell_blinding_points_opt: Option<Vec<Option<PublicKey>>> = None;
 
                let mut malformed_htlcs: Option<Vec<(u64, u16, [u8; 32])>> = None;
+               let mut monitor_pending_update_adds: Option<Vec<msgs::UpdateAddHTLC>> = None;
 
                read_tlv_fields!(reader, {
                        (0, announcement_sigs, option),
@@ -8923,6 +9047,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                        (7, shutdown_scriptpubkey, option),
                        (8, blocked_monitor_updates, optional_vec),
                        (9, target_closing_feerate_sats_per_kw, option),
+                       (10, monitor_pending_update_adds, option), // Added in 0.0.122
                        (11, monitor_pending_finalized_fulfills, optional_vec),
                        (13, channel_creation_height, option),
                        (15, preimages_opt, optional_vec),
@@ -8941,7 +9066,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                        (39, pending_outbound_blinding_points_opt, optional_vec),
                        (41, holding_cell_blinding_points_opt, optional_vec),
                        (43, malformed_htlcs, optional_vec), // Added in 0.0.119
-                       (45, local_initiated_shutdown, option),
+                       // 45 and 47 are reserved for async signing
+                       (49, local_initiated_shutdown, option),
                });
 
                let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id {
@@ -9094,6 +9220,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                                monitor_pending_forwards,
                                monitor_pending_failures,
                                monitor_pending_finalized_fulfills: monitor_pending_finalized_fulfills.unwrap(),
+                               monitor_pending_update_adds: monitor_pending_update_adds.unwrap_or(Vec::new()),
 
                                signer_pending_commitment_update: false,
                                signer_pending_funding: false,
index bddcd4c9b8117b7884228161757028d118dc7af0..fa8a0b2163d2ffcb828d34c07675f8ee823e9e99 100644 (file)
@@ -903,7 +903,7 @@ pub(super) struct PeerState<SP: Deref> where SP::Target: SignerProvider {
        /// The peer is currently connected (i.e. we've seen a
        /// [`ChannelMessageHandler::peer_connected`] and no corresponding
        /// [`ChannelMessageHandler::peer_disconnected`].
-       is_connected: bool,
+       pub is_connected: bool,
 }
 
 impl <SP: Deref> PeerState<SP> where SP::Target: SignerProvider {
@@ -1109,11 +1109,620 @@ where
        fn get_cm(&self) -> &ChannelManager<M, T, ES, NS, SP, F, R, L> { self }
 }
 
-/// Manager which keeps track of a number of channels and sends messages to the appropriate
-/// channel, also tracking HTLC preimages and forwarding onion packets appropriately.
+/// A lightning node's channel state machine and payment management logic, which facilitates
+/// sending, forwarding, and receiving payments through lightning channels.
 ///
-/// Implements [`ChannelMessageHandler`], handling the multi-channel parts and passing things through
-/// to individual Channels.
+/// [`ChannelManager`] is parameterized by a number of components to achieve this.
+/// - [`chain::Watch`] (typically [`ChainMonitor`]) for on-chain monitoring and enforcement of each
+///   channel
+/// - [`BroadcasterInterface`] for broadcasting transactions related to opening, funding, and
+///   closing channels
+/// - [`EntropySource`] for providing random data needed for cryptographic operations
+/// - [`NodeSigner`] for cryptographic operations scoped to the node
+/// - [`SignerProvider`] for providing signers whose operations are scoped to individual channels
+/// - [`FeeEstimator`] to determine transaction fee rates needed to have a transaction mined in a
+///   timely manner
+/// - [`Router`] for finding payment paths when initiating and retrying payments
+/// - [`Logger`] for logging operational information of varying degrees
+///
+/// Additionally, it implements the following traits:
+/// - [`ChannelMessageHandler`] to handle off-chain channel activity from peers
+/// - [`MessageSendEventsProvider`] to similarly send such messages to peers
+/// - [`OffersMessageHandler`] for BOLT 12 message handling and sending
+/// - [`EventsProvider`] to generate user-actionable [`Event`]s
+/// - [`chain::Listen`] and [`chain::Confirm`] for notification of on-chain activity
+///
+/// Thus, [`ChannelManager`] is typically used to parameterize a [`MessageHandler`] and an
+/// [`OnionMessenger`]. The latter is required to support BOLT 12 functionality.
+///
+/// # `ChannelManager` vs `ChannelMonitor`
+///
+/// It's important to distinguish between the *off-chain* management and *on-chain* enforcement of
+/// lightning channels. [`ChannelManager`] exchanges messages with peers to manage the off-chain
+/// state of each channel. During this process, it generates a [`ChannelMonitor`] for each channel
+/// and a [`ChannelMonitorUpdate`] for each relevant change, notifying its parameterized
+/// [`chain::Watch`] of them.
+///
+/// An implementation of [`chain::Watch`], such as [`ChainMonitor`], is responsible for aggregating
+/// these [`ChannelMonitor`]s and applying any [`ChannelMonitorUpdate`]s to them. It then monitors
+/// for any pertinent on-chain activity, enforcing claims as needed.
+///
+/// This division of off-chain management and on-chain enforcement allows for interesting node
+/// setups. For instance, on-chain enforcement could be moved to a separate host or have added
+/// redundancy, possibly as a watchtower. See [`chain::Watch`] for the relevant interface.
+///
+/// # Initialization
+///
+/// Use [`ChannelManager::new`] with the most recent [`BlockHash`] when creating a fresh instance.
+/// Otherwise, if restarting, construct [`ChannelManagerReadArgs`] with the necessary parameters and
+/// references to any deserialized [`ChannelMonitor`]s that were previously persisted. Use this to
+/// deserialize the [`ChannelManager`] and feed it any new chain data since it was last online, as
+/// detailed in the [`ChannelManagerReadArgs`] documentation.
+///
+/// ```
+/// use bitcoin::BlockHash;
+/// use bitcoin::network::constants::Network;
+/// use lightning::chain::BestBlock;
+/// # use lightning::chain::channelmonitor::ChannelMonitor;
+/// use lightning::ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs};
+/// # use lightning::routing::gossip::NetworkGraph;
+/// use lightning::util::config::UserConfig;
+/// use lightning::util::ser::ReadableArgs;
+///
+/// # fn read_channel_monitors() -> Vec<ChannelMonitor<lightning::sign::InMemorySigner>> { vec![] }
+/// # fn example<
+/// #     'a,
+/// #     L: lightning::util::logger::Logger,
+/// #     ES: lightning::sign::EntropySource,
+/// #     S: for <'b> lightning::routing::scoring::LockableScore<'b, ScoreLookUp = SL>,
+/// #     SL: lightning::routing::scoring::ScoreLookUp<ScoreParams = SP>,
+/// #     SP: Sized,
+/// #     R: lightning::io::Read,
+/// # >(
+/// #     fee_estimator: &dyn lightning::chain::chaininterface::FeeEstimator,
+/// #     chain_monitor: &dyn lightning::chain::Watch<lightning::sign::InMemorySigner>,
+/// #     tx_broadcaster: &dyn lightning::chain::chaininterface::BroadcasterInterface,
+/// #     router: &lightning::routing::router::DefaultRouter<&NetworkGraph<&'a L>, &'a L, &ES, &S, SP, SL>,
+/// #     logger: &L,
+/// #     entropy_source: &ES,
+/// #     node_signer: &dyn lightning::sign::NodeSigner,
+/// #     signer_provider: &lightning::sign::DynSignerProvider,
+/// #     best_block: lightning::chain::BestBlock,
+/// #     current_timestamp: u32,
+/// #     mut reader: R,
+/// # ) -> Result<(), lightning::ln::msgs::DecodeError> {
+/// // Fresh start with no channels
+/// let params = ChainParameters {
+///     network: Network::Bitcoin,
+///     best_block,
+/// };
+/// let default_config = UserConfig::default();
+/// let channel_manager = ChannelManager::new(
+///     fee_estimator, chain_monitor, tx_broadcaster, router, logger, entropy_source, node_signer,
+///     signer_provider, default_config, params, current_timestamp
+/// );
+///
+/// // Restart from deserialized data
+/// let mut channel_monitors = read_channel_monitors();
+/// let args = ChannelManagerReadArgs::new(
+///     entropy_source, node_signer, signer_provider, fee_estimator, chain_monitor, tx_broadcaster,
+///     router, logger, default_config, channel_monitors.iter_mut().collect()
+/// );
+/// let (block_hash, channel_manager) =
+///     <(BlockHash, ChannelManager<_, _, _, _, _, _, _, _>)>::read(&mut reader, args)?;
+///
+/// // Update the ChannelManager and ChannelMonitors with the latest chain data
+/// // ...
+///
+/// // Move the monitors to the ChannelManager's chain::Watch parameter
+/// for monitor in channel_monitors {
+///     chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor);
+/// }
+/// # Ok(())
+/// # }
+/// ```
+///
+/// # Operation
+///
+/// The following is required for [`ChannelManager`] to function properly:
+/// - Handle messages from peers using its [`ChannelMessageHandler`] implementation (typically
+///   called by [`PeerManager::read_event`] when processing network I/O)
+/// - Send messages to peers obtained via its [`MessageSendEventsProvider`] implementation
+///   (typically initiated when [`PeerManager::process_events`] is called)
+/// - Feed on-chain activity using either its [`chain::Listen`] or [`chain::Confirm`] implementation
+///   as documented by those traits
+/// - Perform any periodic channel and payment checks by calling [`timer_tick_occurred`] roughly
+///   every minute
+/// - Persist to disk whenever [`get_and_clear_needs_persistence`] returns `true` using a
+///   [`Persister`] such as a [`KVStore`] implementation
+/// - Handle [`Event`]s obtained via its [`EventsProvider`] implementation
+///
+/// The [`Future`] returned by [`get_event_or_persistence_needed_future`] is useful in determining
+/// when the last two requirements need to be checked.
+///
+/// The [`lightning-block-sync`] and [`lightning-transaction-sync`] crates provide utilities that
+/// simplify feeding in on-chain activity using the [`chain::Listen`] and [`chain::Confirm`] traits,
+/// respectively. The remaining requirements can be met using the [`lightning-background-processor`]
+/// crate. For languages other than Rust, the availability of similar utilities may vary.
+///
+/// # Channels
+///
+/// [`ChannelManager`]'s primary function involves managing a channel state. Without channels,
+/// payments can't be sent. Use [`list_channels`] or [`list_usable_channels`] for a snapshot of the
+/// currently open channels.
+///
+/// ```
+/// # use lightning::ln::channelmanager::AChannelManager;
+/// #
+/// # fn example<T: AChannelManager>(channel_manager: T) {
+/// # let channel_manager = channel_manager.get_cm();
+/// let channels = channel_manager.list_usable_channels();
+/// for details in channels {
+///     println!("{:?}", details);
+/// }
+/// # }
+/// ```
+///
+/// Each channel is identified using a [`ChannelId`], which will change throughout the channel's
+/// life cycle. Additionally, channels are assigned a `user_channel_id`, which is given in
+/// [`Event`]s associated with the channel and serves as a fixed identifier but is otherwise unused
+/// by [`ChannelManager`].
+///
+/// ## Opening Channels
+///
+/// To an open a channel with a peer, call [`create_channel`]. This will initiate the process of
+/// opening an outbound channel, which requires self-funding when handling
+/// [`Event::FundingGenerationReady`].
+///
+/// ```
+/// # use bitcoin::{ScriptBuf, Transaction};
+/// # use bitcoin::secp256k1::PublicKey;
+/// # use lightning::ln::channelmanager::AChannelManager;
+/// # use lightning::events::{Event, EventsProvider};
+/// #
+/// # trait Wallet {
+/// #     fn create_funding_transaction(
+/// #         &self, _amount_sats: u64, _output_script: ScriptBuf
+/// #     ) -> Transaction;
+/// # }
+/// #
+/// # fn example<T: AChannelManager, W: Wallet>(channel_manager: T, wallet: W, peer_id: PublicKey) {
+/// # let channel_manager = channel_manager.get_cm();
+/// let value_sats = 1_000_000;
+/// let push_msats = 10_000_000;
+/// match channel_manager.create_channel(peer_id, value_sats, push_msats, 42, None, None) {
+///     Ok(channel_id) => println!("Opening channel {}", channel_id),
+///     Err(e) => println!("Error opening channel: {:?}", e),
+/// }
+///
+/// // On the event processing thread once the peer has responded
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::FundingGenerationReady {
+///         temporary_channel_id, counterparty_node_id, channel_value_satoshis, output_script,
+///         user_channel_id, ..
+///     } => {
+///         assert_eq!(user_channel_id, 42);
+///         let funding_transaction = wallet.create_funding_transaction(
+///             channel_value_satoshis, output_script
+///         );
+///         match channel_manager.funding_transaction_generated(
+///             &temporary_channel_id, &counterparty_node_id, funding_transaction
+///         ) {
+///             Ok(()) => println!("Funding channel {}", temporary_channel_id),
+///             Err(e) => println!("Error funding channel {}: {:?}", temporary_channel_id, e),
+///         }
+///     },
+///     Event::ChannelPending { channel_id, user_channel_id, former_temporary_channel_id, .. } => {
+///         assert_eq!(user_channel_id, 42);
+///         println!(
+///             "Channel {} now {} pending (funding transaction has been broadcasted)", channel_id,
+///             former_temporary_channel_id.unwrap()
+///         );
+///     },
+///     Event::ChannelReady { channel_id, user_channel_id, .. } => {
+///         assert_eq!(user_channel_id, 42);
+///         println!("Channel {} ready", channel_id);
+///     },
+///     // ...
+/// #     _ => {},
+/// });
+/// # }
+/// ```
+///
+/// ## Accepting Channels
+///
+/// Inbound channels are initiated by peers and are automatically accepted unless [`ChannelManager`]
+/// has [`UserConfig::manually_accept_inbound_channels`] set. In that case, the channel may be
+/// either accepted or rejected when handling [`Event::OpenChannelRequest`].
+///
+/// ```
+/// # use bitcoin::secp256k1::PublicKey;
+/// # use lightning::ln::channelmanager::AChannelManager;
+/// # use lightning::events::{Event, EventsProvider};
+/// #
+/// # fn is_trusted(counterparty_node_id: PublicKey) -> bool {
+/// #     // ...
+/// #     unimplemented!()
+/// # }
+/// #
+/// # fn example<T: AChannelManager>(channel_manager: T) {
+/// # let channel_manager = channel_manager.get_cm();
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::OpenChannelRequest { temporary_channel_id, counterparty_node_id, ..  } => {
+///         if !is_trusted(counterparty_node_id) {
+///             match channel_manager.force_close_without_broadcasting_txn(
+///                 &temporary_channel_id, &counterparty_node_id
+///             ) {
+///                 Ok(()) => println!("Rejecting channel {}", temporary_channel_id),
+///                 Err(e) => println!("Error rejecting channel {}: {:?}", temporary_channel_id, e),
+///             }
+///             return;
+///         }
+///
+///         let user_channel_id = 43;
+///         match channel_manager.accept_inbound_channel(
+///             &temporary_channel_id, &counterparty_node_id, user_channel_id
+///         ) {
+///             Ok(()) => println!("Accepting channel {}", temporary_channel_id),
+///             Err(e) => println!("Error accepting channel {}: {:?}", temporary_channel_id, e),
+///         }
+///     },
+///     // ...
+/// #     _ => {},
+/// });
+/// # }
+/// ```
+///
+/// ## Closing Channels
+///
+/// There are two ways to close a channel: either cooperatively using [`close_channel`] or
+/// unilaterally using [`force_close_broadcasting_latest_txn`]. The former is ideal as it makes for
+/// lower fees and immediate access to funds. However, the latter may be necessary if the
+/// counterparty isn't behaving properly or has gone offline. [`Event::ChannelClosed`] is generated
+/// once the channel has been closed successfully.
+///
+/// ```
+/// # use bitcoin::secp256k1::PublicKey;
+/// # use lightning::ln::ChannelId;
+/// # use lightning::ln::channelmanager::AChannelManager;
+/// # use lightning::events::{Event, EventsProvider};
+/// #
+/// # fn example<T: AChannelManager>(
+/// #     channel_manager: T, channel_id: ChannelId, counterparty_node_id: PublicKey
+/// # ) {
+/// # let channel_manager = channel_manager.get_cm();
+/// match channel_manager.close_channel(&channel_id, &counterparty_node_id) {
+///     Ok(()) => println!("Closing channel {}", channel_id),
+///     Err(e) => println!("Error closing channel {}: {:?}", channel_id, e),
+/// }
+///
+/// // On the event processing thread
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::ChannelClosed { channel_id, user_channel_id, ..  } => {
+///         assert_eq!(user_channel_id, 42);
+///         println!("Channel {} closed", channel_id);
+///     },
+///     // ...
+/// #     _ => {},
+/// });
+/// # }
+/// ```
+///
+/// # Payments
+///
+/// [`ChannelManager`] is responsible for sending, forwarding, and receiving payments through its
+/// channels. A payment is typically initiated from a [BOLT 11] invoice or a [BOLT 12] offer, though
+/// spontaneous (i.e., keysend) payments are also possible. Incoming payments don't require
+/// maintaining any additional state as [`ChannelManager`] can reconstruct the [`PaymentPreimage`]
+/// from the [`PaymentSecret`]. Sending payments, however, require tracking in order to retry failed
+/// HTLCs.
+///
+/// After a payment is initiated, it will appear in [`list_recent_payments`] until a short time
+/// after either an [`Event::PaymentSent`] or [`Event::PaymentFailed`] is handled. Failed HTLCs
+/// for a payment will be retried according to the payment's [`Retry`] strategy or until
+/// [`abandon_payment`] is called.
+///
+/// ## BOLT 11 Invoices
+///
+/// The [`lightning-invoice`] crate is useful for creating BOLT 11 invoices. Specifically, use the
+/// functions in its `utils` module for constructing invoices that are compatible with
+/// [`ChannelManager`]. These functions serve as a convenience for building invoices with the
+/// [`PaymentHash`] and [`PaymentSecret`] returned from [`create_inbound_payment`]. To provide your
+/// own [`PaymentHash`], use [`create_inbound_payment_for_hash`] or the corresponding functions in
+/// the [`lightning-invoice`] `utils` module.
+///
+/// [`ChannelManager`] generates an [`Event::PaymentClaimable`] once the full payment has been
+/// received. Call [`claim_funds`] to release the [`PaymentPreimage`], which in turn will result in
+/// an [`Event::PaymentClaimed`].
+///
+/// ```
+/// # use lightning::events::{Event, EventsProvider, PaymentPurpose};
+/// # use lightning::ln::channelmanager::AChannelManager;
+/// #
+/// # fn example<T: AChannelManager>(channel_manager: T) {
+/// # let channel_manager = channel_manager.get_cm();
+/// // Or use utils::create_invoice_from_channelmanager
+/// let known_payment_hash = match channel_manager.create_inbound_payment(
+///     Some(10_000_000), 3600, None
+/// ) {
+///     Ok((payment_hash, _payment_secret)) => {
+///         println!("Creating inbound payment {}", payment_hash);
+///         payment_hash
+///     },
+///     Err(()) => panic!("Error creating inbound payment"),
+/// };
+///
+/// // On the event processing thread
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::PaymentClaimable { payment_hash, purpose, .. } => match purpose {
+///         PaymentPurpose::InvoicePayment { payment_preimage: Some(payment_preimage), .. } => {
+///             assert_eq!(payment_hash, known_payment_hash);
+///             println!("Claiming payment {}", payment_hash);
+///             channel_manager.claim_funds(payment_preimage);
+///         },
+///         PaymentPurpose::InvoicePayment { payment_preimage: None, .. } => {
+///             println!("Unknown payment hash: {}", payment_hash);
+///         },
+///         PaymentPurpose::SpontaneousPayment(payment_preimage) => {
+///             assert_ne!(payment_hash, known_payment_hash);
+///             println!("Claiming spontaneous payment {}", payment_hash);
+///             channel_manager.claim_funds(payment_preimage);
+///         },
+///     },
+///     Event::PaymentClaimed { payment_hash, amount_msat, .. } => {
+///         assert_eq!(payment_hash, known_payment_hash);
+///         println!("Claimed {} msats", amount_msat);
+///     },
+///     // ...
+/// #     _ => {},
+/// });
+/// # }
+/// ```
+///
+/// For paying an invoice, [`lightning-invoice`] provides a `payment` module with convenience
+/// functions for use with [`send_payment`].
+///
+/// ```
+/// # use lightning::events::{Event, EventsProvider};
+/// # use lightning::ln::PaymentHash;
+/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, RecipientOnionFields, Retry};
+/// # use lightning::routing::router::RouteParameters;
+/// #
+/// # fn example<T: AChannelManager>(
+/// #     channel_manager: T, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
+/// #     route_params: RouteParameters, retry: Retry
+/// # ) {
+/// # let channel_manager = channel_manager.get_cm();
+/// // let (payment_hash, recipient_onion, route_params) =
+/// //     payment::payment_parameters_from_invoice(&invoice);
+/// let payment_id = PaymentId([42; 32]);
+/// match channel_manager.send_payment(
+///     payment_hash, recipient_onion, payment_id, route_params, retry
+/// ) {
+///     Ok(()) => println!("Sending payment with hash {}", payment_hash),
+///     Err(e) => println!("Failed sending payment with hash {}: {:?}", payment_hash, e),
+/// }
+///
+/// let expected_payment_id = payment_id;
+/// let expected_payment_hash = payment_hash;
+/// assert!(
+///     channel_manager.list_recent_payments().iter().find(|details| matches!(
+///         details,
+///         RecentPaymentDetails::Pending {
+///             payment_id: expected_payment_id,
+///             payment_hash: expected_payment_hash,
+///             ..
+///         }
+///     )).is_some()
+/// );
+///
+/// // On the event processing thread
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::PaymentSent { payment_hash, .. } => println!("Paid {}", payment_hash),
+///     Event::PaymentFailed { payment_hash, .. } => println!("Failed paying {}", payment_hash),
+///     // ...
+/// #     _ => {},
+/// });
+/// # }
+/// ```
+///
+/// ## BOLT 12 Offers
+///
+/// The [`offers`] module is useful for creating BOLT 12 offers. An [`Offer`] is a precursor to a
+/// [`Bolt12Invoice`], which must first be requested by the payer. The interchange of these messages
+/// as defined in the specification is handled by [`ChannelManager`] and its implementation of
+/// [`OffersMessageHandler`]. However, this only works with an [`Offer`] created using a builder
+/// returned by [`create_offer_builder`]. With this approach, BOLT 12 offers and invoices are
+/// stateless just as BOLT 11 invoices are.
+///
+/// ```
+/// # use lightning::events::{Event, EventsProvider, PaymentPurpose};
+/// # use lightning::ln::channelmanager::AChannelManager;
+/// # use lightning::offers::parse::Bolt12SemanticError;
+/// #
+/// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> {
+/// # let channel_manager = channel_manager.get_cm();
+/// let offer = channel_manager
+///     .create_offer_builder("coffee".to_string())?
+/// # ;
+/// # // Needed for compiling for c_bindings
+/// # let builder: lightning::offers::offer::OfferBuilder<_, _> = offer.into();
+/// # let offer = builder
+///     .amount_msats(10_000_000)
+///     .build()?;
+/// let bech32_offer = offer.to_string();
+///
+/// // On the event processing thread
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::PaymentClaimable { payment_hash, purpose, .. } => match purpose {
+///         PaymentPurpose::InvoicePayment { payment_preimage: Some(payment_preimage), .. } => {
+///             println!("Claiming payment {}", payment_hash);
+///             channel_manager.claim_funds(payment_preimage);
+///         },
+///         PaymentPurpose::InvoicePayment { payment_preimage: None, .. } => {
+///             println!("Unknown payment hash: {}", payment_hash);
+///         },
+///         // ...
+/// #         _ => {},
+///     },
+///     Event::PaymentClaimed { payment_hash, amount_msat, .. } => {
+///         println!("Claimed {} msats", amount_msat);
+///     },
+///     // ...
+/// #     _ => {},
+/// });
+/// # Ok(())
+/// # }
+/// ```
+///
+/// Use [`pay_for_offer`] to initiated payment, which sends an [`InvoiceRequest`] for an [`Offer`]
+/// and pays the [`Bolt12Invoice`] response. In addition to success and failure events,
+/// [`ChannelManager`] may also generate an [`Event::InvoiceRequestFailed`].
+///
+/// ```
+/// # use lightning::events::{Event, EventsProvider};
+/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
+/// # use lightning::offers::offer::Offer;
+/// #
+/// # fn example<T: AChannelManager>(
+/// #     channel_manager: T, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
+/// #     payer_note: Option<String>, retry: Retry, max_total_routing_fee_msat: Option<u64>
+/// # ) {
+/// # let channel_manager = channel_manager.get_cm();
+/// let payment_id = PaymentId([42; 32]);
+/// match channel_manager.pay_for_offer(
+///     offer, quantity, amount_msats, payer_note, payment_id, retry, max_total_routing_fee_msat
+/// ) {
+///     Ok(()) => println!("Requesting invoice for offer"),
+///     Err(e) => println!("Unable to request invoice for offer: {:?}", e),
+/// }
+///
+/// // First the payment will be waiting on an invoice
+/// let expected_payment_id = payment_id;
+/// assert!(
+///     channel_manager.list_recent_payments().iter().find(|details| matches!(
+///         details,
+///         RecentPaymentDetails::AwaitingInvoice { payment_id: expected_payment_id }
+///     )).is_some()
+/// );
+///
+/// // Once the invoice is received, a payment will be sent
+/// assert!(
+///     channel_manager.list_recent_payments().iter().find(|details| matches!(
+///         details,
+///         RecentPaymentDetails::Pending { payment_id: expected_payment_id, ..  }
+///     )).is_some()
+/// );
+///
+/// // On the event processing thread
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::PaymentSent { payment_id: Some(payment_id), .. } => println!("Paid {}", payment_id),
+///     Event::PaymentFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
+///     Event::InvoiceRequestFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
+///     // ...
+/// #     _ => {},
+/// });
+/// # }
+/// ```
+///
+/// ## BOLT 12 Refunds
+///
+/// A [`Refund`] is a request for an invoice to be paid. Like *paying* for an [`Offer`], *creating*
+/// a [`Refund`] involves maintaining state since it represents a future outbound payment.
+/// Therefore, use [`create_refund_builder`] when creating one, otherwise [`ChannelManager`] will
+/// refuse to pay any corresponding [`Bolt12Invoice`] that it receives.
+///
+/// ```
+/// # use core::time::Duration;
+/// # use lightning::events::{Event, EventsProvider};
+/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
+/// # use lightning::offers::parse::Bolt12SemanticError;
+/// #
+/// # fn example<T: AChannelManager>(
+/// #     channel_manager: T, amount_msats: u64, absolute_expiry: Duration, retry: Retry,
+/// #     max_total_routing_fee_msat: Option<u64>
+/// # ) -> Result<(), Bolt12SemanticError> {
+/// # let channel_manager = channel_manager.get_cm();
+/// let payment_id = PaymentId([42; 32]);
+/// let refund = channel_manager
+///     .create_refund_builder(
+///         "coffee".to_string(), amount_msats, absolute_expiry, payment_id, retry,
+///         max_total_routing_fee_msat
+///     )?
+/// # ;
+/// # // Needed for compiling for c_bindings
+/// # let builder: lightning::offers::refund::RefundBuilder<_> = refund.into();
+/// # let refund = builder
+///     .payer_note("refund for order 1234".to_string())
+///     .build()?;
+/// let bech32_refund = refund.to_string();
+///
+/// // First the payment will be waiting on an invoice
+/// let expected_payment_id = payment_id;
+/// assert!(
+///     channel_manager.list_recent_payments().iter().find(|details| matches!(
+///         details,
+///         RecentPaymentDetails::AwaitingInvoice { payment_id: expected_payment_id }
+///     )).is_some()
+/// );
+///
+/// // Once the invoice is received, a payment will be sent
+/// assert!(
+///     channel_manager.list_recent_payments().iter().find(|details| matches!(
+///         details,
+///         RecentPaymentDetails::Pending { payment_id: expected_payment_id, ..  }
+///     )).is_some()
+/// );
+///
+/// // On the event processing thread
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::PaymentSent { payment_id: Some(payment_id), .. } => println!("Paid {}", payment_id),
+///     Event::PaymentFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
+///     // ...
+/// #     _ => {},
+/// });
+/// # Ok(())
+/// # }
+/// ```
+///
+/// Use [`request_refund_payment`] to send a [`Bolt12Invoice`] for receiving the refund. Similar to
+/// *creating* an [`Offer`], this is stateless as it represents an inbound payment.
+///
+/// ```
+/// # use lightning::events::{Event, EventsProvider, PaymentPurpose};
+/// # use lightning::ln::channelmanager::AChannelManager;
+/// # use lightning::offers::refund::Refund;
+/// #
+/// # fn example<T: AChannelManager>(channel_manager: T, refund: &Refund) {
+/// # let channel_manager = channel_manager.get_cm();
+/// match channel_manager.request_refund_payment(refund) {
+///     Ok(()) => println!("Requesting payment for refund"),
+///     Err(e) => println!("Unable to request payment for refund: {:?}", e),
+/// }
+///
+/// // On the event processing thread
+/// channel_manager.process_pending_events(&|event| match event {
+///     Event::PaymentClaimable { payment_hash, purpose, .. } => match purpose {
+///            PaymentPurpose::InvoicePayment { payment_preimage: Some(payment_preimage), .. } => {
+///             println!("Claiming payment {}", payment_hash);
+///             channel_manager.claim_funds(payment_preimage);
+///         },
+///            PaymentPurpose::InvoicePayment { payment_preimage: None, .. } => {
+///             println!("Unknown payment hash: {}", payment_hash);
+///            },
+///         // ...
+/// #         _ => {},
+///     },
+///     Event::PaymentClaimed { payment_hash, amount_msat, .. } => {
+///         println!("Claimed {} msats", amount_msat);
+///     },
+///     // ...
+/// #     _ => {},
+/// });
+/// # }
+/// ```
+///
+/// # Persistence
 ///
 /// Implements [`Writeable`] to write out all channel state to disk. Implies [`peer_disconnected`] for
 /// all peers during write/read (though does not modify this instance, only the instance being
@@ -1134,12 +1743,16 @@ where
 /// tells you the last block hash which was connected. You should get the best block tip before using the manager.
 /// See [`chain::Listen`] and [`chain::Confirm`] for more details.
 ///
+/// # `ChannelUpdate` Messages
+///
 /// Note that `ChannelManager` is responsible for tracking liveness of its channels and generating
 /// [`ChannelUpdate`] messages informing peers that the channel is temporarily disabled. To avoid
 /// spam due to quick disconnection/reconnection, updates are not sent until the channel has been
 /// offline for a full minute. In order to track this, you must call
 /// [`timer_tick_occurred`] roughly once per minute, though it doesn't have to be perfect.
 ///
+/// # DoS Mitigation
+///
 /// To avoid trivial DoS issues, `ChannelManager` limits the number of inbound connections and
 /// inbound channels without confirmed funding transactions. This may result in nodes which we do
 /// not have a channel with being unable to connect to us or open new channels with us if we have
@@ -1149,19 +1762,53 @@ where
 /// exempted from the count of unfunded channels. Similarly, outbound channels and connections are
 /// never limited. Please ensure you limit the count of such channels yourself.
 ///
+/// # Type Aliases
+///
 /// Rather than using a plain `ChannelManager`, it is preferable to use either a [`SimpleArcChannelManager`]
 /// a [`SimpleRefChannelManager`], for conciseness. See their documentation for more details, but
 /// essentially you should default to using a [`SimpleRefChannelManager`], and use a
 /// [`SimpleArcChannelManager`] when you require a `ChannelManager` with a static lifetime, such as when
 /// you're using lightning-net-tokio.
 ///
+/// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor
+/// [`MessageHandler`]: crate::ln::peer_handler::MessageHandler
+/// [`OnionMessenger`]: crate::onion_message::messenger::OnionMessenger
+/// [`PeerManager::read_event`]: crate::ln::peer_handler::PeerManager::read_event
+/// [`PeerManager::process_events`]: crate::ln::peer_handler::PeerManager::process_events
+/// [`timer_tick_occurred`]: Self::timer_tick_occurred
+/// [`get_and_clear_needs_persistence`]: Self::get_and_clear_needs_persistence
+/// [`Persister`]: crate::util::persist::Persister
+/// [`KVStore`]: crate::util::persist::KVStore
+/// [`get_event_or_persistence_needed_future`]: Self::get_event_or_persistence_needed_future
+/// [`lightning-block-sync`]: https://docs.rs/lightning_block_sync/latest/lightning_block_sync
+/// [`lightning-transaction-sync`]: https://docs.rs/lightning_transaction_sync/latest/lightning_transaction_sync
+/// [`lightning-background-processor`]: https://docs.rs/lightning_background_processor/lightning_background_processor
+/// [`list_channels`]: Self::list_channels
+/// [`list_usable_channels`]: Self::list_usable_channels
+/// [`create_channel`]: Self::create_channel
+/// [`close_channel`]: Self::force_close_broadcasting_latest_txn
+/// [`force_close_broadcasting_latest_txn`]: Self::force_close_broadcasting_latest_txn
+/// [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
+/// [BOLT 12]: https://github.com/rustyrussell/lightning-rfc/blob/guilt/offers/12-offer-encoding.md
+/// [`list_recent_payments`]: Self::list_recent_payments
+/// [`abandon_payment`]: Self::abandon_payment
+/// [`lightning-invoice`]: https://docs.rs/lightning_invoice/latest/lightning_invoice
+/// [`create_inbound_payment`]: Self::create_inbound_payment
+/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
+/// [`claim_funds`]: Self::claim_funds
+/// [`send_payment`]: Self::send_payment
+/// [`offers`]: crate::offers
+/// [`create_offer_builder`]: Self::create_offer_builder
+/// [`pay_for_offer`]: Self::pay_for_offer
+/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
+/// [`create_refund_builder`]: Self::create_refund_builder
+/// [`request_refund_payment`]: Self::request_refund_payment
 /// [`peer_disconnected`]: msgs::ChannelMessageHandler::peer_disconnected
 /// [`funding_created`]: msgs::FundingCreated
 /// [`funding_transaction_generated`]: Self::funding_transaction_generated
 /// [`BlockHash`]: bitcoin::hash_types::BlockHash
 /// [`update_channel`]: chain::Watch::update_channel
 /// [`ChannelUpdate`]: msgs::ChannelUpdate
-/// [`timer_tick_occurred`]: Self::timer_tick_occurred
 /// [`read`]: ReadableArgs::read
 //
 // Lock order:
@@ -1181,6 +1828,8 @@ where
 //  |   |
 //  |   |__`pending_intercepted_htlcs`
 //  |
+//  |__`decode_update_add_htlcs`
+//  |
 //  |__`per_peer_state`
 //      |
 //      |__`pending_inbound_payments`
@@ -1271,6 +1920,18 @@ where
        /// See `ChannelManager` struct-level documentation for lock order requirements.
        pending_intercepted_htlcs: Mutex<HashMap<InterceptId, PendingAddHTLCInfo>>,
 
+       /// SCID/SCID Alias -> pending `update_add_htlc`s to decode.
+       ///
+       /// Note that because we may have an SCID Alias as the key we can have two entries per channel,
+       /// though in practice we probably won't be receiving HTLCs for a channel both via the alias
+       /// and via the classic SCID.
+       ///
+       /// Note that no consistency guarantees are made about the existence of a channel with the
+       /// `short_channel_id` here, nor the `channel_id` in `UpdateAddHTLC`!
+       ///
+       /// See `ChannelManager` struct-level documentation for lock order requirements.
+       decode_update_add_htlcs: Mutex<HashMap<u64, Vec<msgs::UpdateAddHTLC>>>,
+
        /// The sets of payments which are claimable or currently being claimed. See
        /// [`ClaimablePayments`]' individual field docs for more info.
        ///
@@ -1414,6 +2075,9 @@ where
 
        pending_offers_messages: Mutex<Vec<PendingOnionMessage<OffersMessage>>>,
 
+       /// Tracks the message events that are to be broadcasted when we are connected to some peer.
+       pending_broadcast_messages: Mutex<Vec<MessageSendEvent>>,
+
        entropy_source: ES,
        node_signer: NS,
        signer_provider: SP,
@@ -2005,7 +2669,7 @@ macro_rules! handle_error {
                match $internal {
                        Ok(msg) => Ok(msg),
                        Err(MsgHandleErrInternal { err, shutdown_finish, .. }) => {
-                               let mut msg_events = Vec::with_capacity(2);
+                               let mut msg_event = None;
 
                                if let Some((shutdown_res, update_option)) = shutdown_finish {
                                        let counterparty_node_id = shutdown_res.counterparty_node_id;
@@ -2017,7 +2681,8 @@ macro_rules! handle_error {
 
                                        $self.finish_close_channel(shutdown_res);
                                        if let Some(update) = update_option {
-                                               msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                                               let mut pending_broadcast_messages = $self.pending_broadcast_messages.lock().unwrap();
+                                               pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                                        msg: update
                                                });
                                        }
@@ -2027,17 +2692,17 @@ macro_rules! handle_error {
 
                                if let msgs::ErrorAction::IgnoreError = err.action {
                                } else {
-                                       msg_events.push(events::MessageSendEvent::HandleError {
+                                       msg_event = Some(events::MessageSendEvent::HandleError {
                                                node_id: $counterparty_node_id,
                                                action: err.action.clone()
                                        });
                                }
 
-                               if !msg_events.is_empty() {
+                               if let Some(msg_event) = msg_event {
                                        let per_peer_state = $self.per_peer_state.read().unwrap();
                                        if let Some(peer_state_mutex) = per_peer_state.get(&$counterparty_node_id) {
                                                let mut peer_state = peer_state_mutex.lock().unwrap();
-                                               peer_state.pending_msg_events.append(&mut msg_events);
+                                               peer_state.pending_msg_events.push(msg_event);
                                        }
                                }
 
@@ -2238,9 +2903,9 @@ macro_rules! handle_monitor_update_completion {
                let update_actions = $peer_state.monitor_update_blocked_actions
                        .remove(&$chan.context.channel_id()).unwrap_or(Vec::new());
 
-               let htlc_forwards = $self.handle_channel_resumption(
+               let (htlc_forwards, decode_update_add_htlcs) = $self.handle_channel_resumption(
                        &mut $peer_state.pending_msg_events, $chan, updates.raa,
-                       updates.commitment_update, updates.order, updates.accepted_htlcs,
+                       updates.commitment_update, updates.order, updates.accepted_htlcs, updates.pending_update_adds,
                        updates.funding_broadcastable, updates.channel_ready,
                        updates.announcement_sigs);
                if let Some(upd) = channel_update {
@@ -2301,6 +2966,9 @@ macro_rules! handle_monitor_update_completion {
                if let Some(forwards) = htlc_forwards {
                        $self.forward_htlcs(&mut [forwards][..]);
                }
+               if let Some(decode) = decode_update_add_htlcs {
+                       $self.push_decode_update_add_htlcs(decode);
+               }
                $self.finalize_claims(updates.finalized_claimed_htlcs);
                for failure in updates.failed_htlcs.drain(..) {
                        let receiver = HTLCDestination::NextHopChannel { node_id: Some(counterparty_node_id), channel_id };
@@ -2477,6 +3145,7 @@ where
                        pending_inbound_payments: Mutex::new(new_hash_map()),
                        pending_outbound_payments: OutboundPayments::new(),
                        forward_htlcs: Mutex::new(new_hash_map()),
+                       decode_update_add_htlcs: Mutex::new(new_hash_map()),
                        claimable_payments: Mutex::new(ClaimablePayments { claimable_payments: new_hash_map(), pending_claiming_payments: new_hash_map() }),
                        pending_intercepted_htlcs: Mutex::new(new_hash_map()),
                        outpoint_to_peer: Mutex::new(new_hash_map()),
@@ -2504,6 +3173,7 @@ where
                        funding_batch_states: Mutex::new(BTreeMap::new()),
 
                        pending_offers_messages: Mutex::new(Vec::new()),
+                       pending_broadcast_messages: Mutex::new(Vec::new()),
 
                        entropy_source,
                        node_signer,
@@ -3002,17 +3672,11 @@ where
                        }
                };
                if let Some(update) = update_opt {
-                       // Try to send the `BroadcastChannelUpdate` to the peer we just force-closed on, but if
-                       // not try to broadcast it via whatever peer we have.
-                       let per_peer_state = self.per_peer_state.read().unwrap();
-                       let a_peer_state_opt = per_peer_state.get(peer_node_id)
-                               .ok_or(per_peer_state.values().next());
-                       if let Ok(a_peer_state_mutex) = a_peer_state_opt {
-                               let mut a_peer_state = a_peer_state_mutex.lock().unwrap();
-                               a_peer_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
-                                       msg: update
-                               });
-                       }
+                       // If we have some Channel Update to broadcast, we cache it and broadcast it later.
+                       let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap();
+                       pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                               msg: update
+                       });
                }
 
                Ok(counterparty_node_id)
@@ -3076,6 +3740,163 @@ where
                }
        }
 
+       fn can_forward_htlc_to_outgoing_channel(
+               &self, chan: &mut Channel<SP>, msg: &msgs::UpdateAddHTLC, next_packet: &NextPacketDetails
+       ) -> Result<(), (&'static str, u16, Option<msgs::ChannelUpdate>)> {
+               if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
+                       // Note that the behavior here should be identical to the above block - we
+                       // should NOT reveal the existence or non-existence of a private channel if
+                       // we don't allow forwards outbound over them.
+                       return Err(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
+               }
+               if chan.context.get_channel_type().supports_scid_privacy() && next_packet.outgoing_scid != chan.context.outbound_scid_alias() {
+                       // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
+                       // "refuse to forward unless the SCID alias was used", so we pretend
+                       // we don't have the channel here.
+                       return Err(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
+               }
+
+               // Note that we could technically not return an error yet here and just hope
+               // that the connection is reestablished or monitor updated by the time we get
+               // around to doing the actual forward, but better to fail early if we can and
+               // hopefully an attacker trying to path-trace payments cannot make this occur
+               // on a small/per-node/per-channel scale.
+               if !chan.context.is_live() { // channel_disabled
+                       // If the channel_update we're going to return is disabled (i.e. the
+                       // peer has been disabled for some time), return `channel_disabled`,
+                       // otherwise return `temporary_channel_failure`.
+                       let chan_update_opt = self.get_channel_update_for_onion(next_packet.outgoing_scid, chan).ok();
+                       if chan_update_opt.as_ref().map(|u| u.contents.flags & 2 == 2).unwrap_or(false) {
+                               return Err(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
+                       } else {
+                               return Err(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
+                       }
+               }
+               if next_packet.outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
+                       let chan_update_opt = self.get_channel_update_for_onion(next_packet.outgoing_scid, chan).ok();
+                       return Err(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
+               }
+               if let Err((err, code)) = chan.htlc_satisfies_config(msg, next_packet.outgoing_amt_msat, next_packet.outgoing_cltv_value) {
+                       let chan_update_opt = self.get_channel_update_for_onion(next_packet.outgoing_scid, chan).ok();
+                       return Err((err, code, chan_update_opt));
+               }
+
+               Ok(())
+       }
+
+       /// Executes a callback `C` that returns some value `X` on the channel found with the given
+       /// `scid`. `None` is returned when the channel is not found.
+       fn do_funded_channel_callback<X, C: Fn(&mut Channel<SP>) -> X>(
+               &self, scid: u64, callback: C,
+       ) -> Option<X> {
+               let (counterparty_node_id, channel_id) = match self.short_to_chan_info.read().unwrap().get(&scid).cloned() {
+                       None => return None,
+                       Some((cp_id, id)) => (cp_id, id),
+               };
+               let per_peer_state = self.per_peer_state.read().unwrap();
+               let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
+               if peer_state_mutex_opt.is_none() {
+                       return None;
+               }
+               let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
+               let peer_state = &mut *peer_state_lock;
+               match peer_state.channel_by_id.get_mut(&channel_id).and_then(
+                       |chan_phase| if let ChannelPhase::Funded(chan) = chan_phase { Some(chan) } else { None }
+               ) {
+                       None => None,
+                       Some(chan) => Some(callback(chan)),
+               }
+       }
+
+       fn can_forward_htlc(
+               &self, msg: &msgs::UpdateAddHTLC, next_packet_details: &NextPacketDetails
+       ) -> Result<(), (&'static str, u16, Option<msgs::ChannelUpdate>)> {
+               match self.do_funded_channel_callback(next_packet_details.outgoing_scid, |chan: &mut Channel<SP>| {
+                       self.can_forward_htlc_to_outgoing_channel(chan, msg, next_packet_details)
+               }) {
+                       Some(Ok(())) => {},
+                       Some(Err(e)) => return Err(e),
+                       None => {
+                               // If we couldn't find the channel info for the scid, it may be a phantom or
+                               // intercept forward.
+                               if (self.default_configuration.accept_intercept_htlcs &&
+                                       fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, next_packet_details.outgoing_scid, &self.chain_hash)) ||
+                                       fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, next_packet_details.outgoing_scid, &self.chain_hash)
+                               {} else {
+                                       return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
+                               }
+                       }
+               }
+
+               let cur_height = self.best_block.read().unwrap().height + 1;
+               if let Err((err_msg, err_code)) = check_incoming_htlc_cltv(
+                       cur_height, next_packet_details.outgoing_cltv_value, msg.cltv_expiry
+               ) {
+                       let chan_update_opt = self.do_funded_channel_callback(next_packet_details.outgoing_scid, |chan: &mut Channel<SP>| {
+                               self.get_channel_update_for_onion(next_packet_details.outgoing_scid, chan).ok()
+                       }).flatten();
+                       return Err((err_msg, err_code, chan_update_opt));
+               }
+
+               Ok(())
+       }
+
+       fn htlc_failure_from_update_add_err(
+               &self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey, err_msg: &'static str,
+               mut err_code: u16, chan_update: Option<msgs::ChannelUpdate>, is_intro_node_blinded_forward: bool,
+               shared_secret: &[u8; 32]
+       ) -> HTLCFailureMsg {
+               let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 2 + 8 + 2));
+               if chan_update.is_some() && err_code & 0x1000 == 0x1000 {
+                       let chan_update = chan_update.unwrap();
+                       if err_code == 0x1000 | 11 || err_code == 0x1000 | 12 {
+                               msg.amount_msat.write(&mut res).expect("Writes cannot fail");
+                       }
+                       else if err_code == 0x1000 | 13 {
+                               msg.cltv_expiry.write(&mut res).expect("Writes cannot fail");
+                       }
+                       else if err_code == 0x1000 | 20 {
+                               // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
+                               0u16.write(&mut res).expect("Writes cannot fail");
+                       }
+                       (chan_update.serialized_length() as u16 + 2).write(&mut res).expect("Writes cannot fail");
+                       msgs::ChannelUpdate::TYPE.write(&mut res).expect("Writes cannot fail");
+                       chan_update.write(&mut res).expect("Writes cannot fail");
+               } else if err_code & 0x1000 == 0x1000 {
+                       // If we're trying to return an error that requires a `channel_update` but
+                       // we're forwarding to a phantom or intercept "channel" (i.e. cannot
+                       // generate an update), just use the generic "temporary_node_failure"
+                       // instead.
+                       err_code = 0x2000 | 2;
+               }
+
+               log_info!(
+                       WithContext::from(&self.logger, Some(*counterparty_node_id), Some(msg.channel_id)),
+                       "Failed to accept/forward incoming HTLC: {}", err_msg
+               );
+               // If `msg.blinding_point` is set, we must always fail with malformed.
+               if msg.blinding_point.is_some() {
+                       return HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
+                               channel_id: msg.channel_id,
+                               htlc_id: msg.htlc_id,
+                               sha256_of_onion: [0; 32],
+                               failure_code: INVALID_ONION_BLINDING,
+                       });
+               }
+
+               let (err_code, err_data) = if is_intro_node_blinded_forward {
+                       (INVALID_ONION_BLINDING, &[0; 32][..])
+               } else {
+                       (err_code, &res.0[..])
+               };
+               HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
+                       channel_id: msg.channel_id,
+                       htlc_id: msg.htlc_id,
+                       reason: HTLCFailReason::reason(err_code, err_data.to_vec())
+                               .get_encrypted_failure_packet(shared_secret, &None),
+               })
+       }
+
        fn decode_update_add_htlc_onion(
                &self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey,
        ) -> Result<
@@ -3085,48 +3906,7 @@ where
                        msg, &self.node_signer, &self.logger, &self.secp_ctx
                )?;
 
-               let is_intro_node_forward = match next_hop {
-                       onion_utils::Hop::Forward {
-                               next_hop_data: msgs::InboundOnionPayload::BlindedForward {
-                                       intro_node_blinding_point: Some(_), ..
-                               }, ..
-                       } => true,
-                       _ => false,
-               };
-
-               macro_rules! return_err {
-                       ($msg: expr, $err_code: expr, $data: expr) => {
-                               {
-                                       log_info!(
-                                               WithContext::from(&self.logger, Some(*counterparty_node_id), Some(msg.channel_id)),
-                                               "Failed to accept/forward incoming HTLC: {}", $msg
-                                       );
-                                       // If `msg.blinding_point` is set, we must always fail with malformed.
-                                       if msg.blinding_point.is_some() {
-                                               return Err(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
-                                                       channel_id: msg.channel_id,
-                                                       htlc_id: msg.htlc_id,
-                                                       sha256_of_onion: [0; 32],
-                                                       failure_code: INVALID_ONION_BLINDING,
-                                               }));
-                                       }
-
-                                       let (err_code, err_data) = if is_intro_node_forward {
-                                               (INVALID_ONION_BLINDING, &[0; 32][..])
-                                       } else { ($err_code, $data) };
-                                       return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
-                                               channel_id: msg.channel_id,
-                                               htlc_id: msg.htlc_id,
-                                               reason: HTLCFailReason::reason(err_code, err_data.to_vec())
-                                                       .get_encrypted_failure_packet(&shared_secret, &None),
-                                       }));
-                               }
-                       }
-               }
-
-               let NextPacketDetails {
-                       next_packet_pubkey, outgoing_amt_msat, outgoing_scid, outgoing_cltv_value
-               } = match next_packet_details_opt {
+               let next_packet_details = match next_packet_details_opt {
                        Some(next_packet_details) => next_packet_details,
                        // it is a receive, so no need for outbound checks
                        None => return Ok((next_hop, shared_secret, None)),
@@ -3134,124 +3914,15 @@ where
 
                // Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
                // can't hold the outbound peer state lock at the same time as the inbound peer state lock.
-               if let Some((err, mut code, chan_update)) = loop {
-                       let id_option = self.short_to_chan_info.read().unwrap().get(&outgoing_scid).cloned();
-                       let forwarding_chan_info_opt = match id_option {
-                               None => { // unknown_next_peer
-                                       // Note that this is likely a timing oracle for detecting whether an scid is a
-                                       // phantom or an intercept.
-                                       if (self.default_configuration.accept_intercept_htlcs &&
-                                               fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash)) ||
-                                               fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash)
-                                       {
-                                               None
-                                       } else {
-                                               break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
-                                       }
-                               },
-                               Some((cp_id, id)) => Some((cp_id.clone(), id.clone())),
-                       };
-                       let chan_update_opt = if let Some((counterparty_node_id, forwarding_id)) = forwarding_chan_info_opt {
-                               let per_peer_state = self.per_peer_state.read().unwrap();
-                               let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
-                               if peer_state_mutex_opt.is_none() {
-                                       break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
-                               }
-                               let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
-                               let peer_state = &mut *peer_state_lock;
-                               let chan = match peer_state.channel_by_id.get_mut(&forwarding_id).map(
-                                       |chan_phase| if let ChannelPhase::Funded(chan) = chan_phase { Some(chan) } else { None }
-                               ).flatten() {
-                                       None => {
-                                               // Channel was removed. The short_to_chan_info and channel_by_id maps
-                                               // have no consistency guarantees.
-                                               break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
-                                       },
-                                       Some(chan) => chan
-                               };
-                               if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
-                                       // Note that the behavior here should be identical to the above block - we
-                                       // should NOT reveal the existence or non-existence of a private channel if
-                                       // we don't allow forwards outbound over them.
-                                       break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
-                               }
-                               if chan.context.get_channel_type().supports_scid_privacy() && outgoing_scid != chan.context.outbound_scid_alias() {
-                                       // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
-                                       // "refuse to forward unless the SCID alias was used", so we pretend
-                                       // we don't have the channel here.
-                                       break Some(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
-                               }
-                               let chan_update_opt = self.get_channel_update_for_onion(outgoing_scid, chan).ok();
-
-                               // Note that we could technically not return an error yet here and just hope
-                               // that the connection is reestablished or monitor updated by the time we get
-                               // around to doing the actual forward, but better to fail early if we can and
-                               // hopefully an attacker trying to path-trace payments cannot make this occur
-                               // on a small/per-node/per-channel scale.
-                               if !chan.context.is_live() { // channel_disabled
-                                       // If the channel_update we're going to return is disabled (i.e. the
-                                       // peer has been disabled for some time), return `channel_disabled`,
-                                       // otherwise return `temporary_channel_failure`.
-                                       if chan_update_opt.as_ref().map(|u| u.contents.flags & 2 == 2).unwrap_or(false) {
-                                               break Some(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
-                                       } else {
-                                               break Some(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
-                                       }
-                               }
-                               if outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
-                                       break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
-                               }
-                               if let Err((err, code)) = chan.htlc_satisfies_config(&msg, outgoing_amt_msat, outgoing_cltv_value) {
-                                       break Some((err, code, chan_update_opt));
-                               }
-                               chan_update_opt
-                       } else {
-                               None
-                       };
-
-                       let cur_height = self.best_block.read().unwrap().height + 1;
-
-                       if let Err((err_msg, code)) = check_incoming_htlc_cltv(
-                               cur_height, outgoing_cltv_value, msg.cltv_expiry
-                       ) {
-                               if code & 0x1000 != 0 && chan_update_opt.is_none() {
-                                       // We really should set `incorrect_cltv_expiry` here but as we're not
-                                       // forwarding over a real channel we can't generate a channel_update
-                                       // for it. Instead we just return a generic temporary_node_failure.
-                                       break Some((err_msg, 0x2000 | 2, None))
-                               }
-                               let chan_update_opt = if code & 0x1000 != 0 { chan_update_opt } else { None };
-                               break Some((err_msg, code, chan_update_opt));
-                       }
+               self.can_forward_htlc(&msg, &next_packet_details).map_err(|e| {
+                       let (err_msg, err_code, chan_update_opt) = e;
+                       self.htlc_failure_from_update_add_err(
+                               msg, counterparty_node_id, err_msg, err_code, chan_update_opt,
+                               next_hop.is_intro_node_blinded_forward(), &shared_secret
+                       )
+               })?;
 
-                       break None;
-               }
-               {
-                       let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 2 + 8 + 2));
-                       if let Some(chan_update) = chan_update {
-                               if code == 0x1000 | 11 || code == 0x1000 | 12 {
-                                       msg.amount_msat.write(&mut res).expect("Writes cannot fail");
-                               }
-                               else if code == 0x1000 | 13 {
-                                       msg.cltv_expiry.write(&mut res).expect("Writes cannot fail");
-                               }
-                               else if code == 0x1000 | 20 {
-                                       // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
-                                       0u16.write(&mut res).expect("Writes cannot fail");
-                               }
-                               (chan_update.serialized_length() as u16 + 2).write(&mut res).expect("Writes cannot fail");
-                               msgs::ChannelUpdate::TYPE.write(&mut res).expect("Writes cannot fail");
-                               chan_update.write(&mut res).expect("Writes cannot fail");
-                       } else if code & 0x1000 == 0x1000 {
-                               // If we're trying to return an error that requires a `channel_update` but
-                               // we're forwarding to a phantom or intercept "channel" (i.e. cannot
-                               // generate an update), just use the generic "temporary_node_failure"
-                               // instead.
-                               code = 0x2000 | 2;
-                       }
-                       return_err!(err, code, &res.0[..]);
-               }
-               Ok((next_hop, shared_secret, Some(next_packet_pubkey)))
+               Ok((next_hop, shared_secret, Some(next_packet_details.next_packet_pubkey)))
        }
 
        fn construct_pending_htlc_status<'a>(
@@ -4088,6 +4759,7 @@ where
                        .ok_or_else(|| APIError::ChannelUnavailable { err: format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id) })?;
                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                let peer_state = &mut *peer_state_lock;
+
                for channel_id in channel_ids {
                        if !peer_state.has_channel(channel_id) {
                                return Err(APIError::ChannelUnavailable {
@@ -4104,7 +4776,8 @@ where
                                }
                                if let ChannelPhase::Funded(channel) = channel_phase {
                                        if let Ok(msg) = self.get_channel_update_for_broadcast(channel) {
-                                               peer_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate { msg });
+                                               let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap();
+                                               pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate { msg });
                                        } else if let Ok(msg) = self.get_channel_update_for_unicast(channel) {
                                                peer_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
                                                        node_id: channel.context.get_counterparty_node_id(),
@@ -4279,6 +4952,145 @@ where
                Ok(())
        }
 
+       fn process_pending_update_add_htlcs(&self) {
+               let mut decode_update_add_htlcs = new_hash_map();
+               mem::swap(&mut decode_update_add_htlcs, &mut self.decode_update_add_htlcs.lock().unwrap());
+
+               let get_failed_htlc_destination = |outgoing_scid_opt: Option<u64>, payment_hash: PaymentHash| {
+                       if let Some(outgoing_scid) = outgoing_scid_opt {
+                               match self.short_to_chan_info.read().unwrap().get(&outgoing_scid) {
+                                       Some((outgoing_counterparty_node_id, outgoing_channel_id)) =>
+                                               HTLCDestination::NextHopChannel {
+                                                       node_id: Some(*outgoing_counterparty_node_id),
+                                                       channel_id: *outgoing_channel_id,
+                                               },
+                                       None => HTLCDestination::UnknownNextHop {
+                                               requested_forward_scid: outgoing_scid,
+                                       },
+                               }
+                       } else {
+                               HTLCDestination::FailedPayment { payment_hash }
+                       }
+               };
+
+               'outer_loop: for (incoming_scid, update_add_htlcs) in decode_update_add_htlcs {
+                       let incoming_channel_details_opt = self.do_funded_channel_callback(incoming_scid, |chan: &mut Channel<SP>| {
+                               let counterparty_node_id = chan.context.get_counterparty_node_id();
+                               let channel_id = chan.context.channel_id();
+                               let funding_txo = chan.context.get_funding_txo().unwrap();
+                               let user_channel_id = chan.context.get_user_id();
+                               let accept_underpaying_htlcs = chan.context.config().accept_underpaying_htlcs;
+                               (counterparty_node_id, channel_id, funding_txo, user_channel_id, accept_underpaying_htlcs)
+                       });
+                       let (
+                               incoming_counterparty_node_id, incoming_channel_id, incoming_funding_txo,
+                               incoming_user_channel_id, incoming_accept_underpaying_htlcs
+                        ) = if let Some(incoming_channel_details) = incoming_channel_details_opt {
+                               incoming_channel_details
+                       } else {
+                               // The incoming channel no longer exists, HTLCs should be resolved onchain instead.
+                               continue;
+                       };
+
+                       let mut htlc_forwards = Vec::new();
+                       let mut htlc_fails = Vec::new();
+                       for update_add_htlc in &update_add_htlcs {
+                               let (next_hop, shared_secret, next_packet_details_opt) = match decode_incoming_update_add_htlc_onion(
+                                       &update_add_htlc, &self.node_signer, &self.logger, &self.secp_ctx
+                               ) {
+                                       Ok(decoded_onion) => decoded_onion,
+                                       Err(htlc_fail) => {
+                                               htlc_fails.push((htlc_fail, HTLCDestination::InvalidOnion));
+                                               continue;
+                                       },
+                               };
+
+                               let is_intro_node_blinded_forward = next_hop.is_intro_node_blinded_forward();
+                               let outgoing_scid_opt = next_packet_details_opt.as_ref().map(|d| d.outgoing_scid);
+
+                               // Process the HTLC on the incoming channel.
+                               match self.do_funded_channel_callback(incoming_scid, |chan: &mut Channel<SP>| {
+                                       let logger = WithChannelContext::from(&self.logger, &chan.context);
+                                       chan.can_accept_incoming_htlc(
+                                               update_add_htlc, &self.fee_estimator, &logger,
+                                       )
+                               }) {
+                                       Some(Ok(_)) => {},
+                                       Some(Err((err, code))) => {
+                                               let outgoing_chan_update_opt = if let Some(outgoing_scid) = outgoing_scid_opt.as_ref() {
+                                                       self.do_funded_channel_callback(*outgoing_scid, |chan: &mut Channel<SP>| {
+                                                               self.get_channel_update_for_onion(*outgoing_scid, chan).ok()
+                                                       }).flatten()
+                                               } else {
+                                                       None
+                                               };
+                                               let htlc_fail = self.htlc_failure_from_update_add_err(
+                                                       &update_add_htlc, &incoming_counterparty_node_id, err, code,
+                                                       outgoing_chan_update_opt, is_intro_node_blinded_forward, &shared_secret,
+                                               );
+                                               let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
+                                               htlc_fails.push((htlc_fail, htlc_destination));
+                                               continue;
+                                       },
+                                       // The incoming channel no longer exists, HTLCs should be resolved onchain instead.
+                                       None => continue 'outer_loop,
+                               }
+
+                               // Now process the HTLC on the outgoing channel if it's a forward.
+                               if let Some(next_packet_details) = next_packet_details_opt.as_ref() {
+                                       if let Err((err, code, chan_update_opt)) = self.can_forward_htlc(
+                                               &update_add_htlc, next_packet_details
+                                       ) {
+                                               let htlc_fail = self.htlc_failure_from_update_add_err(
+                                                       &update_add_htlc, &incoming_counterparty_node_id, err, code,
+                                                       chan_update_opt, is_intro_node_blinded_forward, &shared_secret,
+                                               );
+                                               let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
+                                               htlc_fails.push((htlc_fail, htlc_destination));
+                                               continue;
+                                       }
+                               }
+
+                               match self.construct_pending_htlc_status(
+                                       &update_add_htlc, &incoming_counterparty_node_id, shared_secret, next_hop,
+                                       incoming_accept_underpaying_htlcs, next_packet_details_opt.map(|d| d.next_packet_pubkey),
+                               ) {
+                                       PendingHTLCStatus::Forward(htlc_forward) => {
+                                               htlc_forwards.push((htlc_forward, update_add_htlc.htlc_id));
+                                       },
+                                       PendingHTLCStatus::Fail(htlc_fail) => {
+                                               let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
+                                               htlc_fails.push((htlc_fail, htlc_destination));
+                                       },
+                               }
+                       }
+
+                       // Process all of the forwards and failures for the channel in which the HTLCs were
+                       // proposed to as a batch.
+                       let pending_forwards = (incoming_scid, incoming_funding_txo, incoming_channel_id,
+                               incoming_user_channel_id, htlc_forwards.drain(..).collect());
+                       self.forward_htlcs_without_forward_event(&mut [pending_forwards]);
+                       for (htlc_fail, htlc_destination) in htlc_fails.drain(..) {
+                               let failure = match htlc_fail {
+                                       HTLCFailureMsg::Relay(fail_htlc) => HTLCForwardInfo::FailHTLC {
+                                               htlc_id: fail_htlc.htlc_id,
+                                               err_packet: fail_htlc.reason,
+                                       },
+                                       HTLCFailureMsg::Malformed(fail_malformed_htlc) => HTLCForwardInfo::FailMalformedHTLC {
+                                               htlc_id: fail_malformed_htlc.htlc_id,
+                                               sha256_of_onion: fail_malformed_htlc.sha256_of_onion,
+                                               failure_code: fail_malformed_htlc.failure_code,
+                                       },
+                               };
+                               self.forward_htlcs.lock().unwrap().entry(incoming_scid).or_insert(vec![]).push(failure);
+                               self.pending_events.lock().unwrap().push_back((events::Event::HTLCHandlingFailed {
+                                       prev_channel_id: incoming_channel_id,
+                                       failed_next_destination: htlc_destination,
+                               }, None));
+                       }
+               }
+       }
+
        /// Processes HTLCs which are pending waiting on random forward delay.
        ///
        /// Should only really ever be called in response to a PendingHTLCsForwardable event.
@@ -4286,6 +5098,8 @@ where
        pub fn process_pending_htlc_forwards(&self) {
                let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
+               self.process_pending_update_add_htlcs();
+
                let mut new_events = VecDeque::new();
                let mut failed_forwards = Vec::new();
                let mut phantom_receives: Vec<(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)> = Vec::new();
@@ -5013,7 +5827,8 @@ where
                                                                                if n >= DISABLE_GOSSIP_TICKS {
                                                                                        chan.set_channel_update_status(ChannelUpdateStatus::Disabled);
                                                                                        if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
-                                                                                               pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                                                                                               let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap();
+                                                                                               pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                                                                                        msg: update
                                                                                                });
                                                                                        }
@@ -5027,7 +5842,8 @@ where
                                                                                if n >= ENABLE_GOSSIP_TICKS {
                                                                                        chan.set_channel_update_status(ChannelUpdateStatus::Enabled);
                                                                                        if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
-                                                                                               pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                                                                                               let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap();
+                                                                                               pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                                                                                        msg: update
                                                                                                });
                                                                                        }
@@ -5330,9 +6146,14 @@ where
                }
        }
 
+       fn fail_htlc_backwards_internal(&self, source: &HTLCSource, payment_hash: &PaymentHash, onion_error: &HTLCFailReason, destination: HTLCDestination) {
+               let push_forward_event = self.fail_htlc_backwards_internal_without_forward_event(source, payment_hash, onion_error, destination);
+               if push_forward_event { self.push_pending_forwards_ev(); }
+       }
+
        /// Fails an HTLC backwards to the sender of it to us.
        /// Note that we do not assume that channels corresponding to failed HTLCs are still available.
-       fn fail_htlc_backwards_internal(&self, source: &HTLCSource, payment_hash: &PaymentHash, onion_error: &HTLCFailReason, destination: HTLCDestination) {
+       fn fail_htlc_backwards_internal_without_forward_event(&self, source: &HTLCSource, payment_hash: &PaymentHash, onion_error: &HTLCFailReason, destination: HTLCDestination) -> bool {
                // Ensure that no peer state channel storage lock is held when calling this function.
                // This ensures that future code doesn't introduce a lock-order requirement for
                // `forward_htlcs` to be locked after the `per_peer_state` peer locks, which calling
@@ -5350,12 +6171,12 @@ where
                // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
                // from block_connected which may run during initialization prior to the chain_monitor
                // being fully configured. See the docs for `ChannelManagerReadArgs` for more.
+               let mut push_forward_event;
                match source {
                        HTLCSource::OutboundRoute { ref path, ref session_priv, ref payment_id, .. } => {
-                               if self.pending_outbound_payments.fail_htlc(source, payment_hash, onion_error, path,
+                               push_forward_event = self.pending_outbound_payments.fail_htlc(source, payment_hash, onion_error, path,
                                        session_priv, payment_id, self.probing_cookie_secret, &self.secp_ctx,
-                                       &self.pending_events, &self.logger)
-                               { self.push_pending_forwards_ev(); }
+                                       &self.pending_events, &self.logger);
                        },
                        HTLCSource::PreviousHopData(HTLCPreviousHopData {
                                ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret,
@@ -5389,11 +6210,9 @@ where
                                        }
                                };
 
-                               let mut push_forward_ev = false;
+                               push_forward_event = self.decode_update_add_htlcs.lock().unwrap().is_empty();
                                let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
-                               if forward_htlcs.is_empty() {
-                                       push_forward_ev = true;
-                               }
+                               push_forward_event &= forward_htlcs.is_empty();
                                match forward_htlcs.entry(*short_channel_id) {
                                        hash_map::Entry::Occupied(mut entry) => {
                                                entry.get_mut().push(failure);
@@ -5403,7 +6222,6 @@ where
                                        }
                                }
                                mem::drop(forward_htlcs);
-                               if push_forward_ev { self.push_pending_forwards_ev(); }
                                let mut pending_events = self.pending_events.lock().unwrap();
                                pending_events.push_back((events::Event::HTLCHandlingFailed {
                                        prev_channel_id: *channel_id,
@@ -5411,6 +6229,7 @@ where
                                }, None));
                        },
                }
+               push_forward_event
        }
 
        /// Provides a payment preimage in response to [`Event::PaymentClaimable`], generating any
@@ -5929,24 +6748,31 @@ where
        fn handle_channel_resumption(&self, pending_msg_events: &mut Vec<MessageSendEvent>,
                channel: &mut Channel<SP>, raa: Option<msgs::RevokeAndACK>,
                commitment_update: Option<msgs::CommitmentUpdate>, order: RAACommitmentOrder,
-               pending_forwards: Vec<(PendingHTLCInfo, u64)>, funding_broadcastable: Option<Transaction>,
+               pending_forwards: Vec<(PendingHTLCInfo, u64)>, pending_update_adds: Vec<msgs::UpdateAddHTLC>,
+               funding_broadcastable: Option<Transaction>,
                channel_ready: Option<msgs::ChannelReady>, announcement_sigs: Option<msgs::AnnouncementSignatures>)
-       -> Option<(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)> {
+       -> (Option<(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)>, Option<(u64, Vec<msgs::UpdateAddHTLC>)>) {
                let logger = WithChannelContext::from(&self.logger, &channel.context);
-               log_trace!(logger, "Handling channel resumption for channel {} with {} RAA, {} commitment update, {} pending forwards, {}broadcasting funding, {} channel ready, {} announcement",
+               log_trace!(logger, "Handling channel resumption for channel {} with {} RAA, {} commitment update, {} pending forwards, {} pending update_add_htlcs, {}broadcasting funding, {} channel ready, {} announcement",
                        &channel.context.channel_id(),
                        if raa.is_some() { "an" } else { "no" },
-                       if commitment_update.is_some() { "a" } else { "no" }, pending_forwards.len(),
+                       if commitment_update.is_some() { "a" } else { "no" },
+                       pending_forwards.len(), pending_update_adds.len(),
                        if funding_broadcastable.is_some() { "" } else { "not " },
                        if channel_ready.is_some() { "sending" } else { "without" },
                        if announcement_sigs.is_some() { "sending" } else { "without" });
 
-               let mut htlc_forwards = None;
-
                let counterparty_node_id = channel.context.get_counterparty_node_id();
+               let short_channel_id = channel.context.get_short_channel_id().unwrap_or(channel.context.outbound_scid_alias());
+
+               let mut htlc_forwards = None;
                if !pending_forwards.is_empty() {
-                       htlc_forwards = Some((channel.context.get_short_channel_id().unwrap_or(channel.context.outbound_scid_alias()),
-                               channel.context.get_funding_txo().unwrap(), channel.context.channel_id(), channel.context.get_user_id(), pending_forwards));
+                       htlc_forwards = Some((short_channel_id, channel.context.get_funding_txo().unwrap(),
+                               channel.context.channel_id(), channel.context.get_user_id(), pending_forwards));
+               }
+               let mut decode_update_add_htlcs = None;
+               if !pending_update_adds.is_empty() {
+                       decode_update_add_htlcs = Some((short_channel_id, pending_update_adds));
                }
 
                if let Some(msg) = channel_ready {
@@ -5997,7 +6823,7 @@ where
                        emit_channel_ready_event!(pending_events, channel);
                }
 
-               htlc_forwards
+               (htlc_forwards, decode_update_add_htlcs)
        }
 
        fn channel_monitor_updated(&self, funding_txo: &OutPoint, channel_id: &ChannelId, highest_applied_update_id: u64, counterparty_node_id: Option<&PublicKey>) {
@@ -6743,9 +7569,8 @@ where
                }
                if let Some(ChannelPhase::Funded(chan)) = chan_option {
                        if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
-                               let mut peer_state_lock = peer_state_mutex.lock().unwrap();
-                               let peer_state = &mut *peer_state_lock;
-                               peer_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                               let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap();
+                               pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                        msg: update
                                });
                        }
@@ -6782,7 +7607,7 @@ where
                match peer_state.channel_by_id.entry(msg.channel_id) {
                        hash_map::Entry::Occupied(mut chan_phase_entry) => {
                                if let ChannelPhase::Funded(chan) = chan_phase_entry.get_mut() {
-                                       let pending_forward_info = match decoded_hop_res {
+                                       let mut pending_forward_info = match decoded_hop_res {
                                                Ok((next_hop, shared_secret, next_packet_pk_opt)) =>
                                                        self.construct_pending_htlc_status(
                                                                msg, counterparty_node_id, shared_secret, next_hop,
@@ -6790,44 +7615,45 @@ where
                                                        ),
                                                Err(e) => PendingHTLCStatus::Fail(e)
                                        };
-                                       let create_pending_htlc_status = |chan: &Channel<SP>, pending_forward_info: PendingHTLCStatus, error_code: u16| {
+                                       let logger = WithChannelContext::from(&self.logger, &chan.context);
+                                       // If the update_add is completely bogus, the call will Err and we will close,
+                                       // but if we've sent a shutdown and they haven't acknowledged it yet, we just
+                                       // want to reject the new HTLC and fail it backwards instead of forwarding.
+                                       if let Err((_, error_code)) = chan.can_accept_incoming_htlc(&msg, &self.fee_estimator, &logger) {
                                                if msg.blinding_point.is_some() {
-                                                       return PendingHTLCStatus::Fail(HTLCFailureMsg::Malformed(
-                                                                       msgs::UpdateFailMalformedHTLC {
-                                                                               channel_id: msg.channel_id,
-                                                                               htlc_id: msg.htlc_id,
-                                                                               sha256_of_onion: [0; 32],
-                                                                               failure_code: INVALID_ONION_BLINDING,
-                                                                       }
-                                                       ))
-                                               }
-                                               // If the update_add is completely bogus, the call will Err and we will close,
-                                               // but if we've sent a shutdown and they haven't acknowledged it yet, we just
-                                               // want to reject the new HTLC and fail it backwards instead of forwarding.
-                                               match pending_forward_info {
-                                                       PendingHTLCStatus::Forward(PendingHTLCInfo {
-                                                               ref incoming_shared_secret, ref routing, ..
-                                                       }) => {
-                                                               let reason = if routing.blinded_failure().is_some() {
-                                                                       HTLCFailReason::reason(INVALID_ONION_BLINDING, vec![0; 32])
-                                                               } else if (error_code & 0x1000) != 0 {
-                                                                       let (real_code, error_data) = self.get_htlc_inbound_temp_fail_err_and_data(error_code, chan);
-                                                                       HTLCFailReason::reason(real_code, error_data)
-                                                               } else {
-                                                                       HTLCFailReason::from_failure_code(error_code)
-                                                               }.get_encrypted_failure_packet(incoming_shared_secret, &None);
-                                                               let msg = msgs::UpdateFailHTLC {
+                                                       pending_forward_info = PendingHTLCStatus::Fail(HTLCFailureMsg::Malformed(
+                                                               msgs::UpdateFailMalformedHTLC {
                                                                        channel_id: msg.channel_id,
                                                                        htlc_id: msg.htlc_id,
-                                                                       reason
-                                                               };
-                                                               PendingHTLCStatus::Fail(HTLCFailureMsg::Relay(msg))
-                                                       },
-                                                       _ => pending_forward_info
+                                                                       sha256_of_onion: [0; 32],
+                                                                       failure_code: INVALID_ONION_BLINDING,
+                                                               }
+                                                       ))
+                                               } else {
+                                                       match pending_forward_info {
+                                                               PendingHTLCStatus::Forward(PendingHTLCInfo {
+                                                                       ref incoming_shared_secret, ref routing, ..
+                                                               }) => {
+                                                                       let reason = if routing.blinded_failure().is_some() {
+                                                                               HTLCFailReason::reason(INVALID_ONION_BLINDING, vec![0; 32])
+                                                                       } else if (error_code & 0x1000) != 0 {
+                                                                               let (real_code, error_data) = self.get_htlc_inbound_temp_fail_err_and_data(error_code, chan);
+                                                                               HTLCFailReason::reason(real_code, error_data)
+                                                                       } else {
+                                                                               HTLCFailReason::from_failure_code(error_code)
+                                                                       }.get_encrypted_failure_packet(incoming_shared_secret, &None);
+                                                                       let msg = msgs::UpdateFailHTLC {
+                                                                               channel_id: msg.channel_id,
+                                                                               htlc_id: msg.htlc_id,
+                                                                               reason
+                                                                       };
+                                                                       pending_forward_info = PendingHTLCStatus::Fail(HTLCFailureMsg::Relay(msg));
+                                                               },
+                                                               _ => {},
+                                                       }
                                                }
-                                       };
-                                       let logger = WithChannelContext::from(&self.logger, &chan.context);
-                                       try_chan_phase_entry!(self, chan.update_add_htlc(&msg, pending_forward_info, create_pending_htlc_status, &self.fee_estimator, &&logger), chan_phase_entry);
+                                       }
+                                       try_chan_phase_entry!(self, chan.update_add_htlc(&msg, pending_forward_info), chan_phase_entry);
                                } else {
                                        return try_chan_phase_entry!(self, Err(ChannelError::Close(
                                                "Got an update_add_htlc message for an unfunded channel!".into())), chan_phase_entry);
@@ -6971,10 +7797,28 @@ where
                }
        }
 
+       fn push_decode_update_add_htlcs(&self, mut update_add_htlcs: (u64, Vec<msgs::UpdateAddHTLC>)) {
+               let mut push_forward_event = self.forward_htlcs.lock().unwrap().is_empty();
+               let mut decode_update_add_htlcs = self.decode_update_add_htlcs.lock().unwrap();
+               push_forward_event &= decode_update_add_htlcs.is_empty();
+               let scid = update_add_htlcs.0;
+               match decode_update_add_htlcs.entry(scid) {
+                       hash_map::Entry::Occupied(mut e) => { e.get_mut().append(&mut update_add_htlcs.1); },
+                       hash_map::Entry::Vacant(e) => { e.insert(update_add_htlcs.1); },
+               }
+               if push_forward_event { self.push_pending_forwards_ev(); }
+       }
+
        #[inline]
        fn forward_htlcs(&self, per_source_pending_forwards: &mut [(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)]) {
+               let push_forward_event = self.forward_htlcs_without_forward_event(per_source_pending_forwards);
+               if push_forward_event { self.push_pending_forwards_ev() }
+       }
+
+       #[inline]
+       fn forward_htlcs_without_forward_event(&self, per_source_pending_forwards: &mut [(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)]) -> bool {
+               let mut push_forward_event = false;
                for &mut (prev_short_channel_id, prev_funding_outpoint, prev_channel_id, prev_user_channel_id, ref mut pending_forwards) in per_source_pending_forwards {
-                       let mut push_forward_event = false;
                        let mut new_intercept_events = VecDeque::new();
                        let mut failed_intercept_forwards = Vec::new();
                        if !pending_forwards.is_empty() {
@@ -6987,6 +7831,7 @@ where
                                        // Pull this now to avoid introducing a lock order with `forward_htlcs`.
                                        let is_our_scid = self.short_to_chan_info.read().unwrap().contains_key(&scid);
 
+                                       let decode_update_add_htlcs_empty = self.decode_update_add_htlcs.lock().unwrap().is_empty();
                                        let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
                                        let forward_htlcs_empty = forward_htlcs.is_empty();
                                        match forward_htlcs.entry(scid) {
@@ -7035,9 +7880,7 @@ where
                                                        } else {
                                                                // We don't want to generate a PendingHTLCsForwardable event if only intercepted
                                                                // payments are being processed.
-                                                               if forward_htlcs_empty {
-                                                                       push_forward_event = true;
-                                                               }
+                                                               push_forward_event |= forward_htlcs_empty && decode_update_add_htlcs_empty;
                                                                entry.insert(vec!(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
                                                                        prev_short_channel_id, prev_funding_outpoint, prev_channel_id, prev_htlc_id, prev_user_channel_id, forward_info })));
                                                        }
@@ -7047,15 +7890,15 @@ where
                        }
 
                        for (htlc_source, payment_hash, failure_reason, destination) in failed_intercept_forwards.drain(..) {
-                               self.fail_htlc_backwards_internal(&htlc_source, &payment_hash, &failure_reason, destination);
+                               push_forward_event |= self.fail_htlc_backwards_internal_without_forward_event(&htlc_source, &payment_hash, &failure_reason, destination);
                        }
 
                        if !new_intercept_events.is_empty() {
                                let mut events = self.pending_events.lock().unwrap();
                                events.append(&mut new_intercept_events);
                        }
-                       if push_forward_event { self.push_pending_forwards_ev() }
                }
+               push_forward_event
        }
 
        fn push_pending_forwards_ev(&self) {
@@ -7265,7 +8108,6 @@ where
        }
 
        fn internal_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) -> Result<NotifyOption, MsgHandleErrInternal> {
-               let htlc_forwards;
                let need_lnd_workaround = {
                        let per_peer_state = self.per_peer_state.read().unwrap();
 
@@ -7308,9 +8150,11 @@ where
                                                        }
                                                }
                                                let need_lnd_workaround = chan.context.workaround_lnd_bug_4006.take();
-                                               htlc_forwards = self.handle_channel_resumption(
+                                               let (htlc_forwards, decode_update_add_htlcs) = self.handle_channel_resumption(
                                                        &mut peer_state.pending_msg_events, chan, responses.raa, responses.commitment_update, responses.order,
-                                                       Vec::new(), None, responses.channel_ready, responses.announcement_sigs);
+                                                       Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs);
+                                               debug_assert!(htlc_forwards.is_none());
+                                               debug_assert!(decode_update_add_htlcs.is_none());
                                                if let Some(upd) = channel_update {
                                                        peer_state.pending_msg_events.push(upd);
                                                }
@@ -7356,16 +8200,10 @@ where
                        }
                };
 
-               let mut persist = NotifyOption::SkipPersistHandleEvents;
-               if let Some(forwards) = htlc_forwards {
-                       self.forward_htlcs(&mut [forwards][..]);
-                       persist = NotifyOption::DoPersist;
-               }
-
                if let Some(channel_ready_msg) = need_lnd_workaround {
                        self.internal_channel_ready(counterparty_node_id, &channel_ready_msg)?;
                }
-               Ok(persist)
+               Ok(NotifyOption::SkipPersistHandleEvents)
        }
 
        /// Process pending events from the [`chain::Watch`], returning whether any events were processed.
@@ -7417,7 +8255,8 @@ where
                                                                                };
                                                                                failed_channels.push(chan.context.force_shutdown(false, reason.clone()));
                                                                                if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
-                                                                                       pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                                                                                       let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap();
+                                                                                       pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                                                                                msg: update
                                                                                        });
                                                                                }
@@ -7602,7 +8441,8 @@ where
                                                                                // We're done with this channel. We got a closing_signed and sent back
                                                                                // a closing_signed with a closing transaction to broadcast.
                                                                                if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
-                                                                                       pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                                                                                       let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap();
+                                                                                       pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                                                                                msg: update
                                                                                        });
                                                                                }
@@ -8362,7 +9202,7 @@ where
        /// will randomly be placed first or last in the returned array.
        ///
        /// Note that even though `BroadcastChannelAnnouncement` and `BroadcastChannelUpdate`
-       /// `MessageSendEvent`s are intended to be broadcasted to all peers, they will be pleaced among
+       /// `MessageSendEvent`s are intended to be broadcasted to all peers, they will be placed among
        /// the `MessageSendEvent`s to the specific peer they were generated under.
        fn get_and_clear_pending_msg_events(&self) -> Vec<MessageSendEvent> {
                let events = RefCell::new(Vec::new());
@@ -8382,6 +9222,7 @@ where
                                result = NotifyOption::DoPersist;
                        }
 
+                       let mut is_any_peer_connected = false;
                        let mut pending_events = Vec::new();
                        let per_peer_state = self.per_peer_state.read().unwrap();
                        for (_cp_id, peer_state_mutex) in per_peer_state.iter() {
@@ -8390,6 +9231,15 @@ where
                                if peer_state.pending_msg_events.len() > 0 {
                                        pending_events.append(&mut peer_state.pending_msg_events);
                                }
+                               if peer_state.is_connected {
+                                       is_any_peer_connected = true
+                               }
+                       }
+
+                       // Ensure that we are connected to some peers before getting broadcast messages.
+                       if is_any_peer_connected {
+                               let mut broadcast_msgs = self.pending_broadcast_messages.lock().unwrap();
+                               pending_events.append(&mut broadcast_msgs);
                        }
 
                        if !pending_events.is_empty() {
@@ -8594,6 +9444,7 @@ where
                                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                                let peer_state = &mut *peer_state_lock;
                                let pending_msg_events = &mut peer_state.pending_msg_events;
+
                                peer_state.channel_by_id.retain(|_, phase| {
                                        match phase {
                                                // Retain unfunded channels.
@@ -8669,7 +9520,8 @@ where
                                                                let reason_message = format!("{}", reason);
                                                                failed_channels.push(channel.context.force_shutdown(true, reason));
                                                                if let Ok(update) = self.get_channel_update_for_broadcast(&channel) {
-                                                                       pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
+                                                                       let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap();
+                                                                       pending_broadcast_messages.push(events::MessageSendEvent::BroadcastChannelUpdate {
                                                                                msg: update
                                                                        });
                                                                }
@@ -8761,6 +9613,9 @@ where
        }
 
        /// Returns true if this [`ChannelManager`] needs to be persisted.
+       ///
+       /// See [`Self::get_event_or_persistence_needed_future`] for retrieving a [`Future`] that
+       /// indicates this should be checked.
        pub fn get_and_clear_needs_persistence(&self) -> bool {
                self.needs_persist_flag.swap(false, Ordering::AcqRel)
        }
@@ -9126,7 +9981,12 @@ where
                                                // Gossip
                                                &events::MessageSendEvent::SendChannelAnnouncement { .. } => false,
                                                &events::MessageSendEvent::BroadcastChannelAnnouncement { .. } => true,
-                                               &events::MessageSendEvent::BroadcastChannelUpdate { .. } => true,
+                                               // [`ChannelManager::pending_broadcast_events`] holds the [`BroadcastChannelUpdate`]
+                                               // This check here is to ensure exhaustivity.
+                                               &events::MessageSendEvent::BroadcastChannelUpdate { .. } => {
+                                                       debug_assert!(false, "This event shouldn't have been here");
+                                                       false
+                                               },
                                                &events::MessageSendEvent::BroadcastNodeAnnouncement { .. } => true,
                                                &events::MessageSendEvent::SendChannelUpdate { .. } => false,
                                                &events::MessageSendEvent::SendChannelRangeQuery { .. } => false,
@@ -10198,6 +11058,12 @@ where
                        }
                }
 
+               let mut decode_update_add_htlcs_opt = None;
+               let decode_update_add_htlcs = self.decode_update_add_htlcs.lock().unwrap();
+               if !decode_update_add_htlcs.is_empty() {
+                       decode_update_add_htlcs_opt = Some(decode_update_add_htlcs);
+               }
+
                let per_peer_state = self.per_peer_state.write().unwrap();
 
                let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap();
@@ -10349,6 +11215,7 @@ where
                        (10, in_flight_monitor_updates, option),
                        (11, self.probing_cookie_secret, required),
                        (13, htlc_onion_fields, optional_vec),
+                       (14, decode_update_add_htlcs_opt, option),
                });
 
                Ok(())
@@ -10814,6 +11681,7 @@ where
                let mut monitor_update_blocked_actions_per_peer: Option<Vec<(_, BTreeMap<_, Vec<_>>)>> = Some(Vec::new());
                let mut events_override = None;
                let mut in_flight_monitor_updates: Option<HashMap<(PublicKey, OutPoint), Vec<ChannelMonitorUpdate>>> = None;
+               let mut decode_update_add_htlcs: Option<HashMap<u64, Vec<msgs::UpdateAddHTLC>>> = None;
                read_tlv_fields!(reader, {
                        (1, pending_outbound_payments_no_retry, option),
                        (2, pending_intercepted_htlcs, option),
@@ -10827,7 +11695,9 @@ where
                        (10, in_flight_monitor_updates, option),
                        (11, probing_cookie_secret, option),
                        (13, claimable_htlc_onion_fields, optional_vec),
+                       (14, decode_update_add_htlcs, option),
                });
+               let mut decode_update_add_htlcs = decode_update_add_htlcs.unwrap_or_else(|| new_hash_map());
                if fake_scid_rand_bytes.is_none() {
                        fake_scid_rand_bytes = Some(args.entropy_source.get_secure_random_bytes());
                }
@@ -10927,7 +11797,7 @@ where
                                                }
                                        }
                                        if chan.get_latest_unblocked_monitor_update_id() > max_in_flight_update_id {
-                                               // If the channel is ahead of the monitor, return InvalidValue:
+                                               // If the channel is ahead of the monitor, return DangerousValue:
                                                log_error!(logger, "A ChannelMonitor is stale compared to the current ChannelManager! This indicates a potentially-critical violation of the chain::Watch API!");
                                                log_error!(logger, " The ChannelMonitor for channel {} is at update_id {} with update_id through {} in-flight",
                                                        chan.context.channel_id(), monitor.get_latest_update_id(), max_in_flight_update_id);
@@ -10936,7 +11806,7 @@ where
                                                log_error!(logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
                                                log_error!(logger, " Without the latest ChannelMonitor we cannot continue without risking funds.");
                                                log_error!(logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/lightningdevkit/rust-lightning");
-                                               return Err(DecodeError::InvalidValue);
+                                               return Err(DecodeError::DangerousValue);
                                        }
                                } else {
                                        // We shouldn't have persisted (or read) any unfunded channel types so none should have been
@@ -11047,6 +11917,18 @@ where
                                                                // still have an entry for this HTLC in `forward_htlcs` or
                                                                // `pending_intercepted_htlcs`, we were apparently not persisted after
                                                                // the monitor was when forwarding the payment.
+                                                               decode_update_add_htlcs.retain(|scid, update_add_htlcs| {
+                                                                       update_add_htlcs.retain(|update_add_htlc| {
+                                                                               let matches = *scid == prev_hop_data.short_channel_id &&
+                                                                                       update_add_htlc.htlc_id == prev_hop_data.htlc_id;
+                                                                               if matches {
+                                                                                       log_info!(logger, "Removing pending to-decode HTLC with hash {} as it was forwarded to the closed channel {}",
+                                                                                               &htlc.payment_hash, &monitor.channel_id());
+                                                                               }
+                                                                               !matches
+                                                                       });
+                                                                       !update_add_htlcs.is_empty()
+                                                               });
                                                                forward_htlcs.retain(|_, forwards| {
                                                                        forwards.retain(|forward| {
                                                                                if let HTLCForwardInfo::AddHTLC(htlc_info) = forward {
@@ -11128,7 +12010,7 @@ where
                        }
                }
 
-               if !forward_htlcs.is_empty() || pending_outbounds.needs_abandon() {
+               if !forward_htlcs.is_empty() || !decode_update_add_htlcs.is_empty() || pending_outbounds.needs_abandon() {
                        // If we have pending HTLCs to forward, assume we either dropped a
                        // `PendingHTLCsForwardable` or the user received it but never processed it as they
                        // shut down before the timer hit. Either way, set the time_forwardable to a small
@@ -11362,6 +12244,7 @@ where
                        pending_intercepted_htlcs: Mutex::new(pending_intercepted_htlcs.unwrap()),
 
                        forward_htlcs: Mutex::new(forward_htlcs),
+                       decode_update_add_htlcs: Mutex::new(decode_update_add_htlcs),
                        claimable_payments: Mutex::new(ClaimablePayments { claimable_payments, pending_claiming_payments: pending_claiming_payments.unwrap() }),
                        outbound_scid_aliases: Mutex::new(outbound_scid_aliases),
                        outpoint_to_peer: Mutex::new(outpoint_to_peer),
@@ -11390,6 +12273,8 @@ where
 
                        pending_offers_messages: Mutex::new(Vec::new()),
 
+                       pending_broadcast_messages: Mutex::new(Vec::new()),
+
                        entropy_source: args.entropy_source,
                        node_signer: args.node_signer,
                        signer_provider: args.signer_provider,
@@ -11921,6 +12806,61 @@ mod tests {
                }
        }
 
+       #[test]
+       fn test_channel_update_cached() {
+               let chanmon_cfgs = create_chanmon_cfgs(3);
+               let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+               let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+               let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+               let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
+
+               nodes[0].node.force_close_channel_with_peer(&chan.2, &nodes[1].node.get_our_node_id(), None, true).unwrap();
+               check_added_monitors!(nodes[0], 1);
+               check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 100000);
+
+               // Confirm that the channel_update was not sent immediately to node[1] but was cached.
+               let node_1_events = nodes[1].node.get_and_clear_pending_msg_events();
+               assert_eq!(node_1_events.len(), 0);
+
+               {
+                       // Assert that ChannelUpdate message has been added to node[0] pending broadcast messages
+                       let pending_broadcast_messages= nodes[0].node.pending_broadcast_messages.lock().unwrap();
+                       assert_eq!(pending_broadcast_messages.len(), 1);
+               }
+
+               // Test that we do not retrieve the pending broadcast messages when we are not connected to any peer
+               nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
+               nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
+
+               nodes[0].node.peer_disconnected(&nodes[2].node.get_our_node_id());
+               nodes[2].node.peer_disconnected(&nodes[0].node.get_our_node_id());
+
+               let node_0_events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(node_0_events.len(), 0);
+
+               // Now we reconnect to a peer
+               nodes[0].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[2].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
+               nodes[2].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
+
+               // Confirm that get_and_clear_pending_msg_events correctly captures pending broadcast messages
+               let node_0_events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(node_0_events.len(), 1);
+               match &node_0_events[0] {
+                       MessageSendEvent::BroadcastChannelUpdate { .. } => (),
+                       _ => panic!("Unexpected event"),
+               }
+               {
+                       // Assert that ChannelUpdate message has been cleared from nodes[0] pending broadcast messages
+                       let pending_broadcast_messages= nodes[0].node.pending_broadcast_messages.lock().unwrap();
+                       assert_eq!(pending_broadcast_messages.len(), 0);
+               }
+       }
+
        #[test]
        fn test_drop_disconnected_peers_when_removing_channels() {
                let chanmon_cfgs = create_chanmon_cfgs(2);
index 04ce90445f994b6216f1a9c58ee7fcccbfcd8501..ff91654a3f79a33f2ed42cf9d2d4017ebde8fbae 100644 (file)
 //! [BOLT #9]: https://github.com/lightning/bolts/blob/master/09-features.md
 //! [messages]: crate::ln::msgs
 
-use crate::{io, io_extras};
+#[allow(unused_imports)]
 use crate::prelude::*;
+
+use crate::{io, io_extras};
 use core::{cmp, fmt};
 use core::borrow::Borrow;
 use core::hash::{Hash, Hasher};
@@ -91,6 +93,7 @@ use crate::ln::msgs::DecodeError;
 use crate::util::ser::{Readable, WithoutLength, Writeable, Writer};
 
 mod sealed {
+       #[allow(unused_imports)]
        use crate::prelude::*;
        use crate::ln::features::Features;
 
index 5840fead943049a6ac2a26eb4e784253ad3bcffb..3a506b57fe2a05b572b7f4c34b2ecc1f617b4f38 100644 (file)
@@ -1553,11 +1553,29 @@ macro_rules! check_warn_msg {
        }}
 }
 
+/// Checks if at least one peer is connected.
+fn is_any_peer_connected(node: &Node) -> bool {
+       let peer_state = node.node.per_peer_state.read().unwrap();
+       for (_, peer_mutex) in peer_state.iter() {
+               let peer = peer_mutex.lock().unwrap();
+               if peer.is_connected { return true; }
+       }
+       false
+}
+
 /// Check that a channel's closing channel update has been broadcasted, and optionally
 /// check whether an error message event has occurred.
 pub fn check_closed_broadcast(node: &Node, num_channels: usize, with_error_msg: bool) -> Vec<msgs::ErrorMessage> {
+       let mut dummy_connected = false;
+       if !is_any_peer_connected(node) {
+               connect_dummy_node(&node);
+               dummy_connected = true;
+       }
        let msg_events = node.node.get_and_clear_pending_msg_events();
        assert_eq!(msg_events.len(), if with_error_msg { num_channels * 2 } else { num_channels });
+       if dummy_connected {
+               disconnect_dummy_node(&node);
+       }
        msg_events.into_iter().filter_map(|msg_event| {
                match msg_event {
                        MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
@@ -1827,14 +1845,9 @@ macro_rules! expect_htlc_handling_failed_destinations {
 /// there are any [`Event::HTLCHandlingFailed`] events their [`HTLCDestination`] is included in the
 /// `expected_failures` set.
 pub fn expect_pending_htlcs_forwardable_conditions(events: Vec<Event>, expected_failures: &[HTLCDestination]) {
-       match events[0] {
-               Event::PendingHTLCsForwardable { .. } => { },
-               _ => panic!("Unexpected event {:?}", events),
-       };
-
        let count = expected_failures.len() + 1;
        assert_eq!(events.len(), count);
-
+       assert!(events.iter().find(|event| matches!(event, Event::PendingHTLCsForwardable { .. })).is_some());
        if expected_failures.len() > 0 {
                expect_htlc_handling_failed_destinations!(events, expected_failures)
        }
@@ -2512,6 +2525,7 @@ pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
        pub clear_recipient_events: bool,
        pub expected_preimage: Option<PaymentPreimage>,
        pub is_probe: bool,
+       pub custom_tlvs: Vec<(u64, Vec<u8>)>,
 }
 
 impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
@@ -2522,7 +2536,7 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
                Self {
                        origin_node, expected_path, recv_value, payment_hash, payment_secret: None, event,
                        payment_claimable_expected: true, clear_recipient_events: true, expected_preimage: None,
-                       is_probe: false,
+                       is_probe: false, custom_tlvs: Vec::new(),
                }
        }
        pub fn without_clearing_recipient_events(mut self) -> Self {
@@ -2546,13 +2560,17 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
                self.expected_preimage = Some(payment_preimage);
                self
        }
+       pub fn with_custom_tlvs(mut self, custom_tlvs: Vec<(u64, Vec<u8>)>) -> Self {
+               self.custom_tlvs = custom_tlvs;
+               self
+       }
 }
 
 pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option<Event> {
        let PassAlongPathArgs {
                origin_node, expected_path, recv_value, payment_hash: our_payment_hash,
                payment_secret: our_payment_secret, event: ev, payment_claimable_expected,
-               clear_recipient_events, expected_preimage, is_probe
+               clear_recipient_events, expected_preimage, is_probe, custom_tlvs
        } = args;
 
        let mut payment_event = SendEvent::from_event(ev);
@@ -2585,6 +2603,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option<Event>
                                                assert_eq!(our_payment_hash, *payment_hash);
                                                assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap());
                                                assert!(onion_fields.is_some());
+                                               assert_eq!(onion_fields.as_ref().unwrap().custom_tlvs, custom_tlvs);
                                                match &purpose {
                                                        PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
                                                                assert_eq!(expected_preimage, *payment_preimage);
@@ -3229,6 +3248,28 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
        nodes
 }
 
+pub fn connect_dummy_node<'a, 'b: 'a, 'c: 'b>(node: &Node<'a, 'b, 'c>) {
+       let node_id_dummy = PublicKey::from_slice(&[2; 33]).unwrap();
+
+       let mut dummy_init_features = InitFeatures::empty();
+       dummy_init_features.set_static_remote_key_required();
+
+       let init_dummy = msgs::Init {
+               features: dummy_init_features,
+               networks: None,
+               remote_network_address: None
+       };
+
+       node.node.peer_connected(&node_id_dummy, &init_dummy, true).unwrap();
+       node.onion_messenger.peer_connected(&node_id_dummy, &init_dummy, true).unwrap();
+}
+
+pub fn disconnect_dummy_node<'a, 'b: 'a, 'c: 'b>(node: &Node<'a, 'b, 'c>) {
+       let node_id_dummy = PublicKey::from_slice(&[2; 33]).unwrap();
+       node.node.peer_disconnected(&node_id_dummy);
+       node.onion_messenger.peer_disconnected(&node_id_dummy);
+}
+
 // Note that the following only works for CLTV values up to 128
 pub const ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 137; // Here we have a diff due to HTLC CLTV expiry being < 2^15 in test
 pub const ACCEPTED_HTLC_SCRIPT_WEIGHT_ANCHORS: usize = 140; // Here we have a diff due to HTLC CLTV expiry being < 2^15 in test
@@ -3340,15 +3381,21 @@ pub fn check_preimage_claim<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, prev_txn: &Vec<
 }
 
 pub fn handle_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, 'b, 'c>>, a: usize, b: usize, needs_err_handle: bool, expected_error: &str)  {
+       let mut dummy_connected = false;
+       if !is_any_peer_connected(&nodes[a]) {
+               connect_dummy_node(&nodes[a]);
+               dummy_connected = true
+       }
+
        let events_1 = nodes[a].node.get_and_clear_pending_msg_events();
        assert_eq!(events_1.len(), 2);
-       let as_update = match events_1[0] {
+       let as_update = match events_1[1] {
                MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
                        msg.clone()
                },
                _ => panic!("Unexpected event"),
        };
-       match events_1[1] {
+       match events_1[0] {
                MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::SendErrorMessage { ref msg } } => {
                        assert_eq!(node_id, nodes[b].node.get_our_node_id());
                        assert_eq!(msg.data, expected_error);
@@ -3365,17 +3412,24 @@ pub fn handle_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, '
                },
                _ => panic!("Unexpected event"),
        }
-
+       if dummy_connected {
+               disconnect_dummy_node(&nodes[a]);
+               dummy_connected = false;
+       }
+       if !is_any_peer_connected(&nodes[b]) {
+               connect_dummy_node(&nodes[b]);
+               dummy_connected = true;
+       }
        let events_2 = nodes[b].node.get_and_clear_pending_msg_events();
        assert_eq!(events_2.len(), if needs_err_handle { 1 } else { 2 });
-       let bs_update = match events_2[0] {
+       let bs_update = match events_2.last().unwrap() {
                MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
                        msg.clone()
                },
                _ => panic!("Unexpected event"),
        };
        if !needs_err_handle {
-               match events_2[1] {
+               match events_2[0] {
                        MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::SendErrorMessage { ref msg } } => {
                                assert_eq!(node_id, nodes[a].node.get_our_node_id());
                                assert_eq!(msg.data, expected_error);
@@ -3387,7 +3441,9 @@ pub fn handle_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, '
                        _ => panic!("Unexpected event"),
                }
        }
-
+       if dummy_connected {
+               disconnect_dummy_node(&nodes[b]);
+       }
        for node in nodes {
                node.gossip_sync.handle_channel_update(&as_update).unwrap();
                node.gossip_sync.handle_channel_update(&bs_update).unwrap();
index af6eee9cf85249bb2e2110bce91034ba1ef5b5d1..5ea3e6372c0d1c497c0b8fcde11961cfdb4206b0 100644 (file)
@@ -49,12 +49,9 @@ use bitcoin::OutPoint as BitcoinOutPoint;
 use bitcoin::secp256k1::Secp256k1;
 use bitcoin::secp256k1::{PublicKey,SecretKey};
 
-use regex;
-
 use crate::io;
 use crate::prelude::*;
 use alloc::collections::BTreeSet;
-use core::default::Default;
 use core::iter::repeat;
 use bitcoin::hashes::Hash;
 use crate::sync::{Arc, Mutex, RwLock};
@@ -2371,13 +2368,13 @@ fn channel_monitor_network_test() {
                connect_blocks(&nodes[3], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
                let events = nodes[3].node.get_and_clear_pending_msg_events();
                assert_eq!(events.len(), 2);
-               let close_chan_update_1 = match events[0] {
+               let close_chan_update_1 = match events[1] {
                        MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
                                msg.clone()
                        },
                        _ => panic!("Unexpected event"),
                };
-               match events[1] {
+               match events[0] {
                        MessageSendEvent::HandleError { action: ErrorAction::DisconnectPeer { .. }, node_id } => {
                                assert_eq!(node_id, nodes[4].node.get_our_node_id());
                        },
@@ -2403,13 +2400,13 @@ fn channel_monitor_network_test() {
                connect_blocks(&nodes[4], TEST_FINAL_CLTV - CLTV_CLAIM_BUFFER + 2);
                let events = nodes[4].node.get_and_clear_pending_msg_events();
                assert_eq!(events.len(), 2);
-               let close_chan_update_2 = match events[0] {
+               let close_chan_update_2 = match events[1] {
                        MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
                                msg.clone()
                        },
                        _ => panic!("Unexpected event"),
                };
-               match events[1] {
+               match events[0] {
                        MessageSendEvent::HandleError { action: ErrorAction::DisconnectPeer { .. }, node_id } => {
                                assert_eq!(node_id, nodes[3].node.get_our_node_id());
                        },
@@ -2750,7 +2747,7 @@ fn claim_htlc_outputs_single_tx() {
                check_added_monitors!(nodes[1], 1);
                check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed, [nodes[0].node.get_our_node_id()], 100000);
                let mut events = nodes[0].node.get_and_clear_pending_events();
-               expect_pending_htlcs_forwardable_from_events!(nodes[0], events[0..1], true);
+               expect_pending_htlcs_forwardable_conditions(events[0..2].to_vec(), &[HTLCDestination::FailedPayment { payment_hash: payment_hash_2 }]);
                match events.last().unwrap() {
                        Event::ChannelClosed { reason: ClosureReason::CommitmentTxConfirmed, .. } => {}
                        _ => panic!("Unexpected event"),
@@ -3312,13 +3309,13 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use
                let events = nodes[1].node.get_and_clear_pending_events();
                assert_eq!(events.len(), 2);
                match events[0] {
-                       Event::PendingHTLCsForwardable { .. } => { },
-                       _ => panic!("Unexpected event"),
-               };
-               match events[1] {
                        Event::HTLCHandlingFailed { .. } => { },
                        _ => panic!("Unexpected event"),
                }
+               match events[1] {
+                       Event::PendingHTLCsForwardable { .. } => { },
+                       _ => panic!("Unexpected event"),
+               };
                // Deliberately don't process the pending fail-back so they all fail back at once after
                // block connection just like the !deliver_bs_raa case
        }
@@ -4616,7 +4613,7 @@ fn test_static_spendable_outputs_preimage_tx() {
                MessageSendEvent::UpdateHTLCs { .. } => {},
                _ => panic!("Unexpected event"),
        }
-       match events[1] {
+       match events[2] {
                MessageSendEvent::BroadcastChannelUpdate { .. } => {},
                _ => panic!("Unexepected event"),
        }
@@ -4659,7 +4656,7 @@ fn test_static_spendable_outputs_timeout_tx() {
        mine_transaction(&nodes[1], &commitment_tx[0]);
        check_added_monitors!(nodes[1], 1);
        let events = nodes[1].node.get_and_clear_pending_msg_events();
-       match events[0] {
+       match events[1] {
                MessageSendEvent::BroadcastChannelUpdate { .. } => {},
                _ => panic!("Unexpected event"),
        }
@@ -5075,7 +5072,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
                MessageSendEvent::UpdateHTLCs { .. } => {},
                _ => panic!("Unexpected event"),
        }
-       match events[1] {
+       match events[2] {
                MessageSendEvent::BroadcastChannelUpdate { .. } => {},
                _ => panic!("Unexepected event"),
        }
@@ -5153,7 +5150,7 @@ fn test_dynamic_spendable_outputs_local_htlc_success_tx() {
                MessageSendEvent::UpdateHTLCs { .. } => {},
                _ => panic!("Unexpected event"),
        }
-       match events[1] {
+       match events[2] {
                MessageSendEvent::BroadcastChannelUpdate { .. } => {},
                _ => panic!("Unexepected event"),
        }
@@ -5351,7 +5348,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
        connect_blocks(&nodes[2], ANTI_REORG_DELAY - 1);
        check_closed_broadcast!(nodes[2], true);
        if deliver_last_raa {
-               expect_pending_htlcs_forwardable_from_events!(nodes[2], events[0..1], true);
+               expect_pending_htlcs_forwardable_from_events!(nodes[2], events[1..2], true);
 
                let expected_destinations: Vec<HTLCDestination> = repeat(HTLCDestination::NextHopChannel { node_id: Some(nodes[3].node.get_our_node_id()), channel_id: chan_2_3.2 }).take(3).collect();
                expect_htlc_handling_failed_destinations!(nodes[2].node.get_and_clear_pending_events(), expected_destinations);
@@ -6182,7 +6179,7 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() {
        // nodes[1]'s ChannelManager will now signal that we have HTLC forwards to process.
        let process_htlc_forwards_event = nodes[1].node.get_and_clear_pending_events();
        assert_eq!(process_htlc_forwards_event.len(), 2);
-       match &process_htlc_forwards_event[0] {
+       match &process_htlc_forwards_event[1] {
                &Event::PendingHTLCsForwardable { .. } => {},
                _ => panic!("Unexpected event"),
        }
@@ -7334,6 +7331,9 @@ fn test_announce_disable_channels() {
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
+       // Connect a dummy node for proper future events broadcasting
+       connect_dummy_node(&nodes[0]);
+
        create_announced_chan_between_nodes(&nodes, 0, 1);
        create_announced_chan_between_nodes(&nodes, 1, 0);
        create_announced_chan_between_nodes(&nodes, 0, 1);
@@ -7543,7 +7543,7 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
        let route_params = RouteParameters::from_payment_params_and_value(payment_params, 3_000_000);
        let route = get_route(&nodes[1].node.get_our_node_id(), &route_params, &nodes[1].network_graph.read_only(), None,
                nodes[0].logger, &scorer, &Default::default(), &random_seed_bytes).unwrap();
-       send_along_route(&nodes[1], route, &[&nodes[0]], 3_000_000);
+       let failed_payment_hash = send_along_route(&nodes[1], route, &[&nodes[0]], 3_000_000).1;
 
        let revoked_local_txn = get_local_commitment_txn!(nodes[1], chan.2);
        assert_eq!(revoked_local_txn[0].input.len(), 1);
@@ -7582,7 +7582,7 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
        let block_129 = create_dummy_block(block_11.block_hash(), 42, vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()]);
        connect_block(&nodes[0], &block_129);
        let events = nodes[0].node.get_and_clear_pending_events();
-       expect_pending_htlcs_forwardable_from_events!(nodes[0], events[0..1], true);
+       expect_pending_htlcs_forwardable_conditions(events[0..2].to_vec(), &[HTLCDestination::FailedPayment { payment_hash: failed_payment_hash }]);
        match events.last().unwrap() {
                Event::ChannelClosed { reason: ClosureReason::CommitmentTxConfirmed, .. } => {}
                _ => panic!("Unexpected event"),
index eeae514fdf3ce4097f79487ed09ceace231cadd4..f27d8aab1195284a0a03c74e9af2e093e8482a65 100644 (file)
@@ -9,7 +9,6 @@
 
 //! Utilities to generate inbound payment information in service of invoice creation.
 
-use alloc::string::ToString;
 use bitcoin::hashes::{Hash, HashEngine};
 use bitcoin::hashes::cmp::fixed_time_eq;
 use bitcoin::hashes::hmac::{Hmac, HmacEngine};
@@ -23,7 +22,9 @@ use crate::crypto::utils::hkdf_extract_expand_5x;
 use crate::util::errors::APIError;
 use crate::util::logger::Logger;
 
-use core::convert::{TryFrom, TryInto};
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 use core::ops::Deref;
 
 pub(crate) const IV_LEN: usize = 16;
index 25b32c4c79dda078d3daaac73b3ece86e9414c48..26a384dffd4768d9bb9e836c28fff2fa1849585a 100644 (file)
@@ -126,7 +126,9 @@ impl From<PaymentPreimage> for PaymentHash {
 #[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
 pub struct PaymentSecret(pub [u8; 32]);
 
+#[allow(unused_imports)]
 use crate::prelude::*;
+
 use bitcoin::bech32;
 use bitcoin::bech32::{Base32Len, FromBase32, ToBase32, WriteBase32, u5};
 
index 2efc3c1c051798eebcad6fc800502d85ab683659..8040d8c420984f6dae30fbd986d21afc036e7acb 100644 (file)
@@ -38,9 +38,9 @@ use crate::ln::onion_utils;
 use crate::onion_message;
 use crate::sign::{NodeSigner, Recipient};
 
+#[allow(unused_imports)]
 use crate::prelude::*;
-#[cfg(feature = "std")]
-use core::convert::TryFrom;
+
 use core::fmt;
 use core::fmt::Debug;
 use core::ops::Deref;
@@ -91,6 +91,16 @@ pub enum DecodeError {
        Io(io::ErrorKind),
        /// The message included zlib-compressed values, which we don't support.
        UnsupportedCompression,
+       /// Value is validly encoded but is dangerous to use.
+       ///
+       /// This is used for things like [`ChannelManager`] deserialization where we want to ensure
+       /// that we don't use a [`ChannelManager`] which is in out of sync with the [`ChannelMonitor`].
+       /// This indicates that there is a critical implementation flaw in the storage implementation
+       /// and it's unsafe to continue.
+       ///
+       /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+       /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor
+       DangerousValue,
 }
 
 /// An [`init`] message to be sent to or received from a peer.
@@ -1663,11 +1673,13 @@ pub struct FinalOnionHopData {
 mod fuzzy_internal_msgs {
        use bitcoin::secp256k1::PublicKey;
        use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
-       use crate::prelude::*;
        use crate::ln::{PaymentPreimage, PaymentSecret};
        use crate::ln::features::BlindedHopFeatures;
        use super::{FinalOnionHopData, TrampolineOnionPacket};
 
+       #[allow(unused_imports)]
+       use crate::prelude::*;
+
        // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
        // them from untrusted input):
 
@@ -1701,6 +1713,7 @@ mod fuzzy_internal_msgs {
                        payment_constraints: PaymentConstraints,
                        intro_node_blinding_point: Option<PublicKey>,
                        keysend_preimage: Option<PaymentPreimage>,
+                       custom_tlvs: Vec<(u64, Vec<u8>)>,
                }
        }
 
@@ -1737,6 +1750,18 @@ mod fuzzy_internal_msgs {
                        encrypted_tlvs: Vec<u8>,
                        intro_node_blinding_point: Option<PublicKey>, // Set if the introduction node of the blinded path is the final node
                        keysend_preimage: Option<PaymentPreimage>,
+                       custom_tlvs: Vec<(u64, Vec<u8>)>,
+               }
+       }
+
+       pub(crate) enum OutboundTrampolinePayload {
+               #[allow(unused)]
+               Forward {
+                       /// The value, in msat, of the payment after this hop's fee is deducted.
+                       amt_to_forward: u64,
+                       outgoing_cltv_value: u32,
+                       /// The node id to which the trampoline node must find a route
+                       outgoing_node_id: PublicKey,
                }
        }
 
@@ -1798,7 +1823,7 @@ pub struct TrampolineOnionPacket {
        // Unlike the onion packets used for payments, Trampoline onion packets have to be shorter than
        // 1300 bytes. The expected default is 650 bytes.
        // TODO: if 650 ends up being the most common size, optimize this to be:
-       // enum { ThirteenHundred([u8; 650]), VarLen(Vec<u8>) }
+       // enum { SixFifty([u8; 650]), VarLen(Vec<u8>) }
        pub hop_data: Vec<u8>,
        /// HMAC to verify the integrity of hop_data
        pub hmac: [u8; 32],
@@ -1849,6 +1874,7 @@ impl fmt::Display for DecodeError {
                        DecodeError::BadLengthDescriptor => f.write_str("A length descriptor in the packet didn't describe the later data correctly"),
                        DecodeError::Io(ref e) => fmt::Debug::fmt(e, f),
                        DecodeError::UnsupportedCompression => f.write_str("We don't support receiving messages with zlib-compressed fields"),
+                       DecodeError::DangerousValue => f.write_str("Value would be dangerous to continue execution with"),
                }
        }
 }
@@ -2581,22 +2607,43 @@ impl Writeable for OutboundOnionPayload {
                        },
                        Self::BlindedReceive {
                                sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs,
-                               intro_node_blinding_point, keysend_preimage,
+                               intro_node_blinding_point, keysend_preimage, ref custom_tlvs,
                        } => {
+                               // We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`]
+                               // to reject any reserved types in the experimental range if new ones are ever
+                               // standardized.
+                               let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode()));
+                               let mut custom_tlvs: Vec<&(u64, Vec<u8>)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect();
+                               custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ);
                                _encode_varint_length_prefixed_tlv!(w, {
                                        (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required),
                                        (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required),
                                        (10, *encrypted_tlvs, required_vec),
                                        (12, intro_node_blinding_point, option),
-                                       (18, HighZeroBytesDroppedBigSize(*total_msat), required),
-                                       (5482373484, keysend_preimage, option)
-                               });
+                                       (18, HighZeroBytesDroppedBigSize(*total_msat), required)
+                               }, custom_tlvs.iter());
                        },
                }
                Ok(())
        }
 }
 
+impl Writeable for OutboundTrampolinePayload {
+       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+               match self {
+                       Self::Forward { amt_to_forward, outgoing_cltv_value, outgoing_node_id } => {
+                               _encode_varint_length_prefixed_tlv!(w, {
+                                       (2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
+                                       (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
+                                       (14, outgoing_node_id, required)
+                               });
+                       }
+               }
+               Ok(())
+       }
+}
+
+
 impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload where NS::Target: NodeSigner {
        fn read<R: Read>(r: &mut R, args: (Option<PublicKey>, &NS)) -> Result<Self, DecodeError> {
                let (update_add_blinding_point, node_signer) = args;
@@ -2677,6 +2724,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload w
                                                payment_constraints,
                                                intro_node_blinding_point,
                                                keysend_preimage,
+                                               custom_tlvs,
                                        })
                                },
                        }
@@ -3117,7 +3165,6 @@ impl_writeable_msg!(GossipTimestampFilter, {
 
 #[cfg(test)]
 mod tests {
-       use std::convert::TryFrom;
        use bitcoin::{Transaction, TxIn, ScriptBuf, Sequence, Witness, TxOut};
        use hex::DisplayHex;
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
index 8a721a8614bf149b40385970e3ffcdad177a2481..aa8ee0ce9be6bfe3a46301c4cb5d9c57610f49c5 100644 (file)
@@ -20,7 +20,9 @@ use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
 use crate::sign::{NodeSigner, Recipient};
 use crate::util::logger::Logger;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
+
 use core::ops::Deref;
 
 /// Invalid inbound onion payment.
@@ -139,7 +141,7 @@ pub(super) fn create_recv_pending_htlc_info(
                         cltv_expiry_height, payment_metadata, false),
                msgs::InboundOnionPayload::BlindedReceive {
                        sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
-                       intro_node_blinding_point, payment_constraints, keysend_preimage, ..
+                       intro_node_blinding_point, payment_constraints, keysend_preimage, custom_tlvs
                } => {
                        check_blinded_payment_constraints(
                                sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints
@@ -152,7 +154,7 @@ pub(super) fn create_recv_pending_htlc_info(
                                        }
                                })?;
                        let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
-                       (Some(payment_data), keysend_preimage, Vec::new(),
+                       (Some(payment_data), keysend_preimage, custom_tlvs,
                         sender_intended_htlc_amt_msat, cltv_expiry_height, None,
                         intro_node_blinding_point.is_none())
                }
index 4bdd234f5aeecb214b24fa73b94d145004625c81..aeb175bc62660b6091c0a71a3960e4dc6ca1bc5e 100644 (file)
@@ -22,7 +22,7 @@ use crate::routing::gossip::{NetworkUpdate, RoutingFees};
 use crate::routing::router::{get_route, PaymentParameters, Route, RouteParameters, RouteHint, RouteHintHop};
 use crate::ln::features::{InitFeatures, Bolt11InvoiceFeatures};
 use crate::ln::msgs;
-use crate::ln::msgs::{ChannelMessageHandler, ChannelUpdate};
+use crate::ln::msgs::{ChannelMessageHandler, ChannelUpdate, OutboundTrampolinePayload};
 use crate::ln::wire::Encode;
 use crate::util::ser::{Writeable, Writer, BigSize};
 use crate::util::test_utils;
@@ -35,11 +35,11 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine};
 use bitcoin::hashes::sha256::Hash as Sha256;
 
 use bitcoin::secp256k1;
-use bitcoin::secp256k1::{Secp256k1, SecretKey};
+use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
 
 use crate::io;
 use crate::prelude::*;
-use core::default::Default;
+use bitcoin::hashes::hex::FromHex;
 
 use crate::ln::functional_test_utils::*;
 
@@ -966,6 +966,25 @@ fn test_always_create_tlv_format_onion_payloads() {
        }
 }
 
+#[test]
+fn test_trampoline_onion_payload_serialization() {
+       // As per https://github.com/lightning/bolts/blob/c01d2e6267d4a8d1095f0f1188970055a9a22d29/bolt04/trampoline-payment-onion-test.json#L3
+       let trampoline_payload = OutboundTrampolinePayload::Forward {
+               amt_to_forward: 100000000,
+               outgoing_cltv_value: 800000,
+               outgoing_node_id: PublicKey::from_slice(&<Vec<u8>>::from_hex("02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145").unwrap()).unwrap(),
+       };
+
+       let slice_to_hex = |slice: &[u8]| {
+               slice.iter()
+                       .map(|b| format!("{:02x}", b).to_string())
+                       .collect::<String>()
+       };
+
+       let carol_payload_hex = slice_to_hex(&trampoline_payload.encode());
+       assert_eq!(carol_payload_hex, "2e020405f5e10004030c35000e2102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145");
+}
+
 fn do_test_fail_htlc_backwards_with_reason(failure_code: FailureCode) {
 
        let chanmon_cfgs = create_chanmon_cfgs(2);
index 53ef0729aa171ba56ff33ba73a55cb4ed922df83..f2b5c69e9e677fb10e3886e4240b58bacd66395a 100644 (file)
@@ -30,10 +30,11 @@ use bitcoin::secp256k1::ecdh::SharedSecret;
 use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey};
 
 use crate::io::{Cursor, Read};
-use crate::prelude::*;
-use core::convert::{AsMut, TryInto};
 use core::ops::Deref;
 
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 pub(crate) struct OnionKeys {
        #[cfg(test)]
        pub(crate) shared_secret: SharedSecret,
@@ -214,6 +215,7 @@ pub(super) fn build_onion_payloads(
                                                        encrypted_tlvs: blinded_hop.encrypted_payload.clone(),
                                                        intro_node_blinding_point: blinding_point.take(),
                                                        keysend_preimage: *keysend_preimage,
+                                                       custom_tlvs: recipient_onion.custom_tlvs.clone(),
                                                });
                                        } else {
                                                res.push(msgs::OutboundOnionPayload::BlindedForward {
@@ -291,6 +293,24 @@ pub(super) fn construct_onion_packet(
        )
 }
 
+#[allow(unused)]
+pub(super) fn construct_trampoline_onion_packet(
+       payloads: Vec<msgs::OutboundTrampolinePayload>, onion_keys: Vec<OnionKeys>,
+       prng_seed: [u8; 32], associated_data: &PaymentHash, length: u16,
+) -> Result<msgs::TrampolineOnionPacket, ()> {
+       let mut packet_data = vec![0u8; length as usize];
+
+       let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]);
+       chacha.process(&vec![0u8; length as usize], &mut packet_data);
+
+       construct_onion_packet_with_init_noise::<_, _>(
+               payloads,
+               onion_keys,
+               packet_data,
+               Some(associated_data),
+       )
+}
+
 #[cfg(test)]
 /// Used in testing to write bogus `BogusOnionHopData` as well as `RawOnionHopData`, which is
 /// otherwise not representable in `msgs::OnionHopData`.
@@ -1054,6 +1074,21 @@ pub(crate) enum Hop {
        },
 }
 
+impl Hop {
+       pub(crate) fn is_intro_node_blinded_forward(&self) -> bool {
+               match self {
+                       Self::Forward {
+                               next_hop_data:
+                                       msgs::InboundOnionPayload::BlindedForward {
+                                               intro_node_blinding_point: Some(_), ..
+                                       },
+                               ..
+                       } => true,
+                       _ => false,
+               }
+       }
+}
+
 /// Error returned when we fail to decode the onion packet.
 #[derive(Debug)]
 pub(crate) enum OnionDecodeErr {
@@ -1206,10 +1241,12 @@ mod tests {
        use crate::ln::features::{ChannelFeatures, NodeFeatures};
        use crate::ln::msgs;
        use crate::ln::PaymentHash;
-       use crate::prelude::*;
        use crate::routing::router::{Path, Route, RouteHop};
        use crate::util::ser::{VecWriter, Writeable, Writer};
 
+       #[allow(unused_imports)]
+       use crate::prelude::*;
+
        use bitcoin::hashes::hex::FromHex;
        use bitcoin::secp256k1::Secp256k1;
        use bitcoin::secp256k1::{PublicKey, SecretKey};
index 09c022a4c87b1f3e8d106126fde4fd212c22b75a..a75120797cafacb1dd86f07baf7afd2842844af2 100644 (file)
@@ -3813,14 +3813,11 @@ fn test_retry_custom_tlvs() {
        check_added_monitors!(nodes[0], 1);
        let mut events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 1);
-       let payment_claimable = pass_along_path(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000,
-               payment_hash, Some(payment_secret), events.pop().unwrap(), true, None).unwrap();
-       match payment_claimable {
-               Event::PaymentClaimable { onion_fields, .. } => {
-                       assert_eq!(&onion_fields.unwrap().custom_tlvs()[..], &custom_tlvs[..]);
-               },
-               _ => panic!("Unexpected event"),
-       };
+       let path = &[&nodes[1], &nodes[2]];
+       let args = PassAlongPathArgs::new(&nodes[0], path, 1_000_000, payment_hash, events.pop().unwrap())
+               .with_payment_secret(payment_secret)
+               .with_custom_tlvs(custom_tlvs);
+       do_pass_along_path(args);
        claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], false, payment_preimage);
 }
 
index 11cdd906abad191ec163c7b0a55766b3101fb223..9c27a23467ce7a8e7134225f352fc961a3998ace 100644 (file)
@@ -36,9 +36,10 @@ use crate::util::atomic_counter::AtomicCounter;
 use crate::util::logger::{Level, Logger, WithContext};
 use crate::util::string::PrintableString;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
+
 use crate::io;
-use alloc::collections::VecDeque;
 use crate::sync::{Mutex, MutexGuard, FairRwLock};
 use core::sync::atomic::{AtomicBool, AtomicU32, AtomicI32, Ordering};
 use core::{cmp, hash, fmt, mem};
@@ -116,7 +117,9 @@ impl RoutingMessageHandler for IgnoringMessageHandler {
        fn handle_query_short_channel_ids(&self, _their_node_id: &PublicKey, _msg: msgs::QueryShortChannelIds) -> Result<(), LightningError> { Ok(()) }
        fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
        fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
-               InitFeatures::empty()
+               let mut features = InitFeatures::empty();
+               features.set_gossip_queries_optional();
+               features
        }
        fn processing_queue_high(&self) -> bool { false }
 }
@@ -1551,6 +1554,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                                                                                                }
                                                                                                (msgs::DecodeError::BadLengthDescriptor, _) => return Err(PeerHandleError { }),
                                                                                                (msgs::DecodeError::Io(_), _) => return Err(PeerHandleError { }),
+                                                                                               (msgs::DecodeError::DangerousValue, _) => return Err(PeerHandleError { }),
                                                                                        }
                                                                                }
                                                                        };
@@ -1588,15 +1592,37 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
        }
 
        /// Process an incoming message and return a decision (ok, lightning error, peer handling error) regarding the next action with the peer
+       ///
        /// Returns the message back if it needs to be broadcasted to all other peers.
        fn handle_message(
                &self,
                peer_mutex: &Mutex<Peer>,
-               mut peer_lock: MutexGuard<Peer>,
-               message: wire::Message<<<CMH as core::ops::Deref>::Target as wire::CustomMessageReader>::CustomMessage>
-       ) -> Result<Option<wire::Message<<<CMH as core::ops::Deref>::Target as wire::CustomMessageReader>::CustomMessage>>, MessageHandlingError> {
+               peer_lock: MutexGuard<Peer>,
+               message: wire::Message<<<CMH as Deref>::Target as wire::CustomMessageReader>::CustomMessage>
+       ) -> Result<Option<wire::Message<<<CMH as Deref>::Target as wire::CustomMessageReader>::CustomMessage>>, MessageHandlingError> {
                let their_node_id = peer_lock.their_node_id.clone().expect("We know the peer's public key by the time we receive messages").0;
                let logger = WithContext::from(&self.logger, Some(their_node_id), None);
+
+               let message = match self.do_handle_message_holding_peer_lock(peer_lock, message, &their_node_id, &logger)? {
+                       Some(processed_message) => processed_message,
+                       None => return Ok(None),
+               };
+
+               self.do_handle_message_without_peer_lock(peer_mutex, message, &their_node_id, &logger)
+       }
+
+       // Conducts all message processing that requires us to hold the `peer_lock`.
+       //
+       // Returns `None` if the message was fully processed and otherwise returns the message back to
+       // allow it to be subsequently processed by `do_handle_message_without_peer_lock`.
+       fn do_handle_message_holding_peer_lock<'a>(
+               &self,
+               mut peer_lock: MutexGuard<Peer>,
+               message: wire::Message<<<CMH as Deref>::Target as wire::CustomMessageReader>::CustomMessage>,
+               their_node_id: &PublicKey,
+               logger: &WithContext<'a, L>
+       ) -> Result<Option<wire::Message<<<CMH as Deref>::Target as wire::CustomMessageReader>::CustomMessage>>, MessageHandlingError>
+       {
                peer_lock.received_message_since_timer_tick = true;
 
                // Need an Init as first message
@@ -1677,8 +1703,20 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                        peer_lock.received_channel_announce_since_backlogged = true;
                }
 
-               mem::drop(peer_lock);
+               Ok(Some(message))
+       }
 
+       // Conducts all message processing that doesn't require us to hold the `peer_lock`.
+       //
+       // Returns the message back if it needs to be broadcasted to all other peers.
+       fn do_handle_message_without_peer_lock<'a>(
+               &self,
+               peer_mutex: &Mutex<Peer>,
+               message: wire::Message<<<CMH as Deref>::Target as wire::CustomMessageReader>::CustomMessage>,
+               their_node_id: &PublicKey,
+               logger: &WithContext<'a, L>
+       ) -> Result<Option<wire::Message<<<CMH as Deref>::Target as wire::CustomMessageReader>::CustomMessage>>, MessageHandlingError>
+       {
                if is_gossip_msg(message.type_id()) {
                        log_gossip!(logger, "Received message {:?} from {}", message, log_pubkey!(their_node_id));
                } else {
@@ -1880,7 +1918,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                Ok(should_forward)
        }
 
-       fn forward_broadcast_msg(&self, peers: &HashMap<Descriptor, Mutex<Peer>>, msg: &wire::Message<<<CMH as core::ops::Deref>::Target as wire::CustomMessageReader>::CustomMessage>, except_node: Option<&PublicKey>) {
+       fn forward_broadcast_msg(&self, peers: &HashMap<Descriptor, Mutex<Peer>>, msg: &wire::Message<<<CMH as Deref>::Target as wire::CustomMessageReader>::CustomMessage>, except_node: Option<&PublicKey>) {
                match msg {
                        wire::Message::ChannelAnnouncement(ref msg) => {
                                log_gossip!(self.logger, "Sending message to all peers except {:?} or the announced channel's counterparties: {:?}", except_node, msg);
@@ -2272,7 +2310,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                                                                        // We do not have the peers write lock, so we just store that we're
                                                                        // about to disconnect the peer and do it after we finish
                                                                        // processing most messages.
-                                                                       let msg = msg.map(|msg| wire::Message::<<<CMH as core::ops::Deref>::Target as wire::CustomMessageReader>::CustomMessage>::Error(msg));
+                                                                       let msg = msg.map(|msg| wire::Message::<<<CMH as Deref>::Target as wire::CustomMessageReader>::CustomMessage>::Error(msg));
                                                                        peers_to_disconnect.insert(node_id, msg);
                                                                },
                                                                msgs::ErrorAction::DisconnectPeerWithWarning { msg } => {
@@ -2645,11 +2683,13 @@ mod tests {
        use bitcoin::blockdata::constants::ChainHash;
        use bitcoin::secp256k1::{PublicKey, SecretKey};
 
-       use crate::prelude::*;
        use crate::sync::{Arc, Mutex};
        use core::convert::Infallible;
        use core::sync::atomic::{AtomicBool, Ordering};
 
+       #[allow(unused_imports)]
+       use crate::prelude::*;
+
        #[derive(Clone)]
        struct FileDescriptor {
                fd: u16,
index 3d799df8d7327d5f0895804f66c64e94cfa94b7d..6fd8623d317376b5b6d156869c2a5949bca7e33d 100644 (file)
@@ -26,7 +26,6 @@ use crate::util::ser::Writeable;
 use crate::util::test_utils;
 
 use crate::prelude::*;
-use core::default::Default;
 
 use crate::ln::functional_test_utils::*;
 
index 4422af1e8c70c63a81b93ece1aac38e2553d00a0..8b25f7701be5a2a48dad594c5bc48442c49e3253 100644 (file)
@@ -27,7 +27,6 @@ use crate::util::config::UserConfig;
 use bitcoin::hash_types::BlockHash;
 
 use crate::prelude::*;
-use core::default::Default;
 use crate::sync::Mutex;
 
 use crate::ln::functional_test_utils::*;
@@ -412,7 +411,7 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
        }
 
        let mut nodes_0_read = &nodes_0_serialized[..];
-       if let Err(msgs::DecodeError::InvalidValue) =
+       if let Err(msgs::DecodeError::DangerousValue) =
                <(BlockHash, ChannelManager<&test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestRouter, &test_utils::TestLogger>)>::read(&mut nodes_0_read, ChannelManagerReadArgs {
                default_config: UserConfig::default(),
                entropy_source: keys_manager,
index dc733dd25a1f0ca154c773f1987d4861e4d30a23..1909eb0c5f7df5f347ea0484bfbdd08fa8a239f8 100644 (file)
@@ -12,9 +12,11 @@ use crate::ln::features::InitFeatures;
 use crate::ln::msgs::DecodeError;
 use crate::util::ser::{Readable, Writeable, Writer};
 
-use core::convert::TryFrom;
 use crate::io;
 
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 /// A script pubkey for shutting down a channel as defined by [BOLT #2].
 ///
 /// [BOLT #2]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md
@@ -167,13 +169,15 @@ impl core::fmt::Display for ShutdownScript{
 #[cfg(test)]
 mod shutdown_script_tests {
        use super::ShutdownScript;
+
+       use bitcoin::address::{WitnessProgram, WitnessVersion};
        use bitcoin::blockdata::opcodes;
        use bitcoin::blockdata::script::{Builder, ScriptBuf};
        use bitcoin::secp256k1::Secp256k1;
        use bitcoin::secp256k1::{PublicKey, SecretKey};
+
        use crate::ln::features::InitFeatures;
-       use core::convert::TryFrom;
-       use bitcoin::address::{WitnessProgram, WitnessVersion};
+       use crate::prelude::*;
 
        fn pubkey() -> bitcoin::key::PublicKey {
                let secp_ctx = Secp256k1::signing_only();
index c6d0cc58b9bf299a1fc2d6e06a34a9a6bc0b3958..7f004948ffeb5cb10790673e5fa36680950bef23 100644 (file)
@@ -25,6 +25,7 @@ use crate::util::test_utils::OnGetShutdownScriptpubkey;
 use crate::util::errors::APIError;
 use crate::util::config::UserConfig;
 use crate::util::string::UntrustedString;
+use crate::prelude::*;
 
 use bitcoin::{Transaction, TxOut};
 use bitcoin::blockdata::locktime::absolute::LockTime;
@@ -33,11 +34,6 @@ use bitcoin::blockdata::opcodes;
 use bitcoin::network::constants::Network;
 use bitcoin::address::{WitnessProgram, WitnessVersion};
 
-use regex;
-
-use core::default::Default;
-use std::convert::TryFrom;
-
 use crate::ln::functional_test_utils::*;
 
 #[test]
index 5087df33b83fee55bfd7edc788ae13459deb486e..dc4eecde6306748e972657423049eef17b879929 100644 (file)
@@ -617,7 +617,6 @@ impl Encode for msgs::GossipTimestampFilter {
 mod tests {
        use super::*;
        use crate::prelude::*;
-       use core::convert::TryInto;
        use crate::ln::peer_handler::IgnoringMessageHandler;
 
        // Big-endian wire encoding of Pong message (type = 19, byteslen = 2).
index fc8371023484d8ade7a2708340a0e2402685d710..f2fb387942dc303e2c895e4e4917777a07aa6492 100644 (file)
@@ -1,4 +1,4 @@
-// This file is Copyright its original authors, visible in version control
+    // This file is Copyright its original authors, visible in version control
 // history.
 //
 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
@@ -110,7 +110,6 @@ use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, self};
 use bitcoin::secp256k1::schnorr::Signature;
 use bitcoin::address::{Address, Payload, WitnessProgram, WitnessVersion};
 use bitcoin::key::TweakedPublicKey;
-use core::convert::{AsRef, TryFrom};
 use core::time::Duration;
 use crate::io;
 use crate::blinded_path::BlindedPath;
@@ -129,6 +128,7 @@ use crate::offers::signer;
 use crate::util::ser::{HighZeroBytesDroppedBigSize, Iterable, SeekReadable, WithoutLength, Writeable, Writer};
 use crate::util::string::PrintableString;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 #[cfg(feature = "std")]
@@ -1452,8 +1452,9 @@ mod tests {
        use bitcoin::secp256k1::{Message, Secp256k1, XOnlyPublicKey, self};
        use bitcoin::address::{Address, Payload, WitnessProgram, WitnessVersion};
        use bitcoin::key::TweakedPublicKey;
-       use core::convert::TryFrom;
+
        use core::time::Duration;
+
        use crate::blinded_path::{BlindedHop, BlindedPath};
        use crate::sign::KeyMaterial;
        use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
@@ -1462,6 +1463,7 @@ mod tests {
        use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
        use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
        use crate::offers::offer::{Amount, OfferTlvStreamRef, Quantity};
+       use crate::prelude::*;
        #[cfg(not(c_bindings))]
        use {
                crate::offers::offer::OfferBuilder,
index 5476ad551b7b627d5e1abac8d19fc836b673e54c..1b634525416acef1a249858a7d78cc44b3c03b06 100644 (file)
@@ -15,6 +15,7 @@ use crate::offers::parse::Bolt12SemanticError;
 use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
 use crate::util::string::UntrustedString;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 /// An error in response to an [`InvoiceRequest`] or an [`Bolt12Invoice`].
index f282075d9333cf1f9002154519474518036b9336..5e3ed40ac08db2b2a8a662c357bb4eb475fb45fc 100644 (file)
@@ -61,7 +61,6 @@ use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::network::constants::Network;
 use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, self};
 use bitcoin::secp256k1::schnorr::Signature;
-use core::convert::{AsRef, TryFrom};
 use core::ops::Deref;
 use crate::sign::EntropySource;
 use crate::io;
@@ -89,6 +88,7 @@ use {
        crate::offers::invoice::{InvoiceWithDerivedSigningPubkeyBuilder, InvoiceWithExplicitSigningPubkeyBuilder},
 };
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 /// Tag for the hash function used when signing an [`InvoiceRequest`]'s merkle root.
@@ -1103,7 +1103,6 @@ mod tests {
        use bitcoin::blockdata::constants::ChainHash;
        use bitcoin::network::constants::Network;
        use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey, self};
-       use core::convert::TryFrom;
        use core::num::NonZeroU64;
        #[cfg(feature = "std")]
        use core::time::Duration;
index 941bf196716d8b5ee2d2e51d2c4db95716bdf869..da3fab589966d8d3d5988437a72aec56bbc1b8d8 100644 (file)
 use bitcoin::hashes::{Hash, HashEngine, sha256};
 use bitcoin::secp256k1::{Message, PublicKey, Secp256k1, self};
 use bitcoin::secp256k1::schnorr::Signature;
-use core::convert::AsRef;
 use crate::io;
 use crate::util::ser::{BigSize, Readable, Writeable, Writer};
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 /// Valid type range for signature TLV records.
index bf5e50deb77b8c290c1385f3459b76fb17bfbd6d..f7b75138b5108bbecad7cae5faae4ede0d9749e5 100644 (file)
@@ -79,7 +79,6 @@
 use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::network::constants::Network;
 use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, self};
-use core::convert::TryFrom;
 use core::hash::{Hash, Hasher};
 use core::num::NonZeroU64;
 use core::ops::Deref;
@@ -107,6 +106,7 @@ use {
        crate::offers::invoice_request::{InvoiceRequestWithDerivedPayerIdBuilder, InvoiceRequestWithExplicitPayerIdBuilder},
 };
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 #[cfg(feature = "std")]
@@ -459,6 +459,16 @@ for OfferWithDerivedMetadataBuilder<'a> {
        }
 }
 
+#[cfg(c_bindings)]
+impl<'a> From<OfferWithDerivedMetadataBuilder<'a>>
+for OfferBuilder<'a, DerivedMetadata, secp256k1::All> {
+       fn from(builder: OfferWithDerivedMetadataBuilder<'a>) -> Self {
+               let OfferWithDerivedMetadataBuilder { offer, metadata_strategy, secp_ctx } = builder;
+
+               Self { offer, metadata_strategy, secp_ctx }
+       }
+}
+
 /// An `Offer` is a potentially long-lived proposal for payment of a good or service.
 ///
 /// An offer is a precursor to an [`InvoiceRequest`]. A merchant publishes an offer from which a
@@ -1066,7 +1076,6 @@ mod tests {
        use bitcoin::blockdata::constants::ChainHash;
        use bitcoin::network::constants::Network;
        use bitcoin::secp256k1::Secp256k1;
-       use core::convert::TryFrom;
        use core::num::NonZeroU64;
        use core::time::Duration;
        use crate::blinded_path::{BlindedHop, BlindedPath};
index 400cf51a2944d47cc0afd19e227acb3216242959..72c4c380d52592f8c87b59c9f50653a449fec0b9 100644 (file)
 
 use bitcoin::bech32;
 use bitcoin::secp256k1;
-use core::convert::TryFrom;
 use crate::io;
 use crate::ln::msgs::DecodeError;
 use crate::util::ser::SeekReadable;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 #[cfg(not(fuzzing))]
@@ -27,10 +27,10 @@ pub use sealed::Bech32Encode;
 mod sealed {
        use bitcoin::bech32;
        use bitcoin::bech32::{FromBase32, ToBase32};
-       use core::convert::TryFrom;
        use core::fmt;
        use super::Bolt12ParseError;
 
+       #[allow(unused_imports)]
        use crate::prelude::*;
 
        /// Indicates a message can be encoded using bech32.
index 19aef23363d8e0afc9a5ddd758d5808098d1d03f..22180ce5f66fef52a2cba2a434c61e769cb287b8 100644 (file)
@@ -12,6 +12,7 @@
 use crate::offers::signer::Metadata;
 use crate::util::ser::WithoutLength;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 /// An unpredictable sequence of bytes typically containing information needed to derive
index 42177960868ab553ee1385f2569146dc8209e2bf..16014cd3c0b7ac6080a31b1c198b7bb669798219 100644 (file)
@@ -84,7 +84,6 @@
 use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::network::constants::Network;
 use bitcoin::secp256k1::{PublicKey, Secp256k1, self};
-use core::convert::TryFrom;
 use core::hash::{Hash, Hasher};
 use core::ops::Deref;
 use core::str::FromStr;
@@ -115,6 +114,7 @@ use {
        crate::offers::invoice::{InvoiceWithDerivedSigningPubkeyBuilder, InvoiceWithExplicitSigningPubkeyBuilder},
 };
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 #[cfg(feature = "std")]
@@ -375,6 +375,16 @@ for RefundMaybeWithDerivedMetadataBuilder<'a> {
        }
 }
 
+#[cfg(c_bindings)]
+impl<'a> From<RefundMaybeWithDerivedMetadataBuilder<'a>>
+for RefundBuilder<'a, secp256k1::All> {
+       fn from(builder: RefundMaybeWithDerivedMetadataBuilder<'a>) -> Self {
+               let RefundMaybeWithDerivedMetadataBuilder { refund, secp_ctx } = builder;
+
+               Self { refund, secp_ctx }
+       }
+}
+
 /// A `Refund` is a request to send an [`Bolt12Invoice`] without a preceding [`Offer`].
 ///
 /// Typically, after an invoice is paid, the recipient may publish a refund allowing the sender to
@@ -894,8 +904,9 @@ mod tests {
        use bitcoin::blockdata::constants::ChainHash;
        use bitcoin::network::constants::Network;
        use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey};
-       use core::convert::TryFrom;
+
        use core::time::Duration;
+
        use crate::blinded_path::{BlindedHop, BlindedPath};
        use crate::sign::KeyMaterial;
        use crate::ln::channelmanager::PaymentId;
@@ -909,6 +920,7 @@ mod tests {
        use crate::offers::test_utils::*;
        use crate::util::ser::{BigSize, Writeable};
        use crate::util::string::PrintableString;
+       use crate::prelude::*;
 
        trait ToBytes {
                fn to_bytes(&self) -> Vec<u8>;
index e0abd82767f6c9fd51dc0a7e425f7236631a0f67..c5a96cbf18491e3f22eb830c879eb4d274e9abc3 100644 (file)
@@ -14,7 +14,6 @@ use bitcoin::hashes::cmp::fixed_time_eq;
 use bitcoin::hashes::hmac::{Hmac, HmacEngine};
 use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey, self};
-use core::convert::TryFrom;
 use core::fmt;
 use crate::ln::channelmanager::PaymentId;
 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
index 29bed53d83f561f030e4966373c4403020ac6ffc..b4329803016fadb395689bf696e30d78c2984e97 100644 (file)
@@ -11,7 +11,7 @@
 
 use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
 use bitcoin::secp256k1::schnorr::Signature;
-use core::convert::AsRef; 
+
 use core::time::Duration;
 use crate::blinded_path::{BlindedHop, BlindedPath};
 use crate::sign::EntropySource;
@@ -20,6 +20,9 @@ use crate::ln::features::BlindedHopFeatures;
 use crate::offers::invoice::BlindedPayInfo;
 use crate::offers::merkle::TaggedHash;
 
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 pub(crate) fn fail_sign<T: AsRef<TaggedHash>>(_message: &T) -> Result<Signature, ()> {
        Err(())
 }
index 6672b5dfcdd0f3e33025c4bfe0654d6cfd2b0e56..faf539f868261a97768e6051b22451861db737ca 100644 (file)
@@ -9,7 +9,6 @@
 
 //! Message handling for BOLT 12 Offers.
 
-use core::convert::TryFrom;
 use core::fmt;
 use crate::io::{self, Read};
 use crate::ln::msgs::DecodeError;
index 045772486ba7aa150636a1e7b5420a606e87ce64..42bf20a78a51684056f896b50fc510d18b279d0f 100644 (file)
@@ -38,7 +38,6 @@ use crate::io;
 use crate::io_extras::{copy, sink};
 use crate::prelude::*;
 use core::{cmp, fmt};
-use core::convert::TryFrom;
 use crate::sync::{RwLock, RwLockReadGuard, LockTestExt};
 #[cfg(feature = "std")]
 use core::sync::atomic::{AtomicUsize, Ordering};
index 8d37182266b11debdda0d96787358c36c87dcd59..e8276712ee89504e002b619aa70544a147467840 100644 (file)
@@ -3259,8 +3259,6 @@ mod tests {
        use crate::prelude::*;
        use crate::sync::Arc;
 
-       use core::convert::TryInto;
-
        fn get_channel_details(short_channel_id: Option<u64>, node_id: PublicKey,
                        features: InitFeatures, outbound_capacity_msat: u64) -> channelmanager::ChannelDetails {
                channelmanager::ChannelDetails {
@@ -8344,17 +8342,14 @@ pub(crate) mod bench_utils {
        use std::time::Duration;
 
        use bitcoin::hashes::Hash;
-       use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
+       use bitcoin::secp256k1::SecretKey;
 
        use crate::chain::transaction::OutPoint;
        use crate::routing::scoring::ScoreUpdate;
-       use crate::sign::{EntropySource, KeysManager};
+       use crate::sign::KeysManager;
        use crate::ln::ChannelId;
-       use crate::ln::channelmanager::{self, ChannelCounterparty, ChannelDetails};
-       use crate::ln::features::Bolt11InvoiceFeatures;
-       use crate::routing::gossip::NetworkGraph;
+       use crate::ln::channelmanager::{self, ChannelCounterparty};
        use crate::util::config::UserConfig;
-       use crate::util::ser::ReadableArgs;
        use crate::util::test_utils::TestLogger;
 
        /// Tries to open a network graph file, or panics with a URL to fetch it.
index bb043164a0e8895f8bbe95c8d0f50b7025d8365b..4850479b8992905cc20e6d1e219dab6251081b28 100644 (file)
@@ -64,7 +64,6 @@ use crate::util::logger::Logger;
 
 use crate::prelude::*;
 use core::{cmp, fmt};
-use core::convert::TryInto;
 use core::ops::{Deref, DerefMut};
 use core::time::Duration;
 use crate::io::{self, Read};
index 9f03b4451eff025665517769934b9a62fd09be47..6aca76a21678ceabc25f3e66ded06c96b1f883aa 100644 (file)
@@ -21,6 +21,7 @@ use bitcoin::network::constants::Network;
 use bitcoin::secp256k1::{PublicKey,SecretKey};
 use bitcoin::secp256k1::{Secp256k1, All};
 
+#[allow(unused)]
 use crate::prelude::*;
 use crate::sync::{self, Arc};
 
index ada90345ee6861ac53a7d81191ea04bfe93a508d..e775e2628f6ca1df9e497a084506be7dd7eed6eb 100644 (file)
@@ -563,7 +563,6 @@ mod tests {
        use super::*;
        use crate::routing::gossip::tests::*;
        use crate::util::test_utils::{TestChainSource, TestLogger};
-       use crate::ln::msgs;
 
        use bitcoin::secp256k1::{Secp256k1, SecretKey};
 
index 070f48f122f9d6365bade472bb87fe3af8ee1b47..45152cf6937d668496b66166c42d96614f084e54 100644 (file)
@@ -11,7 +11,9 @@ use crate::ln::PaymentPreimage;
 use crate::ln::chan_utils::{HTLCOutputInCommitment, HolderCommitmentTransaction, CommitmentTransaction, ClosingTransaction};
 use crate::ln::msgs::UnsignedChannelAnnouncement;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
+
 use crate::sign::{ChannelSigner, HTLCDescriptor};
 
 /// A trait to sign Lightning channel transactions as described in
index a7237493be7592676d0d22b2d6e00e43cf929995..2a5d19efd1c59f119fc1554cc60190c5cd239060 100644 (file)
@@ -53,7 +53,6 @@ use crate::offers::invoice::UnsignedBolt12Invoice;
 use crate::offers::invoice_request::UnsignedInvoiceRequest;
 
 use crate::prelude::*;
-use core::convert::TryInto;
 use core::ops::Deref;
 use core::sync::atomic::{AtomicUsize, Ordering};
 #[cfg(taproot)]
@@ -736,6 +735,19 @@ pub trait NodeSigner {
        fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()>;
 }
 
+// Primarily needed in doctests because of https://github.com/rust-lang/rust/issues/67295
+/// A dynamic [`SignerProvider`] temporarily needed for doc tests.
+#[cfg(taproot)]
+#[doc(hidden)]
+#[deprecated(note = "Remove once taproot cfg is removed")]
+pub type DynSignerProvider = dyn SignerProvider<EcdsaSigner = InMemorySigner, TaprootSigner = InMemorySigner>;
+
+/// A dynamic [`SignerProvider`] temporarily needed for doc tests.
+#[cfg(not(taproot))]
+#[doc(hidden)]
+#[deprecated(note = "Remove once taproot cfg is removed")]
+pub type DynSignerProvider = dyn SignerProvider<EcdsaSigner = InMemorySigner>;
+
 /// A trait that can return signer instances for individual channels.
 pub trait SignerProvider {
        /// A type which implements [`WriteableEcdsaChannelSigner`] which will be returned by [`Self::derive_channel_signer`].
index 2b75e095380ec09f22d07d4d1bd636dd93e53c61..5968a79ee4daa50439a3cac96478c49d3803458b 100644 (file)
@@ -103,7 +103,9 @@ fn locate_call_symbol(backtrace: &Backtrace) -> (String, Option<u32>) {
                        }
                }
        }
-       let symbol = symbol_after_latest_debug_sync.expect("Couldn't find lock call symbol");
+       let symbol = symbol_after_latest_debug_sync.unwrap_or_else(|| {
+               panic!("Couldn't find lock call symbol in trace {:?}", backtrace);
+       });
        (format!("{}:{}", symbol.filename().unwrap().display(), symbol.lineno().unwrap()), symbol.colno())
 }
 
index 2e66d59383fb9d7db7d81fdbafdf1beb8d4e31d7..e116dccbf59ad5bee31f1aa50bb7e2323f127774 100644 (file)
@@ -6,7 +6,7 @@
 // Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or
 // MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT) at your option.
 
-
+#[allow(unused)]
 use crate::prelude::*;
 
 /// RFC4648 encoding table
index 4ffde9a72d2cba94927e36373125d0d06fdb73d4..735ce044f810b6a4f9aa97e500c1c628cd43ee4d 100644 (file)
@@ -11,7 +11,9 @@
 
 use crate::ln::script::ShutdownScript;
 
-use alloc::string::String;
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 use core::fmt;
 
 /// Indicates an error on the client's part (usually some variant of attempting to use too-low or
index d4c20f722154fe499c68a296c45f25d8dd55aff4..4f694bd2b6ec723e5dcaed614db36bdad0ea2aeb 100644 (file)
@@ -1,10 +1,8 @@
 //! This module has a map which can be iterated in a deterministic order. See the [`IndexedMap`].
 
 use crate::prelude::*;
-use alloc::vec::Vec;
 use alloc::slice::Iter;
 use core::hash::Hash;
-use core::cmp::Ord;
 use core::ops::{Bound, RangeBounds};
 
 /// A map which can be iterated in a deterministic order.
index 8c22200b9b2c2fecebfb4276228a91ce97db1274..b6cf452ffc955935a55a3e4cb801c649fb10d915 100644 (file)
@@ -1,6 +1,8 @@
 //! Low level invoice utilities.
 
 use bitcoin::bech32::{u5, FromBase32};
+
+#[allow(unused)]
 use crate::prelude::*;
 
 /// Construct the invoice's HRP and signatureless data into a preimage to be hashed.
index 88ff18ff204c8ae96ee723bd0a718bed0ae3394a..79572f31246a7ae53fa1885b13ee3cc282c68d50 100644 (file)
@@ -20,6 +20,7 @@
 //! <https://lightning.readthedocs.io/lightning-signmessage.7.html>
 //! <https://api.lightning.community/#signmessage>
 
+#[allow(unused)]
 use crate::prelude::*;
 use crate::util::base32;
 use bitcoin::hashes::{sha256d, Hash};
index 35f5b0c79224b18fb4b1aa30a6cad2bdd585a49f..6fd0048daf7ddeec9e3f754c0f368e44572891d4 100644 (file)
 //! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
 
 use core::cmp;
-use core::convert::{TryFrom, TryInto};
 use core::ops::Deref;
 use core::str::FromStr;
 use bitcoin::{BlockHash, Txid};
 
 use crate::{io, log_error};
-use crate::alloc::string::ToString;
 use crate::prelude::*;
 
 use crate::chain;
@@ -158,7 +156,7 @@ where
 }
 
 
-impl<'a, A: KVStore, CM: Deref, L: Deref, S: WriteableScore<'a>> Persister<'a, CM, L, S> for A
+impl<'a, A: KVStore + ?Sized, CM: Deref, L: Deref, S: WriteableScore<'a>> Persister<'a, CM, L, S> for A
 where
        CM::Target: 'static + AChannelManager,
        L::Target: 'static + Logger,
@@ -185,65 +183,7 @@ where
        }
 }
 
-impl<'a, CM: Deref, L: Deref, S: WriteableScore<'a>> Persister<'a, CM, L, S> for dyn KVStore + Send + Sync
-where
-       CM::Target: 'static + AChannelManager,
-       L::Target: 'static + Logger,
-{
-       fn persist_manager(&self, channel_manager: &CM) -> Result<(), io::Error> {
-               self.write(CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
-                       CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE,
-                       CHANNEL_MANAGER_PERSISTENCE_KEY,
-                       &channel_manager.get_cm().encode())
-       }
-
-       fn persist_graph(&self, network_graph: &NetworkGraph<L>) -> Result<(), io::Error> {
-               self.write(NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE,
-                       NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE,
-                       NETWORK_GRAPH_PERSISTENCE_KEY,
-                       &network_graph.encode())
-       }
-
-       fn persist_scorer(&self, scorer: &S) -> Result<(), io::Error> {
-               self.write(SCORER_PERSISTENCE_PRIMARY_NAMESPACE,
-                       SCORER_PERSISTENCE_SECONDARY_NAMESPACE,
-                       SCORER_PERSISTENCE_KEY,
-                       &scorer.encode())
-       }
-}
-
-impl<ChannelSigner: WriteableEcdsaChannelSigner, K: KVStore> Persist<ChannelSigner> for K {
-       // TODO: We really need a way for the persister to inform the user that its time to crash/shut
-       // down once these start returning failure.
-       // Then we should return InProgress rather than UnrecoverableError, implying we should probably
-       // just shut down the node since we're not retrying persistence!
-
-       fn persist_new_channel(&self, funding_txo: OutPoint, monitor: &ChannelMonitor<ChannelSigner>, _update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
-               let key = format!("{}_{}", funding_txo.txid.to_string(), funding_txo.index);
-               match self.write(
-                       CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
-                       CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
-                       &key, &monitor.encode())
-               {
-                       Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
-                       Err(_) => chain::ChannelMonitorUpdateStatus::UnrecoverableError
-               }
-       }
-
-       fn update_persisted_channel(&self, funding_txo: OutPoint, _update: Option<&ChannelMonitorUpdate>, monitor: &ChannelMonitor<ChannelSigner>, _update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
-               let key = format!("{}_{}", funding_txo.txid.to_string(), funding_txo.index);
-               match self.write(
-                       CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
-                       CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
-                       &key, &monitor.encode())
-               {
-                       Ok(()) => chain::ChannelMonitorUpdateStatus::Completed,
-                       Err(_) => chain::ChannelMonitorUpdateStatus::UnrecoverableError
-               }
-       }
-}
-
-impl<ChannelSigner: WriteableEcdsaChannelSigner> Persist<ChannelSigner> for dyn KVStore + Send + Sync {
+impl<ChannelSigner: WriteableEcdsaChannelSigner, K: KVStore + ?Sized> Persist<ChannelSigner> for K {
        // TODO: We really need a way for the persister to inform the user that its time to crash/shut
        // down once these start returning failure.
        // Then we should return InProgress rather than UnrecoverableError, implying we should probably
@@ -895,12 +835,13 @@ impl From<u64> for UpdateName {
 #[cfg(test)]
 mod tests {
        use super::*;
-       use crate::chain::chainmonitor::Persist;
        use crate::chain::ChannelMonitorUpdateStatus;
        use crate::events::{ClosureReason, MessageSendEventsProvider};
        use crate::ln::functional_test_utils::*;
        use crate::util::test_utils::{self, TestLogger, TestStore};
        use crate::{check_added_monitors, check_closed_broadcast};
+       use crate::sync::Arc;
+       use crate::util::test_channel_signer::TestChannelSigner;
 
        const EXPECTED_UPDATES_PER_PAYMENT: u64 = 5;
 
@@ -1241,4 +1182,14 @@ mod tests {
                        .read(CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE, monitor_name.as_str(), UpdateName::from(u64::MAX - 1).as_str())
                        .is_err());
        }
+
+       fn persist_fn<P: Deref, ChannelSigner: WriteableEcdsaChannelSigner>(_persist: P) -> bool where P::Target: Persist<ChannelSigner> {
+               true
+       }
+
+       #[test]
+       fn kvstore_trait_object_usage() {
+               let store: Arc<dyn KVStore + Send + Sync> = Arc::new(TestStore::new(false));
+               assert!(persist_fn::<_, TestChannelSigner>(store.clone()));
+       }
 }
index 38be0eb88fc3bdc0767c6725e30fb7437f3bbec4..c9485b60b70be78fd88b52eb45703c74f4da5af1 100644 (file)
@@ -76,8 +76,8 @@ pub(crate) mod fake_scid {
        use crate::sign::EntropySource;
        use crate::crypto::chacha20::ChaCha20;
        use crate::util::scid_utils;
+       use crate::prelude::*;
 
-       use core::convert::TryInto;
        use core::ops::Deref;
 
        const TEST_SEGWIT_ACTIVATION_HEIGHT: u32 = 1;
index 0611e6ffb385b66459f93d3cee1fc46ec1f46223..f88d9f36a72832ef1161c4ff65b48abb9e66a14a 100644 (file)
@@ -19,7 +19,6 @@ use crate::io_extras::{copy, sink};
 use core::hash::Hash;
 use crate::sync::{Mutex, RwLock};
 use core::cmp;
-use core::convert::TryFrom;
 use core::ops::Deref;
 
 use alloc::collections::BTreeMap;
@@ -35,7 +34,6 @@ use bitcoin::{consensus, Witness};
 use bitcoin::consensus::Encodable;
 use bitcoin::hashes::sha256d::Hash as Sha256dHash;
 use bitcoin::hash_types::{Txid, BlockHash};
-use core::marker::Sized;
 use core::time::Duration;
 use crate::chain::ClaimId;
 use crate::ln::msgs::DecodeError;
@@ -108,14 +106,14 @@ impl Writer for LengthCalculatingWriter {
 /// forward to ensure we always consume exactly the fixed length specified.
 ///
 /// This is not exported to bindings users as manual TLV building is not currently supported in bindings
-pub struct FixedLengthReader<R: Read> {
-       read: R,
+pub struct FixedLengthReader<'a, R: Read> {
+       read: &'a mut R,
        bytes_read: u64,
        total_bytes: u64,
 }
-impl<R: Read> FixedLengthReader<R> {
+impl<'a, R: Read> FixedLengthReader<'a, R> {
        /// Returns a new [`FixedLengthReader`].
-       pub fn new(read: R, total_bytes: u64) -> Self {
+       pub fn new(read: &'a mut R, total_bytes: u64) -> Self {
                Self { read, bytes_read: 0, total_bytes }
        }
 
@@ -136,7 +134,7 @@ impl<R: Read> FixedLengthReader<R> {
                }
        }
 }
-impl<R: Read> Read for FixedLengthReader<R> {
+impl<'a, R: Read> Read for FixedLengthReader<'a, R> {
        #[inline]
        fn read(&mut self, dest: &mut [u8]) -> Result<usize, io::Error> {
                if self.total_bytes == self.bytes_read {
@@ -154,7 +152,7 @@ impl<R: Read> Read for FixedLengthReader<R> {
        }
 }
 
-impl<R: Read> LengthRead for FixedLengthReader<R> {
+impl<'a, R: Read> LengthRead for FixedLengthReader<'a, R> {
        #[inline]
        fn total_bytes(&self) -> u64 {
                self.total_bytes
@@ -820,6 +818,49 @@ macro_rules! impl_for_vec {
        }
 }
 
+// Alternatives to impl_writeable_for_vec/impl_readable_for_vec that add a length prefix to each
+// element in the Vec. Intended to be used when elements have variable lengths.
+macro_rules! impl_writeable_for_vec_with_element_length_prefix {
+       ($ty: ty $(, $name: ident)*) => {
+               impl<$($name : Writeable),*> Writeable for Vec<$ty> {
+                       #[inline]
+                       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+                               CollectionLength(self.len() as u64).write(w)?;
+                               for elem in self.iter() {
+                                       CollectionLength(elem.serialized_length() as u64).write(w)?;
+                                       elem.write(w)?;
+                               }
+                               Ok(())
+                       }
+               }
+       }
+}
+macro_rules! impl_readable_for_vec_with_element_length_prefix {
+       ($ty: ty $(, $name: ident)*) => {
+               impl<$($name : Readable),*> Readable for Vec<$ty> {
+                       #[inline]
+                       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+                               let len: CollectionLength = Readable::read(r)?;
+                               let mut ret = Vec::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<$ty>()));
+                               for _ in 0..len.0 {
+                                       let elem_len: CollectionLength = Readable::read(r)?;
+                                       let mut elem_reader = FixedLengthReader::new(r, elem_len.0);
+                                       if let Some(val) = MaybeReadable::read(&mut elem_reader)? {
+                                               ret.push(val);
+                                       }
+                               }
+                               Ok(ret)
+                       }
+               }
+       }
+}
+macro_rules! impl_for_vec_with_element_length_prefix {
+       ($ty: ty $(, $name: ident)*) => {
+               impl_writeable_for_vec_with_element_length_prefix!($ty $(, $name)*);
+               impl_readable_for_vec_with_element_length_prefix!($ty $(, $name)*);
+       }
+}
+
 impl Writeable for Vec<u8> {
        #[inline]
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
@@ -851,6 +892,8 @@ impl_for_vec!(crate::ln::msgs::SocketAddress);
 impl_for_vec!((A, B), A, B);
 impl_writeable_for_vec!(&crate::routing::router::BlindedTail);
 impl_readable_for_vec!(crate::routing::router::BlindedTail);
+impl_for_vec_with_element_length_prefix!(crate::ln::msgs::UpdateAddHTLC);
+impl_writeable_for_vec_with_element_length_prefix!(&crate::ln::msgs::UpdateAddHTLC);
 
 impl Writeable for Vec<Witness> {
        #[inline]
@@ -1449,10 +1492,10 @@ impl Readable for ClaimId {
 
 #[cfg(test)]
 mod tests {
-       use core::convert::TryFrom;
        use bitcoin::hashes::hex::FromHex;
        use bitcoin::secp256k1::ecdsa;
        use crate::util::ser::{Readable, Hostname, Writeable};
+       use crate::prelude::*;
 
        #[test]
        fn hostname_conversion() {
index e1f4762ecbb8dde0b2600cd9b5fe5a85aa453fdc..df030d0b01eb4452ccf8e7b391e8c738bb9af453 100644 (file)
@@ -1053,7 +1053,7 @@ macro_rules! impl_writeable_tlv_based_enum {
                                        $($variant_id => {
                                                // Because read_tlv_fields creates a labeled loop, we cannot call it twice
                                                // in the same function body. Instead, we define a closure and call it.
-                                               let f = || {
+                                               let mut f = || {
                                                        $crate::_init_and_read_len_prefixed_tlv_fields!(reader, {
                                                                $(($type, $field, $fieldty)),*
                                                        });
@@ -1111,7 +1111,7 @@ macro_rules! impl_writeable_tlv_based_enum_upgradable {
                                        $($variant_id => {
                                                // Because read_tlv_fields creates a labeled loop, we cannot call it twice
                                                // in the same function body. Instead, we define a closure and call it.
-                                               let f = || {
+                                               let mut f = || {
                                                        $crate::_init_and_read_len_prefixed_tlv_fields!(reader, {
                                                                $(($type, $field, $fieldty)),*
                                                        });
@@ -1143,8 +1143,10 @@ macro_rules! impl_writeable_tlv_based_enum_upgradable {
 
 #[cfg(test)]
 mod tests {
-       use crate::io::{self, Cursor};
+       #[allow(unused_imports)]
        use crate::prelude::*;
+
+       use crate::io::{self, Cursor};
        use crate::ln::msgs::DecodeError;
        use crate::util::ser::{Writeable, HighZeroBytesDroppedBigSize, VecWriter};
        use bitcoin::hashes::hex::FromHex;
index 6949c936e00e575ad8b4a848e61ee892a65b3eca..ab12486a0d8ebfbac985dd3289b8e6dbeb23f3f2 100644 (file)
@@ -9,12 +9,14 @@
 
 //! Utilities for strings.
 
-use alloc::string::String;
 use core::fmt;
 use crate::io::{self, Read};
 use crate::ln::msgs;
 use crate::util::ser::{Writeable, Writer, Readable};
 
+#[allow(unused_imports)]
+use crate::prelude::*;
+
 /// Struct to `Display` fields in a safe way using `PrintableString`
 #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
 pub struct UntrustedString(pub String);
index bfa3e32c91f5b3d683c26d5b9f9bf2700512efb6..43ac9ff87e95f20d792aead9348a341dbb25b9e5 100644 (file)
@@ -14,7 +14,9 @@ use crate::ln::{msgs, PaymentPreimage};
 use crate::sign::{InMemorySigner, ChannelSigner};
 use crate::sign::ecdsa::{EcdsaChannelSigner, WriteableEcdsaChannelSigner};
 
+#[allow(unused_imports)]
 use crate::prelude::*;
+
 use core::cmp;
 use crate::sync::{Mutex, Arc};
 #[cfg(test)] use crate::sync::MutexGuard;
index 15cc07466d603b4f049d00fc52df7bb546765107..305dc40a0a296e701add66f2066d8182c0eb4d78 100644 (file)
@@ -13,6 +13,7 @@ use crate::chain;
 use crate::chain::WatchedOutput;
 use crate::chain::chaininterface;
 use crate::chain::chaininterface::ConfirmationTarget;
+#[cfg(test)]
 use crate::chain::chaininterface::FEERATE_FLOOR_SATS_PER_KW;
 use crate::chain::chainmonitor;
 use crate::chain::chainmonitor::{MonitorUpdateId, UpdateOrigin};
@@ -25,6 +26,7 @@ use crate::events;
 use crate::events::bump_transaction::{WalletSource, Utxo};
 use crate::ln::ChannelId;
 use crate::ln::channelmanager::{ChannelDetails, self};
+#[cfg(test)]
 use crate::ln::chan_utils::CommitmentTransaction;
 use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
 use crate::ln::{msgs, wire};
@@ -59,9 +61,6 @@ use bitcoin::secp256k1::ecdh::SharedSecret;
 use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
 use bitcoin::secp256k1::schnorr;
 
-#[cfg(any(test, feature = "_test_utils"))]
-use regex;
-
 use crate::io;
 use crate::prelude::*;
 use core::cell::RefCell;
@@ -399,12 +398,14 @@ impl<'a> chain::Watch<TestChannelSigner> for TestChainMonitor<'a> {
        }
 }
 
+#[cfg(test)]
 struct JusticeTxData {
        justice_tx: Transaction,
        value: u64,
        commitment_number: u64,
 }
 
+#[cfg(test)]
 pub(crate) struct WatchtowerPersister {
        persister: TestPersister,
        /// Upon a new commitment_signed, we'll get a
@@ -418,6 +419,7 @@ pub(crate) struct WatchtowerPersister {
        destination_script: ScriptBuf,
 }
 
+#[cfg(test)]
 impl WatchtowerPersister {
        #[cfg(test)]
        pub(crate) fn new(destination_script: ScriptBuf) -> Self {
@@ -448,6 +450,7 @@ impl WatchtowerPersister {
        }
 }
 
+#[cfg(test)]
 impl<Signer: sign::ecdsa::WriteableEcdsaChannelSigner> chainmonitor::Persist<Signer> for WatchtowerPersister {
        fn persist_new_channel(&self, funding_txo: OutPoint,
                data: &channelmonitor::ChannelMonitor<Signer>, id: MonitorUpdateId
index a6e6f4d1fda6b6e58a102a0baeb97cbed102159f..bedeab1d4890ac78c0dbda3f2506e8a28ee9f07d 100644 (file)
@@ -16,16 +16,8 @@ pub trait Time: Copy + Sub<Duration, Output = Self> where Self: Sized {
        /// Returns an instance corresponding to the current moment.
        fn now() -> Self;
 
-       /// Returns the amount of time elapsed since `self` was created.
-       fn elapsed(&self) -> Duration;
-
        /// Returns the amount of time passed between `earlier` and `self`.
        fn duration_since(&self, earlier: Self) -> Duration;
-
-       /// Returns the amount of time passed since the beginning of [`Time`].
-       ///
-       /// Used during (de-)serialization.
-       fn duration_since_epoch() -> Duration;
 }
 
 /// A state in which time has no meaning.
@@ -40,14 +32,6 @@ impl Time for Eternity {
        fn duration_since(&self, _earlier: Self) -> Duration {
                Duration::from_secs(0)
        }
-
-       fn duration_since_epoch() -> Duration {
-               Duration::from_secs(0)
-       }
-
-       fn elapsed(&self) -> Duration {
-               Duration::from_secs(0)
-       }
 }
 
 impl Sub<Duration> for Eternity {
@@ -82,15 +66,6 @@ impl Time for MonotonicTime {
                let now = Self::now();
                if now.0 > earlier.0 { now.0 - earlier.0 } else { Duration::from_secs(0) }
        }
-
-       fn duration_since_epoch() -> Duration {
-               use std::time::SystemTime;
-               SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
-       }
-
-       fn elapsed(&self) -> Duration {
-               Self::now().0 - self.0
-       }
 }
 
 #[cfg(feature = "std")]
@@ -127,20 +102,12 @@ pub mod tests {
 
        impl Time for SinceEpoch {
                fn now() -> Self {
-                       Self(Self::duration_since_epoch())
+                       Self(Self::ELAPSED.with(|elapsed| elapsed.get()))
                }
 
                fn duration_since(&self, earlier: Self) -> Duration {
                        self.0 - earlier.0
                }
-
-               fn duration_since_epoch() -> Duration {
-                       Self::ELAPSED.with(|elapsed| elapsed.get())
-               }
-
-               fn elapsed(&self) -> Duration {
-                       Self::duration_since_epoch() - self.0
-               }
        }
 
        impl Sub<Duration> for SinceEpoch {
@@ -154,36 +121,20 @@ pub mod tests {
        #[test]
        fn time_passes_when_advanced() {
                let now = SinceEpoch::now();
-               assert_eq!(now.elapsed(), Duration::from_secs(0));
 
                SinceEpoch::advance(Duration::from_secs(1));
                SinceEpoch::advance(Duration::from_secs(1));
 
-               let elapsed = now.elapsed();
                let later = SinceEpoch::now();
 
-               assert_eq!(elapsed, Duration::from_secs(2));
-               assert_eq!(later - elapsed, now);
+               assert_eq!(now.0 + Duration::from_secs(2), later.0);
        }
 
        #[test]
        fn time_never_passes_in_an_eternity() {
                let now = Eternity::now();
-               let elapsed = now.elapsed();
                let later = Eternity::now();
 
-               assert_eq!(now.elapsed(), Duration::from_secs(0));
-               assert_eq!(later - elapsed, now);
-       }
-
-       #[test]
-       #[cfg(feature = "std")]
-       fn monotonic_time_subtracts() {
-               let now = super::MonotonicTime::now();
-               assert!(now.elapsed() < Duration::from_secs(10));
-
-               let ten_years = Duration::from_secs(10 * 365 * 24 * 60 * 60);
-               let past = now - ten_years;
-               assert!(past.elapsed() >= ten_years);
+               assert_eq!(later, now);
        }
 }
index 12b504a69ef8dd50aceeeaed1ea9431fd905d8eb..59b7be6073c1dd9a1516adb25f3a41af1d0222f5 100644 (file)
@@ -14,7 +14,9 @@ use bitcoin::consensus::encode::VarInt;
 
 use crate::ln::msgs::MAX_VALUE_MSAT;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
+
 use crate::io_extras::sink;
 use core::cmp::Ordering;
 
@@ -72,8 +74,8 @@ mod tests {
        use super::*;
 
        use bitcoin::blockdata::locktime::absolute::LockTime;
-       use bitcoin::blockdata::transaction::{Transaction, TxOut, TxIn, OutPoint};
-       use bitcoin::blockdata::script::{ScriptBuf, Builder};
+       use bitcoin::blockdata::transaction::{TxIn, OutPoint};
+       use bitcoin::blockdata::script::Builder;
        use bitcoin::hash_types::{PubkeyHash, Txid};
        use bitcoin::hashes::Hash;
        use bitcoin::hashes::hex::FromHex;
index b2c9d21b998e790dba23570d49be13a2be6d2053..c95b3dbef3d90e66b118f92790256073a2f67dce 100644 (file)
@@ -17,6 +17,7 @@ use alloc::sync::Arc;
 use core::mem;
 use crate::sync::Mutex;
 
+#[allow(unused_imports)]
 use crate::prelude::*;
 
 #[cfg(feature = "std")]
@@ -305,7 +306,7 @@ mod tests {
        use super::*;
        use core::sync::atomic::{AtomicBool, Ordering};
        use core::future::Future as FutureTrait;
-       use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+       use core::task::{RawWaker, RawWakerVTable};
 
        #[test]
        fn notifier_pre_notified_future() {