diff --git a/Cargo.lock b/Cargo.lock index b7af866..35248a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1493,6 +1493,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.41" @@ -2326,8 +2332,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -2337,9 +2345,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -3021,6 +3031,12 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lz4-sys" version = "1.11.1+lz4-1.10.0" @@ -3371,6 +3387,82 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.12", + "tracing", +] + +[[package]] +name = "opentelemetry-http" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry", + "reqwest", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b" +dependencies = [ + "http", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", + "reqwest", + "thiserror 2.0.12", + "tokio", + "tonic", + "tracing", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "rand 0.9.1", + "serde_json", + "thiserror 2.0.12", + "tokio", + "tokio-stream", +] + [[package]] name = "ordered-float" version = "4.6.0" @@ -3796,10 +3888,14 @@ name = "prover_cli" version = "0.1.0" dependencies = [ "clap", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry_sdk", "prover", "tokio", "toml", "tracing", + "tracing-opentelemetry", "tracing-subscriber 0.3.19", "tracing-test", ] @@ -3809,7 +3905,9 @@ name = "prover_client" version = "0.1.0" dependencies = [ "alloy", + "clap", "prost", + "sha2", "tokio", "tonic", "tonic-build", @@ -3836,6 +3934,61 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quinn" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2", + "thiserror 2.0.12", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +dependencies = [ + "bytes", + "getrandom 0.3.2", + "lru-slab", + "rand 0.9.1", + "ring", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.12", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.40" @@ -4046,12 +4199,14 @@ checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ "base64", "bytes", + "futures-channel", "futures-core", "futures-util", "http", "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-tls", "hyper-util", "ipnet", @@ -4062,13 +4217,18 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-rustls", "tower", "tower-service", "url", @@ -4272,6 +4432,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "aws-lc-rs", + "log", "once_cell", "ring", "rustls-pki-types", @@ -4306,6 +4467,9 @@ name = "rustls-pki-types" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" @@ -4948,6 +5112,21 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.46.0" @@ -5093,8 +5272,10 @@ dependencies = [ "percent-encoding", "pin-project", "prost", + "rustls-native-certs", "socket2", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -5247,6 +5428,24 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcf5959f39507d0d04d6413119c04f33b623f4f951ebcbdddddfad2d0623a9c" +dependencies = [ + "js-sys", + "once_cell", + "opentelemetry", + "opentelemetry_sdk", + "smallvec", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber 0.3.19", + "web-time", +] + [[package]] name = "tracing-subscriber" version = "0.2.25" @@ -5569,6 +5768,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.26.11" diff --git a/Readme.md b/Readme.md index a654097..6e84a45 100644 --- a/Readme.md +++ b/Readme.md @@ -3,17 +3,24 @@ ## Docker * docker build --progress=plain --no-cache -t prover . -* sudo docker run -p 50051:50051 prover --mock-sc true --mock-user mock/mock_user_1.json +* docker run -p 50051:50051 prover --mock-sc true --mock-user mock/mock_user_1.json ## Run prover RUST_LOG=debug cargo run -p prover_cli -- -i 127.0.0.1 -r "wss://eth-mainnet.g.alchemy.com/v2/__MY_TOKEN__" -## Run prover + Mock +### Run prover + Mock -RUST_LOG=debug cargo run -p prover_cli -- -i 127.0.0.1 --metrics-ip 127.0.0.1 --mock-sc true --mock-user mock/mock_user_1.json +RUST_LOG=debug cargo run -p prover_cli -- -i 127.0.0.1 --metrics-ip 127.0.0.1 --mock-sc true --mock-user mock/mock_user_1.json -## Run prover client (for tests) +### Run prover + opentelemetry + +* Run jaeger (locally, port 16686 -> Web ui, port 4317 -> otlp/grpc, port 4318 -> otlp/http) + * docker run -d --name jaeger -e COLLECTOR_OTLP_ENABLED=true -p 16686:16686 -p 4317:4317 -p 4318:4318 jaegertracing/all-in-one:latest +* Run prover: + * OTEL_EXPORTER_OTLP_PROTOCOL=grpc RUST_LOG=debug cargo run -p prover_cli -- -i 127.0.0.1 --metrics-ip 127.0.0.1 --mock-sc true --mock-user mock/mock_user_1.json + +### Run prover client (for tests) RUST_LOG=debug cargo run -p prover_client diff --git a/prover/src/epoch_service.rs b/prover/src/epoch_service.rs index 8469305..659083f 100644 --- a/prover/src/epoch_service.rs +++ b/prover/src/epoch_service.rs @@ -10,7 +10,9 @@ use tokio::sync::Notify; use tracing::{debug, error}; // internal use crate::error::AppError; -use crate::metrics::{EPOCH_SERVICE_CURRENT_EPOCH, EPOCH_SERVICE_CURRENT_EPOCH_SLICE, EPOCH_SERVICE_DRIFT_MILLIS}; +use crate::metrics::{ + EPOCH_SERVICE_CURRENT_EPOCH, EPOCH_SERVICE_CURRENT_EPOCH_SLICE, EPOCH_SERVICE_DRIFT_MILLIS, +}; /// Duration of an epoch (1 day) const EPOCH_DURATION: Duration = Duration::from_secs(TimeDelta::days(1).num_seconds() as u64); @@ -39,6 +41,9 @@ pub struct EpochService { } impl EpochService { + // Note: listen_for_new_epoch never ends so no log will happen with #[instrument] + // + metrics already tracks the current epoch / epoch_slice + // #[instrument(skip(self), fields(self.epoch_slice_duration, self.genesis, self.current_epoch))] pub(crate) async fn listen_for_new_epoch(&self) -> Result<(), AppError> { let epoch_slice_count = Self::compute_epoch_slice_count(EPOCH_DURATION, self.epoch_slice_duration); @@ -91,7 +96,8 @@ impl EpochService { { let now_ = tokio::time::Instant::now(); debug!("awake at: {:?}, drift by: {:?}", now_, now_ - wait_until); - histogram!(EPOCH_SERVICE_DRIFT_MILLIS.name, "prover" => "epoch service").record(now_ - wait_until); + histogram!(EPOCH_SERVICE_DRIFT_MILLIS.name, "prover" => "epoch service") + .record(now_ - wait_until); } // Note: could use checked_add() here, but it's quite impossible to have an overflow here @@ -112,8 +118,10 @@ impl EpochService { // Note: based on this link https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions // "Casting from an integer to float will produce the closest possible float *" - gauge!(EPOCH_SERVICE_CURRENT_EPOCH.name, "prover" => "epoch service").set(i64::from(current_epoch) as f64); - gauge!(EPOCH_SERVICE_CURRENT_EPOCH_SLICE.name, "prover" => "epoch service").set(i64::from(current_epoch_slice) as f64); + gauge!(EPOCH_SERVICE_CURRENT_EPOCH.name, "prover" => "epoch service") + .set(current_epoch as f64); + gauge!(EPOCH_SERVICE_CURRENT_EPOCH_SLICE.name, "prover" => "epoch service") + .set(current_epoch_slice as f64); // println!("Epoch changed: {}", current_epoch); self.epoch_changes.notify_one(); diff --git a/prover/src/grpc_service.rs b/prover/src/grpc_service.rs index b31fa54..8288e3b 100644 --- a/prover/src/grpc_service.rs +++ b/prover/src/grpc_service.rs @@ -20,9 +20,12 @@ use tracing::debug; use url::Url; // internal use crate::error::{AppError, ProofGenerationStringError}; +use crate::metrics::{ + GET_PROOFS_LISTENERS, GET_USER_TIER_INFO_REQUESTS, GaugeWrapper, SEND_TRANSACTION_REQUESTS, + USER_REGISTERED, USER_REGISTERED_REQUESTS, +}; use crate::proof_generation::{ProofGenerationData, ProofSendingData}; use crate::user_db::{UserDb, UserTierInfo}; -use crate::metrics::{USER_REGISTERED, USER_REGISTERED_REQUESTS, SEND_TRANSACTION_REQUESTS, GET_USER_TIER_INFO_REQUESTS, GET_PROOFS_LISTENERS, GaugeWrapper}; use crate::user_db_error::RegisterError; use rln_proof::RlnIdentifier; use smart_contract::{ @@ -98,11 +101,11 @@ where RLNSC: RLNRegister + Send + Sync + 'static, RLNSC::Error: std::error::Error + Send + Sync + 'static, { + #[tracing::instrument(skip(self), err, ret)] async fn send_transaction( &self, request: Request, ) -> Result, Status> { - counter!(SEND_TRANSACTION_REQUESTS.name, "service" => "grpc").increment(1); debug!("send_transaction request: {:?}", request); let req = request.into_inner(); @@ -153,6 +156,7 @@ where Ok(Response::new(reply)) } + #[tracing::instrument(skip(self), err, ret)] async fn register_user( &self, request: Request, @@ -204,11 +208,11 @@ where type GetProofsStream = ReceiverStream>; + #[tracing::instrument(skip(self), err, ret)] async fn get_proofs( &self, request: Request, ) -> Result, Status> { - debug!("get_proofs request: {:?}", request); let gauge = GaugeWrapper::new(GET_PROOFS_LISTENERS.name, "service", "grpc"); @@ -217,7 +221,6 @@ where // Channel to receive a RLN proof (from one proof service) let mut rx2 = self.broadcast_channel.0.subscribe(); tokio::spawn(async move { - // FIXME: Should we send the error here? let gauge_ = gauge; @@ -246,11 +249,11 @@ where Ok(Response::new(ReceiverStream::new(rx))) } + #[tracing::instrument(skip(self), err, ret)] async fn get_user_tier_info( &self, request: Request, ) -> Result, Status> { - debug!("request: {:?}", request); counter!(GET_USER_TIER_INFO_REQUESTS.name, "service" => "grpc").increment(1); diff --git a/prover/src/lib.rs b/prover/src/lib.rs index ace4b77..624fca0 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -38,12 +38,12 @@ use crate::proof_service::ProofService; use crate::registry_listener::RegistryListener; use crate::tier::TierLimits; use crate::tiers_listener::TiersListener; +use crate::user_db_error::RegisterError; use crate::user_db_service::UserDbService; use crate::user_db_types::RateLimit; use rln_proof::RlnIdentifier; use smart_contract::KarmaTiersSC::KarmaTiersSCInstance; use smart_contract::TIER_LIMITS; -use crate::user_db_error::RegisterError; const RLN_IDENTIFIER_NAME: &[u8] = b"test-rln-identifier"; const PROVER_SPAM_LIMIT: RateLimit = RateLimit::new(10_000u64); @@ -54,7 +54,6 @@ const PROVER_MINIMAL_AMOUNT_FOR_REGISTRATION: U256 = pub async fn run_prover( app_args: AppArgs, ) -> Result<(), Box> { - // Epoch let epoch_service = EpochService::try_from((Duration::from_secs(60 * 2), GENESIS)) .expect("Failed to create epoch service"); @@ -92,7 +91,6 @@ pub async fn run_prover( let mock_users = read_mock_user(user_filepath)?; debug!("Mock - will register {} users", mock_users.len()); for mock_user in mock_users { - debug!( "Registering user address: {} - tx count: {}", mock_user.address, mock_user.tx_count @@ -103,14 +101,13 @@ pub async fn run_prover( match e { RegisterError::AlreadyRegistered(_) => { debug!("User {} already registered", mock_user.address); - }, + } _ => { return Err(Box::new(e)); } } } - user_db - .on_new_tx(&mock_user.address, Some(mock_user.tx_count))?; + user_db.on_new_tx(&mock_user.address, Some(mock_user.tx_count))?; } } } diff --git a/prover/src/metrics.rs b/prover/src/metrics.rs index d0365c4..d3d1225 100644 --- a/prover/src/metrics.rs +++ b/prover/src/metrics.rs @@ -1,5 +1,5 @@ -use std::net::{IpAddr, SocketAddr}; use metrics::gauge; +use std::net::{IpAddr, SocketAddr}; // third-party use metrics_exporter_prometheus::PrometheusBuilder; // use metrics_util::MetricKindMask; @@ -49,7 +49,7 @@ pub const EPOCH_SERVICE_DRIFT_MILLIS: Metric = Metric { pub const PROOF_SERVICE_GEN_PROOF_TIME: Metric = Metric { name: "proof_service_gen_proof_time", - description: "Generation time of a proof in milliseconds", + description: "Generation time of a proof in seconds", }; pub const GET_PROOFS_LISTENERS: Metric = Metric { @@ -61,7 +61,7 @@ pub const COUNTERS: [Metric; 4] = [ USER_REGISTERED, USER_REGISTERED_REQUESTS, SEND_TRANSACTION_REQUESTS, - GET_USER_TIER_INFO_REQUESTS + GET_USER_TIER_INFO_REQUESTS, ]; pub const GAUGES: [Metric; 3] = [ EPOCH_SERVICE_CURRENT_EPOCH, @@ -118,8 +118,8 @@ fn register_histogram(metric: Metric) { let _histogram = ::metrics::histogram!(metric.name); } -/// A Wrapper around a metric gauge -/// +/// A Wrapper around a metric gauge +/// /// Increment the given metric gauge on a new and decrement on drop /// Useful in a closure (or an async closure) pub struct GaugeWrapper { @@ -129,7 +129,11 @@ pub struct GaugeWrapper { } impl GaugeWrapper { - pub fn new(gauge_name: &'static str, gauge_app: &'static str, gauge_label: &'static str) -> Self { + pub fn new( + gauge_name: &'static str, + gauge_app: &'static str, + gauge_label: &'static str, + ) -> Self { gauge!(gauge_name, gauge_app => gauge_label).increment(1.0); Self { gauge_name, @@ -143,4 +147,4 @@ impl Drop for GaugeWrapper { fn drop(&mut self) { gauge!(self.gauge_name, self.gauge_app => self.gauge_label).decrement(1.0); } -} \ No newline at end of file +} diff --git a/prover/src/proof_service.rs b/prover/src/proof_service.rs index f37dea4..c41dc34 100644 --- a/prover/src/proof_service.rs +++ b/prover/src/proof_service.rs @@ -8,15 +8,15 @@ use metrics::histogram; use parking_lot::RwLock; use rln::hashers::hash_to_field; use rln::protocol::serialize_proof_values; -use tracing::{debug, info}; +use tracing::{Instrument, debug, debug_span, info}; // internal use crate::epoch_service::{Epoch, EpochSlice}; use crate::error::{AppError, ProofGenerationError, ProofGenerationStringError}; +use crate::metrics::PROOF_SERVICE_GEN_PROOF_TIME; use crate::proof_generation::{ProofGenerationData, ProofSendingData}; use crate::user_db::UserDb; use crate::user_db_types::RateLimit; use rln_proof::{RlnData, compute_rln_proof_and_values}; -use crate::metrics::PROOF_SERVICE_GEN_PROOF_TIME; const PROOF_SIZE: usize = 512; @@ -51,7 +51,6 @@ impl ProofService { } pub(crate) async fn serve(&self) -> Result<(), AppError> { - loop { let received = self.receiver.recv().await; @@ -69,7 +68,6 @@ impl ProofService { // Move to a task (as generating the proof can take quite some time) let blocking_task = tokio::task::spawn_blocking(move || { - let proof_generation_start = std::time::Instant::now(); let message_id = { @@ -124,7 +122,7 @@ impl ProofService { Ok::, ProofGenerationError>(output_buffer.into_inner()) }); - let result = blocking_task.await; + let result = blocking_task.instrument(debug_span!("compute proof")).await; // Result (1st) is a JoinError (and should not happen) // Result (2nd) is a ProofGenerationError let result = result.unwrap(); // Should never happen (but should panic if it does) diff --git a/prover/src/rocksdb_operands.rs b/prover/src/rocksdb_operands.rs index ad2187a..97684a2 100644 --- a/prover/src/rocksdb_operands.rs +++ b/prover/src/rocksdb_operands.rs @@ -1,5 +1,5 @@ use crate::epoch_service::{Epoch, EpochSlice}; -use claims::debug_assert_ge; +// use claims::debug_assert_ge; use nom::{ IResult, error::ContextError, diff --git a/prover_cli/Cargo.toml b/prover_cli/Cargo.toml index 745f82a..99ae661 100644 --- a/prover_cli/Cargo.toml +++ b/prover_cli/Cargo.toml @@ -11,5 +11,11 @@ tracing = "0.1.41" toml = "0.8" prover = { path = "../prover" } +opentelemetry = { version = "0.30", default-features = false, features = ["trace"]} +opentelemetry_sdk = { version = "0.30", features = ["rt-tokio"] } +opentelemetry-otlp = { version = "0.30", features = ["grpc-tonic", "reqwest-client", "reqwest-rustls", "http-proto", "tls", "tls-roots"]} +tracing-opentelemetry = "0.31" + + [dev-dependencies] tracing-test = "0.2.5" diff --git a/prover_cli/src/main.rs b/prover_cli/src/main.rs index 2f49410..7fe4432 100644 --- a/prover_cli/src/main.rs +++ b/prover_cli/src/main.rs @@ -8,20 +8,41 @@ use tracing::{ // error, // info }; -use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt}; +use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt}; + +use opentelemetry::trace::TracerProvider; +use opentelemetry_otlp::WithTonicConfig; +use opentelemetry_sdk::Resource; // internal use prover::{AppArgs, AppArgsConfig, metrics::init_metrics, run_prover}; +const APP_NAME: &str = "prover-cli"; + #[tokio::main] async fn main() -> Result<(), Box> { - // debug!("Args: {:?}", std::env::args()); - + // tracing let filter = EnvFilter::builder() .with_default_directive(LevelFilter::INFO.into()) - .from_env_lossy(); + .from_env_lossy() + // TODO: Add a way to disable this for maximum log? + .add_directive("h2=error".parse()?) + .add_directive("sled::pagecache=error".parse()?) + .add_directive("opentelemetry_sdk=error".parse()?); + + let fmt_layer = tracing_subscriber::fmt::layer(); + + let telemetry_layer = match create_otlp_tracer_provider() { + Some(tracer_provider) => { + let tracer = tracer_provider.tracer(APP_NAME); + Some(tracing_opentelemetry::OpenTelemetryLayer::new(tracer)) + } + None => None, + }; + tracing_subscriber::registry() - .with(fmt::layer()) + .with(fmt_layer) .with(filter) + .with(telemetry_layer) .init(); // let app_args = AppArgs::parse(); @@ -60,3 +81,46 @@ async fn main() -> Result<(), Box run_prover(app_args).await } + +fn create_otlp_tracer_provider() -> Option { + if !std::env::vars().any(|(name, _)| name.starts_with("OTEL_")) { + return None; + } + let protocol = std::env::var("OTEL_EXPORTER_OTLP_PROTOCOL").unwrap_or("grpc".to_string()); + + let exporter = match protocol.as_str() { + "grpc" => { + // Note - Performance: + // https://docs.rs/opentelemetry-otlp/latest/opentelemetry_otlp/index.html#performance + let mut exporter = opentelemetry_otlp::SpanExporter::builder() + .with_tonic() + //.with_endpoint(...) + ; + + // Check if we need TLS + if let Ok(endpoint) = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT") { + if endpoint.starts_with("https") { + exporter = exporter.with_tls_config( + opentelemetry_otlp::tonic_types::transport::ClientTlsConfig::default() + .with_enabled_roots(), + ); + } + } + exporter.build().expect("Failed to create tonic exporter") + } + "http/protobuf" => opentelemetry_otlp::SpanExporter::builder() + .with_http() + .build() + .expect("Failed to create http/protobuf exporter"), + p => panic!("Unsupported protocol {p}"), + }; + + let resource = Resource::builder().with_service_name(APP_NAME).build(); + + Some( + opentelemetry_sdk::trace::SdkTracerProvider::builder() + .with_resource(resource) + .with_batch_exporter(exporter) + .build(), + ) +} diff --git a/prover_client/Cargo.toml b/prover_client/Cargo.toml index 81f4a4f..f3e2be0 100644 --- a/prover_client/Cargo.toml +++ b/prover_client/Cargo.toml @@ -9,7 +9,9 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread"] } # TODO: workspace? tonic = "0.13.1" prost = "0.13" +clap = { version = "4.5.40", features = ["derive", "wrap_help"] } alloy.workspace = true +sha2 = "0.10" [build-dependencies] tonic-build = "*" diff --git a/prover_client/src/main.rs b/prover_client/src/main.rs index 2d0c4d0..20a6664 100644 --- a/prover_client/src/main.rs +++ b/prover_client/src/main.rs @@ -1,40 +1,139 @@ -use alloy::primitives::Address; -use std::str::FromStr; +use alloy::primitives::{Address, U256}; +use clap::{Args, Parser, Subcommand}; +use sha2::Digest; +use std::net::IpAddr; use tonic::Response; pub mod prover_proto { - // Include generated code (see build.rs) tonic::include_proto!("prover"); } +use crate::prover_proto::{GetUserTierInfoReply, GetUserTierInfoRequest, RegistrationStatus}; use prover_proto::{ - Address as GrpcAddress, RegisterUserReply, RegisterUserRequest, + Address as GrpcAddress, + RegisterUserReply, + RegisterUserRequest, + SendTransactionReply, + SendTransactionRequest, + U256 as GrpcU256, + Wei as GrpcWei, // RegistrationStatus, rln_prover_client::RlnProverClient, }; +#[derive(Debug, Clone, Parser)] +#[command(about = "RLN prover client", long_about = None)] +pub struct AppArgs { + #[arg(short = 'i', long = "ip", default_value = "::1", help = "Service ip")] + pub ip: IpAddr, + #[arg( + short = 'p', + long = "port", + default_value = "50051", + help = "Service port" + )] + pub port: u16, + #[arg( + short = 'a', + long = "address", + default_value = "0xb20a608c624Ca5003905aA834De7156C68b2E1d0", + help = "User address" + )] + pub address: Address, + #[command(subcommand)] + command: Commands, +} + +#[derive(Debug, Clone, PartialEq, Subcommand)] +pub(crate) enum Commands { + #[command(about = "Register a new user")] + RegisterUser, // (RegisterUserArgs), + #[command(about = "Send a transaction")] + SendTransaction(SendTransactionArgs), + #[command(about = "Get user tier info")] + GetUserTierInfo, +} + +#[derive(Debug, Clone, PartialEq, Args)] +pub struct SendTransactionArgs { + #[arg(short = 'c', long = "chain-id", help = "Chain id", default_value = "1")] + chain_id: U256, + #[arg(short = 'w', long = "wei", help = "Tx fee", default_value = "1000")] + wei: U256, + #[arg(short = 't', long = "tx-hash", help = "Tx hash", default_value = "foo")] + tx_hash: String, + #[arg( + long = "invalid-tx-hash", + default_missing_value = "false", + help = "Send an invalid tx hash" + )] + invalid_hash: bool, +} + #[tokio::main] async fn main() { - // FIXME: clap - let url = "http://127.0.0.1:42942"; - let addr = "0xb20a608c624Ca5003905aA834De7156C68b2E1d0"; - - let addr = Address::from_str(addr).unwrap(); - - let grpc_addr = GrpcAddress { - value: addr.to_vec(), - }; + let app_args = AppArgs::parse(); + let url = format!("http://{}:{}", app_args.ip, app_args.port); + println!("url: {url}"); let mut client = RlnProverClient::connect(url).await.unwrap(); - let request_0 = RegisterUserRequest { - user: Some(grpc_addr), + let grpc_addr = GrpcAddress { + value: app_args.address.to_vec(), }; - let request = tonic::Request::new(request_0); - let response: Response = client.register_user(request).await.unwrap(); - println!( - "RegisterUSerReply status: {:?}", - response.into_inner().status - ); + match app_args.command { + Commands::RegisterUser => { + let request_0 = RegisterUserRequest { + user: Some(grpc_addr), + }; + let request = tonic::Request::new(request_0); + let response: Response = + client.register_user(request).await.unwrap(); + + println!( + "RegisterUSerReply status: {:?}", + RegistrationStatus::try_from(response.into_inner().status) + ); + } + Commands::SendTransaction(send_transaction_args) => { + let chain_id = GrpcU256 { + // FIXME: LE or BE? + value: send_transaction_args.chain_id.to_le_bytes::<32>().to_vec(), + }; + let wei = GrpcWei { + // FIXME: LE or BE? + value: send_transaction_args.wei.to_le_bytes::<32>().to_vec(), + }; + + let tx_hash = if send_transaction_args.invalid_hash { + vec![] + } else { + // U256::from(42).to_le_bytes::<32>().to_vec() + sha2::Sha256::digest(send_transaction_args.tx_hash).to_vec() + }; + + let request_0 = SendTransactionRequest { + gas_price: Some(wei), + sender: Some(grpc_addr), + chain_id: Some(chain_id), + transaction_hash: tx_hash, + }; + let request = tonic::Request::new(request_0); + let response: Response = + client.send_transaction(request).await.unwrap(); + + println!("SendTransactionReply status: {:?}", response.into_inner()); + } + Commands::GetUserTierInfo => { + let request_0 = GetUserTierInfoRequest { + user: Some(grpc_addr), + }; + let request = tonic::Request::new(request_0); + let response: Response = + client.get_user_tier_info(request).await.unwrap(); + + println!("GetUserTierInfoReply: {:?}", response.into_inner()); + } + } }