Skip to content

Commit

Permalink
docs: add docs for starknet-providers (#639)
Browse files Browse the repository at this point in the history
  • Loading branch information
xJonathanLEI authored Jul 29, 2024
1 parent 4726535 commit d297f81
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 38 deletions.
2 changes: 2 additions & 0 deletions starknet-providers/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ use crate::{
/// it's still needed anymore.
#[derive(Debug)]
pub enum AnyProvider {
/// JSON-RPC provider.
JsonRpcHttp(JsonRpcClient<HttpTransport>),
/// Sequencer gateway provider.
SequencerGateway(SequencerGatewayProvider),
}

Expand Down
103 changes: 101 additions & 2 deletions starknet-providers/src/jsonrpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,144 +24,242 @@ use crate::{provider::ProviderImplError, Provider, ProviderError};
mod transports;
pub use transports::{HttpTransport, HttpTransportError, JsonRpcTransport};

/// A generic JSON-RPC client with any transport.
///
/// A "transport" is any implementation that can send JSON-RPC requests and receive responses. This
/// most commonly happens over a network via HTTP connections, as with [`HttpTransport`].
#[derive(Debug)]
pub struct JsonRpcClient<T> {
transport: T,
}

/// All JSON-RPC methods as listed by the official specification.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum JsonRpcMethod {
/// The `starknet_specVersion` method.
#[serde(rename = "starknet_specVersion")]
SpecVersion,
/// The `starknet_getBlockWithTxHashes` method.
#[serde(rename = "starknet_getBlockWithTxHashes")]
GetBlockWithTxHashes,
/// The `starknet_getBlockWithTxs` method.
#[serde(rename = "starknet_getBlockWithTxs")]
GetBlockWithTxs,
/// The `starknet_getBlockWithReceipts` method.
#[serde(rename = "starknet_getBlockWithReceipts")]
GetBlockWithReceipts,
/// The `starknet_getStateUpdate` method.
#[serde(rename = "starknet_getStateUpdate")]
GetStateUpdate,
/// The `starknet_getStorageAt` method.
#[serde(rename = "starknet_getStorageAt")]
GetStorageAt,
/// The `starknet_getTransactionStatus` method.
#[serde(rename = "starknet_getTransactionStatus")]
GetTransactionStatus,
/// The `starknet_getTransactionByHash` method.
#[serde(rename = "starknet_getTransactionByHash")]
GetTransactionByHash,
/// The `starknet_getTransactionByBlockIdAndIndex` method.
#[serde(rename = "starknet_getTransactionByBlockIdAndIndex")]
GetTransactionByBlockIdAndIndex,
/// The `starknet_getTransactionReceipt` method.
#[serde(rename = "starknet_getTransactionReceipt")]
GetTransactionReceipt,
/// The `starknet_getClass` method.
#[serde(rename = "starknet_getClass")]
GetClass,
/// The `starknet_getClassHashAt` method.
#[serde(rename = "starknet_getClassHashAt")]
GetClassHashAt,
/// The `starknet_getClassAt` method.
#[serde(rename = "starknet_getClassAt")]
GetClassAt,
/// The `starknet_getBlockTransactionCount` method.
#[serde(rename = "starknet_getBlockTransactionCount")]
GetBlockTransactionCount,
/// The `starknet_call` method.
#[serde(rename = "starknet_call")]
Call,
/// The `starknet_estimateFee` method.
#[serde(rename = "starknet_estimateFee")]
EstimateFee,
/// The `starknet_estimateMessageFee` method.
#[serde(rename = "starknet_estimateMessageFee")]
EstimateMessageFee,
/// The `starknet_blockNumber` method.
#[serde(rename = "starknet_blockNumber")]
BlockNumber,
/// The `starknet_blockHashAndNumber` method.
#[serde(rename = "starknet_blockHashAndNumber")]
BlockHashAndNumber,
/// The `starknet_chainId` method.
#[serde(rename = "starknet_chainId")]
ChainId,
/// The `starknet_syncing` method.
#[serde(rename = "starknet_syncing")]
Syncing,
/// The `starknet_getEvents` method.
#[serde(rename = "starknet_getEvents")]
GetEvents,
/// The `starknet_getNonce` method.
#[serde(rename = "starknet_getNonce")]
GetNonce,
/// The `starknet_addInvokeTransaction` method.
#[serde(rename = "starknet_addInvokeTransaction")]
AddInvokeTransaction,
/// The `starknet_addDeclareTransaction` method.
#[serde(rename = "starknet_addDeclareTransaction")]
AddDeclareTransaction,
/// The `starknet_addDeployAccountTransaction` method.
#[serde(rename = "starknet_addDeployAccountTransaction")]
AddDeployAccountTransaction,
/// The `starknet_traceTransaction` method.
#[serde(rename = "starknet_traceTransaction")]
TraceTransaction,
/// The `starknet_simulateTransactions` method.
#[serde(rename = "starknet_simulateTransactions")]
SimulateTransactions,
/// The `starknet_traceBlockTransactions` method.
#[serde(rename = "starknet_traceBlockTransactions")]
TraceBlockTransactions,
}

/// JSON-RPC request.
#[derive(Debug, Clone)]
pub struct JsonRpcRequest {
/// ID of the request. Useful for identifying responses in certain transports like `WebSocket`.
pub id: u64,
/// Data of the requeest.
pub data: JsonRpcRequestData,
}

/// Typed request data for Starknet JSON-RPC requests.
#[derive(Debug, Clone)]
pub enum JsonRpcRequestData {
/// Request data for `starknet_specVersion`.
SpecVersion(SpecVersionRequest),
/// Request data for `starknet_getBlockWithTxHashes`.
GetBlockWithTxHashes(GetBlockWithTxHashesRequest),
/// Request data for `starknet_getBlockWithTxs`.
GetBlockWithTxs(GetBlockWithTxsRequest),
/// Request data for `starknet_getBlockWithReceipts`.
GetBlockWithReceipts(GetBlockWithReceiptsRequest),
/// Request data for `starknet_getStateUpdate`.
GetStateUpdate(GetStateUpdateRequest),
/// Request data for `starknet_getStorageAt`.
GetStorageAt(GetStorageAtRequest),
/// Request data for `starknet_getTransactionStatus`.
GetTransactionStatus(GetTransactionStatusRequest),
/// Request data for `starknet_getTransactionByHash`.
GetTransactionByHash(GetTransactionByHashRequest),
/// Request data for `starknet_getTransactionByBlockIdAndIndex`.
GetTransactionByBlockIdAndIndex(GetTransactionByBlockIdAndIndexRequest),
/// Request data for `starknet_getTransactionReceipt`.
GetTransactionReceipt(GetTransactionReceiptRequest),
/// Request data for `starknet_getClass`.
GetClass(GetClassRequest),
/// Request data for `starknet_getClassHashAt`.
GetClassHashAt(GetClassHashAtRequest),
/// Request data for `starknet_getClassAt`.
GetClassAt(GetClassAtRequest),
/// Request data for `starknet_getBlockTransactionCount`.
GetBlockTransactionCount(GetBlockTransactionCountRequest),
/// Request data for `starknet_call`.
Call(CallRequest),
/// Request data for `starknet_estimateFee`.
EstimateFee(EstimateFeeRequest),
/// Request data for `starknet_estimateMessageFee`.
EstimateMessageFee(EstimateMessageFeeRequest),
/// Request data for `starknet_blockNumber`.
BlockNumber(BlockNumberRequest),
/// Request data for `starknet_blockHashAndNumber`.
BlockHashAndNumber(BlockHashAndNumberRequest),
/// Request data for `starknet_chainId`.
ChainId(ChainIdRequest),
/// Request data for `starknet_syncing`.
Syncing(SyncingRequest),
/// Request data for `starknet_getEvents`.
GetEvents(GetEventsRequest),
/// Request data for `starknet_getNonce`.
GetNonce(GetNonceRequest),
/// Request data for `starknet_addInvokeTransaction`.
AddInvokeTransaction(AddInvokeTransactionRequest),
/// Request data for `starknet_addDeclareTransaction`.
AddDeclareTransaction(AddDeclareTransactionRequest),
/// Request data for `starknet_addDeployAccountTransaction`.
AddDeployAccountTransaction(AddDeployAccountTransactionRequest),
/// Request data for `starknet_traceTransaction`.
TraceTransaction(TraceTransactionRequest),
/// Request data for `starknet_simulateTransactions`.
SimulateTransactions(SimulateTransactionsRequest),
/// Request data for `starknet_traceBlockTransactions`.
TraceBlockTransactions(TraceBlockTransactionsRequest),
}

/// Errors from JSON-RPC client.
#[derive(Debug, thiserror::Error)]
pub enum JsonRpcClientError<T> {
/// JSON serialization/deserialization erors.
#[error(transparent)]
JsonError(serde_json::Error),
/// Transport-specific errors.
#[error(transparent)]
TransportError(T),
/// An unsuccessful response returned from the server is encountered.
#[error(transparent)]
JsonRpcError(JsonRpcError),
}

/// An unsuccessful response returned from the server.
#[derive(Debug, Deserialize)]
pub struct JsonRpcError {
/// Error code.
pub code: i64,
/// Error message.
pub message: String,
/// Additional error data if any.
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
}

/// JSON-RPC response returned from a server.
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum JsonRpcResponse<T> {
Success { id: u64, result: T },
Error { id: u64, error: JsonRpcError },
/// Successful response.
Success {
/// Same ID as the corresponding request.
id: u64,
/// Response data.
result: T,
},
/// Unsuccessful response.
Error {
/// Same ID as the corresponding request.
id: u64,
/// Error details.
error: JsonRpcError,
},
}

/// Failures trying to parse a [`JsonRpcError`] into [`StarknetError`].
///
/// [`StarknetError`] is the standard, provider-agnostic error type that all [`Provider`]
/// implementations should strive to return in an error case, in a best-effort basis. This allows
/// for unified error handling logic.
///
/// However, not all error cases can be properly converted, and this error type represents the cases
/// when such failure happens.
#[derive(Debug, thiserror::Error)]
pub enum JsonRpcErrorConversionError {
/// The error code is outside of the range specified by the specification.
#[error("unknown error code")]
UnknownCode,
/// Error data is expected but missing.
#[error("missing data field")]
MissingData,
/// Error data is malformed.
#[error("unable to parse the data field")]
DataParsingFailure,
}
Expand All @@ -175,6 +273,7 @@ struct Felt(#[serde_as(as = "UfeHex")] pub FeltPrimitive);
struct FeltArray(#[serde_as(as = "Vec<UfeHex>")] pub Vec<FeltPrimitive>);

impl<T> JsonRpcClient<T> {
/// Constructs a new [`JsonRpcClient`] from a transport.
pub const fn new(transport: T) -> Self {
Self { transport }
}
Expand Down
9 changes: 9 additions & 0 deletions starknet-providers/src/jsonrpc/transports/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@ use serde::{de::DeserializeOwned, Serialize};

use crate::jsonrpc::{transports::JsonRpcTransport, JsonRpcMethod, JsonRpcResponse};

/// A [`JsonRpcTransport`] implementation that uses HTTP connections.
#[derive(Debug)]
pub struct HttpTransport {
client: Client,
url: Url,
headers: Vec<(String, String)>,
}

/// Errors using [`HttpTransport`].
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub enum HttpTransportError {
/// HTTP-related errors.
Reqwest(reqwest::Error),
/// JSON serialization/deserialization errors.
Json(serde_json::Error),
}

Expand All @@ -28,10 +32,15 @@ struct JsonRpcRequest<T> {
}

impl HttpTransport {
/// Constructs [`HttpTransport`] from a JSON-RPC server URL, using default HTTP client settings.
///
/// To use custom HTTP settings (e.g. proxy, timeout), use
/// [`new_with_client`](fn.new_with_client) instead.
pub fn new(url: impl Into<Url>) -> Self {
Self::new_with_client(url, Client::new())
}

/// Constructs [`HttpTransport`] from a JSON-RPC server URL and a custom `reqwest` client.
pub fn new_with_client(url: impl Into<Url>, client: Client) -> Self {
Self {
client,
Expand Down
4 changes: 4 additions & 0 deletions starknet-providers/src/jsonrpc/transports/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ use crate::jsonrpc::{JsonRpcMethod, JsonRpcResponse};
mod http;
pub use http::{HttpTransport, HttpTransportError};

/// Any type that is capable of producing JSON-RPC responses when given JSON-RPC requests. An
/// implementation does not necessarily use the network, but typically does.
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[auto_impl(&, Box, Arc)]
pub trait JsonRpcTransport {
/// Possible errors processing requests.
type Error: Error + Send + Sync;

/// Sends a JSON-RPC request to retrieve a response.
async fn send_request<P, R>(
&self,
method: JsonRpcMethod,
Expand Down
12 changes: 11 additions & 1 deletion starknet-providers/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
#![doc = include_str!("../README.md")]
//! Clients for interacting with Starknet nodes and sequencers.
//!
//! This crate provides the [`Provider`] trait for abstraction over means of accessing the Starknet
//! network. The most commonly used implementation is [`JsonRpcClient`] with
//! [`HttpTransport`](jsonrpc::HttpTransport).
#![deny(missing_docs)]

mod provider;
pub use provider::{Provider, ProviderError};

// Sequencer-related functionalities are mostly deprecated so we skip the docs.
/// Module containing types related to the (now deprecated) sequencer gateway client.
#[allow(missing_docs)]
pub mod sequencer;
pub use sequencer::{
GatewayClientError as SequencerGatewayProviderError, SequencerGatewayProvider,
};

/// Module containing types related to JSON-RPC clients and servers.
pub mod jsonrpc;
pub use jsonrpc::JsonRpcClient;

Expand Down
Loading

0 comments on commit d297f81

Please sign in to comment.