arbiter_core/environment/
instruction.rs

1//! This module contains the `Instruction` and `Outcome` enums that are used to
2//! communicate instructions and their outcomes between the
3//! [`middleware::ArbiterMiddleware`] and the [`Environment`].
4
5use super::*;
6
7/// [`Instruction`]s that can be sent to the [`Environment`] via the
8/// [`Socket`].
9/// These instructions can be:
10/// - [`Instruction::AddAccount`],
11/// - [`Instruction::BlockUpdate`],
12/// - [`Instruction::Call`],
13/// - [`Instruction::Cheatcode`],
14/// - [`Instruction::Query`].
15/// - [`Instruction::SetGasPrice`],
16/// - [`Instruction::Stop`],
17/// - [`Instruction::Transaction`],
18
19/// The [`Instruction`]s are sent to the [`Environment`] via the
20/// [`Socket::instruction_sender`] and the results are received via the
21/// [`crate::middleware::Connection::outcome_receiver`].
22#[derive(Debug, Clone)]
23pub(crate) enum Instruction {
24    /// An `AddAccount` is used to add a default/unfunded account to the
25    /// [`Environment`].
26    AddAccount {
27        /// The address of the account to add to the [`EVM`].
28        address: eAddress,
29
30        /// The sender used to to send the outcome of the account addition back
31        /// to.
32        outcome_sender: OutcomeSender,
33    },
34
35    /// A `BlockUpdate` is used to update the block number and timestamp of the
36    /// [`Environment`].
37    BlockUpdate {
38        /// The block number to update the [`EVM`] to.
39        block_number: eU256,
40
41        /// The block timestamp to update the [`EVM`] to.
42        block_timestamp: eU256,
43
44        /// The sender used to to send the outcome of the block update back to.
45        outcome_sender: OutcomeSender,
46    },
47
48    /// A `Call` is processed by the [`EVM`] but will not be state changing and
49    /// will not create events.
50    Call {
51        /// The transaction environment for the call.
52        tx_env: TxEnv,
53
54        /// The sender used to to send the outcome of the call back to.
55        outcome_sender: OutcomeSender,
56    },
57
58    /// A `cheatcode` enables direct access to the underlying [`EVM`].
59    Cheatcode {
60        /// The [`Cheatcode`] to use to access the underlying [`EVM`].
61        cheatcode: Cheatcodes,
62
63        /// The sender used to to send the outcome of the cheatcode back to.
64        outcome_sender: OutcomeSender,
65    },
66
67    /// A `Query` is used to query the [`EVM`] for some data, the choice of
68    /// which data is specified by the inner `EnvironmentData` enum.
69    Query {
70        /// The data to query the [`EVM`] for.
71        environment_data: EnvironmentData,
72
73        /// The sender used to to send the outcome of the query back to.
74        outcome_sender: OutcomeSender,
75    },
76
77    /// A `SetGasPrice` is used to set the gas price of the [`EVM`].
78    SetGasPrice {
79        /// The gas price to set the [`EVM`] to.
80        gas_price: eU256,
81
82        /// The sender used to to send the outcome of the gas price setting back
83        /// to.
84        outcome_sender: OutcomeSender,
85    },
86
87    /// A `Stop` is used to stop the [`Environment`].
88    Stop(OutcomeSender),
89
90    /// A `Transaction` is processed by the [`EVM`] and will be state changing
91    /// and will create events.
92    Transaction {
93        /// The transaction environment for the transaction.
94        tx_env: TxEnv,
95
96        /// The sender used to to send the outcome of the transaction back to.
97        outcome_sender: OutcomeSender,
98    },
99}
100
101/// [`Outcome`]s that can be sent back to the the client via the
102/// [`Socket`].
103/// These outcomes can be from `Call`, `Transaction`, or `BlockUpdate`
104/// instructions sent to the [`Environment`]
105#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
106pub(crate) enum Outcome {
107    /// The outcome of an [`Instruction::AddAccount`] instruction that is used
108    /// to signify that the account was added successfully.
109    AddAccountCompleted,
110
111    /// The outcome of a `BlockUpdate` instruction that is used to provide a
112    /// non-error output of updating the block number and timestamp of the
113    /// [`EVM`] to the client.
114    BlockUpdateCompleted(ReceiptData),
115
116    /// Return value from a cheatcode instruction.
117    /// todo: make a decision on how to handle cheatcode returns.
118    CheatcodeReturn(CheatcodesReturn),
119
120    /// The outcome of a `Call` instruction that is used to provide the output
121    /// of some [`EVM`] computation to the client.
122    CallCompleted(ExecutionResult),
123
124    /// The outcome of a [`Instruction::SetGasPrice`] instruction that is used
125    /// to signify that the gas price was set successfully.
126    SetGasPriceCompleted,
127
128    /// The outcome of a `Transaction` instruction that is first unpacked to see
129    /// if the result is successful, then it can be used to build a
130    /// `TransactionReceipt` in the `Middleware`.
131    TransactionCompleted(ExecutionResult, ReceiptData),
132
133    /// The outcome of a `Query` instruction that carries a `String`
134    /// representation of the data. Currently this may carry the block
135    /// number, block timestamp, gas price, or balance of an account.
136    QueryReturn(String),
137
138    /// The outcome of a `Stop` instruction that is used to signify that the
139    /// [`Environment`] was stopped successfully.
140    StopCompleted(ArbiterDB),
141}
142
143/// [`EnvironmentData`] is an enum used inside of the [`Instruction::Query`] to
144/// specify what data should be returned to the user.
145/// Currently this may be the block number, block timestamp, gas price, or
146/// balance of an account.
147#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
148#[allow(clippy::large_enum_variant)]
149pub(crate) enum EnvironmentData {
150    /// The query is for the block number of the [`EVM`].
151    BlockNumber,
152
153    /// The query is for the block timestamp of the [`EVM`].
154    BlockTimestamp,
155
156    /// The query is for the gas price of the [`EVM`].
157    GasPrice,
158
159    /// The query is for the balance of an account given by the inner `Address`.
160    Balance(eAddress),
161
162    // TODO: Rename this to `Nonce`?
163    /// The query is for the nonce of an account given by the inner `Address`.
164    TransactionCount(eAddress),
165
166    /// Query for logs in a range of blocks.
167    Logs {
168        /// The filter to use to query for logs
169        filter: Filter,
170    },
171}
172
173/// [`ReceiptData`] is a structure that holds the block number, transaction
174/// index, and cumulative gas used per block for a transaction.
175#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
176pub struct ReceiptData {
177    /// `block_number` is the number of the block in which the transaction was
178    /// included.
179    pub block_number: U64,
180    /// `transaction_index` is the index position of the transaction in the
181    /// block.
182    pub transaction_index: U64,
183    /// `cumulative_gas_per_block` is the total amount of gas used in the
184    /// block up until and including the transaction.
185    pub cumulative_gas_per_block: eU256,
186}
187
188/// Cheatcodes are a direct way to access the underlying [`EVM`] environment and
189/// database.
190#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
191pub enum Cheatcodes {
192    /// A `Deal` is used to increase the balance of an account in the [`EVM`].
193    Deal {
194        /// The address of the account to increase the balance of.
195        address: eAddress,
196
197        /// The amount to increase the balance of the account by.
198        amount: eU256,
199    },
200    /// Fetches the value of a storage slot of an account.
201    Load {
202        /// The address of the account to fetch the storage slot from.
203        account: eAddress,
204        /// The storage slot to fetch.
205        key: H256,
206        /// The block to fetch the storage slot from.
207        /// todo: implement storage slots at blocks.
208        block: Option<ethers::types::BlockId>,
209    },
210    /// Overwrites a storage slot of an account.
211    /// TODO: for more complicated data types, like structs, there's more work
212    /// to do.
213    Store {
214        /// The address of the account to overwrite the storage slot of.
215        account: ethers::types::Address,
216        /// The storage slot to overwrite.
217        key: ethers::types::H256,
218        /// The value to overwrite the storage slot with.
219        value: ethers::types::H256,
220    },
221    /// Fetches the `DbAccount` account at the given address.
222    Access {
223        /// The address of the account to fetch.
224        address: ethers::types::Address,
225    },
226}
227
228/// Wrapper around [`AccountState`] that can be serialized and deserialized.
229#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
230pub enum AccountStateSerializable {
231    /// Before Spurious Dragon hardfork there was a difference between empty and
232    /// not existing. And we are flagging it here.
233    NotExisting,
234    /// EVM touched this account. For newer hardfork this means it can be
235    /// cleared/removed from state.
236    Touched,
237    /// EVM cleared storage of this account, mostly by selfdestruct, we don't
238    /// ask database for storage slots and assume they are U256::ZERO
239    StorageCleared,
240    /// EVM didn't interacted with this account
241    #[default]
242    None,
243}
244
245/// Return values of applying cheatcodes.
246#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
247pub enum CheatcodesReturn {
248    /// A `Load` returns the value of a storage slot of an account.
249    Load {
250        /// The value of the storage slot.
251        value: U256,
252    },
253    /// A `Store` returns nothing.
254    Store,
255    /// A `Deal` returns nothing.
256    Deal,
257    /// Gets the DbAccount associated with an address.
258    Access {
259        /// Basic account information like nonce, balance, code hash, bytcode.
260        info: AccountInfo,
261        /// todo: revm must be updated with serde deserialize, then `DbAccount`
262        /// can be used.
263        account_state: AccountStateSerializable,
264        /// Storage slots of the account.
265        storage: HashMap<U256, U256>,
266    },
267}