From 22435a4974247f7fe9bf3e8a111091906812a7e6 Mon Sep 17 00:00:00 2001 From: FredCoen <43670554+FredCoen@users.noreply.github.com> Date: Sat, 14 Dec 2024 11:07:14 +0100 Subject: [PATCH] implement serde for interpreter (#1909) * implement serde for interpreter * add bytecode check * remove bytecode check * remove defaults generic params * add sanity check + cargo fmt * modify panic message --- crates/interpreter/src/interpreter.rs | 37 ++++++++++++++++ .../src/interpreter/ext_bytecode.rs | 3 ++ .../src/interpreter/ext_bytecode/serde.rs | 42 +++++++++++++++++++ crates/interpreter/src/interpreter/input.rs | 3 ++ .../src/interpreter/loop_control.rs | 3 ++ .../src/interpreter/return_data.rs | 3 ++ .../src/interpreter/runtime_flags.rs | 3 ++ 7 files changed, 94 insertions(+) create mode 100644 crates/interpreter/src/interpreter/ext_bytecode/serde.rs diff --git a/crates/interpreter/src/interpreter.rs b/crates/interpreter/src/interpreter.rs index a2198d3a84..d7d38c05b9 100644 --- a/crates/interpreter/src/interpreter.rs +++ b/crates/interpreter/src/interpreter.rs @@ -29,6 +29,7 @@ use std::rc::Rc; use subroutine_stack::SubRoutineImpl; #[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct Interpreter { pub bytecode: WIRE::Bytecode, pub stack: WIRE::Stack, @@ -284,4 +285,40 @@ mod tests { // >(); // let _ = interp.run(EMPTY_SHARED_MEMORY, table, host); // } + + use super::*; + use bytecode::Bytecode; + use primitives::{Address, Bytes, U256}; + use specification::hardfork::SpecId; + use std::{cell::RefCell, rc::Rc}; + + #[test] + #[cfg(feature = "serde")] + fn test_interpreter_serde() { + let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..])); + let interpreter = Interpreter::::new( + Rc::new(RefCell::new(SharedMemory::new())), + bytecode, + InputsImpl { + target_address: Address::ZERO, + caller_address: Address::ZERO, + input: Bytes::default(), + call_value: U256::ZERO, + }, + false, + false, + SpecId::LATEST, + u64::MAX, + ); + + let serialized = bincode::serialize(&interpreter).unwrap(); + + let deserialized: Interpreter = bincode::deserialize(&serialized).unwrap(); + + assert_eq!( + interpreter.bytecode.pc(), + deserialized.bytecode.pc(), + "Program counter should be preserved" + ); + } } diff --git a/crates/interpreter/src/interpreter/ext_bytecode.rs b/crates/interpreter/src/interpreter/ext_bytecode.rs index b9bf01bbbd..b19f25d159 100644 --- a/crates/interpreter/src/interpreter/ext_bytecode.rs +++ b/crates/interpreter/src/interpreter/ext_bytecode.rs @@ -7,6 +7,9 @@ use primitives::Bytes; use super::{EofCodeInfo, EofContainer, EofData, Immediates, Jumps, LegacyBytecode}; +#[cfg(feature = "serde")] +mod serde; + #[derive(Debug)] pub struct ExtBytecode { base: Bytecode, diff --git a/crates/interpreter/src/interpreter/ext_bytecode/serde.rs b/crates/interpreter/src/interpreter/ext_bytecode/serde.rs new file mode 100644 index 0000000000..9e1f1abbdf --- /dev/null +++ b/crates/interpreter/src/interpreter/ext_bytecode/serde.rs @@ -0,0 +1,42 @@ +use super::ExtBytecode; +use crate::interpreter::Jumps; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[derive(Serialize, Deserialize)] +struct ExtBytecodeSerde { + base: bytecode::Bytecode, + program_counter: usize, +} + +impl Serialize for ExtBytecode { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + ExtBytecodeSerde { + base: self.base.clone(), + program_counter: self.pc(), + } + .serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for ExtBytecode { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let ExtBytecodeSerde { + base, + program_counter, + } = ExtBytecodeSerde::deserialize(deserializer)?; + + let mut bytecode = Self::new(base); + + if program_counter >= bytecode.base.bytecode().len() { + panic!("serde pc: {program_counter} is greater than or equal to bytecode len"); + } + bytecode.absolute_jump(program_counter); + Ok(bytecode) + } +} diff --git a/crates/interpreter/src/interpreter/input.rs b/crates/interpreter/src/interpreter/input.rs index 2adb0e5827..d3f2e21e56 100644 --- a/crates/interpreter/src/interpreter/input.rs +++ b/crates/interpreter/src/interpreter/input.rs @@ -1,6 +1,9 @@ use crate::interpreter_types::InputsTrait; use primitives::{Address, Bytes, U256}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct InputsImpl { pub target_address: Address, pub caller_address: Address, diff --git a/crates/interpreter/src/interpreter/loop_control.rs b/crates/interpreter/src/interpreter/loop_control.rs index a0f5d00b8c..52c1fd00cb 100644 --- a/crates/interpreter/src/interpreter/loop_control.rs +++ b/crates/interpreter/src/interpreter/loop_control.rs @@ -1,6 +1,9 @@ use crate::interpreter_types::LoopControl as LoopControlTrait; use crate::{Gas, InstructionResult, InterpreterAction}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct LoopControl { /// The execution control flag. If this is not set to `Continue`, the interpreter will stop /// execution. diff --git a/crates/interpreter/src/interpreter/return_data.rs b/crates/interpreter/src/interpreter/return_data.rs index e1a6655e2e..8940ea78aa 100644 --- a/crates/interpreter/src/interpreter/return_data.rs +++ b/crates/interpreter/src/interpreter/return_data.rs @@ -1,6 +1,9 @@ use crate::interpreter::ReturnData; use primitives::Bytes; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Default)] pub struct ReturnDataImpl(Bytes); diff --git a/crates/interpreter/src/interpreter/runtime_flags.rs b/crates/interpreter/src/interpreter/runtime_flags.rs index a6e93c25f2..8e4011f6cd 100644 --- a/crates/interpreter/src/interpreter/runtime_flags.rs +++ b/crates/interpreter/src/interpreter/runtime_flags.rs @@ -1,7 +1,10 @@ use specification::hardfork::SpecId; use super::RuntimeFlag; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RuntimeFlags { pub is_static: bool, pub is_eof_init: bool,