Skip to content

Commit

Permalink
replace cursor with by block basis
Browse files Browse the repository at this point in the history
  • Loading branch information
kariy committed May 20, 2024
1 parent 855da31 commit 6d70126
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 291 deletions.
19 changes: 7 additions & 12 deletions crates/katana/rpc/rpc-api/src/saya.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
use jsonrpsee::core::RpcResult;
use jsonrpsee::proc_macros::rpc;
use katana_rpc_types::transaction::{TransactionsExecutionsPage, TransactionsPageCursor};
use katana_primitives::block::BlockIdOrTag;
use katana_rpc_types::trace::TxExecutionInfo;

#[cfg_attr(not(feature = "client"), rpc(server, namespace = "saya"))]
#[cfg_attr(feature = "client", rpc(client, server, namespace = "saya"))]
pub trait SayaApi {
/// Fetches the transaction execution info for all the transactions in the
/// given block.
///
/// # Arguments
///
/// * `block_number` - The block number to get executions from.
/// * `chunk_size` - The maximum number of transaction execution that should be returned.
#[method(name = "getTransactionsExecutions")]
async fn get_transactions_executions(
/// Retrieves a list of transaction execution informations of a given block.
#[method(name = "getTransactionExecutionsByBlock")]
async fn transaction_executions_by_block(
&self,
cursor: TransactionsPageCursor,
) -> RpcResult<TransactionsExecutionsPage>;
block_id: BlockIdOrTag,
) -> RpcResult<Vec<TxExecutionInfo>>;
}
13 changes: 12 additions & 1 deletion crates/katana/rpc/rpc-types/src/trace.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use katana_primitives::trace::CallInfo;
use katana_primitives::trace::{CallInfo, TxExecInfo};
use katana_primitives::transaction::TxHash;
use serde::{Deserialize, Serialize};
use starknet::core::types::{
CallType, EntryPointType, ExecutionResources, OrderedEvent, OrderedMessage,
};
Expand Down Expand Up @@ -72,3 +74,12 @@ impl From<CallInfo> for FunctionInvocation {
})
}
}

/// The type returned by the `saya_getTransactionExecutionsByBlock` RPC method.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TxExecutionInfo {
/// The transaction hash.
pub hash: TxHash,
/// The transaction execution trace.
pub trace: TxExecInfo,
}
7 changes: 0 additions & 7 deletions crates/katana/rpc/rpc-types/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use katana_primitives::conversion::rpc::{
compiled_class_hash_from_flattened_sierra_class, flattened_sierra_to_compiled_class,
legacy_rpc_to_compiled_class,
};
use katana_primitives::trace::TxExecInfo;
use katana_primitives::transaction::{
DeclareTx, DeclareTxV1, DeclareTxV2, DeclareTxV3, DeclareTxWithClass, DeployAccountTx,
DeployAccountTxV1, DeployAccountTxV3, InvokeTx, InvokeTxV1, InvokeTxV3, TxHash, TxWithHash,
Expand Down Expand Up @@ -519,9 +518,3 @@ pub struct TransactionsPage {
pub transactions: Vec<(TxWithHash, MaybePendingTxReceipt)>,
pub cursor: TransactionsPageCursor,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionsExecutionsPage {
pub transactions_executions: Vec<TxExecInfo>,
pub cursor: TransactionsPageCursor,
}
99 changes: 67 additions & 32 deletions crates/katana/rpc/rpc/src/saya.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ use std::sync::Arc;
use jsonrpsee::core::{async_trait, RpcResult};
use katana_core::sequencer::KatanaSequencer;
use katana_executor::ExecutorFactory;
use katana_primitives::block::BlockHashOrNumber;
use katana_provider::traits::transaction::TransactionTraceProvider;
use katana_primitives::block::{BlockIdOrTag, BlockTag};
use katana_provider::error::ProviderError;
use katana_provider::traits::block::{BlockIdReader, BlockProvider};
use katana_provider::traits::transaction::{TransactionTraceProvider, TransactionsProviderExt};
use katana_rpc_api::saya::SayaApiServer;
use katana_rpc_types::error::saya::SayaApiError;
use katana_rpc_types::transaction::{TransactionsExecutionsPage, TransactionsPageCursor};
use katana_rpc_types::trace::TxExecutionInfo;
use katana_tasks::TokioTaskSpawner;

pub struct SayaApi<EF: ExecutorFactory> {
Expand Down Expand Up @@ -37,39 +39,72 @@ impl<EF: ExecutorFactory> SayaApi<EF> {

#[async_trait]
impl<EF: ExecutorFactory> SayaApiServer for SayaApi<EF> {
async fn get_transactions_executions(
async fn transaction_executions_by_block(
&self,
cursor: TransactionsPageCursor,
) -> RpcResult<TransactionsExecutionsPage> {
block_id: BlockIdOrTag,
) -> RpcResult<Vec<TxExecutionInfo>> {
self.on_io_blocking_task(move |this| {
let provider = this.sequencer.backend.blockchain.provider();
let mut next_cursor = cursor;

let transactions_executions = provider
.transactions_executions_by_block(BlockHashOrNumber::Num(cursor.block_number))
.map_err(SayaApiError::from)?
.ok_or(SayaApiError::BlockNotFound)?;

let total_execs = transactions_executions.len() as u64;

let transactions_executions = transactions_executions
.into_iter()
.skip(cursor.transaction_index as usize)
.take(cursor.chunk_size as usize)
.collect::<Vec<_>>();

if cursor.transaction_index + cursor.chunk_size >= total_execs {
// All transactions of the block pointed by the cursor were fetched.
// Indicate to the client this situation by setting the block number
// to the next block and transaction index to 0.
next_cursor.block_number = cursor.block_number + 1;
next_cursor.transaction_index = 0;
} else {
next_cursor.transaction_index +=
cursor.transaction_index + transactions_executions.len() as u64;
}

Ok(TransactionsExecutionsPage { transactions_executions, cursor: next_cursor })
match block_id {
BlockIdOrTag::Tag(BlockTag::Pending) => {
// if there is no pending block (eg on instant mining), return an empty list
let Some(pending) = this.sequencer.pending_executor() else {
return Ok(Vec::new());
};

// get the read lock on the pending block
let lock = pending.read();

// extract the traces from the pending block
let mut traces = Vec::new();
for (tx, res) in lock.transactions() {
if let Some(trace) = res.trace().cloned() {
traces.push(TxExecutionInfo { hash: tx.hash, trace });
}
}

Ok(traces)
}

id => {
let number = provider
.convert_block_id(id)
.map_err(SayaApiError::from)?
.ok_or(SayaApiError::BlockNotFound)?;

// get the transaction traces and their corresponding hashes

let traces = provider
.transaction_executions_by_block(number.into())
.map_err(SayaApiError::from)?
.expect("qed; must be Some if block exists");

// get the block body indices for the requested block to determine its tx range
// in the db for the tx hashes

let block_indices = provider
.block_body_indices(number.into())
.map_err(SayaApiError::from)?
.ok_or(ProviderError::MissingBlockBodyIndices(number))
.expect("qed; must be Some if block exists");

// TODO: maybe we should add a `_by_block` method for the tx hashes as well?
let hashes = provider
.transaction_hashes_in_range(block_indices.clone().into())
.map_err(SayaApiError::from)?;

// build the rpc response

let traces = hashes
.into_iter()
.zip(traces)
.map(|(hash, trace)| TxExecutionInfo { hash, trace })
.collect::<Vec<_>>();

Ok(traces)
}
}
})
.await
}
Expand Down
204 changes: 0 additions & 204 deletions crates/katana/rpc/rpc/tests/saya.rs

This file was deleted.

Loading

0 comments on commit 6d70126

Please sign in to comment.