diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f1ec14fc..4be45cfda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ -# 0.7.0-rc.18 (Synonym Fork) +# 0.7.0-rc.26 (Synonym Fork) ## Bug Fixes + +- Fixed `PeerStore::add_peer` silently ignoring address updates for existing peers. When a peer's + IP address changes (e.g., LSP node migration), `add_peer` now upserts the socket address and + re-persists, instead of returning early. This fixes the issue where ldk-node's reconnection loop + would indefinitely use a stale cached IP after an LSP node IP change. + (See [upstream issue #700](https://github.com/lightningdevkit/ldk-node/issues/700)) - Backported upstream Electrum sync fix (PR #4341): Skip unconfirmed `get_history` entries in `ElectrumSyncClient`. Previously, mempool entries (height=0 or -1) were incorrectly treated as confirmed, causing `get_merkle` to fail for 0-conf channel funding transactions. @@ -8,6 +14,7 @@ emitted when LDK replays events after node restart. ## Synonym Fork Additions + - Upgraded to Kotlin 2.2.0 for compatibility with consuming apps using Kotlin 2.x - Added JitPack support for `ldk-node-jvm` module to enable unit testing in consuming apps - Added runtime-adjustable wallet sync intervals for battery optimization on mobile: @@ -88,11 +95,13 @@ would use internally. # 0.7.0 - Dec. 3, 2025 + This seventh minor release introduces numerous new features, bug fixes, and API improvements. In particular, it adds support for channel Splicing, Async Payments, as well as sourcing chain data from a Bitcoin Core REST backend. ## Feature and API updates + - Experimental support for channel splicing has been added. (#677) - - **Note**: Splicing-related transactions might currently still get misclassified in the payment store. + - **Note**: Splicing-related transactions might currently still get misclassified in the payment store. - Support for serving and paying static invoices for Async Payments has been added. (#621, #632) - Sourcing chain data via Bitcoin Core's REST interface is now supported. (#526) - A new `Builder::set_chain_source_esplora_with_headers` method has been added @@ -111,6 +120,7 @@ This seventh minor release introduces numerous new features, bug fixes, and API - The `generate_entropy_mnemonic` method now supports specifying a word count. (#699) ## Bug Fixes and Improvements + - Robustness of the shutdown procedure has been improved, minimizing risk of blocking during `Node::stop`. (#592, #612, #619, #622) - The VSS storage backend now supports 'lazy' deletes, allowing it to avoid unnecessarily waiting on remote calls for certain operations. (#689, #722) @@ -127,6 +137,7 @@ This seventh minor release introduces numerous new features, bug fixes, and API - The node now listens on all provided listening addresses. (#644) ## Compatibility Notes + - The minimum supported Rust version (MSRV) has been bumped to `rustc` v1.85 (#606) - The LDK dependency has been bumped to v0.2. - The BDK dependency has been bumped to v2.2. (#656) @@ -155,11 +166,13 @@ deletions in 264 commits from 14 authors in alphabetical order: - tosynthegeek # 0.6.2 - Aug. 14, 2025 + This patch release fixes a panic that could have been hit when syncing to a TLS-enabled Electrum server, as well as some minor issues when shutting down the node. ## Bug Fixes and Improvements + - If not set by the user, we now install a default `CryptoProvider` for the `rustls` TLS library. This fixes an issue that would have the node panic whenever they first try to access an Electrum server behind an `ssl://` @@ -176,15 +189,18 @@ deletions in 13 commits from 2 authors in alphabetical order: - moisesPomilio # 0.6.1 - Jun. 19, 2025 + This patch release fixes minor issues with the recently-exposed `Bolt11Invoice` type in bindings. ## Feature and API updates + - The `Bolt11Invoice::description` method is now exposed as `Bolt11Invoice::invoice_description` in bindings, to avoid collisions with a Swift standard method of same name (#576) ## Bug Fixes and Improvements + - The `Display` implementation of `Bolt11Invoice` is now exposed in bindings, (re-)allowing to render the invoice as a string. (#574) @@ -194,16 +210,19 @@ in 8 commits from 1 author in alphabetical order: - Elias Rohrer # 0.6.0 - Jun. 9, 2025 + This sixth minor release mainly fixes an issue that could have left the on-chain wallet unable to spend funds if transactions that had previously been accepted to the mempool ended up being evicted. ## Feature and API updates + - Onchain addresses are now validated against the expected network before use (#519). - The API methods on the `Bolt11Invoice` type are now exposed in bindings (#522). - The `UnifiedQrPayment::receive` flow no longer aborts if we're unable to generate a BOLT12 offer (#548). ## Bug Fixes and Improvements + - Previously, the node could potentially enter a state that would have left the onchain wallet unable spend any funds if previously-generated transactions had been first accepted, and then evicted from the mempool. This has been @@ -213,6 +232,7 @@ accepted to the mempool ended up being evicted. - The output of the `log` facade logger has been corrected (#547). ## Compatibility Notes + - The BDK dependency has been bumped to `bdk_wallet` v2.0 (#551). In total, this release features 20 files changed, 1188 insertions, 447 deletions, in 18 commits from 3 authors in alphabetical order: @@ -222,9 +242,11 @@ In total, this release features 20 files changed, 1188 insertions, 447 deletions - Elias Rohrer # 0.5.0 - Apr. 29, 2025 + Besides numerous API improvements and bugfixes this fifth minor release notably adds support for sourcing chain and fee rate data from an Electrum backend, requesting channels via the [bLIP-51 / LSPS1](https://github.com/lightning/blips/blob/master/blip-0051.md) protocol, as well as experimental support for operating as a [bLIP-52 / LSPS2](https://github.com/lightning/blips/blob/master/blip-0052.md) service. ## Feature and API updates + - The `PaymentSuccessful` event now exposes a `payment_preimage` field (#392). - The node now emits `PaymentForwarded` events for forwarded payments (#404). - The ability to send custom TLVs as part of spontaneous payments has been added (#411). @@ -238,7 +260,7 @@ Besides numerous API improvements and bugfixes this fifth minor release notably - On-chain transactions are now added to the internal payment store and exposed via `Node::list_payments` (#432). - Inbound announced channels are now rejected if not all requirements for operating as a forwarding node (set listening addresses and node alias) have been met (#467). - Initial support for operating as an bLIP-52 / LSPS2 service has been added (#420). - - **Note**: bLIP-52 / LSPS2 support is considered 'alpha'/'experimental' and should *not* yet be used in production. + - **Note**: bLIP-52 / LSPS2 support is considered 'alpha'/'experimental' and should _not_ yet be used in production. - The `Builder::set_entropy_seed_bytes` method now takes an array rather than a `Vec` (#493). - The builder will now return a `NetworkMismatch` error in case of network switching (#485). - The `Bolt11Jit` payment variant now exposes a field telling how much fee the LSP withheld (#497). @@ -248,6 +270,7 @@ Besides numerous API improvements and bugfixes this fifth minor release notably - The ability to sync the node via an Electrum backend has been added (#486). ## Bug Fixes and Improvements + - When syncing from Bitcoin Core RPC, syncing mempool entries has been made more efficient (#410, #465). - We now ensure the our configured fallback rates are used when the configured chain source would return huge bogus values during fee estimation (#430). - We now re-enabled trying to bump Anchor channel transactions for trusted counterparties in the `ContentiousClaimable` case to reduce the risk of losing funds in certain edge cases (#461). @@ -255,6 +278,7 @@ Besides numerous API improvements and bugfixes this fifth minor release notably - The `Node::remove_payment` now also removes the respective entry from the in-memory state, not only from the persisted payment store (#514). ## Compatibility Notes + - The filesystem logger was simplified and its default path changed to `ldk_node.log` in the configured storage directory (#394). - The BDK dependency has been bumped to `bdk_wallet` v1.0 (#426). - The LDK dependency has been bumped to `lightning` v0.1 (#426). @@ -295,7 +319,6 @@ In total, this release features 1 files changed, 40 insertions, 4 deletions in 3 - Fuyin - Elias Rohrer - # 0.4.1 - Oct 18, 2024 This patch release fixes a wallet syncing issue where full syncs were used instead of incremental syncs, and vice versa (#383). @@ -311,10 +334,11 @@ In total, this release features 3 files changed, 13 insertions, 9 deletions in 6 Besides numerous API improvements and bugfixes this fourth minor release notably adds support for sourcing chain and fee rate data from a Bitcoin Core RPC backend, as well as experimental support for the [VSS] remote storage backend. ## Feature and API updates + - Support for multiple chain sources has been added. To this end, Esplora-specific configuration options can now be given via `EsploraSyncConfig` to `Builder::set_chain_source_esplora`. Furthermore, all configuration objects (including the main `Config`) is now exposed via the `config` sub-module (#365). - Support for sourcing chain and fee estimation data from a Bitcoin Core RPC backed has been added (#370). - Initial experimental support for an encrypted [VSS] remote storage backend has been added (#369, #376, #378). - - **Caution**: VSS support is in **alpha** and is considered experimental. Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are unrecoverable, i.e., if they remain unresolved after internal retries are exhausted. + - **Caution**: VSS support is in **alpha** and is considered experimental. Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are unrecoverable, i.e., if they remain unresolved after internal retries are exhausted. - Support for setting the `NodeAlias` in public node announcements as been added. We now ensure that announced channels can only be opened and accepted when the required configuration options to operate as a public forwarding node are set (listening addresses and node alias). As part of this `Node::connect_open_channel` was split into `open_channel` and `open_announced_channel` API methods. (#330, #366). - The `Node` can now be started via a new `Node::start_with_runtime` call that allows to reuse an outer `tokio` runtime context, avoiding runtime stacking when run in `async` environments (#319). - Support for generating and paying unified QR codes has been added (#302). @@ -322,16 +346,19 @@ Besides numerous API improvements and bugfixes this fourth minor release notably - Support for setting additional parameters when sending BOLT11 payments has been added (#336, #351). ## Bug Fixes + - The `ChannelConfig` object has been refactored, now allowing to query the currently applied `MaxDustHTLCExposure` limit (#350). - A bug potentially leading to panicking on shutdown when stacking `tokio` runtime contexts has been fixed (#373). - We now no longer panic when hitting a persistence failure during event handling. Instead, events will be replayed until successful (#374). -, + , + ## Compatibility Notes + - The LDK dependency has been updated to version 0.0.125 (#358, #375). - The BDK dependency has been updated to version 1.0-beta.4 (#358). - - Going forward, the BDK state will be persisted in the configured `KVStore` backend. - - **Note**: The old descriptor state will *not* be automatically migrated on upgrade, potentially leading to address reuse. Privacy-concious users might want to manually advance the descriptor by requesting new addresses until it reaches the previously observed height. - - After the node as been successfully upgraded users may safely delete `bdk_wallet_*.sqlite` from the storage path. + - Going forward, the BDK state will be persisted in the configured `KVStore` backend. + - **Note**: The old descriptor state will _not_ be automatically migrated on upgrade, potentially leading to address reuse. Privacy-concious users might want to manually advance the descriptor by requesting new addresses until it reaches the previously observed height. + - After the node as been successfully upgraded users may safely delete `bdk_wallet_*.sqlite` from the storage path. - The `rust-bitcoin` dependency has been updated to version 0.32.2 (#358). - The UniFFI dependency has been updated to version 0.27.3 (#379). - The `bip21` dependency has been updated to version 0.5 (#358). @@ -354,6 +381,7 @@ This third minor release notably adds support for BOLT12 payments, Anchor channels, and sourcing inbound liquidity via LSPS2 just-in-time channels. ## Feature and API updates + - Support for creating and paying BOLT12 offers and refunds has been added (#265). - Support for Anchor channels has been added (#141). - Support for sourcing inbound liquidity via LSPS2 just-in-time (JIT) channels has been added (#223). @@ -371,6 +399,7 @@ channels, and sourcing inbound liquidity via LSPS2 just-in-time channels. - The ability to register and claim from custom payment hashes generated outside of LDK Node has been added (#308). ## Bug Fixes + - Node announcements are now correctly only broadcast if we have any public, sufficiently confirmed channels (#248, #314). - Falling back to default fee values is now disallowed on mainnet, ensuring we won't startup without a successful fee cache update (#249). - Persisted peers are now correctly reconnected after startup (#265). @@ -378,6 +407,7 @@ channels, and sourcing inbound liquidity via LSPS2 just-in-time channels. - Several steps have been taken to reduce the risk of blocking node operation on wallet syncing in the face of unresponsive Esplora services (#281). ## Compatibility Notes + - LDK has been updated to version 0.0.123 (#291). In total, this release features 54 files changed, 7282 insertions, 2410 deletions in 165 commits from 3 authors, in alphabetical order: @@ -406,9 +436,11 @@ This is a bugfix release bumping the used LDK and BDK dependencies to the latest stable versions. ## Bug Fixes + - Swift bindings now can be built on macOS again. ## Compatibility Notes + - LDK has been updated to version 0.0.121 (#214, #229) - BDK has been updated to version 0.29.0 (#229) @@ -422,6 +454,7 @@ deletions in 26 commits from 3 authors, in alphabetical order: # 0.2.0 - Dec 13, 2023 ## Feature and API updates + - The capability to send pre-flight probes has been added (#147). - Pre-flight probes will skip outbound channels based on the liquidity available (#156). - Additional fields are now exposed via `ChannelDetails` (#165). @@ -432,10 +465,12 @@ deletions in 26 commits from 3 authors, in alphabetical order: - A module persisting, sweeping, and rebroadcasting output spends has been added (#152). ## Bug Fixes + - No errors are logged anymore when we choose to omit spending of `StaticOutput`s (#137). - An inconsistent state of the log file symlink no longer results in an error during startup (#153). ## Compatibility Notes + - Our currently supported minimum Rust version (MSRV) is 1.63.0. - The Rust crate edition has been bumped to 2021. - Building on Windows is now supported (#160). @@ -454,6 +489,7 @@ In total, this release features 57 files changed, 7369 insertions, 1738 deletion - Orbital # 0.1.0 - Jun 22, 2023 + This is the first non-experimental release of LDK Node. - Log files are now split based on the start date of the node (#116). @@ -467,15 +503,18 @@ This is the first non-experimental release of LDK Node. - The API has been updated to be more aligned between Rust and bindings (#114). ## Compatibility Notes + - Our currently supported minimum Rust version (MSRV) is 1.60.0. - The superfluous `SendingFailed` payment status has been removed, breaking serialization compatibility with alpha releases (#125). - The serialization formats of `PaymentDetails` and `Event` types have been updated, ensuring users upgrading from an alpha release fail to start rather than continuing operating with bogus data. Alpha users should wipe their persisted payment metadata (`payments/*`) and event queue (`events`) after the update (#130). In total, this release includes changes in 52 commits from 2 authors: + - Elias Rohrer - Richard Ulrich # 0.1-alpha.1 - Jun 6, 2023 + - Generation of Swift, Kotlin (JVM and Android), and Python bindings is now supported through UniFFI (#25). - Lists of connected peers and channels may now be retrieved in bindings (#56). - Gossip data may now be sourced from the P2P network, or a Rapid Gossip Sync server (#70). @@ -490,8 +529,8 @@ In total, this release includes changes in 52 commits from 2 authors: - The wallet sync intervals are now configurable (#102). - Granularity of logging can now be configured (#108). - In total, this release includes changes in 64 commits from 4 authors: + - Steve Myers - Elias Rohrer - Jurvis Tan @@ -501,6 +540,7 @@ In total, this release includes changes in 64 commits from 4 authors: production, and no compatibility guarantees are given until the release of 0.1. # 0.1-alpha - Apr 27, 2023 + This is the first alpha release of LDK Node. It features support for sourcing chain data via an Esplora server, file system persistence, gossip sourcing via the Lightning peer-to-peer network, and configurable entropy sources for the diff --git a/Cargo.toml b/Cargo.toml index 76c8fda7a..6f8751bb7 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ldk-node" -version = "0.7.0-rc.18" +version = "0.7.0-rc.26" authors = ["Elias Rohrer "] homepage = "https://lightningdevkit.org/" license = "MIT OR Apache-2.0" diff --git a/Package.swift b/Package.swift index ab06e22ba..83d13cccc 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription -let tag = "v0.7.0-rc.18" -let checksum = "05903150276c3c31b2552b89d3781157ac1bbf55a10598655897abd9fe936b6c" +let tag = "v0.7.0-rc.26" +let checksum = "70e5eeed841b4f2394a148e93b729ec503aa1a4255d8f040443de960aeea90cf" let url = "https://github.com/synonymdev/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip" let package = Package( diff --git a/bindings/kotlin/ldk-node-android/gradle.properties b/bindings/kotlin/ldk-node-android/gradle.properties index 2b0abdb57..36b21240f 100644 --- a/bindings/kotlin/ldk-node-android/gradle.properties +++ b/bindings/kotlin/ldk-node-android/gradle.properties @@ -2,4 +2,4 @@ org.gradle.jvmargs=-Xmx1536m android.useAndroidX=true android.enableJetifier=true kotlin.code.style=official -libraryVersion=0.7.0-rc.18 +libraryVersion=0.7.0-rc.26 diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so index 1798f33a0..9a10003fe 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so index 45afa3297..d18f5cb2f 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so index b75d024e8..998fb7694 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-jvm/gradle.properties b/bindings/kotlin/ldk-node-jvm/gradle.properties index f2e17b9f8..217f1c465 100644 --- a/bindings/kotlin/ldk-node-jvm/gradle.properties +++ b/bindings/kotlin/ldk-node-jvm/gradle.properties @@ -1,3 +1,3 @@ org.gradle.jvmargs=-Xmx1536m kotlin.code.style=official -libraryVersion=0.7.0-rc.18 +libraryVersion=0.7.0-rc.26 diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib index b77fef4a4..944a08e55 100644 Binary files a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib differ diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib index c9b9a44e9..f201ef683 100644 Binary files a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib differ diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 079fbce67..2e2bce858 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ldk_node" -version = "0.7.0-rc.18" +version = "0.7.0-rc.26" authors = [ { name="Elias Rohrer", email="dev@tnull.de" }, ] diff --git a/src/lib.rs b/src/lib.rs index 4b94448fa..ebbeed529 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1106,6 +1106,10 @@ impl Node { let peer_info = PeerInfo { node_id, address }; + if persist { + self.peer_store.add_peer(peer_info.clone())?; + } + let con_node_id = peer_info.node_id; let con_addr = peer_info.address.clone(); let con_cm = Arc::clone(&self.connection_manager); @@ -1118,10 +1122,6 @@ impl Node { log_info!(self.logger, "Connected to peer {}@{}. ", peer_info.node_id, peer_info.address); - if persist { - self.peer_store.add_peer(peer_info)?; - } - Ok(()) } diff --git a/src/peer_store.rs b/src/peer_store.rs index 59cd3d94f..fc0ea090b 100644 --- a/src/peer_store.rs +++ b/src/peer_store.rs @@ -18,7 +18,7 @@ use crate::io::{ PEER_INFO_PERSISTENCE_KEY, PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::logger::{log_error, LdkLogger}; +use crate::logger::{log_error, log_info, LdkLogger}; use crate::types::DynStore; use crate::{Error, SocketAddress}; @@ -43,8 +43,17 @@ where pub(crate) fn add_peer(&self, peer_info: PeerInfo) -> Result<(), Error> { let mut locked_peers = self.peers.write().unwrap(); - if locked_peers.contains_key(&peer_info.node_id) { - return Ok(()); + if let Some(existing) = locked_peers.get(&peer_info.node_id) { + if existing.address == peer_info.address { + return Ok(()); + } + log_info!( + self.logger, + "Updating socket address for peer {}: {} -> {}", + peer_info.node_id, + existing.address, + peer_info.address + ); } locked_peers.insert(peer_info.node_id, peer_info); @@ -194,4 +203,55 @@ mod tests { assert_eq!(peers[0], expected_peer_info); assert_eq!(deser_peer_store.get_peer(&node_id), Some(expected_peer_info)); } + + #[test] + fn peer_address_updated_on_readd() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(TestLogger::new()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let old_address = SocketAddress::from_str("34.65.186.40:9735").unwrap(); + let new_address = SocketAddress::from_str("34.65.153.174:9735").unwrap(); + + peer_store.add_peer(PeerInfo { node_id, address: old_address.clone() }).unwrap(); + assert_eq!(peer_store.get_peer(&node_id).unwrap().address, old_address); + + peer_store.add_peer(PeerInfo { node_id, address: new_address.clone() }).unwrap(); + assert_eq!(peer_store.get_peer(&node_id).unwrap().address, new_address); + + assert_eq!(peer_store.list_peers().len(), 1); + + let persisted_bytes = KVStoreSync::read( + &*store, + PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, + PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, + PEER_INFO_PERSISTENCE_KEY, + ) + .unwrap(); + let deser_peer_store = + PeerStore::read(&mut &persisted_bytes[..], (Arc::clone(&store), logger)).unwrap(); + assert_eq!(deser_peer_store.get_peer(&node_id).unwrap().address, new_address); + } + + #[test] + fn peer_same_address_skips_persist() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(TestLogger::new()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let address = SocketAddress::from_str("127.0.0.1:9738").unwrap(); + + peer_store.add_peer(PeerInfo { node_id, address: address.clone() }).unwrap(); + + peer_store.add_peer(PeerInfo { node_id, address }).unwrap(); + assert_eq!(peer_store.list_peers().len(), 1); + } } diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index abc53d572..21ae14d4f 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -911,6 +911,66 @@ async fn do_connection_restart_behavior(persist: bool) { } } +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn peer_address_persisted_on_connect_failure() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, false, false); + + let node_id_b = node_b.node_id(); + let real_addr_b = node_b.listening_addresses().unwrap().first().unwrap().clone(); + + // Stop node_b so all connection attempts to it will fail. + node_b.stop().unwrap(); + + let fake_addr: lightning::ln::msgs::SocketAddress = "127.0.0.1:19999".parse().unwrap(); + + // Attempt to connect with persist=true to an unreachable address. The connection + // will fail, but the peer address must still be persisted. This is a regression test + // for a bug where add_peer was called AFTER the connection attempt, meaning a failed + // connect would skip persistence entirely. + let res = node_a.connect(node_id_b, fake_addr.clone(), true); + assert!(res.is_err()); + + let peers_a = node_a.list_peers(); + let peer = peers_a + .iter() + .find(|p| p.node_id == node_id_b) + .expect("Peer must be in store even after failed connection when persist=true"); + assert!(peer.is_persisted); + assert!(!peer.is_connected); + assert_eq!(peer.address, fake_addr); + + // Now "update" to the real address (still unreachable since node_b is stopped). + // This verifies the upsert: even though connect fails again, the stored address + // should be updated to the new one. + let res = node_a.connect(node_id_b, real_addr_b.clone(), true); + assert!(res.is_err()); + + let peers_a = node_a.list_peers(); + let peer = peers_a + .iter() + .find(|p| p.node_id == node_id_b) + .expect("Peer must still be in store after second failed connection"); + assert_eq!(peer.address, real_addr_b, "Stored address must be updated to the new one"); + + // Restart node_b and node_a to verify the persisted address survives restart + // and the reconnection loop uses the correct (updated) address. + node_b.start().unwrap(); + node_a.stop().unwrap(); + node_a.start().unwrap(); + + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + + let peers_a = node_a.list_peers(); + let peer = peers_a + .iter() + .find(|p| p.node_id == node_id_b) + .expect("Peer must reconnect after restart using persisted address"); + assert!(peer.is_connected); + assert!(peer.is_persisted); +} + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn concurrent_connections_succeed() { let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd();