Transaction: Move contract address generation outside the EVM
The current EVM generates its own new contract addresses, and this is why there are separate `msg.contractAddress` and `msg.codeAddress` fields in the computation start message. In EVMC, account updates are only allowed on the host side, including contract generation, and the start message has one destination field, `msg.destination`. The EVM cannot select addresses, only use them. It's a sensible design. The difference makes the current EVM incompatible with EVMC and its message format, so this patch corrects the difference. It moves contract address generation to the host side. This simplifies the EVM and its API a little. (As an API change, this is incompatible with vm2, so it's guarded under `evmc_enabled` to allow vm2 to continue to build and run at this time. This is also why there are fewer deletions than would otherwise be expected.) Signed-off-by: Jamie Lokier <jamie@shareable.org>
This commit is contained in:
parent
775231eef1
commit
b3a788c7ce
|
@ -9,7 +9,7 @@
|
||||||
import
|
import
|
||||||
eth/common/eth_types, stint, options, stew/ranges/ptr_arith,
|
eth/common/eth_types, stint, options, stew/ranges/ptr_arith,
|
||||||
".."/[vm_types, vm_types2, vm_state, vm_computation, vm_state_transactions],
|
".."/[vm_types, vm_types2, vm_state, vm_computation, vm_state_transactions],
|
||||||
".."/[db/accounts_cache, vm_precompiles, vm_gas_costs],
|
".."/[db/accounts_cache, utils, vm_precompiles, vm_gas_costs],
|
||||||
".."/vm_internals,
|
".."/vm_internals,
|
||||||
./host_types
|
./host_types
|
||||||
|
|
||||||
|
@ -136,6 +136,34 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||||
# All other defaults in `TransactionHost` are fine.
|
# All other defaults in `TransactionHost` are fine.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Generate new contract address, prepare code, and update message `destination`
|
||||||
|
# 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):
|
||||||
|
var code: seq[byte]
|
||||||
|
if call.isCreate:
|
||||||
|
let sender = call.sender
|
||||||
|
let contractAddress =
|
||||||
|
generateAddress(sender, call.vmState.readOnlyStateDB.getNonce(sender))
|
||||||
|
host.msg.destination = 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)
|
||||||
|
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
|
||||||
|
# remains valid after the end of `call` lifetime.
|
||||||
|
host.input = call.input
|
||||||
|
host.msg.input_data = host.input[0].addr
|
||||||
|
|
||||||
|
let cMsg = hostToComputationMessage(host.msg)
|
||||||
|
host.computation = newComputation(vmState, cMsg, code)
|
||||||
|
|
||||||
|
else:
|
||||||
if call.input.len > 0:
|
if call.input.len > 0:
|
||||||
host.msg.input_size = call.input.len.csize_t
|
host.msg.input_size = call.input.len.csize_t
|
||||||
# Must copy the data so the `host.msg.input_data` pointer
|
# Must copy the data so the `host.msg.input_data` pointer
|
||||||
|
@ -145,6 +173,7 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||||
|
|
||||||
let cMsg = hostToComputationMessage(host.msg)
|
let cMsg = hostToComputationMessage(host.msg)
|
||||||
host.computation = newComputation(vmState, cMsg)
|
host.computation = newComputation(vmState, cMsg)
|
||||||
|
|
||||||
return host
|
return host
|
||||||
|
|
||||||
proc runComputation*(call: CallParams): CallResult =
|
proc runComputation*(call: CallParams): CallResult =
|
||||||
|
|
|
@ -163,6 +163,24 @@ proc newComputation*(vmState: BaseVMState, message: Message, salt= 0.u256): Comp
|
||||||
cast[evmc_host_context](result)
|
cast[evmc_host_context](result)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
proc newComputation*(vmState: BaseVMState, message: Message, code: seq[byte]): Computation =
|
||||||
|
new result
|
||||||
|
result.vmState = vmState
|
||||||
|
result.msg = message
|
||||||
|
result.memory = Memory()
|
||||||
|
result.stack = newStack()
|
||||||
|
result.returnStack = @[]
|
||||||
|
result.gasMeter.init(message.gas)
|
||||||
|
result.touchedAccounts = initHashSet[EthAddress]()
|
||||||
|
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 =
|
template gasCosts*(c: Computation): untyped =
|
||||||
c.vmState.gasCosts
|
c.vmState.gasCosts
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue