revm_primitives/
bytecode.rspub mod eof;
pub mod legacy;
pub use eof::{Eof, EOF_MAGIC, EOF_MAGIC_BYTES, EOF_MAGIC_HASH};
pub use legacy::{JumpTable, LegacyAnalyzedBytecode};
use crate::{
eip7702::bytecode::Eip7702DecodeError, keccak256, Bytes, Eip7702Bytecode, B256,
EIP7702_MAGIC_BYTES, KECCAK_EMPTY,
};
use alloy_primitives::Address;
use core::fmt::Debug;
use eof::EofDecodeError;
use std::{fmt, sync::Arc};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Bytecode {
LegacyRaw(Bytes),
LegacyAnalyzed(LegacyAnalyzedBytecode),
Eof(Arc<Eof>),
Eip7702(Eip7702Bytecode),
}
impl Default for Bytecode {
#[inline]
fn default() -> Self {
Self::new()
}
}
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,
}
}
pub fn hash_slow(&self) -> B256 {
if self.is_empty() {
KECCAK_EMPTY
} else {
keccak256(self.original_byte_slice())
}
}
#[inline]
pub const fn eof(&self) -> Option<&Arc<Eof>> {
match self {
Self::Eof(eof) => Some(eof),
_ => None,
}
}
#[inline]
pub const fn is_eof(&self) -> bool {
matches!(self, Self::Eof(_))
}
pub const fn is_eip7702(&self) -> bool {
matches!(self, Self::Eip7702(_))
}
#[inline]
pub fn new_legacy(raw: Bytes) -> Self {
Self::LegacyRaw(raw)
}
#[inline]
pub fn new_raw(bytecode: Bytes) -> Self {
Self::new_raw_checked(bytecode).expect("Expect correct EOF bytecode")
}
#[inline]
pub fn new_eip7702(address: Address) -> Self {
Self::Eip7702(Eip7702Bytecode::new(address))
}
#[inline]
pub fn new_raw_checked(bytecode: Bytes) -> Result<Self, BytecodeDecodeError> {
let prefix = bytecode.get(..2);
match prefix {
Some(prefix) if prefix == &EOF_MAGIC_BYTES => {
let eof = Eof::decode(bytecode)?;
Ok(Self::Eof(Arc::new(eof)))
}
Some(prefix) if prefix == &EIP7702_MAGIC_BYTES => {
let eip7702 = Eip7702Bytecode::new_raw(bytecode)?;
Ok(Self::Eip7702(eip7702))
}
_ => Ok(Self::LegacyRaw(bytecode)),
}
}
pub unsafe 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::LegacyRaw(bytes) => bytes,
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
Self::Eof(eof) => eof
.body
.code(0)
.expect("Valid EOF has at least one code section"),
Self::Eip7702(code) => code.raw(),
}
}
pub fn is_execution_ready(&self) -> bool {
!matches!(self, Self::LegacyRaw(_))
}
#[inline]
pub fn bytes(&self) -> Bytes {
match self {
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode().clone(),
_ => self.original_bytes(),
}
}
#[inline]
pub fn bytes_slice(&self) -> &[u8] {
match self {
Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
_ => self.original_byte_slice(),
}
}
#[inline]
pub fn original_bytes(&self) -> Bytes {
match self {
Self::LegacyRaw(bytes) => bytes.clone(),
Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
Self::Eof(eof) => eof.raw().clone(),
Self::Eip7702(eip7702) => eip7702.raw().clone(),
}
}
#[inline]
pub fn original_byte_slice(&self) -> &[u8] {
match self {
Self::LegacyRaw(bytes) => bytes,
Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
Self::Eof(eof) => eof.raw(),
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
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BytecodeDecodeError {
Eof(EofDecodeError),
Eip7702(Eip7702DecodeError),
}
impl From<EofDecodeError> for BytecodeDecodeError {
fn from(error: EofDecodeError) -> Self {
Self::Eof(error)
}
}
impl From<Eip7702DecodeError> for BytecodeDecodeError {
fn from(error: Eip7702DecodeError) -> Self {
Self::Eip7702(error)
}
}
#[cfg(feature = "std")]
impl std::error::Error for BytecodeDecodeError {}
impl fmt::Display for BytecodeDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Eof(e) => fmt::Display::fmt(e, f),
Self::Eip7702(e) => fmt::Display::fmt(e, f),
}
}
}
#[cfg(test)]
mod tests {
use super::{Bytecode, Eof};
use std::sync::Arc;
#[test]
fn eof_arc_clone() {
let eof = Arc::new(Eof::default());
let bytecode = Bytecode::Eof(Arc::clone(&eof));
let cloned_bytecode = bytecode.clone();
if let Bytecode::Eof(original_arc) = bytecode {
if let Bytecode::Eof(cloned_arc) = cloned_bytecode {
assert!(Arc::ptr_eq(&original_arc, &cloned_arc));
} else {
panic!("Cloned bytecode is not Eof");
}
} else {
panic!("Original bytecode is not Eof");
}
}
}