revm_context/
local.rs

1//! Local context that is filled by execution.
2use bytecode::{CodeType, Eof};
3use context_interface::LocalContextTr;
4use core::cell::RefCell;
5use primitives::{keccak256, Bytes, HashMap, B256};
6use std::{rc::Rc, vec::Vec};
7
8/// Local context that is filled by execution.
9#[derive(Clone, Debug)]
10pub struct LocalContext {
11    /// Mapping of initcode hash that contains raw bytes ready for validation or status of validation.
12    ///
13    /// Used in EIP-7873 EOF - TXCREATE to fetch initcode by hash and cache its validation.
14    pub initcode_mapping: HashMap<B256, Initcode>,
15    /// Interpreter shared memory buffer. A reused memory buffer for calls.
16    pub shared_memory_buffer: Rc<RefCell<Vec<u8>>>,
17}
18
19impl Default for LocalContext {
20    fn default() -> Self {
21        Self {
22            initcode_mapping: HashMap::default(),
23            shared_memory_buffer: Rc::new(RefCell::new(Vec::with_capacity(1024 * 4))),
24        }
25    }
26}
27
28impl LocalContextTr for LocalContext {
29    fn insert_initcodes(&mut self, initcodes: &[Bytes]) {
30        self.initcode_mapping = initcodes
31            .iter()
32            .map(|b| (keccak256(b), Initcode::new(b.clone())))
33            .collect();
34    }
35
36    fn clear(&mut self) {
37        self.initcode_mapping.clear();
38        // Sets len to 0 but it will not shrink to drop the capacity.
39        unsafe { self.shared_memory_buffer.borrow_mut().set_len(0) };
40    }
41
42    fn get_validated_initcode(&mut self, hash: B256) -> Option<Bytes> {
43        let initcode = self.initcode_mapping.get_mut(&hash)?;
44        initcode.validate().cloned()
45    }
46
47    fn shared_memory_buffer(&mut self) -> &Rc<RefCell<Vec<u8>>> {
48        &self.shared_memory_buffer
49    }
50}
51
52impl LocalContext {
53    /// Creates a new local context, initcodes are hashes and added to the mapping.
54    pub fn new(initcode: &[Bytes]) -> Self {
55        let mut s = Self::default();
56        s.insert_initcodes(initcode);
57        s
58    }
59}
60
61/// Status of the initcode.
62#[derive(Clone, Debug, PartialEq, Eq)]
63pub enum InitcodeStatus {
64    /// Initcode is valid, it was decoded into EOF and validated.
65    Valid,
66    /// Initcode is invalid this can mean decoding failed or validation failed.
67    Invalid,
68    /// Initcode is pending validation.
69    PendingValidation,
70}
71
72/// Initcode with validation status.
73#[derive(Clone, Debug)]
74pub struct Initcode {
75    /// Raw bytes of the initcode.
76    bytes: Bytes,
77    /// Status of the initcode.
78    status: InitcodeStatus,
79}
80
81impl Initcode {
82    /// Creates a new initcode with validation set to false.
83    pub fn new(initcode: Bytes) -> Self {
84        Self {
85            bytes: initcode,
86            status: InitcodeStatus::PendingValidation,
87        }
88    }
89
90    /// Validates the initcode and sets the status to valid if it is valid.
91    ///
92    /// If initcode is not pending validation it will return None.
93    pub fn validate(&mut self) -> Option<&Bytes> {
94        match self.status {
95            InitcodeStatus::Valid => return Some(&self.bytes),
96            InitcodeStatus::Invalid => return None,
97            InitcodeStatus::PendingValidation => (),
98        }
99
100        // pending validation
101        let Ok(eof) = Eof::decode(self.bytes.clone()) else {
102            self.status = InitcodeStatus::Invalid;
103            return None;
104        };
105
106        // validate in Initcode mode, data section should be filled and it should not contain RETURN or STOP
107        if eof.validate_mode(CodeType::Initcode).is_err() {
108            self.status = InitcodeStatus::Invalid;
109            return None;
110        }
111        // mark initcode as valid so we can skip this validation next time.
112        self.status = InitcodeStatus::Valid;
113        Some(&self.bytes)
114    }
115}