revm_interpreter/instructions/
host.rs

1use crate::{
2    gas::{self, warm_cold_cost, warm_cold_cost_with_delegation},
3    interpreter::Interpreter,
4    primitives::{Bytes, Log, LogData, Spec, SpecId::*, B256, U256},
5    Host, InstructionResult,
6};
7use core::cmp::min;
8use std::vec::Vec;
9
10pub fn balance<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
11    pop_address!(interpreter, address);
12    let Some(balance) = host.balance(address) else {
13        interpreter.instruction_result = InstructionResult::FatalExternalError;
14        return;
15    };
16    gas!(
17        interpreter,
18        if SPEC::enabled(BERLIN) {
19            warm_cold_cost(balance.is_cold)
20        } else if SPEC::enabled(ISTANBUL) {
21            // EIP-1884: Repricing for trie-size-dependent opcodes
22            700
23        } else if SPEC::enabled(TANGERINE) {
24            400
25        } else {
26            20
27        }
28    );
29    push!(interpreter, balance.data);
30}
31
32/// EIP-1884: Repricing for trie-size-dependent opcodes
33pub fn selfbalance<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
34    check!(interpreter, ISTANBUL);
35    gas!(interpreter, gas::LOW);
36    let Some(balance) = host.balance(interpreter.contract.target_address) else {
37        interpreter.instruction_result = InstructionResult::FatalExternalError;
38        return;
39    };
40    push!(interpreter, balance.data);
41}
42
43pub fn extcodesize<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
44    pop_address!(interpreter, address);
45    let Some(code) = host.code(address) else {
46        interpreter.instruction_result = InstructionResult::FatalExternalError;
47        return;
48    };
49    let (code, load) = code.into_components();
50    if SPEC::enabled(BERLIN) {
51        gas!(interpreter, warm_cold_cost_with_delegation(load));
52    } else if SPEC::enabled(TANGERINE) {
53        gas!(interpreter, 700);
54    } else {
55        gas!(interpreter, 20);
56    }
57
58    push!(interpreter, U256::from(code.len()));
59}
60
61/// EIP-1052: EXTCODEHASH opcode
62pub fn extcodehash<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
63    check!(interpreter, CONSTANTINOPLE);
64    pop_address!(interpreter, address);
65    let Some(code_hash) = host.code_hash(address) else {
66        interpreter.instruction_result = InstructionResult::FatalExternalError;
67        return;
68    };
69    let (code_hash, load) = code_hash.into_components();
70    if SPEC::enabled(BERLIN) {
71        gas!(interpreter, warm_cold_cost_with_delegation(load))
72    } else if SPEC::enabled(ISTANBUL) {
73        gas!(interpreter, 700);
74    } else {
75        gas!(interpreter, 400);
76    }
77    push_b256!(interpreter, code_hash);
78}
79
80pub fn extcodecopy<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
81    pop_address!(interpreter, address);
82    pop!(interpreter, memory_offset, code_offset, len_u256);
83
84    let Some(code) = host.code(address) else {
85        interpreter.instruction_result = InstructionResult::FatalExternalError;
86        return;
87    };
88
89    let len = as_usize_or_fail!(interpreter, len_u256);
90    let (code, load) = code.into_components();
91    gas_or_fail!(
92        interpreter,
93        gas::extcodecopy_cost(SPEC::SPEC_ID, len as u64, load)
94    );
95    if len == 0 {
96        return;
97    }
98    let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
99    let code_offset = min(as_usize_saturated!(code_offset), code.len());
100    resize_memory!(interpreter, memory_offset, len);
101
102    // Note: this can't panic because we resized memory to fit.
103    interpreter
104        .shared_memory
105        .set_data(memory_offset, code_offset, len, &code);
106}
107
108pub fn blockhash<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
109    gas!(interpreter, gas::BLOCKHASH);
110    pop_top!(interpreter, number);
111
112    let number_u64 = as_u64_saturated!(number);
113    let Some(hash) = host.block_hash(number_u64) else {
114        interpreter.instruction_result = InstructionResult::FatalExternalError;
115        return;
116    };
117    *number = U256::from_be_bytes(hash.0);
118}
119
120pub fn sload<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
121    pop_top!(interpreter, index);
122    let Some(value) = host.sload(interpreter.contract.target_address, *index) else {
123        interpreter.instruction_result = InstructionResult::FatalExternalError;
124        return;
125    };
126    gas!(interpreter, gas::sload_cost(SPEC::SPEC_ID, value.is_cold));
127    *index = value.data;
128}
129
130pub fn sstore<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
131    require_non_staticcall!(interpreter);
132
133    pop!(interpreter, index, value);
134    let Some(state_load) = host.sstore(interpreter.contract.target_address, index, value) else {
135        interpreter.instruction_result = InstructionResult::FatalExternalError;
136        return;
137    };
138    gas_or_fail!(interpreter, {
139        let remaining_gas = interpreter.gas.remaining();
140        gas::sstore_cost(
141            SPEC::SPEC_ID,
142            &state_load.data,
143            remaining_gas,
144            state_load.is_cold,
145        )
146    });
147    refund!(
148        interpreter,
149        gas::sstore_refund(SPEC::SPEC_ID, &state_load.data)
150    );
151}
152
153/// EIP-1153: Transient storage opcodes
154/// Store value to transient storage
155pub fn tstore<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
156    check!(interpreter, CANCUN);
157    require_non_staticcall!(interpreter);
158    gas!(interpreter, gas::WARM_STORAGE_READ_COST);
159
160    pop!(interpreter, index, value);
161
162    host.tstore(interpreter.contract.target_address, index, value);
163}
164
165/// EIP-1153: Transient storage opcodes
166/// Load value from transient storage
167pub fn tload<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
168    check!(interpreter, CANCUN);
169    gas!(interpreter, gas::WARM_STORAGE_READ_COST);
170
171    pop_top!(interpreter, index);
172
173    *index = host.tload(interpreter.contract.target_address, *index);
174}
175
176pub fn log<const N: usize, H: Host + ?Sized>(interpreter: &mut Interpreter, host: &mut H) {
177    require_non_staticcall!(interpreter);
178
179    pop!(interpreter, offset, len);
180    let len = as_usize_or_fail!(interpreter, len);
181    gas_or_fail!(interpreter, gas::log_cost(N as u8, len as u64));
182    let data = if len == 0 {
183        Bytes::new()
184    } else {
185        let offset = as_usize_or_fail!(interpreter, offset);
186        resize_memory!(interpreter, offset, len);
187        Bytes::copy_from_slice(interpreter.shared_memory.slice(offset, len))
188    };
189
190    if interpreter.stack.len() < N {
191        interpreter.instruction_result = InstructionResult::StackUnderflow;
192        return;
193    }
194
195    let mut topics = Vec::with_capacity(N);
196    for _ in 0..N {
197        // SAFETY: stack bounds already checked few lines above
198        topics.push(B256::from(unsafe { interpreter.stack.pop_unsafe() }));
199    }
200
201    let log = Log {
202        address: interpreter.contract.target_address,
203        data: LogData::new(topics, data).expect("LogData should have <=4 topics"),
204    };
205
206    host.log(log);
207}
208
209pub fn selfdestruct<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
210    require_non_staticcall!(interpreter);
211    pop_address!(interpreter, target);
212
213    let Some(res) = host.selfdestruct(interpreter.contract.target_address, target) else {
214        interpreter.instruction_result = InstructionResult::FatalExternalError;
215        return;
216    };
217
218    // EIP-3529: Reduction in refunds
219    if !SPEC::enabled(LONDON) && !res.previously_destroyed {
220        refund!(interpreter, gas::SELFDESTRUCT)
221    }
222    gas!(interpreter, gas::selfdestruct_cost(SPEC::SPEC_ID, res));
223
224    interpreter.instruction_result = InstructionResult::SelfDestruct;
225}