Skip to content

Commit

Permalink
feat: Add read and write jsonrpc transport
Browse files Browse the repository at this point in the history
  • Loading branch information
clint committed Sep 27, 2023
1 parent 759d1b3 commit 61c905b
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 4 deletions.
21 changes: 21 additions & 0 deletions examples/rw_jsonrpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use starknet_providers::{
jsonrpc::{HttpTransport, JsonRpcClient, RwTransport},
Provider,
};
use url::Url;

#[tokio::main]
async fn main() {
let read = HttpTransport::new(
Url::parse("https://starknet-goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161")
.unwrap(),
);
let write = HttpTransport::new(
Url::parse("https://starknet-goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161")
.unwrap(),
);
let rw = RwTransport::new(read, write);
let rpc_client = JsonRpcClient::new(rw);
let block_number = rpc_client.block_number().await.unwrap();
dbg!(block_number);
}
6 changes: 4 additions & 2 deletions starknet-providers/src/jsonrpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ use crate::{
};

mod transports;
pub use transports::{HttpTransport, HttpTransportError, JsonRpcTransport};
pub use transports::{
HttpTransport, HttpTransportError, JsonRpcTransport, RwTransport, RwTransportError,
};

#[derive(Debug)]
pub struct JsonRpcClient<T> {
transport: T,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum JsonRpcMethod {
#[serde(rename = "starknet_getBlockWithTxHashes")]
GetBlockWithTxHashes,
Expand Down
2 changes: 1 addition & 1 deletion starknet-providers/src/jsonrpc/transports/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl JsonRpcTransport for HttpTransport {
) -> Result<JsonRpcResponse<R>, Self::Error>
where
P: Serialize + Send + Sync,
R: DeserializeOwned + Send + Sync,
R: DeserializeOwned + Send,
{
let request_body = JsonRpcRequest {
id: 1,
Expand Down
5 changes: 4 additions & 1 deletion starknet-providers/src/jsonrpc/transports/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use std::error::Error;
use crate::jsonrpc::{JsonRpcMethod, JsonRpcResponse};

mod http;
mod rw;

pub use http::{HttpTransport, HttpTransportError};
pub use rw::{RwTransport, RwTransportError};

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
Expand All @@ -21,5 +24,5 @@ pub trait JsonRpcTransport {
) -> Result<JsonRpcResponse<R>, Self::Error>
where
P: Serialize + Send + Sync,
R: DeserializeOwned + Send + Sync;
R: DeserializeOwned + Send;
}
124 changes: 124 additions & 0 deletions starknet-providers/src/jsonrpc/transports/rw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//! A [JsonRpcTransport] implementation that serves as a wrapper around two different [JsonRpcTransport]
//! and uses a dedicated client for read and the other for write operations
use std::{error::Error as StdError, fmt::Debug};

use async_trait::async_trait;
use serde::{de::DeserializeOwned, Serialize};
use thiserror::Error;

use crate::jsonrpc::{
JsonRpcMethod,
JsonRpcMethod::{AddDeclareTransaction, AddDeployAccountTransaction, AddInvokeTransaction},
JsonRpcResponse, JsonRpcTransport,
};

/// A client containing two clients.
///
/// One is used for _read_ operations
/// One is used for _write_ operations that consume gas `["starknet_addInvokeTransaction",
/// "starknet_addDeclareTransaction", "starknet_addDeployAccountTransaction"]`
///
/// **Note**: if the method is unknown this client falls back to the _read_ client
// # Example
#[derive(Debug, Clone)]
pub struct RwTransport<Read, Write> {
/// client used to read
r: Read,
/// client used to write
w: Write,
}

impl<Read, Write> RwTransport<Read, Write> {
/// Creates a new client using two different clients
///
/// # Example
///
/// ```no_run
/// # use url::Url;
/// async fn t(){
/// use starknet_providers::jsonrpc::{JsonRpcClient,HttpTransport,RwTransport};
/// let read = HttpTransport::new(Url::parse("http://localhost:5050").unwrap());
/// let write = HttpTransport::new(Url::parse("http://localhost:5050").unwrap());
/// let rw = RwTransport::new(read, write);
/// let client = JsonRpcClient::new(rw);
/// # }
/// ```
pub fn new(r: Read, w: Write) -> RwTransport<Read, Write> {
Self { r, w }
}

/// Returns the client used for read operations
pub fn read_client(&self) -> &Read {
&self.r
}

/// Returns the client used for write operations
pub fn write_client(&self) -> &Write {
&self.w
}

/// Returns a new `RwClient` with transposed clients
pub fn transpose(self) -> RwTransport<Write, Read> {
let RwTransport { r, w } = self;
RwTransport::new(w, r)
}

/// Consumes the client and returns the underlying clients
pub fn split(self) -> (Read, Write) {
let RwTransport { r, w } = self;
(r, w)
}
}

#[derive(Error, Debug)]
/// Error thrown when using either read or write client
pub enum RwTransportError<Read, Write>
where
Read: JsonRpcTransport,
<Read as JsonRpcTransport>::Error: StdError + Sync + Send,
Write: JsonRpcTransport,
<Write as JsonRpcTransport>::Error: StdError + Sync + Send,
{
/// Thrown if the _read_ request failed
#[error(transparent)]
Read(Read::Error),
#[error(transparent)]
/// Thrown if the _write_ request failed
Write(Write::Error),
}

#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<Read, Write> JsonRpcTransport for RwTransport<Read, Write>
where
Read: JsonRpcTransport + Debug + Send + Sync,
Write: JsonRpcTransport + Debug + Send + Sync,
{
type Error = RwTransportError<Read, Write>;

/// Sends a POST request with the provided method and the params serialized as JSON
/// over HTTP
async fn send_request<P, R>(
&self,
method: JsonRpcMethod,
params: P,
) -> Result<JsonRpcResponse<R>, Self::Error>
where
P: Serialize + Send + Sync,
R: DeserializeOwned + Send,
{
match method {
AddInvokeTransaction | AddDeclareTransaction | AddDeployAccountTransaction => self
.w
.send_request(method, params)
.await
.map_err(RwTransportError::Write),
_ => self
.r
.send_request(method, params)
.await
.map_err(RwTransportError::Read),
}
}
}

0 comments on commit 61c905b

Please sign in to comment.