Skip to main content

revm_rwasm_bytecode/
metadata.rs

1use std::vec;
2use primitives::{keccak256, Bytes, B256};
3
4mod bytecode;
5pub use bytecode::{AnalyzedBytecode, LegacyBytecode};
6
7/// Ethereum metadata
8#[derive(Debug)]
9pub enum EthereumMetadata {
10    /// Legacy EVM bytecode
11    Legacy(LegacyBytecode),
12    /// Analyzed EVM bytecode
13    Analyzed(AnalyzedBytecode),
14}
15
16/// A prefix indicating analyzed bytecode
17pub const ETHEREUM_METADATA_VERSION_ANALYZED: B256 = B256::with_last_byte(0x01);
18
19impl EthereumMetadata {
20    /// Create new analyzed EVM bytecode metadata
21    pub fn new_analyzed(bytecode: Bytes) -> Self {
22        let code_hash = keccak256(bytecode.as_ref());
23        Self::Analyzed(AnalyzedBytecode::new(bytecode, code_hash))
24    }
25
26    /// Create new legacy EVM bytecode metadata
27    pub fn new_legacy(bytecode: Bytes) -> Self {
28        let hash = keccak256(bytecode.as_ref());
29        Self::Legacy(LegacyBytecode { hash, bytecode })
30    }
31
32    /// Read metadata from bytes
33    pub fn read_from_bytes(metadata: &Bytes) -> Option<Self> {
34        if metadata.len() < 32 {
35            return None;
36        }
37        Some(match B256::from_slice(&metadata[0..32]) {
38            ETHEREUM_METADATA_VERSION_ANALYZED => Self::Analyzed(
39                AnalyzedBytecode::deserialize(&metadata[32..])
40                    .unwrap_or_else(|_| unreachable!("failed to deserialize analyzed bytecode")),
41            ),
42            hash => {
43                let bytecode = metadata.slice(32..);
44                Self::Legacy(LegacyBytecode { hash, bytecode })
45            }
46        })
47    }
48
49    /// Write metadata into bytes
50    pub fn write_to_bytes(&self) -> Bytes {
51        match self {
52            EthereumMetadata::Legacy(legacy_bytecode) => {
53                let mut result = vec![];
54                result.extend_from_slice(&legacy_bytecode.hash[..]);
55                result.extend_from_slice(&legacy_bytecode.bytecode[..]);
56                result.into()
57            }
58            EthereumMetadata::Analyzed(analyzed_bytecode) => {
59                let hint_size = analyzed_bytecode.hint_size();
60                let mut result = vec![0u8; B256::len_bytes() + hint_size];
61                result[0..B256::len_bytes()]
62                    .copy_from_slice(&ETHEREUM_METADATA_VERSION_ANALYZED[..]);
63                analyzed_bytecode
64                    .serialize(&mut result[B256::len_bytes()..])
65                    .unwrap_or_else(|_| unreachable!("evm: failed to serialize analyzed bytecode"));
66                result.into()
67            }
68        }
69    }
70
71    /// Get the code size
72    pub fn code_size(&self) -> usize {
73        match self {
74            EthereumMetadata::Legacy(bytecode) => bytecode.bytecode.len(),
75            EthereumMetadata::Analyzed(bytecode) => bytecode.len(),
76        }
77    }
78
79    /// Get the code hash
80    pub fn code_hash(&self) -> B256 {
81        match self {
82            EthereumMetadata::Legacy(bytecode) => bytecode.hash,
83            EthereumMetadata::Analyzed(bytecode) => bytecode.hash,
84        }
85    }
86
87    /// Copy EVM bytecode into bytes
88    pub fn code_copy(&self) -> Bytes {
89        match self {
90            EthereumMetadata::Legacy(bytecode) => bytecode.bytecode.clone(),
91            EthereumMetadata::Analyzed(bytecode) => bytecode.bytecode.slice(0..bytecode.len()),
92        }
93    }
94}