use crate::Fork;
pub trait OpcodeExt: crate::OpCode {
fn modifies_state(&self) -> bool {
matches!(
(*self).into(),
0x55 | 0x5d | 0xf0 | 0xf1 | 0xf2 | 0xf4 | 0xf5 | 0xff ) && (*self).into() != 0xfa }
fn can_revert(&self) -> bool {
matches!(
(*self).into(),
0xf1 | 0xf2 | 0xf4 | 0xf5 | 0xfa | 0xfd )
}
fn is_push(&self) -> bool {
let opcode = (*self).into();
(0x5f..=0x7f).contains(&opcode) }
fn push_size(&self) -> Option<u8> {
let opcode = (*self).into();
match opcode {
0x5f => Some(0), 0x60..=0x7f => Some(opcode - 0x5f), _ => None,
}
}
fn is_dup(&self) -> bool {
let opcode = (*self).into();
(0x80..=0x8f).contains(&opcode)
}
fn is_swap(&self) -> bool {
let opcode = (*self).into();
(0x90..=0x9f).contains(&opcode)
}
fn min_stack_depth(&self) -> u8 {
let metadata = self.metadata();
if self.is_dup() {
let opcode = (*self).into();
opcode - 0x7f } else if self.is_swap() {
let opcode = (*self).into();
opcode - 0x8e } else {
metadata.stack_inputs
}
}
}
impl<T: crate::OpCode> OpcodeExt for T {}
pub trait OpcodeComparison {
fn compare_gas_costs(opcode: u8, fork1: Fork, fork2: Fork) -> Option<(u16, u16)>;
fn get_changes_between_forks(fork1: Fork, fork2: Fork) -> Vec<OpcodeChange>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpcodeChange {
pub opcode: u8,
pub change_type: ChangeType,
pub old_value: Option<u16>,
pub new_value: Option<u16>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ChangeType {
Added,
Removed,
GasCostChanged,
StackBehaviorChanged,
SemanticsChanged,
}
pub trait ForkValidation {
fn validate_fork_consistency(fork: Fork) -> Result<(), Vec<String>>;
fn check_known_issues(fork: Fork) -> Vec<String>;
}
pub trait OpcodeAnalysis {
fn analyze_gas_usage(opcodes: &[u8], fork: Fork) -> GasAnalysis;
fn validate_opcode_sequence(opcodes: &[u8], fork: Fork) -> Result<(), String>;
}
#[derive(Debug, Clone)]
pub struct GasAnalysis {
pub total_gas: u64,
pub breakdown: Vec<(u8, u16)>,
pub optimizations: Vec<String>,
pub warnings: Vec<String>,
}