Skip to content

Commit fe2db11

Browse files
authored
Merge pull request #2 from moneydevkit/austin_mdk-672_vss-support
Wire up VSS storage and standalone test harness
2 parents 866f495 + d3239ab commit fe2db11

8 files changed

Lines changed: 240 additions & 51 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
run: nix flake check --print-build-logs
3737

3838
- name: Run integration tests
39-
run: nix build .#integration-test --print-build-logs
39+
run: nix run .#integration-test --print-build-logs
4040

4141
build:
4242
name: Build Static (${{ matrix.arch }})

flake.lock

Lines changed: 18 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
};
1111
crane.url = "github:ipetkov/crane";
1212
nixpkgs-unstable.url = "github:nixos/nixpkgs/e6f23dc08d3624daab7094b701aa3954923c6bbb";
13+
vss-server = {
14+
url = "github:lightningdevkit/vss-server";
15+
flake = false;
16+
};
1317
};
1418

1519
outputs =
@@ -20,6 +24,7 @@
2024
fenix,
2125
crane,
2226
nixpkgs-unstable,
27+
vss-server,
2328
}:
2429
flake-utils.lib.eachDefaultSystem (
2530
system:
@@ -107,6 +112,35 @@
107112
Entrypoint = [ "/bin/mdk-server" ];
108113
};
109114
};
115+
116+
# VSS server (lightningdevkit/vss-server) for integration tests.
117+
# Built with noop_authorizer so no JWT/sig config is needed.
118+
vssSrc = craneLib.cleanCargoSource "${vss-server}/rust";
119+
vssArgs = {
120+
src = vssSrc;
121+
pname = "vss-server";
122+
version = "0.1.0";
123+
strictDeps = true;
124+
nativeBuildInputs = [
125+
pkgs.protobuf
126+
pkgs.pkg-config
127+
pkgs.autoPatchelfHook
128+
];
129+
buildInputs = [
130+
pkgs.openssl
131+
pkgs.stdenv.cc.cc.lib
132+
];
133+
cargoExtraArgs = "--no-default-features";
134+
CARGO_BUILD_RUSTFLAGS = "--cfg noop_authorizer";
135+
};
136+
vssCargoArtifacts = craneLib.buildDepsOnly vssArgs;
137+
vss = craneLib.buildPackage (
138+
vssArgs
139+
// {
140+
cargoArtifacts = vssCargoArtifacts;
141+
doCheck = false;
142+
}
143+
);
110144
in
111145
{
112146
packages = {
@@ -117,13 +151,28 @@
117151
doCheck = false; # Tests run in checks.test
118152
}
119153
);
120-
integration-test = craneLib.cargoNextest (
121-
commonArgs
122-
// {
123-
inherit cargoArtifacts;
124-
cargoNextestExtraArgs = "--test integration";
125-
}
126-
);
154+
# Wrapper script that runs `just integration-test` with all
155+
# dependencies available. Intended for CI (`nix run .#integration-test`).
156+
integration-test = pkgs.writeShellApplication {
157+
name = "integration-test";
158+
runtimeInputs = [
159+
buildToolchain
160+
pkgs.cargo-nextest
161+
pkgs.just
162+
pkgs.postgresql_16
163+
pkgs.curl
164+
pkgs.protobuf
165+
pkgsUnstable.bitcoind
166+
vss
167+
];
168+
text = ''
169+
export BITCOIND_EXE="${pkgsUnstable.bitcoind}/bin/bitcoind"
170+
export VSS_EXE="${vss}/bin/vss-server"
171+
export NIX_SYSTEM="${system}"
172+
just integration-test "$@"
173+
'';
174+
};
175+
inherit vss;
127176
}
128177
// lib.optionalAttrs isLinux {
129178
static = staticBin;
@@ -161,10 +210,12 @@
161210
jq
162211
unixtools.xxd
163212
microsocks
213+
postgresql_16
164214
];
165215

166216
env = {
167217
BITCOIND_EXE = "${pkgsUnstable.bitcoind}/bin/bitcoind";
218+
VSS_EXE = "${vss}/bin/vss-server";
168219
NIX_SYSTEM = system;
169220
};
170221

justfile

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,80 @@ clippy:
2323
unit-test:
2424
nix build .#checks.{{system}}.test
2525

26-
# Run integration tests
26+
# Run integration tests (starts ephemeral PostgreSQL + VSS, tears down after)
2727
integration-test *args:
28-
cargo nextest run --test integration {{args}}
28+
#!/usr/bin/env bash
29+
set -euo pipefail
30+
31+
: "${VSS_EXE:?VSS_EXE not set (use nix develop)}"
32+
33+
# -- Ephemeral PostgreSQL -----------------------------------------------
34+
pg_dir=$(mktemp -d)
35+
pg_port=$(shuf -i 10000-60000 -n 1)
36+
pg_log="$pg_dir/pg.log"
37+
38+
cleanup() {
39+
echo "==> Tearing down..."
40+
[ -n "${VSS_PID:-}" ] && kill "$VSS_PID" 2>/dev/null && wait "$VSS_PID" 2>/dev/null || true
41+
pg_ctl -D "$pg_dir/data" -m immediate stop 2>/dev/null || true
42+
rm -rf "$pg_dir"
43+
}
44+
trap cleanup EXIT
45+
46+
echo "==> Starting ephemeral PostgreSQL on port $pg_port..."
47+
initdb -D "$pg_dir/data" --no-locale --encoding=UTF8 -A trust >/dev/null
48+
pg_ctl -D "$pg_dir/data" -l "$pg_log" -o "-p $pg_port -k $pg_dir -h 127.0.0.1" start >/dev/null
49+
for i in $(seq 1 30); do
50+
pg_isready -h 127.0.0.1 -p "$pg_port" -q && break
51+
sleep 0.1
52+
done
53+
54+
# -- Start VSS ----------------------------------------------------------
55+
vss_port=$(shuf -i 10000-60000 -n 1)
56+
vss_config="$pg_dir/vss-config.toml"
57+
cat > "$vss_config" << TOML
58+
[server_config]
59+
bind_address = "127.0.0.1:$vss_port"
60+
61+
[postgresql_config]
62+
username = "$USER"
63+
password = ""
64+
address = "127.0.0.1:$pg_port"
65+
default_database = "postgres"
66+
vss_database = "vss_test"
67+
TOML
68+
69+
vss_log="$pg_dir/vss.log"
70+
echo "==> Starting VSS on port $vss_port..."
71+
"$VSS_EXE" "$vss_config" >"$vss_log" 2>&1 &
72+
VSS_PID=$!
73+
74+
for i in $(seq 1 30); do
75+
# VSS has no health endpoint; probe putObjects (returns 400 on empty body = alive)
76+
code=$(curl -sf -o /dev/null -w '%{http_code}' -X POST "http://127.0.0.1:$vss_port/vss/putObjects" 2>/dev/null || true)
77+
[ "$code" = "400" ] && break
78+
sleep 0.2
79+
done
80+
echo "==> VSS ready at http://127.0.0.1:$vss_port/vss"
81+
82+
# -- Run tests ----------------------------------------------------------
83+
if MDK_VSS_URL="http://127.0.0.1:$vss_port/vss" \
84+
cargo nextest run --test integration {{args}}; then
85+
:
86+
else
87+
echo ""
88+
echo "==> VSS server log (on failure):"
89+
# cat "$vss_log" skip this for now
90+
exit 1
91+
fi
2992

3093
# Auto-fix lint issues
3194
fix:
3295
cargo clippy --all-targets --fix --allow-dirty --allow-staged
3396

34-
# Run tests (cargo, all)
97+
# Run tests (unit + doc; use `just integration-test` for integration tests)
3598
test *args:
36-
cargo nextest run {{args}}
99+
cargo nextest run --bin mdk-server {{args}}
37100

38101
# Run the server
39102
run *args:
@@ -517,6 +580,7 @@ dev-config:
517580
MDK_LSP_NODE_ID=${n1_pubkey}
518581
MDK_LSP_ADDRESS=127.0.0.1:${n1_p2p}
519582
MDK_API_BASE_URL=${MDK_API_BASE_URL:-http://localhost:3900/rpc}
583+
MDK_VSS_URL=${MDK_VSS_URL:-http://localhost:9999/vss}
520584
MDK_WEBHOOK_SECRET=${MDK_WEBHOOK_SECRET:-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}
521585
MDK_HTTP_PASSWORD_FULL=${MDK_HTTP_PASSWORD_FULL:-dev_full_password}
522586
MDK_HTTP_PASSWORD_READ_ONLY=${MDK_HTTP_PASSWORD_READ_ONLY:-dev_readonly_password}

src/config.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ pub struct LspInfra {
145145
pub lsp_node_id: &'static str,
146146
pub lsp_address: &'static str,
147147
pub mdk_api_base_url: &'static str,
148+
pub vss_url: &'static str,
148149
}
149150

150151
impl LspInfra {
@@ -155,12 +156,14 @@ impl LspInfra {
155156
lsp_node_id: "02a63339cc6b913b6330bd61b2f469af8785a6011a6305bb102298a8e76697473b",
156157
lsp_address: "lsp.moneydevkit.com:9735",
157158
mdk_api_base_url: "https://moneydevkit.com/rpc",
159+
vss_url: "https://vss.moneydevkit.com/vss",
158160
}),
159161
Network::Signet => Some(LspInfra {
160162
chain_source: ChainSource::Esplora("https://mutinynet.com/api"),
161163
lsp_node_id: "03fd9a377576df94cc7e458471c43c400630655083dee89df66c6ad38d1b7acffd",
162164
lsp_address: "lsp.staging.moneydevkit.com:9735",
163165
mdk_api_base_url: "https://staging.moneydevkit.com/rpc",
166+
vss_url: "https://vss.staging.moneydevkit.com/vss",
164167
}),
165168
_ => None,
166169
}
@@ -184,6 +187,7 @@ pub enum NetworkInfra {
184187
lsp_node_id: String,
185188
lsp_address: String,
186189
mdk_api_base_url: String,
190+
vss_url: String,
187191
},
188192
}
189193

@@ -209,6 +213,7 @@ impl NetworkInfra {
209213
lsp_node_id: env_required("MDK_LSP_NODE_ID")?,
210214
lsp_address: env_required("MDK_LSP_ADDRESS")?,
211215
mdk_api_base_url: env_required("MDK_API_BASE_URL")?,
216+
vss_url: env_required("MDK_VSS_URL")?,
212217
})
213218
}
214219
}
@@ -223,26 +228,33 @@ impl NetworkInfra {
223228

224229
pub fn lsp_node_id(&self) -> &str {
225230
match self {
226-
NetworkInfra::Production(i) => i.lsp_node_id,
231+
NetworkInfra::Production(lsp_infra) => lsp_infra.lsp_node_id,
227232
NetworkInfra::Regtest { lsp_node_id, .. } => lsp_node_id,
228233
}
229234
}
230235

231236
pub fn lsp_address(&self) -> &str {
232237
match self {
233-
NetworkInfra::Production(i) => i.lsp_address,
238+
NetworkInfra::Production(lsp_infra) => lsp_infra.lsp_address,
234239
NetworkInfra::Regtest { lsp_address, .. } => lsp_address,
235240
}
236241
}
237242

238243
pub fn mdk_api_base_url(&self) -> &str {
239244
match self {
240-
NetworkInfra::Production(i) => i.mdk_api_base_url,
245+
NetworkInfra::Production(lsp_infra) => lsp_infra.mdk_api_base_url,
241246
NetworkInfra::Regtest {
242247
mdk_api_base_url, ..
243248
} => mdk_api_base_url,
244249
}
245250
}
251+
252+
pub fn vss_url(&self) -> &str {
253+
match self {
254+
NetworkInfra::Production(lsp_infra) => lsp_infra.vss_url,
255+
NetworkInfra::Regtest { vss_url, .. } => vss_url,
256+
}
257+
}
246258
}
247259

248260
fn env_required(name: &str) -> io::Result<String> {

src/main.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod time;
1010
mod types;
1111
mod webhook;
1212

13+
use std::collections::HashMap;
1314
use std::net::ToSocketAddrs;
1415
use std::path::PathBuf;
1516
use std::str::FromStr;
@@ -18,6 +19,8 @@ use std::sync::Arc;
1819
use clap::Parser;
1920
use hex::FromHex;
2021
use ldk_node::bip39::Mnemonic;
22+
use ldk_node::bitcoin::hashes::sha256;
23+
use ldk_node::bitcoin::hashes::Hash;
2124
use ldk_node::bitcoin::secp256k1::PublicKey;
2225
use ldk_node::config::Config as LdkNodeConfig;
2326
use ldk_node::lightning::ln::msgs::SocketAddress;
@@ -113,6 +116,13 @@ fn main() {
113116
};
114117

115118
let network_dir: PathBuf = storage_dir.join(format!("{}", config_file.network));
119+
if let Err(e) = std::fs::create_dir_all(&network_dir) {
120+
eprintln!(
121+
"Failed to create data directory {}: {e}",
122+
network_dir.display()
123+
);
124+
std::process::exit(1);
125+
}
116126

117127
logger::init(config_file.log_level);
118128

@@ -213,18 +223,28 @@ fn main() {
213223
error!("Invalid MDK_MNEMONIC: {e}");
214224
std::process::exit(1);
215225
});
216-
builder.set_entropy_bip39_mnemonic(mnemonic, None);
217-
info!("Wallet seed derived from MDK_MNEMONIC");
218-
219-
let node = match builder.build() {
226+
builder.set_entropy_bip39_mnemonic(mnemonic.clone(), None);
227+
228+
let store_id = derive_vss_identifier(&mnemonic);
229+
info!(
230+
"VSS store: {} (store_id={}...)",
231+
infra.vss_url(),
232+
&store_id[..16]
233+
);
234+
235+
let node = match builder.build_with_vss_store_and_fixed_headers(
236+
infra.vss_url().to_string(),
237+
store_id,
238+
HashMap::new(),
239+
) {
220240
Ok(node) => Arc::new(node),
221241
Err(e) => {
222242
error!("Failed to build LDK Node: {e}");
223243
std::process::exit(1);
224244
}
225245
};
226246

227-
let db_path = network_dir.join("ldk_server_data.sqlite");
247+
let db_path = network_dir.join("mdkd.sqlite");
228248
let metadata_store = match InvoiceMetadataStore::new(&db_path) {
229249
Ok(store) => Arc::new(store),
230250
Err(e) => {
@@ -359,3 +379,8 @@ fn main() {
359379
node.stop().expect("Shutdown should always succeed.");
360380
info!("Shutdown complete.");
361381
}
382+
383+
fn derive_vss_identifier(mnemonic: &Mnemonic) -> String {
384+
let mnemonic_phrase = mnemonic.to_string();
385+
sha256::Hash::hash(mnemonic_phrase.as_bytes()).to_string()
386+
}

0 commit comments

Comments
 (0)