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 new(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self {
60 if original_len > bytecode.len() {
61 panic!("original_len is greater than bytecode length");
62 }
63 if original_len > jump_table.0.len() {
64 panic!(
65 "jump table length {} is less than original length {}",
66 jump_table.0.len(),
67 original_len
68 );
69 }
70
71 if bytecode.is_empty() {
72 panic!("bytecode cannot be empty");
73 }
74
75 if bytecode.last() != Some(&opcode::STOP) {
76 panic!("last bytecode byte should be STOP (0x00)");
77 }
78
79 Self {
80 bytecode,
81 original_len,
82 jump_table,
83 }
84 }
85
86 pub fn bytecode(&self) -> &Bytes {
90 &self.bytecode
91 }
92
93 pub fn original_len(&self) -> usize {
95 self.original_len
96 }
97
98 pub fn original_bytes(&self) -> Bytes {
100 self.bytecode.slice(..self.original_len)
101 }
102
103 pub fn original_byte_slice(&self) -> &[u8] {
105 &self.bytecode[..self.original_len]
106 }
107
108 pub fn jump_table(&self) -> &JumpTable {
110 &self.jump_table
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use crate::{opcode, LegacyRawBytecode};
118 use bitvec::{bitvec, order::Lsb0};
119 use std::sync::Arc;
120
121 #[test]
122 fn test_bytecode_new() {
123 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
124 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
125 let _ = LegacyAnalyzedBytecode::new(
126 bytecode.bytecode,
127 bytecode.original_len,
128 bytecode.jump_table,
129 );
130 }
131
132 #[test]
133 #[should_panic(expected = "original_len is greater than bytecode length")]
134 fn test_panic_on_large_original_len() {
135 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
136 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
137 let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, 100, bytecode.jump_table);
138 }
139
140 #[test]
141 #[should_panic(expected = "jump table length 1 is less than original length 2")]
142 fn test_panic_on_short_jump_table() {
143 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
144 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
145 let jump_table = JumpTable(Arc::new(bitvec![u8, Lsb0; 0; 1]));
146 let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, bytecode.original_len, jump_table);
147 }
148
149 #[test]
150 #[should_panic(expected = "last bytecode byte should be STOP (0x00)")]
151 fn test_panic_on_non_stop_bytecode() {
152 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
153 let jump_table = JumpTable(Arc::new(bitvec![u8, Lsb0; 0; 2]));
154 let _ = LegacyAnalyzedBytecode::new(bytecode, 2, jump_table);
155 }
156
157 #[test]
158 #[should_panic(expected = "bytecode cannot be empty")]
159 fn test_panic_on_empty_bytecode() {
160 let bytecode = Bytes::from_static(&[]);
161 let jump_table = JumpTable(Arc::new(bitvec![u8, Lsb0; 0; 0]));
162 let _ = LegacyAnalyzedBytecode::new(bytecode, 0, jump_table);
163 }
164}