Skip to main content

revm_rwasm_bytecode/metadata/
bytecode.rs

1//! Compact representation of analyzed EVM bytecode.
2//!
3//! Stores padded bytecode, original length, jump table, and code hash for
4//! fast interpreter setup and inexpensive serialization.
5use crate::{legacy::analyze_legacy, JumpTable};
6use bincode::{
7    de::read::SliceReader, decode_from_reader, enc::write::SliceWriter, encode_into_writer, error,
8};
9use bitvec::vec::BitVec;
10use primitives::{Bytes, B256};
11use std::vec::Vec;
12
13#[derive(Debug)]
14/// A legacy bytecode
15pub struct LegacyBytecode {
16    /// A code hash of the bytecode
17    pub hash: B256,
18    /// Original EVM bytecode
19    pub bytecode: Bytes,
20}
21
22#[derive(Debug)]
23/// Bytecode plus metadata required by the interpreter.
24pub struct AnalyzedBytecode {
25    /// A padded bytecode (length might be different)
26    pub bytecode: Bytes,
27    /// An original bytecode len (w/o padding)
28    pub len: u64,
29    /// Jump table for JUMPDEST checks
30    pub jump_table: JumpTable,
31    /// Code hash of bytecode (non-padded version)
32    pub hash: B256,
33}
34
35impl Default for AnalyzedBytecode {
36    fn default() -> Self {
37        Self::new(Bytes::default(), B256::ZERO)
38    }
39}
40
41impl AnalyzedBytecode {
42    /// Analyze legacy bytecode, compute jump table, and keep orthe iginal length and hash.
43    pub fn new(bytecode: Bytes, hash: B256) -> Self {
44        let len = bytecode.len() as u64;
45        let (jump_table, bytecode) = analyze_legacy(bytecode);
46        Self {
47            bytecode,
48            len,
49            jump_table,
50            hash,
51        }
52    }
53
54    /// Returns a size hint for data serialization
55    pub fn hint_size(&self) -> usize {
56        8 // padded bytecode len
57        + self.bytecode.len() // padded bytecode
58        + 8 // original bytecode len
59        + 8 // jump table len
60        + self.jump_table.as_slice().len() // jump table
61        + 32 // code hash
62    }
63
64    /// Serialize into a contiguous buffer suitable for metadata storage.
65    pub fn serialize(&self, buffer: &mut [u8]) -> Result<(), error::EncodeError> {
66        debug_assert!(buffer.len() >= self.hint_size());
67        let mut writer = SliceWriter::new(buffer);
68        let config = bincode::config::legacy();
69        encode_into_writer(self.hash.0, &mut writer, config)?;
70        encode_into_writer(self.len, &mut writer, config)?;
71        encode_into_writer(&self.bytecode[..], &mut writer, config)?;
72        encode_into_writer(self.jump_table.as_slice(), &mut writer, config)?;
73        Ok(())
74    }
75
76    /// Deserialize from a buffer produced by `serialize`.
77    pub fn deserialize(bytes: &[u8]) -> Result<Self, error::DecodeError> {
78        let config = bincode::config::legacy();
79        let mut reader = SliceReader::new(bytes);
80        let hash: [u8; 32] = decode_from_reader(&mut reader, config)?;
81        let len: u64 = decode_from_reader(&mut reader, config)?;
82        let bytecode: Vec<u8> = decode_from_reader(&mut reader, config)?;
83        let jump_table: Vec<u8> = decode_from_reader(&mut reader, config)?;
84        if len > bytecode.len() as u64 {
85            return Err(error::DecodeError::ArrayLengthMismatch {
86                required: len as usize,
87                found: bytecode.len(),
88            });
89        }
90        Ok(Self {
91            bytecode: bytecode.into(),
92            len,
93            jump_table: JumpTable::new(BitVec::from_vec(jump_table)),
94            hash: B256::from(hash),
95        })
96    }
97
98    /// Return the original (unpadded) bytecode slice.
99    #[inline]
100    pub fn as_slice(&self) -> &[u8] {
101        &self.bytecode[..self.len as usize]
102    }
103
104    /// Original bytecode length (before padding).
105    #[inline]
106    pub fn len(&self) -> usize {
107        self.len as usize
108    }
109
110    /// Checks is bytecode empty
111    #[inline]
112    pub fn is_empty(&self) -> bool {
113        self.len == 0
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120    use primitives::hex;
121
122    #[test]
123    fn test_analyzed_bytecode_encoding() {
124        let bytecode = [
125            0x60, 0x03, // PUSH1 3
126            0x56, // JUMP
127            0x5b, // JUMPDEST
128        ];
129        let original_bytecode = AnalyzedBytecode::new(bytecode.into(), B256::ZERO);
130        let mut raw = vec![0u8; original_bytecode.hint_size()];
131        original_bytecode.serialize(&mut raw).unwrap();
132        let new_bytecode = AnalyzedBytecode::deserialize(&raw).unwrap();
133        assert_eq!(original_bytecode.bytecode, new_bytecode.bytecode);
134        assert_eq!(original_bytecode.len, new_bytecode.len);
135        assert_eq!(
136            original_bytecode.jump_table.as_slice(),
137            new_bytecode.jump_table.as_slice()
138        );
139        for (pc, _) in bytecode.iter().enumerate() {
140            assert_eq!(
141                original_bytecode.jump_table.is_valid(pc),
142                new_bytecode.jump_table.is_valid(pc)
143            );
144        }
145    }
146
147    #[test]
148    fn test_analyzed_bytecode() {
149        let bytecode = hex!("0x608060405234801561000f575f80fd5b506004361061003f575f3560e01c80633b2e97481461004357806345773e4e1461007357806348b8bcc314610091575b5f80fd5b61005d600480360381019061005891906102e5565b6100af565b60405161006a919061039a565b60405180910390f35b61007b6100dd565b604051610088919061039a565b60405180910390f35b61009961011a565b6040516100a6919061039a565b60405180910390f35b60605f8273ffffffffffffffffffffffffffffffffffffffff163190506100d58161012f565b915050919050565b60606040518060400160405280600b81526020017f48656c6c6f20576f726c64000000000000000000000000000000000000000000815250905090565b60605f4790506101298161012f565b91505090565b60605f8203610175576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050610282565b5f8290505f5b5f82146101a457808061018d906103f0565b915050600a8261019d9190610464565b915061017b565b5f8167ffffffffffffffff8111156101bf576101be610494565b5b6040519080825280601f01601f1916602001820160405280156101f15781602001600182028036833780820191505090505b5090505b5f851461027b578180610207906104c1565b925050600a8561021791906104e8565b60306102239190610518565b60f81b8183815181106102395761023861054b565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350600a856102749190610464565b94506101f5565b8093505050505b919050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6102b48261028b565b9050919050565b6102c4816102aa565b81146102ce575f80fd5b50565b5f813590506102df816102bb565b92915050565b5f602082840312156102fa576102f9610287565b5b5f610307848285016102d1565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561034757808201518184015260208101905061032c565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61036c82610310565b610376818561031a565b935061038681856020860161032a565b61038f81610352565b840191505092915050565b5f6020820190508181035f8301526103b28184610362565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f819050919050565b5f6103fa826103e7565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361042c5761042b6103ba565b5b600182019050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f61046e826103e7565b9150610479836103e7565b92508261048957610488610437565b5b828204905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f6104cb826103e7565b91505f82036104dd576104dc6103ba565b5b600182039050919050565b5f6104f2826103e7565b91506104fd836103e7565b92508261050d5761050c610437565b5b828206905092915050565b5f610522826103e7565b915061052d836103e7565b9250828201905080821115610545576105446103ba565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea2646970667358221220feebf5ace29c3c3146cb63bf7ca9009c2005f349075639d267cfbd817adde3e564736f6c63430008180033");
150        let original_bytecode = AnalyzedBytecode::new(bytecode.into(), B256::ZERO);
151        assert!(original_bytecode.jump_table.is_valid(0x039a));
152        let mut raw = vec![0u8; original_bytecode.hint_size()];
153        original_bytecode.serialize(&mut raw).unwrap();
154        let new_bytecode = AnalyzedBytecode::deserialize(&raw).unwrap();
155        assert!(new_bytecode.jump_table.is_valid(0x039a));
156    }
157}