revm_bytecode/eof/
types_section.rs

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