Skip to content

Commit

Permalink
fix: tracing (kkrt-labs#1137)
Browse files Browse the repository at this point in the history
* update tracing

* fix cache hit on storage for tracing

* add test for local debug of the tracing

* don't error on contract not found for storage

* typo
  • Loading branch information
greged93 authored May 30, 2024
1 parent 454eda3 commit f2d4803
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 34 deletions.
4 changes: 2 additions & 2 deletions .trunk/trunk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ lint:
disabled:
- checkov
enabled:
- [email protected].0
- [email protected].1
- [email protected]
- git-diff-check
- [email protected]
Expand All @@ -31,7 +31,7 @@ lint:
- [email protected]
- [email protected]
- [email protected]
- trufflehog@3.76.3
- trufflehog@3.77.0
- [email protected]
ignore:
- linters: [ALL]
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "kakarot-rpc"
version = "0.6.16"
version = "0.6.17"
edition = "2021"
authors = [
"Abdelhamid Bakhta <@abdelhamidbakhta>",
Expand Down
13 changes: 6 additions & 7 deletions src/eth_provider/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,14 +341,13 @@ where
let keys = split_u256(index.0);
let storage_address = get_storage_var_address("Account_storage", &keys).expect("Storage var name is not ASCII");

let storage = contract
.storage(&storage_address)
.block_id(starknet_block_id)
.call()
.await
.map_err(KakarotError::from)?
.value;
let maybe_storage = contract.storage(&storage_address).block_id(starknet_block_id).call().await;

if contract_not_found(&maybe_storage) || entrypoint_not_found(&maybe_storage) {
return Ok(U256::ZERO.into());
}

let storage = maybe_storage.map_err(KakarotError::from)?.value;
let low: U256 = into_via_wrapper!(storage.low);
let high: U256 = into_via_wrapper!(storage.high);
let storage: U256 = low + (high << 128);
Expand Down
9 changes: 9 additions & 0 deletions src/eth_rpc/servers/debug_rpc.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(clippy::blocks_in_conditions)]
use std::sync::Arc;

use alloy_rlp::Encodable;
Expand Down Expand Up @@ -26,6 +27,7 @@ impl<P: EthereumProvider> DebugRpc<P> {
#[async_trait]
impl<P: EthereumProvider + Send + Sync + 'static> DebugApiServer for DebugRpc<P> {
/// Returns an RLP-encoded header.
#[tracing::instrument(skip(self), err, fields(block_id = ?block_id))]
async fn raw_header(&self, block_id: BlockId) -> Result<Bytes> {
let mut res = Vec::new();
if let Some(header) = self
Expand All @@ -43,6 +45,7 @@ impl<P: EthereumProvider + Send + Sync + 'static> DebugApiServer for DebugRpc<P>
}

/// Returns an RLP-encoded block.
#[tracing::instrument(skip(self), err, fields(block_id = ?block_id))]
async fn raw_block(&self, block_id: BlockId) -> Result<Bytes> {
let block = match block_id {
BlockId::Hash(hash) => self.eth_provider.block_by_hash(hash.into(), true).await?,
Expand All @@ -60,6 +63,7 @@ impl<P: EthereumProvider + Send + Sync + 'static> DebugApiServer for DebugRpc<P>
/// Returns a EIP-2718 binary-encoded transaction.
///
/// If this is a pooled EIP-4844 transaction, the blob sidecar is included.
#[tracing::instrument(skip(self), err, fields(hash = ?hash))]
async fn raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
let transaction = self.eth_provider.transaction_by_hash(hash).await?;

Expand All @@ -83,6 +87,7 @@ impl<P: EthereumProvider + Send + Sync + 'static> DebugApiServer for DebugRpc<P>
}

/// Returns an array of EIP-2718 binary-encoded transactions for the given [BlockId].
#[tracing::instrument(skip(self), err, fields(block_id = ?block_id))]
async fn raw_transactions(&self, block_id: BlockId) -> Result<Vec<Bytes>> {
let transactions = self.eth_provider.block_transactions(Some(block_id)).await?.unwrap_or_default();
let mut raw_transactions = Vec::with_capacity(transactions.len());
Expand All @@ -107,6 +112,7 @@ impl<P: EthereumProvider + Send + Sync + 'static> DebugApiServer for DebugRpc<P>
}

/// Returns an array of EIP-2718 binary-encoded receipts.
#[tracing::instrument(skip(self), err, fields(block_id = ?block_id))]
async fn raw_receipts(&self, block_id: BlockId) -> Result<Vec<Bytes>> {
let receipts = self.eth_provider.block_receipts(Some(block_id)).await?.unwrap_or_default();

Expand Down Expand Up @@ -149,6 +155,7 @@ impl<P: EthereumProvider + Send + Sync + 'static> DebugApiServer for DebugRpc<P>
}

/// Returns the Geth debug trace for the given block number.
#[tracing::instrument(skip(self), err, fields(block_number = ?block_number, opts = ?opts))]
async fn trace_block_by_number(
&self,
block_number: BlockNumberOrTag,
Expand All @@ -161,6 +168,7 @@ impl<P: EthereumProvider + Send + Sync + 'static> DebugApiServer for DebugRpc<P>
}

/// Returns the Geth debug trace for the given block hash.
#[tracing::instrument(skip(self), err, fields(block_hash = ?block_hash, opts = ?opts))]
async fn trace_block_by_hash(
&self,
block_hash: B256,
Expand All @@ -174,6 +182,7 @@ impl<P: EthereumProvider + Send + Sync + 'static> DebugApiServer for DebugRpc<P>
}

/// Returns the Geth debug trace for the given transaction hash.
#[tracing::instrument(skip(self), err, fields(transaction_hash = ?transaction_hash, opts = ?opts))]
async fn trace_transaction(
&self,
transaction_hash: B256,
Expand Down
40 changes: 20 additions & 20 deletions src/eth_rpc/servers/eth_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,45 +61,45 @@ where
Ok(self.eth_provider.chain_id().await?)
}

#[tracing::instrument(skip_all, ret, err, fields(hash = %hash))]
#[tracing::instrument(skip(self), ret, err, fields(hash = %hash))]
async fn block_by_hash(&self, hash: B256, full: bool) -> Result<Option<RichBlock>> {
Ok(self.eth_provider.block_by_hash(hash, full).await?)
}

#[tracing::instrument(skip_all, err, fields(number = %number, full = full))]
#[tracing::instrument(skip(self), err, fields(number = %number, full = full))]
async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> Result<Option<RichBlock>> {
Ok(self.eth_provider.block_by_number(number, full).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(hash = %hash))]
#[tracing::instrument(skip(self), ret, err, fields(hash = %hash))]
async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
Ok(self.eth_provider.block_transaction_count_by_hash(hash).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(number = %number))]
#[tracing::instrument(skip(self), ret, err, fields(number = %number))]
async fn block_transaction_count_by_number(&self, number: BlockNumberOrTag) -> Result<Option<U256>> {
Ok(self.eth_provider.block_transaction_count_by_number(number).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(hash = %_hash))]
#[tracing::instrument(skip(self), ret, err, fields(hash = %_hash))]
async fn block_uncles_count_by_block_hash(&self, _hash: B256) -> Result<U256> {
tracing::warn!("Kakarot chain does not produce uncles");
Ok(U256::ZERO)
}

#[tracing::instrument(skip_all, ret, err, fields(number = %_number))]
#[tracing::instrument(skip(self), ret, err, fields(number = %_number))]
async fn block_uncles_count_by_block_number(&self, _number: BlockNumberOrTag) -> Result<U256> {
tracing::warn!("Kakarot chain does not produce uncles");
Ok(U256::ZERO)
}

#[tracing::instrument(skip_all, err, fields(hash = %_hash, index = ?_index))]
#[tracing::instrument(skip(self), err, fields(hash = %_hash, index = ?_index))]
async fn uncle_by_block_hash_and_index(&self, _hash: B256, _index: Index) -> Result<Option<RichBlock>> {
tracing::warn!("Kakarot chain does not produce uncles");
Ok(None)
}

#[tracing::instrument(skip_all, err, fields(hash = %_number, index = ?_index))]
#[tracing::instrument(skip(self), err, fields(hash = %_number, index = ?_index))]
async fn uncle_by_block_number_and_index(
&self,
_number: BlockNumberOrTag,
Expand All @@ -109,17 +109,17 @@ where
Ok(None)
}

#[tracing::instrument(skip_all, ret, err, fields(hash = %hash))]
#[tracing::instrument(skip(self), ret, err, fields(hash = %hash))]
async fn transaction_by_hash(&self, hash: B256) -> Result<Option<Transaction>> {
Ok(self.eth_provider.transaction_by_hash(hash).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(hash = %hash, index = ?index))]
#[tracing::instrument(skip(self), ret, err, fields(hash = %hash, index = ?index))]
async fn transaction_by_block_hash_and_index(&self, hash: B256, index: Index) -> Result<Option<Transaction>> {
Ok(self.eth_provider.transaction_by_block_hash_and_index(hash, index).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(number = %number, index = ?index))]
#[tracing::instrument(skip(self), ret, err, fields(number = %number, index = ?index))]
async fn transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
Expand All @@ -128,37 +128,37 @@ where
Ok(self.eth_provider.transaction_by_block_number_and_index(number, index).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(hash = %hash))]
#[tracing::instrument(skip(self), ret, err, fields(hash = %hash))]
async fn transaction_receipt(&self, hash: B256) -> Result<Option<TransactionReceipt>> {
Ok(self.eth_provider.transaction_receipt(hash).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(address = %address, block_id = ?block_id))]
#[tracing::instrument(skip(self), ret, err, fields(address = %address, block_id = ?block_id))]
async fn balance(&self, address: Address, block_id: Option<BlockId>) -> Result<U256> {
Ok(self.eth_provider.balance(address, block_id).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(address = %address, index = ?index, block_id = ?block_id))]
#[tracing::instrument(skip(self), ret, err, fields(address = %address, index = ?index, block_id = ?block_id))]
async fn storage_at(&self, address: Address, index: JsonStorageKey, block_id: Option<BlockId>) -> Result<B256> {
Ok(self.eth_provider.storage_at(address, index, block_id).await?)
}

#[tracing::instrument(skip_all, ret, err, fields(address = %address, block_id = ?block_id))]
#[tracing::instrument(skip(self), ret, err, fields(address = %address, block_id = ?block_id))]
async fn transaction_count(&self, address: Address, block_id: Option<BlockId>) -> Result<U256> {
Ok(self.eth_provider.transaction_count(address, block_id).await?)
}

#[tracing::instrument(skip_all, err, fields(address = %address, block_id = ?block_id))]
#[tracing::instrument(skip(self), err, fields(address = %address, block_id = ?block_id))]
async fn get_code(&self, address: Address, block_id: Option<BlockId>) -> Result<Bytes> {
Ok(self.eth_provider.get_code(address, block_id).await?)
}

#[tracing::instrument(skip_all, err, fields(filter = ?filter))]
#[tracing::instrument(skip(self), err, fields(filter = ?filter))]
async fn get_logs(&self, filter: Filter) -> Result<FilterChanges> {
Ok(self.eth_provider.get_logs(filter).await?)
}

#[tracing::instrument(skip_all, err, fields(block_id = ?block_id))]
#[tracing::instrument(skip(self, request), err, fields(block_id = ?block_id, gas_limit = request.gas))]
async fn call(&self, request: TransactionRequest, block_id: Option<BlockId>) -> Result<Bytes> {
Ok(self.eth_provider.call(request, block_id).await?)
}
Expand All @@ -171,7 +171,7 @@ where
Err(EthApiError::Unsupported("eth_createAccessList").into())
}

#[tracing::instrument(skip_all, ret, fields(block_id = ?block_id))]
#[tracing::instrument(skip(self, request), err, fields(block_id = ?block_id, gas_limit = request.gas))]
async fn estimate_gas(&self, request: TransactionRequest, block_id: Option<BlockId>) -> Result<U256> {
Ok(self.eth_provider.estimate_gas(request, block_id).await?)
}
Expand All @@ -181,7 +181,7 @@ where
Ok(self.eth_provider.gas_price().await?)
}

#[tracing::instrument(skip_all, ret, err, fields(block_count = ?block_count, newest_block = %newest_block, reward_percentiles = ?reward_percentiles))]
#[tracing::instrument(skip(self), ret, err, fields(block_count = ?block_count, newest_block = %newest_block, reward_percentiles = ?reward_percentiles))]
async fn fee_history(
&self,
block_count: U64,
Expand Down
2 changes: 2 additions & 0 deletions src/eth_rpc/servers/trace_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ impl<P: EthereumProvider> TraceRpc<P> {
#[async_trait]
impl<P: EthereumProvider + Send + Sync + 'static> TraceApiServer for TraceRpc<P> {
/// Returns the parity traces for the given block.
#[allow(clippy::blocks_in_conditions)]
#[tracing::instrument(skip(self), err, fields(block_id = ?block_id))]
async fn trace_block(&self, block_id: BlockId) -> Result<Option<Vec<LocalizedTransactionTrace>>> {
let provider = Arc::new(&self.eth_provider);
let tracer = TracerBuilder::new(provider).await?.with_block_id(block_id).await?.build()?;
Expand Down
4 changes: 1 addition & 3 deletions src/tracing/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ impl<P: EthereumProvider + Send + Sync> Database for EthDatabaseSnapshot<P> {
fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
let cache = &self.cache;
if let Some(account) = cache.accounts.get(&address) {
if let Some(storage) = account.storage.get(&index) {
return Ok(*storage);
}
return Ok(account.storage.get(&index).copied().unwrap_or_default());
}

let storage = Handle::current().block_on(async {
Expand Down
62 changes: 62 additions & 0 deletions src/tracing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,65 @@ where
{
tokio::task::block_in_place(|| evm.transact_commit().map_err(|err| TransactionError::Tracing(err.into()).into()))
}

#[cfg(test)]
mod tests {
use super::*;
use crate::eth_provider::database::Database;
use crate::eth_provider::provider::EthDataProvider;
use builder::TracerBuilder;
use hex::FromHex;
use mongodb::options::{DatabaseOptions, ReadConcern, WriteConcern};
use starknet::providers::{jsonrpc::HttpTransport, JsonRpcClient};
use std::sync::Arc;
use url::Url;

#[tokio::test(flavor = "multi_thread")]
#[ignore = "This test is used for debugging purposes only"]
async fn test_debug_tracing() {
// Set the env vars
std::env::set_var("KAKAROT_ADDRESS", "CHECK THE KAKAROT ADDRESS FOR THE BLOCK YOU ARE DEBUGGING");
std::env::set_var(
"UNINITIALIZED_ACCOUNT_CLASS_HASH",
"CHECK THE KAKAROT UNINITIALIZED ACCOUNT CLASS HASH FOR THE BLOCK YOU ARE DEBUGGING",
);

// Given
let url = Url::parse("https://juno-kakarot-dev.karnot.xyz/").unwrap();
let starknet_provider = JsonRpcClient::new(HttpTransport::new(url));

// Start a local mongodb instance with the state of the network:
// - Install `mongod`.
// - Run `brew services start mongodb-community` on MacOS.
// - Connect to the remote mongodb instance using MongoCompass and export the headers collection
// and the transactions collection. Instructions for exporting/importing can be found at
// `https://www.mongodb.com/docs/compass/current/import-export/`.
// - Connect to the local mongodb instance using MongoCompass.
// - Import the headers and transactions collections.
// - ‼️ You might need to manually fix some transactions that don't have an `accessList` field. ‼️
// - ‼️ Be sure to import the collections in the database called `local`. ‼️
let db_client = mongodb::Client::with_uri_str("mongodb://localhost:27017/").await.unwrap();
let db = Database::new(
db_client.database_with_options(
"local",
DatabaseOptions::builder()
.read_concern(ReadConcern::MAJORITY)
.write_concern(WriteConcern::MAJORITY)
.build(),
),
);

let eth_provider = Arc::new(EthDataProvider::new(db, starknet_provider).await.unwrap());
let tracer = TracerBuilder::new(eth_provider)
.await
.unwrap()
.with_transaction_hash(B256::from_hex("INSERT THE TRANSACTION HASH YOU WISH TO DEBUG").unwrap())
.await
.unwrap()
.build()
.unwrap();

// When
let _ = tracer.trace_block(TracingInspectorConfig::default_parity()).unwrap();
}
}

0 comments on commit f2d4803

Please sign in to comment.