Skip to content

Commit 3a3cd88

Browse files
authored
Mintd lib (#914)
* feat(cdk-integration-tests): refactor regtest setup and mintd integration - Replace shell-based regtest setup with Rust binary (start_regtest_mints) - Add cdk-mintd crate to workspace and integration tests - Improve environment variable handling for test configurations - Update integration tests to use proper temp directory management - Remove deprecated start_regtest.rs binary - Enhance CLN client connection with retry logic - Simplify regtest shell script (itests.sh) to use new binary - Fix tracing filters and improve error handling in setup - Update dependencies and configurations for integration tests fix: killing chore: comment tests for ci debugging chore: compile Revert "chore: comment tests for ci debugging" This reverts commit bfc594c. * chore: sql cipher * fix: removal of sqlite cipher * fix: auth password * refactor(cdk-mintd): improve database password handling and function signatures - Pass database password as parameter instead of parsing CLI args in setup_database - Update function signatures for run_mintd and run_mintd_with_shutdown to accept db_password - Remove direct CLI parsing from database setup logic - Fix auth database initialization to use correct type when sqlcipher feature enabled
1 parent 9e4b768 commit 3a3cd88

33 files changed

Lines changed: 2469 additions & 1210 deletions

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
- cashu: NUT-19 support in the wallet ([crodas]).
1515
- cdk: SIG_ALL support for swap and melt operations ([thesimplekid]).
1616
- cdk-sql-common: Add cache to SQL statements for better performance ([crodas]).
17+
- cdk-integration-tests: New binary `start_fake_auth_mint` for testing fake mint with authentication ([thesimplekid]).
18+
- cdk-integration-tests: New binary `start_fake_mint` for testing fake mint instances ([thesimplekid]).
19+
- cdk-integration-tests: New binary `start_regtest_mints` for testing regtest mints ([thesimplekid]).
20+
- cdk-integration-tests: Shared utilities module for common integration test functionality ([thesimplekid]).
1721

1822
### Changed
1923
- cdk: Refactored wallet keyset management methods for better clarity and separation of concerns ([thesimplekid]).
@@ -28,6 +32,12 @@
2832
- cdk-integration-tests: Updated test utilities to use new mint lifecycle management ([thesimplekid]).
2933
- cdk-sqlite: Introduce `cdk-sql-common` crate for shared SQL storage codebase ([crodas]).
3034
- cdk-sqlite: Rename `still_active` to `stale` for better clarity ([crodas]).
35+
- cdk-integration-tests: Refactored regtest setup to use Rust binaries instead of shell scripts ([thesimplekid]).
36+
- cdk-integration-tests: Improved environment variable handling for test configurations ([thesimplekid]).
37+
- cdk-integration-tests: Enhanced CLN client connection with retry logic ([thesimplekid]).
38+
- cdk-integration-tests: Updated integration tests to use proper temp directory management ([thesimplekid]).
39+
- cdk-integration-tests: Simplified regtest shell scripts to use new binaries ([thesimplekid]).
40+
- crates/cdk-mintd: Moved mintd library functions to separate module for better organization and testability ([thesimplekid]).
3141

3242
### Fixed
3343
- cashu: Fixed CurrencyUnit custom units preserving original case instead of being converted to uppercase ([thesimplekid]).

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ cdk-redb = { path = "./crates/cdk-redb", default-features = true, version = "=0.
5757
cdk-sql-common = { path = "./crates/cdk-sql-common", default-features = true, version = "=0.11.0" }
5858
cdk-sqlite = { path = "./crates/cdk-sqlite", default-features = true, version = "=0.11.0" }
5959
cdk-signatory = { path = "./crates/cdk-signatory", version = "=0.11.0", default-features = false }
60+
cdk-mintd = { path = "./crates/cdk-mintd", version = "=0.11.0", default-features = false }
6061
clap = { version = "4.5.31", features = ["derive"] }
6162
ciborium = { version = "0.2.2", default-features = false, features = ["std"] }
6263
cbor-diag = "0.1.12"

crates/cdk-integration-tests/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ cashu = { workspace = true, features = ["mint", "wallet"] }
2323
cdk = { workspace = true, features = ["mint", "wallet", "auth"] }
2424
cdk-cln = { workspace = true }
2525
cdk-lnd = { workspace = true }
26-
cdk-axum = { workspace = true }
26+
cdk-axum = { workspace = true, features = ["auth"] }
2727
cdk-sqlite = { workspace = true }
2828
cdk-redb = { workspace = true }
2929
cdk-fake-wallet = { workspace = true }
30+
cdk-common = { workspace = true, features = ["mint", "wallet", "auth"] }
31+
cdk-mintd = { workspace = true, features = ["cln", "lnd", "fakewallet", "grpc-processor", "auth", "lnbits", "management-rpc"] }
3032
futures = { workspace = true, default-features = false, features = [
3133
"executor",
3234
] }
@@ -44,6 +46,7 @@ tower-http = { workspace = true, features = ["cors"] }
4446
tower-service = "0.3.3"
4547
reqwest.workspace = true
4648
bitcoin = "0.32.0"
49+
clap = { workspace = true, features = ["derive"] }
4750

4851
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
4952
tokio.workspace = true
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
//! Binary for starting a fake mint with authentication for testing
2+
//!
3+
//! This binary provides a programmatic way to start a fake mint instance with authentication for testing purposes:
4+
//! 1. Sets up a fake mint instance with authentication using the cdk-mintd library
5+
//! 2. Configures OpenID Connect authentication settings
6+
//! 3. Waits for the mint to be ready and responsive
7+
//! 4. Keeps it running until interrupted (Ctrl+C)
8+
//! 5. Gracefully shuts down on receiving shutdown signal
9+
//!
10+
//! This approach offers better control and integration compared to external scripts,
11+
//! making it easier to run authentication integration tests with consistent configuration.
12+
13+
use std::path::Path;
14+
use std::sync::Arc;
15+
16+
use anyhow::Result;
17+
use bip39::Mnemonic;
18+
use cdk_integration_tests::cli::CommonArgs;
19+
use cdk_integration_tests::shared;
20+
use clap::Parser;
21+
use tokio::sync::Notify;
22+
23+
#[derive(Parser)]
24+
#[command(name = "start-fake-auth-mint")]
25+
#[command(about = "Start a fake mint with authentication for testing", long_about = None)]
26+
struct Args {
27+
#[command(flatten)]
28+
common: CommonArgs,
29+
30+
/// Database type (sqlite)
31+
database_type: String,
32+
33+
/// Working directory path
34+
work_dir: String,
35+
36+
/// OpenID discovery URL
37+
openid_discovery: String,
38+
39+
/// Port to listen on (default: 8087)
40+
#[arg(default_value_t = 8087)]
41+
port: u16,
42+
}
43+
44+
/// Start a fake mint with authentication using the library
45+
async fn start_fake_auth_mint(
46+
temp_dir: &Path,
47+
port: u16,
48+
openid_discovery: String,
49+
shutdown: Arc<Notify>,
50+
) -> Result<tokio::task::JoinHandle<()>> {
51+
println!("Starting fake auth mintd on port {port}");
52+
53+
// Create settings struct for fake mint with auth using shared function
54+
let fake_wallet_config = cdk_mintd::config::FakeWallet {
55+
supported_units: vec![cdk::nuts::CurrencyUnit::Sat, cdk::nuts::CurrencyUnit::Usd],
56+
fee_percent: 0.0,
57+
reserve_fee_min: cdk::Amount::from(1),
58+
min_delay_time: 1,
59+
max_delay_time: 3,
60+
};
61+
62+
let mut settings = shared::create_fake_wallet_settings(
63+
port,
64+
Some(Mnemonic::generate(12)?.to_string()),
65+
None,
66+
Some(fake_wallet_config),
67+
);
68+
69+
// Enable authentication
70+
settings.auth = Some(cdk_mintd::config::Auth {
71+
openid_discovery,
72+
openid_client_id: "cashu-client".to_string(),
73+
mint_max_bat: 50,
74+
enabled_mint: true,
75+
enabled_melt: true,
76+
enabled_swap: true,
77+
enabled_check_mint_quote: true,
78+
enabled_check_melt_quote: true,
79+
enabled_restore: true,
80+
enabled_check_proof_state: true,
81+
});
82+
83+
// Set description for the mint
84+
settings.mint_info.description = "fake test mint with auth".to_string();
85+
86+
let temp_dir = temp_dir.to_path_buf();
87+
let shutdown_clone = shutdown.clone();
88+
89+
// Run the mint in a separate task
90+
let handle = tokio::spawn(async move {
91+
// Create a future that resolves when the shutdown signal is received
92+
let shutdown_future = async move {
93+
shutdown_clone.notified().await;
94+
println!("Fake auth mint shutdown signal received");
95+
};
96+
97+
match cdk_mintd::run_mintd_with_shutdown(&temp_dir, &settings, shutdown_future, None).await
98+
{
99+
Ok(_) => println!("Fake auth mint exited normally"),
100+
Err(e) => eprintln!("Fake auth mint exited with error: {e}"),
101+
}
102+
});
103+
104+
Ok(handle)
105+
}
106+
107+
#[tokio::main]
108+
async fn main() -> Result<()> {
109+
let args = Args::parse();
110+
111+
// Initialize logging based on CLI arguments
112+
shared::setup_logging(&args.common);
113+
114+
let temp_dir = shared::init_working_directory(&args.work_dir)?;
115+
116+
// Start fake auth mint
117+
let shutdown = shared::create_shutdown_handler();
118+
let shutdown_clone = shutdown.clone();
119+
120+
let handle = start_fake_auth_mint(
121+
&temp_dir,
122+
args.port,
123+
args.openid_discovery.clone(),
124+
shutdown_clone,
125+
)
126+
.await?;
127+
128+
// Wait for fake auth mint to be ready
129+
if let Err(e) = shared::wait_for_mint_ready(args.port, 100).await {
130+
eprintln!("Error waiting for fake auth mint: {e}");
131+
return Err(e);
132+
}
133+
134+
println!("Fake auth mint started successfully!");
135+
println!("Fake auth mint: http://127.0.0.1:{}", args.port);
136+
println!("Temp directory: {temp_dir:?}");
137+
println!("Database type: {}", args.database_type);
138+
println!("OpenID Discovery: {}", args.openid_discovery);
139+
println!();
140+
println!("Environment variables needed for tests:");
141+
println!(" CDK_TEST_OIDC_USER=<username>");
142+
println!(" CDK_TEST_OIDC_PASSWORD=<password>");
143+
println!();
144+
println!("You can now run auth integration tests with:");
145+
println!(" cargo test -p cdk-integration-tests --test fake_auth");
146+
println!();
147+
148+
println!("Press Ctrl+C to stop the mint...");
149+
150+
// Wait for Ctrl+C signal
151+
shared::wait_for_shutdown_signal(shutdown).await;
152+
153+
println!("\nReceived Ctrl+C, shutting down mint...");
154+
155+
// Wait for mint to finish gracefully
156+
if let Err(e) = handle.await {
157+
eprintln!("Error waiting for mint to shut down: {e}");
158+
}
159+
160+
println!("Mint shut down successfully");
161+
162+
Ok(())
163+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
//! Binary for starting a fake mint for testing
2+
//!
3+
//! This binary provides a programmatic way to start a fake mint instance for testing purposes:
4+
//! 1. Sets up a fake mint instance using the cdk-mintd library
5+
//! 2. Configures the mint with fake wallet backend for testing Lightning Network interactions
6+
//! 3. Waits for the mint to be ready and responsive
7+
//! 4. Keeps it running until interrupted (Ctrl+C)
8+
//! 5. Gracefully shuts down on receiving shutdown signal
9+
//!
10+
//! This approach offers better control and integration compared to external scripts,
11+
//! making it easier to run integration tests with consistent configuration.
12+
13+
use std::path::Path;
14+
use std::sync::Arc;
15+
16+
use anyhow::Result;
17+
use cdk::nuts::CurrencyUnit;
18+
use cdk_integration_tests::cli::CommonArgs;
19+
use cdk_integration_tests::shared;
20+
use clap::Parser;
21+
use tokio::sync::Notify;
22+
23+
#[derive(Parser)]
24+
#[command(name = "start-fake-mint")]
25+
#[command(about = "Start a fake mint for testing", long_about = None)]
26+
struct Args {
27+
#[command(flatten)]
28+
common: CommonArgs,
29+
30+
/// Database type (sqlite)
31+
database_type: String,
32+
33+
/// Working directory path
34+
work_dir: String,
35+
36+
/// Port to listen on (default: 8086)
37+
#[arg(default_value_t = 8086)]
38+
port: u16,
39+
40+
/// Use external signatory
41+
#[arg(long, default_value_t = false)]
42+
external_signatory: bool,
43+
}
44+
45+
/// Start a fake mint using the library
46+
async fn start_fake_mint(
47+
temp_dir: &Path,
48+
port: u16,
49+
shutdown: Arc<Notify>,
50+
external_signatory: bool,
51+
) -> Result<tokio::task::JoinHandle<()>> {
52+
let signatory_config = if external_signatory {
53+
println!("Configuring external signatory");
54+
Some((
55+
"https://127.0.0.1:15060".to_string(), // Default signatory URL
56+
temp_dir.to_string_lossy().to_string(), // Certs directory as string
57+
))
58+
} else {
59+
None
60+
};
61+
62+
let mnemonic = if external_signatory {
63+
None
64+
} else {
65+
Some(
66+
"eye survey guilt napkin crystal cup whisper salt luggage manage unveil loyal"
67+
.to_string(),
68+
)
69+
};
70+
71+
let fake_wallet_config = Some(cdk_mintd::config::FakeWallet {
72+
supported_units: vec![CurrencyUnit::Sat, CurrencyUnit::Usd],
73+
fee_percent: 0.0,
74+
reserve_fee_min: 1.into(),
75+
min_delay_time: 1,
76+
max_delay_time: 3,
77+
});
78+
79+
// Create settings struct for fake mint using shared function
80+
let settings =
81+
shared::create_fake_wallet_settings(port, mnemonic, signatory_config, fake_wallet_config);
82+
83+
println!("Starting fake mintd on port {port}");
84+
85+
let temp_dir = temp_dir.to_path_buf();
86+
let shutdown_clone = shutdown.clone();
87+
88+
// Run the mint in a separate task
89+
let handle = tokio::spawn(async move {
90+
// Create a future that resolves when the shutdown signal is received
91+
let shutdown_future = async move {
92+
shutdown_clone.notified().await;
93+
println!("Fake mint shutdown signal received");
94+
};
95+
96+
match cdk_mintd::run_mintd_with_shutdown(&temp_dir, &settings, shutdown_future, None).await
97+
{
98+
Ok(_) => println!("Fake mint exited normally"),
99+
Err(e) => eprintln!("Fake mint exited with error: {e}"),
100+
}
101+
});
102+
103+
Ok(handle)
104+
}
105+
106+
#[tokio::main]
107+
async fn main() -> Result<()> {
108+
let args = Args::parse();
109+
110+
// Initialize logging based on CLI arguments
111+
shared::setup_logging(&args.common);
112+
113+
let temp_dir = shared::init_working_directory(&args.work_dir)?;
114+
115+
// Write environment variables to a .env file in the temp_dir BEFORE starting the mint
116+
let mint_url = format!("http://127.0.0.1:{}", args.port);
117+
let itests_dir = temp_dir.display().to_string();
118+
let env_vars: Vec<(&str, &str)> = vec![
119+
("CDK_TEST_MINT_URL", &mint_url),
120+
("CDK_ITESTS_DIR", &itests_dir),
121+
];
122+
123+
shared::write_env_file(&temp_dir, &env_vars)?;
124+
125+
// Start fake mint
126+
let shutdown = shared::create_shutdown_handler();
127+
let shutdown_clone = shutdown.clone();
128+
129+
let handle = start_fake_mint(
130+
&temp_dir,
131+
args.port,
132+
shutdown_clone,
133+
args.external_signatory,
134+
)
135+
.await?;
136+
137+
// Wait for fake mint to be ready
138+
if let Err(e) = shared::wait_for_mint_ready(args.port, 100).await {
139+
eprintln!("Error waiting for fake mint: {e}");
140+
return Err(e);
141+
}
142+
143+
shared::display_mint_info(args.port, &temp_dir, &args.database_type);
144+
145+
println!();
146+
println!(
147+
"Environment variables written to: {}/.env",
148+
temp_dir.display()
149+
);
150+
println!("You can source these variables with:");
151+
println!(" source {}/.env", temp_dir.display());
152+
println!();
153+
println!("Environment variables set:");
154+
println!(" CDK_TEST_MINT_URL=http://127.0.0.1:{}", args.port);
155+
println!(" CDK_ITESTS_DIR={}", temp_dir.display());
156+
println!();
157+
println!("You can now run integration tests with:");
158+
println!(" cargo test -p cdk-integration-tests --test fake_wallet");
159+
println!(" cargo test -p cdk-integration-tests --test happy_path_mint_wallet");
160+
println!(" etc.");
161+
println!();
162+
163+
println!("Press Ctrl+C to stop the mint...");
164+
165+
// Wait for Ctrl+C signal
166+
shared::wait_for_shutdown_signal(shutdown).await;
167+
168+
println!("\nReceived Ctrl+C, shutting down mint...");
169+
170+
// Wait for mint to finish gracefully
171+
if let Err(e) = handle.await {
172+
eprintln!("Error waiting for mint to shut down: {e}");
173+
}
174+
175+
println!("Mint shut down successfully");
176+
177+
Ok(())
178+
}

0 commit comments

Comments
 (0)