diff --git a/Cargo.lock b/Cargo.lock index fd8bd7c..e77bee0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2133,9 +2133,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.20.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "affdc52f7596ccb2d7645231fc6163bb314630c989b64998f3699a28b4d5d4dc" +checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -2148,9 +2148,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.20.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" +checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" dependencies = [ "anyhow", "async-trait", @@ -2163,7 +2163,6 @@ dependencies = [ "rustc-hash", "serde", "serde_json", - "soketto", "thiserror", "tokio", "tracing", @@ -2171,9 +2170,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.20.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" +checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", "hyper", @@ -2191,28 +2190,29 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.20.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" +checksum = "7d0bb047e79a143b32ea03974a6bf59b62c2a4c5f5d42a381c907a8bbb3f75c0" dependencies = [ "heck 0.4.1", - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] name = "jsonrpsee-server" -version = "0.20.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" +checksum = "12d8b6a9674422a8572e0b0abb12feeb3f2aeda86528c80d0350c2bd0923ab41" dependencies = [ "futures-util", "http", "hyper", "jsonrpsee-core", "jsonrpsee-types", + "pin-project", "route-recognizer", "serde", "serde_json", @@ -2227,16 +2227,15 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.20.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" +checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" dependencies = [ "anyhow", "beef", "serde", "serde_json", "thiserror", - "tracing", ] [[package]] @@ -2639,7 +2638,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.63", @@ -5102,6 +5101,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", + "tokio-util", ] [[package]] @@ -5156,9 +5156,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] diff --git a/Cargo.toml b/Cargo.toml index ef67ced..9b64fed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ cadence = "0.29.0" cadence-macros = "0.29.0" dashmap = "5.5.3" queues = "1.1.0" -jsonrpsee = { version = "0.20.1", features = [ +jsonrpsee = { version = "0.22.5", features = [ "server", "http-client", "macros", @@ -38,4 +38,4 @@ yellowstone-grpc-geyser = { git = "https://github.com/helius-labs/yellowstone-gr rand = "0.8.5" futures = "0.3.24" figment = { version = "0.10.6", features = ["env", "test"] } -tower = { version = "0.4.13", features = ["full"] } +tower = { version = "0.4.13", features = ["full"] } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c1935c1..f926db0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,11 +5,13 @@ use cadence::{BufferedUdpMetricSink, QueuingMetricSink, StatsdClient}; use cadence_macros::set_global_default; use figment::{providers::Env, Figment}; use grpc_geyser::GrpcGeyserImpl; -use jsonrpsee::server::{middleware::ProxyGetRequestLayer, ServerBuilder}; +use jsonrpsee::server::{RpcServiceBuilder, ServerBuilder}; +use jsonrpsee::server::middleware::http::ProxyGetRequestLayer; use priority_fee::PriorityFeeTracker; use rpc_server::AtlasPriorityFeeEstimator; use serde::Deserialize; use tracing::{error, info}; + mod errors; mod grpc_consumer; mod grpc_geyser; @@ -17,6 +19,7 @@ mod priority_fee; mod rpc_server; mod slot_cache; mod solana; +mod temp_validator; #[derive(Debug, Deserialize, Clone)] struct EstimatorEnv { @@ -50,7 +53,8 @@ async fn main() { let port = env.port.unwrap_or(4141); let server = ServerBuilder::default() - .set_middleware( + .set_rpc_middleware(RpcServiceBuilder::new().layer(temp_validator::RpcValidatorLayer::new())) + .set_http_middleware( tower::ServiceBuilder::new() // Proxy `GET /health` requests to internal `health` method. .layer( diff --git a/src/rpc_server.rs b/src/rpc_server.rs index db8a523..6a7a83b 100644 --- a/src/rpc_server.rs +++ b/src/rpc_server.rs @@ -44,8 +44,8 @@ impl fmt::Debug for AtlasPriorityFeeEstimator { #[derive(Serialize, Deserialize, Clone, Debug, Default)] #[serde( rename_all(serialize = "camelCase", deserialize = "camelCase"), - deny_unknown_fields )] +// TODO: DKH - add deny_unknown_fields pub struct GetPriorityFeeEstimateRequest { pub transaction: Option, // estimate fee for a txn pub account_keys: Option>, // estimate fee for a list of accounts @@ -55,8 +55,8 @@ pub struct GetPriorityFeeEstimateRequest { #[derive(Serialize, Deserialize, Clone, Debug, Default)] #[serde( rename_all(serialize = "camelCase", deserialize = "camelCase"), - deny_unknown_fields )] +// TODO: DKH - add deny_unknown_fields pub struct GetPriorityFeeEstimateOptions { // controls input txn encoding pub transaction_encoding: Option, @@ -399,7 +399,6 @@ mod tests { use cadence::{NopMetricSink, StatsdClient}; use jsonrpsee::core::Cow; use jsonrpsee::core::__reexports::serde_json; - use jsonrpsee::core::__reexports::serde_json::value::RawValue; use jsonrpsee::types::{Id, Request, TwoPointZero}; use solana_sdk::clock::Slot; use solana_sdk::pubkey::Pubkey; @@ -517,18 +516,21 @@ mod tests { assert_eq!(resp.priority_fee_estimate, Some(10500.0)); } - #[test] + // #[test] + // TODO: DKH - add the test back after we readd the validation fn test_parsing_wrong_fields() { for (param, error) in bad_params() { - let json_val = format!("{{\"jsonrpc\": \"2.0\",\"id\": \"1\", \"method\": \"getPriorityFeeEstimate\", \"params\": {param} }}"); - let res = serde_json::from_str::(json_val.as_str()); + let json_val = format!("{{\"jsonrpc\": \"2.0\",\"id\": \"1\", \"method\": \"getPriorityFeeEstimate\", \"params\": [{param}] }}"); + let res = serde_json::from_str::(json_val.as_str()); let res = res.unwrap(); assert_request(&res, Id::Str(Cow::const_str("1")), "getPriorityFeeEstimate"); - let params: serde_json::error::Result = - serde_json::from_str(res.params.map(RawValue::get).unwrap()); - assert!(params.is_err()); - assert_eq!(params.err().unwrap().to_string(), error, "testing {param}"); + if let Some(val) = res.params + { + let params: Result, _> = serde_json::from_str(val.get()); + assert!(params.is_err()); + assert_eq!(params.err().unwrap().to_string(), error, "testing {param}"); + } } } diff --git a/src/temp_validator.rs b/src/temp_validator.rs new file mode 100644 index 0000000..60caf0a --- /dev/null +++ b/src/temp_validator.rs @@ -0,0 +1,80 @@ +use cadence_macros::statsd_count; +use crate::priority_fee::PriorityLevel; +use jsonrpsee::core::__reexports::serde_json; +use jsonrpsee::server::middleware::rpc::RpcServiceT; +use jsonrpsee::types::Request; +use serde::{Deserialize, Serialize}; +use solana_transaction_status::UiTransactionEncoding; +use tracing::debug; + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[serde( + rename_all(serialize = "camelCase", deserialize = "camelCase"), + deny_unknown_fields +)] +struct GetPriorityFeeEstimateOptionsFake { + // controls input txn encoding + pub transaction_encoding: Option, + // controls custom priority fee level response + pub priority_level: Option, // Default to MEDIUM + pub include_all_priority_fee_levels: Option, // Include all priority level estimates in the response + #[serde()] + pub lookback_slots: Option, // how many slots to look back on, default 50, min 1, max 300 + pub include_vote: Option, // include vote txns in the estimate + // returns recommended fee, incompatible with custom controls. Currently the recommended fee is the median fee excluding vote txns + pub recommended: Option, // return the recommended fee (median fee excluding vote txns) +} + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[serde( + rename_all(serialize = "camelCase", deserialize = "camelCase"), + deny_unknown_fields +)] +struct GetPriorityFeeEstimateRequestFake { + transaction: Option, // estimate fee for a txn + account_keys: Option>, // estimate fee for a list of accounts + options: Option, +} + +/// RPC logger layer. +#[derive(Copy, Clone, Debug)] +pub struct RpcValidatorLayer; + +impl RpcValidatorLayer { + /// Create a new logging layer. + pub fn new() -> Self { + Self + } +} + +impl tower::Layer for RpcValidatorLayer { + type Service = RpcValidator; + + fn layer(&self, service: S) -> Self::Service { + RpcValidator { service } + } +} + +/// A middleware that logs each RPC call and response. +#[derive(Debug)] +pub struct RpcValidator { + service: S, +} + +impl<'a, S> RpcServiceT<'a> for RpcValidator +where + S: RpcServiceT<'a> + Send + Sync, +{ + type Future = S::Future; + + fn call(&self, req: Request<'a>) -> Self::Future { + if let Some(params) = &req.params { + if let Err(err_val) = serde_json::from_str::>(params.get()) { + statsd_count!("rpc_payload_parse_failed", 1); + debug!("RPC parse error: {}, {}", err_val, params); + } + } + + self.service.call(req) + } +}