Skip to content

Commit

Permalink
refactor(katana-rpc): starknet rpc clean up (#2205)
Browse files Browse the repository at this point in the history
  • Loading branch information
kariy authored Jul 23, 2024
1 parent a1c80c5 commit c87358e
Show file tree
Hide file tree
Showing 8 changed files with 478 additions and 374 deletions.
6 changes: 2 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ katana-executor = { path = "crates/katana/executor", default-features = false }
katana-primitives = { path = "crates/katana/primitives" }
katana-provider = { path = "crates/katana/storage/provider" }
katana-rpc = { path = "crates/katana/rpc/rpc" }
katana-rpc-api = { path = "crates/katana/rpc/rpc-api" }
katana-rpc-api = { path = "crates/katana/rpc/rpc-api", default-features = false }
katana-rpc-types = { path = "crates/katana/rpc/rpc-types" }
katana-rpc-types-builder = { path = "crates/katana/rpc/rpc-types-builder" }
katana-runner = { path = "crates/katana/runner" }
Expand Down Expand Up @@ -231,9 +231,7 @@ slot = { git = "https://github.com/cartridge-gg/slot", rev = "4c1165d" }
alloy-contract = { version = "0.2", default-features = false }
alloy-json-rpc = { version = "0.2", default-features = false }
alloy-network = { version = "0.2", default-features = false }
alloy-provider = { version = "0.2", default-features = false, features = [
"reqwest",
] }
alloy-provider = { version = "0.2", default-features = false, features = [ "reqwest" ] }
alloy-rpc-types-eth = { version = "0.2", default-features = false }
alloy-signer = { version = "0.2", default-features = false }
alloy-transport = { version = "0.2", default-features = false }
Expand Down
29 changes: 26 additions & 3 deletions crates/katana/rpc/rpc-api/src/starknet.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Starknet JSON-RPC specifications: <https://github.com/starkware-libs/starknet-specs>
use jsonrpsee::core::RpcResult;
use jsonrpsee::proc_macros::rpc;
use katana_primitives::block::{BlockIdOrTag, BlockNumber};
Expand All @@ -19,12 +21,14 @@ use katana_rpc_types::{
ContractClass, FeeEstimate, FeltAsHex, FunctionCall, SimulationFlag,
SimulationFlagForEstimateFee, SyncingStatus,
};
use starknet::core::types::{SimulatedTransaction, TransactionStatus};
use starknet::core::types::{
SimulatedTransaction, TransactionStatus, TransactionTrace, TransactionTraceWithHash,
};

/// The currently supported version of the Starknet JSON-RPC specification.
pub const RPC_SPEC_VERSION: &str = "0.7.1";

/// Starknet JSON-RPC APIs: <https://github.com/starkware-libs/starknet-specs>
/// Read API.
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "starknet"))]
#[cfg_attr(feature = "client", rpc(client, server, namespace = "starknet"))]
pub trait StarknetApi {
Expand Down Expand Up @@ -172,7 +176,12 @@ pub trait StarknetApi {
block_id: BlockIdOrTag,
contract_address: FieldElement,
) -> RpcResult<FeltAsHex>;
}

/// Write API.
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "starknet"))]
#[cfg_attr(feature = "client", rpc(client, server, namespace = "starknet"))]
pub trait StarknetWriteApi {
/// Submit a new transaction to be added to the chain.
#[method(name = "addInvokeTransaction")]
async fn add_invoke_transaction(
Expand All @@ -193,13 +202,27 @@ pub trait StarknetApi {
&self,
deploy_account_transaction: BroadcastedDeployAccountTx,
) -> RpcResult<DeployAccountTxResult>;
}

/// Trace API.
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "starknet"))]
#[cfg_attr(feature = "client", rpc(client, server, namespace = "starknet"))]
pub trait StarknetTraceApi {
/// Returns the execution trace of the transaction designated by the input hash.
#[method(name = "traceTransaction")]
async fn trace(&self, transaction_hash: TxHash) -> RpcResult<TransactionTrace>;

/// Simulates a list of transactions on the provided block.
#[method(name = "simulateTransactions")]
async fn simulate_transactions(
async fn simulate(
&self,
block_id: BlockIdOrTag,
transactions: Vec<BroadcastedTx>,
simulation_flags: Vec<SimulationFlag>,
) -> RpcResult<Vec<SimulatedTransaction>>;

/// Returns the execution traces of all transactions included in the given block.
#[method(name = "traceBlockTransactions")]
async fn trace_block(&self, block_id: BlockIdOrTag)
-> RpcResult<Vec<TransactionTraceWithHash>>;
}
8 changes: 6 additions & 2 deletions crates/katana/rpc/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use katana_executor::ExecutorFactory;
use katana_rpc_api::dev::DevApiServer;
use katana_rpc_api::katana::KatanaApiServer;
use katana_rpc_api::saya::SayaApiServer;
use katana_rpc_api::starknet::StarknetApiServer;
use katana_rpc_api::starknet::{StarknetApiServer, StarknetTraceApiServer, StarknetWriteApiServer};
use katana_rpc_api::torii::ToriiApiServer;
use katana_rpc_api::ApiKind;
use metrics::RpcServerMetrics;
Expand All @@ -46,7 +46,11 @@ pub async fn spawn<EF: ExecutorFactory>(
for api in &config.apis {
match api {
ApiKind::Starknet => {
methods.merge(StarknetApi::new(sequencer.clone()).into_rpc())?;
// TODO: merge these into a single logic.
let server = StarknetApi::new(sequencer.clone());
methods.merge(StarknetApiServer::into_rpc(server.clone()))?;
methods.merge(StarknetWriteApiServer::into_rpc(server.clone()))?;
methods.merge(StarknetTraceApiServer::into_rpc(server))?;
}
ApiKind::Katana => {
methods.merge(KatanaApi::new(sequencer.clone()).into_rpc())?;
Expand Down
99 changes: 99 additions & 0 deletions crates/katana/rpc/rpc/src/starknet/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! Server implementation for the Starknet JSON-RPC API.
mod read;
mod trace;
mod write;

use std::sync::Arc;

use katana_core::sequencer::KatanaSequencer;
use katana_executor::ExecutorFactory;
use katana_primitives::block::BlockIdOrTag;
use katana_primitives::transaction::ExecutableTxWithHash;
use katana_rpc_types::error::starknet::StarknetApiError;
use katana_rpc_types::FeeEstimate;
use katana_tasks::{BlockingTaskPool, TokioTaskSpawner};

#[allow(missing_debug_implementations)]
pub struct StarknetApi<EF: ExecutorFactory> {
inner: Arc<Inner<EF>>,
}

impl<EF: ExecutorFactory> Clone for StarknetApi<EF> {
fn clone(&self) -> Self {
Self { inner: Arc::clone(&self.inner) }
}
}

struct Inner<EF: ExecutorFactory> {
sequencer: Arc<KatanaSequencer<EF>>,
blocking_task_pool: BlockingTaskPool,
}

impl<EF: ExecutorFactory> StarknetApi<EF> {
pub fn new(sequencer: Arc<KatanaSequencer<EF>>) -> Self {
let blocking_task_pool =
BlockingTaskPool::new().expect("failed to create blocking task pool");
Self { inner: Arc::new(Inner { sequencer, blocking_task_pool }) }
}

async fn on_cpu_blocking_task<F, T>(&self, func: F) -> T
where
F: FnOnce(Self) -> T + Send + 'static,
T: Send + 'static,
{
let this = self.clone();
self.inner.blocking_task_pool.spawn(move || func(this)).await.unwrap()
}

async fn on_io_blocking_task<F, T>(&self, func: F) -> T
where
F: FnOnce(Self) -> T + Send + 'static,
T: Send + 'static,
{
let this = self.clone();
TokioTaskSpawner::new().unwrap().spawn_blocking(move || func(this)).await.unwrap()
}

fn estimate_fee_with(
&self,
transactions: Vec<ExecutableTxWithHash>,
block_id: BlockIdOrTag,
flags: katana_executor::SimulationFlag,
) -> Result<Vec<FeeEstimate>, StarknetApiError> {
let sequencer = &self.inner.sequencer;
// get the state and block env at the specified block for execution
let state = sequencer.state(&block_id).map_err(StarknetApiError::from)?;
let env = sequencer
.block_env_at(block_id)
.map_err(StarknetApiError::from)?
.ok_or(StarknetApiError::BlockNotFound)?;

// create the executor
let executor = sequencer.backend.executor_factory.with_state_and_block_env(state, env);
let results = executor.estimate_fee(transactions, flags);

let mut estimates = Vec::with_capacity(results.len());
for (i, res) in results.into_iter().enumerate() {
match res {
Ok(fee) => estimates.push(FeeEstimate {
gas_price: fee.gas_price.into(),
gas_consumed: fee.gas_consumed.into(),
overall_fee: fee.overall_fee.into(),
unit: fee.unit,
data_gas_price: Default::default(),
data_gas_consumed: Default::default(),
}),

Err(err) => {
return Err(StarknetApiError::TransactionExecutionError {
transaction_index: i,
execution_error: err.to_string(),
});
}
}
}

Ok(estimates)
}
}
Loading

0 comments on commit c87358e

Please sign in to comment.