eth-etl-core 0.1.0

Core types and utilities for Ethereum ETL
Documentation
use serde::{Deserialize, Serialize};

/// Execution trace (call, create, suicide, reward)
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EthTrace {
    #[serde(rename = "type", default = "default_trace_type")]
    pub item_type: String,
    pub block_number: u64,
    pub transaction_hash: Option<String>,
    pub transaction_index: Option<u64>,
    pub trace_id: String,
    pub from_address: Option<String>,
    pub to_address: Option<String>,
    pub value: Option<String>,
    pub input: Option<String>,
    pub output: Option<String>,
    /// Type of trace: call, create, suicide, reward
    pub trace_type: String,
    /// Call type: call, callcode, delegatecall, staticcall
    #[serde(skip_serializing_if = "Option::is_none")]
    pub call_type: Option<String>,
    /// Reward type: block, uncle
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reward_type: Option<String>,
    pub gas: Option<u64>,
    pub gas_used: Option<u64>,
    pub subtraces: u64,
    /// Trace address as comma-separated string
    pub trace_address: String,
    pub error: Option<String>,
    /// 1 = success, 0 = failure
    pub status: u64,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub block_hash: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub block_timestamp: Option<u64>,
}

fn default_trace_type() -> String {
    "trace".to_string()
}

impl EthTrace {
    /// Get CSV headers for trace export
    pub fn csv_headers() -> &'static [&'static str] {
        &[
            "block_number",
            "transaction_hash",
            "transaction_index",
            "trace_id",
            "from_address",
            "to_address",
            "value",
            "input",
            "output",
            "trace_type",
            "call_type",
            "reward_type",
            "gas",
            "gas_used",
            "subtraces",
            "trace_address",
            "error",
            "status",
        ]
    }

    /// Convert to CSV row
    pub fn to_csv_row(&self) -> Vec<String> {
        vec![
            self.block_number.to_string(),
            self.transaction_hash.clone().unwrap_or_default(),
            self.transaction_index
                .map(|v| v.to_string())
                .unwrap_or_default(),
            self.trace_id.clone(),
            self.from_address.clone().unwrap_or_default(),
            self.to_address.clone().unwrap_or_default(),
            self.value.clone().unwrap_or_default(),
            self.input.clone().unwrap_or_default(),
            self.output.clone().unwrap_or_default(),
            self.trace_type.clone(),
            self.call_type.clone().unwrap_or_default(),
            self.reward_type.clone().unwrap_or_default(),
            self.gas.map(|v| v.to_string()).unwrap_or_default(),
            self.gas_used.map(|v| v.to_string()).unwrap_or_default(),
            self.subtraces.to_string(),
            self.trace_address.clone(),
            self.error.clone().unwrap_or_default(),
            self.status.to_string(),
        ]
    }
}

/// Geth trace format from debug_traceBlockByNumber with callTracer
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct GethTrace {
    pub block_number: u64,
    pub transaction_hash: String,
    pub transaction_index: u64,
    #[serde(rename = "type")]
    pub trace_type: String,
    pub from_address: String,
    pub to_address: Option<String>,
    pub value: Option<String>,
    pub input: Option<String>,
    pub output: Option<String>,
    pub gas: Option<u64>,
    pub gas_used: Option<u64>,
    pub error: Option<String>,
    pub calls: Vec<GethTrace>,
    pub trace_address: String,
    pub trace_id: String,
}