revm_interpreter/interpreter/contract.rs
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
use revm_primitives::TxKind;
use super::analysis::to_analysed;
use crate::{
primitives::{Address, Bytecode, Bytes, Env, B256, U256},
CallInputs,
};
/// EVM contract information.
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
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: Bytecode,
/// Bytecode hash for legacy. For EOF this would be None.
pub hash: Option<B256>,
/// Target address of the account. Storage of this address is going to be modified.
pub target_address: Address,
/// Address of the account the bytecode was loaded from. This can be different from target_address
/// in the case of DELEGATECALL or CALLCODE
pub bytecode_address: Option<Address>,
/// Caller of the EVM.
pub caller: Address,
/// Value send to contract from transaction or from CALL opcodes.
pub call_value: U256,
}
impl Contract {
/// Instantiates a new contract by analyzing the given bytecode.
#[inline]
pub fn new(
input: Bytes,
bytecode: Bytecode,
hash: Option<B256>,
target_address: Address,
bytecode_address: Option<Address>,
caller: Address,
call_value: U256,
) -> Self {
let bytecode = to_analysed(bytecode);
Self {
input,
bytecode,
hash,
target_address,
bytecode_address,
caller,
call_value,
}
}
/// Creates a new contract from the given [`Env`].
#[inline]
pub fn new_env(env: &Env, bytecode: Bytecode, hash: Option<B256>) -> Self {
let contract_address = match env.tx.transact_to {
TxKind::Call(caller) => caller,
TxKind::Create => Address::ZERO,
};
let bytecode_address = match env.tx.transact_to {
TxKind::Call(caller) => Some(caller),
TxKind::Create => None,
};
Self::new(
env.tx.data.clone(),
bytecode,
hash,
contract_address,
bytecode_address,
env.tx.caller,
env.tx.value,
)
}
/// Creates a new contract from the given inputs.
#[inline]
pub fn new_with_context(
input: Bytes,
bytecode: Bytecode,
hash: Option<B256>,
call_context: &CallInputs,
) -> Self {
Self::new(
input,
bytecode,
hash,
call_context.target_address,
Some(call_context.bytecode_address),
call_context.caller,
call_context.call_value(),
)
}
/// Returns whether the given position is a valid jump destination.
#[inline]
pub fn is_valid_jump(&self, pos: usize) -> bool {
self.bytecode
.legacy_jump_table()
.map(|i| i.is_valid(pos))
.unwrap_or(false)
}
}