2021-04-08 15:52:10 +01:00
|
|
|
# Nimbus
|
2024-02-24 09:38:50 +07:00
|
|
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
2021-04-08 15:52:10 +01:00
|
|
|
# Licensed under either of
|
2021-04-22 19:12:16 +01:00
|
|
|
# * 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.
|
2021-04-08 15:52:10 +01:00
|
|
|
|
|
|
|
import
|
2024-11-25 17:28:03 +07:00
|
|
|
../core/eip7702,
|
2021-04-26 13:03:20 +01:00
|
|
|
../constants,
|
2023-12-12 19:12:56 +00:00
|
|
|
../db/ledger,
|
2021-04-26 13:03:20 +01:00
|
|
|
./computation,
|
2021-04-26 17:00:46 +01:00
|
|
|
./interpreter_dispatch,
|
2021-04-26 15:08:17 +01:00
|
|
|
./message,
|
2021-04-26 13:03:20 +01:00
|
|
|
./state,
|
2024-11-25 17:28:03 +07:00
|
|
|
./types,
|
|
|
|
./interpreter/gas_meter
|
2021-04-22 19:12:16 +01:00
|
|
|
|
2023-02-14 15:37:21 +01:00
|
|
|
{.push raises: [].}
|
|
|
|
|
2024-06-27 19:21:01 +00:00
|
|
|
# Using `proc` as `incNonce()` might be `proc` in logging mode
|
Added basic async capabilities for vm2. (#1260)
* Added basic async capabilities for vm2.
This is a whole new Git branch, not the same one as last time
(https://github.com/status-im/nimbus-eth1/pull/1250) - there wasn't
much worth salvaging. Main differences:
I didn't do the "each opcode has to specify an async handler" junk
that I put in last time. Instead, in oph_memory.nim you can see
sloadOp calling asyncChainTo and passing in an async operation.
That async operation is then run by the execCallOrCreate (or
asyncExecCallOrCreate) code in interpreter_dispatch.nim.
In the test code, the (previously existing) macro called "assembler"
now allows you to add a section called "initialStorage", specifying
fake data to be used by the EVM computation run by that test. (In
the long run we'll obviously want to write tests that for-real use
the JSON-RPC API to asynchronously fetch data; for now, this was
just an expedient way to write a basic unit test that exercises the
async-EVM code pathway.)
There's also a new macro called "concurrentAssemblers" that allows
you to write a test that runs multiple assemblers concurrently (and
then waits for them all to finish). There's one example test using
this, in test_op_memory_lazy.nim, though you can't actually see it
doing so unless you uncomment some echo statements in
async_operations.nim (in which case you can see the two concurrently
running EVM computations each printing out what they're doing, and
you'll see that they interleave).
A question: is it possible to make EVMC work asynchronously? (For
now, this code compiles and "make test" passes even if ENABLE_EVMC
is turned on, but it doesn't actually work asynchronously, it just
falls back on doing the usual synchronous EVMC thing. See
FIXME-asyncAndEvmc.)
* Moved the AsyncOperationFactory to the BaseVMState object.
* Made the AsyncOperationFactory into a table of fn pointers.
Also ditched the plain-data Vm2AsyncOperation type; it wasn't
really serving much purpose. Instead, the pendingAsyncOperation
field directly contains the Future.
* Removed the hasStorage idea.
It's not the right solution to the "how do we know whether we
still need to fetch the storage value or not?" problem. I
haven't implemented the right solution yet, but at least
we're better off not putting in a wrong one.
* Added/modified/removed some comments.
(Based on feedback on the PR.)
* Removed the waitFor from execCallOrCreate.
There was some back-and-forth in the PR regarding whether nested
waitFor calls are acceptable:
https://github.com/status-im/nimbus-eth1/pull/1260#discussion_r998587449
The eventual decision was to just change the waitFor to a doAssert
(since we probably won't want this extra functionality when running
synchronously anyway) to make sure that the Future is already
finished.
2022-11-01 11:35:46 -04:00
|
|
|
proc preExecComputation(c: Computation) =
|
2021-04-08 15:52:10 +01:00
|
|
|
if not c.msg.isCreate:
|
|
|
|
c.vmState.mutateStateDB:
|
|
|
|
db.incNonce(c.msg.sender)
|
|
|
|
|
2024-11-25 17:28:03 +07:00
|
|
|
# EIP-7702
|
|
|
|
for auth in c.authorizationList:
|
|
|
|
# 1. Verify the chain id is either 0 or the chain's current ID.
|
|
|
|
if not(auth.chainId == 0.ChainId or auth.chainId == c.vmState.com.chainId):
|
|
|
|
continue
|
|
|
|
|
|
|
|
# 2. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s]
|
|
|
|
let authority = authority(auth).valueOr:
|
|
|
|
continue
|
|
|
|
|
|
|
|
# 3. Add authority to accessed_addresses (as defined in EIP-2929.)
|
|
|
|
let ledger = c.vmState.stateDB
|
|
|
|
ledger.accessList(authority)
|
|
|
|
|
|
|
|
# 4. Verify the code of authority is either empty or already delegated.
|
|
|
|
let code = ledger.getCode(authority)
|
|
|
|
if code.len > 0:
|
|
|
|
if not parseDelegation(code):
|
|
|
|
continue
|
|
|
|
|
|
|
|
# 5. Verify the nonce of authority is equal to nonce.
|
|
|
|
if ledger.getNonce(authority) != auth.nonce:
|
|
|
|
continue
|
|
|
|
|
|
|
|
# 6. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie.
|
|
|
|
if ledger.accountExists(authority):
|
|
|
|
c.gasMeter.refundGas(PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST)
|
|
|
|
|
|
|
|
# 7. Set the code of authority to be 0xef0100 || address. This is a delegation designation.
|
|
|
|
ledger.setCode(authority, @(addressToDelegation(authority)))
|
|
|
|
|
|
|
|
# 8. Increase the nonce of authority by one.
|
|
|
|
ledger.setNonce(authority, auth.nonce + 1)
|
|
|
|
|
2024-06-27 19:21:01 +00:00
|
|
|
proc postExecComputation(c: Computation) =
|
2021-04-08 15:52:10 +01:00
|
|
|
if c.isSuccess:
|
2021-06-28 20:03:50 +07:00
|
|
|
if c.fork < FkLondon:
|
|
|
|
# EIP-3529: Reduction in refunds
|
|
|
|
c.refundSelfDestruct()
|
2022-04-08 11:54:11 +07:00
|
|
|
c.vmState.status = c.isSuccess
|
Added basic async capabilities for vm2. (#1260)
* Added basic async capabilities for vm2.
This is a whole new Git branch, not the same one as last time
(https://github.com/status-im/nimbus-eth1/pull/1250) - there wasn't
much worth salvaging. Main differences:
I didn't do the "each opcode has to specify an async handler" junk
that I put in last time. Instead, in oph_memory.nim you can see
sloadOp calling asyncChainTo and passing in an async operation.
That async operation is then run by the execCallOrCreate (or
asyncExecCallOrCreate) code in interpreter_dispatch.nim.
In the test code, the (previously existing) macro called "assembler"
now allows you to add a section called "initialStorage", specifying
fake data to be used by the EVM computation run by that test. (In
the long run we'll obviously want to write tests that for-real use
the JSON-RPC API to asynchronously fetch data; for now, this was
just an expedient way to write a basic unit test that exercises the
async-EVM code pathway.)
There's also a new macro called "concurrentAssemblers" that allows
you to write a test that runs multiple assemblers concurrently (and
then waits for them all to finish). There's one example test using
this, in test_op_memory_lazy.nim, though you can't actually see it
doing so unless you uncomment some echo statements in
async_operations.nim (in which case you can see the two concurrently
running EVM computations each printing out what they're doing, and
you'll see that they interleave).
A question: is it possible to make EVMC work asynchronously? (For
now, this code compiles and "make test" passes even if ENABLE_EVMC
is turned on, but it doesn't actually work asynchronously, it just
falls back on doing the usual synchronous EVMC thing. See
FIXME-asyncAndEvmc.)
* Moved the AsyncOperationFactory to the BaseVMState object.
* Made the AsyncOperationFactory into a table of fn pointers.
Also ditched the plain-data Vm2AsyncOperation type; it wasn't
really serving much purpose. Instead, the pendingAsyncOperation
field directly contains the Future.
* Removed the hasStorage idea.
It's not the right solution to the "how do we know whether we
still need to fetch the storage value or not?" problem. I
haven't implemented the right solution yet, but at least
we're better off not putting in a wrong one.
* Added/modified/removed some comments.
(Based on feedback on the PR.)
* Removed the waitFor from execCallOrCreate.
There was some back-and-forth in the PR regarding whether nested
waitFor calls are acceptable:
https://github.com/status-im/nimbus-eth1/pull/1260#discussion_r998587449
The eventual decision was to just change the waitFor to a doAssert
(since we probably won't want this extra functionality when running
synchronously anyway) to make sure that the Future is already
finished.
2022-11-01 11:35:46 -04:00
|
|
|
|
2024-06-07 15:24:32 +07:00
|
|
|
proc execComputation*(c: Computation) =
|
Added basic async capabilities for vm2. (#1260)
* Added basic async capabilities for vm2.
This is a whole new Git branch, not the same one as last time
(https://github.com/status-im/nimbus-eth1/pull/1250) - there wasn't
much worth salvaging. Main differences:
I didn't do the "each opcode has to specify an async handler" junk
that I put in last time. Instead, in oph_memory.nim you can see
sloadOp calling asyncChainTo and passing in an async operation.
That async operation is then run by the execCallOrCreate (or
asyncExecCallOrCreate) code in interpreter_dispatch.nim.
In the test code, the (previously existing) macro called "assembler"
now allows you to add a section called "initialStorage", specifying
fake data to be used by the EVM computation run by that test. (In
the long run we'll obviously want to write tests that for-real use
the JSON-RPC API to asynchronously fetch data; for now, this was
just an expedient way to write a basic unit test that exercises the
async-EVM code pathway.)
There's also a new macro called "concurrentAssemblers" that allows
you to write a test that runs multiple assemblers concurrently (and
then waits for them all to finish). There's one example test using
this, in test_op_memory_lazy.nim, though you can't actually see it
doing so unless you uncomment some echo statements in
async_operations.nim (in which case you can see the two concurrently
running EVM computations each printing out what they're doing, and
you'll see that they interleave).
A question: is it possible to make EVMC work asynchronously? (For
now, this code compiles and "make test" passes even if ENABLE_EVMC
is turned on, but it doesn't actually work asynchronously, it just
falls back on doing the usual synchronous EVMC thing. See
FIXME-asyncAndEvmc.)
* Moved the AsyncOperationFactory to the BaseVMState object.
* Made the AsyncOperationFactory into a table of fn pointers.
Also ditched the plain-data Vm2AsyncOperation type; it wasn't
really serving much purpose. Instead, the pendingAsyncOperation
field directly contains the Future.
* Removed the hasStorage idea.
It's not the right solution to the "how do we know whether we
still need to fetch the storage value or not?" problem. I
haven't implemented the right solution yet, but at least
we're better off not putting in a wrong one.
* Added/modified/removed some comments.
(Based on feedback on the PR.)
* Removed the waitFor from execCallOrCreate.
There was some back-and-forth in the PR regarding whether nested
waitFor calls are acceptable:
https://github.com/status-im/nimbus-eth1/pull/1260#discussion_r998587449
The eventual decision was to just change the waitFor to a doAssert
(since we probably won't want this extra functionality when running
synchronously anyway) to make sure that the Future is already
finished.
2022-11-01 11:35:46 -04:00
|
|
|
c.preExecComputation()
|
|
|
|
c.execCallOrCreate()
|
|
|
|
c.postExecComputation()
|
|
|
|
|
2023-09-20 20:10:16 +07:00
|
|
|
template execSysCall*(c: Computation) =
|
2024-02-24 09:38:50 +07:00
|
|
|
# A syscall to EVM doesn't require
|
|
|
|
# a pre or post ceremony
|
2023-09-20 20:10:16 +07:00
|
|
|
c.execCallOrCreate()
|