mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-23 02:29:26 +00:00
parent
94ec3349a4
commit
4b142ac52d
@ -18,3 +18,6 @@ type
|
||||
FkIstanbul = "Istanbul"
|
||||
FkBerlin = "Berlin"
|
||||
FkLondon = "London"
|
||||
FkParis = "Paris"
|
||||
FkShanghai = "Shanghai"
|
||||
FkCancun = "Cancun"
|
||||
|
@ -38,7 +38,10 @@ const
|
||||
eth2, # FkPetersburg
|
||||
eth2, # FkIstanbul
|
||||
eth2, # FkBerlin
|
||||
eth2 # FkLondon
|
||||
eth2, # FkLondon
|
||||
eth0, # FkParis
|
||||
eth0, # FkShanghai
|
||||
eth0, # FkCancun
|
||||
]
|
||||
|
||||
{.push raises: [Defect].}
|
||||
|
@ -53,8 +53,8 @@ proc hostToComputationMessage*(msg: EvmcMessage): Message =
|
||||
depth: msg.depth,
|
||||
gas: msg.gas,
|
||||
sender: msg.sender.fromEvmc,
|
||||
contractAddress: msg.destination.fromEvmc,
|
||||
codeAddress: msg.destination.fromEvmc,
|
||||
contractAddress: msg.recipient.fromEvmc,
|
||||
codeAddress: msg.code_address.fromEvmc,
|
||||
value: msg.value.fromEvmc,
|
||||
# When input size is zero, input data pointer may be null.
|
||||
data: if msg.input_size <= 0: @[]
|
||||
@ -122,18 +122,19 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||
let host = TransactionHost(
|
||||
vmState: vmState,
|
||||
msg: EvmcMessage(
|
||||
kind: if call.isCreate: EVMC_CREATE else: EVMC_CALL,
|
||||
kind: if call.isCreate: EVMC_CREATE else: EVMC_CALL,
|
||||
# Default: flags: {},
|
||||
# Default: depth: 0,
|
||||
gas: call.gasLimit - intrinsicGas,
|
||||
destination: call.to.toEvmc,
|
||||
sender: call.sender.toEvmc,
|
||||
value: call.value.toEvmc,
|
||||
gas: call.gasLimit - intrinsicGas,
|
||||
recipient: call.to.toEvmc,
|
||||
code_address: call.to.toEvmc,
|
||||
sender: call.sender.toEvmc,
|
||||
value: call.value.toEvmc,
|
||||
)
|
||||
# All other defaults in `TransactionHost` are fine.
|
||||
)
|
||||
|
||||
# Generate new contract address, prepare code, and update message `destination`
|
||||
# Generate new contract address, prepare code, and update message `recipient`
|
||||
# with the contract address. This differs from the previous Nimbus EVM API.
|
||||
# Guarded under `evmc_enabled` for now so it doesn't break vm2.
|
||||
when defined(evmc_enabled):
|
||||
@ -142,14 +143,14 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||
let sender = call.sender
|
||||
let contractAddress =
|
||||
generateAddress(sender, call.vmState.readOnlyStateDB.getNonce(sender))
|
||||
host.msg.destination = contractAddress.toEvmc
|
||||
host.msg.recipient = contractAddress.toEvmc
|
||||
host.msg.input_size = 0
|
||||
host.msg.input_data = nil
|
||||
code = call.input
|
||||
else:
|
||||
# TODO: Share the underlying data, but only after checking this does not
|
||||
# cause problems with the database.
|
||||
code = host.vmState.readOnlyStateDB.getCode(host.msg.destination.fromEvmc)
|
||||
code = host.vmState.readOnlyStateDB.getCode(host.msg.code_address.fromEvmc)
|
||||
if call.input.len > 0:
|
||||
host.msg.input_size = call.input.len.csize_t
|
||||
# Must copy the data so the `host.msg.input_data` pointer
|
||||
|
@ -132,8 +132,8 @@ proc evmcExecComputation*(host: TransactionHost): EvmcResult {.inline.} =
|
||||
|
||||
host.showCallReturn(result)
|
||||
|
||||
# This code assumes fields, methods and types of ABI version 9, and must be
|
||||
# This code assumes fields, methods and types of ABI version 10, and must be
|
||||
# checked for compatibility if the `import evmc/evmc` major version is updated.
|
||||
when EVMC_ABI_VERSION != 9:
|
||||
{.error: ("This code assumes EVMC_ABI_VERSION 9;" &
|
||||
when EVMC_ABI_VERSION != 10:
|
||||
{.error: ("This code assumes EVMC_ABI_VERSION 10;" &
|
||||
" update the code to use EVMC_ABI_VERSION " & $EVMC_ABI_VERSION).}
|
||||
|
@ -64,6 +64,8 @@ proc evmcExecute(vm: ptr evmc_vm, hostInterface: ptr evmc_host_interface,
|
||||
# Gas left is required to be zero when not `EVMC_SUCCESS` or `EVMC_REVERT`.
|
||||
gas_left: if result.status_code notin {EVMC_SUCCESS, EVMC_REVERT}: 0'i64
|
||||
else: c.gasMeter.gasRemaining.int64,
|
||||
gas_refund: if result.status_code == EVMC_SUCCESS: c.gasMeter.gasRefunded.int64
|
||||
else: 0'i64,
|
||||
output_data: output_data,
|
||||
output_size: output_size.csize_t,
|
||||
release: if output_data.isNil: nil
|
||||
@ -100,8 +102,8 @@ proc evmc_create_nimbus_evm(): ptr evmc_vm {.cdecl, exportc.} =
|
||||
GC_ref(vm)
|
||||
return cast[ptr evmc_vm](vm)
|
||||
|
||||
# This code assumes fields, methods and types of ABI version 9, and must be
|
||||
# This code assumes fields, methods and types of ABI version 10, and must be
|
||||
# checked for compatibility if the `import evmc/evmc` major version is updated.
|
||||
when EVMC_ABI_VERSION != 9:
|
||||
{.error: ("This code assumes EVMC_ABI_VERSION 9;" &
|
||||
when EVMC_ABI_VERSION != 10:
|
||||
{.error: ("This code assumes EVMC_ABI_VERSION 10;" &
|
||||
" update the code to use EVMC_ABI_VERSION " & $EVMC_ABI_VERSION).}
|
||||
|
@ -56,9 +56,9 @@ proc beforeExecCallEvmcNested(host: TransactionHost,
|
||||
depth: m.depth,
|
||||
gas: m.gas,
|
||||
sender: m.sender.fromEvmc,
|
||||
codeAddress: m.destination.fromEvmc,
|
||||
codeAddress: m.code_address.fromEvmc,
|
||||
contractAddress: if m.kind == EVMC_CALL:
|
||||
m.destination.fromEvmc
|
||||
m.recipient.fromEvmc
|
||||
else:
|
||||
host.computation.msg.contractAddress,
|
||||
value: m.value.fromEvmc,
|
||||
|
@ -11,7 +11,7 @@
|
||||
import
|
||||
sets, times, stint, chronicles,
|
||||
eth/common/eth_types, ../db/accounts_cache, ../forks,
|
||||
".."/[vm_state, vm_computation, vm_internals],
|
||||
".."/[vm_state, vm_computation, vm_internals, vm_gas_costs],
|
||||
./host_types, ./host_trace, ./host_call_nested
|
||||
|
||||
proc setupTxContext(host: TransactionHost) =
|
||||
@ -45,7 +45,7 @@ proc setupTxContext(host: TransactionHost) =
|
||||
# [EIP-1985](https://eips.ethereum.org/EIPS/eip-1985) although it's not
|
||||
# officially accepted), and `vmState.gasLimit` is too (`GasInt`).
|
||||
#
|
||||
# `txContext.block_difficulty` is 256-bit, and this one can genuinely take
|
||||
# `txContext.block_prev_randao` is 256-bit, and this one can genuinely take
|
||||
# values over much of the 256-bit range.
|
||||
|
||||
let vmState = host.vmState
|
||||
@ -73,7 +73,7 @@ proc setupTxContext(host: TransactionHost) =
|
||||
# EIP-4399
|
||||
# Transfer block randomness to difficulty OPCODE
|
||||
let difficulty = vmState.difficulty.toEvmc
|
||||
host.txContext.block_difficulty = flip256(difficulty)
|
||||
host.txContext.block_prev_randao = flip256(difficulty)
|
||||
|
||||
host.cachedTxContext = true
|
||||
|
||||
@ -100,80 +100,66 @@ proc accountExists(host: TransactionHost, address: HostAddress): bool {.show.} =
|
||||
proc getStorage(host: TransactionHost, address: HostAddress, key: HostKey): HostValue {.show.} =
|
||||
host.vmState.readOnlyStateDB.getStorage(address, key)
|
||||
|
||||
const
|
||||
# EIP-1283
|
||||
SLOAD_GAS_CONSTANTINOPLE = 200
|
||||
# EIP-2200
|
||||
SSTORE_SET_GAS = 20000
|
||||
SSTORE_RESET_GAS = 5000
|
||||
SLOAD_GAS_ISTANBUL = 800
|
||||
# EIP-2929
|
||||
WARM_STORAGE_READ_COST = 100
|
||||
COLD_SLOAD_COST = 2100
|
||||
COLD_ACCOUNT_ACCESS_COST = 2600
|
||||
proc setStorageStatus(host: TransactionHost, address: HostAddress,
|
||||
key: HostKey, newVal: HostValue): EvmcStorageStatus {.show.} =
|
||||
let
|
||||
db = host.vmState.readOnlyStateDB
|
||||
currentVal = db.getStorage(address, key)
|
||||
|
||||
SSTORE_CLEARS_SCHEDULE_EIP2200 = 15000
|
||||
SSTORE_CLEARS_SCHEDULE_EIP3529 = 4800
|
||||
|
||||
func storageModifiedAgainRefund(originalValue, oldValue, value: HostValue,
|
||||
fork: Fork): int {.inline.} =
|
||||
# Calculate `SSTORE` refund according to EIP-2929 (Berlin),
|
||||
# EIP-2200 (Istanbul) or EIP-1283 (Constantinople only).
|
||||
result = 0
|
||||
if value == originalValue:
|
||||
result = if value.isZero: SSTORE_SET_GAS
|
||||
elif fork >= FkBerlin: SSTORE_RESET_GAS - COLD_SLOAD_COST
|
||||
else: SSTORE_RESET_GAS
|
||||
let SLOAD_GAS = if fork >= FkBerlin: WARM_STORAGE_READ_COST
|
||||
elif fork >= FkIstanbul: SLOAD_GAS_ISTANBUL
|
||||
else: SLOAD_GAS_CONSTANTINOPLE
|
||||
result -= SLOAD_GAS
|
||||
|
||||
let SSTORE_CLEARS_SCHEDULE = if fork >= FkLondon:
|
||||
SSTORE_CLEARS_SCHEDULE_EIP3529
|
||||
else:
|
||||
SSTORE_CLEARS_SCHEDULE_EIP2200
|
||||
if not originalValue.isZero:
|
||||
if value.isZero:
|
||||
result += SSTORE_CLEARS_SCHEDULE
|
||||
elif oldValue.isZero:
|
||||
result -= SSTORE_CLEARS_SCHEDULE
|
||||
|
||||
proc setStorage(host: TransactionHost, address: HostAddress,
|
||||
key: HostKey, value: HostValue): EvmcStorageStatus {.show.} =
|
||||
let db = host.vmState.readOnlyStateDB
|
||||
let oldValue = db.getStorage(address, key)
|
||||
|
||||
if oldValue == value:
|
||||
return EVMC_STORAGE_UNCHANGED
|
||||
if currentVal == newVal:
|
||||
return EVMC_STORAGE_ASSIGNED
|
||||
|
||||
host.vmState.mutateStateDB:
|
||||
db.setStorage(address, key, value)
|
||||
db.setStorage(address, key, newVal)
|
||||
|
||||
if host.vmState.fork >= FkIstanbul or host.vmState.fork == FkConstantinople:
|
||||
let originalValue = db.getCommittedStorage(address, key)
|
||||
if oldValue != originalValue:
|
||||
# Gas refund for `MODIFIED_AGAIN` (EIP-1283/2200/2929 only).
|
||||
let refund = storageModifiedAgainRefund(originalValue, oldValue, value,
|
||||
host.vmState.fork)
|
||||
# TODO: Refund depends on `Computation` at the moment.
|
||||
if refund != 0:
|
||||
host.computation.gasMeter.refundGas(refund)
|
||||
return EVMC_STORAGE_MODIFIED_AGAIN
|
||||
# https://eips.ethereum.org/EIPS/eip-1283
|
||||
let originalVal = db.getCommittedStorage(address, key)
|
||||
if originalVal == currentVal:
|
||||
if originalVal.isZero:
|
||||
return EVMC_STORAGE_ADDED
|
||||
|
||||
if oldValue.isZero:
|
||||
return EVMC_STORAGE_ADDED
|
||||
elif value.isZero:
|
||||
# Gas refund for `DELETED` (all forks).
|
||||
# TODO: Refund depends on `Computation` at the moment.
|
||||
let SSTORE_CLEARS_SCHEDULE = if host.vmState.fork >= FkLondon:
|
||||
SSTORE_CLEARS_SCHEDULE_EIP3529
|
||||
else:
|
||||
SSTORE_CLEARS_SCHEDULE_EIP2200
|
||||
host.computation.gasMeter.refundGas(SSTORE_CLEARS_SCHEDULE)
|
||||
return EVMC_STORAGE_DELETED
|
||||
# !is_zero(original_val)
|
||||
if newVal.isZero:
|
||||
return EVMC_STORAGE_DELETED
|
||||
else:
|
||||
return EVMC_STORAGE_MODIFIED
|
||||
|
||||
# originalVal != currentVal
|
||||
if originalVal.isZero.not:
|
||||
if currentVal.isZero:
|
||||
if originalVal == newVal:
|
||||
return EVMC_STORAGE_DELETED_RESTORED
|
||||
else:
|
||||
return EVMC_STORAGE_DELETED_ADDED
|
||||
|
||||
# !is_zero(current_val)
|
||||
if newVal.isZero:
|
||||
return EVMC_STORAGE_MODIFIED_DELETED
|
||||
|
||||
# !is_zero(new_val)
|
||||
if originalVal == newVal:
|
||||
return EVMC_STORAGE_MODIFIED_RESTORED
|
||||
else:
|
||||
return EVMC_STORAGE_ASSIGNED
|
||||
|
||||
# is_zero(original_val)
|
||||
if originalVal == newVal:
|
||||
return EVMC_STORAGE_ADDED_DELETED
|
||||
else:
|
||||
return EVMC_STORAGE_MODIFIED
|
||||
return EVMC_STORAGE_ASSIGNED
|
||||
|
||||
proc setStorage(host: TransactionHost, address: HostAddress,
|
||||
key: HostKey, newVal: HostValue): EvmcStorageStatus {.show.} =
|
||||
let
|
||||
status = setStorageStatus(host, address, key, newVal)
|
||||
fork = host.vmState.fork
|
||||
refund = SstoreCost[fork][status].gasRefund
|
||||
|
||||
if refund != 0:
|
||||
# TODO: Refund depends on `Computation` at the moment.
|
||||
host.computation.gasMeter.refundGas(refund)
|
||||
|
||||
status
|
||||
|
||||
proc getBalance(host: TransactionHost, address: HostAddress): HostBalance {.show.} =
|
||||
host.vmState.readOnlyStateDB.getBalance(address)
|
||||
|
@ -58,7 +58,8 @@ proc showEvmcMessage(msg: EvmcMessage): string =
|
||||
&" gas={$msg.gas}" &
|
||||
&" value={$msg.value.fromEvmc}" &
|
||||
&" sender={$msg.sender.fromEvmc}" &
|
||||
&" destination={$msg.destination.fromEvmc}" &
|
||||
&" recipient={$msg.recipient.fromEvmc}" &
|
||||
&" code_address={$msg.code_address.fromEvmc}" &
|
||||
&" input_data={inputStr}"
|
||||
if msg.kind == EVMC_CREATE2:
|
||||
result.add &" create2_salt={$msg.create2_salt.fromEvmc}"
|
||||
@ -88,7 +89,7 @@ proc showEvmcTxContext(txc: EvmcTxContext): string =
|
||||
&" block_number={$txc.block_number}" &
|
||||
&" block_timestamp={$txc.block_timestamp}" &
|
||||
&" block_gas_limit={$txc.block_gas_limit}" &
|
||||
&" block_difficulty={$txc.block_difficulty.fromEvmc}" &
|
||||
&" block_prev_randao={$txc.block_prev_randao.fromEvmc}" &
|
||||
&" chain_id={$txc.chain_id.fromEvmc}" &
|
||||
&" block_base_fee={$txc.block_base_fee.fromEvmc}"
|
||||
|
||||
|
@ -82,7 +82,7 @@ template getBlockNumber*(c: Computation): UInt256 =
|
||||
|
||||
template getDifficulty*(c: Computation): DifficultyInt =
|
||||
when evmc_enabled:
|
||||
UInt256.fromEvmc c.host.getTxContext().block_difficulty
|
||||
UInt256.fromEvmc c.host.getTxContext().block_prev_randao
|
||||
else:
|
||||
c.vmState.difficulty
|
||||
|
||||
@ -192,12 +192,6 @@ proc newComputation*(vmState: BaseVMState, message: Message,
|
||||
result.code = newCodeStream(
|
||||
vmState.readOnlyStateDB.getCode(message.codeAddress))
|
||||
|
||||
when evmc_enabled:
|
||||
result.host.init(
|
||||
nim_host_get_interface(),
|
||||
cast[evmc_host_context](result)
|
||||
)
|
||||
|
||||
proc newComputation*(vmState: BaseVMState, message: Message, code: seq[byte]): Computation =
|
||||
new result
|
||||
result.vmState = vmState
|
||||
@ -210,12 +204,6 @@ proc newComputation*(vmState: BaseVMState, message: Message, code: seq[byte]): C
|
||||
result.selfDestructs = initHashSet[EthAddress]()
|
||||
result.code = newCodeStream(code)
|
||||
|
||||
when evmc_enabled:
|
||||
result.host.init(
|
||||
nim_host_get_interface(),
|
||||
cast[evmc_host_context](result)
|
||||
)
|
||||
|
||||
template gasCosts*(c: Computation): untyped =
|
||||
c.vmState.gasCosts
|
||||
|
||||
|
@ -23,30 +23,32 @@ type
|
||||
block_number* : int64 # The block number.
|
||||
block_timestamp* : int64 # The block timestamp.
|
||||
block_gas_limit* : int64 # The block gas limit.
|
||||
block_difficulty*: evmc_uint256be # The block difficulty.
|
||||
block_prev_randao*: evmc_uint256be # The block difficulty.
|
||||
chain_id* : evmc_uint256be # The blockchain's ChainID.
|
||||
block_base_fee* : evmc_uint256be # The block base fee.
|
||||
|
||||
nimbus_message* = object
|
||||
kind*: evmc_call_kind
|
||||
flags*: uint32
|
||||
depth*: int32
|
||||
gas*: int64
|
||||
destination*: EthAddress
|
||||
sender*: EthAddress
|
||||
input_data*: ptr byte
|
||||
input_size*: uint
|
||||
value*: evmc_uint256be
|
||||
kind* : evmc_call_kind
|
||||
flags* : uint32
|
||||
depth* : int32
|
||||
gas* : int64
|
||||
recipient* : EthAddress
|
||||
sender* : EthAddress
|
||||
input_data* : ptr byte
|
||||
input_size* : uint
|
||||
value* : evmc_uint256be
|
||||
create2_salt*: evmc_bytes32
|
||||
code_address*: EthAddress
|
||||
|
||||
nimbus_result* = object
|
||||
status_code*: evmc_status_code
|
||||
gas_left*: int64
|
||||
output_data*: ptr byte
|
||||
output_size*: uint
|
||||
release*: proc(result: var nimbus_result) {.cdecl, gcsafe.}
|
||||
status_code* : evmc_status_code
|
||||
gas_left* : int64
|
||||
gas_refund* : int64
|
||||
output_data* : ptr byte
|
||||
output_size* : uint
|
||||
release* : proc(result: var nimbus_result) {.cdecl, gcsafe.}
|
||||
create_address*: EthAddress
|
||||
padding*: array[4, byte]
|
||||
padding* : array[4, byte]
|
||||
|
||||
nimbus_host_interface* = object
|
||||
account_exists*: proc(context: evmc_host_context, address: EthAddress): bool {.cdecl, gcsafe.}
|
||||
@ -151,11 +153,3 @@ proc accessStorage*(ctx: HostContext, address: EthAddress,
|
||||
key: UInt256): evmc_access_status {.inline.} =
|
||||
var key = toEvmc(key)
|
||||
ctx.host.access_storage(ctx.context, address, key)
|
||||
|
||||
#proc vmHost*(vmState: BaseVMState, gasPrice: GasInt, origin: EthAddress): HostContext =
|
||||
# let host = nim_host_get_interface()
|
||||
# let context = nim_host_create_context(cast[pointer](vmState), gasPrice, toEvmc(origin))
|
||||
# result.init(host, context)
|
||||
#
|
||||
#proc destroy*(hc: HostContext) =
|
||||
# nim_host_destroy_context(hc.context)
|
||||
|
@ -1,288 +0,0 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2019 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
proc hostReleaseResultImpl(res: var nimbus_result) {.cdecl, gcsafe.} =
|
||||
dealloc(res.output_data)
|
||||
|
||||
proc hostGetTxContextImpl(ctx: Computation): nimbus_tx_context {.cdecl.} =
|
||||
let vmstate = ctx.vmState
|
||||
result.tx_gas_price = toEvmc(vmstate.txGasPrice.u256)
|
||||
result.tx_origin = vmstate.txOrigin
|
||||
result.block_coinbase = vmstate.coinbase
|
||||
result.block_number = vmstate.blockNumber.truncate(int64)
|
||||
result.block_timestamp = vmstate.timestamp.toUnix()
|
||||
result.block_gas_limit = int64(vmstate.gasLimit)
|
||||
|
||||
# EIP-4399
|
||||
# Transfer block randomness to difficulty OPCODE
|
||||
let difficulty = toEvmc(vmstate.difficulty)
|
||||
result.block_difficulty = difficulty
|
||||
|
||||
result.chain_id = toEvmc(vmstate.chaindb.config.chainId.uint.u256)
|
||||
result.block_base_fee = toEvmc(vmstate.baseFee)
|
||||
|
||||
proc hostGetBlockHashImpl(ctx: Computation, number: int64): Hash256 {.cdecl.} =
|
||||
ctx.vmState.getAncestorHash(number.u256)
|
||||
|
||||
proc hostAccountExistsImpl(ctx: Computation, address: EthAddress): bool {.cdecl.} =
|
||||
let db = ctx.vmState.readOnlyStateDB
|
||||
if ctx.fork >= FkSpurious:
|
||||
not db.isDeadAccount(address)
|
||||
else:
|
||||
db.accountExists(address)
|
||||
|
||||
proc hostGetStorageImpl(ctx: Computation, address: EthAddress, key: var evmc_bytes32): evmc_bytes32 {.cdecl.} =
|
||||
ctx.vmState.stateDB.getStorage(address, UInt256.fromEvmc(key)).toEvmc()
|
||||
|
||||
proc sstoreNetGasMetering(ctx: Computation): bool {.inline.} =
|
||||
ctx.fork in {FkConstantinople, FkIstanbul, FkBerlin, FkLondon}
|
||||
|
||||
proc hostSetStorageImpl(ctx: Computation, address: EthAddress,
|
||||
key, value: var evmc_bytes32): evmc_storage_status {.cdecl.} =
|
||||
let
|
||||
slot = UInt256.fromEvmc(key)
|
||||
newValue = UInt256.fromEvmc(value)
|
||||
statedb = ctx.vmState.readOnlyStateDB
|
||||
currValue = statedb.getStorage(address, slot)
|
||||
|
||||
assert address == ctx.msg.contractAddress
|
||||
|
||||
var
|
||||
status = EVMC_STORAGE_MODIFIED
|
||||
gasRefund = 0.GasInt
|
||||
origValue = 0.u256
|
||||
|
||||
if newValue == currValue:
|
||||
status = EVMC_STORAGE_UNCHANGED
|
||||
else:
|
||||
origValue = statedb.getCommittedStorage(address, slot)
|
||||
if origValue == currValue or not ctx.sstoreNetGasMetering():
|
||||
if currValue == 0:
|
||||
status = EVMC_STORAGE_ADDED
|
||||
elif newValue == 0:
|
||||
status = EVMC_STORAGE_DELETED
|
||||
else:
|
||||
status = EVMC_STORAGE_MODIFIED_AGAIN
|
||||
ctx.vmState.mutateStateDB:
|
||||
db.setStorage(address, slot, newValue)
|
||||
|
||||
let gasParam = GasParams(kind: Op.Sstore,
|
||||
s_status: status,
|
||||
s_currentValue: currValue,
|
||||
s_originalValue: origValue
|
||||
)
|
||||
gasRefund = ctx.gasCosts[Sstore].c_handler(newValue, gasParam)[1]
|
||||
|
||||
if gasRefund != 0:
|
||||
ctx.gasMeter.refundGas(gasRefund)
|
||||
|
||||
result = status
|
||||
|
||||
proc hostGetBalanceImpl(ctx: Computation, address: EthAddress): evmc_bytes32 {.cdecl.} =
|
||||
ctx.vmState.readOnlyStateDB.getBalance(address).toEvmc()
|
||||
|
||||
proc hostGetCodeSizeImpl(ctx: Computation, address: EthAddress): uint {.cdecl.} =
|
||||
ctx.vmState.readOnlyStateDB.getCode(address).len.uint
|
||||
|
||||
proc hostGetCodeHashImpl(ctx: Computation, address: EthAddress): Hash256 {.cdecl.} =
|
||||
let db = ctx.vmstate.readOnlyStateDB
|
||||
if not db.accountExists(address):
|
||||
return
|
||||
if db.isEmptyAccount(address):
|
||||
return
|
||||
db.getCodeHash(address)
|
||||
|
||||
proc hostCopyCodeImpl(ctx: Computation, address: EthAddress,
|
||||
codeOffset: int, bufferData: ptr byte,
|
||||
bufferSize: int): int {.cdecl.} =
|
||||
|
||||
var code = ctx.vmState.readOnlyStateDB.getCode(address)
|
||||
|
||||
# Handle "big offset" edge case.
|
||||
if codeOffset > code.len:
|
||||
return 0
|
||||
|
||||
let maxToCopy = code.len - codeOffset
|
||||
let numToCopy = min(maxToCopy, bufferSize)
|
||||
if numToCopy > 0:
|
||||
copyMem(bufferData, code[codeOffset].addr, numToCopy)
|
||||
result = numToCopy
|
||||
|
||||
proc hostSelfdestructImpl(ctx: Computation, address, beneficiary: EthAddress) {.cdecl.} =
|
||||
assert address == ctx.msg.contractAddress
|
||||
ctx.execSelfDestruct(beneficiary)
|
||||
|
||||
proc hostEmitLogImpl(ctx: Computation, address: EthAddress,
|
||||
data: ptr byte, dataSize: int,
|
||||
topics: UncheckedArray[evmc_bytes32], topicsCount: int) {.cdecl.} =
|
||||
var log: Log
|
||||
if topicsCount > 0:
|
||||
log.topics = newSeq[Topic](topicsCount)
|
||||
for i in 0 ..< topicsCount:
|
||||
log.topics[i] = topics[i].bytes
|
||||
|
||||
log.data = @(makeOpenArray(data, dataSize))
|
||||
log.address = address
|
||||
ctx.addLogEntry(log)
|
||||
|
||||
proc hostAccessAccountImpl(ctx: Computation, address: EthAddress): evmc_access_status {.cdecl.} =
|
||||
ctx.vmState.mutateStateDB:
|
||||
if not db.inAccessList(address):
|
||||
db.accessList(address)
|
||||
return EVMC_ACCESS_COLD
|
||||
else:
|
||||
return EVMC_ACCESS_WARM
|
||||
|
||||
proc hostAccessStorageImpl(ctx: Computation, address: EthAddress,
|
||||
key: var evmc_bytes32): evmc_access_status {.cdecl.} =
|
||||
let slot = UInt256.fromEvmc(key)
|
||||
ctx.vmState.mutateStateDB:
|
||||
if not db.inAccessList(address, slot):
|
||||
db.accessList(address, slot)
|
||||
return EVMC_ACCESS_COLD
|
||||
else:
|
||||
return EVMC_ACCESS_WARM
|
||||
|
||||
proc enterCreateImpl(c: Computation, m: nimbus_message): Computation =
|
||||
# TODO: use evmc_message to evoid copy
|
||||
let childMsg = Message(
|
||||
kind: CallKind(m.kind),
|
||||
depth: m.depth,
|
||||
gas: m.gas,
|
||||
sender: m.sender,
|
||||
value: UInt256.fromEvmc(m.value),
|
||||
data: @(makeOpenArray(m.inputData, m.inputSize.int))
|
||||
)
|
||||
return newComputation(c.vmState, childMsg,
|
||||
ContractSalt.fromEvmc(m.create2_salt))
|
||||
|
||||
template leaveCreateImpl(c, child: Computation, res: nimbus_result) =
|
||||
if not child.shouldBurnGas:
|
||||
res.gas_left = child.gasMeter.gasRemaining
|
||||
|
||||
if child.isSuccess:
|
||||
c.merge(child)
|
||||
res.status_code = EVMC_SUCCESS
|
||||
res.create_address = child.msg.contractAddress
|
||||
else:
|
||||
res.status_code = if child.shouldBurnGas: EVMC_FAILURE else: EVMC_REVERT
|
||||
if child.output.len > 0:
|
||||
# TODO: can we move the ownership of seq to raw pointer?
|
||||
res.output_size = child.output.len.uint
|
||||
res.output_data = cast[ptr byte](alloc(child.output.len))
|
||||
copyMem(res.output_data, child.output[0].addr, child.output.len)
|
||||
res.release = hostReleaseResultImpl
|
||||
|
||||
template enterCallImpl(c: Computation, m: nimbus_message): Computation =
|
||||
let childMsg = Message(
|
||||
kind: CallKind(m.kind),
|
||||
depth: m.depth,
|
||||
gas: m.gas,
|
||||
sender: m.sender,
|
||||
codeAddress: m.destination,
|
||||
contractAddress: if m.kind == EVMC_CALL: m.destination else: c.msg.contractAddress,
|
||||
value: UInt256.fromEvmc(m.value),
|
||||
data: @(makeOpenArray(m.inputData, m.inputSize.int)),
|
||||
flags: MsgFlags(m.flags)
|
||||
)
|
||||
newComputation(c.vmState, childMsg)
|
||||
|
||||
template leaveCallImpl(c, child: Computation, res: nimbus_result) =
|
||||
if not child.shouldBurnGas:
|
||||
res.gas_left = child.gasMeter.gasRemaining
|
||||
|
||||
if child.isSuccess:
|
||||
c.merge(child)
|
||||
res.status_code = EVMC_SUCCESS
|
||||
else:
|
||||
res.status_code = if child.shouldBurnGas: EVMC_FAILURE else: EVMC_REVERT
|
||||
|
||||
if child.output.len > 0:
|
||||
# TODO: can we move the ownership of seq to raw pointer?
|
||||
res.output_size = child.output.len.uint
|
||||
res.output_data = cast[ptr byte](alloc(child.output.len))
|
||||
copyMem(res.output_data, child.output[0].addr, child.output.len)
|
||||
res.release = hostReleaseResultImpl
|
||||
|
||||
proc enterHostCall(c: Computation, msg: var nimbus_message): Computation {.noinline.} =
|
||||
if msg.kind == EVMC_CREATE or msg.kind == EVMC_CREATE2:
|
||||
enterCreateImpl(c, msg)
|
||||
else:
|
||||
enterCallImpl(c, msg)
|
||||
|
||||
proc leaveHostCall(c, child: Computation, kind: evmc_call_kind): nimbus_result {.noinline.} =
|
||||
if kind == EVMC_CREATE or kind == EVMC_CREATE2:
|
||||
leaveCreateImpl(c, child, result)
|
||||
else:
|
||||
leaveCallImpl(c, child, result)
|
||||
|
||||
proc hostCallImpl(ctx: Computation, msg: var nimbus_message): nimbus_result {.cdecl.} =
|
||||
let child = enterHostCall(ctx, msg)
|
||||
child.execCallOrCreate()
|
||||
leaveHostCall(ctx, child, msg.kind)
|
||||
|
||||
proc initHostInterface(): evmc_host_interface =
|
||||
result.account_exists = cast[evmc_account_exists_fn](hostAccountExistsImpl)
|
||||
result.get_storage = cast[evmc_get_storage_fn](hostGetStorageImpl)
|
||||
result.set_storage = cast[evmc_set_storage_fn](hostSetStorageImpl)
|
||||
result.get_balance = cast[evmc_get_balance_fn](hostGetBalanceImpl)
|
||||
result.get_code_size = cast[evmc_get_code_size_fn](hostGetCodeSizeImpl)
|
||||
result.get_code_hash = cast[evmc_get_code_hash_fn](hostGetCodeHashImpl)
|
||||
result.copy_code = cast[evmc_copy_code_fn](hostCopyCodeImpl)
|
||||
result.selfdestruct = cast[evmc_selfdestruct_fn](hostSelfdestructImpl)
|
||||
result.call = cast[evmc_call_fn](hostCallImpl)
|
||||
result.get_tx_context = cast[evmc_get_tx_context_fn](hostGetTxContextImpl)
|
||||
result.get_block_hash = cast[evmc_get_block_hash_fn](hostGetBlockHashImpl)
|
||||
result.emit_log = cast[evmc_emit_log_fn](hostEmitLogImpl)
|
||||
result.access_account = cast[evmc_access_account_fn](hostAccessAccountImpl)
|
||||
result.access_storage = cast[evmc_access_storage_fn](hostAccessStorageImpl)
|
||||
|
||||
proc vmSetOptionImpl(vm: ptr evmc_vm, name, value: cstring): evmc_set_option_result {.cdecl.} =
|
||||
return EVMC_SET_OPTION_INVALID_NAME
|
||||
|
||||
proc vmExecuteImpl(vm: ptr evmc_vm, host: ptr evmc_host_interface,
|
||||
ctx: Computation, rev: evmc_revision,
|
||||
msg: evmc_message, code: ptr byte, code_size: uint): evmc_result {.cdecl.} =
|
||||
discard
|
||||
|
||||
proc vmGetCapabilitiesImpl(vm: ptr evmc_vm): evmc_capabilities {.cdecl.} =
|
||||
result.incl(EVMC_CAPABILITY_EVM1)
|
||||
|
||||
proc vmDestroyImpl(vm: ptr evmc_vm) {.cdecl.} =
|
||||
dealloc(vm)
|
||||
|
||||
const
|
||||
EVMC_HOST_NAME = "nimbus_vm"
|
||||
EVMC_VM_VERSION = "0.0.1"
|
||||
|
||||
proc init(vm: var evmc_vm) =
|
||||
vm.abi_version = EVMC_ABI_VERSION
|
||||
vm.name = EVMC_HOST_NAME
|
||||
vm.version = EVMC_VM_VERSION
|
||||
vm.destroy = vmDestroyImpl
|
||||
vm.execute = cast[evmc_execute_fn](vmExecuteImpl)
|
||||
vm.get_capabilities = vmGetCapabilitiesImpl
|
||||
vm.set_option = vmSetOptionImpl
|
||||
|
||||
let gHost = initHostInterface()
|
||||
proc nim_host_get_interface(): ptr nimbus_host_interface {.exportc, cdecl.} =
|
||||
result = cast[ptr nimbus_host_interface](gHost.unsafeAddr)
|
||||
|
||||
proc nim_host_create_context(vmstate: BaseVmState, msg: ptr evmc_message): Computation {.exportc, cdecl.} =
|
||||
#result = HostContext(
|
||||
# vmState: vmstate,
|
||||
# gasPrice: GasInt(gasPrice),
|
||||
# origin: fromEvmc(origin)
|
||||
#)
|
||||
GC_ref(result)
|
||||
|
||||
proc nim_host_destroy_context(ctx: Computation) {.exportc, cdecl.} =
|
||||
GC_unref(ctx)
|
||||
|
||||
proc nim_create_nimbus_vm(): ptr evmc_vm {.exportc, cdecl.} =
|
||||
result = create(evmc_vm)
|
||||
init(result[])
|
@ -125,6 +125,87 @@ const
|
||||
ACCESS_LIST_STORAGE_KEY_COST* = 1900.GasInt
|
||||
ACCESS_LIST_ADDRESS_COST* = 2400.GasInt
|
||||
|
||||
|
||||
when defined(evmc_enabled):
|
||||
type
|
||||
# The gas cost specification for storage instructions.
|
||||
StorageCostSpec = object
|
||||
netCost : bool # Is this net gas cost metering schedule?
|
||||
warmAccess: int16 # Storage warm access cost, YP: G_{warmaccess}
|
||||
sset : int16 # Storage addition cost, YP: G_{sset}
|
||||
reset : int16 # Storage modification cost, YP: G_{sreset}
|
||||
clear : int16 # Storage deletion refund, YP: R_{sclear}
|
||||
|
||||
StorageStoreCost* = object
|
||||
gasCost* : int16
|
||||
gasRefund*: int16
|
||||
|
||||
# Table of gas cost specification for storage instructions per EVM revision.
|
||||
func storageCostSpec(): array[Fork, StorageCostSpec] {.compileTime.} =
|
||||
# Legacy cost schedule.
|
||||
const revs = [
|
||||
FkFrontier, FkHomestead, FkTangerine,
|
||||
FkSpurious, FkByzantium, FkPetersburg]
|
||||
|
||||
for rev in revs:
|
||||
result[rev] = StorageCostSpec(
|
||||
netCost: false, warmAccess: 200, sset: 20000, reset: 5000, clear: 15000)
|
||||
|
||||
# Net cost schedule.
|
||||
result[FkConstantinople] = StorageCostSpec(
|
||||
netCost: true, warmAccess: 200, sset: 20000, reset: 5000, clear: 15000)
|
||||
result[FkIstanbul] = StorageCostSpec(
|
||||
netCost: true, warmAccess: 800, sset: 20000, reset: 5000, clear: 15000)
|
||||
result[FkBerlin] = StorageCostSpec(
|
||||
netCost: true, warmAccess: WarmStorageReadCost, sset: 20000,
|
||||
reset: 5000 - ColdSloadCost, clear: 15000)
|
||||
result[FkLondon] = StorageCostSpec(
|
||||
netCost: true, warmAccess: WarmStorageReadCost, sset: 20000,
|
||||
reset: 5000 - ColdSloadCost, clear: 4800)
|
||||
|
||||
result[FkParis] = result[FkLondon]
|
||||
result[FkShanghai] = result[FkLondon]
|
||||
result[FkCancun] = result[FkLondon]
|
||||
|
||||
proc legacySStoreCost(e: var array[evmc_storage_status, StorageStoreCost],
|
||||
c: StorageCostSpec) {.compileTime.} =
|
||||
e[EVMC_STORAGE_ADDED] = StorageStoreCost(gasCost: c.sset , gasRefund: 0)
|
||||
e[EVMC_STORAGE_DELETED] = StorageStoreCost(gasCost: c.reset, gasRefund: c.clear)
|
||||
e[EVMC_STORAGE_MODIFIED] = StorageStoreCost(gasCost: c.reset, gasRefund: 0)
|
||||
e[EVMC_STORAGE_ASSIGNED] = e[EVMC_STORAGE_MODIFIED]
|
||||
e[EVMC_STORAGE_DELETED_ADDED] = e[EVMC_STORAGE_ADDED]
|
||||
e[EVMC_STORAGE_MODIFIED_DELETED] = e[EVMC_STORAGE_DELETED]
|
||||
e[EVMC_STORAGE_DELETED_RESTORED] = e[EVMC_STORAGE_ADDED]
|
||||
e[EVMC_STORAGE_ADDED_DELETED] = e[EVMC_STORAGE_DELETED]
|
||||
e[EVMC_STORAGE_MODIFIED_RESTORED] = e[EVMC_STORAGE_MODIFIED]
|
||||
|
||||
proc netSStoreCost(e: var array[evmc_storage_status, StorageStoreCost],
|
||||
c: StorageCostSpec) {.compileTime.} =
|
||||
e[EVMC_STORAGE_ASSIGNED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: 0)
|
||||
e[EVMC_STORAGE_ADDED] = StorageStoreCost(gasCost: c.sset , gasRefund: 0)
|
||||
e[EVMC_STORAGE_DELETED] = StorageStoreCost(gasCost: c.reset , gasRefund: c.clear)
|
||||
e[EVMC_STORAGE_MODIFIED] = StorageStoreCost(gasCost: c.reset , gasRefund: 0)
|
||||
e[EVMC_STORAGE_DELETED_ADDED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: -c.clear)
|
||||
e[EVMC_STORAGE_MODIFIED_DELETED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: c.clear)
|
||||
e[EVMC_STORAGE_DELETED_RESTORED] = StorageStoreCost(gasCost: c.warmAccess,
|
||||
gasRefund: c.reset - c.warmAccess - c.clear)
|
||||
e[EVMC_STORAGE_ADDED_DELETED] = StorageStoreCost(gasCost: c.warmAccess,
|
||||
gasRefund: c.sset - c.warmAccess)
|
||||
e[EVMC_STORAGE_MODIFIED_RESTORED] = StorageStoreCost(gasCost: c.warmAccess,
|
||||
gasRefund: c.reset - c.warm_access)
|
||||
|
||||
proc storageStoreCost(): array[Fork, array[evmc_storage_status, StorageStoreCost]] {.compileTime.} =
|
||||
const tbl = storageCostSpec()
|
||||
for rev in Fork:
|
||||
let c = tbl[rev]
|
||||
if not c.netCost: # legacy
|
||||
legacySStoreCost(result[rev], c)
|
||||
else: # net cost
|
||||
netSStoreCost(result[rev], c)
|
||||
|
||||
const
|
||||
SstoreCost* = storageStoreCost()
|
||||
|
||||
template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) =
|
||||
|
||||
## Generate the gas cost for each forks and store them in a const
|
||||
@ -224,52 +305,31 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) =
|
||||
|
||||
func `prefix gasSstore`(value: UInt256, gasParams: GasParams): GasResult {.nimcall.} =
|
||||
## Value is word to save
|
||||
|
||||
when fork >= FkBerlin:
|
||||
# EIP2929
|
||||
const
|
||||
SLOAD_GAS = WarmStorageReadCost
|
||||
SSTORE_RESET_GAS = 5000 - ColdSloadCost
|
||||
else:
|
||||
const
|
||||
SLOAD_GAS = FeeSchedule[GasSload]
|
||||
SSTORE_RESET_GAS = FeeSchedule[GasSreset]
|
||||
|
||||
const
|
||||
NoopGas = SLOAD_GAS # if the value doesn't change.
|
||||
DirtyGas = SLOAD_GAS # if a dirty value is changed.
|
||||
InitGas = FeeSchedule[GasSset] # from clean zero to non-zero
|
||||
InitRefund = FeeSchedule[GasSset] - SLOAD_GAS # resetting to the original zero value
|
||||
CleanGas = SSTORE_RESET_GAS # from clean non-zero to something else
|
||||
CleanRefund = SSTORE_RESET_GAS - SLOAD_GAS # resetting to the original non-zero value
|
||||
ClearRefund = FeeSchedule[RefundsClear]# clearing an originally existing storage slot
|
||||
|
||||
when defined(evmc_enabled):
|
||||
const
|
||||
sstoreDirty = when fork < FkConstantinople or fork == FkPetersburg: CleanGas
|
||||
else: DirtyGas
|
||||
|
||||
case gasParams.s_status
|
||||
of EVMC_STORAGE_ADDED: result.gasCost = InitGas
|
||||
of EVMC_STORAGE_MODIFIED: result.gasCost = CleanGas
|
||||
of EVMC_STORAGE_DELETED:
|
||||
result.gasCost = CleanGas
|
||||
result.gasRefund += ClearRefund
|
||||
of EVMC_STORAGE_UNCHANGED: result.gasCost = sstoreDirty
|
||||
of EVMC_STORAGE_MODIFIED_AGAIN:
|
||||
result.gasCost = sstoreDirty
|
||||
if not gasParams.s_originalValue.isZero:
|
||||
if gasParams.s_currentValue.isZero:
|
||||
result.gasRefund -= ClearRefund
|
||||
if value.isZero:
|
||||
result.gasRefund += ClearRefund
|
||||
|
||||
if gasParams.s_originalValue == value:
|
||||
if gasParams.s_originalValue.isZero:
|
||||
result.gasRefund += InitRefund
|
||||
else:
|
||||
result.gasRefund += CleanRefund
|
||||
const c = SStoreCost[fork]
|
||||
let sc = c[gasParams.s_status]
|
||||
result.gasCost = sc.gasCost
|
||||
result.gasRefund = sc.gasRefund
|
||||
else:
|
||||
when fork >= FkBerlin:
|
||||
# EIP2929
|
||||
const
|
||||
SLOAD_GAS = WarmStorageReadCost
|
||||
SSTORE_RESET_GAS = 5000 - ColdSloadCost
|
||||
else:
|
||||
const
|
||||
SLOAD_GAS = FeeSchedule[GasSload]
|
||||
SSTORE_RESET_GAS = FeeSchedule[GasSreset]
|
||||
|
||||
const
|
||||
NoopGas = SLOAD_GAS # if the value doesn't change.
|
||||
DirtyGas = SLOAD_GAS # if a dirty value is changed.
|
||||
InitGas = FeeSchedule[GasSset] # from clean zero to non-zero
|
||||
InitRefund = FeeSchedule[GasSset] - SLOAD_GAS # resetting to the original zero value
|
||||
CleanGas = SSTORE_RESET_GAS # from clean non-zero to something else
|
||||
CleanRefund = SSTORE_RESET_GAS - SLOAD_GAS # resetting to the original non-zero value
|
||||
ClearRefund = FeeSchedule[RefundsClear]# clearing an originally existing storage slot
|
||||
|
||||
when fork < FkConstantinople or fork == FkPetersburg:
|
||||
let isStorageEmpty = gasParams.s_currentValue.isZero
|
||||
|
||||
@ -760,7 +820,10 @@ const
|
||||
FkPetersburg: SpuriousGasFees,
|
||||
FkIstanbul: IstanbulGasFees,
|
||||
FkBerlin: BerlinGasFees,
|
||||
FkLondon: LondonGasFees
|
||||
FkLondon: LondonGasFees,
|
||||
FkParis: LondonGasFees,
|
||||
FkShanghai: LondonGasFees,
|
||||
FkCancun: LondonGasFees,
|
||||
]
|
||||
|
||||
gasCosts(FkFrontier, base, BaseGasCosts)
|
||||
|
@ -40,7 +40,7 @@ type
|
||||
LocalParams = tuple
|
||||
gas: UInt256
|
||||
value: UInt256
|
||||
destination: EthAddress
|
||||
codeAddress: EthAddress
|
||||
sender: EthAddress
|
||||
memInPos: int
|
||||
memInLen: int
|
||||
@ -72,14 +72,14 @@ proc updateStackAndParams(q: var LocalParams; c: Computation) =
|
||||
# and further `childGasLimit`
|
||||
if FkBerlin <= c.fork:
|
||||
when evmc_enabled:
|
||||
if c.host.accessAccount(q.destination) == EVMC_ACCESS_COLD:
|
||||
if c.host.accessAccount(q.codeAddress) == EVMC_ACCESS_COLD:
|
||||
c.gasMeter.consumeGas(
|
||||
ColdAccountAccessCost - WarmStorageReadCost,
|
||||
reason = "EIP2929 gasCall")
|
||||
else:
|
||||
c.vmState.mutateStateDB:
|
||||
if not db.inAccessList(q.destination):
|
||||
db.accessList(q.destination)
|
||||
if not db.inAccessList(q.codeAddress):
|
||||
db.accessList(q.codeAddress)
|
||||
|
||||
# The WarmStorageReadCostEIP2929 (100) is already deducted in
|
||||
# the form of a constant `gasCall`
|
||||
@ -91,7 +91,7 @@ proc updateStackAndParams(q: var LocalParams; c: Computation) =
|
||||
proc callParams(c: Computation): LocalParams =
|
||||
## Helper for callOp()
|
||||
result.gas = c.stack.popInt()
|
||||
result.destination = c.stack.popAddress()
|
||||
result.codeAddress = c.stack.popAddress()
|
||||
result.value = c.stack.popInt()
|
||||
result.memInPos = c.stack.popInt().cleanMemRef
|
||||
result.memInLen = c.stack.popInt().cleanMemRef
|
||||
@ -100,7 +100,7 @@ proc callParams(c: Computation): LocalParams =
|
||||
|
||||
result.sender = c.msg.contractAddress
|
||||
result.flags = c.msg.flags
|
||||
result.contractAddress = result.destination
|
||||
result.contractAddress = result.codeAddress
|
||||
|
||||
result.updateStackAndParams(c)
|
||||
|
||||
@ -114,7 +114,7 @@ proc callCodeParams(c: Computation): LocalParams =
|
||||
proc delegateCallParams(c: Computation): LocalParams =
|
||||
## Helper for delegateCall()
|
||||
result.gas = c.stack.popInt()
|
||||
result.destination = c.stack.popAddress()
|
||||
result.codeAddress = c.stack.popAddress()
|
||||
result.memInPos = c.stack.popInt().cleanMemRef
|
||||
result.memInLen = c.stack.popInt().cleanMemRef
|
||||
result.memOutPos = c.stack.popInt().cleanMemRef
|
||||
@ -131,7 +131,7 @@ proc delegateCallParams(c: Computation): LocalParams =
|
||||
proc staticCallParams(c: Computation): LocalParams =
|
||||
## Helper for staticCall()
|
||||
result.gas = c.stack.popInt()
|
||||
result.destination = c.stack.popAddress()
|
||||
result.codeAddress = c.stack.popAddress()
|
||||
result.memInPos = c.stack.popInt().cleanMemRef
|
||||
result.memInLen = c.stack.popInt().cleanMemRef
|
||||
result.memOutPos = c.stack.popInt().cleanMemRef
|
||||
@ -140,7 +140,7 @@ proc staticCallParams(c: Computation): LocalParams =
|
||||
result.value = 0.u256
|
||||
result.sender = c.msg.contractAddress
|
||||
result.flags = emvcStatic
|
||||
result.contractAddress = result.destination
|
||||
result.contractAddress = result.codeAddress
|
||||
|
||||
result.updateStackAndParams(c)
|
||||
|
||||
@ -246,15 +246,16 @@ const
|
||||
msg = new(nimbus_message)
|
||||
c = k.cpt
|
||||
msg[] = nimbus_message(
|
||||
kind : evmcCall.evmc_call_kind,
|
||||
depth : (k.cpt.msg.depth + 1).int32,
|
||||
gas : childGasLimit,
|
||||
sender : p.sender,
|
||||
destination: p.destination,
|
||||
input_data : k.cpt.memory.readPtr(p.memInPos),
|
||||
input_size : p.memInLen.uint,
|
||||
value : toEvmc(p.value),
|
||||
flags : p.flags.uint32
|
||||
kind : evmcCall.evmc_call_kind,
|
||||
depth : (k.cpt.msg.depth + 1).int32,
|
||||
gas : childGasLimit,
|
||||
sender : p.sender,
|
||||
recipient : p.contractAddress,
|
||||
code_address: p.codeAddress,
|
||||
input_data : k.cpt.memory.readPtr(p.memInPos),
|
||||
input_size : p.memInLen.uint,
|
||||
value : toEvmc(p.value),
|
||||
flags : p.flags.uint32
|
||||
)
|
||||
c.execSubCall(msg, p)
|
||||
else:
|
||||
@ -267,7 +268,7 @@ const
|
||||
gas: childGasLimit,
|
||||
sender: p.sender,
|
||||
contractAddress: p.contractAddress,
|
||||
codeAddress: p.destination,
|
||||
codeAddress: p.codeAddress,
|
||||
value: p.value,
|
||||
data: k.cpt.memory.read(p.memInPos, p.memInLen),
|
||||
flags: p.flags))
|
||||
@ -329,15 +330,16 @@ const
|
||||
msg = new(nimbus_message)
|
||||
c = k.cpt
|
||||
msg[] = nimbus_message(
|
||||
kind : evmcCallCode.evmc_call_kind,
|
||||
depth : (k.cpt.msg.depth + 1).int32,
|
||||
gas : childGasLimit,
|
||||
sender : p.sender,
|
||||
destination: p.destination,
|
||||
input_data : k.cpt.memory.readPtr(p.memInPos),
|
||||
input_size : p.memInLen.uint,
|
||||
value : toEvmc(p.value),
|
||||
flags : p.flags.uint32
|
||||
kind : evmcCallCode.evmc_call_kind,
|
||||
depth : (k.cpt.msg.depth + 1).int32,
|
||||
gas : childGasLimit,
|
||||
sender : p.sender,
|
||||
recipient : p.contractAddress,
|
||||
code_address: p.codeAddress,
|
||||
input_data : k.cpt.memory.readPtr(p.memInPos),
|
||||
input_size : p.memInLen.uint,
|
||||
value : toEvmc(p.value),
|
||||
flags : p.flags.uint32
|
||||
)
|
||||
c.execSubCall(msg, p)
|
||||
else:
|
||||
@ -350,7 +352,7 @@ const
|
||||
gas: childGasLimit,
|
||||
sender: p.sender,
|
||||
contractAddress: p.contractAddress,
|
||||
codeAddress: p.destination,
|
||||
codeAddress: p.codeAddress,
|
||||
value: p.value,
|
||||
data: k.cpt.memory.read(p.memInPos, p.memInLen),
|
||||
flags: p.flags))
|
||||
@ -401,15 +403,16 @@ const
|
||||
msg = new(nimbus_message)
|
||||
c = k.cpt
|
||||
msg[] = nimbus_message(
|
||||
kind : evmcDelegateCall.evmc_call_kind,
|
||||
depth : (k.cpt.msg.depth + 1).int32,
|
||||
gas : childGasLimit,
|
||||
sender : p.sender,
|
||||
destination: p.destination,
|
||||
input_data : k.cpt.memory.readPtr(p.memInPos),
|
||||
input_size : p.memInLen.uint,
|
||||
value : toEvmc(p.value),
|
||||
flags : p.flags.uint32
|
||||
kind : evmcDelegateCall.evmc_call_kind,
|
||||
depth : (k.cpt.msg.depth + 1).int32,
|
||||
gas : childGasLimit,
|
||||
sender : p.sender,
|
||||
recipient : p.contractAddress,
|
||||
code_address: p.codeAddress,
|
||||
input_data : k.cpt.memory.readPtr(p.memInPos),
|
||||
input_size : p.memInLen.uint,
|
||||
value : toEvmc(p.value),
|
||||
flags : p.flags.uint32
|
||||
)
|
||||
c.execSubCall(msg, p)
|
||||
else:
|
||||
@ -422,7 +425,7 @@ const
|
||||
gas: childGasLimit,
|
||||
sender: p.sender,
|
||||
contractAddress: p.contractAddress,
|
||||
codeAddress: p.destination,
|
||||
codeAddress: p.codeAddress,
|
||||
value: p.value,
|
||||
data: k.cpt.memory.read(p.memInPos, p.memInLen),
|
||||
flags: p.flags))
|
||||
@ -451,7 +454,7 @@ const
|
||||
# from 700 to 40
|
||||
#
|
||||
# when opCode == StaticCall:
|
||||
# if k.cpt.fork >= FkBerlin and destination.toInt <= MaxPrecompilesAddr:
|
||||
# if k.cpt.fork >= FkBerlin and codeAddress.toInt <= MaxPrecompilesAddr:
|
||||
# gasCost = gasCost - 660.GasInt
|
||||
if gasCost >= 0:
|
||||
k.cpt.gasMeter.consumeGas(gasCost, reason = $StaticCall)
|
||||
@ -478,15 +481,16 @@ const
|
||||
msg = new(nimbus_message)
|
||||
c = k.cpt
|
||||
msg[] = nimbus_message(
|
||||
kind : evmcCall.evmc_call_kind,
|
||||
depth : (k.cpt.msg.depth + 1).int32,
|
||||
gas : childGasLimit,
|
||||
sender : p.sender,
|
||||
destination: p.destination,
|
||||
input_data : k.cpt.memory.readPtr(p.memInPos),
|
||||
input_size : p.memInLen.uint,
|
||||
value : toEvmc(p.value),
|
||||
flags : p.flags.uint32
|
||||
kind : evmcCall.evmc_call_kind,
|
||||
depth : (k.cpt.msg.depth + 1).int32,
|
||||
gas : childGasLimit,
|
||||
sender : p.sender,
|
||||
recipient : p.contractAddress,
|
||||
code_address: p.codeAddress,
|
||||
input_data : k.cpt.memory.readPtr(p.memInPos),
|
||||
input_size : p.memInLen.uint,
|
||||
value : toEvmc(p.value),
|
||||
flags : p.flags.uint32
|
||||
)
|
||||
c.execSubCall(msg, p)
|
||||
else:
|
||||
@ -499,7 +503,7 @@ const
|
||||
gas: childGasLimit,
|
||||
sender: p.sender,
|
||||
contractAddress: p.contractAddress,
|
||||
codeAddress: p.destination,
|
||||
codeAddress: p.codeAddress,
|
||||
value: p.value,
|
||||
data: k.cpt.memory.read(p.memInPos, p.memInLen),
|
||||
flags: p.flags))
|
||||
|
@ -256,6 +256,3 @@ else:
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
when defined(evmc_enabled):
|
||||
include evmc_host
|
||||
|
@ -48,4 +48,8 @@ export
|
||||
vmg.ACCESS_LIST_STORAGE_KEY_COST,
|
||||
vmg.ACCESS_LIST_ADDRESS_COST
|
||||
|
||||
when defined(evmc_enabled):
|
||||
export
|
||||
vmg.SstoreCost
|
||||
|
||||
# End
|
||||
|
Loading…
x
Reference in New Issue
Block a user