1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use super::analysis::{to_analysed, BytecodeLocked};
use crate::primitives::{Address, Bytecode, Bytes, Env, TransactTo, B256, U256};
use crate::CallContext;

/// EVM contract information.
#[derive(Clone, Debug, Default)]
pub struct Contract {
    /// Contracts data
    pub input: Bytes,
    /// Bytecode contains contract code, size of original code, analysis with gas block and jump table.
    /// Note that current code is extended with push padding and STOP at end.
    pub bytecode: BytecodeLocked,
    /// Bytecode hash.
    pub hash: B256,
    /// Contract address
    pub address: Address,
    /// Caller of the EVM.
    pub caller: Address,
    /// Value send to contract.
    pub value: U256,
}

impl Contract {
    /// Instantiates a new contract by analyzing the given bytecode.
    #[inline]
    pub fn new(
        input: Bytes,
        bytecode: Bytecode,
        hash: B256,
        address: Address,
        caller: Address,
        value: U256,
    ) -> Self {
        let bytecode = to_analysed(bytecode).try_into().expect("it is analyzed");

        Self {
            input,
            bytecode,
            hash,
            address,
            caller,
            value,
        }
    }

    /// Creates a new contract from the given [`Env`].
    #[inline]
    pub fn new_env(env: &Env, bytecode: Bytecode, hash: B256) -> Self {
        let contract_address = match env.tx.transact_to {
            TransactTo::Call(caller) => caller,
            TransactTo::Create(..) => Address::ZERO,
        };
        Self::new(
            env.tx.data.clone(),
            bytecode,
            hash,
            contract_address,
            env.tx.caller,
            env.tx.value,
        )
    }

    /// Creates a new contract from the given [`CallContext`].
    #[inline]
    pub fn new_with_context(
        input: Bytes,
        bytecode: Bytecode,
        hash: B256,
        call_context: &CallContext,
    ) -> Self {
        Self::new(
            input,
            bytecode,
            hash,
            call_context.address,
            call_context.caller,
            call_context.apparent_value,
        )
    }

    /// Returns whether the given position is a valid jump destination.
    #[inline]
    pub fn is_valid_jump(&self, pos: usize) -> bool {
        self.bytecode.jump_map().is_valid(pos)
    }
}