mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 06:13:07 +00:00
Fix CALL gas (#1030)
* Fix call gas + precompiles can be non-existent * Memory expansion before call gas * Minor * Add call_gas.asm * EIP-2200: If gasleft is less than or equal to gas stipend, fail the current call frame with ‘out of gas’ exception.
This commit is contained in:
parent
944d4a2460
commit
202985b24f
@ -25,6 +25,7 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/bignum/util.asm"),
|
||||
include_str!("asm/core/bootloader.asm"),
|
||||
include_str!("asm/core/call.asm"),
|
||||
include_str!("asm/core/call_gas.asm"),
|
||||
include_str!("asm/core/create.asm"),
|
||||
include_str!("asm/core/create_addresses.asm"),
|
||||
include_str!("asm/core/create_contract_account.asm"),
|
||||
|
||||
@ -11,19 +11,19 @@ global sys_call:
|
||||
MUL // Cheaper than AND
|
||||
%jumpi(fault_exception)
|
||||
|
||||
%stack (kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(args_size, args_offset, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%stack (kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(ret_size, ret_offset, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
|
||||
SWAP2
|
||||
// stack: address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size
|
||||
%u256_to_addr // Truncate to 160 bits
|
||||
DUP1 %insert_accessed_addresses
|
||||
|
||||
%call_charge_gas
|
||||
|
||||
%stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(args_size, args_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(ret_size, ret_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%call_charge_gas(1, 1)
|
||||
|
||||
%create_context
|
||||
// stack: new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
@ -56,19 +56,19 @@ global sys_call:
|
||||
// given account. In particular the storage remains the same.
|
||||
global sys_callcode:
|
||||
// stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%stack (kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(args_size, args_offset, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%stack (kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(ret_size, ret_offset, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
|
||||
SWAP2
|
||||
// stack: address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size
|
||||
%u256_to_addr // Truncate to 160 bits
|
||||
DUP1 %insert_accessed_addresses
|
||||
|
||||
%call_charge_gas
|
||||
|
||||
%stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(args_size, args_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(ret_size, ret_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%call_charge_gas(1, 0)
|
||||
|
||||
// stack: kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%create_context
|
||||
@ -104,6 +104,13 @@ global sys_callcode:
|
||||
// CALL if the value sent is not 0.
|
||||
global sys_staticcall:
|
||||
// stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size
|
||||
%stack (kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(args_size, args_offset, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%stack (kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(ret_size, ret_offset, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
|
||||
SWAP2
|
||||
// stack: address, gas, kexit_info, args_offset, args_size, ret_offset, ret_size
|
||||
%u256_to_addr // Truncate to 160 bits
|
||||
@ -111,14 +118,7 @@ global sys_staticcall:
|
||||
|
||||
// Add a value of 0 to the stack. Slightly inefficient but that way we can reuse %call_charge_gas.
|
||||
%stack (cold_access, address, gas, kexit_info) -> (cold_access, address, gas, kexit_info, 0)
|
||||
%call_charge_gas
|
||||
|
||||
%stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(args_size, args_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(ret_size, ret_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%call_charge_gas(0, 1)
|
||||
|
||||
// stack: kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%create_context
|
||||
@ -152,6 +152,13 @@ global sys_staticcall:
|
||||
// value remain the same.
|
||||
global sys_delegatecall:
|
||||
// stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size
|
||||
%stack (kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(args_size, args_offset, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%stack (kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(ret_size, ret_offset, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
|
||||
SWAP2
|
||||
// stack: address, gas, kexit_info, args_offset, args_size, ret_offset, ret_size
|
||||
%u256_to_addr // Truncate to 160 bits
|
||||
@ -159,14 +166,7 @@ global sys_delegatecall:
|
||||
|
||||
// Add a value of 0 to the stack. Slightly inefficient but that way we can reuse %call_charge_gas.
|
||||
%stack (cold_access, address, gas, kexit_info) -> (cold_access, address, gas, kexit_info, 0)
|
||||
%call_charge_gas
|
||||
|
||||
%stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(args_size, args_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%stack (kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size) ->
|
||||
(ret_size, ret_offset, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
%checked_mem_expansion
|
||||
%call_charge_gas(0, 0)
|
||||
|
||||
// stack: kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%create_context
|
||||
@ -336,67 +336,6 @@ global after_call_instruction:
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
// Charge gas for *call opcodes and return the sub-context gas limit.
|
||||
// Doesn't include memory expansion costs.
|
||||
%macro call_charge_gas
|
||||
// Compute C_aaccess
|
||||
// stack: cold_access, address, gas, kexit_info, value
|
||||
%mul_const(@GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS)
|
||||
%add_const(@GAS_WARMACCESS)
|
||||
|
||||
// Compute C_xfer
|
||||
// stack: Caaccess, address, gas, kexit_info, value
|
||||
DUP5 ISZERO %not_bit
|
||||
// stack: value≠0, Caaccess, address, gas, kexit_info, value
|
||||
DUP1
|
||||
%mul_const(@GAS_CALLVALUE)
|
||||
|
||||
// Compute C_new
|
||||
// stack: Cxfer, value≠0, Caaccess, address, gas, kexit_info, value
|
||||
SWAP1
|
||||
// stack: value≠0, Cxfer, Caaccess, address, gas, kexit_info, value
|
||||
DUP4 %is_dead MUL
|
||||
// stack: is_dead(address) and value≠0, Cxfer, Caaccess, address, gas, kexit_info, value
|
||||
%mul_const(@GAS_NEWACCOUNT)
|
||||
// stack: Cnew, Cxfer, Caaccess, address, gas, kexit_info, value
|
||||
|
||||
// Compute C_extra
|
||||
ADD ADD
|
||||
|
||||
// Compute C_gascap
|
||||
// stack: Cextra, address, gas, kexit_info, value
|
||||
DUP4 %leftover_gas
|
||||
// stack: leftover_gas, Cextra, address, gas, kexit_info, value
|
||||
DUP2 DUP2 LT
|
||||
// stack: leftover_gas<Cextra, leftover_gas, Cextra, address, gas, kexit_info, value
|
||||
DUP5 DUP2 MUL
|
||||
// stack: (leftover_gas<Cextra)*gas, leftover_gas<Cextra, leftover_gas, Cextra, address, gas, kexit_info, value
|
||||
SWAP1 %not_bit
|
||||
// stack: leftover_gas>=Cextra, (leftover_gas<Cextra)*gas, leftover_gas, Cextra, address, gas, kexit_info, value
|
||||
DUP4 DUP4 SUB
|
||||
// stack: leftover_gas - Cextra, leftover_gas>=Cextra, (leftover_gas<Cextra)*gas, leftover_gas, Cextra, address, gas, kexit_info, value
|
||||
%all_but_one_64th
|
||||
// stack: L(leftover_gas - Cextra), leftover_gas>=Cextra, (leftover_gas<Cextra)*gas, leftover_gas, Cextra, address, gas, kexit_info, value
|
||||
DUP7 %min MUL ADD
|
||||
// stack: Cgascap, leftover_gas, Cextra, address, gas, kexit_info, value
|
||||
|
||||
// Compute C_call and charge for it.
|
||||
%stack (Cgascap, leftover_gas, Cextra) -> (Cextra, Cgascap, Cgascap)
|
||||
ADD
|
||||
%stack (C_call, Cgascap, address, gas, kexit_info, value) ->
|
||||
(C_call, kexit_info, Cgascap, address, gas, value)
|
||||
%charge_gas
|
||||
|
||||
// Compute C_callgas
|
||||
%stack (kexit_info, Cgascap, address, gas, value) ->
|
||||
(Cgascap, address, gas, kexit_info, value)
|
||||
DUP5 ISZERO %not_bit
|
||||
// stack: value!=0, Cgascap, address, gas, kexit_info, value
|
||||
%mul_const(@GAS_CALLSTIPEND) ADD
|
||||
%stack (C_callgas, address, gas, kexit_info, value) ->
|
||||
(kexit_info, C_callgas, address, value)
|
||||
%endmacro
|
||||
|
||||
// Checked memory expansion.
|
||||
%macro checked_mem_expansion
|
||||
// stack: size, offset, kexit_info
|
||||
|
||||
92
evm/src/cpu/kernel/asm/core/call_gas.asm
Normal file
92
evm/src/cpu/kernel/asm/core/call_gas.asm
Normal file
@ -0,0 +1,92 @@
|
||||
%macro call_charge_gas(is_call_or_callcode, is_call_or_staticcall)
|
||||
%stack (cold_access, address, gas, kexit_info, value) ->
|
||||
($is_call_or_callcode, $is_call_or_staticcall, cold_access, address, gas, kexit_info, value, %%after)
|
||||
%jump(call_charge_gas)
|
||||
%%after:
|
||||
// stack: kexit_info, C_callgas, address, value
|
||||
%endmacro
|
||||
|
||||
// Charge gas for *call opcodes and return the sub-context gas limit.
|
||||
// Doesn't include memory expansion costs.
|
||||
global call_charge_gas:
|
||||
// Compute C_aaccess
|
||||
// stack: is_call_or_callcode, is_call_or_staticcall, cold_access, address, gas, kexit_info, value, retdest
|
||||
SWAP2
|
||||
// stack: cold_access, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%mul_const(@GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS)
|
||||
%add_const(@GAS_WARMACCESS)
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
DUP4
|
||||
// stack: is_call_or_callcode, cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%jumpi(xfer_cost)
|
||||
after_xfer_cost:
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
DUP2
|
||||
%jumpi(new_cost)
|
||||
after_new_cost:
|
||||
%stack (Cextra, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest) ->
|
||||
(Cextra, address, gas, kexit_info, value, retdest)
|
||||
// Compute C_gascap
|
||||
// stack: Cextra, address, gas, kexit_info, value, retdest
|
||||
DUP4 %leftover_gas
|
||||
// stack: leftover_gas, Cextra, address, gas, kexit_info, value, retdest
|
||||
DUP2 DUP2 LT
|
||||
// stack: leftover_gas<Cextra, leftover_gas, Cextra, address, gas, kexit_info, value, retdest
|
||||
DUP5 DUP2 MUL
|
||||
// stack: (leftover_gas<Cextra)*gas, leftover_gas<Cextra, leftover_gas, Cextra, address, gas, kexit_info, value, retdest
|
||||
SWAP1 %not_bit
|
||||
// stack: leftover_gas>=Cextra, (leftover_gas<Cextra)*gas, leftover_gas, Cextra, address, gas, kexit_info, value, retdest
|
||||
DUP4 DUP4 SUB
|
||||
// stack: leftover_gas - Cextra, leftover_gas>=Cextra, (leftover_gas<Cextra)*gas, leftover_gas, Cextra, address, gas, kexit_info, value, retdest
|
||||
%all_but_one_64th
|
||||
// stack: L(leftover_gas - Cextra), leftover_gas>=Cextra, (leftover_gas<Cextra)*gas, leftover_gas, Cextra, address, gas, kexit_info, value, retdest
|
||||
DUP7 %min MUL ADD
|
||||
// stack: Cgascap, leftover_gas, Cextra, address, gas, kexit_info, value, retdest
|
||||
|
||||
// Compute C_call and charge for it.
|
||||
%stack (Cgascap, leftover_gas, Cextra) -> (Cextra, Cgascap, Cgascap)
|
||||
ADD
|
||||
%stack (C_call, Cgascap, address, gas, kexit_info, value) ->
|
||||
(C_call, kexit_info, Cgascap, address, gas, value)
|
||||
%charge_gas
|
||||
|
||||
// Compute C_callgas
|
||||
%stack (kexit_info, Cgascap, address, gas, value) ->
|
||||
(Cgascap, address, gas, kexit_info, value)
|
||||
DUP5 ISZERO %not_bit
|
||||
// stack: value!=0, Cgascap, address, gas, kexit_info, value, retdest
|
||||
%mul_const(@GAS_CALLSTIPEND) ADD
|
||||
%stack (C_callgas, address, gas, kexit_info, value, retdest) ->
|
||||
(retdest, kexit_info, C_callgas, address, value)
|
||||
JUMP
|
||||
|
||||
xfer_cost:
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
DUP7
|
||||
// stack: value, cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%jumpi(xfer_cost_nonzero)
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%jump(after_xfer_cost)
|
||||
xfer_cost_nonzero:
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%add_const(@GAS_CALLVALUE)
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%jump(after_xfer_cost)
|
||||
|
||||
new_cost:
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
DUP7
|
||||
// stack: value, cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%jumpi(new_cost_transfers_value)
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%jump(after_new_cost)
|
||||
new_cost_transfers_value:
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
DUP4 %is_dead
|
||||
%jumpi(new_cost_nonzero)
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%jump(after_new_cost)
|
||||
new_cost_nonzero:
|
||||
// stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest
|
||||
%add_const(@GAS_NEWACCOUNT)
|
||||
%jump(after_new_cost)
|
||||
@ -38,14 +38,7 @@
|
||||
// Returns 1 if the account is non-existent, 0 otherwise.
|
||||
%macro is_non_existent
|
||||
// stack: addr
|
||||
DUP1
|
||||
// stack: addr, addr
|
||||
%mpt_read_state_trie ISZERO
|
||||
SWAP1
|
||||
// stack: addr, zero_state_trie
|
||||
%is_precompile ISZERO
|
||||
// stack: not_precompile, zero_state_trie
|
||||
MUL // Cheaper than AND
|
||||
%endmacro
|
||||
|
||||
// Returns 1 if the account is empty, 0 otherwise.
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
global sys_sstore:
|
||||
%check_static
|
||||
DUP1 %leftover_gas %le_const(@GAS_CALLSTIPEND) %jumpi(fault_exception)
|
||||
%stack (kexit_info, slot, value) -> (slot, kexit_info, slot, value)
|
||||
%sload_current
|
||||
%address
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user