From 4327e46bf3e76b4f1afe82e14ddb093cae4909de Mon Sep 17 00:00:00 2001 From: Collin Jackson Date: Thu, 3 Oct 2024 15:31:23 -0700 Subject: [PATCH] feat!: Update README with latest naming, prompting for acceptance of terms, noninteractive mode, replace keep_proving with just_once (#5) --- README.md | 5 +- clients/cli/Cargo.lock | 272 +++++++++++++++-------------------- clients/cli/Cargo.toml | 9 +- clients/cli/README.md | 7 + clients/cli/build.rs | 15 +- clients/cli/src/analytics.rs | 57 ++++++++ clients/cli/src/config.rs | 11 ++ clients/cli/src/prover.rs | 208 +++++++++++++++++++++------ 8 files changed, 372 insertions(+), 212 deletions(-) create mode 100644 clients/cli/src/analytics.rs create mode 100644 clients/cli/src/config.rs diff --git a/README.md b/README.md index bfed436..279cdda 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# network-cli +# network-api -This repository contains the Nexus Network CLI and the interface definition for the Orchestrator server API. +This repository contains the Nexus network command-line interface and +the interface it uses to communicate with Nexus servers. See the [CLI readme](./clients/cli/README.md) to get started. diff --git a/clients/cli/Cargo.lock b/clients/cli/Cargo.lock index 60062cf..54b14b2 100644 --- a/clients/cli/Cargo.lock +++ b/clients/cli/Cargo.lock @@ -24,6 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -39,14 +40,18 @@ dependencies = [ ] [[package]] -name = "allo-isolate" -version = "0.1.25" +name = "alloc-no-stdlib" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b6d794345b06592d0ebeed8e477e41b71e5a0a49df4fc0e4184d5938b99509" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" dependencies = [ - "anyhow", - "atomic", - "backtrace", + "alloc-no-stdlib", ] [[package]] @@ -56,21 +61,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] -name = "android_log-sys" -version = "0.3.1" +name = "android-tzdata" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] -name = "android_logger" -version = "0.13.3" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ - "android_log-sys", - "env_logger", - "log", - "once_cell", + "libc", ] [[package]] @@ -441,12 +443,6 @@ dependencies = [ "syn 2.0.71", ] -[[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" - [[package]] name = "atomic-waker" version = "1.1.2" @@ -571,10 +567,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] -name = "build-target" -version = "0.4.0" +name = "brotli" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b" +checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] [[package]] name = "bumpalo" @@ -588,12 +599,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -[[package]] -name = "bytemuck" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" - [[package]] name = "byteorder" version = "1.5.0" @@ -622,6 +627,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] + [[package]] name = "clap" version = "4.5.9" @@ -691,16 +710,6 @@ dependencies = [ "serde", ] -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - [[package]] name = "constant_time_eq" version = "0.3.1" @@ -767,42 +776,12 @@ dependencies = [ "typenum", ] -[[package]] -name = "dart-sys-fork" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "933dafff26172b719bb9695dd3715a1e7792f62dcdc8a5d4c740db7e0fedee8b" -dependencies = [ - "cc", -] - -[[package]] -name = "dashmap" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" -dependencies = [ - "cfg-if", - "num_cpus", -] - [[package]] name = "data-encoding" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" -[[package]] -name = "delegate-attr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51aac4c99b2e6775164b412ea33ae8441b2fde2dbf05a20bc0052a63d08c475b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.71", -] - [[package]] name = "derivative" version = "2.2.0" @@ -864,16 +843,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "log", - "regex", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -923,46 +892,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "flutter_rust_bridge" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebee2d1d5b8b3cfbbb11919b44791b4e0f037328195efd3832c7f7e0c6c6c8b" -dependencies = [ - "allo-isolate", - "android_logger", - "anyhow", - "build-target", - "bytemuck", - "byteorder", - "console_error_panic_hook", - "dart-sys-fork", - "delegate-attr", - "flutter_rust_bridge_macros", - "futures", - "js-sys", - "lazy_static", - "oslog", - "threadpool", - "tokio", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "flutter_rust_bridge_macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c061770f5f09e99d6143612e95cfc1ba2ae773746fbe5826a9c914a533b0723" -dependencies = [ - "hex", - "md-5", - "proc-macro2", - "quote", - "syn 2.0.71", -] - [[package]] name = "fnv" version = "1.0.7" @@ -1247,6 +1176,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "1.1.0" @@ -1360,6 +1298,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "idna" version = "0.5.0" @@ -1495,16 +1456,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest 0.10.7", -] - [[package]] name = "memchr" version = "2.7.4" @@ -1633,18 +1584,20 @@ dependencies = [ "ark-test-curves", "ark-vesta", "async-stream", - "base64", + "chrono", "clap", "elf", - "flutter_rust_bridge", "futures", "getrandom 0.2.15", "hex", + "home", + "iana-time-zone", "jsonrpsee", "nexus-core", "prost", "prost-build", "rand 0.8.5", + "random_word", "reqwest", "serde", "serde_json", @@ -1830,17 +1783,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "oslog" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8343ce955f18e7e68c0207dd0ea776ec453035685395ababd2ea651c569728b3" -dependencies = [ - "cc", - "dashmap", - "log", -] - [[package]] name = "overload" version = "0.1.1" @@ -2115,6 +2057,20 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "random_word" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07eed67a16dde2cc3c7f65c072acd8d5b2e53d4aab95067c320db851c7651f29" +dependencies = [ + "ahash", + "brotli", + "once_cell", + "paste", + "rand 0.8.5", + "unicase", +] + [[package]] name = "rayon" version = "1.10.0" @@ -2197,7 +2153,6 @@ dependencies = [ "base64", "bytes", "encoding_rs", - "futures-channel", "futures-core", "futures-util", "h2", @@ -2635,15 +2590,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - [[package]] name = "tinyvec" version = "1.8.0" @@ -2871,6 +2817,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -3070,6 +3025,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/clients/cli/Cargo.toml b/clients/cli/Cargo.toml index 413ec79..abd11a9 100644 --- a/clients/cli/Cargo.toml +++ b/clients/cli/Cargo.toml @@ -16,15 +16,14 @@ clap = { version = "4.5", features = ["derive"] } futures = "0.3" prost = "0.13" rand = "0.8.5" -reqwest = { version = "0.12", features = ["blocking"] } +reqwest = { version = "0.12", features = ["json"] } tokio = { version = "1.38", features = ["full"] } tokio-tungstenite = { version = "0.23", features = ["native-tls"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["std", "env-filter"] } uuid = { version = "1.9", features = ["v4", "fast-rng"] } - -base64 = "0.22.1" -flutter_rust_bridge = "=2.1.0" +home = "0.5.9" +random_word = { version = "0.4.3", features = ["en"] } nexus-core = { git = "https://github.com/nexus-xyz/nexus-zkvm.git" } getrandom = { version = "0.2", features = ["js"] } # Workaround for "failed to resolve patches for `https://github.com/rust-lang/crates.io-index`" @@ -60,6 +59,8 @@ ark-grumpkin = "0.4.0" ark-pallas = "0.4.0" ark-vesta = "0.4.0" ark-test-curves = { version = "0.4.2", features = ["bls12_381_curve"] } +iana-time-zone = "0.1.60" +chrono = "0.4.38" [patch.crates-io] ark-crypto-primitives = { git = "https://github.com/arkworks-rs/crypto-primitives", rev = "d27a5c8" } diff --git a/clients/cli/README.md b/clients/cli/README.md index 5acdebf..05e5067 100644 --- a/clients/cli/README.md +++ b/clients/cli/README.md @@ -10,6 +10,13 @@ curl https://network-cli.nexus.xyz/install.sh | sh If you do not already have Rust, you will be prompted to install it. +## Terms of Use + +Use of the CLI is subject to the [Terms of Use](https://nexus.xyz/terms_of_use). +The first time you run it, it prompts you to accept the terms. To accept the terms +noninteractively (for example, in a continuous integration environment), +add `NONINTERACTIVE=1` at the start of the command. + ## Known issues Currently only proving is supported. Submitting programs to the network is in private beta. diff --git a/clients/cli/build.rs b/clients/cli/build.rs index 7003e51..b5448b1 100644 --- a/clients/cli/build.rs +++ b/clients/cli/build.rs @@ -1,14 +1,19 @@ -use std::{error::Error, path::PathBuf}; +use std::{error::Error, path::PathBuf, process::Command}; fn main() -> Result<(), Box> { let out_dir: PathBuf = "./src/generated/".into(); let proto_file: PathBuf = "../../proto/orchestrator.proto".into(); let proto_dir = proto_file.parent().unwrap(); - prost_build::Config::new() - .out_dir(out_dir) - .protoc_arg("--experimental_allow_proto3_optional") - .compile_protos(&[&proto_file], &[proto_dir])?; + match Command::new("protoc --version").spawn() { + Ok(_) => prost_build::Config::new() + .out_dir(out_dir) + .protoc_arg("--experimental_allow_proto3_optional") + .compile_protos(&[&proto_file], &[proto_dir])?, + Err(_) => { + // Skipping protobuf compilation. + } + } Ok(()) } diff --git a/clients/cli/src/analytics.rs b/clients/cli/src/analytics.rs new file mode 100644 index 0000000..190f180 --- /dev/null +++ b/clients/cli/src/analytics.rs @@ -0,0 +1,57 @@ +use crate::config::analytics_token; +use chrono::Datelike; +use chrono::Timelike; +use reqwest::header::{ACCEPT, CONTENT_TYPE}; +use serde_json::{json, Value}; +use std::{ + env, + time::{SystemTime, UNIX_EPOCH}, +}; + +pub fn track( + event_name: String, + description: String, + ws_addr_string: &str, + event_properties: Value, +) { + println!("{}", description); + + let token = analytics_token(ws_addr_string); + if token.is_empty() { + return; + } + let local_now = chrono::offset::Local::now(); + let mut properties = json!({ + "token": token, + "time": SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(), + "distinct_id": event_properties["prover_id"], + "prover_type": "volunteer", + "client_type": "cli", + "operating_system": env::consts::OS, + "time_zone": iana_time_zone::get_timezone().unwrap(), + "local_hour": local_now.hour(), + "local_weekday_number_from_monday": local_now.weekday().number_from_monday(), + "ws_addr_string": ws_addr_string, + }); + for (k, v) in event_properties.as_object().unwrap() { + properties[k] = v.clone(); + } + let body = json!({ + "event": event_name, + "properties": properties + }); + tokio::spawn(async move { + let client = reqwest::Client::new(); + let _ = client + .post("https://api.mixpanel.com/track?ip=1") + .body(format!("[{}]", body.to_string())) + .header(ACCEPT, "text/plain") + .header(CONTENT_TYPE, "application/json") + .send() + .await + .unwrap() + .text() + .await + .unwrap(); + }); +} diff --git a/clients/cli/src/config.rs b/clients/cli/src/config.rs new file mode 100644 index 0000000..aff1d5a --- /dev/null +++ b/clients/cli/src/config.rs @@ -0,0 +1,11 @@ +pub fn analytics_token(ws_addr_string: &str) -> String { + if ws_addr_string.starts_with("wss://dev.orchestrator.nexus.xyz:443/") { + return "504d4d443854f2cd10e2e385aca81aa4".into(); + } else if ws_addr_string.starts_with("wss://staging.orchestrator.nexus.xyz:443/") { + return "30bcb58893992aabc5aec014e7b903d2".into(); + } else if ws_addr_string.starts_with("wss://beta.orchestrator.nexus.xyz:443/") { + return "3c16d3853f4258414c9c9109bbbdef0e".into(); + } else { + return "".into(); + }; +} diff --git a/clients/cli/src/prover.rs b/clients/cli/src/prover.rs index 8130538..6de1cff 100644 --- a/clients/cli/src/prover.rs +++ b/clients/cli/src/prover.rs @@ -1,7 +1,11 @@ // Copyright (c) 2024 Nexus. All rights reserved. +mod analytics; +mod config; mod generated; +use crate::analytics::track; + use std::borrow::Cow; use clap::Parser; @@ -11,6 +15,9 @@ use generated::pb::{ ProverRequest, ProverRequestRegistration, ProverResponse, ProverType, }; use prost::Message as _; +use random_word::Lang; +use serde_json::json; +use std::{fs, path::Path, time::SystemTime}; use tokio_tungstenite::tungstenite::protocol::{frame::coding::CloseCode, CloseFrame, Message}; use tracing_subscriber::fmt::format::FmtSpan; use tracing_subscriber::EnvFilter; @@ -22,14 +29,12 @@ use nexus_core::{ NexusVM, }, prover::nova::{ - init_circuit_trace, - key::{CanonicalSerialize}, - prove_seq_step, - types::*, - pp::gen_vm_pp, + init_circuit_trace, key::CanonicalSerialize, pp::gen_vm_pp, prove_seq_step, types::*, }, }; +use std::env; use zstd::stream::Encoder; +use rand::{ RngCore }; #[derive(Parser, Debug)] struct Args { @@ -40,13 +45,9 @@ struct Args { #[arg(short, long, default_value_t = 443u16)] port: u16, - /// Whether to connect using secure web sockets - #[arg(short, long, default_value_t = true)] - use_https: bool, - - /// Whether to loop and keep the connection open - #[arg(short, long, default_value_t = true)] - keep_listening: bool, + /// Whether to hang up after the first proof + #[arg(short, long, default_value_t = false)] + just_once: bool, } #[tokio::main] @@ -61,50 +62,101 @@ async fn main() { let ws_addr_string = format!( "{}://{}:{}/prove", - if args.use_https { "wss" } else { "ws" }, + if args.port == 443 { "wss" } else { "ws" }, args.hostname, args.port ); - let prover_id = format!("prover_{}", rand::random::()); - let k = 4; // TODO(collinjackson): Get parameters from a file or URL. let pp = gen_vm_pp::>(k as usize, &()) .expect("error generating public parameters"); - println!( - "{} supplying proofs to Orchestrator at {}", - prover_id, &ws_addr_string + // If the prover_id file is found, use the contents, otherwise generate a new random id + // and store it. + let _ = match env::var("NONINTERACTIVE") { + Ok(_) => (), + Err(_) => { + println!( + "Do you agree to the Nexus Beta Terms of Use (https://nexus.xyz/terms-of-use)? (Y/n)" + ); + let mut input = String::new(); + let _ = std::io::stdin().read_line(&mut input); + if input.chars().nth(0).unwrap() == 'n' || input.chars().nth(0).unwrap() == 'N' { + return (); + } + } + }; + let mut prover_id = format!( + "{}-{}-{}", + random_word::gen(Lang::En), + random_word::gen(Lang::En), + rand::thread_rng().next_u32() % 100, + ); + match home::home_dir() { + Some(path) if !path.as_os_str().is_empty() => { + let nexus_dir = Path::new(&path).join(".nexus"); + prover_id = match fs::read(nexus_dir.join("prover-id")) { + Ok(buf) => String::from_utf8(buf).unwrap(), + Err(_) => { + let _ = fs::create_dir(nexus_dir.clone()); + fs::write(nexus_dir.join("prover-id"), prover_id.clone()).unwrap(); + prover_id + } + } + } + _ => { + println!("Unable to get home dir."); + } + }; + + track( + "connect".into(), + format!("Connecting to {}...", &ws_addr_string), + &ws_addr_string, + json!({"prover_id": prover_id}), + ); + + let (mut client, _) = tokio_tungstenite::connect_async(&ws_addr_string) + .await + .unwrap(); + + track( + "connected".into(), + "Connected.".into(), + &ws_addr_string, + json!({"prover_id": prover_id}), ); let registration = ProverRequest { contents: Some(prover_request::Contents::Registration( ProverRequestRegistration { prover_type: ProverType::Volunteer.into(), - prover_id: prover_id, + prover_id: prover_id.clone().into(), estimated_proof_cycles_hertz: None, }, )), }; - let (mut client, _) = tokio_tungstenite::connect_async(ws_addr_string) - .await - .unwrap(); - client .send(Message::Binary(registration.encode_to_vec())) .await .unwrap(); - println!("Sent registration message..."); + track( + "register".into(), + format!("Your assigned prover identifier is {}.", prover_id), + &ws_addr_string, + json!({"ws_addr_string": ws_addr_string, "prover_id": prover_id}), + ); + println!( + "Network stats are available at https://beta.nexus.xyz/." + ); loop { let program_message = match client.next().await.unwrap().unwrap() { Message::Binary(b) => b, _ => panic!("Unexpected message type"), }; - println!("Received program message..."); - let program = ProverResponse::decode(program_message.as_slice()).unwrap(); let Program::Rv32iElfBytes(elf_bytes) = program @@ -118,32 +170,35 @@ async fn main() { let to_prove = program.to_prove.unwrap(); let Input::RawBytes(input) = to_prove.input.unwrap().input.unwrap(); - println!( - "Received a {} byte program to prove with {} bytes of input", - elf_bytes.len(), - input.len() + track( + "program".into(), + format!( + "Received a {} byte program to prove with {} bytes of input", + elf_bytes.len(), + input.len() + ), + &ws_addr_string, + json!({"prover_id": prover_id}), ); let mut vm: NexusVM = parse_elf(&elf_bytes.as_ref()).expect("error loading and parsing RISC-V instruction"); vm.syscalls.set_input(&input); - let k = 4; // TODO(collinjackson): Get outputs let completed_trace = trace(&mut vm, k as usize, false).expect("error generating trace"); let tr = init_circuit_trace(completed_trace).expect("error initializing circuit trace"); let total_steps = tr.steps(); - println!("Program trace {} steps", total_steps); let start: usize = match to_prove.step_to_start { Some(step) => step as usize, None => 0, }; - let steps_to_prove = to_prove.steps_to_prove; - let mut end: usize = match steps_to_prove { - Some(steps) => start + steps as usize, + let steps_to_prove = match to_prove.steps_to_prove { + Some(steps) => steps as usize, None => total_steps, }; + let mut end: usize = start + steps_to_prove; if end > total_steps { end = total_steps } @@ -162,22 +217,63 @@ async fn main() { .unwrap(); let z_st = tr.input(start).expect("error starting circuit trace"); - println!("Proving..."); let mut proof = IVCProof::new(&z_st); - println!("Proving from {} to {}", start, end); + let mut completed_fraction = 0.0; + let mut steps_proven = 0; + track( + "progress".into(), + format!( + "Program trace is {} steps. Proving from {} to {}...", + total_steps, start, end + ), + &ws_addr_string, + json!({ + "completed_fraction": completed_fraction, + "steps_in_trace": total_steps, + "steps_to_prove": steps_to_prove, + "steps_proven": steps_proven, + "cycles_proven": steps_proven * k, + "k": k, + "prover_id": prover_id, + }), + ); + let start_time = SystemTime::now(); + let mut progress_time = start_time; for step in start..end { proof = prove_seq_step(Some(proof), &pp, &tr).expect("error proving step"); - println!("Proved step {}", step); - let steps_proven = step - start + 1; + steps_proven += 1; + completed_fraction = steps_proven as f32 / steps_to_prove as f32; let progress = ProverRequest { contents: Some(prover_request::Contents::Progress(Progress { - completed_fraction: steps_proven as f32 / steps_to_prove.unwrap() as f32, + completed_fraction: completed_fraction, steps_in_trace: total_steps as i32, - steps_to_prove: (end - start) as i32, + steps_to_prove: steps_to_prove as i32, steps_proven: steps_proven as i32, })), }; + let progress_duration = SystemTime::now().duration_since(progress_time).unwrap(); + let cycles_proven = steps_proven * 4; + let proof_cycles_hertz = k * 1000 / progress_duration.as_millis(); + let proof_cycles_per_minute = k * 60 * 1000 / progress_duration.as_millis(); + track( + "progress".into(), + format!("Proved step {} at {} Hz.", step, proof_cycles_hertz), + &ws_addr_string, + json!({ + "completed_fraction": completed_fraction, + "steps_in_trace": total_steps, + "steps_to_prove": steps_to_prove, + "steps_proven": steps_proven, + "cycles_proven": steps_proven * 4, + "k": k, + "progress_duration_millis": progress_duration.as_millis(), + "proof_cycles_hertz": proof_cycles_hertz, + "proof_cycles_per_minute": proof_cycles_per_minute, + "prover_id": prover_id, + }), + ); + progress_time = SystemTime::now(); client .send(Message::Binary(progress.encode_to_vec())) .await @@ -200,17 +296,30 @@ async fn main() { .send(Message::Binary(response.encode_to_vec())) .await .unwrap(); + let duration = SystemTime::now().duration_since(start_time).unwrap(); + let proof_cycles_hertz = cycles_proven * 1000 / duration.as_millis(); + let proof_cycles_per_minute = cycles_proven * 60 * 1000 / duration.as_millis(); + track( + "proof".into(), + format!("Proof sent! You proved at {} Hz.", proof_cycles_hertz), + &ws_addr_string, + json!({ + "proof_duration_sec": duration.as_secs(), + "proof_duration_millis": duration.as_millis(), + "proof_cycles_hertz": proof_cycles_hertz, + "proof_cycles_per_minute": proof_cycles_per_minute, + "prover_id": prover_id, + }), + ); } } // TODO(collinjackson): Consider verifying the proof before sending it // proof.verify(&public_params, proof.step_num() as _).expect("error verifying execution") - println!("Proof sent!"); - - if args.keep_listening { - println!("Waiting for another program to prove..."); - } else { + if args.just_once { break; + } else { + println!("Waiting for another program to prove..."); } } @@ -221,5 +330,10 @@ async fn main() { })) .await .unwrap(); - println!("Sent proof and closed connection..."); + track( + "disconnect".into(), + "Sent proof and closed connection...".into(), + &ws_addr_string, + json!({ "prover_id": prover_id }), + ); }