Skip to content
Merged
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: 0 additions & 2 deletions client_prover/psy_cli/psy_user_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ fn command_paths(cli: &Cli) -> Vec<&str> {
Commands::GetLatestBlockState(args) => paths.push(&args.rpc_config),
Commands::GetBlockState(args) => paths.push(&args.rpc_config),
Commands::LocalProver(args) => paths.push(&args.rpc_config),
#[cfg(feature = "gnark-wrap")]
Commands::ProveProxy(args) => paths.push(&args.rpc_config),
Commands::FaucetServer(args) => paths.push(&args.rpc_config),
Commands::GetClaimAmount(args) => paths.push(&args.rpc_config),
Expand Down Expand Up @@ -666,7 +665,6 @@ async fn main() -> anyhow::Result<()> {
psy_prover::run_server(prover_args).await?;
CommandResult::generic("local-prover")
}
#[cfg(feature = "gnark-wrap")]
Commands::ProveProxy(prove_proxy_args) => {
crate::subcommand::prove_proxy::run(prove_proxy_args).await?;
CommandResult::generic("prove-proxy")
Expand Down
2 changes: 0 additions & 2 deletions client_prover/psy_cli/psy_user_cli/src/subcommand/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ pub mod contract_abi_upload;
pub mod deploy_contract;
pub mod faucet_server;
pub mod local_prover;
#[cfg(feature = "gnark-wrap")]
pub mod prove_proxy;
pub mod simulate;
pub mod update_contract;
Expand Down Expand Up @@ -110,7 +109,6 @@ pub enum Commands {

// local proving
LocalProver(ProverArgs),
#[cfg(feature = "gnark-wrap")]
ProveProxy(psy_client_common::args::ProveProxyArgs),
FaucetServer(PsyFaucetServerArgs),

Expand Down
69 changes: 69 additions & 0 deletions client_prover/psy_core/psy_common/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,45 @@ pub struct ProverArgs {
pub api_key: String,
}

/// Which proof families a prove-proxy instance serves.
///
/// `user` — wallet proofs: UPS session chain, contract calls, signatures, minifiers.
/// `system` — relayer proofs: the three bridge Groth16 methods.
/// `all` — both; intended for single-machine local testnets.
#[derive(Clone, Copy, Debug, PartialEq, Eq, ValueEnum)]
pub enum ProveProxyRole {
User,
System,
All,
}

impl ProveProxyRole {
pub fn serves_user(&self) -> bool {
matches!(self, ProveProxyRole::User | ProveProxyRole::All)
}

pub fn serves_system(&self) -> bool {
matches!(self, ProveProxyRole::System | ProveProxyRole::All)
}

pub fn as_str(&self) -> &'static str {
match self {
ProveProxyRole::User => "user",
ProveProxyRole::System => "system",
ProveProxyRole::All => "all",
}
}
}

#[derive(Clone, Debug, Parser)]
pub struct ProveProxyArgs {
#[clap(env = "PROVE_PROXY_LISTEN_ADDR", long, default_value = "0.0.0.0:9999")]
pub listen_addr: String,
#[clap(env, long, default_value = "config.json", env)]
pub rpc_config: String,
/// Proof families this instance serves. Defaults to user proofs only.
#[clap(env = "PROVE_PROXY_ROLE", long, value_enum, default_value_t = ProveProxyRole::User, ignore_case = true)]
pub role: ProveProxyRole,
}

#[derive(Clone, Debug, Parser)]
Expand Down Expand Up @@ -258,3 +291,39 @@ pub struct ExportKeyStoreArgs {
#[clap(long, env = "WALLET_PASSWORD")]
pub wallet_password: String,
}

#[cfg(test)]
mod prove_proxy_role_tests {
use super::*;
use clap::Parser;

#[test]
fn role_defaults_to_user() {
let args = ProveProxyArgs::try_parse_from(["prove-proxy"]).unwrap();
assert_eq!(args.role, ProveProxyRole::User);
assert!(args.role.serves_user());
assert!(!args.role.serves_system());
}

#[test]
fn role_parses_case_insensitively() {
let args = ProveProxyArgs::try_parse_from(["prove-proxy", "--role", "SYSTEM"]).unwrap();
assert_eq!(args.role, ProveProxyRole::System);
assert!(!args.role.serves_user());
assert!(args.role.serves_system());
}

#[test]
fn role_all_serves_both() {
let args = ProveProxyArgs::try_parse_from(["prove-proxy", "--role", "all"]).unwrap();
assert_eq!(args.role, ProveProxyRole::All);
assert!(args.role.serves_user());
assert!(args.role.serves_system());
assert_eq!(args.role.as_str(), "all");
}

#[test]
fn role_rejects_unknown_value() {
assert!(ProveProxyArgs::try_parse_from(["prove-proxy", "--role", "bridge"]).is_err());
}
}
120 changes: 96 additions & 24 deletions client_prover/psy_core/psy_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ pub struct NetworkConfig<F: RichField> {
pub realm_configs: Vec<RealmConfig>,
pub coordinator_configs: Vec<CoordinatorConfig>,
pub prove_proxy_url: Vec<String>,
/// Prove-proxy pool that serves the bridge Groth16 (relayer) proofs.
/// The relayer refuses to start when this is empty for the current network.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub system_prove_proxy_url: Vec<String>,
pub faucet_rpc_url: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub api_services_url: Option<Vec<String>>,
Expand Down Expand Up @@ -780,7 +784,7 @@ mod tests {

#[test]
fn test_config_loading() {
let config_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../config.json");
let config_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../psy-genesis/config.json");
let config = PsyConfigGoldilocks::from_file(config_path.to_str().unwrap()).unwrap();

assert_eq!(config.current_network_name(), "localhost");
Expand All @@ -795,42 +799,48 @@ mod tests {
let json = r#"{
"networks": {
"localhost": {
"network": {
"magic": "0x1",
"faucet_rpc_url": [],
"nostr_relay_url": "ws://127.0.0.1:8081",
"users_per_realm": 1048576,
"global_user_tree_height": 24,
"realm_user_tree_height": 20,
"group_realm_height": 1,
"realm_configs": [{"id": 0, "rpc_url": ["http://127.0.0.1:8546"]}],
"coordinator_configs": [{"id": 0, "rpc_url": ["http://127.0.0.1:8545"]}],
"prove_proxy_url": ["http://127.0.0.1:9999"],
"system_prove_proxy_url": ["http://127.0.0.1:9999"],
"native_currency": "PSY",
"native_currency_decimal": 9,
"native_currency_name": "PSY",
"fees": {
"register_user_fee": 0,
"deploy_contract_fee": 0,
"guta_fee": 5000000000
"guta_fee": 5000000000,
"da_fee": 0
}
}
},
"testnet": {
"network": {
"magic": "0x1",
"faucet_rpc_url": [],
"nostr_relay_url": "ws://127.0.0.1:8081",
"users_per_realm": 1048576,
"global_user_tree_height": 24,
"realm_user_tree_height": 20,
"group_realm_height": 1,
"realm_configs": [{"id": 0, "rpc_url": ["https://testnet.example.com"]}],
"coordinator_configs": [{"id": 0, "rpc_url": ["https://testnet-coord.example.com"]}],
"prove_proxy_url": ["https://testnet-prover.example.com"],
"system_prove_proxy_url": ["https://testnet-prover.example.com"],
"native_currency": "tPSY",
"native_currency_decimal": 9,
"native_currency_name": "Test PSY",
"fees": {
"register_user_fee": 1000,
"deploy_contract_fee": 5000,
"guta_fee": 5000000000
"guta_fee": 5000000000,
"da_fee": 0
}
}
}
},
"defaultNetwork": "localhost"
Expand All @@ -846,50 +856,103 @@ mod tests {
assert_eq!(testnet.fees.register_user_fee, 1000);
}

#[test]
fn system_prove_proxy_url_defaults_to_empty_and_reads_when_present() {
// Template: the "localhost" network object's fields from test_network_switching
// above, plus `magic`, `faucet_rpc_url` and `nostr_relay_url` (required fields
// on NetworkConfig with no serde default) and without the extra "network"
// wrapper key that test_network_switching's literal uses. Config::networks is
// HashMap<String, NetworkConfig<F>>, i.e. flat — real config.json (see
// psy-genesis/config.json) has no "network" wrapper either. The
// test_network_switching-family tests are pre-existing failures for this
// structural reason; see task report.
// This base still does not contain system_prove_proxy_url.
let base = r#"{
"magic": "0x1",
"users_per_realm": 1048576,
"global_user_tree_height": 24,
"realm_user_tree_height": 20,
"group_realm_height": 1,
"realm_configs": [{"id": 0, "rpc_url": ["http://127.0.0.1:8546"]}],
"coordinator_configs": [{"id": 0, "rpc_url": ["http://127.0.0.1:8545"]}],
"prove_proxy_url": ["http://127.0.0.1:9999"],
"faucet_rpc_url": ["http://127.0.0.1:8547"],
"nostr_relay_url": "wss://relay.127.0.0.1.example",
"native_currency": "PSY",
"native_currency_decimal": 9,
"native_currency_name": "PSY",
"fees": {
"register_user_fee": 0,
"deploy_contract_fee": 0,
"guta_fee": 5000000000,
"da_fee": 0
}
}"#;
let without = format!(r#"{{"networks":{{"localhost":{base}}},"defaultNetwork":"localhost"}}"#);
let with = without.replacen(
r#""prove_proxy_url": ["http://127.0.0.1:9999"],"#,
r#""prove_proxy_url": ["http://127.0.0.1:9999"], "system_prove_proxy_url": ["http://127.0.0.1:9997"],"#,
1,
);
assert_ne!(with, without, "replacen must hit the prove_proxy_url line");

let cfg = PsyConfigGoldilocks::from_json(&without).unwrap();
assert!(cfg.get_current_network().unwrap().system_prove_proxy_url.is_empty());

let cfg = PsyConfigGoldilocks::from_json(&with).unwrap();
assert_eq!(cfg.get_current_network().unwrap().system_prove_proxy_url, vec!["http://127.0.0.1:9997"]);
}

#[test]
fn test_flexible_config_creation() {
let json = r#"{
"networks": {
"dev": {
"network": {
"magic": "0x1",
"faucet_rpc_url": [],
"nostr_relay_url": "ws://127.0.0.1:8081",
"users_per_realm": 1024,
"global_user_tree_height": 20,
"realm_user_tree_height": 10,
"group_realm_height": 1,
"realm_configs": [{"id": 0, "rpc_url": ["http://dev.local"]}],
"coordinator_configs": [{"id": 0, "rpc_url": ["http://coord.local"]}],
"prove_proxy_url": ["http://prover.local"],
"system_prove_proxy_url": ["http://prover.local"],
"native_currency": "DEV",
"native_currency_decimal": 6,
"native_currency_name": "Development",
"fees": {
"register_user_fee": 100,
"deploy_contract_fee": 500,
"guta_fee": 1000000000
"guta_fee": 1000000000,
"da_fee": 0
}
}
},
"localhost": {
"network": {
"magic": "0x1",
"faucet_rpc_url": [],
"nostr_relay_url": "ws://127.0.0.1:8081",
"users_per_realm": 1024,
"global_user_tree_height": 20,
"realm_user_tree_height": 10,
"group_realm_height": 1,
"realm_configs": [{"id": 0, "rpc_url": ["http://localhost:8546"]}],
"coordinator_configs": [{"id": 0, "rpc_url": ["http://localhost:8545"]}],
"prove_proxy_url": ["http://localhost:9999"],
"system_prove_proxy_url": ["http://localhost:9999"],
"native_currency": "LOCAL",
"native_currency_decimal": 8,
"native_currency_name": "Local Token",
"fees": {
"register_user_fee": 50,
"deploy_contract_fee": 250,
"guta_fee": 500000000
"guta_fee": 500000000,
"da_fee": 0
}
}
}
},
"defaultNetwork": "dev"
"defaultNetwork": "localhost"
}"#;

let config1 = PsyConfigGoldilocks::from_json(json).unwrap();
Expand All @@ -909,42 +972,48 @@ mod tests {
let json = r#"{
"networks": {
"dev": {
"network": {
"magic": "0x1",
"faucet_rpc_url": [],
"nostr_relay_url": "ws://127.0.0.1:8081",
"users_per_realm": 1024,
"global_user_tree_height": 20,
"realm_user_tree_height": 10,
"group_realm_height": 1,
"realm_configs": [{"id": 0, "rpc_url": ["http://dev.local"]}],
"coordinator_configs": [{"id": 0, "rpc_url": ["http://coord.local"]}],
"prove_proxy_url": ["http://prover.local"],
"system_prove_proxy_url": ["http://prover.local"],
"native_currency": "DEV",
"native_currency_decimal": 6,
"native_currency_name": "Development",
"fees": {
"register_user_fee": 100,
"deploy_contract_fee": 500,
"guta_fee": 1000000000
"guta_fee": 1000000000,
"da_fee": 0
}
}
},
"localhost": {
"network": {
"magic": "0x1",
"faucet_rpc_url": [],
"nostr_relay_url": "ws://127.0.0.1:8081",
"users_per_realm": 512,
"global_user_tree_height": 18,
"realm_user_tree_height": 9,
"group_realm_height": 1,
"realm_configs": [{"id": 0, "rpc_url": ["http://localhost:8546"]}],
"coordinator_configs": [{"id": 0, "rpc_url": ["http://localhost:8545"]}],
"prove_proxy_url": ["http://localhost:9999"],
"system_prove_proxy_url": ["http://localhost:9999"],
"native_currency": "LOCAL",
"native_currency_decimal": 8,
"native_currency_name": "Local Token",
"fees": {
"register_user_fee": 50,
"deploy_contract_fee": 250,
"guta_fee": 500000000
"guta_fee": 500000000,
"da_fee": 0
}
}
}
},
"defaultNetwork": "localhost"
Expand Down Expand Up @@ -975,26 +1044,29 @@ mod tests {
let json = r#"{
"networks": {
"only_network": {
"network": {
"magic": "0x1",
"faucet_rpc_url": [],
"nostr_relay_url": "ws://127.0.0.1:8081",
"users_per_realm": 1024,
"global_user_tree_height": 20,
"realm_user_tree_height": 10,
"group_realm_height": 1,
"realm_configs": [{"id": 0, "rpc_url": ["http://test.local"]}],
"coordinator_configs": [{"id": 0, "rpc_url": ["http://coord.local"]}],
"prove_proxy_url": ["http://prover.local"],
"system_prove_proxy_url": ["http://prover.local"],
"native_currency": "TEST",
"native_currency_decimal": 6,
"native_currency_name": "Test",
"fees": {
"register_user_fee": 0,
"deploy_contract_fee": 0,
"guta_fee": 1000000000
"guta_fee": 1000000000,
"da_fee": 0
}
}
}
},
"defaultNetwork": "only_network"
"defaultNetwork": "missing_network"
}"#;

let result = PsyConfigGoldilocks::from_json(json);
Expand Down
Loading