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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ All notable changes to this project will be documented in this file.
- Add `solana_l1_rpc_url` to `doublezero-config::NetworkConfig`. Per RFC-20 §Environments: `mainnet-beta` resolves to `https://api.mainnet-beta.solana.com`, `testnet` to `https://api.testnet.solana.com`, `devnet` to `https://api.testnet.solana.com` (intentional asymmetry, see RFC), and `local` to `http://localhost:8899`. A new `DZ_SOLANA_RPC_URL` environment variable overrides the resolved value, mirroring the existing `DZ_LEDGER_RPC_URL` / `DZ_LEDGER_WS_RPC_URL` overrides.
- Add `--solana-url <SOLANA_RPC_URL>` global flag to `doublezero` per RFC-20 §Global flags. Distinct from `--url`, which continues to override the DZ ledger transport; `--solana-url` targets the Solana L1 transport. The flag is parsed and exposed on the binary's `App` struct; per-verb consumption lands when verbs migrate to construct typed Solana L1 clients from `CliContext`.
- Add `--log-verbose` (repeatable) global flag and initialize the `tracing` subscriber at startup. Default level is `warn`; one `--log-verbose` raises to `debug`, two raise to `trace`. Diagnostic logs go to stderr so `--json` output on stdout remains parseable. Honors the `RUST_LOG` environment variable when set, overriding the CLI-flag verbosity for per-module filtering. Replaces the previous `println!("using keypair: ...")` stdout line with a `tracing::info!` event; the keypair confirmation now appears only at `--log-verbose` or higher and no longer pollutes parseable stdout. (Named `--log-verbose` rather than the RFC-20 §Global-flags suggested `--verbose` / `-v` because the existing `doublezero connect` / `disconnect` subcommands already own a `--verbose` flag with `bool` type; the global flag deviation will be revisited when the daemon-control module crate is carved out.)
- Build a `CliContext` once at binary startup from `--env` and the per-field global overrides (`--url`, `--ws`, `--solana-url`, `--keypair`, `--sock-file`), per RFC-20 (§CliContext). The context resolves to `Environment::default()` (`devnet`) when `--env` is absent. `DZClient` continues to consume the legacy `Option<String>` tuple via a thin bridge that forwards `None` when neither `--env` nor a per-field override is set, preserving today's fall-back to `~/.config/solana/cli/config.yml`. Verbs that migrate to the RFC-20 module contract will consume `CliContext` directly and the bridge shrinks.
- Centralize top-level error rendering through `doublezero_cli_core::error::render_eyre`. Replaces three ad-hoc `eprintln!("Error: {e}")` sites in `client/doublezero/src/main.rs` (env-parse failure, env-config resolution failure, top-level command failure) with a single helper that prints `Error: <head>` followed by the full chain of causes on stderr.
- Drop the activator-only pollers from `doublezero` (user and multicastgroup activation waits). The `--wait` flag on `user create`, `user create-subscribe`, `user subscribe`, `multicastgroup create`, and `multicastgroup update` now fetches the post-create state once instead of polling; creates are atomic to `Activated` post-RFC-11, so the wait loop was watching a transition that no longer happens ([#3614](https://github.com/malbeclabs/doublezero/issues/3614))
- `doublezero geolocation` `probe ...` and `user ...` mirrors `doublezero-geolocation` versions; new `--geo-program-id` global flag, `config get/set` include Geolocation Program ID; new `-init-geolocation-config` for init of geolocation program
- cli: `doublezero geolocation` `probe ...` and `user ...` mirrors `doublezero-geolocation` versions; new `--geo-program-id` global flag, `config get/set` include Geolocation Program ID.
Expand Down
69 changes: 46 additions & 23 deletions client/doublezero/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,30 +114,53 @@ async fn main() -> eyre::Result<()> {
tracing::info!(keypair = %keypair.display(), "using keypair");
}

let (url, ws, program_id) = if let Some(env) = app.env {
let config = match env.parse::<Environment>() {
Ok(env) => match env.config() {
Ok(config) => config,
Err(e) => {
eprintln!("Error: {e}");
std::process::exit(1);
}
},
Err(e) => {
eprintln!("Error: {e}");
std::process::exit(1);
}
};
(
Some(config.ledger_public_rpc_url),
Some(config.ledger_public_ws_rpc_url),
Some(config.serviceability_program_id.to_string()),
)
} else {
(app.url, app.ws, app.program_id)
// Resolve global configuration into a CliContext per RFC-20 (§CliContext).
// The binary populates it once at startup; future verbs read from it.
let env_explicit = app.env.is_some();
let env = match app.env.as_deref() {
Some(s) => s.parse::<Environment>().unwrap_or_else(|e| {
doublezero_cli_core::error::render_eyre(&e);
std::process::exit(1);
}),
None => Environment::default(),
};
let mut ctx_builder = doublezero_cli_core::CliContextBuilder::new().with_env(env);
if let Some(u) = app.url.clone() {
ctx_builder = ctx_builder.with_ledger_rpc_url(u);
}
if let Some(w) = app.ws.clone() {
ctx_builder = ctx_builder.with_ledger_ws_rpc_url(w);
}
if let Some(s) = app.solana_url.clone() {
ctx_builder = ctx_builder.with_solana_l1_rpc_url(s);
}
if let Some(k) = app.keypair.clone() {
ctx_builder = ctx_builder.with_keypair_path(k);
}
if let Some(s) = app.sock_file.clone() {
ctx_builder = ctx_builder.with_daemon_socket_path(s);
}
let ctx = ctx_builder.build().unwrap_or_else(|e| {
doublezero_cli_core::error::render_eyre(&e);
std::process::exit(1);
});

// Bridge to the legacy `DZClient::new(Option<String>, ...)` signature.
// When neither `--env` nor a per-field override is set, forward `None`
// so `DZClient` keeps falling back to the user's
// `~/.config/doublezero/cli/config.yml`. As verbs migrate to construct
// typed clients from `CliContext` directly, this bridge shrinks.
//
// `CliContextBuilder::build` derives WS from RPC when only `--url` is
// overridden, so `ctx.ledger_ws_rpc_url` stays consistent with
// `ctx.ledger_rpc_url` on every path that reaches here.
let any_url_explicit = env_explicit || app.url.is_some() || app.ws.is_some();
let url = any_url_explicit.then(|| ctx.ledger_rpc_url.clone());
let ws = any_url_explicit.then(|| ctx.ledger_ws_rpc_url.clone());
let program_id = (env_explicit || app.program_id.is_some())
.then(|| ctx.serviceability_program_id.to_string());

let dzclient = DZClient::new(url.clone(), ws, program_id, app.keypair.clone())?;
let dzclient = DZClient::new(url.clone(), ws, program_id, ctx.keypair_path.clone())?;
let client = CliCommandImpl::new(&dzclient);

let stdout = std::io::stdout();
Expand Down Expand Up @@ -444,7 +467,7 @@ async fn main() -> eyre::Result<()> {
match res {
Ok(_) => {}
Err(e) => {
eprintln!("Error: {e}");
doublezero_cli_core::error::render_eyre(&e);
std::process::exit(1);
}
};
Expand Down
Loading