1use crate::{
2 Contract, FunctionStack, Gas, InstructionResult, InterpreterAction, SharedMemory, Stack,
3};
4
5use super::Interpreter;
6use rtvm_primitives::Bytes;
7use serde::de::{self, MapAccess, Visitor};
8use serde::ser::SerializeStruct;
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use std::fmt;
11
12impl Serialize for Interpreter {
13 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14 where
15 S: Serializer,
16 {
17 let mut state = serializer.serialize_struct("Interpreter", 8)?;
18 let program_counter = self.program_counter();
20 state.serialize_field("program_counter", &program_counter)?;
21 state.serialize_field("gas", &self.gas)?;
22 state.serialize_field("contract", &self.contract)?;
23 state.serialize_field("instruction_result", &self.instruction_result)?;
24 state.serialize_field("bytecode", &self.bytecode)?;
25 state.serialize_field("is_eof", &self.is_eof)?;
26 state.serialize_field("is_eof_init", &self.is_eof_init)?;
27 state.serialize_field("shared_memory", &self.shared_memory)?;
28 state.serialize_field("stack", &self.stack)?;
29 state.serialize_field("function_stack", &self.function_stack)?;
30 state.serialize_field("return_data_buffer", &self.return_data_buffer)?;
31 state.serialize_field("is_static", &self.is_static)?;
32 state.serialize_field("next_action", &self.next_action)?;
33 state.end()
34 }
35}
36
37impl<'de> Deserialize<'de> for Interpreter {
38 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
39 where
40 D: Deserializer<'de>,
41 {
42 struct InterpreterVisitor;
43
44 #[derive(serde::Deserialize)]
45 #[serde(field_identifier, rename_all = "lowercase")]
46 enum InterpreterFields {
47 ProgramCounter,
48 Gas,
49 Contract,
50 InstructionResult,
51 Bytecode,
52 IsEof,
53 IsEofInit,
54 SharedMemory,
55 Stack,
56 FunctionStack,
57 ReturnDataBuffer,
58 IsStatic,
59 NextAction,
60 }
61
62 #[allow(clippy::too_many_arguments)]
63 fn rebuild_interp(
64 program_counter: isize,
65 gas: Gas,
66 contract: Contract,
67 instruction_result: InstructionResult,
68 bytecode: Bytes,
69 is_eof: bool,
70 is_eof_init: bool,
71 shared_memory: SharedMemory,
72 stack: Stack,
73 function_stack: FunctionStack,
74 return_data_buffer: Bytes,
75 is_static: bool,
76 next_action: InterpreterAction,
77 ) -> Result<Interpreter, &'static str> {
78 if program_counter < 0 || program_counter >= bytecode.len() as isize {
80 return Err("program_counter index out of range");
81 }
82
83 let instruction_pointer = unsafe { bytecode.as_ptr().offset(program_counter) };
85
86 Ok(Interpreter {
88 instruction_pointer,
89 gas,
90 contract,
91 instruction_result,
92 bytecode,
93 is_eof,
94 is_eof_init,
95 shared_memory,
96 stack,
97 function_stack,
98 return_data_buffer,
99 is_static,
100 next_action,
101 })
102 }
103
104 impl<'de> Visitor<'de> for InterpreterVisitor {
105 type Value = Interpreter;
106
107 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
108 formatter.write_str("struct Interpreter")
109 }
110
111 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
112 where
113 A: de::SeqAccess<'de>,
114 {
115 macro_rules! extract_field {
116 ($i:ident, $idx:expr) => {
117 let $i = seq
118 .next_element()?
119 .ok_or_else(|| de::Error::invalid_length($idx, &self))?;
120 };
121 }
122 extract_field!(instruction_pointer, 0);
123 extract_field!(gas, 1);
124 extract_field!(contract, 2);
125 extract_field!(instruction_result, 3);
126 extract_field!(bytecode, 4);
127 extract_field!(is_eof, 5);
128 extract_field!(is_eof_init, 6);
129 extract_field!(shared_memory, 7);
130 extract_field!(stack, 8);
131 extract_field!(function_stack, 9);
132 extract_field!(return_data_buffer, 10);
133 extract_field!(is_static, 11);
134 extract_field!(next_action, 12);
135 rebuild_interp(
136 instruction_pointer,
137 gas,
138 contract,
139 instruction_result,
140 bytecode,
141 is_eof,
142 is_eof_init,
143 shared_memory,
144 stack,
145 function_stack,
146 return_data_buffer,
147 is_static,
148 next_action,
149 )
150 .map_err(de::Error::custom)
151 }
152
153 fn visit_map<V>(self, mut map: V) -> Result<Interpreter, V::Error>
154 where
155 V: MapAccess<'de>,
156 {
157 macro_rules! parse_map {
158 ( $(($enum:pat, $var_name:ident)),* ) => {
159 $(
160 let mut $var_name = None;
161 )*
162 while let Some(key) = map.next_key()? {
163 match key {
164 $(
165 $enum => {
166 $var_name = Some(map.next_value()?);
167 }
168 )*
169 }
170 }
171 $(
172 let $var_name = $var_name.ok_or_else(|| de::Error::missing_field(stringify!($var_name)))?;
173 )*
174 };
175 }
176 parse_map!(
177 (InterpreterFields::ProgramCounter, program_counter),
178 (InterpreterFields::Gas, gas),
179 (InterpreterFields::Contract, contract),
180 (InterpreterFields::InstructionResult, instruction_result),
181 (InterpreterFields::Bytecode, bytecode),
182 (InterpreterFields::IsEof, is_eof),
183 (InterpreterFields::IsEofInit, is_eof_init),
184 (InterpreterFields::SharedMemory, shared_memory),
185 (InterpreterFields::Stack, stack),
186 (InterpreterFields::FunctionStack, function_stack),
187 (InterpreterFields::ReturnDataBuffer, return_data_buffer),
188 (InterpreterFields::IsStatic, is_static),
189 (InterpreterFields::NextAction, next_action)
190 );
191
192 rebuild_interp(
193 program_counter,
194 gas,
195 contract,
196 instruction_result,
197 bytecode,
198 is_eof,
199 is_eof_init,
200 shared_memory,
201 stack,
202 function_stack,
203 return_data_buffer,
204 is_static,
205 next_action,
206 )
207 .map_err(de::Error::custom)
208 }
209 }
210
211 const FIELDS: &[&str] = &[
212 "program_counter",
213 "gas",
214 "contract",
215 "instruction_result",
216 "bytecode",
217 "is_eof",
218 "is_eof_init",
219 "shared_memory",
220 "stack",
221 "function_stack",
222 "return_data_buffer",
223 "is_static",
224 "next_action",
225 ];
226
227 deserializer.deserialize_struct("Interpreter", FIELDS, InterpreterVisitor)
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
236 fn test_serde() {
237 let interp = Interpreter::new(Contract::default(), u64::MAX, false);
238 let serialized = bincode::serialize(&interp).unwrap();
239 let de: Interpreter = bincode::deserialize(&serialized).unwrap();
240 assert_eq!(interp.program_counter(), de.program_counter());
241 }
242}