From f2d4803d5ab7ce2c01cede80dfccf1285468a102 Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Thu, 30 May 2024 14:49:44 +0200 Subject: [PATCH] fix: tracing (#1137) * 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 --- .trunk/trunk.yaml | 4 +-- Cargo.lock | 2 +- Cargo.toml | 2 +- src/eth_provider/provider.rs | 13 ++++--- src/eth_rpc/servers/debug_rpc.rs | 9 +++++ src/eth_rpc/servers/eth_rpc.rs | 40 ++++++++++----------- src/eth_rpc/servers/trace_rpc.rs | 2 ++ src/tracing/database.rs | 4 +-- src/tracing/mod.rs | 62 ++++++++++++++++++++++++++++++++ 9 files changed, 104 insertions(+), 34 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index d670726ec..3f1387148 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -17,7 +17,7 @@ lint: disabled: - checkov enabled: - - actionlint@1.7.0 + - actionlint@1.7.1 - clippy@1.65.0 - git-diff-check - hadolint@2.12.0 @@ -31,7 +31,7 @@ lint: - taplo@0.8.1 - terrascan@1.19.1 - trivy@0.51.4 - - trufflehog@3.76.3 + - trufflehog@3.77.0 - yamllint@1.35.1 ignore: - linters: [ALL] diff --git a/Cargo.lock b/Cargo.lock index 752d796f6..9fc35fefd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8000,7 +8000,7 @@ dependencies = [ [[package]] name = "kakarot-rpc" -version = "0.6.15" +version = "0.6.17" dependencies = [ "alloy-primitives 0.7.2", "alloy-rlp", diff --git a/Cargo.toml b/Cargo.toml index ad3506be7..07c83da08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kakarot-rpc" -version = "0.6.16" +version = "0.6.17" edition = "2021" authors = [ "Abdelhamid Bakhta <@abdelhamidbakhta>", diff --git a/src/eth_provider/provider.rs b/src/eth_provider/provider.rs index 37ecc2327..7a13b89a7 100644 --- a/src/eth_provider/provider.rs +++ b/src/eth_provider/provider.rs @@ -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); diff --git a/src/eth_rpc/servers/debug_rpc.rs b/src/eth_rpc/servers/debug_rpc.rs index a07c74569..8a536e1fb 100644 --- a/src/eth_rpc/servers/debug_rpc.rs +++ b/src/eth_rpc/servers/debug_rpc.rs @@ -1,3 +1,4 @@ +#![allow(clippy::blocks_in_conditions)] use std::sync::Arc; use alloy_rlp::Encodable; @@ -26,6 +27,7 @@ impl DebugRpc

{ #[async_trait] impl DebugApiServer for DebugRpc

{ /// Returns an RLP-encoded header. + #[tracing::instrument(skip(self), err, fields(block_id = ?block_id))] async fn raw_header(&self, block_id: BlockId) -> Result { let mut res = Vec::new(); if let Some(header) = self @@ -43,6 +45,7 @@ impl DebugApiServer for DebugRpc

} /// Returns an RLP-encoded block. + #[tracing::instrument(skip(self), err, fields(block_id = ?block_id))] async fn raw_block(&self, block_id: BlockId) -> Result { let block = match block_id { BlockId::Hash(hash) => self.eth_provider.block_by_hash(hash.into(), true).await?, @@ -60,6 +63,7 @@ impl DebugApiServer for DebugRpc

/// 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> { let transaction = self.eth_provider.transaction_by_hash(hash).await?; @@ -83,6 +87,7 @@ impl DebugApiServer for DebugRpc

} /// 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> { let transactions = self.eth_provider.block_transactions(Some(block_id)).await?.unwrap_or_default(); let mut raw_transactions = Vec::with_capacity(transactions.len()); @@ -107,6 +112,7 @@ impl DebugApiServer for DebugRpc

} /// 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> { let receipts = self.eth_provider.block_receipts(Some(block_id)).await?.unwrap_or_default(); @@ -149,6 +155,7 @@ impl DebugApiServer for DebugRpc

} /// 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, @@ -161,6 +168,7 @@ impl DebugApiServer for DebugRpc

} /// 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, @@ -174,6 +182,7 @@ impl DebugApiServer for DebugRpc

} /// 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, diff --git a/src/eth_rpc/servers/eth_rpc.rs b/src/eth_rpc/servers/eth_rpc.rs index f90cd9429..5e2d36d94 100644 --- a/src/eth_rpc/servers/eth_rpc.rs +++ b/src/eth_rpc/servers/eth_rpc.rs @@ -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> { 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> { 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> { 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> { 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 { 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 { 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> { 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, @@ -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> { 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> { 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, @@ -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> { 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) -> Result { 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) -> Result { 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) -> Result { 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) -> Result { 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 { 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) -> Result { Ok(self.eth_provider.call(request, block_id).await?) } @@ -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) -> Result { Ok(self.eth_provider.estimate_gas(request, block_id).await?) } @@ -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, diff --git a/src/eth_rpc/servers/trace_rpc.rs b/src/eth_rpc/servers/trace_rpc.rs index 8bc44504b..4d2776502 100644 --- a/src/eth_rpc/servers/trace_rpc.rs +++ b/src/eth_rpc/servers/trace_rpc.rs @@ -23,6 +23,8 @@ impl TraceRpc

{ #[async_trait] impl TraceApiServer for TraceRpc

{ /// 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>> { let provider = Arc::new(&self.eth_provider); let tracer = TracerBuilder::new(provider).await?.with_block_id(block_id).await?.build()?; diff --git a/src/tracing/database.rs b/src/tracing/database.rs index 87dc179b5..1e5c9cae7 100644 --- a/src/tracing/database.rs +++ b/src/tracing/database.rs @@ -68,9 +68,7 @@ impl Database for EthDatabaseSnapshot

{ fn storage(&mut self, address: Address, index: U256) -> Result { 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 { diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index a58519d45..17f94e5de 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -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(); + } +}