Skip to content
Open
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,035 changes: 1,005 additions & 30 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ alloy-sol-types = "0.6"
alloy-dyn-abi = { version = "0.6", features = ["arbitrary", "eip712"] }
alloy-primitives = "0.6"
alloy-json-abi = "0.6"

# error handling
anyhow = "1.0"
thiserror = "1.0"
Expand All @@ -129,3 +130,9 @@ colored = "2.0"
evmole = "0.3.7"
semver = "1.0.22"

parquet = "52.0.0"
polars-core = "0.40.0"
polars-utils = "0.40.0"
polars = "0.40.0"

eyre = "0.6.12"
14 changes: 13 additions & 1 deletion src/evm/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,7 @@ mod tests {
let mut test_state = FuzzState::new(0);
let mutation_result =
abi.mutate::<EVMAddress, EVMAddress, EVMState, EVMFuzzState, ConciseEVMInput>(&mut test_state);
debug!("result: {:?} abi: {:?}", mutation_result, hex::encode(abi.get_bytes()));
println!("result: {:?} abi: {:?}", mutation_result, hex::encode(abi.get_bytes()));
}

#[test]
Expand Down Expand Up @@ -1412,6 +1412,18 @@ mod tests {
debug!("result: {:?} abi: {:?}", mutation_result, hex::encode(abibytes));
}

#[test]
fn test_struct_p() {
let mut abi = get_abi_type_boxed(&String::from(
"((bytes32,uint8,address,address,uint256,bytes),(address,bool,address,bool),uint256,uint256)",
));
abi.function = [82, 187, 190, 41];
let tx_data = "52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000b0b401d4761317e272e02c9513771768a10133870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b0b401d4761317e272e02c9513771768a101338700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b3c379d592b75990000000000000000000000000000000000000000000000000000000066675e5edc4a9779d6084c1ab3e815b67ed5e6780ccf4d900002000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086cba7808127d76deac14ec26ef6000aa78b2ebb000000000000000000000000000000000000000000000000000012309ce5400000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000014b0b401d4761317e272e02c9513771768a1013387000000000000000000000000";
let mut tx_data_vec = hex::decode(tx_data).unwrap();
abi.set_bytes(tx_data_vec);
println!("abi data is {:?}", abi.get_bytes());
}

#[test]
fn test_100_times() {
for _ in 0..100 {
Expand Down
1 change: 1 addition & 0 deletions src/evm/blaz/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod builder;
pub(crate) mod linking;
pub mod offchain_artifacts;
pub mod offchain_config;
pub mod offchain_cor;

fn get_client() -> reqwest::blocking::Client {
reqwest::blocking::Client::builder()
Expand Down
127 changes: 127 additions & 0 deletions src/evm/blaz/offchain_cor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use std::{
collections::{BTreeMap, HashMap},
default::Default,
str::FromStr,
};

use alloy_sol_types::SolValue;
use bytes::Bytes;
use ethers::{
abi::{ethereum_types, AbiEncode},
prelude::{Provider, ProviderExt},
providers::Middleware,
types::{AccountState, Address, Transaction, U256, U64},
};
use foundry_cheatcodes::Vm::VmCalls::rpc;
use libafl::prelude::{Scheduler, StdMapObserver};
use parquet::{
data_type::AsBytes,
file::reader::{FileReader, SerializedFileReader},
record::{Field, Row},
};
use primitive_types::H256;
use revm_interpreter::BytecodeLocked;
use revm_primitives::{BlockEnv, Bytecode, Env, B160};
use tracing::debug;

use crate::evm::{
abi::{get_abi_type_boxed, BoxedABI},
input::{ConciseEVMInput, EVMInput, EVMInputTy::ABI},
onchain::endpoints::{
Chain::{BSC, ETH},
OnChainConfig,
},
types::EVMAddress,
};

pub type CryoTestcases = Vec<Vec<ConciseEVMInput>>;

#[derive(Clone, Debug, Default)]
pub struct OffchainCor;

impl OffchainCor {
pub async fn get_call_env(rpc_url: &str, tx_hash: String) -> Env {
let provider = Provider::try_connect(rpc_url).await.expect("rpc connect error");
let req = H256::from_str(tx_hash.as_str()).unwrap();
let tx = provider
.get_transaction(req)
.await
.expect("tx_hash or rpc error")
.unwrap();
let block_id = tx.block_number.unwrap().as_u64();
let block_rep = provider
.get_block(block_id)
.await
.expect("block_number error ")
.unwrap();
println!("block number is {:?}", tx.block_number.unwrap().as_usize());
let block_env = BlockEnv {
number: U256::from(tx.block_number.unwrap().as_usize()).into(),
coinbase: Default::default(),
timestamp: block_rep.clone().timestamp.into(),
difficulty: block_rep.clone().difficulty.into(),
prevrandao: None,
basefee: Default::default(),
gas_limit: Default::default(),
};
Env {
cfg: Default::default(),
block: block_env,
tx: Default::default(),
}
}

pub async fn get_transaction(rpc_url: &str, tx_hash: String) -> ConciseEVMInput {
let provider = Provider::try_connect(rpc_url).await.expect("rpc connect error");
let req = H256::from_str(tx_hash.as_str()).unwrap();
let env = Self::get_call_env(rpc_url, tx_hash).await;
let tx_info = provider.get_transaction(req).await.expect("rpc error").unwrap();

let mut abi = get_abi_type_boxed(&String::from(
"((uint256,uint256,address,address,uint256,bytes),address,bool,address,bool,uint256,uint256)",
));
abi.function = [82, 187, 190, 41];
let tx_data = "52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000b0b401d4761317e272e02c9513771768a10133870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b0b401d4761317e272e02c9513771768a101338700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b3c379d592b75990000000000000000000000000000000000000000000000000000000066675e5edc4a9779d6084c1ab3e815b67ed5e6780ccf4d900002000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086cba7808127d76deac14ec26ef6000aa78b2ebb000000000000000000000000000000000000000000000000000012309ce5400000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000014b0b401d4761317e272e02c9513771768a1013387000000000000000000000000";
let mut tx_data_vec = hex::decode(tx_data).unwrap();
// println!("tx_data_vec1 is {:?}", tx_data_vec);
abi.set_bytes(tx_data_vec);
// println!("tx_data_vec2 is {:?}", abi.get_bytes());

let to_address = B160::from_slice(&tx_info.to.unwrap().0);
ConciseEVMInput {
input_type: ABI,
caller: tx_info.from.into(),
contract: to_address,
#[cfg(not(feature = "debug"))]
data: Some(abi),
txn_value: Some(tx_info.value.into()),
step: false,
env,
liquidation_percent: 0,
randomness: vec![],
repeat: 1,
layer: 0,
call_leak: 0,
return_data: None,
swap_data: Default::default(),
#[cfg(feature = "debug")]
direct_data: tx_info.input.to_string(),
}
}

pub fn generate_testcases_from_txhash(rpc_url: &str, tx_hash: String) -> CryoTestcases {
let mut cryo_testcases = vec![];
let mut test_case: Vec<ConciseEVMInput> = vec![];
let rt = tokio::runtime::Runtime::new().unwrap();
let tx_input = rt.block_on(OffchainCor::get_transaction(rpc_url, tx_hash));
test_case.push(tx_input);
cryo_testcases.push(test_case);
cryo_testcases
}
}

mod test {
use revm_primitives::Env;

use crate::evm::blaz::offchain_cor::OffchainCor;
}
1 change: 1 addition & 0 deletions src/evm/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub struct Config<VS, Addr, Code, By, Loc, SlotTy, Out, I, S, CI, E> {
pub load_corpus: String,
#[cfg(feature = "use_presets")]
pub preset_file_path: String,
pub load_crypo_corpus: Option<String>,
}

impl<VS, Addr, Code, By, Loc, SlotTy, Out, I, S, CI, E> Debug
Expand Down
5 changes: 5 additions & 0 deletions src/evm/corpus_initializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,3 +592,8 @@ where
}
}
}

mod test {
#[test]
fn test_load_crypo() {}
}
3 changes: 2 additions & 1 deletion src/evm/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use alloy_sol_types::SolValue;
use bytes::Bytes;
use itertools::Itertools;
use libafl::prelude::{HasMetadata, Scheduler};
use parquet::data_type::AsBytes;
use revm::precompile::{Precompile, Precompiles};
use revm_interpreter::{
analysis::to_analysed,
Expand Down Expand Up @@ -72,7 +73,7 @@ use super::{
use crate::{
evm::{
abi::{get_abi_type_boxed, register_abi_instance},
contract_utils::extract_sig_from_contract,
contract_utils::{extract_sig_from_contract, to_hex_string},
corpus_initializer::ABIMap,
input::{EVMInput, EVMInputTy},
middlewares::middleware::{add_corpus, CallMiddlewareReturn, Middleware, MiddlewareType},
Expand Down
9 changes: 8 additions & 1 deletion src/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ struct RPCCall {
}

/// CLI for ItyFuzz for EVM smart contracts
#[derive(Parser, Debug, Default)]
#[derive(Parser, Debug, Default, Clone)]
#[command(author, version, about, long_about = None, trailing_var_arg = true, allow_hyphen_values = true)]
pub struct EvmArgs {
/// Glob pattern / address to find contracts
Expand Down Expand Up @@ -269,6 +269,10 @@ pub struct EvmArgs {
#[arg(long, default_value = "")]
load_corpus: String,

/// Load corpus from crypo. If not specified, will use empty corpus.
#[arg(long, short = 'l', default_value = None)]
load_crypo_corpus: Option<String>,

/// [DEPRECATED] Specify the setup file that deploys all the contract.
/// Fuzzer invokes setUp() to deploy.
#[arg(long, default_value = "")]
Expand Down Expand Up @@ -812,6 +816,7 @@ pub fn evm_main(mut args: EvmArgs) {
preset_file_path: args.preset_file_path,
load_corpus: args.load_corpus,
etherscan_api_key,
load_crypo_corpus: args.load_crypo_corpus,
};

let mut abis_map: HashMap<String, Vec<Vec<serde_json::Value>>> = HashMap::new();
Expand All @@ -837,6 +842,7 @@ pub fn evm_main(mut args: EvmArgs) {
let abis_json = format!("{}/abis.json", args.work_dir.clone().as_str());

utils::try_write_file(&abis_json, &json_str, true).unwrap();

evm_fuzzer(config, &mut state)
}

Expand Down Expand Up @@ -987,6 +993,7 @@ fn test_evm_offchain_setup() {
preset_file_path: args.preset_file_path,
load_corpus: args.load_corpus,
etherscan_api_key: String::from(""),
load_crypo_corpus: args.load_crypo_corpus,
};

let mut abis_map: HashMap<String, Vec<Vec<serde_json::Value>>> = HashMap::new();
Expand Down
4 changes: 2 additions & 2 deletions src/evm/onchain/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ impl Chain {
Chain::CELO => "https://rpc.ankr.com/celo",
Chain::ZKEVM => "https://rpc.ankr.com/polygon_zkevm",
Chain::ZkevmTestnet => "https://rpc.ankr.com/polygon_zkevm_testnet",
Chain::BLAST => "https://rpc.ankr.com/blast",
Chain::BLAST => "https://lb.nodies.app/v1/041287f6f8c549fa8cf6d4f9b745206d",
Chain::LINEA => "https://rpc.ankr.com/linea",
Chain::IOTEX => "https://rpc.ankr.com/iotex",
Chain::LOCAL => "http://localhost:8545",
Expand All @@ -252,7 +252,7 @@ impl Chain {
Chain::CELO => "https://api.celoscan.io/api",
Chain::ZKEVM => "https://api-zkevm.polygonscan.com/api",
Chain::ZkevmTestnet => "https://api-testnet-zkevm.polygonscan.com/api",
Chain::BLAST => "https://api.routescan.io/v2/network/mainnet/evm/81457/etherscan",
Chain::BLAST => " https://api.blastscan.io/api",
Chain::LINEA => "https://api.lineascan.build/api",
Chain::LOCAL => "http://localhost:8080/abi/",
Chain::IOTEX => "https://babel-api.mainnet.IoTeX.io",
Expand Down
Loading
Loading