Skip to content

Commit

Permalink
feat: support trace methods in provider (#481)
Browse files Browse the repository at this point in the history
  • Loading branch information
xJonathanLEI authored Oct 22, 2023
1 parent 711f73b commit 26f5c55
Show file tree
Hide file tree
Showing 8 changed files with 575 additions and 8 deletions.
79 changes: 78 additions & 1 deletion starknet-providers/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use starknet_core::types::{
ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter,
EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult,
MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate,
MaybePendingTransactionReceipt, MsgFromL1, SyncStatusType, Transaction,
MaybePendingTransactionReceipt, MsgFromL1, SimulatedTransaction, SimulationFlag,
SyncStatusType, Transaction, TransactionTrace, TransactionTraceWithHash,
};

use crate::{
Expand Down Expand Up @@ -551,6 +552,82 @@ impl Provider for AnyProvider {
),
}
}

async fn trace_transaction<H>(
&self,
transaction_hash: H,
) -> Result<TransactionTrace, ProviderError<Self::Error>>
where
H: AsRef<FieldElement> + Send + Sync,
{
match self {
Self::JsonRpcHttp(inner) => Ok(
<JsonRpcClient<HttpTransport> as Provider>::trace_transaction(
inner,
transaction_hash,
)
.await?,
),
Self::SequencerGateway(inner) => Ok(
<SequencerGatewayProvider as Provider>::trace_transaction(inner, transaction_hash)
.await?,
),
}
}

async fn simulate_transactions<B, T, S>(
&self,
block_id: B,
transactions: T,
simulation_flags: S,
) -> Result<Vec<SimulatedTransaction>, ProviderError<Self::Error>>
where
B: AsRef<BlockId> + Send + Sync,
T: AsRef<[BroadcastedTransaction]> + Send + Sync,
S: AsRef<[SimulationFlag]> + Send + Sync,
{
match self {
Self::JsonRpcHttp(inner) => Ok(
<JsonRpcClient<HttpTransport> as Provider>::simulate_transactions(
inner,
block_id,
transactions,
simulation_flags,
)
.await?,
),
Self::SequencerGateway(inner) => Ok(
<SequencerGatewayProvider as Provider>::simulate_transactions(
inner,
block_id,
transactions,
simulation_flags,
)
.await?,
),
}
}

async fn trace_block_transactions<H>(
&self,
block_hash: H,
) -> Result<Vec<TransactionTraceWithHash>, ProviderError<Self::Error>>
where
H: AsRef<FieldElement> + Send + Sync,
{
match self {
Self::JsonRpcHttp(inner) => Ok(
<JsonRpcClient<HttpTransport> as Provider>::trace_block_transactions(
inner, block_hash,
)
.await?,
),
Self::SequencerGateway(inner) => Ok(
<SequencerGatewayProvider as Provider>::trace_block_transactions(inner, block_hash)
.await?,
),
}
}
}

impl From<ProviderError<<JsonRpcClient<HttpTransport> as Provider>::Error>>
Expand Down
83 changes: 82 additions & 1 deletion starknet-providers/src/jsonrpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use starknet_core::{
EventFilterWithPage, EventsPage, FeeEstimate, FieldElement, FunctionCall,
InvokeTransactionResult, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs,
MaybePendingStateUpdate, MaybePendingTransactionReceipt, MsgFromL1, ResultPageRequest,
StarknetError, SyncStatusType, Transaction,
SimulatedTransaction, SimulationFlag, StarknetError, SyncStatusType, Transaction,
TransactionTrace, TransactionTraceWithHash,
},
};

Expand Down Expand Up @@ -77,6 +78,12 @@ pub enum JsonRpcMethod {
AddDeclareTransaction,
#[serde(rename = "starknet_addDeployAccountTransaction")]
AddDeployAccountTransaction,
#[serde(rename = "starknet_traceTransaction")]
TraceTransaction,
#[serde(rename = "starknet_simulateTransactions")]
SimulateTransactions,
#[serde(rename = "starknet_traceBlockTransactions")]
TraceBlockTransactions,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -111,6 +118,9 @@ pub enum JsonRpcRequestData {
AddInvokeTransaction(AddInvokeTransactionRequest),
AddDeclareTransaction(AddDeclareTransactionRequest),
AddDeployAccountTransaction(AddDeployAccountTransactionRequest),
TraceTransaction(TraceTransactionRequest),
SimulateTransactions(SimulateTransactionsRequest),
TraceBlockTransactions(TraceBlockTransactionsRequest),
}

#[derive(Debug, thiserror::Error)]
Expand Down Expand Up @@ -601,6 +611,65 @@ where
)
.await
}

/// For a given executed transaction, return the trace of its execution, including internal
/// calls
async fn trace_transaction<H>(
&self,
transaction_hash: H,
) -> Result<TransactionTrace, ProviderError<Self::Error>>
where
H: AsRef<FieldElement> + Send + Sync,
{
self.send_request(
JsonRpcMethod::TraceTransaction,
TraceTransactionRequestRef {
transaction_hash: transaction_hash.as_ref(),
},
)
.await
}

/// Simulate a given sequence of transactions on the requested state, and generate the execution
/// traces. If one of the transactions is reverted, raises CONTRACT_ERROR.
async fn simulate_transactions<B, TX, S>(
&self,
block_id: B,
transactions: TX,
simulation_flags: S,
) -> Result<Vec<SimulatedTransaction>, ProviderError<Self::Error>>
where
B: AsRef<BlockId> + Send + Sync,
TX: AsRef<[BroadcastedTransaction]> + Send + Sync,
S: AsRef<[SimulationFlag]> + Send + Sync,
{
self.send_request(
JsonRpcMethod::SimulateTransactions,
SimulateTransactionsRequestRef {
block_id: block_id.as_ref(),
transactions: transactions.as_ref(),
simulation_flags: simulation_flags.as_ref(),
},
)
.await
}

/// Retrieve traces for all transactions in the given block.
async fn trace_block_transactions<H>(
&self,
block_hash: H,
) -> Result<Vec<TransactionTraceWithHash>, ProviderError<Self::Error>>
where
H: AsRef<FieldElement> + Send + Sync,
{
self.send_request(
JsonRpcMethod::TraceBlockTransactions,
TraceBlockTransactionsRequestRef {
block_hash: block_hash.as_ref(),
},
)
.await
}
}

impl<'de> Deserialize<'de> for JsonRpcRequest {
Expand Down Expand Up @@ -725,6 +794,18 @@ impl<'de> Deserialize<'de> for JsonRpcRequest {
.map_err(error_mapper)?,
)
}
JsonRpcMethod::TraceTransaction => JsonRpcRequestData::TraceTransaction(
serde_json::from_value::<TraceTransactionRequest>(raw_request.params)
.map_err(error_mapper)?,
),
JsonRpcMethod::SimulateTransactions => JsonRpcRequestData::SimulateTransactions(
serde_json::from_value::<SimulateTransactionsRequest>(raw_request.params)
.map_err(error_mapper)?,
),
JsonRpcMethod::TraceBlockTransactions => JsonRpcRequestData::TraceBlockTransactions(
serde_json::from_value::<TraceBlockTransactionsRequest>(raw_request.params)
.map_err(error_mapper)?,
),
};

Ok(Self {
Expand Down
61 changes: 60 additions & 1 deletion starknet-providers/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use starknet_core::types::{
ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter,
EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult,
MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate,
MaybePendingTransactionReceipt, MsgFromL1, StarknetError, SyncStatusType, Transaction,
MaybePendingTransactionReceipt, MsgFromL1, SimulatedTransaction, SimulationFlag, StarknetError,
SyncStatusType, Transaction, TransactionTrace, TransactionTraceWithHash,
};
use std::error::Error;

Expand Down Expand Up @@ -202,6 +203,36 @@ pub trait Provider {
where
D: AsRef<BroadcastedDeployAccountTransaction> + Send + Sync;

/// For a given executed transaction, return the trace of its execution, including internal
/// calls
async fn trace_transaction<H>(
&self,
transaction_hash: H,
) -> Result<TransactionTrace, ProviderError<Self::Error>>
where
H: AsRef<FieldElement> + Send + Sync;

/// Simulate a given sequence of transactions on the requested state, and generate the execution
/// traces. If one of the transactions is reverted, raises CONTRACT_ERROR.
async fn simulate_transactions<B, T, S>(
&self,
block_id: B,
transactions: T,
simulation_flags: S,
) -> Result<Vec<SimulatedTransaction>, ProviderError<Self::Error>>
where
B: AsRef<BlockId> + Send + Sync,
T: AsRef<[BroadcastedTransaction]> + Send + Sync,
S: AsRef<[SimulationFlag]> + Send + Sync;

/// Retrieve traces for all transactions in the given block.
async fn trace_block_transactions<H>(
&self,
block_hash: H,
) -> Result<Vec<TransactionTraceWithHash>, ProviderError<Self::Error>>
where
H: AsRef<FieldElement> + Send + Sync;

/// Same as [estimate_fee], but only with one estimate.
async fn estimate_fee_single<R, B>(
&self,
Expand All @@ -223,6 +254,34 @@ pub trait Provider {
Err(ProviderError::ArrayLengthMismatch)
}
}

/// Same as [simulate_transactions], but only with one simulation.
async fn simulate_transaction<B, T, S>(
&self,
block_id: B,
transaction: T,
simulation_flags: S,
) -> Result<SimulatedTransaction, ProviderError<Self::Error>>
where
B: AsRef<BlockId> + Send + Sync,
T: AsRef<BroadcastedTransaction> + Send + Sync,
S: AsRef<[SimulationFlag]> + Send + Sync,
{
let mut result = self
.simulate_transactions(
block_id,
[transaction.as_ref().to_owned()],
simulation_flags,
)
.await?;

if result.len() == 1 {
// Unwrapping here is safe becuase we already checked length
Ok(result.pop().unwrap())
} else {
Err(ProviderError::ArrayLengthMismatch)
}
}
}

#[derive(Debug, thiserror::Error)]
Expand Down
6 changes: 6 additions & 0 deletions starknet-providers/src/sequencer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ pub enum GatewayClientError {
/// Model conversion error (only when using as [Provider])
#[error("unable to convert gateway models to jsonrpc types")]
ModelConversionError,
/// Simulating multiple transactions is not supported (only when using as [Provider])
#[error("simulating multiple transactions not supported")]
BulkSimulationNotSupported,
/// At least one of the simulation flags is not supported (only when using as [Provider])
#[error("unsupported simulation flag")]
UnsupportedSimulationFlag,
}

#[derive(Debug, thiserror::Error, Deserialize)]
Expand Down
Loading

0 comments on commit 26f5c55

Please sign in to comment.