Skip to content

Commit

Permalink
feat(inspect): tracing, Parameterize trait
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon-Becker committed Dec 9, 2023
1 parent 13b012d commit 8b65118
Show file tree
Hide file tree
Showing 16 changed files with 640 additions and 164 deletions.
5 changes: 5 additions & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
cmd.rpc_url = configuration.rpc_url;
}

// if the user has not specified a transpose api key, use the default
if cmd.transpose_api_key.is_none() {
cmd.transpose_api_key = Some(configuration.transpose_api_key);
}

inspect(cmd).await?;
}

Expand Down
32 changes: 17 additions & 15 deletions common/src/ether/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ pub async fn chain_id(rpc_url: &str) -> Result<u64, Box<dyn std::error::Error>>
// make sure the RPC provider isn't empty
if rpc_url.is_empty() {
logger.error("reading on-chain data requires an RPC provider. Use `heimdall --help` for more information.");
std::process::exit(1);
return Err(backoff::Error::Permanent(()))
}

// create new provider
let provider = match Provider::<Http>::try_from(rpc_url) {
Ok(provider) => provider,
Err(_) => {
logger.error(&format!("failed to connect to RPC provider '{}' .", &rpc_url));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand Down Expand Up @@ -107,15 +107,15 @@ pub async fn get_code(
// make sure the RPC provider isn't empty
if rpc_url.is_empty() {
logger.error("reading on-chain data requires an RPC provider. Use `heimdall --help` for more information.");
std::process::exit(1);
return Err(backoff::Error::Permanent(()))
}

// create new provider
let provider = match Provider::<Http>::try_from(rpc_url) {
Ok(provider) => provider,
Err(_) => {
logger.error(&format!("failed to connect to RPC provider '{}' .", &rpc_url));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -124,7 +124,7 @@ pub async fn get_code(
Ok(address) => address,
Err(_) => {
logger.error(&format!("failed to parse address '{}' .", &contract_address));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand Down Expand Up @@ -181,15 +181,15 @@ pub async fn get_transaction(
// make sure the RPC provider isn't empty
if rpc_url.is_empty() {
logger.error("reading on-chain data requires an RPC provider. Use `heimdall --help` for more information.");
std::process::exit(1);
return Err(backoff::Error::Permanent(()));
}

// create new provider
let provider = match Provider::<Http>::try_from(rpc_url) {
Ok(provider) => provider,
Err(_) => {
logger.error(&format!("failed to connect to RPC provider '{}' .", &rpc_url));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -198,7 +198,7 @@ pub async fn get_transaction(
Ok(transaction_hash) => transaction_hash,
Err(_) => {
logger.error(&format!("failed to parse transaction hash '{}' .", &transaction_hash));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -208,7 +208,7 @@ pub async fn get_transaction(
Some(tx) => tx,
None => {
logger.error(&format!("transaction '{}' doesn't exist.", &transaction_hash));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
},
Err(_) => {
Expand Down Expand Up @@ -265,7 +265,7 @@ pub async fn get_storage_diff(
Ok(provider) => provider,
Err(_) => {
logger.error(&format!("failed to connect to RPC provider '{}' .", &rpc_url));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -277,7 +277,7 @@ pub async fn get_storage_diff(
"failed to parse transaction hash '{}' .",
&transaction_hash
));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -293,7 +293,7 @@ pub async fn get_storage_diff(
&transaction_hash
));
logger.error(&format!("error: '{e}' ."));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -316,6 +316,7 @@ pub async fn get_storage_diff(
},
)
.await
.map_err(|_| Box::from("failed to get storage diff"))
}

/// Get the raw trace data of the provided transaction hash
Expand Down Expand Up @@ -350,7 +351,7 @@ pub async fn get_trace(
Ok(provider) => provider,
Err(_) => {
logger.error(&format!("failed to connect to RPC provider '{}' .", &rpc_url));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -362,7 +363,7 @@ pub async fn get_trace(
"failed to parse transaction hash '{}' .",
&transaction_hash
));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -381,7 +382,7 @@ pub async fn get_trace(
&transaction_hash
));
logger.error(&format!("error: '{e}' ."));
std::process::exit(1)
return Err(backoff::Error::Permanent(()))
}
};

Expand All @@ -391,6 +392,7 @@ pub async fn get_trace(
},
)
.await
.map_err(|_| Box::from("failed to get trace"))
}

// TODO: add tests
Expand Down
59 changes: 55 additions & 4 deletions common/src/resources/transpose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct TransposeResponse {
}

/// executes a transpose SQL query and returns the response
async fn _call_transpose(query: &str, api_key: &str) -> Option<TransposeResponse> {
async fn call_transpose(query: &str, api_key: &str) -> Option<TransposeResponse> {
// get a new logger
let logger = Logger::default();

Expand Down Expand Up @@ -115,7 +115,7 @@ pub async fn get_transaction_list(
bounds.1
);

let response = match _call_transpose(&query, api_key).await {
let response = match call_transpose(&query, api_key).await {
Some(response) => response,
None => {
logger.error("failed to get transaction list from Transpose");
Expand Down Expand Up @@ -197,7 +197,7 @@ pub async fn get_contract_creation(
"{{\"sql\":\"SELECT block_number, transaction_hash FROM {chain}.transactions WHERE TIMESTAMP = ( SELECT created_timestamp FROM {chain}.accounts WHERE address = '{address}' ) AND contract_address = '{address}'\",\"parameters\":{{}},\"options\":{{\"timeout\": 999999999}}}}",
);

let response = match _call_transpose(&query, api_key).await {
let response = match call_transpose(&query, api_key).await {
Some(response) => response,
None => {
logger.error("failed to get creation tx from Transpose");
Expand Down Expand Up @@ -237,7 +237,58 @@ pub async fn get_contract_creation(
}
};

return Some((block_number, transaction_hash))
return Some((block_number, transaction_hash));
};

None
}

/// Get the label for the given address.
///
/// ```
/// use heimdall_common::resources::transpose::get_label;
///
/// let address = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
/// let api_key = "YOUR_API_KEY";
///
/// // let label = get_label(address, api_key).await;
/// ```
pub async fn get_label(address: &str, api_key: &str) -> Option<String> {
// get a new logger
let logger = Logger::default();
let start_time = Instant::now();

// build the SQL query
let query = format!(
"{{\"sql\":\"SELECT COALESCE( (SELECT name FROM ethereum.contract_labels WHERE contract_address = '{address}' ), (SELECT ens_name FROM ethereum.ens_names WHERE primary_address = '{address}' LIMIT 1), (SELECT protocol_name FROM ethereum.protocols WHERE contract_address = '{address}' ), (SELECT symbol FROM ethereum.tokens WHERE contract_address = '{address}' ), (SELECT symbol FROM ethereum.collections WHERE contract_address = '{address}' ) ) as label\",\"parameters\":{{}},\"options\":{{\"timeout\": 999999999}}}}",
);

let response = match call_transpose(&query, api_key).await {
Some(response) => response,
None => {
logger.error("failed to get contract label from Transpose");
return None;
}
};

logger.debug(&format!("fetching contract creation took {:?}", start_time.elapsed()));

// parse the results
if let Some(result) = response.results.into_iter().next() {
let label: String = match result.get("label") {
Some(label) => match label.as_str() {
Some(label) => label.to_string(),
None => {
logger.error("failed to parse label from Transpose");
return None;
}
},
None => {
logger.error("failed to fetch label from Transpose response");
return None;
}
};
return Some(label);
};

None
Expand Down
43 changes: 43 additions & 0 deletions common/src/utils/hex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use ethers::types::{Bloom, Bytes, H160, H256, H64};

use super::strings::encode_hex;

pub trait ToLowerHex {
fn to_lower_hex(&self) -> String;
}

impl ToLowerHex for H256 {
fn to_lower_hex(&self) -> String {
format!("{:#032x}", self)
}
}

impl ToLowerHex for H160 {
fn to_lower_hex(&self) -> String {
format!("{:#020x}", self)
}
}

impl ToLowerHex for H64 {
fn to_lower_hex(&self) -> String {
format!("{:#016x}", self)
}
}

impl ToLowerHex for Bloom {
fn to_lower_hex(&self) -> String {
format!("{:#064x}", self)
}
}

impl ToLowerHex for Bytes {
fn to_lower_hex(&self) -> String {
format!("{:#0x}", self)
}
}

impl ToLowerHex for Vec<u8> {
fn to_lower_hex(&self) -> String {
encode_hex(self.to_vec())
}
}
9 changes: 4 additions & 5 deletions common/src/utils/io/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ use std::{
/// assert_eq!(short_path, "./something.json");
/// ```
pub fn short_path(path: &str) -> String {
let current_dir = match env::current_dir() {
Ok(dir) => dir.into_os_string().into_string().unwrap(),
Err(_) => std::process::exit(1),
};
path.replace(&current_dir, ".")
match env::current_dir() {
Ok(dir) => path.replace(&dir.into_os_string().into_string().unwrap(), "."),
Err(_) => path.to_owned(),
}
}

/// Write contents to a file on the disc
Expand Down
42 changes: 42 additions & 0 deletions common/src/utils/io/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,26 @@ impl TraceFactory {
self.add("call", parent_index, instruction, vec![title, returns])
}

pub fn add_call_with_extra(
&mut self,
parent_index: u32,
instruction: u32,
origin: String,
function_name: String,
args: Vec<String>,
returns: String,
extra: Vec<String>,
) -> u32 {
let title = format!(
"{}::{}({}) {}",
origin.bright_cyan(),
function_name.bright_cyan(),
args.join(", "),
extra.iter().map(|s| format!("[{}]", s)).collect::<Vec<String>>().join(" ").dimmed()
);
self.add("call", parent_index, instruction, vec![title, returns])
}

/// adds a contract creation trace
pub fn add_creation(
&mut self,
Expand Down Expand Up @@ -375,6 +395,28 @@ impl Default for Logger {
}
}

impl Default for TraceFactory {
fn default() -> Self {
// get the environment variable RUST_LOG and parse it
let level = match std::env::var("RUST_LOG") {
Ok(level) => match level.to_lowercase().as_str() {
"silent" => -1,
"error" => 0,
"warn" => 1,
"info" => 2,
"debug" => 3,
"trace" => 4,
"all" => 5,
"max" => 6,
_ => 1,
},
Err(_) => 2,
};

TraceFactory::new(level)
}
}

impl Logger {
/// create a new logger with the given verbosity
pub fn new(verbosity: &str) -> (Logger, TraceFactory) {
Expand Down
Loading

0 comments on commit 8b65118

Please sign in to comment.