From 50aa1eaf828834c857fccc610be3009a116a273b Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Sat, 18 Jan 2025 01:22:13 +0530 Subject: [PATCH 1/8] Add method to derive Peer Storage encryption key Add get_peer_storage_key method to derive a 32-byte encryption key for securing Peer Storage. This method utilizes HKDF with the node's secret key as input and a fixed info string to generate the encryption key. - Add 'get_peer_storage_key' to NodeSigner. - Implement 'get_peer_storage_key' for KeysManager & PhantomKeysManager. --- fuzz/src/chanmon_consistency.rs | 8 +++++- fuzz/src/full_stack.rs | 19 +++++++++----- fuzz/src/onion_message.rs | 6 ++++- lightning/src/ln/blinded_payment_tests.rs | 4 ++- lightning/src/ln/channelmanager.rs | 4 +-- lightning/src/sign/mod.rs | 31 +++++++++++++++++++++++ lightning/src/util/dyn_signer.rs | 10 +++++--- lightning/src/util/test_utils.rs | 10 +++++++- 8 files changed, 77 insertions(+), 15 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 7c3700f85f5..5d5a31053ae 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -62,7 +62,9 @@ use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessa use lightning::routing::router::{ InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, Router, }; -use lightning::sign::{EntropySource, InMemorySigner, NodeSigner, Recipient, SignerProvider}; +use lightning::sign::{ + EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, Recipient, SignerProvider, +}; use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::util::config::UserConfig; use lightning::util::hash_tables::*; @@ -338,6 +340,10 @@ impl NodeSigner for KeyProvider { unreachable!() } + fn get_peer_storage_key(&self) -> PeerStorageKey { + PeerStorageKey { inner: [42; 32] } + } + fn sign_bolt12_invoice( &self, _invoice: &UnsignedBolt12Invoice, ) -> Result { diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 90755ae94f1..3ba46f43de1 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -56,6 +56,7 @@ use lightning::routing::router::{ InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router, }; use lightning::routing::utxo::UtxoLookup; +use lightning::sign::PeerStorageKey; use lightning::sign::{EntropySource, InMemorySigner, NodeSigner, Recipient, SignerProvider}; use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::util::config::{ChannelConfig, UserConfig}; @@ -428,6 +429,10 @@ impl NodeSigner for KeyProvider { let secp_ctx = Secp256k1::signing_only(); Ok(secp_ctx.sign_ecdsa(&msg_hash, &self.node_secret)) } + + fn get_peer_storage_key(&self) -> PeerStorageKey { + PeerStorageKey { inner: [42; 32] } + } } impl SignerProvider for KeyProvider { @@ -560,6 +565,14 @@ pub fn do_test(mut data: &[u8], logger: &Arc) { ]; let broadcast = Arc::new(TestBroadcaster { txn_broadcasted: Mutex::new(Vec::new()) }); + + let keys_manager = Arc::new(KeyProvider { + node_secret: our_network_key.clone(), + inbound_payment_key: ExpandedKey::new(inbound_payment_key), + counter: AtomicU64::new(0), + signer_state: RefCell::new(new_hash_map()), + }); + let monitor = Arc::new(chainmonitor::ChainMonitor::new( None, broadcast.clone(), @@ -568,12 +581,6 @@ pub fn do_test(mut data: &[u8], logger: &Arc) { Arc::new(TestPersister { update_ret: Mutex::new(ChannelMonitorUpdateStatus::Completed) }), )); - let keys_manager = Arc::new(KeyProvider { - node_secret: our_network_key.clone(), - inbound_payment_key: ExpandedKey::new(inbound_payment_key), - counter: AtomicU64::new(0), - signer_state: RefCell::new(new_hash_map()), - }); let network = Network::Bitcoin; let best_block_timestamp = genesis_block(network).header.time; let params = ChainParameters { network, best_block: BestBlock::from_network(network) }; diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index a5782dacd42..f2da1a316fc 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -23,7 +23,7 @@ use lightning::onion_message::messenger::{ }; use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler}; use lightning::onion_message::packet::OnionMessageContents; -use lightning::sign::{EntropySource, NodeSigner, Recipient, SignerProvider}; +use lightning::sign::{EntropySource, NodeSigner, PeerStorageKey, Recipient, SignerProvider}; use lightning::types::features::InitFeatures; use lightning::util::logger::Logger; use lightning::util::ser::{LengthReadable, Writeable, Writer}; @@ -249,6 +249,10 @@ impl NodeSigner for KeyProvider { ) -> Result { unreachable!() } + + fn get_peer_storage_key(&self) -> PeerStorageKey { + unreachable!() + } } impl SignerProvider for KeyProvider { diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index f43d672a164..b714f76616f 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -36,7 +36,7 @@ use crate::offers::invoice::UnsignedBolt12Invoice; use crate::offers::nonce::Nonce; use crate::prelude::*; use crate::routing::router::{BlindedTail, Path, Payee, PaymentParameters, RouteHop, RouteParameters, TrampolineHop}; -use crate::sign::{NodeSigner, Recipient}; +use crate::sign::{NodeSigner, PeerStorageKey, Recipient}; use crate::util::config::UserConfig; use crate::util::ser::{WithoutLength, Writeable}; use crate::util::test_utils; @@ -1631,6 +1631,7 @@ fn route_blinding_spec_test_vector() { fn sign_invoice( &self, _invoice: &RawBolt11Invoice, _recipient: Recipient, ) -> Result { unreachable!() } + fn get_peer_storage_key(&self) -> PeerStorageKey { unreachable!() } fn sign_bolt12_invoice( &self, _invoice: &UnsignedBolt12Invoice, ) -> Result { unreachable!() } @@ -1940,6 +1941,7 @@ fn test_trampoline_inbound_payment_decoding() { fn sign_invoice( &self, _invoice: &RawBolt11Invoice, _recipient: Recipient, ) -> Result { unreachable!() } + fn get_peer_storage_key(&self) -> PeerStorageKey { unreachable!() } fn sign_bolt12_invoice( &self, _invoice: &UnsignedBolt12Invoice, ) -> Result { unreachable!() } diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 6a3c066ce14..3dfc3b2f21f 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -16829,9 +16829,9 @@ pub mod bench { config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253); config.channel_handshake_config.minimum_depth = 1; - let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a); let seed_a = [1u8; 32]; let keys_manager_a = KeysManager::new(&seed_a, 42, 42); + let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a, keys_manager_a.get_peer_storage_key()); let node_a = ChannelManager::new(&fee_estimator, &chain_monitor_a, &tx_broadcaster, &router, &message_router, &logger_a, &keys_manager_a, &keys_manager_a, &keys_manager_a, config.clone(), ChainParameters { network, best_block: BestBlock::from_network(network), @@ -16839,9 +16839,9 @@ pub mod bench { let node_a_holder = ANodeHolder { node: &node_a }; let logger_b = test_utils::TestLogger::with_id("node a".to_owned()); - let chain_monitor_b = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_b); let seed_b = [2u8; 32]; let keys_manager_b = KeysManager::new(&seed_b, 42, 42); + let chain_monitor_b = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_b, keys_manager_b.get_peer_storage_key()); let node_b = ChannelManager::new(&fee_estimator, &chain_monitor_b, &tx_broadcaster, &router, &message_router, &logger_b, &keys_manager_b, &keys_manager_b, &keys_manager_b, config.clone(), ChainParameters { network, best_block: BestBlock::from_network(network), diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index f35a407634a..665cba693ed 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -796,6 +796,13 @@ pub trait ChannelSigner { fn channel_keys_id(&self) -> [u8; 32]; } +/// Represents Secret Key used for encrypting Peer Storage. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct PeerStorageKey { + /// Represents the key used to encrypt and decrypt Peer Storage. + pub inner: [u8; 32], +} + /// Specifies the recipient of an invoice. /// /// This indicates to [`NodeSigner::sign_invoice`] what node secret key should be used to sign @@ -834,6 +841,15 @@ pub trait NodeSigner { /// [phantom node payments]: PhantomKeysManager fn get_inbound_payment_key(&self) -> ExpandedKey; + /// Defines a method to derive a 32-byte encryption key for peer storage. + /// + /// Implementations of this method must derive a secure encryption key. + /// The key is used to encrypt or decrypt backups of our state stored with our peers. + /// + /// Thus, if you wish to rely on recovery using this method, you should use a key which + /// can be re-derived from data which would be available after state loss (eg the wallet seed). + fn get_peer_storage_key(&self) -> PeerStorageKey; + /// Get node id based on the provided [`Recipient`]. /// /// This method must return the same value each time it is called with a given [`Recipient`] @@ -1809,6 +1825,7 @@ pub struct KeysManager { shutdown_pubkey: PublicKey, channel_master_key: Xpriv, channel_child_index: AtomicUsize, + peer_storage_key: PeerStorageKey, #[cfg(test)] pub(crate) entropy_source: RandomBytes, @@ -1877,6 +1894,10 @@ impl KeysManager { .private_key; let mut inbound_pmt_key_bytes = [0; 32]; inbound_pmt_key_bytes.copy_from_slice(&inbound_payment_key[..]); + let peer_storage_key: SecretKey = master_key + .derive_priv(&secp_ctx, &ChildNumber::from_hardened_idx(6).unwrap()) + .expect("Your RNG is busted") + .private_key; let mut rand_bytes_engine = Sha256::engine(); rand_bytes_engine.input(&starting_time_secs.to_be_bytes()); @@ -1892,6 +1913,8 @@ impl KeysManager { node_id, inbound_payment_key: ExpandedKey::new(inbound_pmt_key_bytes), + peer_storage_key: PeerStorageKey { inner: peer_storage_key.secret_bytes() }, + destination_script, shutdown_pubkey, @@ -2117,6 +2140,10 @@ impl NodeSigner for KeysManager { self.inbound_payment_key.clone() } + fn get_peer_storage_key(&self) -> PeerStorageKey { + self.peer_storage_key.clone() + } + fn sign_invoice( &self, invoice: &RawBolt11Invoice, recipient: Recipient, ) -> Result { @@ -2278,6 +2305,10 @@ impl NodeSigner for PhantomKeysManager { self.inbound_payment_key.clone() } + fn get_peer_storage_key(&self) -> PeerStorageKey { + self.inner.peer_storage_key.clone() + } + fn sign_invoice( &self, invoice: &RawBolt11Invoice, recipient: Recipient, ) -> Result { diff --git a/lightning/src/util/dyn_signer.rs b/lightning/src/util/dyn_signer.rs index 939e40cf7c4..7e9844e2ac0 100644 --- a/lightning/src/util/dyn_signer.rs +++ b/lightning/src/util/dyn_signer.rs @@ -17,7 +17,9 @@ use crate::sign::taproot::TaprootChannelSigner; use crate::sign::ChannelSigner; use crate::sign::InMemorySigner; use crate::sign::{EntropySource, HTLCDescriptor, OutputSpender, PhantomKeysManager}; -use crate::sign::{NodeSigner, Recipient, SignerProvider, SpendableOutputDescriptor}; +use crate::sign::{ + NodeSigner, PeerStorageKey, Recipient, SignerProvider, SpendableOutputDescriptor, +}; use bitcoin; use bitcoin::absolute::LockTime; use bitcoin::secp256k1::All; @@ -214,7 +216,8 @@ inner, fn sign_bolt12_invoice(, invoice: &crate::offers::invoice::UnsignedBolt12Invoice ) -> Result, - fn get_inbound_payment_key(,) -> ExpandedKey + fn get_inbound_payment_key(,) -> ExpandedKey, + fn get_peer_storage_key(,) -> PeerStorageKey ); delegate!(DynKeysInterface, SignerProvider, @@ -278,7 +281,8 @@ delegate!(DynPhantomKeysInterface, NodeSigner, fn sign_invoice(, invoice: &RawBolt11Invoice, recipient: Recipient) -> Result, fn sign_bolt12_invoice(, invoice: &crate::offers::invoice::UnsignedBolt12Invoice ) -> Result, - fn get_inbound_payment_key(,) -> ExpandedKey + fn get_inbound_payment_key(,) -> ExpandedKey, + fn get_peer_storage_key(,) -> PeerStorageKey ); impl SignerProvider for DynPhantomKeysInterface { diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index a6f0b38a4fb..5ef8b5f56de 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -46,7 +46,7 @@ use crate::routing::router::{ use crate::routing::scoring::{ChannelUsage, ScoreLookUp, ScoreUpdate}; use crate::routing::utxo::{UtxoLookup, UtxoLookupError, UtxoResult}; use crate::sign; -use crate::sign::ChannelSigner; +use crate::sign::{ChannelSigner, PeerStorageKey}; use crate::sync::RwLock; use crate::types::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use crate::util::config::UserConfig; @@ -1488,6 +1488,10 @@ impl NodeSigner for TestNodeSigner { unreachable!() } + fn get_peer_storage_key(&self) -> PeerStorageKey { + unreachable!() + } + fn get_node_id(&self, recipient: Recipient) -> Result { let node_secret = match recipient { Recipient::Node => Ok(&self.node_secret), @@ -1568,6 +1572,10 @@ impl NodeSigner for TestKeysInterface { self.backing.sign_invoice(invoice, recipient) } + fn get_peer_storage_key(&self) -> PeerStorageKey { + self.backing.get_peer_storage_key() + } + fn sign_bolt12_invoice( &self, invoice: &UnsignedBolt12Invoice, ) -> Result { From d1cd82f241d62d857629cfebc4ca55a06a61ac95 Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Wed, 26 Feb 2025 08:48:50 +0530 Subject: [PATCH 2/8] Add OurPeerStorage for serialized Peer Storage backups Introduce the OurPeerStorage struct to manage serialized channel data for peer storage backups. This struct facilitates the distribution of peer storage to channel partners and includes versioning and timestamping for comparison between retrieved peer storage instances. - Add the OurPeerStorage struct with fields for version, timestamp, and serialized channel data (ser_channels). - Implement methods to encrypt and decrypt peer storage securely. - Add functionality to update channel data within OurPeerStorage. --- fuzz/src/full_stack.rs | 5 +- lightning/src/ln/mod.rs | 1 + lightning/src/ln/our_peer_storage.rs | 186 +++++++++++++++++++++++++++ lightning/src/sign/mod.rs | 2 +- 4 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 lightning/src/ln/our_peer_storage.rs diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 3ba46f43de1..480a08d0a4b 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -56,8 +56,9 @@ use lightning::routing::router::{ InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router, }; use lightning::routing::utxo::UtxoLookup; -use lightning::sign::PeerStorageKey; -use lightning::sign::{EntropySource, InMemorySigner, NodeSigner, Recipient, SignerProvider}; +use lightning::sign::{ + EntropySource, InMemorySigner, NodeSigner, PeerStorageKey, Recipient, SignerProvider, +}; use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::util::config::{ChannelConfig, UserConfig}; use lightning::util::errors::APIError; diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 8d741f2954d..d95c9fc1275 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -21,6 +21,7 @@ mod features; pub mod inbound_payment; pub mod msgs; pub mod onion_payment; +pub mod our_peer_storage; pub mod peer_handler; pub mod script; pub mod types; diff --git a/lightning/src/ln/our_peer_storage.rs b/lightning/src/ln/our_peer_storage.rs new file mode 100644 index 00000000000..430c9f559f9 --- /dev/null +++ b/lightning/src/ln/our_peer_storage.rs @@ -0,0 +1,186 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +//! `DecryptedOurPeerStorage` enables storage of encrypted serialized channel data. +//! It provides encryption of data to maintain data integrity and +//! security during transmission. + +use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine}; + +use crate::sign::PeerStorageKey; + +use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC; +use crate::prelude::*; + +/// [`DecryptedOurPeerStorage`] is used to store serialised channel information that allows for the creation of a +/// `peer_storage` backup. +/// +/// This structure is designed to serialize channel data for backup and supports encryption +/// using `ChaCha20Poly1305RFC` for transmission. +/// +/// # Key Methods +/// - [`DecryptedOurPeerStorage::new`]: Returns [`DecryptedOurPeerStorage`] with the given data. +/// - [`DecryptedOurPeerStorage::encrypt`]: Returns [`EncryptedOurPeerStorage`] created from encrypting the provided data. +/// - [`DecryptedOurPeerStorage::into_vec`]: Returns the data in [`Vec`] format. +/// +/// ## Example +/// ``` +/// use lightning::ln::our_peer_storage::DecryptedOurPeerStorage; +/// use lightning::sign::{KeysManager, NodeSigner}; +/// let seed = [1u8; 32]; +/// let keys_mgr = KeysManager::new(&seed, 42, 42); +/// let key = keys_mgr.get_peer_storage_key(); +/// let decrypted_ops = DecryptedOurPeerStorage::new(vec![1, 2, 3]); +/// let our_peer_storage = decrypted_ops.encrypt(&key, &[0u8; 32]); +/// let decrypted_data = our_peer_storage.decrypt(&key).unwrap(); +/// assert_eq!(decrypted_data.into_vec(), vec![1, 2, 3]); +/// ``` +pub struct DecryptedOurPeerStorage { + data: Vec, +} + +impl DecryptedOurPeerStorage { + /// Returns [`DecryptedOurPeerStorage`] with the given data. + pub fn new(data: Vec) -> Self { + Self { data } + } + + /// Returns data stored in [`Vec`] format. + pub fn into_vec(self) -> Vec { + self.data + } + + /// Encrypts the data inside [`DecryptedOurPeerStorage`] using [`PeerStorageKey`] and `random_bytes` + /// and returns [`EncryptedOurPeerStorage`]. + pub fn encrypt(self, key: &PeerStorageKey, random_bytes: &[u8; 32]) -> EncryptedOurPeerStorage { + let mut data = self.data; + let plaintext_len = data.len(); + let nonce = derive_nonce(key, random_bytes); + + let mut chacha = ChaCha20Poly1305RFC::new(&key.inner, &nonce, b""); + let mut tag = [0; 16]; + chacha.encrypt_full_message_in_place(&mut data[0..plaintext_len], &mut tag); + + data.extend_from_slice(&tag); + + // Append `random_bytes` in front of the encrypted_blob. + data.extend_from_slice(random_bytes); + + EncryptedOurPeerStorage { cipher: data } + } +} + +/// [`EncryptedOurPeerStorage`] represents encrypted state of the corresponding [`DecryptedOurPeerStorage`]. +/// +/// # Key Methods +/// - [`EncryptedOurPeerStorage::new`]: Returns [`EncryptedOurPeerStorage`] with the given encrypted cipher. +/// - [`EncryptedOurPeerStorage::decrypt`]: Returns [`DecryptedOurPeerStorage`] created from decrypting the cipher. +/// - [`EncryptedOurPeerStorage::into_vec`]: Returns the cipher in [`Vec`] format. +pub struct EncryptedOurPeerStorage { + cipher: Vec, +} + +impl EncryptedOurPeerStorage { + // Ciphertext is of the form: random_bytes(32 bytes) + encrypted_data + tag(16 bytes). + const MIN_CIPHERTEXT_LEN: usize = 32 + 16; + + /// Returns [`EncryptedOurPeerStorage`] if cipher is of appropriate length, else returns error. + pub fn new(cipher: Vec) -> Result { + if cipher.len() < Self::MIN_CIPHERTEXT_LEN { + return Err(()); + } + return Ok(Self { cipher }); + } + + /// Returns cipher in the format [`Vec`]. + pub fn into_vec(self) -> Vec { + self.cipher + } + + /// Returns [`DecryptedOurPeerStorage`] if it successfully decrypts the ciphertext with the `key`, + /// else returns error. + pub fn decrypt(self, key: &PeerStorageKey) -> Result { + let mut cipher = self.cipher; + let cyphertext_len = cipher.len(); + + if cipher.len() < Self::MIN_CIPHERTEXT_LEN { + return Err(()); + } + + // Ciphertext is of the form: encrypted_data + tag(16 bytes) + random_bytes(32 bytes). + let (data_mut, random_bytes) = cipher.split_at_mut(cyphertext_len - 32); + let (encrypted_data, tag) = data_mut.split_at_mut(data_mut.len() - 16); + + let nonce = derive_nonce(key, random_bytes); + + let mut chacha = ChaCha20Poly1305RFC::new(&key.inner, &nonce, b""); + + if chacha.check_decrypt_in_place(encrypted_data, tag).is_err() { + return Err(()); + } + + // Remove tag(16 bytes) + random_bytes(32 bytes). + cipher.truncate(cyphertext_len - 16 - 32); + + Ok(DecryptedOurPeerStorage { data: cipher }) + } +} + +/// Nonce for encryption and decryption: Hmac(Sha256(key) + random_bytes). +fn derive_nonce(key: &PeerStorageKey, random_bytes: &[u8]) -> [u8; 12] { + let key_hash = Sha256::hash(&key.inner); + + let mut hmac = HmacEngine::::new(key_hash.as_byte_array()); + hmac.input(&random_bytes); + let mut nonce = [0u8; 12]; + // First 4 bytes of the nonce should be 0. + nonce[4..].copy_from_slice(&Hmac::from_engine(hmac).to_byte_array()[0..8]); + + nonce +} + +#[cfg(test)] +mod tests { + use crate::ln::our_peer_storage::{derive_nonce, DecryptedOurPeerStorage}; + use crate::sign::PeerStorageKey; + + #[test] + fn test_peer_storage_encryption_decryption() { + let key1 = PeerStorageKey { inner: [0u8; 32] }; + let key2 = PeerStorageKey { inner: [1u8; 32] }; + let random_bytes1 = [200; 32]; + let random_bytes2 = [201; 32]; + + // Happy Path + let decrypted_ops = DecryptedOurPeerStorage::new(vec![42u8; 32]); + let decrypted_ops_res: DecryptedOurPeerStorage = + decrypted_ops.encrypt(&key1, &random_bytes1).decrypt(&key1).unwrap(); + assert_eq!(decrypted_ops_res.into_vec(), vec![42u8; 32]); + + // Changing Key + let decrypted_ops_wrong_key = DecryptedOurPeerStorage::new(vec![42u8; 32]); + let decrypted_ops_wrong_key_res = + decrypted_ops_wrong_key.encrypt(&key2, &random_bytes2).decrypt(&key1); + assert!(decrypted_ops_wrong_key_res.is_err()); + + // Nonce derivation happy path + let nonce = derive_nonce(&key1, &random_bytes1); + let nonce_happy_path = derive_nonce(&key1, &random_bytes1); + assert_eq!(nonce, nonce_happy_path); + + // Nonce derivation with different `random_bytes` & `key` + let nonce_diff_random_bytes = derive_nonce(&key1, &random_bytes2); + let nonce_diff_key = derive_nonce(&key2, &random_bytes1); + let nonce_diff_key_random_bytes = derive_nonce(&key2, &random_bytes2); + assert_ne!(nonce, nonce_diff_random_bytes); + assert_ne!(nonce, nonce_diff_key); + assert_ne!(nonce, nonce_diff_key_random_bytes); + } +} diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 665cba693ed..bd39cb87f3c 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -796,7 +796,7 @@ pub trait ChannelSigner { fn channel_keys_id(&self) -> [u8; 32]; } -/// Represents Secret Key used for encrypting Peer Storage. +/// Represents the secret key material used for encrypting Peer Storage. #[derive(Clone, Copy, PartialEq, Eq)] pub struct PeerStorageKey { /// Represents the key used to encrypt and decrypt Peer Storage. From 9db37f2889800f22b8614ec5e98bcfb6197fec12 Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Sat, 18 Jan 2025 18:17:19 +0530 Subject: [PATCH 3/8] Enable ChainMonitor to distribute PeerStorage To enable ChainMonitor sending peer storage to channel partners whenever a new block is added, We implement BaseMessageHandler for ChainMonitor. This allows the `ChainMonitor` to handle the peer storage distribution. Key changes: - Add BaseMessageHandler into the MessageHandler. - Implement BaseMessageHandler for ChainMonitor. - Process BaseMessageHandler events inside process_events(). --- fuzz/src/chanmon_consistency.rs | 3 + fuzz/src/full_stack.rs | 7 + lightning-background-processor/src/lib.rs | 22 +++- lightning-block-sync/src/init.rs | 4 +- lightning-liquidity/tests/common/mod.rs | 7 +- lightning-net-tokio/src/lib.rs | 3 + lightning/src/chain/chainmonitor.rs | 122 ++++++++++++++---- lightning/src/ln/channelmanager.rs | 5 +- lightning/src/ln/peer_handler.rs | 75 +++++++---- lightning/src/util/anchor_channel_reserves.rs | 4 + lightning/src/util/test_utils.rs | 3 + 11 files changed, 194 insertions(+), 61 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 5d5a31053ae..59612636a9e 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -191,6 +191,7 @@ struct TestChainMonitor { Arc, Arc, Arc, + Arc, >, >, pub latest_monitors: Mutex>, @@ -207,6 +208,8 @@ impl TestChainMonitor { logger.clone(), feeest, Arc::clone(&persister), + Arc::clone(&keys), + keys.get_peer_storage_key(), )), logger, keys, diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 480a08d0a4b..39fe28a27c1 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -225,6 +225,7 @@ type ChannelMan<'a> = ChannelManager< Arc, Arc, Arc, + Arc, >, >, Arc, @@ -244,6 +245,7 @@ type PeerMan<'a> = PeerManager< Arc, IgnoringMessageHandler, Arc, + IgnoringMessageHandler, >; struct MoneyLossDetector<'a> { @@ -256,6 +258,7 @@ struct MoneyLossDetector<'a> { Arc, Arc, Arc, + Arc, >, >, handler: PeerMan<'a>, @@ -280,6 +283,7 @@ impl<'a> MoneyLossDetector<'a> { Arc, Arc, Arc, + Arc, >, >, handler: PeerMan<'a>, @@ -580,6 +584,8 @@ pub fn do_test(mut data: &[u8], logger: &Arc) { Arc::clone(&logger), fee_est.clone(), Arc::new(TestPersister { update_ret: Mutex::new(ChannelMonitorUpdateStatus::Completed) }), + Arc::clone(&keys_manager), + keys_manager.get_peer_storage_key(), )); let network = Network::Bitcoin; @@ -613,6 +619,7 @@ pub fn do_test(mut data: &[u8], logger: &Arc) { route_handler: gossip_sync.clone(), onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: IgnoringMessageHandler {}, + send_only_message_handler: IgnoringMessageHandler {}, }; let random_data = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 239ff3f0c98..dda54362e35 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -37,6 +37,7 @@ use lightning::routing::utxo::UtxoLookup; use lightning::sign::ChangeDestinationSource; #[cfg(feature = "std")] use lightning::sign::ChangeDestinationSourceSync; +use lightning::sign::EntropySource; use lightning::sign::OutputSpender; use lightning::util::logger::Logger; use lightning::util::persist::{KVStore, Persister}; @@ -668,14 +669,14 @@ use futures_util::{dummy_waker, OptionalSelector, Selector, SelectorOutput}; /// # fn send_data(&mut self, _data: &[u8], _resume_read: bool) -> usize { 0 } /// # fn disconnect_socket(&mut self) {} /// # } -/// # type ChainMonitor = lightning::chain::chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc>; +/// # type ChainMonitor = lightning::chain::chainmonitor::ChainMonitor, Arc, Arc, Arc, Arc, Arc>; /// # type NetworkGraph = lightning::routing::gossip::NetworkGraph>; /// # type P2PGossipSync
    = lightning::routing::gossip::P2PGossipSync, Arc
      , Arc>; /// # type ChannelManager = lightning::ln::channelmanager::SimpleArcChannelManager, B, FE, Logger>; /// # type OnionMessenger = lightning::onion_message::messenger::OnionMessenger, Arc, Arc, Arc>, Arc, Arc, Arc>>, Arc>, lightning::ln::peer_handler::IgnoringMessageHandler, lightning::ln::peer_handler::IgnoringMessageHandler, lightning::ln::peer_handler::IgnoringMessageHandler>; /// # type LiquidityManager = lightning_liquidity::LiquidityManager, Arc>, Arc>; /// # type Scorer = RwLock, Arc>>; -/// # type PeerManager = lightning::ln::peer_handler::SimpleArcPeerManager, B, FE, Arc
        , Logger>; +/// # type PeerManager = lightning::ln::peer_handler::SimpleArcPeerManager, B, FE, Arc
          , Logger, F, Store>; /// # /// # struct Node< /// # B: lightning::chain::chaininterface::BroadcasterInterface + Send + Sync + 'static, @@ -780,8 +781,9 @@ pub async fn process_events_async< EventHandlerFuture: core::future::Future>, EventHandler: Fn(Event) -> EventHandlerFuture, PS: 'static + Deref + Send, + ES: 'static + Deref + Send, M: 'static - + Deref::Signer, CF, T, F, L, P>> + + Deref::Signer, CF, T, F, L, P, ES>> + Send + Sync, CM: 'static + Deref, @@ -813,6 +815,7 @@ where L::Target: 'static + Logger, P::Target: 'static + Persist<::Signer>, PS::Target: 'static + Persister<'a, CM, L, S>, + ES::Target: 'static + EntropySource, CM::Target: AChannelManager, OM::Target: AOnionMessenger, PM::Target: APeerManager, @@ -976,8 +979,11 @@ impl BackgroundProcessor { P: 'static + Deref, EH: 'static + EventHandler + Send, PS: 'static + Deref + Send, + ES: 'static + Deref + Send, M: 'static - + Deref::Signer, CF, T, F, L, P>> + + Deref< + Target = ChainMonitor<::Signer, CF, T, F, L, P, ES>, + > + Send + Sync, CM: 'static + Deref + Send, @@ -1005,6 +1011,7 @@ impl BackgroundProcessor { L::Target: 'static + Logger, P::Target: 'static + Persist<::Signer>, PS::Target: 'static + Persister<'a, CM, L, S>, + ES::Target: 'static + EntropySource, CM::Target: AChannelManager, OM::Target: AOnionMessenger, PM::Target: APeerManager, @@ -1174,7 +1181,7 @@ mod tests { use lightning::routing::gossip::{NetworkGraph, P2PGossipSync}; use lightning::routing::router::{CandidateRouteHop, DefaultRouter, Path, RouteHop}; use lightning::routing::scoring::{ChannelUsage, LockableScore, ScoreLookUp, ScoreUpdate}; - use lightning::sign::{ChangeDestinationSourceSync, InMemorySigner, KeysManager}; + use lightning::sign::{ChangeDestinationSourceSync, InMemorySigner, KeysManager, NodeSigner}; use lightning::types::features::{ChannelFeatures, NodeFeatures}; use lightning::types::payment::PaymentHash; use lightning::util::config::UserConfig; @@ -1250,6 +1257,7 @@ mod tests { Arc, Arc, Arc, + Arc, >; type PGS = Arc< @@ -1301,6 +1309,7 @@ mod tests { Arc, IgnoringMessageHandler, Arc, + IgnoringMessageHandler, >, >, liquidity_manager: Arc, @@ -1662,6 +1671,8 @@ mod tests { logger.clone(), fee_estimator.clone(), kv_store.clone(), + keys_manager.clone(), + keys_manager.get_peer_storage_key(), )); let best_block = BestBlock::from_network(network); let params = ChainParameters { network, best_block }; @@ -1715,6 +1726,7 @@ mod tests { route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new()), onion_message_handler: messenger.clone(), custom_message_handler: IgnoringMessageHandler {}, + send_only_message_handler: IgnoringMessageHandler {}, }; let peer_manager = Arc::new(PeerManager::new( msg_handler, diff --git a/lightning-block-sync/src/init.rs b/lightning-block-sync/src/init.rs index 7697adacf2a..f71a72456dc 100644 --- a/lightning-block-sync/src/init.rs +++ b/lightning-block-sync/src/init.rs @@ -76,7 +76,7 @@ where /// P: chainmonitor::Persist, /// >( /// block_source: &B, -/// chain_monitor: &ChainMonitor, +/// chain_monitor: &ChainMonitor, /// config: UserConfig, /// entropy_source: &ES, /// node_signer: &NS, @@ -109,7 +109,7 @@ where /// config, /// vec![&mut monitor], /// ); -/// <(BlockHash, ChannelManager<&ChainMonitor, &T, &ES, &NS, &SP, &F, &R, &MR, &L>)>::read( +/// <(BlockHash, ChannelManager<&ChainMonitor, &T, &ES, &NS, &SP, &F, &R, &MR, &L>)>::read( /// &mut Cursor::new(&serialized_manager), read_args).unwrap() /// }; /// diff --git a/lightning-liquidity/tests/common/mod.rs b/lightning-liquidity/tests/common/mod.rs index 2259d1eae06..7d5ff0280e0 100644 --- a/lightning-liquidity/tests/common/mod.rs +++ b/lightning-liquidity/tests/common/mod.rs @@ -5,7 +5,7 @@ #![allow(unused_macros)] use lightning::chain::Filter; -use lightning::sign::EntropySource; +use lightning::sign::{EntropySource, NodeSigner}; use bitcoin::blockdata::constants::{genesis_block, ChainHash}; use bitcoin::blockdata::transaction::Transaction; @@ -101,6 +101,7 @@ type ChainMonitor = chainmonitor::ChainMonitor< Arc, Arc, Arc, + Arc, >; type PGS = Arc< @@ -130,6 +131,7 @@ pub(crate) struct Node { >, >, Arc, + Arc, >, >, pub(crate) liquidity_manager: @@ -429,6 +431,8 @@ pub(crate) fn create_liquidity_node( logger.clone(), fee_estimator.clone(), kv_store.clone(), + keys_manager.clone(), + keys_manager.get_peer_storage_key(), )); let best_block = BestBlock::from_network(network); let chain_params = ChainParameters { network, best_block }; @@ -467,6 +471,7 @@ pub(crate) fn create_liquidity_node( route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new()), onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: Arc::clone(&liquidity_manager), + send_only_message_handler: Arc::clone(&chain_monitor), }; let peer_manager = Arc::new(PeerManager::new(msg_handler, 0, &seed, logger.clone(), keys_manager.clone())); diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index 888915f43e2..ea23e5a0115 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -837,6 +837,7 @@ mod tests { route_handler: Arc::clone(&a_handler), onion_message_handler: Arc::new(IgnoringMessageHandler {}), custom_message_handler: Arc::new(IgnoringMessageHandler {}), + send_only_message_handler: Arc::new(IgnoringMessageHandler {}), }; let a_manager = Arc::new(PeerManager::new( a_msg_handler, @@ -860,6 +861,7 @@ mod tests { route_handler: Arc::clone(&b_handler), onion_message_handler: Arc::new(IgnoringMessageHandler {}), custom_message_handler: Arc::new(IgnoringMessageHandler {}), + send_only_message_handler: Arc::new(IgnoringMessageHandler {}), }; let b_manager = Arc::new(PeerManager::new( b_msg_handler, @@ -922,6 +924,7 @@ mod tests { onion_message_handler: Arc::new(IgnoringMessageHandler {}), route_handler: Arc::new(lightning::ln::peer_handler::IgnoringMessageHandler {}), custom_message_handler: Arc::new(IgnoringMessageHandler {}), + send_only_message_handler: Arc::new(IgnoringMessageHandler {}), }; let a_manager = Arc::new(PeerManager::new( a_msg_handler, diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index 09d87b775be..7094a9ff2fe 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -34,16 +34,18 @@ use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, Balance, MonitorEvent, TransactionOutputs, WithChannelMonitor}; use crate::chain::transaction::{OutPoint, TransactionData}; use crate::ln::types::ChannelId; +use crate::ln::msgs::{self, BaseMessageHandler, Init, MessageSendEvent}; use crate::sign::ecdsa::EcdsaChannelSigner; +use crate::sign::{EntropySource, PeerStorageKey}; use crate::events::{self, Event, EventHandler, ReplayEvent}; use crate::util::logger::{Logger, WithContext}; use crate::util::errors::APIError; use crate::util::persist::MonitorName; use crate::util::wakers::{Future, Notifier}; use crate::ln::channel_state::ChannelDetails; - use crate::prelude::*; use crate::sync::{RwLock, RwLockReadGuard, Mutex, MutexGuard}; +use crate::types::features::{InitFeatures, NodeFeatures}; use core::ops::Deref; use core::sync::atomic::{AtomicUsize, Ordering}; use bitcoin::secp256k1::PublicKey; @@ -233,12 +235,13 @@ impl Deref for LockedChannelMonitor<'_, Chann /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager /// [module-level documentation]: crate::chain::chainmonitor /// [`rebroadcast_pending_claims`]: Self::rebroadcast_pending_claims -pub struct ChainMonitor +pub struct ChainMonitor where C::Target: chain::Filter, - T::Target: BroadcasterInterface, - F::Target: FeeEstimator, - L::Target: Logger, - P::Target: Persist, + T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + P::Target: Persist, + ES::Target: EntropySource, { monitors: RwLock>>, chain_source: Option, @@ -246,6 +249,7 @@ pub struct ChainMonitor, PublicKey)>>, @@ -255,14 +259,18 @@ pub struct ChainMonitor>, } -impl ChainMonitor +impl ChainMonitor where C::Target: chain::Filter, - T::Target: BroadcasterInterface, - F::Target: FeeEstimator, - L::Target: Logger, - P::Target: Persist, + T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + P::Target: Persist, + ES::Target: EntropySource, { /// Dispatches to per-channel monitors, which are responsible for updating their on-chain view /// of a channel and reacting accordingly based on transactions in the given chain data. See @@ -388,7 +396,19 @@ where C::Target: chain::Filter, /// pre-filter blocks or only fetch blocks matching a compact filter. Otherwise, clients may /// always need to fetch full blocks absent another means for determining which blocks contain /// transactions relevant to the watched channels. - pub fn new(chain_source: Option, broadcaster: T, logger: L, feeest: F, persister: P) -> Self { + /// + /// # Note + /// `our_peerstorage_encryption_key` must be obtained from [`NodeSigner::get_peer_storage_key`]. + /// This key is used to encrypt peer storage backups. + /// + /// **Important**: This key should not be set arbitrarily or changed after initialization. The same key + /// is obtained by the [`ChannelManager`] through [`NodeSigner`] to decrypt peer backups. + /// Using an inconsistent or incorrect key will result in the inability to decrypt previously encrypted backups. + /// + /// [`NodeSigner`]: crate::sign::NodeSigner + /// [`NodeSigner::get_peer_storage_key`]: crate::sign::NodeSigner::get_peer_storage_key + /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager + pub fn new(chain_source: Option, broadcaster: T, logger: L, feeest: F, persister: P, entropy_source: ES, our_peerstorage_encryption_key: PeerStorageKey) -> Self { Self { monitors: RwLock::new(new_hash_map()), chain_source, @@ -396,9 +416,11 @@ where C::Target: chain::Filter, logger, fee_estimator: feeest, persister, + entropy_source, pending_monitor_events: Mutex::new(Vec::new()), highest_chain_height: AtomicUsize::new(0), event_notifier: Notifier::new(), + pending_send_only_events: Mutex::new(Vec::new()), } } @@ -667,16 +689,57 @@ where C::Target: chain::Filter, }); } } + + /// This function collects the counterparty node IDs from all monitors into a `HashSet`, + /// ensuring unique IDs are returned. + fn all_counterparty_node_ids(&self) -> HashSet { + let mon = self.monitors.read().unwrap(); + mon + .values() + .map(|monitor| monitor.monitor.get_counterparty_node_id()) + .collect() + } + + fn send_peer_storage(&self, their_node_id: PublicKey) { + // TODO: Serialize `ChannelMonitor`s inside `our_peer_storage` and update [`OurPeerStorage::block_height`] accordingly. + } } -impl -chain::Listen for ChainMonitor +impl BaseMessageHandler for ChainMonitor +where C::Target: chain::Filter, + T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + P::Target: Persist, + ES::Target: EntropySource, +{ + fn get_and_clear_pending_msg_events(&self) -> Vec { + let mut pending_events = self.pending_send_only_events.lock().unwrap(); + core::mem::take(&mut *pending_events) + } + + fn peer_disconnected(&self, _their_node_id: PublicKey) {} + + fn provided_node_features(&self) -> NodeFeatures { + NodeFeatures::empty() + } + + fn provided_init_features(&self, _their_node_id: PublicKey) -> InitFeatures { + InitFeatures::empty() + } + + fn peer_connected(&self, _their_node_id: PublicKey, _msg: &Init, _inbound: bool) -> Result<(), ()> { Ok(()) } +} + +impl +chain::Listen for ChainMonitor where C::Target: chain::Filter, T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, P::Target: Persist, + ES::Target: EntropySource, { fn filtered_block_connected(&self, header: &Header, txdata: &TransactionData, height: u32) { log_debug!(self.logger, "New best block {} at height {} provided via block_connected", header.block_hash(), height); @@ -698,14 +761,15 @@ where } } -impl -chain::Confirm for ChainMonitor +impl +chain::Confirm for ChainMonitor where C::Target: chain::Filter, T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, P::Target: Persist, + ES::Target: EntropySource, { fn transactions_confirmed(&self, header: &Header, txdata: &TransactionData, height: u32) { log_debug!(self.logger, "{} provided transactions confirmed at height {} in block {}", txdata.len(), height, header.block_hash()); @@ -752,13 +816,14 @@ where } } -impl -chain::Watch for ChainMonitor +impl +chain::Watch for ChainMonitor where C::Target: chain::Filter, - T::Target: BroadcasterInterface, - F::Target: FeeEstimator, - L::Target: Logger, - P::Target: Persist, + T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + P::Target: Persist, + ES::Target: EntropySource, { fn watch_channel(&self, channel_id: ChannelId, monitor: ChannelMonitor) -> Result { let logger = WithChannelMonitor::from(&self.logger, &monitor, None); @@ -891,12 +956,13 @@ where C::Target: chain::Filter, } } -impl events::EventsProvider for ChainMonitor - where C::Target: chain::Filter, - T::Target: BroadcasterInterface, - F::Target: FeeEstimator, - L::Target: Logger, - P::Target: Persist, +impl events::EventsProvider for ChainMonitor +where C::Target: chain::Filter, + T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + P::Target: Persist, + ES::Target: EntropySource, { /// Processes [`SpendableOutputs`] events produced from each [`ChannelMonitor`] upon maturity. /// diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 3dfc3b2f21f..4beb321c089 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -16778,6 +16778,7 @@ pub mod bench { &'a test_utils::TestFeeEstimator, &'a test_utils::TestLogger, &'a P, + &'a KeysManager, >, &'a test_utils::TestBroadcaster, &'a KeysManager, @@ -16831,7 +16832,7 @@ pub mod bench { let seed_a = [1u8; 32]; let keys_manager_a = KeysManager::new(&seed_a, 42, 42); - let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a, keys_manager_a.get_peer_storage_key()); + let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a, &keys_manager_a, keys_manager_a.get_peer_storage_key()); let node_a = ChannelManager::new(&fee_estimator, &chain_monitor_a, &tx_broadcaster, &router, &message_router, &logger_a, &keys_manager_a, &keys_manager_a, &keys_manager_a, config.clone(), ChainParameters { network, best_block: BestBlock::from_network(network), @@ -16841,7 +16842,7 @@ pub mod bench { let logger_b = test_utils::TestLogger::with_id("node a".to_owned()); let seed_b = [2u8; 32]; let keys_manager_b = KeysManager::new(&seed_b, 42, 42); - let chain_monitor_b = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_b, keys_manager_b.get_peer_storage_key()); + let chain_monitor_b = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_b, &keys_manager_b, keys_manager_b.get_peer_storage_key()); let node_b = ChannelManager::new(&fee_estimator, &chain_monitor_b, &tx_broadcaster, &router, &message_router, &logger_b, &keys_manager_b, &keys_manager_b, &keys_manager_b, config.clone(), ChainParameters { network, best_block: BestBlock::from_network(network), diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 92fc73d64f9..a989d172687 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -51,10 +51,11 @@ use core::ops::Deref; use core::convert::Infallible; #[cfg(not(c_bindings))] use { + crate::chain::chainmonitor::ChainMonitor, crate::ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}, crate::onion_message::messenger::{SimpleArcOnionMessenger, SimpleRefOnionMessenger}, crate::routing::gossip::{NetworkGraph, P2PGossipSync}, - crate::sign::KeysManager, + crate::sign::{KeysManager, InMemorySigner}, crate::sync::Arc, }; @@ -418,11 +419,12 @@ impl Deref for ErroringMessageHandler { } /// Provides references to trait impls which handle different types of messages. -pub struct MessageHandler where +pub struct MessageHandler where CM::Target: ChannelMessageHandler, RM::Target: RoutingMessageHandler, OM::Target: OnionMessageHandler, CustomM::Target: CustomMessageHandler, + SM::Target: BaseMessageHandler, { /// A message handler which handles messages specific to channels. Usually this is just a /// [`ChannelManager`] object or an [`ErroringMessageHandler`]. @@ -444,6 +446,12 @@ pub struct MessageHandler where /// A message handler which handles custom messages. The only LDK-provided implementation is /// [`IgnoringMessageHandler`]. pub custom_message_handler: CustomM, + + /// A message handler which only allows sending messages. This should generally be a + /// [`ChainMonitor`]. + /// + /// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor + pub send_only_message_handler: SM, } /// Provides an object which can be used to send data to and which uniquely identifies a connection @@ -732,14 +740,15 @@ impl Peer { /// /// This is not exported to bindings users as type aliases aren't supported in most languages. #[cfg(not(c_bindings))] -pub type SimpleArcPeerManager = PeerManager< +pub type SimpleArcPeerManager = PeerManager< SD, Arc>, Arc>>, C, Arc>>, Arc>, Arc, IgnoringMessageHandler, - Arc + Arc, + Arc, Arc, Arc, Arc, Arc, Arc>>, >; /// SimpleRefPeerManager is a type alias for a PeerManager reference, and is the reference @@ -760,7 +769,8 @@ pub type SimpleRefPeerManager< &'h SimpleRefOnionMessenger<'a, 'b, 'c, 'd, 'e, 'graph, 'logger, 'i, 'j, 'k, M, T, F, L>, &'logger L, IgnoringMessageHandler, - &'c KeysManager + &'c KeysManager, + &'j ChainMonitor<&'a M, C, &'b T, &'c F, &'logger L, &'c KeysManager, &'c KeysManager>, >; @@ -785,18 +795,21 @@ pub trait APeerManager { type CMH: Deref; type NST: NodeSigner + ?Sized; type NS: Deref; + type SMT: BaseMessageHandler + ?Sized; + type SM: Deref; /// Gets a reference to the underlying [`PeerManager`]. - fn as_ref(&self) -> &PeerManager; + fn as_ref(&self) -> &PeerManager; } -impl -APeerManager for PeerManager where +impl +APeerManager for PeerManager where CM::Target: ChannelMessageHandler, RM::Target: RoutingMessageHandler, OM::Target: OnionMessageHandler, L::Target: Logger, CMH::Target: CustomMessageHandler, NS::Target: NodeSigner, + SM::Target: BaseMessageHandler, { type Descriptor = Descriptor; type CMT = ::Target; @@ -811,7 +824,9 @@ APeerManager for PeerManager where type CMH = CMH; type NST = ::Target; type NS = NS; - fn as_ref(&self) -> &PeerManager { self } + type SMT = ::Target; + type SM = SM; + fn as_ref(&self) -> &PeerManager { self } } /// A PeerManager manages a set of peers, described by their [`SocketDescriptor`] and marshalls @@ -833,14 +848,16 @@ APeerManager for PeerManager where /// you're using lightning-net-tokio. /// /// [`read_event`]: PeerManager::read_event -pub struct PeerManager where +pub struct PeerManager where CM::Target: ChannelMessageHandler, RM::Target: RoutingMessageHandler, OM::Target: OnionMessageHandler, L::Target: Logger, CMH::Target: CustomMessageHandler, - NS::Target: NodeSigner { - message_handler: MessageHandler, + NS::Target: NodeSigner, + SM::Target: BaseMessageHandler, +{ + message_handler: MessageHandler, /// Connection state for each connected peer - we have an outer read-write lock which is taken /// as read while we're doing processing for a peer and taken write when a peer is being added /// or removed. @@ -915,11 +932,13 @@ macro_rules! encode_msg { }} } -impl PeerManager where +impl PeerManager where CM::Target: ChannelMessageHandler, OM::Target: OnionMessageHandler, L::Target: Logger, - NS::Target: NodeSigner { + NS::Target: NodeSigner, + SM::Target: BaseMessageHandler, +{ /// Constructs a new `PeerManager` with the given `ChannelMessageHandler` and /// `OnionMessageHandler`. No routing message handler is used and network graph messages are /// ignored. @@ -933,17 +952,18 @@ impl Pe /// minute should suffice. /// /// This is not exported to bindings users as we can't export a PeerManager with a dummy route handler - pub fn new_channel_only(channel_message_handler: CM, onion_message_handler: OM, current_time: u32, ephemeral_random_data: &[u8; 32], logger: L, node_signer: NS) -> Self { + pub fn new_channel_only(channel_message_handler: CM, onion_message_handler: OM, current_time: u32, ephemeral_random_data: &[u8; 32], logger: L, node_signer: NS, send_only_message_handler: SM) -> Self { Self::new(MessageHandler { chan_handler: channel_message_handler, route_handler: IgnoringMessageHandler{}, onion_message_handler, custom_message_handler: IgnoringMessageHandler{}, + send_only_message_handler, }, current_time, ephemeral_random_data, logger, node_signer) } } -impl PeerManager where +impl PeerManager where RM::Target: RoutingMessageHandler, L::Target: Logger, NS::Target: NodeSigner { @@ -967,6 +987,7 @@ impl PeerManager) -> Option } } -impl PeerManager where +impl PeerManager where CM::Target: ChannelMessageHandler, RM::Target: RoutingMessageHandler, OM::Target: OnionMessageHandler, L::Target: Logger, CMH::Target: CustomMessageHandler, - NS::Target: NodeSigner + NS::Target: NodeSigner, + SM::Target: BaseMessageHandler, { /// Constructs a new `PeerManager` with the given message handlers. /// @@ -1029,7 +1051,7 @@ impl, current_time: u32, ephemeral_random_data: &[u8; 32], logger: L, node_signer: NS) -> Self { + pub fn new(message_handler: MessageHandler, current_time: u32, ephemeral_random_data: &[u8; 32], logger: L, node_signer: NS) -> Self { let mut ephemeral_key_midstate = Sha256::engine(); ephemeral_key_midstate.input(ephemeral_random_data); @@ -2671,6 +2693,11 @@ impl(peer_count: usize, cfgs: &'a Vec) -> Vec> { + fn create_network<'a>(peer_count: usize, cfgs: &'a Vec) -> Vec> { let mut peers = Vec::new(); for i in 0..peer_count { let ephemeral_bytes = [i as u8; 32]; let msg_handler = MessageHandler { chan_handler: &cfgs[i].chan_handler, route_handler: &cfgs[i].routing_handler, - onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: &cfgs[i].custom_handler + onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: &cfgs[i].custom_handler, send_only_message_handler: IgnoringMessageHandler {}, }; let peer = PeerManager::new(msg_handler, 0, &ephemeral_bytes, &cfgs[i].logger, &cfgs[i].node_signer); peers.push(peer); @@ -3183,7 +3210,7 @@ mod tests { peers } - fn try_establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor, Result, Result) { + fn try_establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor, Result, Result) { let addr_a = SocketAddress::TcpIpV4{addr: [127, 0, 0, 1], port: 1000}; let addr_b = SocketAddress::TcpIpV4{addr: [127, 0, 0, 1], port: 1001}; @@ -3214,7 +3241,7 @@ mod tests { } - fn establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { + fn establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { let addr_a = SocketAddress::TcpIpV4{addr: [127, 0, 0, 1], port: 1000}; let addr_b = SocketAddress::TcpIpV4{addr: [127, 0, 0, 1], port: 1001}; @@ -3616,12 +3643,14 @@ mod tests { route_handler: IgnoringMessageHandler {}, onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: IgnoringMessageHandler {}, + send_only_message_handler: IgnoringMessageHandler {}, }, 0, &[0; 32], &logger, &node_signer_a); let peer_b = PeerManager::new(MessageHandler { chan_handler: ErroringMessageHandler::new(), route_handler: IgnoringMessageHandler {}, onion_message_handler: IgnoringMessageHandler {}, custom_message_handler: IgnoringMessageHandler {}, + send_only_message_handler: IgnoringMessageHandler {}, }, 0, &[1; 32], &logger, &node_signer_b); let a_id = node_signer_a.get_node_id(Recipient::Node).unwrap(); diff --git a/lightning/src/util/anchor_channel_reserves.rs b/lightning/src/util/anchor_channel_reserves.rs index 968a60ada0b..ebae770fb8a 100644 --- a/lightning/src/util/anchor_channel_reserves.rs +++ b/lightning/src/util/anchor_channel_reserves.rs @@ -29,6 +29,7 @@ use crate::ln::chan_utils::max_htlcs; use crate::ln::channelmanager::AChannelManager; use crate::prelude::new_hash_set; use crate::sign::ecdsa::EcdsaChannelSigner; +use crate::sign::EntropySource; use crate::types::features::ChannelTypeFeatures; use crate::util::logger::Logger; use bitcoin::constants::WITNESS_SCALE_FACTOR; @@ -276,6 +277,7 @@ pub fn can_support_additional_anchor_channel< EstimatorRef: Deref, LoggerRef: Deref, PersistRef: Deref, + EntropySourceRef: Deref, ChainMonitorRef: Deref< Target = ChainMonitor< ChannelSigner, @@ -284,6 +286,7 @@ pub fn can_support_additional_anchor_channel< EstimatorRef, LoggerRef, PersistRef, + EntropySourceRef, >, >, >( @@ -297,6 +300,7 @@ where EstimatorRef::Target: FeeEstimator, LoggerRef::Target: Logger, PersistRef::Target: Persist, + EntropySourceRef::Target: EntropySource, { let mut anchor_channels = new_hash_set(); // Calculate the number of in-progress anchor channels by inspecting ChannelMonitors with balance. diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 5ef8b5f56de..db8457a55a3 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -407,6 +407,7 @@ pub struct TestChainMonitor<'a> { &'a TestFeeEstimator, &'a TestLogger, &'a dyn SyncPersist, + &'a TestKeysInterface, >, pub keys_manager: &'a TestKeysInterface, /// If this is set to Some(), the next update_channel call (not watch_channel) must be a @@ -435,6 +436,8 @@ impl<'a> TestChainMonitor<'a> { logger, fee_estimator, persister, + keys_manager, + keys_manager.get_peer_storage_key(), ), keys_manager, expect_channel_force_closed: Mutex::new(None), From 3f73c8ed1f51d1a19937f849e0ab0d5113250234 Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Sun, 19 Jan 2025 16:10:04 +0530 Subject: [PATCH 4/8] Distribute PeerStorage from ChainMonitor Everytime a new block is added we send PeerStorage to all of our channel partner. - Add our_peer_storage and our_peerstorage_encryption_key to ChainMonitor - Write send_peer_storage() and send it to all channel partners whenever a new block is added --- lightning/src/chain/chainmonitor.rs | 30 ++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index 7094a9ff2fe..53784a84163 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -35,6 +35,7 @@ use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, Balance use crate::chain::transaction::{OutPoint, TransactionData}; use crate::ln::types::ChannelId; use crate::ln::msgs::{self, BaseMessageHandler, Init, MessageSendEvent}; +use crate::ln::our_peer_storage::DecryptedOurPeerStorage; use crate::sign::ecdsa::EcdsaChannelSigner; use crate::sign::{EntropySource, PeerStorageKey}; use crate::events::{self, Event, EventHandler, ReplayEvent}; @@ -262,6 +263,8 @@ pub struct ChainMonitor>, + + our_peerstorage_encryption_key: PeerStorageKey, } impl ChainMonitor @@ -421,6 +424,7 @@ where C::Target: chain::Filter, highest_chain_height: AtomicUsize::new(0), event_notifier: Notifier::new(), pending_send_only_events: Mutex::new(Vec::new()), + our_peerstorage_encryption_key } } @@ -701,7 +705,19 @@ where C::Target: chain::Filter, } fn send_peer_storage(&self, their_node_id: PublicKey) { - // TODO: Serialize `ChannelMonitor`s inside `our_peer_storage` and update [`OurPeerStorage::block_height`] accordingly. + // TODO: Serialize `ChannelMonitor`s inside `our_peer_storage`. + + let random_bytes = self.entropy_source.get_secure_random_bytes(); + let serialised_channels = Vec::new(); + let our_peer_storage = DecryptedOurPeerStorage::new(serialised_channels); + let cipher = our_peer_storage.encrypt(&self.our_peerstorage_encryption_key, &random_bytes); + + log_debug!(self.logger, "Sending Peer Storage to {}", log_pubkey!(their_node_id)); + let send_peer_storage_event = MessageSendEvent::SendPeerStorage { + node_id: their_node_id, msg: msgs::PeerStorage { data: cipher.into_vec() } + }; + + self.pending_send_only_events.lock().unwrap().push(send_peer_storage_event) } } @@ -747,6 +763,12 @@ where monitor.block_connected( header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &self.logger) }); + + // Send peer storage everytime a new block arrives. + for node_id in self.all_counterparty_node_ids() { + self.send_peer_storage(node_id); + } + // Assume we may have some new events and wake the event processor self.event_notifier.notify(); } @@ -799,6 +821,12 @@ where header, height, &*self.broadcaster, &*self.fee_estimator, &self.logger ) }); + + // Send peer storage everytime a new block arrives. + for node_id in self.all_counterparty_node_ids() { + self.send_peer_storage(node_id); + } + // Assume we may have some new events and wake the event processor self.event_notifier.notify(); } From d9af88cb41a97917c67b1a4dd8342ca1e00dcb75 Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Sun, 19 Jan 2025 21:49:04 +0530 Subject: [PATCH 5/8] Handle PeerStorageRetrieval in ChannelManager Ensure ChannelManager properly handles peer_storage_retrieval. - Write internal_peer_storage_retreival to verify if we recv correct peer storage. - Send error if we get invalid peer_storage data. --- lightning/src/ln/channelmanager.rs | 38 ++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 4beb321c089..04eacd090e0 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -78,6 +78,7 @@ use crate::ln::onion_payment::{ }; use crate::ln::onion_utils::{self}; use crate::ln::onion_utils::{HTLCFailReason, LocalHTLCFailureReason}; +use crate::ln::our_peer_storage::EncryptedOurPeerStorage; #[cfg(test)] use crate::ln::outbound_payment; use crate::ln::outbound_payment::{ @@ -8546,15 +8547,38 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ } #[rustfmt::skip] - fn internal_peer_storage_retrieval(&self, counterparty_node_id: PublicKey, _msg: msgs::PeerStorageRetrieval) -> Result<(), MsgHandleErrInternal> { - // TODO: Decrypt and check if have any stale or missing ChannelMonitor. + fn internal_peer_storage_retrieval(&self, counterparty_node_id: PublicKey, msg: msgs::PeerStorageRetrieval) -> Result<(), MsgHandleErrInternal> { + // TODO: Check if have any stale or missing ChannelMonitor. let logger = WithContext::from(&self.logger, Some(counterparty_node_id), None, None); + let err = MsgHandleErrInternal::from_chan_no_close( + ChannelError::Ignore("Invalid PeerStorageRetrieval message received.".into()), + ChannelId([0; 32]), + ); + let err_str = || { + format!("Invalid PeerStorage received from {}", counterparty_node_id) + }; + + let encrypted_ops = match EncryptedOurPeerStorage::new(msg.data) { + Ok(encrypted_ops) => encrypted_ops, + Err(_) => { + log_debug!(logger, "{}", err_str()); + return Err(err); + } + }; - log_debug!(logger, "Received unexpected peer_storage_retrieval from {}. This is unusual since we do not yet distribute peer storage. Sending a warning.", log_pubkey!(counterparty_node_id)); + let decrypted_data = match encrypted_ops.decrypt(&self.node_signer.get_peer_storage_key()) { + Ok(decrypted_ops) => decrypted_ops.into_vec(), + Err(_) => { + log_debug!(logger, "{}", err_str()); + return Err(err); + } + }; - Err(MsgHandleErrInternal::from_chan_no_close(ChannelError::Warn( - "Invalid peer_storage_retrieval message received.".into(), - ), ChannelId([0; 32]))) + if decrypted_data.is_empty() { + log_debug!(logger, "Received a peer storage from peer {} with 0 channels.", log_pubkey!(counterparty_node_id)); + } + + Ok(()) } #[rustfmt::skip] @@ -16755,7 +16779,7 @@ pub mod bench { use crate::ln::msgs::{BaseMessageHandler, ChannelMessageHandler, Init, MessageSendEvent}; use crate::routing::gossip::NetworkGraph; use crate::routing::router::{PaymentParameters, RouteParameters}; - use crate::sign::{InMemorySigner, KeysManager}; + use crate::sign::{InMemorySigner, KeysManager, NodeSigner}; use crate::util::config::{MaxDustHTLCExposure, UserConfig}; use crate::util::test_utils; From e5c177b1bfe46017313ef895e790a98e22596bf5 Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Sat, 8 Mar 2025 02:50:12 +0530 Subject: [PATCH 6/8] test: update test_peer_storage to validate latest changes Ensure that we correctly handle the sendpeerstorage message event from chainmonitor and process it through channelmonitor. Key Changes: - Retrieve sendpeerstorage message event from chainmonitor for both nodes. - Handle peer storage messages exchanged between nodes and verify correct decryption. --- lightning/src/ln/channelmanager.rs | 81 ++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 04eacd090e0..649c71d8fb3 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -15463,9 +15463,26 @@ mod tests { create_announced_chan_between_nodes(&nodes, 0, 1); - // Since we do not send peer storage, we manually simulate receiving a dummy - // `PeerStorage` from the channel partner. - nodes[0].node.handle_peer_storage(nodes[1].node.get_our_node_id(), msgs::PeerStorage{data: vec![0; 100]}); + let peer_storage_msg_events_node0 = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_msg_events(); + let peer_storage_msg_events_node1 = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_msg_events(); + assert_ne!(peer_storage_msg_events_node0.len(), 0); + assert_ne!(peer_storage_msg_events_node1.len(), 0); + + match peer_storage_msg_events_node0[0] { + MessageSendEvent::SendPeerStorage { ref node_id, ref msg } => { + assert_eq!(*node_id, nodes[1].node.get_our_node_id()); + nodes[1].node.handle_peer_storage(nodes[0].node.get_our_node_id(), msg.clone()); + } + _ => panic!("Unexpected event"), + } + + match peer_storage_msg_events_node1[0] { + MessageSendEvent::SendPeerStorage { ref node_id, ref msg } => { + assert_eq!(*node_id, nodes[0].node.get_our_node_id()); + nodes[0].node.handle_peer_storage(nodes[1].node.get_our_node_id(), msg.clone()); + } + _ => panic!("Unexpected event"), + } nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id()); nodes[1].node.peer_disconnected(nodes[0].node.get_our_node_id()); @@ -15477,9 +15494,24 @@ mod tests { features: nodes[0].node.init_features(), networks: None, remote_network_address: None }, false).unwrap(); + let node_1_events = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(node_1_events.len(), 2); + let node_0_events = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(node_0_events.len(), 2); + for msg in node_1_events{ + if let MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } = msg { + nodes[0].node.handle_channel_reestablish(nodes[1].node.get_our_node_id(), msg); + assert_eq!(*node_id, nodes[0].node.get_our_node_id()); + } else if let MessageSendEvent::SendPeerStorageRetrieval { ref node_id, ref msg } = msg { + nodes[0].node.handle_peer_storage_retrieval(nodes[1].node.get_our_node_id(), msg.clone()); + assert_eq!(*node_id, nodes[0].node.get_our_node_id()); + } else { + panic!("Unexpected event") + } + } + for msg in node_0_events{ if let MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } = msg { nodes[1].node.handle_channel_reestablish(nodes[0].node.get_our_node_id(), msg); @@ -15492,29 +15524,34 @@ mod tests { } } - let msg_events_after_peer_storage_retrieval = nodes[1].node.get_and_clear_pending_msg_events(); + let node_1_msg_events = nodes[1].node.get_and_clear_pending_msg_events(); + let node_0_msg_events = nodes[0].node.get_and_clear_pending_msg_events(); - // Check if we receive a warning message. - let peer_storage_warning: Vec<&MessageSendEvent> = msg_events_after_peer_storage_retrieval - .iter() - .filter(|event| match event { - MessageSendEvent::HandleError { .. } => true, - _ => false, - }) - .collect(); - - assert_eq!(peer_storage_warning.len(), 1); + assert_eq!(node_1_msg_events.len(), 3); + assert_eq!(node_0_msg_events.len(), 3); - match peer_storage_warning[0] { - MessageSendEvent::HandleError { node_id, action } => { + for msg in node_1_msg_events { + if let MessageSendEvent::SendChannelReady { ref node_id, .. } = msg { assert_eq!(*node_id, nodes[0].node.get_our_node_id()); - match action { - ErrorAction::SendWarningMessage { msg, .. } => - assert_eq!(msg.data, "Invalid peer_storage_retrieval message received.".to_owned()), - _ => panic!("Unexpected error action"), - } + } else if let MessageSendEvent::SendAnnouncementSignatures { ref node_id, .. } = msg { + assert_eq!(*node_id, nodes[0].node.get_our_node_id()); + } else if let MessageSendEvent::SendChannelUpdate { ref node_id, .. } = msg { + assert_eq!(*node_id, nodes[0].node.get_our_node_id()); + } else { + panic!("Unexpected event") + } + } + + for msg in node_0_msg_events { + if let MessageSendEvent::SendChannelReady { ref node_id, .. } = msg { + assert_eq!(*node_id, nodes[1].node.get_our_node_id()); + } else if let MessageSendEvent::SendAnnouncementSignatures { ref node_id, .. } = msg { + assert_eq!(*node_id, nodes[1].node.get_our_node_id()); + } else if let MessageSendEvent::SendChannelUpdate { ref node_id, .. } = msg { + assert_eq!(*node_id, nodes[1].node.get_our_node_id()); + } else { + panic!("Unexpected event") } - _ => panic!("Unexpected event"), } } From 3826fbc24d1e16cf961d9c09ee02ddebad6274e6 Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Thu, 13 Mar 2025 23:10:52 +0530 Subject: [PATCH 7/8] Introduce constants for derivation path indices This commit replaces magic numbers with descriptive constant names for the indices used in key derivation paths within the `new` function. - Added constants: - `NODE_SECRET_INDEX` - `DESTINATION_SCRIPT_INDEX` - `SHUTDOWN_PUBKEY_INDEX` - `CHANNEL_MASTER_KEY_INDEX` - `INBOUND_PAYMENT_KEY_INDEX` - `PEER_STORAGE_KEY_INDEX` --- lightning/src/sign/mod.rs | 56 ++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index bd39cb87f3c..a623858ae56 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1856,46 +1856,52 @@ impl KeysManager { /// /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor pub fn new(seed: &[u8; 32], starting_time_secs: u64, starting_time_nanos: u32) -> Self { + // Constants for key derivation path indices used in this function. + const NODE_SECRET_INDEX: ChildNumber = ChildNumber::Hardened { index: 0 }; + const DESTINATION_SCRIPT_INDEX: ChildNumber = ChildNumber::Hardened { index: (1) }; + const SHUTDOWN_PUBKEY_INDEX: ChildNumber = ChildNumber::Hardened { index: (2) }; + const CHANNEL_MASTER_KEY_INDEX: ChildNumber = ChildNumber::Hardened { index: (3) }; + const INBOUND_PAYMENT_KEY_INDEX: ChildNumber = ChildNumber::Hardened { index: (5) }; + const PEER_STORAGE_KEY_INDEX: ChildNumber = ChildNumber::Hardened { index: (6) }; + let secp_ctx = Secp256k1::new(); // Note that when we aren't serializing the key, network doesn't matter match Xpriv::new_master(Network::Testnet, seed) { Ok(master_key) => { let node_secret = master_key - .derive_priv(&secp_ctx, &ChildNumber::from_hardened_idx(0).unwrap()) + .derive_priv(&secp_ctx, &NODE_SECRET_INDEX) .expect("Your RNG is busted") .private_key; let node_id = PublicKey::from_secret_key(&secp_ctx, &node_secret); - let destination_script = match master_key - .derive_priv(&secp_ctx, &ChildNumber::from_hardened_idx(1).unwrap()) - { - Ok(destination_key) => { - let wpubkey_hash = WPubkeyHash::hash( - &Xpub::from_priv(&secp_ctx, &destination_key).to_pub().to_bytes(), - ); - Builder::new() - .push_opcode(opcodes::all::OP_PUSHBYTES_0) - .push_slice(&wpubkey_hash.to_byte_array()) - .into_script() - }, - Err(_) => panic!("Your RNG is busted"), - }; - let shutdown_pubkey = match master_key - .derive_priv(&secp_ctx, &ChildNumber::from_hardened_idx(2).unwrap()) - { - Ok(shutdown_key) => Xpub::from_priv(&secp_ctx, &shutdown_key).public_key, - Err(_) => panic!("Your RNG is busted"), - }; + let destination_script = + match master_key.derive_priv(&secp_ctx, &DESTINATION_SCRIPT_INDEX) { + Ok(destination_key) => { + let wpubkey_hash = WPubkeyHash::hash( + &Xpub::from_priv(&secp_ctx, &destination_key).to_pub().to_bytes(), + ); + Builder::new() + .push_opcode(opcodes::all::OP_PUSHBYTES_0) + .push_slice(&wpubkey_hash.to_byte_array()) + .into_script() + }, + Err(_) => panic!("Your RNG is busted"), + }; + let shutdown_pubkey = + match master_key.derive_priv(&secp_ctx, &SHUTDOWN_PUBKEY_INDEX) { + Ok(shutdown_key) => Xpub::from_priv(&secp_ctx, &shutdown_key).public_key, + Err(_) => panic!("Your RNG is busted"), + }; let channel_master_key = master_key - .derive_priv(&secp_ctx, &ChildNumber::from_hardened_idx(3).unwrap()) + .derive_priv(&secp_ctx, &CHANNEL_MASTER_KEY_INDEX) .expect("Your RNG is busted"); let inbound_payment_key: SecretKey = master_key - .derive_priv(&secp_ctx, &ChildNumber::from_hardened_idx(5).unwrap()) + .derive_priv(&secp_ctx, &INBOUND_PAYMENT_KEY_INDEX) .expect("Your RNG is busted") .private_key; let mut inbound_pmt_key_bytes = [0; 32]; inbound_pmt_key_bytes.copy_from_slice(&inbound_payment_key[..]); - let peer_storage_key: SecretKey = master_key - .derive_priv(&secp_ctx, &ChildNumber::from_hardened_idx(6).unwrap()) + let peer_storage_key = master_key + .derive_priv(&secp_ctx, &PEER_STORAGE_KEY_INDEX) .expect("Your RNG is busted") .private_key; From e39d99ae8c42fa2cd65460181d2af265df5f8b4e Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Mon, 9 Jun 2025 19:53:34 +0530 Subject: [PATCH 8/8] fuzz fix Generating random bytes while sending peer storage broke the fuzz due to change in parameters. Key Changes: - Change in HTLC amount as there were both remote and local commitments with the same txid. --- fuzz/src/full_stack.rs | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 39fe28a27c1..f6fa07199fa 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -1185,7 +1185,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 255 ext_from_hex("0301ff", &mut test); // beginning of accept_channel - ext_from_hex("0021 0000000000000000000000000000000000000000000000000000000000000e05 0000000000000162 00000000004c4b40 00000000000003e8 00000000000003e8 00000002 03f0 0005 030000000000000000000000000000000000000000000000000000000000000100 030000000000000000000000000000000000000000000000000000000000000200 030000000000000000000000000000000000000000000000000000000000000300 030000000000000000000000000000000000000000000000000000000000000400 030000000000000000000000000000000000000000000000000000000000000500 02660000000000000000000000000000", &mut test); + ext_from_hex("0021 0000000000000000000000000000000000000000000000000000000000000e12 0000000000000162 00000000004c4b40 00000000000003e8 00000000000003e8 00000002 03f0 0005 030000000000000000000000000000000000000000000000000000000000000100 030000000000000000000000000000000000000000000000000000000000000200 030000000000000000000000000000000000000000000000000000000000000300 030000000000000000000000000000000000000000000000000000000000000400 030000000000000000000000000000000000000000000000000000000000000500 02660000000000000000000000000000", &mut test); // inbound read from peer id 1 of len 35 ext_from_hex("030123", &mut test); // rest of accept_channel and mac @@ -1206,11 +1206,11 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 114 ext_from_hex("030172", &mut test); // funding_signed message and mac - ext_from_hex("0023 3a00000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000007c0001000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); + ext_from_hex("0023 2900000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000b90001000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); // broadcast funding transaction ext_from_hex("0b", &mut test); - // by now client should have sent a channel_ready (CHECK 4: SendChannelReady to 03020000 for chan 3f000000) + // by now client should have sent a channel_ready (CHECK 4: SendChannelReady to 03020000 for chan 2f000000) // inbound read from peer id 1 of len 18 ext_from_hex("030112", &mut test); @@ -1219,7 +1219,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 83 ext_from_hex("030153", &mut test); // channel_ready and mac - ext_from_hex("0024 3a00000000000000000000000000000000000000000000000000000000000000 026700000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); + ext_from_hex("0024 2900000000000000000000000000000000000000000000000000000000000000 026700000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); // inbound read from peer id 0 of len 18 ext_from_hex("030012", &mut test); @@ -1272,7 +1272,7 @@ fn two_peer_forwarding_seed() -> Vec { ext_from_hex("07", &mut test); // Four feerate requests to check dust exposure while forwarding the HTLC ext_from_hex("00fd00fd00fd00fd", &mut test); - // client now sends id 1 update_add_htlc and commitment_signed (CHECK 7: UpdateHTLCs event for node 03020000 with 1 HTLCs for channel 3f000000) + // client now sends id 1 update_add_htlc and commitment_signed (CHECK 7: UpdateHTLCs event for node 03020000 with 1 HTLCs for channel 2f000000) // we respond with commitment_signed then revoke_and_ack (a weird, but valid, order) // inbound read from peer id 1 of len 18 @@ -1282,7 +1282,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 116 ext_from_hex("030174", &mut test); // commitment_signed and mac - ext_from_hex("0084 3a00000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000006a0001000000000000000000000000000000000000000000000000000000000000 0000 01000000000000000000000000000000", &mut test); + ext_from_hex("0084 2900000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000e40001000000000000000000000000000000000000000000000000000000000000 0000 01000000000000000000000000000000", &mut test); // // inbound read from peer id 1 of len 18 ext_from_hex("030112", &mut test); @@ -1291,7 +1291,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 115 ext_from_hex("030173", &mut test); // revoke_and_ack and mac - ext_from_hex("0085 3a00000000000000000000000000000000000000000000000000000000000000 6600000000000000000000000000000000000000000000000000000000000000 026400000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); + ext_from_hex("0085 2900000000000000000000000000000000000000000000000000000000000000 6600000000000000000000000000000000000000000000000000000000000000 026400000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); // // inbound read from peer id 1 of len 18 ext_from_hex("030112", &mut test); @@ -1300,7 +1300,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 90 ext_from_hex("03015a", &mut test); // update_fulfill_htlc and mac - ext_from_hex("0082 3a00000000000000000000000000000000000000000000000000000000000000 0000000000000000 ff00888888888888888888888888888888888888888888888888888888888888 01000000000000000000000000000000", &mut test); + ext_from_hex("0082 2900000000000000000000000000000000000000000000000000000000000000 0000000000000000 ff00888888888888888888888888888888888888888888888888888888888888 01000000000000000000000000000000", &mut test); // client should immediately claim the pending HTLC from peer 0 (CHECK 8: SendFulfillHTLCs for node 03000000 with preimage ff00888888 for channel 3d000000) // inbound read from peer id 1 of len 18 @@ -1310,7 +1310,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 116 ext_from_hex("030174", &mut test); // commitment_signed and mac - ext_from_hex("0084 3a00000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000000 0000 01000000000000000000000000000000", &mut test); + ext_from_hex("0084 2900000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000330001000000000000000000000000000000000000000000000000000000000000 0000 01000000000000000000000000000000", &mut test); // inbound read from peer id 1 of len 18 ext_from_hex("030112", &mut test); @@ -1319,7 +1319,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 115 ext_from_hex("030173", &mut test); // revoke_and_ack and mac - ext_from_hex("0085 3a00000000000000000000000000000000000000000000000000000000000000 6700000000000000000000000000000000000000000000000000000000000000 026500000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); + ext_from_hex("0085 2900000000000000000000000000000000000000000000000000000000000000 6700000000000000000000000000000000000000000000000000000000000000 026500000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); // before responding to the commitment_signed generated above, send a new HTLC // inbound read from peer id 0 of len 18 @@ -1395,7 +1395,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 116 ext_from_hex("030174", &mut test); // commitment_signed and mac - ext_from_hex("0084 3a00000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000390001000000000000000000000000000000000000000000000000000000000000 0000 01000000000000000000000000000000", &mut test); + ext_from_hex("0084 2900000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000009c0001000000000000000000000000000000000000000000000000000000000000 0000 01000000000000000000000000000000", &mut test); // inbound read from peer id 1 of len 18 ext_from_hex("030112", &mut test); @@ -1404,7 +1404,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 115 ext_from_hex("030173", &mut test); // revoke_and_ack and mac - ext_from_hex("0085 3a00000000000000000000000000000000000000000000000000000000000000 6400000000000000000000000000000000000000000000000000000000000000 027000000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); + ext_from_hex("0085 2900000000000000000000000000000000000000000000000000000000000000 6400000000000000000000000000000000000000000000000000000000000000 027000000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); // inbound read from peer id 1 of len 18 ext_from_hex("030112", &mut test); @@ -1413,7 +1413,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 60 ext_from_hex("03013c", &mut test); // update_fail_htlc and mac - ext_from_hex("0083 3a00000000000000000000000000000000000000000000000000000000000000 0000000000000001 0000 01000000000000000000000000000000", &mut test); + ext_from_hex("0083 2900000000000000000000000000000000000000000000000000000000000000 0000000000000001 0000 01000000000000000000000000000000", &mut test); // inbound read from peer id 1 of len 18 ext_from_hex("030112", &mut test); @@ -1422,7 +1422,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 116 ext_from_hex("030174", &mut test); // commitment_signed and mac - ext_from_hex("0084 3a00000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000390001000000000000000000000000000000000000000000000000000000000000 0000 01000000000000000000000000000000", &mut test); + ext_from_hex("0084 2900000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000e20001000000000000000000000000000000000000000000000000000000000000 0000 01000000000000000000000000000000", &mut test); // inbound read from peer id 1 of len 18 ext_from_hex("030112", &mut test); @@ -1431,7 +1431,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 1 of len 115 ext_from_hex("030173", &mut test); // revoke_and_ack and mac - ext_from_hex("0085 3a00000000000000000000000000000000000000000000000000000000000000 6500000000000000000000000000000000000000000000000000000000000000 027100000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); + ext_from_hex("0085 2900000000000000000000000000000000000000000000000000000000000000 6500000000000000000000000000000000000000000000000000000000000000 027100000000000000000000000000000000000000000000000000000000000000 01000000000000000000000000000000", &mut test); // process the now-pending HTLC forward ext_from_hex("07", &mut test); @@ -1464,7 +1464,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 0 of len 255 ext_from_hex("0300ff", &mut test); // beginning of update_add_htlc from 0 to 1 via client - ext_from_hex("0080 3d00000000000000000000000000000000000000000000000000000000000000 0000000000000002 00000000000b0838 ff00000000000000000000000000000000000000000000000000000000000000 000003f0 00 030000000000000000000000000000000000000000000000000000000000000555 12 02030927c0 0401a0 060800000e0000010000 0a00000000000000000000000000000000000000000000000000000000000000 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", &mut test); + ext_from_hex("0080 3d00000000000000000000000000000000000000000000000000000000000000 0000000000000002 00000000000b0838 ff00000000000000000000000000000000000000000000000000000000000000 000003f0 00 030000000000000000000000000000000000000000000000000000000000000555 12 02030927c1 0401a0 060800000e0000010000 0a00000000000000000000000000000000000000000000000000000000000000 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", &mut test); // inbound read from peer id 0 of len 255 ext_from_hex("0300ff", &mut test); ext_from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", &mut test); @@ -1480,7 +1480,7 @@ fn two_peer_forwarding_seed() -> Vec { // inbound read from peer id 0 of len 193 ext_from_hex("0300c1", &mut test); // end of update_add_htlc from 0 to 1 via client and mac - ext_from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 5300000000000000000000000000000000000000000000000000000000000000 03000000000000000000000000000000", &mut test); + ext_from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 5200000000000000000000000000000000000000000000000000000000000000 03000000000000000000000000000000", &mut test); // One feerate request to check dust exposure ext_from_hex("00fd", &mut test); @@ -1512,15 +1512,15 @@ fn two_peer_forwarding_seed() -> Vec { // connect a block with one transaction of len 125 ext_from_hex("0c007d", &mut test); - // the commitment transaction for channel 3f00000000000000000000000000000000000000000000000000000000000000 - ext_from_hex("02000000013a000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200204b0000000000000000000000000000000000000000000000000000000000000014c0000000000000160014280000000000000000000000000000000000000005000020", &mut test); + // the commitment transaction for channel 2900000000000000000000000000000000000000000000000000000000000000 + ext_from_hex("020000000129000000000000000000000000000000000000000000000000000000000000000000000000000000800258020000000000002200201f0000000000000000000000000000000000000000000000000000000000000013c00000000000001600143b0000000000000000000000000000000000000005000020", &mut test); // Two feerate requests during block connection ext_from_hex("00fd00fd", &mut test); // // connect a block with one transaction of len 94 ext_from_hex("0c005e", &mut test); // the HTLC timeout transaction - ext_from_hex("0200000001730000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020b20000000000000000000000000000000000000000000000000000000000000000000000", &mut test); + ext_from_hex("0200000001200000000000000000000000000000000000000000000000000000000000000000000000000000000001a701000000000000220020e60000000000000000000000000000000000000000000000000000000000000000000000", &mut test); // Two feerate requests during block connection ext_from_hex("00fd00fd", &mut test); // connect a block with no transactions @@ -1702,19 +1702,19 @@ mod tests { // 3 assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendChannelReady event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 4 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendChannelReady event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 for channel 3a00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendChannelReady event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 for channel 2900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 5 assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendRevokeAndACK event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&4)); // 6 assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 with 0 adds, 0 fulfills, 0 fails, 1 commits for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 7 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails, 1 commits for channel 3a00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); + assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails, 1 commits for channel 2900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 8 assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 with 0 adds, 1 fulfills, 0 fails, 1 commits for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 9 assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000002 with 0 adds, 0 fulfills, 1 fails, 1 commits for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&2)); // 10 - assert_eq!(log_entries.get(&("lightning::chain::channelmonitor".to_string(), "Input spending counterparty commitment tx (0000000000000000000000000000000000000000000000000000000000000073:0) in 0000000000000000000000000000000000000000000000000000000000000067 resolves outbound HTLC with payment hash ff00000000000000000000000000000000000000000000000000000000000000 with timeout".to_string())), Some(&1)); + assert_eq!(log_entries.get(&("lightning::chain::channelmonitor".to_string(), "Input spending counterparty commitment tx (0000000000000000000000000000000000000000000000000000000000000020:0) in 0000000000000000000000000000000000000000000000000000000000000060 resolves outbound HTLC with payment hash ff00000000000000000000000000000000000000000000000000000000000000 with timeout".to_string())), Some(&1)); } #[test]