From 18590782418ec20c0fae27ad0c4012b992efe178 Mon Sep 17 00:00:00 2001 From: GroovieGermanikus Date: Mon, 29 Jul 2024 11:29:21 +0200 Subject: [PATCH] MAJOR: cut solana-rpc dependency --- connector/Cargo.toml | 6 +- connector/examples/call_gpa_gma_example.rs | 32 +++++ connector/examples/snapshot_example.rs | 4 +- .../examples/websocket_example_consumer.rs | 4 +- connector/src/lib.rs | 3 +- connector/src/snapshot.rs | 6 +- connector/src/solana_rpc_minimal.rs | 120 ++++++++++++++++++ connector/src/websocket_source.rs | 2 +- 8 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 connector/examples/call_gpa_gma_example.rs create mode 100644 connector/src/solana_rpc_minimal.rs diff --git a/connector/Cargo.toml b/connector/Cargo.toml index 81f5cf6..abb5ed1 100644 --- a/connector/Cargo.toml +++ b/connector/Cargo.toml @@ -14,8 +14,12 @@ default = [] [dependencies] jsonrpc-core = { workspace = true } jsonrpc-core-client = { workspace = true } +jsonrpc-derive = "18.0.0" +jsonrpc-pubsub = "18.0.0" -solana-rpc = { workspace = true } +# note: avoid solana-rpc dependency +solana-rpc-client = "1.17" +solana-rpc-client-api = "1.17" solana-client = { workspace = true } solana-account-decoder = { workspace = true } solana-sdk = { workspace = true } diff --git a/connector/examples/call_gpa_gma_example.rs b/connector/examples/call_gpa_gma_example.rs new file mode 100644 index 0000000..7970e23 --- /dev/null +++ b/connector/examples/call_gpa_gma_example.rs @@ -0,0 +1,32 @@ +#![allow(unused_variables)] + +use clap::Parser; + +use mango_feeds_connector::snapshot::get_snapshot_gma; +use solana_sdk::pubkey::Pubkey; + +#[derive(Parser, Debug, Clone)] +#[clap()] +struct Cli { + // e.g. https://mango.devnet.rpcpool.com + #[clap(short, long, env)] + rpc_url: String, + + // e.g. 4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg + #[clap(short, long, env)] + program_account: Pubkey, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + solana_logger::setup_with_default("info"); + + let cli = Cli::parse_from(std::env::args_os()); + + let rpc_http_url = cli.rpc_url; + let program_id = cli.program_account; + + get_snapshot_gma(&rpc_http_url, vec![program_id.to_string()]).await?; + + Ok(()) +} diff --git a/connector/examples/snapshot_example.rs b/connector/examples/snapshot_example.rs index 13db3b0..c8b9c2c 100644 --- a/connector/examples/snapshot_example.rs +++ b/connector/examples/snapshot_example.rs @@ -3,7 +3,7 @@ use clap::Parser; use jsonrpc_core_client::transports::http; -use mango_feeds_connector::GetProgramAccountsClient; +use mango_feeds_connector::solana_rpc_minimal::rpc_accounts_scan::RpcAccountsScanClient; use solana_account_decoder::UiAccountEncoding; use solana_client::rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}; use solana_client::rpc_response::OptionalContext; @@ -31,7 +31,7 @@ async fn main() -> anyhow::Result<()> { let rpc_http_url = cli.rpc_url; let program_id = cli.program_account; - let rpc_client_scan = http::connect::(&rpc_http_url) + let rpc_client_scan = http::connect::(&rpc_http_url) .await .unwrap(); diff --git a/connector/examples/websocket_example_consumer.rs b/connector/examples/websocket_example_consumer.rs index 138427e..d3f11a7 100644 --- a/connector/examples/websocket_example_consumer.rs +++ b/connector/examples/websocket_example_consumer.rs @@ -27,10 +27,10 @@ async fn main() -> anyhow::Result<()> { grpc_sources: vec![], // used for websocket+geyser snapshot: SnapshotSourceConfig { - rpc_http_url: "http://127.0.0.1:8899".to_string(), + rpc_http_url: "http://localhost:18899/".to_string(), }, // used only for websocket - rpc_ws_url: "ws://localhost:8900/".to_string(), + rpc_ws_url: "ws://localhost:18900/".to_string(), }; let filter_config1 = FilterConfig { diff --git a/connector/src/lib.rs b/connector/src/lib.rs index df86a62..8809b89 100644 --- a/connector/src/lib.rs +++ b/connector/src/lib.rs @@ -3,6 +3,7 @@ pub mod chain_data; pub mod grpc_plugin_source; pub mod metrics; pub mod snapshot; +pub mod solana_rpc_minimal; pub mod websocket_source; use itertools::Itertools; @@ -12,8 +13,6 @@ use { solana_sdk::{account::Account, pubkey::Pubkey}, }; -pub use solana_rpc::rpc::rpc_accounts_scan::AccountsScanClient as GetProgramAccountsClient; - pub use solana_sdk; trait AnyhowWrap { diff --git a/connector/src/snapshot.rs b/connector/src/snapshot.rs index a8cf655..5cb0101 100644 --- a/connector/src/snapshot.rs +++ b/connector/src/snapshot.rs @@ -5,9 +5,9 @@ use solana_client::{ rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}, rpc_response::{OptionalContext, RpcKeyedAccount}, }; -use solana_rpc::rpc::rpc_accounts::AccountsDataClient; use solana_sdk::{commitment_config::CommitmentConfig, slot_history::Slot}; +use crate::solana_rpc_minimal::rpc_accounts_scan::RpcAccountsScanClient; use crate::AnyhowWrap; /// gPA snapshot struct @@ -27,7 +27,7 @@ pub async fn get_snapshot_gpa( rpc_http_url: String, program_id: String, ) -> anyhow::Result { - let rpc_client = http::connect::(&rpc_http_url) + let rpc_client = http::connect::(&rpc_http_url) .await .map_err_anyhow()?; @@ -66,7 +66,7 @@ pub async fn get_snapshot_gma( rpc_http_url: &str, ids: Vec, ) -> anyhow::Result { - let rpc_client = http::connect::(rpc_http_url) + let rpc_client = http::connect::(rpc_http_url) .await .map_err_anyhow()?; diff --git a/connector/src/solana_rpc_minimal.rs b/connector/src/solana_rpc_minimal.rs new file mode 100644 index 0000000..fe20cfa --- /dev/null +++ b/connector/src/solana_rpc_minimal.rs @@ -0,0 +1,120 @@ +pub mod rpc_accounts_scan { + use jsonrpc_core::Result; + use jsonrpc_derive::rpc; + use solana_account_decoder::UiAccount; + use solana_rpc_client_api::config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}; + use solana_rpc_client_api::response::{ + OptionalContext, Response as RpcResponse, RpcKeyedAccount, + }; + + /// this definition is derived from solana-rpc/rpc.rs + /// we want to avoid the heavy dependency to solana-rpc + /// the crate solana-rpc-client provides some client methods but do not expose the ```Context```we need + /// + #[rpc] + pub trait RpcAccountsScan { + type Metadata; + + #[rpc(meta, name = "getProgramAccounts")] + fn get_program_accounts( + &self, + meta: Self::Metadata, + program_id_str: String, + config: Option, + ) -> Result>>; + + #[rpc(meta, name = "getMultipleAccounts")] + fn get_multiple_accounts( + &self, + meta: Self::Metadata, + pubkey_strs: Vec, + config: Option, + ) -> Result>>>; + } +} + +pub mod rpc_pubsub { + use jsonrpc_core::Result; + use jsonrpc_derive::rpc; + use jsonrpc_pubsub::typed::Subscriber; + use jsonrpc_pubsub::SubscriptionId as PubSubSubscriptionId; + use solana_account_decoder::UiAccount; + use solana_rpc_client_api::config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}; + use solana_rpc_client_api::response::{Response as RpcResponse, RpcKeyedAccount, SlotUpdate}; + use std::sync::Arc; + + #[rpc] + pub trait RpcSolPubSub { + type Metadata; + + #[pubsub( + subscription = "accountNotification", + subscribe, + name = "accountSubscribe" + )] + fn account_subscribe( + &self, + meta: Self::Metadata, + subscriber: Subscriber>, + pubkey_str: String, + config: Option, + ); + + #[pubsub( + subscription = "accountNotification", + unsubscribe, + name = "accountUnsubscribe" + )] + fn account_unsubscribe( + &self, + meta: Option, + id: PubSubSubscriptionId, + ) -> Result; + + #[pubsub( + subscription = "programNotification", + subscribe, + name = "programSubscribe" + )] + fn program_subscribe( + &self, + meta: Self::Metadata, + subscriber: Subscriber>, + pubkey_str: String, + config: Option, + ); + + #[pubsub( + subscription = "programNotification", + unsubscribe, + name = "programUnsubscribe" + )] + fn program_unsubscribe( + &self, + meta: Option, + id: PubSubSubscriptionId, + ) -> Result; + + #[pubsub( + subscription = "slotsUpdatesNotification", + subscribe, + name = "slotsUpdatesSubscribe" + )] + fn slots_updates_subscribe( + &self, + meta: Self::Metadata, + subscriber: Subscriber>, + ); + + #[pubsub( + subscription = "slotsUpdatesNotification", + unsubscribe, + name = "slotsUpdatesUnsubscribe" + )] + fn slots_updates_unsubscribe( + &self, + meta: Option, + id: PubSubSubscriptionId, + ) -> Result; + } +} diff --git a/connector/src/websocket_source.rs b/connector/src/websocket_source.rs index 31ed977..bc8dc82 100644 --- a/connector/src/websocket_source.rs +++ b/connector/src/websocket_source.rs @@ -6,7 +6,6 @@ use solana_client::{ rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}, rpc_response::{Response, RpcKeyedAccount}, }; -use solana_rpc::rpc_pubsub::RpcSolPubSubClient; use solana_sdk::{ account::Account, commitment_config::CommitmentConfig, pubkey::Pubkey, slot_history::Slot, }; @@ -25,6 +24,7 @@ use tokio::time::timeout; use crate::snapshot::{ get_snapshot_gma, get_snapshot_gpa, SnapshotMultipleAccounts, SnapshotProgramAccounts, }; +use crate::solana_rpc_minimal::rpc_pubsub::RpcSolPubSubClient; use crate::{ chain_data::SlotStatus, AccountWrite, AnyhowWrap, EntityFilter, FeedMetadata, FilterConfig, SlotUpdate, SourceConfig,