use eot::{forks::*, Fork, OpCode, OpcodeRegistry};
#[test]
fn test_gas_cost_analysis() {
let opcodes_to_analyze = vec![
0x60, 0x60, 0x01, 0x54, 0x55, 0xf3, ];
let mut total_gas = 0;
for &byte in &opcodes_to_analyze {
if Cancun::has_opcode(byte) {
let opcode = Cancun::from(byte);
total_gas += opcode.gas_cost() as u64;
}
}
assert!(total_gas > 0);
assert!(total_gas < 1000); }
#[test]
fn test_fork_compatibility_check() {
let modern_opcodes = vec![0x5c, 0x5d];
for &opcode in &modern_opcodes {
assert!(!Frontier::has_opcode(opcode));
assert!(!Homestead::has_opcode(opcode));
assert!(!Byzantium::has_opcode(opcode));
assert!(!Constantinople::has_opcode(opcode));
assert!(!Istanbul::has_opcode(opcode));
assert!(!Berlin::has_opcode(opcode));
assert!(!London::has_opcode(opcode));
assert!(!Shanghai::has_opcode(opcode));
assert!(Cancun::has_opcode(opcode));
}
}
#[test]
fn test_contract_analysis_workflow() {
let _contract_bytecode = vec![
0x60, 0x80, 0x60, 0x40, 0x52, 0x34, 0x80, 0x15, 0x61, 0x00, 0x16, 0x57, 0x60, 0x00, 0x80, 0xfd, ];
let opcodes = vec![
0x60, 0x60, 0x52, 0x34, 0x80, 0x15, 0x61, 0x57, 0x60, 0x80, 0xfd,
];
let mut analysis = ContractAnalysis::new();
for &opcode_byte in &opcodes {
if Cancun::has_opcode(opcode_byte) {
let opcode = Cancun::from(opcode_byte);
analysis.add_opcode(opcode);
}
}
assert!(analysis.total_gas > 0);
assert!(analysis.uses_revert);
assert!(!analysis.uses_create);
assert!(!analysis.uses_transient_storage);
}
#[test]
fn test_minimal_fork_detection() {
let opcodes = vec![
0x01, 0xf4, 0xfd, 0x5f, ];
let min_fork = find_minimal_fork(&opcodes);
assert_eq!(min_fork, Fork::Shanghai);
}
#[test]
fn test_upgrade_path_analysis() {
let london_count = London::all_opcodes().len();
let shanghai_count = Shanghai::all_opcodes().len();
let cancun_count = Cancun::all_opcodes().len();
assert!(shanghai_count > london_count);
assert!(cancun_count > shanghai_count);
assert!(!London::has_opcode(0x5f)); assert!(Shanghai::has_opcode(0x5f));
assert!(!Shanghai::has_opcode(0x5c)); assert!(Cancun::has_opcode(0x5c)); }
#[test]
fn test_registry_comprehensive() {
let registry = OpcodeRegistry::new();
let frontier_opcodes = registry.get_opcodes(Fork::Frontier);
let cancun_opcodes = registry.get_opcodes(Fork::Cancun);
assert!(!frontier_opcodes.is_empty());
assert!(!cancun_opcodes.is_empty());
assert!(cancun_opcodes.len() > frontier_opcodes.len());
assert!(registry.is_opcode_available(Fork::Frontier, 0x01)); assert!(!registry.is_opcode_available(Fork::Frontier, 0xf4)); assert!(registry.is_opcode_available(Fork::Homestead, 0xf4)); assert!(registry.is_opcode_available(Fork::Cancun, 0x5c)); }
struct ContractAnalysis {
total_gas: u64,
uses_revert: bool,
uses_create: bool,
uses_transient_storage: bool,
opcode_count: usize,
}
impl ContractAnalysis {
fn new() -> Self {
Self {
total_gas: 0,
uses_revert: false,
uses_create: false,
uses_transient_storage: false,
opcode_count: 0,
}
}
fn add_opcode<T: OpCode>(&mut self, opcode: T) {
self.total_gas += opcode.gas_cost() as u64;
self.opcode_count += 1;
let byte_val: u8 = opcode.into();
match byte_val {
0xfd => self.uses_revert = true, 0xf0 | 0xf5 => self.uses_create = true, 0x5c | 0x5d => self.uses_transient_storage = true, _ => {}
}
}
}
fn find_minimal_fork(opcodes: &[u8]) -> Fork {
let forks = [
Fork::Frontier,
Fork::Homestead,
Fork::Byzantium,
Fork::Constantinople,
Fork::Istanbul,
Fork::Berlin,
Fork::London,
Fork::Shanghai,
Fork::Cancun,
];
let registry = OpcodeRegistry::new();
for &fork in &forks {
let available = opcodes
.iter()
.all(|&opcode| registry.is_opcode_available(fork, opcode));
if available {
return fork;
}
}
Fork::Cancun }