Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(executor): add EVM tracing listener #1234

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,171 changes: 559 additions & 612 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jemalloc = ["core-run/jemalloc"]
pprof = ["core-api/pprof"]
random_leader = ["core-consensus/random_leader"]
# tentacle_metrics = ["core-network/tentacle_metrics"]
tracing = ["core-run/tracing"]

[profile.release]
overflow-checks = true
Expand Down
2 changes: 1 addition & 1 deletion core/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ serde_json = "1.0"
common-apm = { path = "../../common/apm" }
common-config-parser = { path = "../../common/config-parser" }
core-consensus = { path = "../../core/consensus" }
core-executor = { path = "../../core/executor" }
core-executor = { path = "../../core/executor", features = ["tracing"] }
core-interoperation ={ path = "../../core/interoperation" }
either = { version = "1.8", features = ["serde"] }
protocol = { path = "../../protocol", package = "axon-protocol" }
Expand Down
19 changes: 15 additions & 4 deletions core/api/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use core_executor::{
use protocol::traits::{APIAdapter, Context, Executor, ExecutorAdapter, MemPool, Network, Storage};
use protocol::types::{
Account, BigEndianHash, Block, BlockNumber, Bytes, CkbRelatedInfo, ExecutorContext, Hash,
Header, Metadata, Proposal, Receipt, SignedTransaction, TxResp, H160, MAX_BLOCK_GAS_LIMIT,
NIL_DATA, RLP_NULL, U256,
Header, Metadata, Proposal, Receipt, SignedTransaction, TransactionTrace, TxResp, H160,
MAX_BLOCK_GAS_LIMIT, NIL_DATA, RLP_NULL, U256,
};
use protocol::{async_trait, codec::ProtocolCodec, trie, ProtocolResult};

Expand Down Expand Up @@ -182,7 +182,8 @@ where
data: Vec<u8>,
state_root: Hash,
mock_header: Proposal,
) -> ProtocolResult<TxResp> {
enable_trace: bool,
) -> ProtocolResult<(TxResp, Option<TransactionTrace>)> {
let mut exec_ctx = ExecutorContext::from(mock_header);
exec_ctx.origin = from.unwrap_or_default();
exec_ctx.gas_price = gas_price.unwrap_or_else(U256::one);
Expand All @@ -197,7 +198,17 @@ where
.map(|gas| gas.as_u64())
.unwrap_or(MAX_BLOCK_GAS_LIMIT);

Ok(AxonExecutor::default().call(&backend, gas_limit, from, to, value, data))
if enable_trace {
let ret =
AxonExecutor::default().tracing_call(&backend, gas_limit, from, to, value, data);

return Ok((ret.0, Some(ret.1)));
}

Ok((
AxonExecutor::default().call(&backend, gas_limit, from, to, value, data),
None,
))
}

async fn get_code_by_hash(&self, ctx: Context, hash: &Hash) -> ProtocolResult<Option<Bytes>> {
Expand Down
3 changes: 3 additions & 0 deletions core/api/src/jsonrpc/impl/web3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl<Adapter: APIAdapter> Web3RpcImpl<Adapter> {

let mock_header = mock_header_by_call_req(header, &req);

// Todo: change the enable_trace flag to false
self.adapter
.evm_call(
Context::new(),
Expand All @@ -88,8 +89,10 @@ impl<Adapter: APIAdapter> Web3RpcImpl<Adapter> {
data.to_vec(),
mock_header.state_root,
Proposal::new_without_state_root(&mock_header),
true,
)
.await
.map(|r| r.0)
}

async fn calculate_rewards(
Expand Down
1 change: 1 addition & 0 deletions core/consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ num-traits = "0.2"
[features]
default = []
random_leader = ["overlord/random_leader"]
tracing = ["core-executor/tracing"]

[[bench]]
harness = false
Expand Down
5 changes: 5 additions & 0 deletions core/executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ common-merkle = { path = "../../common/merkle" }
core-interoperation = { path = "../interoperation" }
ethers = "2.0"
evm = { version = "0.37", features = ["tracing"] }
evm-runtime = { version = "0.37", features = ["tracing"] }
futures = "0.3"
hasher = "0.1"
lazy_static = "1.4"
Expand All @@ -26,6 +27,7 @@ lru = "0.10"
molecule = "0.7"
parking_lot = "0.12"
protocol = { path = "../../protocol", package = "axon-protocol", default-features = false }
revm-interpreter = "1.1"
ripemd = "0.1"
rlp = "0.5"
rlp-derive = "0.1"
Expand All @@ -51,6 +53,9 @@ rlp = "0.5"
serde_json = "1.0"
tempfile = "3.3"

[features]
tracing = []

[[bench]]
harness = false
name = "bench_convert_u256"
Expand Down
11 changes: 0 additions & 11 deletions core/executor/src/debugger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ mod uniswap2;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};

use evm::tracing::{Event, EventListener};

use common_config_parser::parse_file;
use common_crypto::{PrivateKey, Secp256k1RecoverablePrivateKey, Signature};
use protocol::codec::{hex_decode, ProtocolCodec};
Expand Down Expand Up @@ -125,15 +123,6 @@ impl EvmDebugger {
}
}

#[derive(Default)]
pub struct EvmListener;

impl EventListener for EvmListener {
fn event(&mut self, event: Event) {
println!("EVM event {:?}", event);
}
}

pub fn mock_efficient_signed_tx(tx: Eip1559Transaction, private_key: &str) -> SignedTransaction {
let priv_key =
Secp256k1RecoverablePrivateKey::try_from(hex_decode(private_key).unwrap().as_ref())
Expand Down
68 changes: 50 additions & 18 deletions core/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod precompiles;
pub mod system_contract;
#[cfg(test)]
mod tests;
mod tracing;
mod utils;

pub use crate::adapter::{AxonExecutorAdapter, MPTTrie, RocksTrieDB};
Expand All @@ -25,15 +26,17 @@ use common_merkle::TrieMerkle;
use protocol::codec::ProtocolCodec;
use protocol::traits::{Backend, Executor, ExecutorAdapter};
use protocol::types::{
data_gas_cost, Account, Config, ExecResp, Hasher, SignedTransaction, TransactionAction, TxResp,
ValidatorExtend, GAS_CALL_TRANSACTION, GAS_CREATE_TRANSACTION, H160, NIL_DATA, RLP_NULL, U256,
data_gas_cost, Account, Config, ExecResp, Hasher, SignedTransaction, TransactionAction,
TransactionTrace, TxResp, ValidatorExtend, GAS_CALL_TRANSACTION, GAS_CREATE_TRANSACTION, H160,
NIL_DATA, RLP_NULL, U256,
};

use crate::precompiles::build_precompile_set;
use crate::system_contract::{
after_block_hook, before_block_hook, system_contract_dispatch, CkbLightClientContract,
ImageCellContract, MetadataContract, NativeTokenContract, SystemContract,
};
use crate::tracing::{trace_using, AxonListener};

lazy_static::lazy_static! {
pub static ref FEE_ALLOCATOR: ArcSwap<Box<dyn FeeAllocate>> = ArcSwap::from_pointee(Box::new(DefaultFeeAllocator::default()));
Expand Down Expand Up @@ -63,29 +66,23 @@ impl Executor for AxonExecutor {
value: U256,
data: Vec<u8>,
) -> TxResp {
let config = Config::london();
let config = self.config(false);
let metadata = StackSubstateMetadata::new(gas_limit, &config);
let state = MemoryStackState::new(metadata, backend);
let precompiles = build_precompile_set();
let mut executor = StackExecutor::new_with_precompiles(state, &config, &precompiles);

let from = from.unwrap_or_default();
let base_gas = if to.is_some() {
GAS_CALL_TRANSACTION + data_gas_cost(&data)
} else {
GAS_CREATE_TRANSACTION + GAS_CALL_TRANSACTION + data_gas_cost(&data)
};

let (exit, res) = if let Some(addr) = &to {
executor.transact_call(
from.unwrap_or_default(),
*addr,
value,
data,
gas_limit,
Vec::new(),
)
executor.transact_call(from, *addr, value, data, gas_limit, Vec::new())
} else {
executor.transact_create(from.unwrap_or_default(), value, data, gas_limit, Vec::new())
executor.transact_create(from, value, data, gas_limit, Vec::new())
};

let used_gas = executor.used_gas() + base_gas;
Expand All @@ -103,9 +100,7 @@ impl Executor for AxonExecutor {
code_address: if to.is_none() {
Some(
executor
.create_address(CreateScheme::Legacy {
caller: from.unwrap_or_default(),
})
.create_address(CreateScheme::Legacy { caller: from })
.into(),
)
} else {
Expand All @@ -128,7 +123,7 @@ impl Executor for AxonExecutor {
let mut hashes = Vec::with_capacity(txs_len);
let (mut gas, mut fee) = (0u64, U256::zero());
let precompiles = build_precompile_set();
let config = Config::london();
let config = self.config(block_number.is_zero());

// Execute system contracts before block hook.
before_block_hook(adapter);
Expand All @@ -139,8 +134,16 @@ impl Executor for AxonExecutor {

// Execute a transaction, if system contract dispatch return None, means the
// transaction called EVM
let mut r = system_contract_dispatch(adapter, tx)
.unwrap_or_else(|| Self::evm_exec(adapter, &config, &precompiles, tx));
let mut r = if cfg!(feature = "tracing") {
let mut listener = AxonListener::new();
trace_using(&mut listener, true, || {
system_contract_dispatch(adapter, tx)
.unwrap_or_else(|| Self::evm_exec(adapter, &config, &precompiles, tx))
})
} else {
system_contract_dispatch(adapter, tx)
.unwrap_or_else(|| Self::evm_exec(adapter, &config, &precompiles, tx))
};

r.logs = adapter.get_logs();
gas += r.gas_used;
Expand Down Expand Up @@ -293,6 +296,35 @@ impl AxonExecutor {
}
}

pub fn tracing_call<B: Backend>(
&self,
backend: &B,
gas_limit: u64,
from: Option<H160>,
to: Option<H160>,
value: U256,
data: Vec<u8>,
) -> (TxResp, TransactionTrace) {
let mut listener = AxonListener::new();
let resp = trace_using(&mut listener, false, || {
self.call(backend, gas_limit, from, to, value, data)
});

(resp, listener.finish().try_into().unwrap())
}

// Todo: add the is_genesis judgement
fn config(&self, _is_genesis: bool) -> Config {
let mut config = Config::london();

// if is_genesis {
// config.create_contract_limit = Some(0xc000);
// }

config.create_contract_limit = Some(0xc000);
config
}

#[cfg(test)]
fn test_exec<Adapter: ExecutorAdapter>(
&self,
Expand Down
Loading