revm_bytecode/eof/
code_info.rs

1use primitives::STACK_LIMIT;
2
3use super::{
4    decode_helpers::{consume_u16, consume_u8},
5    EofDecodeError,
6};
7use std::vec::Vec;
8
9/// Non returning function has a output `0x80`
10const EOF_NON_RETURNING_FUNCTION: u8 = 0x80;
11
12/// Types section that contains stack information for matching code section
13#[derive(Debug, Clone, Default, Hash, PartialEq, Eq, Copy, PartialOrd, Ord)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct CodeInfo {
16    /// `inputs` - 1 byte - `0x00-0x7F`
17    ///
18    /// Number of stack elements the code section consumes
19    pub inputs: u8,
20    /// `outputs` - 1 byte - `0x00-0x80`
21    ///
22    /// Number of stack elements the code section returns or 0x80 for non-returning functions
23    pub outputs: u8,
24    /// `max_stack_increase` - 2 bytes - `0x0000-0x03FF`
25    ///
26    /// Maximum number of elements that got added to the stack by this code section.
27    pub max_stack_increase: u16,
28}
29
30impl CodeInfo {
31    /// Returns new `CodeInfo` with the given inputs, outputs, and max_stack_increase.
32    pub fn new(inputs: u8, outputs: u8, max_stack_increase: u16) -> Self {
33        Self {
34            inputs,
35            outputs,
36            max_stack_increase,
37        }
38    }
39
40    /// Returns `true` if section is non-returning.
41    pub fn is_non_returning(&self) -> bool {
42        self.outputs == EOF_NON_RETURNING_FUNCTION
43    }
44
45    /// Calculates the difference between the number of input and output stack elements.
46    #[inline]
47    pub const fn io_diff(&self) -> i32 {
48        self.outputs as i32 - self.inputs as i32
49    }
50
51    /// Encodes the section into the buffer.
52    #[inline]
53    pub fn encode(&self, buffer: &mut Vec<u8>) {
54        buffer.push(self.inputs);
55        buffer.push(self.outputs);
56        buffer.extend_from_slice(&self.max_stack_increase.to_be_bytes());
57    }
58
59    /// Decodes the section from the input.
60    #[inline]
61    pub fn decode(input: &[u8]) -> Result<(Self, &[u8]), EofDecodeError> {
62        let (input, inputs) = consume_u8(input)?;
63        let (input, outputs) = consume_u8(input)?;
64        let (input, max_stack_increase) = consume_u16(input)?;
65        let section = Self {
66            inputs,
67            outputs,
68            max_stack_increase,
69        };
70        section.validate()?;
71        Ok((section, input))
72    }
73
74    /// Validates the section.
75    pub fn validate(&self) -> Result<(), EofDecodeError> {
76        if self.inputs > 0x7f {
77            return Err(EofDecodeError::InvalidCodeInfoInputValue { value: self.inputs });
78        }
79
80        if self.outputs > 0x80 {
81            return Err(EofDecodeError::InvalidCodeInfoOutputValue {
82                value: self.outputs,
83            });
84        }
85
86        if self.max_stack_increase > 0x03FF {
87            return Err(EofDecodeError::InvalidCodeInfoMaxIncrementValue {
88                value: self.max_stack_increase,
89            });
90        }
91
92        if self.inputs as usize + self.max_stack_increase as usize > STACK_LIMIT {
93            return Err(EofDecodeError::InvalidCodeInfoStackOverflow {
94                inputs: self.inputs,
95                max_stack_increment: self.max_stack_increase,
96            });
97        }
98
99        Ok(())
100    }
101}