revm_interpreter/interpreter/
contract.rs

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