rtvm_interpreter/interpreter/
contract.rs

1use super::analysis::to_analysed;
2use crate::{
3    primitives::{Address, Bytecode, Bytes, Env, TransactTo, B256, U256},
4    CallInputs,
5};
6
7/// EVM contract information.
8#[derive(Clone, Debug, Default)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Contract {
11    /// Contracts data
12    pub input: Bytes,
13    /// Bytecode contains contract code, size of original code, analysis with gas block and jump table.
14    /// Note that current code is extended with push padding and STOP at end.
15    pub bytecode: Bytecode,
16    /// Bytecode hash for legacy. For EOF this would be None.
17    pub hash: Option<B256>,
18    /// Target address of the account. Storage of this address is going to be modified.
19    pub target_address: Address,
20    /// Caller of the EVM.
21    pub caller: Address,
22    /// Value send to contract from transaction or from CALL opcodes.
23    pub call_value: U256,
24}
25
26impl Contract {
27    /// Instantiates a new contract by analyzing the given bytecode.
28    #[inline]
29    pub fn new(
30        input: Bytes,
31        bytecode: Bytecode,
32        hash: Option<B256>,
33        target_address: Address,
34        caller: Address,
35        call_value: U256,
36    ) -> Self {
37        let bytecode = to_analysed(bytecode);
38
39        Self {
40            input,
41            bytecode,
42            hash,
43            target_address,
44            caller,
45            call_value,
46        }
47    }
48
49    /// Creates a new contract from the given [`Env`].
50    #[inline]
51    pub fn new_env(env: &Env, bytecode: Bytecode, hash: Option<B256>) -> Self {
52        let contract_address = match env.tx.transact_to {
53            TransactTo::Call(caller) => caller,
54            TransactTo::Create => Address::ZERO,
55        };
56        Self::new(
57            env.tx.data.clone(),
58            bytecode,
59            hash,
60            contract_address,
61            env.tx.caller,
62            env.tx.value,
63        )
64    }
65
66    /// Creates a new contract from the given inputs.
67    #[inline]
68    pub fn new_with_context(
69        input: Bytes,
70        bytecode: Bytecode,
71        hash: Option<B256>,
72        call_context: &CallInputs,
73    ) -> Self {
74        Self::new(
75            input,
76            bytecode,
77            hash,
78            call_context.target_address,
79            call_context.caller,
80            call_context.call_value(),
81        )
82    }
83
84    /// Returns whether the given position is a valid jump destination.
85    #[inline]
86    pub fn is_valid_jump(&self, pos: usize) -> bool {
87        self.bytecode
88            .legacy_jump_table()
89            .map(|i| i.is_valid(pos))
90            .unwrap_or(false)
91    }
92}