revm_bytecode/legacy/
analyzed.rs1use super::JumpTable;
2use crate::opcode;
3use primitives::Bytes;
4
5#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct LegacyAnalyzedBytecode {
32 bytecode: Bytes,
34 original_len: usize,
36 jump_table: JumpTable,
38}
39
40impl Default for LegacyAnalyzedBytecode {
41 #[inline]
42 fn default() -> Self {
43 Self {
44 bytecode: Bytes::from_static(&[0]),
45 original_len: 0,
46 jump_table: JumpTable::default(),
47 }
48 }
49}
50
51impl LegacyAnalyzedBytecode {
52 pub fn analyze(bytecode: Bytes) -> Self {
56 let original_len = bytecode.len();
57 let (jump_table, padded_bytecode) = super::analysis::analyze_legacy(bytecode);
58 Self::new(padded_bytecode, original_len, jump_table)
59 }
60
61 pub fn new(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self {
71 assert!(
72 original_len <= bytecode.len(),
73 "original_len is greater than bytecode length"
74 );
75 assert!(
76 original_len <= jump_table.len(),
77 "jump table length is less than original length"
78 );
79 assert!(!bytecode.is_empty(), "bytecode cannot be empty");
80 assert!(
81 bytecode.last() == Some(&opcode::STOP),
82 "last bytecode byte should be STOP (0x00)"
83 );
84 Self {
85 bytecode,
86 original_len,
87 jump_table,
88 }
89 }
90
91 pub fn bytecode(&self) -> &Bytes {
95 &self.bytecode
96 }
97
98 pub fn original_len(&self) -> usize {
100 self.original_len
101 }
102
103 pub fn original_bytes(&self) -> Bytes {
105 self.bytecode.slice(..self.original_len)
106 }
107
108 pub fn original_byte_slice(&self) -> &[u8] {
110 &self.bytecode[..self.original_len]
111 }
112
113 pub fn jump_table(&self) -> &JumpTable {
115 &self.jump_table
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use crate::{opcode, LegacyRawBytecode};
123 use bitvec::{bitvec, order::Lsb0};
124
125 #[test]
126 fn test_bytecode_new() {
127 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
128 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
129 let _ = LegacyAnalyzedBytecode::new(
130 bytecode.bytecode,
131 bytecode.original_len,
132 bytecode.jump_table,
133 );
134 }
135
136 #[test]
137 #[should_panic(expected = "original_len is greater than bytecode length")]
138 fn test_panic_on_large_original_len() {
139 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
140 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
141 let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, 100, bytecode.jump_table);
142 }
143
144 #[test]
145 #[should_panic(expected = "jump table length is less than original length")]
146 fn test_panic_on_short_jump_table() {
147 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
148 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
149 let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 1]);
150 let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, bytecode.original_len, jump_table);
151 }
152
153 #[test]
154 #[should_panic(expected = "last bytecode byte should be STOP (0x00)")]
155 fn test_panic_on_non_stop_bytecode() {
156 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
157 let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 2]);
158 let _ = LegacyAnalyzedBytecode::new(bytecode, 2, jump_table);
159 }
160
161 #[test]
162 #[should_panic(expected = "bytecode cannot be empty")]
163 fn test_panic_on_empty_bytecode() {
164 let bytecode = Bytes::from_static(&[]);
165 let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 0]);
166 let _ = LegacyAnalyzedBytecode::new(bytecode, 0, jump_table);
167 }
168}