mod bundles;
use std::fs;
use anyhow::Context;
use fvm::trace::{ExecutionEvent, ExecutionTrace};
use fvm_integration_tests::{tester, testkit};
use fvm_shared::address::Address;
use fvm_shared::error::ExitCode;
const CONTRACT_PATH: &str = "../../tools/contracts/gas-stress/recursive.bin";
#[test]
fn test_gasfuzz() {
let trace = gasfuzz_get_exec_trace();
let mut charge_points_milligas = Vec::new();
let mut aggregate_charge = 0u64;
for tr in trace.iter() {
if let ExecutionEvent::GasCharge(ch) = tr {
let this_charge = ch.total();
aggregate_charge += this_charge.as_milligas();
charge_points_milligas.push(aggregate_charge);
}
}
gasfuzz_fuzz(charge_points_milligas);
}
fn gasfuzz_fuzz(charge_points_milligas: Vec<u64>) {
let options = tester::ExecutionOptions {
debug: false,
trace: false,
events: false,
};
let mut tester = bundles::new_basic_tester(options).unwrap();
let mut account = tester.create_basic_account().unwrap();
let contract = hex::decode(fs::read_to_string(CONTRACT_PATH).unwrap())
.context("error decoding contract")
.unwrap();
let create_res = testkit::fevm::create_contract(&mut tester, &mut account, &contract).unwrap();
assert!(create_res.msg_receipt.exit_code.is_success());
let create_return: testkit::fevm::CreateReturn =
create_res.msg_receipt.return_data.deserialize().unwrap();
let actor = Address::new_id(create_return.actor_id);
println!(
"Fuzzing gas for {} charge points",
charge_points_milligas.len()
);
for cpm in charge_points_milligas[1..].iter() {
println!("Fuzzing gas at {}", cpm / 1000);
let gas_lo = (cpm - 500) / 1000;
let invoke_res =
testkit::fevm::invoke_contract(&mut tester, &mut account, actor, &[], gas_lo).unwrap();
assert_eq!(
invoke_res.msg_receipt.exit_code,
ExitCode::SYS_OUT_OF_GAS,
"{:?}",
invoke_res.failure_info,
);
let gas_hi = (cpm + 500) / 1000;
let invoke_res =
testkit::fevm::invoke_contract(&mut tester, &mut account, actor, &[], gas_hi).unwrap();
assert_eq!(
invoke_res.msg_receipt.exit_code,
ExitCode::SYS_OUT_OF_GAS,
"{:?}",
invoke_res.failure_info
);
}
}
fn gasfuzz_get_exec_trace() -> ExecutionTrace {
let options = tester::ExecutionOptions {
debug: false,
trace: true,
events: false,
};
let mut tester = bundles::new_basic_tester(options).unwrap();
let mut account = tester.create_basic_account().unwrap();
let contract = hex::decode(fs::read_to_string(CONTRACT_PATH).unwrap())
.context("error decoding contract")
.unwrap();
let create_res = testkit::fevm::create_contract(&mut tester, &mut account, &contract).unwrap();
assert!(
create_res.msg_receipt.exit_code.is_success(),
"{:?}",
create_res.failure_info
);
let create_return: testkit::fevm::CreateReturn =
create_res.msg_receipt.return_data.deserialize().unwrap();
let actor = Address::new_id(create_return.actor_id);
let gas = 12_000_000;
let invoke_res =
testkit::fevm::invoke_contract(&mut tester, &mut account, actor, &[], gas).unwrap();
assert_eq!(invoke_res.msg_receipt.exit_code, ExitCode::SYS_OUT_OF_GAS);
invoke_res.exec_trace
}