revme/cmd/bench/
burntpix.rs

1pub mod static_data;
2
3use criterion::Criterion;
4use static_data::{
5    BURNTPIX_ADDRESS_ONE, BURNTPIX_ADDRESS_THREE, BURNTPIX_ADDRESS_TWO, BURNTPIX_BYTECODE_FOUR,
6    BURNTPIX_BYTECODE_ONE, BURNTPIX_BYTECODE_THREE, BURNTPIX_BYTECODE_TWO, BURNTPIX_MAIN_ADDRESS,
7    STORAGE_ONE, STORAGE_TWO, STORAGE_ZERO,
8};
9
10use alloy_sol_types::{sol, SolCall};
11use database::{CacheDB, BENCH_CALLER};
12use revm::{
13    database_interface::EmptyDB,
14    primitives::{hex, keccak256, Address, Bytes, TxKind, B256, U256},
15    state::{AccountInfo, Bytecode},
16    Context, ExecuteEvm, MainBuilder, MainContext,
17};
18
19use std::{error::Error, fs::File, io::Write};
20
21use std::str::FromStr;
22
23sol! {
24    #[derive(Debug, PartialEq, Eq)]
25    interface IBURNTPIX {
26        function run( uint32 seed, uint256 iterations) returns (string);
27    }
28}
29
30pub fn run(criterion: &mut Criterion) {
31    let (seed, iterations) = try_init_env_vars().expect("Failed to parse env vars");
32
33    let run_call_data = IBURNTPIX::runCall { seed, iterations }.abi_encode();
34
35    let db = init_db();
36
37    let mut evm = Context::mainnet()
38        .with_db(db)
39        .modify_tx_chained(|tx| {
40            tx.caller = BENCH_CALLER;
41            tx.kind = TxKind::Call(BURNTPIX_MAIN_ADDRESS);
42            tx.data = run_call_data.clone().into();
43            tx.gas_limit = u64::MAX;
44        })
45        .build_mainnet();
46
47    criterion.bench_function("burntpix", |b| {
48        b.iter(|| {
49            evm.replay().unwrap();
50        })
51    });
52
53    //Collects the data and uses it to generate the svg after running the benchmark
54    /*
55    let tx_result = evm.replay().unwrap();
56    let return_data = match tx_result.result {
57        context::result::ExecutionResult::Success {
58            output, gas_used, ..
59        } => {
60            println!("Gas used: {:?}", gas_used);
61            match output {
62                context::result::Output::Call(value) => value,
63                _ => unreachable!("Unexpected output type"),
64            }
65        }
66        _ => unreachable!("Execution failed: {:?}", tx_result),
67    };
68
69    // Remove returndata offset and length from output
70    let returndata_offset = 64;
71    let data = &return_data[returndata_offset..];
72
73    // Remove trailing zeros
74    let trimmed_data = data
75        .split_at(data.len() - data.iter().rev().filter(|&x| *x == 0).count())
76        .0;
77    let file_name = format!("{}_{}", seed, iterations);
78
79    svg(file_name, trimmed_data).expect("Failed to store svg");
80    */
81}
82
83/// Actually generates the svg
84pub fn svg(filename: String, svg_data: &[u8]) -> Result<(), Box<dyn Error>> {
85    let current_dir = std::env::current_dir()?;
86    let svg_dir = current_dir.join("burntpix").join("svgs");
87    std::fs::create_dir_all(&svg_dir)?;
88
89    let file_path = svg_dir.join(format!("{}.svg", filename));
90    let mut file = File::create(file_path)?;
91    file.write_all(svg_data)?;
92
93    Ok(())
94}
95
96const DEFAULT_SEED: &str = "0";
97const DEFAULT_ITERATIONS: &str = "0x4E20"; // 20_000 iterations
98fn try_init_env_vars() -> Result<(u32, U256), Box<dyn Error>> {
99    let seed_from_env = std::env::var("SEED").unwrap_or(DEFAULT_SEED.to_string());
100    let seed: u32 = try_from_hex_to_u32(&seed_from_env)?;
101    let iterations_from_env = std::env::var("ITERATIONS").unwrap_or(DEFAULT_ITERATIONS.to_string());
102    let iterations = U256::from_str(&iterations_from_env)?;
103    Ok((seed, iterations))
104}
105
106fn try_from_hex_to_u32(hex: &str) -> Result<u32, Box<dyn Error>> {
107    let trimmed = hex.strip_prefix("0x").unwrap_or(hex);
108    u32::from_str_radix(trimmed, 16).map_err(|e| format!("Failed to parse hex: {}", e).into())
109}
110
111fn insert_account_info(cache_db: &mut CacheDB<EmptyDB>, addr: Address, code: &str) {
112    let code = Bytes::from(hex::decode(code).unwrap());
113    let code_hash = hex::encode(keccak256(&code));
114    let account_info = AccountInfo::new(
115        U256::from(0),
116        0,
117        B256::from_str(&code_hash).unwrap(),
118        Bytecode::new_raw(code),
119    );
120    cache_db.insert_account_info(addr, account_info);
121}
122
123fn init_db() -> CacheDB<EmptyDB> {
124    let mut cache_db = CacheDB::new(EmptyDB::default());
125
126    insert_account_info(&mut cache_db, BURNTPIX_ADDRESS_ONE, BURNTPIX_BYTECODE_ONE);
127    insert_account_info(&mut cache_db, BURNTPIX_MAIN_ADDRESS, BURNTPIX_BYTECODE_TWO);
128    insert_account_info(&mut cache_db, BURNTPIX_ADDRESS_TWO, BURNTPIX_BYTECODE_THREE);
129    insert_account_info(
130        &mut cache_db,
131        BURNTPIX_ADDRESS_THREE,
132        BURNTPIX_BYTECODE_FOUR,
133    );
134
135    cache_db
136        .insert_account_storage(
137            BURNTPIX_MAIN_ADDRESS,
138            U256::from(0),
139            U256::from_be_bytes(*STORAGE_ZERO),
140        )
141        .unwrap();
142
143    cache_db
144        .insert_account_storage(
145            BURNTPIX_MAIN_ADDRESS,
146            U256::from(1),
147            U256::from_be_bytes(*STORAGE_ONE),
148        )
149        .unwrap();
150
151    cache_db
152        .insert_account_storage(
153            BURNTPIX_MAIN_ADDRESS,
154            U256::from(2),
155            U256::from_be_bytes(*STORAGE_TWO),
156        )
157        .unwrap();
158
159    cache_db
160}