revm_primitives/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)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct TypesSection {
14    /// inputs - 1 byte - `0x00-0x7F`
15    /// number of stack elements the code section consumes
16    pub inputs: u8,
17    /// outputs - 1 byte - `0x00-0x80`
18    /// number of stack elements the code section returns or 0x80 for non-returning functions
19    pub outputs: u8,
20    /// max_stack_height - 2 bytes - `0x0000-0x03FF`
21    /// maximum number of elements ever placed onto the stack by the code section
22    pub max_stack_size: u16,
23}
24
25impl TypesSection {
26    /// Returns new `TypesSection` with the given inputs, outputs, and max_stack_size.
27    pub fn new(inputs: u8, outputs: u8, max_stack_size: u16) -> Self {
28        Self {
29            inputs,
30            outputs,
31            max_stack_size,
32        }
33    }
34
35    /// True if section is non-returning.
36    pub fn is_non_returning(&self) -> bool {
37        self.outputs == EOF_NON_RETURNING_FUNCTION
38    }
39
40    /// Calculates the difference between the number of input and output stack elements.
41    #[inline]
42    pub const fn io_diff(&self) -> i32 {
43        self.outputs as i32 - self.inputs as i32
44    }
45
46    /// Encode the section into the buffer.
47    #[inline]
48    pub fn encode(&self, buffer: &mut Vec<u8>) {
49        buffer.push(self.inputs);
50        buffer.push(self.outputs);
51        buffer.extend_from_slice(&self.max_stack_size.to_be_bytes());
52    }
53
54    /// Decode the section from the input.
55    #[inline]
56    pub fn decode(input: &[u8]) -> Result<(Self, &[u8]), EofDecodeError> {
57        let (input, inputs) = consume_u8(input)?;
58        let (input, outputs) = consume_u8(input)?;
59        let (input, max_stack_size) = consume_u16(input)?;
60        let section = Self {
61            inputs,
62            outputs,
63            max_stack_size,
64        };
65        section.validate()?;
66        Ok((section, input))
67    }
68
69    /// Validate the section.
70    pub fn validate(&self) -> Result<(), EofDecodeError> {
71        if self.inputs > 0x7f || self.outputs > 0x80 || self.max_stack_size > 0x03FF {
72            return Err(EofDecodeError::InvalidTypesSection);
73        }
74        if self.inputs as u16 > self.max_stack_size {
75            return Err(EofDecodeError::InvalidTypesSection);
76        }
77        Ok(())
78    }
79}