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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! Mock types and functions to generate GethData used for tests

use std::str::FromStr;

use eth_types::{address, bytecode, bytecode::Bytecode, word, Address, Bytes, Hash, Word};
use ethers_signers::LocalWallet;
use lazy_static::lazy_static;
use rand::{random, SeedableRng};
use rand_chacha::ChaCha20Rng;
mod account;
mod block;
mod sha3;
pub mod test_ctx;
pub mod test_ctx2;
mod transaction;
mod withdrawal;

pub(crate) use account::MockAccount;
pub(crate) use block::MockBlock;
pub use sha3::Sha3CodeGen;
pub use test_ctx::TestContext;
pub use test_ctx2::TestContext2;
pub use transaction::{AddrOrWallet, MockTransaction, CORRECT_MOCK_TXS};

/// Mock block gas limit
pub const MOCK_BLOCK_GAS_LIMIT: u64 = 10_000_000_000_000_000;

lazy_static! {
    /// Mock 1 ETH
    pub static ref MOCK_1_ETH: Word = eth(1);
    /// Mock coinbase value
    pub static ref MOCK_COINBASE: Address =
        address!("0x00000000000000000000000000000000c014ba5e");
    /// Mock gasprice value
    pub static ref MOCK_GASPRICE: Word = Word::from(1u8);
    /// Mock BASEFEE value
    pub static ref MOCK_BASEFEE: Word = Word::zero();
     /// Mock GASLIMIT value
    pub static ref MOCK_GASLIMIT: Word = Word::from(0x2386f26fc10000u64);
    /// Mock chain ID value
    pub static ref MOCK_CHAIN_ID: Word = Word::from(1338u64);
    /// Mock DIFFICULTY value
    pub static ref MOCK_DIFFICULTY: Word = Word::from(0x200000u64);
    /// Mock mix hash value
    pub static ref MOCK_MIX_HASH: Hash =
        Hash::from_str("0x3fbea7af642a4e20cd93a945a1f5e23bd72fc5261153e09102cf718980aeff38").unwrap();
    /// Mock accounts loaded with ETH to use for test cases.
    pub static ref MOCK_ACCOUNTS: Vec<Address> = vec![
        address!("0x000000000000000000000000000000000cafe111"),
        address!("0x000000000000000000000000000000000cafe222"),
        address!("0x000000000000000000000000000000000cafe333"),
        address!("0x000000000000000000000000000000000cafe444"),
        address!("0x000000000000000000000000000000000cafe555"),
    ];
    /// Mock EVM codes to use for test cases.
    pub static ref MOCK_CODES: Vec<Bytes> = vec![
        Bytes::from([0x60, 0x10, 0x00]), // PUSH1(0x10), STOP
        Bytes::from([0x60, 0x01, 0x60, 0x02, 0x01, 0x00]), // PUSH1(1), PUSH1(2), ADD, STOP
        Bytes::from([0x60, 0x01, 0x60, 0x02, 0x02, 0x00]), // PUSH1(1), PUSH1(2), MUL, STOP
        Bytes::from([0x60, 0x02, 0x60, 0x01, 0x03, 0x00]), // PUSH1(2), PUSH1(1), SUB, STOP
        Bytes::from([0x60, 0x09, 0x60, 0x03, 0x04, 0x00]), // PUSH1(9), PUSH1(3), DIV, STOP
        Bytes::from([0x30; 256]), // ADDRESS * 256
    ];
    /// Mock wallets used to generate correctly signed and hashed Transactions.
    pub static ref MOCK_WALLETS: Vec<LocalWallet> = {
        let mut rng = ChaCha20Rng::seed_from_u64(2u64);
        vec![
            LocalWallet::new(&mut rng),
            LocalWallet::new(&mut rng),
            LocalWallet::new(&mut rng),
    ]
    };
    /// Mock EVM bytecode for a deployed contract.
    /// PUSH1 0x20
    /// PUSH1 0
    /// PUSH1 0
    /// CALLDATACOPY
    /// PUSH1 0x20
    /// PUSH1 0
    /// RETURN
    ///
    /// bytecode: 0x6020600060003760206000F3
    ///
    /// // constructor
    /// PUSH12 0x6020600060003760206000F3
    /// PUSH1 0
    /// MSTORE
    /// PUSH1 0xC
    /// PUSH1 0x14
    /// RETURN
    ///
    /// bytecode: 0x6B6020600060003760206000F3600052600C6014F3
    pub static ref MOCK_DEPLOYED_CONTRACT_BYTECODE: Word = word!("6B6020600060003760206000F3600052600C6014F3");
}

/// Generate a [`Word`] which corresponds to a certain amount of ETH.
pub fn eth(x: u64) -> Word {
    Word::from(x) * Word::from(10u64.pow(18))
}

/// Express an amount of ETH in GWei.
pub fn gwei(x: u64) -> Word {
    Word::from(x) * Word::from(10u64.pow(9))
}

/// Holds the parameters for generating mock EVM bytecode for a contract call
pub struct MockCallBytecodeParams {
    /// The address to call with the generated bytecode
    pub address: Address,
    /// The data to be passed as arguments to the contract function.
    pub pushdata: Vec<u8>,
    /// The offset in memory where the return data will be stored.
    pub return_data_offset: usize,
    /// The size of the return data.
    pub return_data_size: usize,
    /// The length of the call data.
    pub call_data_length: usize,
    /// The offset in memory where the call data will be stored.
    pub call_data_offset: usize,
    /// The amount of gas to be used for the contract call.
    pub gas: u64,
    /// The instructions to be executed after the contract call.
    pub instructions_after_call: Bytecode,
}

/// Set default parameters for MockCallBytecodeParams
impl Default for MockCallBytecodeParams {
    fn default() -> Self {
        MockCallBytecodeParams {
            address: address!("0x0000000000000000000000000000000000000000"),
            pushdata: Vec::new(),
            return_data_offset: 0x00usize,
            return_data_size: 0x00usize,
            call_data_length: 0x00usize,
            call_data_offset: 0x00usize,
            gas: 0x1_0000u64,
            instructions_after_call: Bytecode::default(),
        }
    }
}

/// Generate random bytes for the specified size.
pub fn rand_bytes(size: usize) -> Vec<u8> {
    (0..size).map(|_| random()).collect::<Vec<u8>>()
}

/// Generate mock EVM bytecode that performs a contract call
pub fn generate_mock_call_bytecode(params: MockCallBytecodeParams) -> Bytecode {
    bytecode! {
        .op_mstore(
            0u64,
            Word::from_big_endian(&params.pushdata)
        )
        .op_call(
            params.gas,
            params.address,
            0u64,
            params.call_data_offset,
            params.call_data_length,
            params.return_data_size,
            params.return_data_offset,
        )
        .append(&params.instructions_after_call)
        STOP
    }
}