EIP-4788: Make it clear what is an EVM system call
This commit is contained in:
parent
2d2def9a8d
commit
cc7a7db74b
|
@ -140,32 +140,26 @@ proc processBeaconBlockRoot*(vmState: BaseVMState, beaconRoot: Hash256):
|
||||||
let
|
let
|
||||||
statedb = vmState.stateDB
|
statedb = vmState.stateDB
|
||||||
call = CallParams(
|
call = CallParams(
|
||||||
vmState: vmState,
|
vmState : vmState,
|
||||||
sender: SystemAddress,
|
sender : SystemAddress,
|
||||||
gasLimit: 30_000_000.GasInt,
|
gasLimit : 30_000_000.GasInt,
|
||||||
gasPrice: 0.GasInt,
|
gasPrice : 0.GasInt,
|
||||||
to: BeaconRootsStorageAddress,
|
to : BeaconRootsStorageAddress,
|
||||||
input: @(beaconRoot.data),
|
input : @(beaconRoot.data),
|
||||||
|
|
||||||
|
# It's a systemCall, no need for other knicks knacks
|
||||||
|
sysCall : true,
|
||||||
|
noAccessList: true,
|
||||||
|
noIntrinsic : true,
|
||||||
|
noGasCharge : true,
|
||||||
|
noRefund : true,
|
||||||
)
|
)
|
||||||
|
|
||||||
# runComputation a.k.a syscall/evm.call
|
# runComputation a.k.a syscall/evm.call
|
||||||
if call.runComputation().isError:
|
if call.runComputation().isError:
|
||||||
return err("processBeaconBlockRoot: syscall error")
|
return err("processBeaconBlockRoot: syscall error")
|
||||||
|
|
||||||
# We can choose to set SystemAddress nonce to 0
|
statedb.persist(clearEmptyAccount = true, clearCache = false)
|
||||||
# like erigon or geth(their EVM have explicit nonce set)
|
|
||||||
# or we delete the account manually instead of let it deleted
|
|
||||||
# by AccountsCache.persist.
|
|
||||||
statedb.deleteAccount(SystemAddress)
|
|
||||||
|
|
||||||
when false:
|
|
||||||
# nimbus EVM automatically increase sender nonce by one
|
|
||||||
# for each call/create.
|
|
||||||
statedb.setNonce(SystemAddress, 0)
|
|
||||||
# statedb.persist probably not needed as each processTransaction
|
|
||||||
# will call it.
|
|
||||||
statedb.persist(clearEmptyAccount = true, clearCache = false)
|
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc asyncProcessTransaction*(
|
proc asyncProcessTransaction*(
|
||||||
|
|
|
@ -448,7 +448,7 @@ proc setBalance*(ac: AccountsCache, address: EthAddress, balance: UInt256) =
|
||||||
proc addBalance*(ac: AccountsCache, address: EthAddress, delta: UInt256) {.inline.} =
|
proc addBalance*(ac: AccountsCache, address: EthAddress, delta: UInt256) {.inline.} =
|
||||||
# EIP161: We must check emptiness for the objects such that the account
|
# EIP161: We must check emptiness for the objects such that the account
|
||||||
# clearing (0,0,0 objects) can take effect.
|
# clearing (0,0,0 objects) can take effect.
|
||||||
if delta == 0.u256:
|
if delta.isZero:
|
||||||
let acc = ac.getAccount(address)
|
let acc = ac.getAccount(address)
|
||||||
if acc.isEmpty:
|
if acc.isEmpty:
|
||||||
ac.makeDirty(address).flags.incl Touched
|
ac.makeDirty(address).flags.incl Touched
|
||||||
|
@ -456,6 +456,12 @@ proc addBalance*(ac: AccountsCache, address: EthAddress, delta: UInt256) {.inlin
|
||||||
ac.setBalance(address, ac.getBalance(address) + delta)
|
ac.setBalance(address, ac.getBalance(address) + delta)
|
||||||
|
|
||||||
proc subBalance*(ac: AccountsCache, address: EthAddress, delta: UInt256) {.inline.} =
|
proc subBalance*(ac: AccountsCache, address: EthAddress, delta: UInt256) {.inline.} =
|
||||||
|
if delta.isZero:
|
||||||
|
# This zero delta early exit is important as shown in EIP-4788.
|
||||||
|
# If the account is created, it will change the state.
|
||||||
|
# But early exit will prevent the account creation.
|
||||||
|
# In this case, the SystemAddress
|
||||||
|
return
|
||||||
ac.setBalance(address, ac.getBalance(address) - delta)
|
ac.setBalance(address, ac.getBalance(address) - delta)
|
||||||
|
|
||||||
proc setNonce*(ac: AccountsCache, address: EthAddress, nonce: AccountNonce) =
|
proc setNonce*(ac: AccountsCache, address: EthAddress, nonce: AccountNonce) =
|
||||||
|
|
|
@ -212,7 +212,7 @@ template getTransientStorage*(c: Computation, slot: UInt256): UInt256 =
|
||||||
c.vmState.readOnlyStateDB.
|
c.vmState.readOnlyStateDB.
|
||||||
getTransientStorage(c.msg.contractAddress, slot)
|
getTransientStorage(c.msg.contractAddress, slot)
|
||||||
|
|
||||||
proc newComputation*(vmState: BaseVMState, message: Message,
|
proc newComputation*(vmState: BaseVMState, sysCall: bool, message: Message,
|
||||||
salt: ContractSalt = ZERO_CONTRACTSALT): Computation =
|
salt: ContractSalt = ZERO_CONTRACTSALT): Computation =
|
||||||
new result
|
new result
|
||||||
result.vmState = vmState
|
result.vmState = vmState
|
||||||
|
@ -221,6 +221,7 @@ proc newComputation*(vmState: BaseVMState, message: Message,
|
||||||
result.stack = newStack()
|
result.stack = newStack()
|
||||||
result.returnStack = @[]
|
result.returnStack = @[]
|
||||||
result.gasMeter.init(message.gas)
|
result.gasMeter.init(message.gas)
|
||||||
|
result.sysCall = sysCall
|
||||||
|
|
||||||
if result.msg.isCreate():
|
if result.msg.isCreate():
|
||||||
result.msg.contractAddress = result.generateContractAddress(salt)
|
result.msg.contractAddress = result.generateContractAddress(salt)
|
||||||
|
@ -230,7 +231,8 @@ proc newComputation*(vmState: BaseVMState, message: Message,
|
||||||
result.code = newCodeStream(
|
result.code = newCodeStream(
|
||||||
vmState.readOnlyStateDB.getCode(message.codeAddress))
|
vmState.readOnlyStateDB.getCode(message.codeAddress))
|
||||||
|
|
||||||
proc newComputation*(vmState: BaseVMState, message: Message, code: seq[byte]): Computation =
|
proc newComputation*(vmState: BaseVMState, sysCall: bool,
|
||||||
|
message: Message, code: seq[byte]): Computation =
|
||||||
new result
|
new result
|
||||||
result.vmState = vmState
|
result.vmState = vmState
|
||||||
result.msg = message
|
result.msg = message
|
||||||
|
@ -239,6 +241,7 @@ proc newComputation*(vmState: BaseVMState, message: Message, code: seq[byte]): C
|
||||||
result.returnStack = @[]
|
result.returnStack = @[]
|
||||||
result.gasMeter.init(message.gas)
|
result.gasMeter.init(message.gas)
|
||||||
result.code = newCodeStream(code)
|
result.code = newCodeStream(code)
|
||||||
|
result.sysCall = sysCall
|
||||||
|
|
||||||
template gasCosts*(c: Computation): untyped =
|
template gasCosts*(c: Computation): untyped =
|
||||||
c.vmState.gasCosts
|
c.vmState.gasCosts
|
||||||
|
|
|
@ -172,7 +172,7 @@ else:
|
||||||
# need to provide explicit <c> and <child> for capturing in chainTo proc()
|
# need to provide explicit <c> and <child> for capturing in chainTo proc()
|
||||||
# <memPos> and <memLen> are provided by value and need not be captured
|
# <memPos> and <memLen> are provided by value and need not be captured
|
||||||
var
|
var
|
||||||
child = newComputation(c.vmState, childMsg)
|
child = newComputation(c.vmState, false, childMsg)
|
||||||
|
|
||||||
c.chainTo(child):
|
c.chainTo(child):
|
||||||
if not child.shouldBurnGas:
|
if not child.shouldBurnGas:
|
||||||
|
|
|
@ -63,7 +63,7 @@ else:
|
||||||
|
|
||||||
# need to provide explicit <c> and <child> for capturing in chainTo proc()
|
# need to provide explicit <c> and <child> for capturing in chainTo proc()
|
||||||
var
|
var
|
||||||
child = newComputation(c.vmState, childMsg, salt)
|
child = newComputation(c.vmState, false, childMsg, salt)
|
||||||
|
|
||||||
c.chainTo(child):
|
c.chainTo(child):
|
||||||
if not child.shouldBurnGas:
|
if not child.shouldBurnGas:
|
||||||
|
|
|
@ -63,6 +63,9 @@ proc execComputation*(c: Computation)
|
||||||
c.execCallOrCreate()
|
c.execCallOrCreate()
|
||||||
c.postExecComputation()
|
c.postExecComputation()
|
||||||
|
|
||||||
|
template execSysCall*(c: Computation) =
|
||||||
|
c.execCallOrCreate()
|
||||||
|
|
||||||
# FIXME-duplicatedForAsync
|
# FIXME-duplicatedForAsync
|
||||||
proc asyncExecComputation*(c: Computation): Future[void] {.async.} =
|
proc asyncExecComputation*(c: Computation): Future[void] {.async.} =
|
||||||
c.preExecComputation()
|
c.preExecComputation()
|
||||||
|
|
|
@ -87,6 +87,7 @@ type
|
||||||
parent*, child*: Computation
|
parent*, child*: Computation
|
||||||
pendingAsyncOperation*: Future[void]
|
pendingAsyncOperation*: Future[void]
|
||||||
continuation*: proc() {.gcsafe, raises: [CatchableError].}
|
continuation*: proc() {.gcsafe, raises: [CatchableError].}
|
||||||
|
sysCall*: bool
|
||||||
|
|
||||||
Error* = ref object
|
Error* = ref object
|
||||||
statusCode*: evmc_status_code
|
statusCode*: evmc_status_code
|
||||||
|
|
|
@ -42,6 +42,7 @@ type
|
||||||
noAccessList*: bool # Don't initialise EIP-2929 access list.
|
noAccessList*: bool # Don't initialise EIP-2929 access list.
|
||||||
noGasCharge*: bool # Don't charge sender account for gas.
|
noGasCharge*: bool # Don't charge sender account for gas.
|
||||||
noRefund*: bool # Don't apply gas refund/burn rule.
|
noRefund*: bool # Don't apply gas refund/burn rule.
|
||||||
|
sysCall*: bool # System call or ordinary call
|
||||||
|
|
||||||
# Standard call result. (Some fields are beyond what EVMC can return,
|
# Standard call result. (Some fields are beyond what EVMC can return,
|
||||||
# and must only be used from tests because they will not always be set).
|
# and must only be used from tests because they will not always be set).
|
||||||
|
@ -176,7 +177,7 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||||
host.msg.input_data = host.input[0].addr
|
host.msg.input_data = host.input[0].addr
|
||||||
|
|
||||||
let cMsg = hostToComputationMessage(host.msg)
|
let cMsg = hostToComputationMessage(host.msg)
|
||||||
host.computation = newComputation(vmState, cMsg, code)
|
host.computation = newComputation(vmState, call.sysCall, cMsg, code)
|
||||||
|
|
||||||
shallowCopy(host.code, code)
|
shallowCopy(host.code, code)
|
||||||
|
|
||||||
|
@ -189,7 +190,7 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||||
host.msg.input_data = host.input[0].addr
|
host.msg.input_data = host.input[0].addr
|
||||||
|
|
||||||
let cMsg = hostToComputationMessage(host.msg)
|
let cMsg = hostToComputationMessage(host.msg)
|
||||||
host.computation = newComputation(vmState, cMsg)
|
host.computation = newComputation(vmState, call.sysCall, cMsg)
|
||||||
|
|
||||||
vmState.captureStart(host.computation, call.sender, call.to,
|
vmState.captureStart(host.computation, call.sender, call.to,
|
||||||
call.isCreate, call.input,
|
call.isCreate, call.input,
|
||||||
|
@ -297,7 +298,10 @@ proc runComputation*(call: CallParams): CallResult
|
||||||
when defined(evmc_enabled):
|
when defined(evmc_enabled):
|
||||||
doExecEvmc(host, call)
|
doExecEvmc(host, call)
|
||||||
else:
|
else:
|
||||||
execComputation(host.computation)
|
if host.computation.sysCall:
|
||||||
|
execSysCall(host.computation)
|
||||||
|
else:
|
||||||
|
execComputation(host.computation)
|
||||||
|
|
||||||
finishRunningComputation(host, call)
|
finishRunningComputation(host, call)
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,10 @@ proc evmcExecute(vm: ptr evmc_vm, hostInterface: ptr evmc_host_interface,
|
||||||
# host.computation = c
|
# host.computation = c
|
||||||
|
|
||||||
c.host.init(cast[ptr nimbus_host_interface](hostInterface), hostContext)
|
c.host.init(cast[ptr nimbus_host_interface](hostInterface), hostContext)
|
||||||
execComputation(c)
|
if c.sysCall:
|
||||||
|
execSysCall(c)
|
||||||
|
else:
|
||||||
|
execComputation(c)
|
||||||
|
|
||||||
# When output size is zero, output data pointer may be null.
|
# When output size is zero, output data pointer may be null.
|
||||||
var output_data: ptr byte
|
var output_data: ptr byte
|
||||||
|
|
|
@ -30,7 +30,7 @@ proc beforeExecCreateEvmcNested(host: TransactionHost,
|
||||||
value: m.value.fromEvmc,
|
value: m.value.fromEvmc,
|
||||||
data: @(makeOpenArray(m.inputData, m.inputSize.int))
|
data: @(makeOpenArray(m.inputData, m.inputSize.int))
|
||||||
)
|
)
|
||||||
return newComputation(host.vmState, childMsg,
|
return newComputation(host.vmState, false, childMsg,
|
||||||
cast[ContractSalt](m.create2_salt))
|
cast[ContractSalt](m.create2_salt))
|
||||||
|
|
||||||
proc afterExecCreateEvmcNested(host: TransactionHost, child: Computation,
|
proc afterExecCreateEvmcNested(host: TransactionHost, child: Computation,
|
||||||
|
@ -67,7 +67,7 @@ proc beforeExecCallEvmcNested(host: TransactionHost,
|
||||||
data: @(makeOpenArray(m.inputData, m.inputSize.int)),
|
data: @(makeOpenArray(m.inputData, m.inputSize.int)),
|
||||||
flags: m.flags,
|
flags: m.flags,
|
||||||
)
|
)
|
||||||
return newComputation(host.vmState, childMsg)
|
return newComputation(host.vmState, false, childMsg)
|
||||||
|
|
||||||
proc afterExecCallEvmcNested(host: TransactionHost, child: Computation,
|
proc afterExecCallEvmcNested(host: TransactionHost, child: Computation,
|
||||||
res: var EvmcResult) {.inline.} =
|
res: var EvmcResult) {.inline.} =
|
||||||
|
|
|
@ -13,6 +13,7 @@ import
|
||||||
|
|
||||||
export
|
export
|
||||||
vmx.asyncExecComputation,
|
vmx.asyncExecComputation,
|
||||||
vmx.execComputation
|
vmx.execComputation,
|
||||||
|
vmx.execSysCall
|
||||||
|
|
||||||
# End
|
# End
|
||||||
|
|
Loading…
Reference in New Issue