Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 44 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,56 @@ cargo build --profile=release-smaller
```

### Testing

#### Unit tests (no external infrastructure needed)
```bash
cargo test --lib
```

#### Standard integration tests
Uses the `electrsd` crate to auto-download and spawn `bitcoind` + `electrs` binaries.
To use pre-downloaded binaries, set `BITCOIND_EXE` and `ELECTRS_EXE` env vars.

On macOS, the default file descriptor limit (256) is too low for spawning `bitcoind` +
`electrs`. Raise it before running integration tests:

Test files: `tests/integration_tests_rust.rs`, `tests/reorg_test.rs`,
`tests/multi_address_types_tests.rs`

```bash
# Run all tests
cargo test
ulimit -n 10240 && cargo test
```

# Run a specific test
#### Run a specific test
```bash
cargo test test_name
```

# Run tests with specific features
#### Run tests with UniFFI bindings feature
```bash
cargo test --features "uniffi"
```

#### CLN integration tests
Requires Docker and `socat` for RPC socket forwarding.
```bash
docker compose -f docker-compose-cln.yml up -d
RUSTFLAGS="--cfg cln_test" cargo test --test integration_tests_cln
```

# Integration tests with specific backends
cargo test --cfg cln_test # Core Lightning tests
cargo test --cfg lnd_test # LND tests
cargo test --cfg vss_test # VSS (Versioned Storage Service) tests
#### LND integration tests
Requires Docker and CMake (>=3.5, <4.0) for `lnd_grpc_rust`.
Set `LND_DATA_DIR`, `LND_CERT_PATH`, and `LND_MACAROON_PATH` env vars.
```bash
docker compose -f docker-compose-lnd.yml up -d
RUSTFLAGS="--cfg lnd_test" cargo test --test integration_tests_lnd
```

#### VSS integration tests
Requires PostgreSQL and a running VSS server (from `lightningdevkit/vss-server`).
Set `TEST_VSS_BASE_URL` env var.
```bash
RUSTFLAGS="--cfg vss_test" cargo test --test integration_tests_vss
```

### Code Quality
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 0.7.0-rc.32 (Synonym Fork)
# 0.7.0-rc.33 (Synonym Fork)

## Bug Fixes

Expand Down Expand Up @@ -29,6 +29,11 @@

## Synonym Fork Additions

- Fixed channel monitor migration from filesystem store to KV store overwriting newer state.
During FS→KV migration, the code now checks if the KV store already has a channel monitor
with a newer `update_id` before writing, preventing stale migration data from overwriting
current state on repeated migrations or restarts. Errors reading or deserializing existing
monitors now fail-closed (abort migration) to avoid silent data loss.
- Added `OnchainPayment::calculate_send_all_fee()` to preview the fee for a drain / send-all
transaction before broadcasting (fee-calculation counterpart of `send_all_to_address`)
- Added runtime APIs for dynamic address type management:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exclude = ["bindings/uniffi-bindgen"]

[package]
name = "ldk-node"
version = "0.7.0-rc.32"
version = "0.7.0-rc.33"
authors = ["Elias Rohrer <dev@tnull.de>"]
homepage = "https://lightningdevkit.org/"
license = "MIT OR Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import PackageDescription

let tag = "v0.7.0-rc.32"
let checksum = "89d987f390e0f8fae370c6d549aacd8b8e1c3c95fb0d6e9ccfcf216cbd263b38"
let tag = "v0.7.0-rc.33"
let checksum = "235e276d2a39ed41abb4034b027f72bf876b65eb40a2a584cc1d06208ad7a58a"
let url = "https://github.com/synonymdev/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip"

let package = Package(
Expand Down
2 changes: 1 addition & 1 deletion bindings/kotlin/ldk-node-android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ android.useAndroidX=true
android.enableJetifier=true
kotlin.code.style=official
group=com.synonym
version=0.7.0-rc.32
version=0.7.0-rc.33
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion bindings/kotlin/ldk-node-jvm/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx1536m
kotlin.code.style=official
group=com.synonym
version=0.7.0-rc.32
version=0.7.0-rc.33
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion bindings/python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "ldk_node"
version = "0.7.0-rc.32"
version = "0.7.0-rc.33"
authors = [
{ name="Elias Rohrer", email="dev@tnull.de" },
]
Expand Down
99 changes: 82 additions & 17 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use lightning::util::persist::{
};
use lightning::util::ser::{Readable, ReadableArgs};
use lightning::util::sweep::OutputSweeper;
use lightning::{log_info, log_trace};
use lightning::{log_info, log_trace, log_warn};
use lightning_persister::fs_store::FilesystemStore;
use vss_client::headers::{FixedHeaders, LnurlAuthToJwtProvider, VssHeaderProvider};

Expand Down Expand Up @@ -1639,23 +1639,88 @@ fn build_with_store_internal(

let funding_txo = channel_monitor.get_funding_txo();
let monitor_key = format!("{}_{}", funding_txo.txid, funding_txo.index);
log_info!(logger, "Migrating channel monitor: {}", monitor_key);
let migrated_update_id = channel_monitor.get_latest_update_id();
log_info!(
logger,
"Migrating channel monitor: {} (update_id={})",
monitor_key,
migrated_update_id
);

runtime
.block_on(async {
KVStore::write(
&*kv_store,
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
&monitor_key,
monitor_data.clone(),
)
.await
})
.map_err(|e| {
log_error!(logger, "Failed to write channel_monitor {}: {}", monitor_key, e);
BuildError::WriteFailed
})?;
// Check if the store already has a newer monitor to avoid overwriting
// current state with stale migration data.
let should_write = match runtime.block_on(KVStore::read(
&*kv_store,
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
&monitor_key,
)) {
Ok(existing_data) => {
let mut existing_reader = Cursor::new(&existing_data);
match <(BlockHash, ChannelMonitor<InMemorySigner>)>::read(
&mut existing_reader,
(&*keys_manager, &*keys_manager),
) {
Ok((_, existing_monitor)) => {
let existing_update_id = existing_monitor.get_latest_update_id();
if existing_update_id > migrated_update_id {
log_warn!(
logger,
"Skipping migration for monitor {}: existing update_id {} is newer than migrated update_id {}",
monitor_key,
existing_update_id,
migrated_update_id
);
false
} else {
true
}
},
Err(e) => {
log_error!(
logger,
"Failed to deserialize existing monitor {}, refusing migration write to avoid overwriting potentially newer state: {:?}",
monitor_key,
e
);
return Err(BuildError::ReadFailed);
},
}
},
Err(e) if e.kind() == lightning::io::ErrorKind::NotFound => true,
Err(e) => {
log_error!(
logger,
"Failed to read existing monitor {}, refusing migration write to avoid overwriting potentially newer state: {}",
monitor_key,
e
);
return Err(BuildError::ReadFailed);
},
};

if should_write {
runtime
.block_on(async {
KVStore::write(
&*kv_store,
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
&monitor_key,
monitor_data.clone(),
)
.await
})
.map_err(|e| {
log_error!(
logger,
"Failed to write channel_monitor {}: {}",
monitor_key,
e
);
BuildError::WriteFailed
})?;
}
}

log_info!(
Expand Down
Loading