5
5
#include " eof.hpp"
6
6
#include " instructions.hpp"
7
7
8
+ constexpr int64_t MIN_RETAINED_GAS = 5000 ;
9
+ constexpr int64_t MIN_CALLEE_GAS = 2300 ;
10
+ constexpr int64_t CALL_VALUE_COST = 9000 ;
11
+ constexpr int64_t ACCOUNT_CREATION_COST = 25000 ;
12
+
13
+ constexpr auto EXTCALL_SUCCESS = 0 ;
14
+ constexpr auto EXTCALL_REVERT = 1 ;
15
+ constexpr auto EXTCALL_ABORT = 2 ;
16
+
8
17
namespace evmone ::instr::core
9
18
{
10
19
template <Opcode Op>
@@ -61,15 +70,15 @@ Result call_impl(StackTop stack, int64_t gas_left, ExecutionState& state) noexce
61
70
msg.input_size = input_size;
62
71
}
63
72
64
- auto cost = has_value ? 9000 : 0 ;
73
+ auto cost = has_value ? CALL_VALUE_COST : 0 ;
65
74
66
75
if constexpr (Op == OP_CALL)
67
76
{
68
77
if (has_value && state.in_static_mode ())
69
78
return {EVMC_STATIC_MODE_VIOLATION, gas_left};
70
79
71
80
if ((has_value || state.rev < EVMC_SPURIOUS_DRAGON) && !state.host .account_exists (dst))
72
- cost += 25000 ;
81
+ cost += ACCOUNT_CREATION_COST ;
73
82
}
74
83
75
84
if ((gas_left -= cost) < 0 )
@@ -96,21 +105,6 @@ Result call_impl(StackTop stack, int64_t gas_left, ExecutionState& state) noexce
96
105
if (has_value && intx::be::load<uint256>(state.host .get_balance (state.msg ->recipient )) < value)
97
106
return {EVMC_SUCCESS, gas_left}; // "Light" failure.
98
107
99
- if constexpr (Op == OP_DELEGATECALL)
100
- {
101
- if (state.rev >= EVMC_PRAGUE && is_eof_container (state.original_code ))
102
- {
103
- // The code targeted by DELEGATECALL must also be an EOF.
104
- // This restriction has been added to EIP-3540 in
105
- // https://github.com/ethereum/EIPs/pull/7131
106
- uint8_t target_code_prefix[2 ];
107
- const auto s = state.host .copy_code (
108
- msg.code_address , 0 , target_code_prefix, std::size (target_code_prefix));
109
- if (!is_eof_container ({target_code_prefix, s}))
110
- return {EVMC_SUCCESS, gas_left};
111
- }
112
- }
113
-
114
108
const auto result = state.host .call (msg);
115
109
state.return_data .assign (result.output_data , result.output_size );
116
110
stack.top () = result.status_code == EVMC_SUCCESS;
@@ -133,6 +127,109 @@ template Result call_impl<OP_DELEGATECALL>(
133
127
template Result call_impl<OP_CALLCODE>(
134
128
StackTop stack, int64_t gas_left, ExecutionState& state) noexcept ;
135
129
130
+ template <Opcode Op>
131
+ Result extcall_impl (StackTop stack, int64_t gas_left, ExecutionState& state) noexcept
132
+ {
133
+ static_assert (Op == OP_EXTCALL || Op == OP_EXTDELEGATECALL || Op == OP_EXTSTATICCALL);
134
+
135
+ const auto dst = intx::be::trunc <evmc::address>(stack.pop ());
136
+ const auto input_offset_u256 = stack.pop ();
137
+ const auto input_size_u256 = stack.pop ();
138
+ const auto value = (Op == OP_EXTSTATICCALL || Op == OP_EXTDELEGATECALL) ? 0 : stack.pop ();
139
+ const auto has_value = value != 0 ;
140
+
141
+ stack.push (EXTCALL_ABORT); // Assume (hard) failure.
142
+ state.return_data .clear ();
143
+
144
+ if (state.host .access_account (dst) == EVMC_ACCESS_COLD)
145
+ {
146
+ if ((gas_left -= instr::additional_cold_account_access_cost) < 0 )
147
+ return {EVMC_OUT_OF_GAS, gas_left};
148
+ }
149
+
150
+ if (!check_memory (gas_left, state.memory , input_offset_u256, input_size_u256))
151
+ return {EVMC_OUT_OF_GAS, gas_left};
152
+
153
+ const auto input_offset = static_cast <size_t >(input_offset_u256);
154
+ const auto input_size = static_cast <size_t >(input_size_u256);
155
+
156
+ auto msg = evmc_message{};
157
+ msg.kind = (Op == OP_EXTDELEGATECALL) ? EVMC_DELEGATECALL : EVMC_CALL;
158
+ msg.flags = (Op == OP_EXTSTATICCALL) ? uint32_t {EVMC_STATIC} : state.msg ->flags ;
159
+ msg.depth = state.msg ->depth + 1 ;
160
+ msg.recipient = (Op != OP_EXTDELEGATECALL) ? dst : state.msg ->recipient ;
161
+ msg.code_address = dst;
162
+ msg.sender = (Op == OP_EXTDELEGATECALL) ? state.msg ->sender : state.msg ->recipient ;
163
+ msg.value =
164
+ (Op == OP_EXTDELEGATECALL) ? state.msg ->value : intx::be::store<evmc::uint256be>(value);
165
+
166
+ if (input_size > 0 )
167
+ {
168
+ // input_offset may be garbage if input_size == 0.
169
+ msg.input_data = &state.memory [input_offset];
170
+ msg.input_size = input_size;
171
+ }
172
+
173
+ auto cost = has_value ? CALL_VALUE_COST : 0 ;
174
+
175
+ if constexpr (Op == OP_EXTCALL)
176
+ {
177
+ if (has_value && state.in_static_mode ())
178
+ return {EVMC_STATIC_MODE_VIOLATION, gas_left};
179
+
180
+ if (has_value && !state.host .account_exists (dst))
181
+ cost += ACCOUNT_CREATION_COST;
182
+ }
183
+
184
+ if ((gas_left -= cost) < 0 )
185
+ return {EVMC_OUT_OF_GAS, gas_left};
186
+
187
+ msg.gas = gas_left - std::max (gas_left / 64 , MIN_RETAINED_GAS);
188
+
189
+ if (msg.gas < MIN_CALLEE_GAS || state.msg ->depth >= 1024 ||
190
+ (has_value &&
191
+ intx::be::load<uint256>(state.host .get_balance (state.msg ->recipient )) < value))
192
+ {
193
+ stack.top () = EXTCALL_REVERT;
194
+ return {EVMC_SUCCESS, gas_left}; // "Light" failure.
195
+ }
196
+
197
+ if constexpr (Op == OP_EXTDELEGATECALL)
198
+ {
199
+ // The code targeted by EXTDELEGATECALL must also be an EOF.
200
+ // This restriction has been added to EIP-3540 in
201
+ // https://github.com/ethereum/EIPs/pull/7131
202
+ uint8_t target_code_prefix[2 ];
203
+ const auto s = state.host .copy_code (
204
+ msg.code_address , 0 , target_code_prefix, std::size (target_code_prefix));
205
+ if (!is_eof_container ({target_code_prefix, s}))
206
+ {
207
+ stack.top () = EXTCALL_REVERT;
208
+ return {EVMC_SUCCESS, gas_left}; // "Light" failure.
209
+ }
210
+ }
211
+
212
+ const auto result = state.host .call (msg);
213
+ state.return_data .assign (result.output_data , result.output_size );
214
+ if (result.status_code == EVMC_SUCCESS)
215
+ stack.top () = EXTCALL_SUCCESS;
216
+ else if (result.status_code == EVMC_REVERT)
217
+ stack.top () = EXTCALL_REVERT;
218
+ else
219
+ stack.top () = EXTCALL_ABORT;
220
+
221
+ const auto gas_used = msg.gas - result.gas_left ;
222
+ gas_left -= gas_used;
223
+ state.gas_refund += result.gas_refund ;
224
+ return {EVMC_SUCCESS, gas_left};
225
+ }
226
+
227
+ template Result extcall_impl<OP_EXTCALL>(
228
+ StackTop stack, int64_t gas_left, ExecutionState& state) noexcept ;
229
+ template Result extcall_impl<OP_EXTSTATICCALL>(
230
+ StackTop stack, int64_t gas_left, ExecutionState& state) noexcept ;
231
+ template Result extcall_impl<OP_EXTDELEGATECALL>(
232
+ StackTop stack, int64_t gas_left, ExecutionState& state) noexcept ;
136
233
137
234
template <Opcode Op>
138
235
Result create_impl (StackTop stack, int64_t gas_left, ExecutionState& state) noexcept
0 commit comments