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
24 changes: 22 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ concurrency:
cancel-in-progress: true

jobs:
rusqlite-compat:
runs-on: self-hosted
timeout-minutes: 30
strategy:
matrix:
# Keep these endpoints in sync with the supported range in Cargo.toml.
rusqlite: ["0.31.0", "0.39.0"]
env:
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
steps:
- uses: actions/checkout@v4
- name: Install MSRV toolchain
run: rustup toolchain install 1.85.0 --profile minimal
- name: Test downstream rusqlite compatibility on MSRV
run: |
export CARGO_TARGET_DIR=$(mktemp -d /tmp/cargo-target-ldk-node-rusqlite-XXXXXX)
trap 'rm -rf "$CARGO_TARGET_DIR"' EXIT
cargo +1.85.0 add --manifest-path tests/rusqlite-compat/Cargo.toml rusqlite@=${{ matrix.rusqlite }}
cargo +1.85.0 test --manifest-path tests/rusqlite-compat/Cargo.toml

build:
defaults:
run:
Expand Down Expand Up @@ -107,8 +127,8 @@ jobs:
- name: Test on Rust ${{ matrix.toolchain }}
if: "matrix.platform != 'windows-latest'"
run: |
RUSTFLAGS="--cfg no_download" cargo test
cargo test
- name: Test with UniFFI support on Rust ${{ matrix.toolchain }}
if: "matrix.platform != 'windows-latest' && matrix.build-uniffi"
run: |
RUSTFLAGS="--cfg no_download" cargo test --features uniffi
cargo test --features uniffi
Comment on lines +130 to +134

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can fix CI by clearing the flags here like this:

diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 04ad5f8e..1ae4ad6d 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -127,8 +127,8 @@ jobs:
       - name: Test on Rust ${{ matrix.toolchain }}
         if: "matrix.platform != 'windows-latest'"
         run: |
-          cargo test
+          RUSTFLAGS="" cargo test
       - name: Test with UniFFI support on Rust ${{ matrix.toolchain }}
         if: "matrix.platform != 'windows-latest' && matrix.build-uniffi"
         run: |
-          cargo test --features uniffi
+          RUSTFLAGS="" cargo test --features uniffi

24 changes: 24 additions & 0 deletions .github/workflows/vss-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,30 @@ jobs:
repository: lightningdevkit/vss-server
path: vss-server

- name: Enable caching for bitcoind
id: cache-bitcoind
uses: actions/cache@v4
with:
path: bin/bitcoind-${{ runner.os }}-${{ runner.arch }}
key: bitcoind-${{ runner.os }}-${{ runner.arch }}
- name: Enable caching for electrs
id: cache-electrs
uses: actions/cache@v4
with:
path: bin/electrs-${{ runner.os }}-${{ runner.arch }}
key: electrs-${{ runner.os }}-${{ runner.arch }}
- name: Download bitcoind/electrs
if: "steps.cache-bitcoind.outputs.cache-hit != 'true' || steps.cache-electrs.outputs.cache-hit != 'true'"
run: |
source ./ldk-node/scripts/download_bitcoind_electrs.sh
mkdir -p bin
mv "$BITCOIND_EXE" bin/bitcoind-${{ runner.os }}-${{ runner.arch }}
mv "$ELECTRS_EXE" bin/electrs-${{ runner.os }}-${{ runner.arch }}
- name: Set bitcoind/electrs environment variables
run: |
echo "BITCOIND_EXE=$( pwd )/bin/bitcoind-${{ runner.os }}-${{ runner.arch }}" >> "$GITHUB_ENV"
echo "ELECTRS_EXE=$( pwd )/bin/electrs-${{ runner.os }}-${{ runner.arch }}" >> "$GITHUB_ENV"

- name: Build and Deploy VSS Server
run: |
version=$(cargo metadata --no-deps --format-version 1 --manifest-path ldk-node/Cargo.toml | jq -r '.packages[] | select(.name == "ldk-node") | .version')
Expand Down
9 changes: 4 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ bdk_wallet = { version = "2.2.0", default-features = false, features = ["std", "

reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
rustls = { version = "0.23", default-features = false }
rusqlite = { version = "0.31.0", features = ["bundled"] }
# rusqlite 0.40.0 and 0.40.1 do not compile on our MSRV.
rusqlite = { version = ">=0.31.0, <0.40.0", features = ["bundled"] }
bitcoin = "0.32.7"
bip39 = { version = "2.0.0", features = ["rand"] }
bip21 = { version = "0.5", features = ["std"], default-features = false }
Expand Down Expand Up @@ -77,10 +78,8 @@ proptest = "1.0.0"
regex = "1.5.6"
criterion = { version = "0.7.0", features = ["async_tokio"] }

[target.'cfg(not(no_download))'.dev-dependencies]
electrsd = { version = "0.36.1", default-features = false, features = ["legacy", "esplora_a33e97e1", "corepc-node_27_2"] }

[target.'cfg(no_download)'.dev-dependencies]
# Test binaries are provided via scripts/download_bitcoind_electrs.sh.
# Keep automatic downloads disabled to avoid the yanked zip dependency.
electrsd = { version = "0.36.1", default-features = false, features = ["legacy"] }
corepc-node = { version = "0.10.0", default-features = false, features = ["27_2"] }

Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ LDK Node itself is written in [Rust][rust] and may therefore be natively added a
## MSRV
The Minimum Supported Rust Version (MSRV) is currently 1.85.0.

## Running Tests

Rust integration tests and benchmarks require Bitcoin Core and Esplora-enabled `electrs` binaries.
On Linux and macOS, run the following from the repository root in Bash:

```bash
source ./scripts/download_bitcoind_electrs.sh
RUSTFLAGS="--cfg tokio_unstable" cargo test
```

The script requires `curl`, `unzip`, `tar`, and `shasum`. It verifies the downloads and exports
`BITCOIND_EXE` and `ELECTRS_EXE` for the current shell. Alternatively, set these variables to
compatible binaries you already have. Cargo's automatic binary downloads are disabled.

[api_docs]: https://docs.rs/ldk-node/*/ldk_node/
[api_docs_node]: https://docs.rs/ldk-node/*/ldk_node/struct.Node.html
[api_docs_builder]: https://docs.rs/ldk-node/*/ldk_node/struct.Builder.html
Expand Down
24 changes: 8 additions & 16 deletions src/io/sqlite_store/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,13 @@ pub(super) fn migrate_schema(
})?;

// Update user_version
tx.pragma(Some(rusqlite::DatabaseName::Main), "user_version", to_version, |_| Ok(()))
.map_err(|e| {
let msg = format!(
"Failed to upgrade user_version from {} to {}: {}",
from_version, to_version, e
);
io::Error::new(io::ErrorKind::Other, msg)
})?;
tx.pragma_update(None, "user_version", to_version).map_err(|e| {
let msg = format!(
"Failed to upgrade user_version from {} to {}: {}",
from_version, to_version, e
);
io::Error::new(io::ErrorKind::Other, msg)
})?;

tx.commit().map_err(|e| {
let msg = format!(
Expand Down Expand Up @@ -104,14 +103,7 @@ mod tests {

let connection = Connection::open(db_file_path.clone()).unwrap();

connection
.pragma(
Some(rusqlite::DatabaseName::Main),
"user_version",
old_schema_version,
|_| Ok(()),
)
.unwrap();
connection.pragma_update(None, "user_version", old_schema_version).unwrap();

let sql = format!(
"CREATE TABLE IF NOT EXISTS {} (
Expand Down
15 changes: 4 additions & 11 deletions src/io/sqlite_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,17 +260,10 @@ impl SqliteStoreInner {

if version_res == 0 {
// New database, set our SCHEMA_USER_VERSION and continue
connection
.pragma(
Some(rusqlite::DatabaseName::Main),
"user_version",
SCHEMA_USER_VERSION,
|_| Ok(()),
)
.map_err(|e| {
let msg = format!("Failed to set PRAGMA user_version: {}", e);
io::Error::new(io::ErrorKind::Other, msg)
})?;
connection.pragma_update(None, "user_version", SCHEMA_USER_VERSION).map_err(|e| {
let msg = format!("Failed to set PRAGMA user_version: {}", e);
io::Error::new(io::ErrorKind::Other, msg)
})?;
} else if version_res < SCHEMA_USER_VERSION {
migrations::migrate_schema(
&mut connection,
Expand Down
10 changes: 3 additions & 7 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,19 +187,15 @@ macro_rules! expect_payment_successful_event {
pub(crate) use expect_payment_successful_event;

pub(crate) fn setup_bitcoind_and_electrsd() -> (BitcoinD, ElectrsD) {
let bitcoind_exe =
env::var("BITCOIND_EXE").ok().or_else(|| corepc_node::downloaded_exe_path().ok()).expect(
"you need to provide an env var BITCOIND_EXE or specify a bitcoind version feature",
);
let bitcoind_exe = env::var("BITCOIND_EXE")
.expect("set BITCOIND_EXE or source ./scripts/download_bitcoind_electrs.sh before testing");
let mut bitcoind_conf = corepc_node::Conf::default();
bitcoind_conf.network = "regtest";
bitcoind_conf.args.push("-rest");
let bitcoind = BitcoinD::with_conf(bitcoind_exe, &bitcoind_conf).unwrap();

let electrs_exe = env::var("ELECTRS_EXE")
.ok()
.or_else(electrsd::downloaded_exe_path)
.expect("you need to provide env var ELECTRS_EXE or specify an electrsd version feature");
.expect("set ELECTRS_EXE or source ./scripts/download_bitcoind_electrs.sh before testing");
let mut electrsd_conf = electrsd::Conf::default();
electrsd_conf.http_enabled = true;
electrsd_conf.network = "regtest";
Expand Down
14 changes: 14 additions & 0 deletions tests/rusqlite-compat/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "ldk-node-rusqlite-compat"
version = "0.0.0"
edition = "2021"
rust-version = "1.85"
publish = false

# Resolve as a downstream application, without LDK Node's legacy test dependencies.
[workspace]

[dependencies]
ldk-node = { path = "../.." }
rusqlite = "=0.39.0"
tokio = { version = "1.39", features = ["macros", "rt"] }
32 changes: 32 additions & 0 deletions tests/rusqlite-compat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Downstream rusqlite compatibility

This separate Cargo workspace checks that an application can select a stock
rusqlite release while using LDK Node's default features. The test writes through
LDK Node, reopens the store, and reads the database with the application's rusqlite.
Neither rusqlite nor libsqlite3-sys is patched.

The root crate's development dependencies on LDK Node 0.6.2 and 0.7.0 require
rusqlite 0.31 unconditionally. They constrain root builds even when individual
tests are filtered out, but do not participate in downstream resolution. Keep
this fixture separate so CI actually tests both ends of the supported range.
Comment on lines +8 to +11

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One nit here:

diff --git a/tests/rusqlite-compat/README.md b/tests/rusqlite-compat/README.md
index c27412e6..3b07c71e 100644
--- a/tests/rusqlite-compat/README.md
+++ b/tests/rusqlite-compat/README.md
@@ -5,9 +5,9 @@ rusqlite release while using LDK Node's default features. The test writes throug
 LDK Node, reopens the store, and reads the database with the application's rusqlite.
 Neither rusqlite nor libsqlite3-sys is patched.

-The root crate's development dependencies on LDK Node 0.6.2 and 0.7.0 require
-rusqlite 0.31 unconditionally. They constrain root builds even when individual
-tests are filtered out, but do not participate in downstream resolution. Keep
+The root crate's development dependency on LDK Node 0.6.2 requires
+rusqlite 0.31 unconditionally. It constrains root builds even when individual
+tests are filtered out, but does not participate in downstream resolution. Keep
 this fixture separate so CI actually tests both ends of the supported range.

 From the repository root, run:


From the repository root, run:

```sh
export CARGO_TARGET_DIR=$(mktemp -d /tmp/cargo-target-ldk-node-rusqlite-XXXXXX)
export CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS=fallback
cargo +1.85.0 test --manifest-path tests/rusqlite-compat/Cargo.toml
```

The fixture defaults to the maximum tested version. To test another release,
change its direct requirement with
`cargo +1.85.0 add --manifest-path tests/rusqlite-compat/Cargo.toml rusqlite@=0.31.0`
and rerun the test. Restore the maximum requirement afterwards. The resolver
setting selects MSRV-compatible versions of unrelated transitive dependencies.

When changing the supported range, update both endpoints in
`.github/workflows/rust.yml` and test each newly included release locally. The
current upper bound excludes 0.40.0 and 0.40.1, which use `cfg_select!` and fail to
compile on Rust 1.85. Although the bundled-feature probe for 0.40.2 passes on
1.85, Cargo cannot express a disjoint requirement that admits it while excluding
those earlier patches and retaining the older release lines.
40 changes: 40 additions & 0 deletions tests/rusqlite-compat/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// This file is Copyright its original authors, visible in version control history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
// accordance with one or both of these licenses.

#[cfg(test)]
mod tests {
use ldk_node::io::sqlite_store::{
SqliteStore, DEFAULT_KV_TABLE_NAME, DEFAULT_SQLITE_DB_FILE_NAME,
};
use ldk_node::lightning::util::persist::KVStore;

#[tokio::test]
async fn persists_with_the_applications_rusqlite() {
let data_dir =
std::env::temp_dir().join(format!("ldk-node-rusqlite-compat-{}", std::process::id()));
let store = SqliteStore::new(data_dir.clone(), None, None).unwrap();
KVStore::write(&store, "test", "", "key", vec![42]).await.unwrap();
drop(store);

let store = SqliteStore::new(data_dir.clone(), None, None).unwrap();
assert_eq!(KVStore::read(&store, "test", "", "key").await.unwrap(), vec![42]);
drop(store);

let connection =
rusqlite::Connection::open(data_dir.join(DEFAULT_SQLITE_DB_FILE_NAME)).unwrap();
let value: Vec<u8> = connection
.query_row(
&format!("SELECT value FROM {DEFAULT_KV_TABLE_NAME} WHERE key = 'key'"),
[],
|row| row.get(0),
)
.unwrap();
assert_eq!(value, vec![42]);
drop(connection);
std::fs::remove_dir_all(data_dir).unwrap();
}
}
Loading