use crate::{
eip7702::{Eip7702Bytecode, EIP7702_MAGIC_BYTES},
BytecodeDecodeError, JumpTable, LegacyAnalyzedBytecode, LegacyRawBytecode,
};
use primitives::{alloy_primitives::Sealable, keccak256, Address, Bytes, B256, KECCAK_EMPTY};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Bytecode {
Eip7702(Eip7702Bytecode),
LegacyAnalyzed(LegacyAnalyzedBytecode),
}
impl Default for Bytecode {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Sealable for Bytecode {
#[inline]
fn hash_slow(&self) -> B256 {
self.hash_slow()
}
}
impl Bytecode {
#[inline]
pub fn new() -> Self {
Self::LegacyAnalyzed(LegacyAnalyzedBytecode::default())
}
#[inline]
pub fn legacy_jump_table(&self) -> Option<&JumpTable> {
match &self {
Self::LegacyAnalyzed(analyzed) => Some(analyzed.jump_table()),
_ => None,
}
}
#[inline]
pub fn hash_slow(&self) -> B256 {
if self.is_empty() {
KECCAK_EMPTY
} else {
keccak256(self.original_byte_slice())
}
}
#[inline]
pub const fn is_eip7702(&self) -> bool {
matches!(self, Self::Eip7702(_))
}
#[inline]
pub fn new_legacy(raw: Bytes) -> Self {
Self::LegacyAnalyzed(LegacyRawBytecode(raw).into_analyzed())
}
#[inline]
pub fn new_raw(bytecode: Bytes) -> Self {
Self::new_raw_checked(bytecode).expect("Expect correct bytecode")
}
#[inline]
pub fn new_eip7702(address: Address) -> Self {
Self::Eip7702(Eip7702Bytecode::new(address))
}
#[inline]
pub fn new_raw_checked(bytes: Bytes) -> Result<Self, BytecodeDecodeError> {
let prefix = bytes.get(..2);
match prefix {
Some(prefix) if prefix == &EIP7702_MAGIC_BYTES => {
let eip7702 = Eip7702Bytecode::new_raw(bytes)?;
Ok(Self::Eip7702(eip7702))
}
_ => Ok(Self::new_legacy(bytes)),
}
}
#[inline]
pub fn new_analyzed(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self {
Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
bytecode,
original_len,
jump_table,
))
}
#[inline]
pub fn bytecode(&self) -> &Bytes {
match self {
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
Self::Eip7702(code) => code.raw(),
}
}
#[inline]
pub fn bytecode_ptr(&self) -> *const u8 {
self.bytecode().as_ptr()
}
#[inline]
pub fn bytes(&self) -> Bytes {
self.bytes_ref().clone()
}
#[inline]
pub fn bytes_ref(&self) -> &Bytes {
match self {
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
Self::Eip7702(code) => code.raw(),
}
}
#[inline]
pub fn bytes_slice(&self) -> &[u8] {
self.bytes_ref()
}
#[inline]
pub fn original_bytes(&self) -> Bytes {
match self {
Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
Self::Eip7702(eip7702) => eip7702.raw().clone(),
}
}
#[inline]
pub fn original_byte_slice(&self) -> &[u8] {
match self {
Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
Self::Eip7702(eip7702) => eip7702.raw(),
}
}
#[inline]
pub fn len(&self) -> usize {
self.original_byte_slice().len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn iter_opcodes(&self) -> crate::BytecodeIterator<'_> {
crate::BytecodeIterator::new(self)
}
}