diff --git a/nimbus/config.nim b/nimbus/config.nim index 6f18601b01..fcbaaa00fc 100644 --- a/nimbus/config.nim +++ b/nimbus/config.nim @@ -134,7 +134,6 @@ type Default Full ## Beware, experimental #Snap ## Beware, experimental - Stateless ## Beware, experimental NimbusConf* = object of RootObj ## Main Nimbus configuration object @@ -171,7 +170,7 @@ type "- default -- legacy sync mode\n" & "- full -- full blockchain archive\n" & # "- snap -- experimental snap mode (development only)\n" & - "- stateless -- experimental stateless mode (development only)" + "" defaultValue: SyncMode.Default defaultValueDesc: $SyncMode.Default abbr: "y" @@ -484,11 +483,6 @@ type defaultValueDesc: $defaultAdminListenAddressDesc name: "metrics-address" }: IpAddress - statelessModeDataSourceUrl* {. - desc: "URL of the node to use as a data source for on-demand data fetching via the JSON-RPC API" - defaultValue: "" - name: "stateless-data-source-url" .}: string - trustedSetupFile* {. desc: "Load EIP-4844 trusted setup file" defaultValue: none(string) diff --git a/nimbus/core/chain/persist_blocks.nim b/nimbus/core/chain/persist_blocks.nim index 4715e0aa11..e7b1ef74e6 100644 --- a/nimbus/core/chain/persist_blocks.nim +++ b/nimbus/core/chain/persist_blocks.nim @@ -38,7 +38,9 @@ type const CleanUpEpoch = 30_000.u256 - ## Regular checks for history clean up (applies to single state DB) + ## Regular checks for history clean up (applies to single state DB). This + ## is mainly a debugging/testing feature so that the database can be held + ## a bit smaller. It is not applicable to a full node. # ------------------------------------------------------------------------------ # Private @@ -57,7 +59,8 @@ proc getVmState(c: ChainRef, header: BlockHeader): return err() return ok(vmState) -proc purgeExpiredBlocks(db: CoreDbRef) {.inline, raises: [RlpError].} = + +proc purgeOutOfJournalBlocks(db: CoreDbRef) {.inline, raises: [RlpError].} = ## Remove non-reachable blocks from KVT database var blkNum = db.getOldestJournalBlockNumber() if 0 < blkNum: @@ -85,10 +88,9 @@ proc persistBlocksImpl(c: ChainRef; headers: openArray[BlockHeader]; let vmState = c.getVmState(headers[0]).valueOr: return ValidationResult.Error - # Needed for figuring out whether KVT cleanup is due (see at the end) let (fromBlock, toBlock) = (headers[0].blockNumber, headers[^1].blockNumber) - trace "Persisting blocks", fromBlock, toBlock + for i in 0 ..< headers.len: let (header, body) = (headers[i], bodies[i]) @@ -197,11 +199,11 @@ proc persistBlocksImpl(c: ChainRef; headers: openArray[BlockHeader]; # `persistent()` together with the respective block number. c.db.persistent(headers[0].blockNumber - 1) - # For a single state ledger, there is only a limited backlog. So clean up - # regularly (the `CleanUpEpoch` should not be too small as each lookup pulls - # a journal entry from disk.) - if (fromBlock mod CleanUpEpoch) <= (toBlock - fromBlock): - c.db.purgeExpiredBlocks() + if c.com.pruneHistory: + # There is a feature for test systems to regularly clean up older blocks + # from the database, not appicable to a full node set up. + if(fromBlock mod CleanUpEpoch) <= (toBlock - fromBlock): + c.db.purgeOutOfJournalBlocks() ValidationResult.OK diff --git a/nimbus/core/executor/process_block.nim b/nimbus/core/executor/process_block.nim index d175f6534f..5e30598487 100644 --- a/nimbus/core/executor/process_block.nim +++ b/nimbus/core/executor/process_block.nim @@ -28,10 +28,12 @@ import # Factored this out of procBlkPreamble so that it can be used directly for # stateless execution of specific transactions. -proc processTransactions*(vmState: BaseVMState; - header: BlockHeader; - transactions: seq[Transaction]): Result[void, string] - {.gcsafe, raises: [CatchableError].} = +proc processTransactions*( + vmState: BaseVMState; + header: BlockHeader; + transactions: seq[Transaction]; + ): Result[void, string] + {.gcsafe, raises: [CatchableError].} = vmState.receipts = newSeq[Receipt](transactions.len) vmState.cumulativeGasUsed = 0 @@ -151,8 +153,9 @@ proc procBlkEpilogue(vmState: BaseVMState; proc processBlock*( vmState: BaseVMState; ## Parent environment of header/body block header: BlockHeader; ## Header/body block to add to the blockchain - body: BlockBody): ValidationResult - {.gcsafe, raises: [CatchableError].} = + body: BlockBody; + ): ValidationResult + {.gcsafe, raises: [CatchableError].} = ## Generalised function to processes `(header,body)` pair for any network, ## regardless of PoA or not. ## diff --git a/nimbus/core/executor/process_transaction.nim b/nimbus/core/executor/process_transaction.nim index 28b92e1188..50589a2763 100644 --- a/nimbus/core/executor/process_transaction.nim +++ b/nimbus/core/executor/process_transaction.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2018-2023 Status Research & Development GmbH +# Copyright (c) 2018-2024 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) @@ -12,6 +12,7 @@ import std/strutils, + stew/results, ../../common/common, ../../db/ledger, ../../transaction/call_evm, @@ -19,11 +20,8 @@ import ../../transaction, ../../vm_state, ../../vm_types, - ../../evm/async/operations, ../../constants, - ../validate, - chronos, - stew/results + ../validate # ------------------------------------------------------------------------------ # Private functions @@ -37,10 +35,13 @@ proc eip1559BaseFee(header: BlockHeader; fork: EVMFork): UInt256 = result = header.baseFee proc commitOrRollbackDependingOnGasUsed( - vmState: BaseVMState, accTx: LedgerSpRef, - header: BlockHeader, tx: Transaction, - gasBurned: GasInt, priorityFee: GasInt): - Result[GasInt, string] {.raises: [].} = + vmState: BaseVMState; + accTx: LedgerSpRef; + header: BlockHeader; + tx: Transaction; + gasBurned: GasInt; + priorityFee: GasInt; + ): Result[GasInt, string] = # Make sure that the tx does not exceed the maximum cumulative limit as # set in the block header. Again, the eip-1559 reference does not mention # an early stop. It would rather detect differing values for the block @@ -63,14 +64,14 @@ proc commitOrRollbackDependingOnGasUsed( vmState.gasPool += tx.gasLimit - gasBurned return ok(gasBurned) -proc asyncProcessTransactionImpl( +proc processTransactionImpl( vmState: BaseVMState; ## Parent accounts environment for transaction tx: Transaction; ## Transaction to validate sender: EthAddress; ## tx.getSender or tx.ecRecover header: BlockHeader; ## Header for the block containing the current tx - fork: EVMFork): Future[Result[GasInt, string]] - # wildcard exception, wrapped below - {.async, gcsafe.} = + fork: EVMFork; + ): Result[GasInt, string] + {.raises: [CatchableError].} = ## Modelled after `https://eips.ethereum.org/EIPS/eip-1559#specification`_ ## which provides a backward compatible framwork for EIP1559. @@ -85,14 +86,10 @@ proc asyncProcessTransactionImpl( # Return failure unless explicitely set `ok()` var res: Result[GasInt, string] = err("") - await ifNecessaryGetAccounts(vmState, @[sender, vmState.coinbase()]) - if tx.to.isSome: - await ifNecessaryGetCode(vmState, tx.to.get) - # buy gas, then the gas goes into gasMeter if vmState.gasPool < tx.gasLimit: - return err("gas limit reached. gasLimit=$1, gasNeeded=$2" % [ - $vmState.gasPool, $tx.gasLimit]) + return err("gas limit reached. gasLimit=" & $vmState.gasPool & + ", gasNeeded=" & $tx.gasLimit) vmState.gasPool -= tx.gasLimit @@ -163,45 +160,25 @@ proc processBeaconBlockRoot*(vmState: BaseVMState, beaconRoot: Hash256): statedb.persist(clearEmptyAccount = true, clearCache = false) ok() -proc asyncProcessTransaction*( - vmState: BaseVMState; ## Parent accounts environment for transaction - tx: Transaction; ## Transaction to validate - sender: EthAddress; ## tx.getSender or tx.ecRecover - header: BlockHeader; ## Header for the block containing the current tx - fork: EVMFork): Future[Result[GasInt,string]] - {.async, gcsafe.} = - ## Process the transaction, write the results to accounts db. The function - ## returns the amount of gas burned if executed. - return await vmState.asyncProcessTransactionImpl(tx, sender, header, fork) - -# FIXME-duplicatedForAsync -proc asyncProcessTransaction*( - vmState: BaseVMState; ## Parent accounts environment for transaction - tx: Transaction; ## Transaction to validate - sender: EthAddress; ## tx.getSender or tx.ecRecover - header: BlockHeader): Future[Result[GasInt,string]] - {.async, gcsafe.} = - ## Variant of `asyncProcessTransaction()` with `*fork* derived - ## from the `vmState` argument. - let fork = vmState.com.toEVMFork(header.forkDeterminationInfo) - return await vmState.asyncProcessTransaction(tx, sender, header, fork) - proc processTransaction*( vmState: BaseVMState; ## Parent accounts environment for transaction tx: Transaction; ## Transaction to validate sender: EthAddress; ## tx.getSender or tx.ecRecover header: BlockHeader; ## Header for the block containing the current tx - fork: EVMFork): Result[GasInt,string] - {.gcsafe, raises: [CatchableError].} = - return waitFor(vmState.asyncProcessTransaction(tx, sender, header, fork)) + fork: EVMFork; + ): Result[GasInt,string] + {.raises: [CatchableError].} = + vmState.processTransactionImpl(tx, sender, header, fork) proc processTransaction*( vmState: BaseVMState; ## Parent accounts environment for transaction tx: Transaction; ## Transaction to validate sender: EthAddress; ## tx.getSender or tx.ecRecover - header: BlockHeader): Result[GasInt,string] - {.gcsafe, raises: [CatchableError].} = - return waitFor(vmState.asyncProcessTransaction(tx, sender, header)) + header: BlockHeader; + ): Result[GasInt,string] + {.raises: [CatchableError].} = + let fork = vmState.com.toEVMFork(header.forkDeterminationInfo) + vmState.processTransaction(tx, sender, header, fork) # ------------------------------------------------------------------------------ # End diff --git a/nimbus/db/core_db/core_apps_newapi.nim b/nimbus/db/core_db/core_apps_newapi.nim index 742547117d..65d6658043 100644 --- a/nimbus/db/core_db/core_apps_newapi.nim +++ b/nimbus/db/core_db/core_apps_newapi.nim @@ -925,19 +925,6 @@ proc persistHeaderToDbWithoutSetHead*( headerHash, action="put()", `error`=($$error) return -# FIXME-Adam: This seems like a bad idea. I don't see a way to get the score -# in stateless mode, but it seems dangerous to just shove the header into -# the DB *without* also storing the score. -proc persistHeaderToDbWithoutSetHeadOrScore*(db: CoreDbRef; header: BlockHeader) = - db.addBlockNumberToHashLookup(header) - let - kvt = db.newKvt() - blockHash = header.blockHash - kvt.put(genericHashKey(blockHash).toOpenArray, rlp.encode(header)).isOkOr: - warn logTxt "persistHeaderToDbWithoutSetHeadOrScore()", - blockHash, action="put()", `error`=($$error) - return - proc persistUncles*(db: CoreDbRef, uncles: openArray[BlockHeader]): Hash256 = ## Persists the list of uncles to the database. ## Returns the uncles hash. diff --git a/nimbus/db/incomplete_db.nim b/nimbus/db/incomplete_db.nim deleted file mode 100644 index 5964412fdc..0000000000 --- a/nimbus/db/incomplete_db.nim +++ /dev/null @@ -1,98 +0,0 @@ -# Nimbus -# Copyright (c) 2023-2024 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. - -#[ -FIXME-Adam: I feel like this and distinct_tries should either be combined or more clearly separated. - -The points of these two files are: - - Have distinct types for the two kinds of tries, because we really don't want to mix them up. - - Have an interface with functions like getAccountBytes rather than just get. (But still just a super-thin wrapper.) - - Have maybeGetWhatever instead of just getWhatever. (Also assertions.) - - Notice that this makes sense at both the bytes level and the Account/UInt256 level. - -]# - -import - chronicles, - eth/common, - "."/[core_db, distinct_tries, storage_types, values_from_bytes] - - - -# Useful for debugging. -const shouldDoAssertionsForMissingNodes* = false - -proc ifNodesExistGetAccountBytes*(trie: AccountsTrie, address: EthAddress): Option[seq[byte]] = - trie.maybeGetAccountBytes(address) - -proc ifNodesExistGetStorageBytesWithinAccount*(storageTrie: StorageTrie, slotAsKey: openArray[byte]): Option[seq[byte]] = - storageTrie.maybeGetSlotBytes(slotAsKey) - - -proc populateDbWithNodes*(db: CoreDbRef, nodes: seq[seq[byte]]) = - error("GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG AARDVARK: populateDbWithNodes received nodes, about to populate", nodes) # AARDVARK not an error, I just want it to stand out - for nodeBytes in nodes: - let nodeHash = keccakHash(nodeBytes) - info("AARDVARK: populateDbWithNodes about to add node", nodeHash, nodeBytes) - db.kvt.put(nodeHash.data, nodeBytes) - -# AARDVARK: just make the callers call populateDbWithNodes directly? -proc populateDbWithBranch*(db: CoreDbRef, branch: seq[seq[byte]]) = - for nodeBytes in branch: - let nodeHash = keccakHash(nodeBytes) - db.kvt.put(nodeHash.data, nodeBytes) - -# Returns a none if there are missing nodes; if the account itself simply -# doesn't exist yet, that's fine and it returns some(newAccount()). -proc ifNodesExistGetAccount*(trie: AccountsTrie, address: EthAddress): Option[Account] = - ifNodesExistGetAccountBytes(trie, address).map(accountFromBytes) - -proc maybeGetCode*(db: CoreDbRef, codeHash: Hash256): Option[seq[byte]] = - some(db.kvt.get(contractHashKey(codeHash).toOpenArray)) - -proc maybeGetCode*(trie: AccountsTrie, address: EthAddress): Option[seq[byte]] = - let maybeAcc = trie.ifNodesExistGetAccount(address) - if maybeAcc.isNone: - none[seq[byte]]() - else: - maybeGetCode(trie.db, maybeAcc.get.codeHash) - -proc checkingForMissingNodes_getCode*(trie: AccountsTrie, address: EthAddress): seq[byte] = - let m = maybeGetCode(trie, address) - doAssert(m.isSome, "missing code for account at " & $(address)) - m.get - -proc assertFetchedCode*(trie: AccountsTrie, address: EthAddress) = - if shouldDoAssertionsForMissingNodes: - let m = maybeGetCode(trie, address) - doAssert(m.isSome, "missing code for account at " & $(address)) - - -proc ifNodesExistGetStorageWithinAccount*(storageTrie: StorageTrie, slot: UInt256): Option[UInt256] = - ifNodesExistGetStorageBytesWithinAccount(storageTrie, createTrieKeyFromSlot(slot)).map(slotValueFromBytes) - -proc ifNodesExistGetStorage*(trie: AccountsTrie, address: EthAddress, slot: UInt256): Option[UInt256] = - let maybeAcc = ifNodesExistGetAccount(trie, address) - if maybeAcc.isNone: - none[UInt256]() - else: - ifNodesExistGetStorageWithinAccount(storageTrieForAccount(trie, maybeAcc.get), slot) - -proc hasAllNodesForAccount*(trie: AccountsTrie, address: EthAddress): bool = - ifNodesExistGetAccountBytes(trie, address).isSome - -proc hasAllNodesForCode*(trie: AccountsTrie, address: EthAddress): bool = - maybeGetCode(trie, address).isSome - -proc hasAllNodesForStorageSlot*(trie: AccountsTrie, address: EthAddress, slot: UInt256): bool = - ifNodesExistGetStorage(trie, address, slot).isSome - -proc assertFetchedStorage*(trie: AccountsTrie, address: EthAddress, slot: UInt256) = - doAssert(hasAllNodesForStorageSlot(trie, address, slot)) diff --git a/nimbus/db/ledger/backend/accounts_ledger.nim b/nimbus/db/ledger/backend/accounts_ledger.nim index e35bf88ae2..bd897319f5 100644 --- a/nimbus/db/ledger/backend/accounts_ledger.nim +++ b/nimbus/db/ledger/backend/accounts_ledger.nim @@ -171,11 +171,7 @@ proc ledgerMethods(lc: impl.AccountsLedgerRef): LedgerFns = proc ledgerExtras(lc: impl.AccountsLedgerRef): LedgerExtras = LedgerExtras( getMptFn: proc(): CoreDbMptRef = - lc.rawTrie.CoreDxAccRef.getMpt.CoreDbMptRef, - - rawRootHashFn: proc(): Hash256 = - lc.rawTrie.state()) - + lc.rawTrie.CoreDxAccRef.getMpt.CoreDbMptRef) proc newAccountsLedgerRef( db: CoreDbRef; diff --git a/nimbus/db/ledger/base.nim b/nimbus/db/ledger/base.nim index 9ea4f10738..f22221eb7d 100644 --- a/nimbus/db/ledger/base.nim +++ b/nimbus/db/ledger/base.nim @@ -372,11 +372,6 @@ proc getMpt*(ldg: LedgerRef): CoreDbMptRef = result = ldg.extras.getMptFn() ldg.ifTrackApi: debug apiTxt, api, elapsed, result -proc rawRootHash*(ldg: LedgerRef): Hash256 = - ldg.beginTrackApi LdgRawRootHashFn - result = ldg.extras.rawRootHashFn() - ldg.ifTrackApi: debug apiTxt, api, elapsed, result - # ------------------------------------------------------------------------------ # Public virtual read-only methods # ------------------------------------------------------------------------------ diff --git a/nimbus/db/ledger/base/base_desc.nim b/nimbus/db/ledger/base/base_desc.nim index 78b7cfd061..4e453bc0cc 100644 --- a/nimbus/db/ledger/base/base_desc.nim +++ b/nimbus/db/ledger/base/base_desc.nim @@ -41,12 +41,10 @@ type extras*: LedgerExtras ## Support might go away methods*: LedgerFns - RawRootHashFn* = proc(): Hash256 {.noRaise.} GetMptFn* = proc(): CoreDbMptRef {.noRaise.} LedgerExtras* = object getMptFn*: GetMptFn - rawRootHashFn*: RawRootHashFn AccessListFn* = proc(eAddr: EthAddress) {.noRaise.} AccessList2Fn* = proc(eAddr: EthAddress, slot: UInt256) {.noRaise.} diff --git a/nimbus/db/ledger/base/validate.nim b/nimbus/db/ledger/base/validate.nim index a5bf0295c6..55a1443c1a 100644 --- a/nimbus/db/ledger/base/validate.nim +++ b/nimbus/db/ledger/base/validate.nim @@ -17,7 +17,6 @@ proc validate*(ldg: LedgerRef) = doAssert ldg.ldgType != LedgerType(0) doAssert not ldg.extras.getMptFn.isNil - doAssert not ldg.extras.rawRootHashFn.isNil doAssert not ldg.methods.accessListFn.isNil doAssert not ldg.methods.accessList2Fn.isNil diff --git a/nimbus/evm/async/data_sources.nim b/nimbus/evm/async/data_sources.nim deleted file mode 100644 index c981c8b818..0000000000 --- a/nimbus/evm/async/data_sources.nim +++ /dev/null @@ -1,60 +0,0 @@ -# Nimbus -# Copyright (c) 2023-2024 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. - -import - std/options, - chronos, - stint, - eth/common, - ../../db/core_db - -type - AsyncDataSource* = ref object of RootObj - ifNecessaryGetSlots*: proc(db: CoreDbRef, blockNumber: BlockNumber, stateRoot: Hash256, address: EthAddress, slots: seq[UInt256], newStateRootForSanityChecking: Hash256): Future[void] {.gcsafe, raises: [].} - ifNecessaryGetCode*: proc(db: CoreDbRef, blockNumber: BlockNumber, stateRoot: Hash256, address: EthAddress, newStateRootForSanityChecking: Hash256): Future[void] {.gcsafe, raises: [].} - ifNecessaryGetAccount*: proc(db: CoreDbRef, blockNumber: BlockNumber, stateRoot: Hash256, address: EthAddress, newStateRootForSanityChecking: Hash256): Future[void] {.gcsafe, raises: [].} - ifNecessaryGetBlockHeaderByNumber*: proc(coreDb: CoreDbRef, blockNumber: BlockNumber): Future[void] {.gcsafe, raises: [].} - # FIXME-Adam: Later. - #fetchNodes*: proc(stateRoot: Hash256, paths: seq[seq[seq[byte]]], nodeHashes: seq[Hash256]): Future[seq[seq[byte]]] {.gcsafe.} - fetchBlockHeaderWithHash*: proc(h: Hash256): Future[BlockHeader] {.gcsafe.} - fetchBlockHeaderWithNumber*: proc(n: BlockNumber): Future[BlockHeader] {.gcsafe.} - fetchBlockHeaderAndBodyWithHash*: proc(h: Hash256): Future[(BlockHeader, BlockBody)] {.gcsafe.} - fetchBlockHeaderAndBodyWithNumber*: proc(n: BlockNumber): Future[(BlockHeader, BlockBody)] {.gcsafe.} - - # FIXME-Adam: maybe rename this? - AsyncOperationFactory* = ref object of RootObj - maybeDataSource*: Option[AsyncDataSource] - - -# FIXME-Adam: Can I make a singleton? -proc asyncFactoryWithNoDataSource*(): AsyncOperationFactory = - AsyncOperationFactory(maybeDataSource: none[AsyncDataSource]()) - - -# FIXME-Adam: Ugly but straightforward; can this be cleaned up using some combination of: -# - an ifSome/map operation on Options -# - some kind of "what are we fetching" tuple, so that this is just one thing - -proc ifNecessaryGetSlots*(asyncFactory: AsyncOperationFactory, db: CoreDbRef, blockNumber: BlockNumber, stateRoot: Hash256, address: EthAddress, slots: seq[UInt256], newStateRootForSanityChecking: Hash256): Future[void] {.async.} = - if asyncFactory.maybeDataSource.isSome: - await asyncFactory.maybeDataSource.get.ifNecessaryGetSlots(db, blockNumber, stateRoot, address, slots, newStateRootForSanityChecking) - -proc ifNecessaryGetCode*(asyncFactory: AsyncOperationFactory, db: CoreDbRef, blockNumber: BlockNumber, stateRoot: Hash256, address: EthAddress, newStateRootForSanityChecking: Hash256): Future[void] {.async.} = - if asyncFactory.maybeDataSource.isSome: - await asyncFactory.maybeDataSource.get.ifNecessaryGetCode(db, blockNumber, stateRoot, address, newStateRootForSanityChecking) - - -proc ifNecessaryGetAccount*(asyncFactory: AsyncOperationFactory, db: CoreDbRef, blockNumber: BlockNumber, stateRoot: Hash256, address: EthAddress, newStateRootForSanityChecking: Hash256): Future[void] {.async.} = - if asyncFactory.maybeDataSource.isSome: - await asyncFactory.maybeDataSource.get.ifNecessaryGetAccount(db, blockNumber, stateRoot, address, newStateRootForSanityChecking) - -proc ifNecessaryGetBlockHeaderByNumber*(asyncFactory: AsyncOperationFactory, coreDb: CoreDbRef, blockNumber: BlockNumber): Future[void] {.async.} = - if asyncFactory.maybeDataSource.isSome: - await asyncFactory.maybeDataSource.get.ifNecessaryGetBlockHeaderByNumber(coreDb, blockNumber) diff --git a/nimbus/evm/async/data_sources/json_rpc_data_source.nim b/nimbus/evm/async/data_sources/json_rpc_data_source.nim deleted file mode 100644 index 54d9301dfa..0000000000 --- a/nimbus/evm/async/data_sources/json_rpc_data_source.nim +++ /dev/null @@ -1,371 +0,0 @@ -# Nimbus -# Copyright (c) 2023-2024 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. - -import - std/[sequtils, typetraits, options, times], - chronicles, - chronos, - nimcrypto, - stint, - stew/byteutils, - json_rpc/rpcclient, - eth/common, - eth/rlp, - eth/trie/hexary_proof_verification, - eth/p2p, - eth/p2p/rlpx, - eth/p2p/private/p2p_types, - #../../../sync/protocol, - ../../../db/[core_db, distinct_tries, incomplete_db, storage_types], - ../data_sources, - ../../../beacon/web3_eth_conv, - web3/conversions, - web3 - -export AsyncOperationFactory, AsyncDataSource - -type - BlockHeader = eth_types.BlockHeader - -var durationSpentDoingFetches*: times.Duration -var fetchCounter*: int - -proc makeAnRpcClient*(web3Url: string): Future[RpcClient] {.async.} = - let myWeb3: Web3 = waitFor(newWeb3(web3Url)) - return myWeb3.provider - -func blockHeaderFromBlockObject(o: BlockObject): BlockHeader = - let nonce: BlockNonce = if o.nonce.isSome: distinctBase(o.nonce.get) else: default(BlockNonce) - BlockHeader( - parentHash: o.parentHash.ethHash, - ommersHash: o.sha3Uncles.ethHash, - coinbase: o.miner.ethAddr, - stateRoot: o.stateRoot.ethHash, - txRoot: o.transactionsRoot.ethHash, - receiptRoot: o.receiptsRoot.ethHash, - bloom: distinctBase(o.logsBloom), - difficulty: o.difficulty, - blockNumber: o.number.u256, - gasLimit: GasInt(distinctBase(o.gasLimit)), - gasUsed: GasInt(distinctBase(o.gasUsed)), - timestamp: EthTime(distinctBase(o.timestamp)), - extraData: distinctBase(o.extraData), - #mixDigest: o.mixHash.ethHash, # AARDVARK what's this? - nonce: nonce, - fee: o.baseFeePerGas, - withdrawalsRoot: ethHash o.withdrawalsRoot, - blobGasUsed: u64 o.blobGasUsed, - excessBlobGas: u64 o.excessBlobGas - ) - -proc fetchBlockHeaderWithHash*(rpcClient: RpcClient, h: common.Hash256): Future[common.BlockHeader] {.async.} = - let t0 = now() - let blockObject: BlockObject = await rpcClient.eth_getBlockByHash(h.w3Hash, false) - durationSpentDoingFetches += now() - t0 - fetchCounter += 1 - return blockHeaderFromBlockObject(blockObject) - -proc fetchBlockHeaderWithNumber*(rpcClient: RpcClient, n: common.BlockNumber): Future[common.BlockHeader] {.async.} = - let t0 = now() - let bid = blockId(w3BlockNumber n) - let blockObject: BlockObject = await rpcClient.eth_getBlockByNumber(bid, false) - durationSpentDoingFetches += now() - t0 - fetchCounter += 1 - return blockHeaderFromBlockObject(blockObject) - -# Cruft moved to `json_rpc_data_source/currently_unused.nim` - -proc fetchBlockHeaderAndBodyWithHash*(rpcClient: RpcClient, h: common.Hash256): Future[(common.BlockHeader, BlockBody)] {.async.} = - doAssert(false, "AARDVARK not implemented") - -proc fetchBlockHeaderAndBodyWithNumber*(rpcClient: RpcClient, n: common.BlockNumber): Future[(common.BlockHeader, BlockBody)] {.async.} = - doAssert(false, "AARDVARK not implemented") - -func mdigestFromFixedBytes*(arg: FixedBytes[32]): MDigest[256] = - MDigest[256](data: distinctBase(arg)) - -func mdigestFromString*(s: string): MDigest[256] = - mdigestFromFixedBytes(FixedBytes[32].fromHex(s)) - -type - AccountProof* = seq[seq[byte]] - -proc fetchAccountAndSlots*(rpcClient: RpcClient, address: EthAddress, slots: seq[UInt256], blockNumber: common.BlockNumber): Future[(Account, AccountProof, seq[StorageProof])] {.async.} = - let t0 = now() - debug "Got to fetchAccountAndSlots", address=address, slots=slots, blockNumber=blockNumber - #let blockNumberUint64 = blockNumber.truncate(uint64) - let a = web3.Address(address) - let bid = blockId(w3BlockNumber blockNumber) - debug "About to call eth_getProof", address=address, slots=slots, blockNumber=blockNumber - let proofResponse: ProofResponse = await rpcClient.eth_getProof(a, slots, bid) - debug "Received response to eth_getProof", proofResponse=proofResponse - - let acc = Account( - nonce: distinctBase(proofResponse.nonce), - balance: proofResponse.balance, - storageRoot: mdigestFromFixedBytes(proofResponse.storageHash), - codeHash: mdigestFromFixedBytes(proofResponse.codeHash) - ) - debug "Parsed response to eth_getProof", acc=acc - let mptNodesBytes: seq[seq[byte]] = proofResponse.accountProof.mapIt(distinctBase(it)) - durationSpentDoingFetches += now() - t0 - fetchCounter += 1 - return (acc, mptNodesBytes, proofResponse.storageProof) - -proc fetchCode*(client: RpcClient, blockNumber: common.BlockNumber, address: EthAddress): Future[seq[byte]] {.async.} = - let t0 = now() - let a = web3.Address(address) - let bid = blockId(w3BlockNumber blockNumber) - let fetchedCode: seq[byte] = await client.eth_getCode(a, bid) - durationSpentDoingFetches += now() - t0 - fetchCounter += 1 - return fetchedCode - -# Cruft moved to json_rpc_data_source/currently_unused.nim - -proc verifyFetchedAccount(stateRoot: common.Hash256, address: EthAddress, acc: Account, accProof: seq[seq[byte]]): Result[void, string] = - let accKey = toSeq(keccakHash(address).data) - let accEncoded = rlp.encode(acc) - let accProofResult = verifyMptProof(accProof, stateRoot, accKey, accEncoded) - case accProofResult.kind - of ValidProof: - return ok() - of MissingKey: - # For an account that doesn't exist yet, which is fine. - return ok() - of InvalidProof: - return err(accProofResult.errorMsg) - -type - CodeFetchingInfo = tuple[blockNumber: common.BlockNumber, address: EthAddress] - -proc fetchCode(client: RpcClient, p: CodeFetchingInfo): Future[seq[byte]] {.async.} = - let (blockNumber, address) = p - let fetchedCode = await fetchCode(client, blockNumber, address) - return fetchedCode - -proc verifyFetchedCode(fetchedCode: seq[byte], desiredCodeHash: common.Hash256): Result[void, common.Hash256] = - let fetchedCodeHash = keccakHash(fetchedCode) - if desiredCodeHash == fetchedCodeHash: - ok() - else: - err(fetchedCodeHash) - -proc fetchAndVerifyCode(client: RpcClient, p: CodeFetchingInfo, desiredCodeHash: common.Hash256): Future[seq[byte]] {.async.} = - let fetchedCode: seq[byte] = await fetchCode(client, p) - let verificationRes = verifyFetchedCode(fetchedCode, desiredCodeHash) - if verificationRes.isOk(): - return fetchedCode - else: - let fetchedCodeHash = verificationRes.error - error("code hash values do not match", p=p, desiredCodeHash=desiredCodeHash, fetchedCodeHash=fetchedCodeHash) - raise newException(CatchableError, "async code received code for " & $(p.address) & " whose hash (" & $(fetchedCodeHash) & ") does not match the desired hash (" & $(desiredCodeHash) & ")") - -proc putCode*(db: CoreDbRef, codeHash: common.Hash256, code: seq[byte]) = - when defined(geth): - db.kvt.put(codeHash.data, code) - else: - db.kvt.put(contractHashKey(codeHash).toOpenArray, code) - -proc putCode*(trie: AccountsTrie, codeHash: common.Hash256, code: seq[byte]) = - putCode(trie.db, codeHash, code) - -proc storeCode(trie: AccountsTrie, p: CodeFetchingInfo, desiredCodeHash: common.Hash256, fetchedCode: seq[byte]) = - trie.putCode(desiredCodeHash, fetchedCode) - -proc assertThatWeHaveStoredCode(trie: AccountsTrie, p: CodeFetchingInfo, codeHash: common.Hash256) = - # FIXME-Adam: this is a bit wrong because we're not checking it against the blockNumber, only the address. (That is, - # if the code for this address has *changed* (which is unlikely), this check isn't the right thing to do.) - let maybeFoundCode = trie.maybeGetCode(p.address) - if maybeFoundCode.isNone: - error("code didn't get put into the db", p=p, codeHash=codeHash) - doAssert false, "code didn't get put into the db" - else: - let foundCode = maybeFoundCode.get - let foundCodeHash = keccakHash(foundCode) - if foundCodeHash != codeHash: - error("code does not have the right hash", p=p, codeHash=codeHash, foundCode=foundCode) - doAssert false, "code does not have the right hash" - - -proc assertThatWeHaveStoredAccount(trie: AccountsTrie, address: EthAddress, fetchedAcc: Account, isForTheNewTrie: bool = false) = - let foundAcc = ifNodesExistGetAccount(trie, address).get - if fetchedAcc != foundAcc: - error "account didn't come out the same", address=address, fetchedAcc=fetchedAcc, foundAcc=foundAcc, isForTheNewTrie=isForTheNewTrie - doAssert false, "account didn't come out the same" - doAssert(trie.hasAllNodesForAccount(address), "Can I check the account this way, too?") - - -proc verifyFetchedSlot(accountStorageRoot: common.Hash256, slot: UInt256, fetchedVal: UInt256, storageMptNodes: seq[seq[byte]]): Result[void, string] = - if storageMptNodes.len == 0: - # I think an empty storage proof is okay; I see lots of these - # where the account is empty and the value is zero. - return ok() - else: - let storageKey = toSeq(keccakHash(toBytesBE(slot)).data) - let storageValueEncoded = rlp.encode(fetchedVal) - let storageProofResult = verifyMptProof(storageMptNodes, accountStorageRoot, storageKey, storageValueEncoded) - case storageProofResult.kind - of ValidProof: - return ok() - of MissingKey: - # This is for a slot that doesn't have anything stored at it, but that's fine. - return ok() - of InvalidProof: - return err(storageProofResult.errorMsg) - - -proc assertThatWeHaveStoredSlot(trie: AccountsTrie, address: EthAddress, acc: Account, slot: common.UInt256, fetchedVal: UInt256, isForTheNewTrie: bool = false) = - if acc.storageRoot == EMPTY_ROOT_HASH and fetchedVal.isZero: - # I believe this is okay. - discard - else: - let foundVal = ifNodesExistGetStorage(trie, address, slot).get - if (fetchedVal != foundVal): - error("slot didn't come out the same", address=address, slot=slot, fetchedVal=fetchedVal, foundVal=foundVal, isForTheNewTrie=isForTheNewTrie) - doAssert false, "slot didn't come out the same" - - -proc verifyFetchedBlockHeader(fetchedHeader: common.BlockHeader, desiredBlockNumber: common.BlockNumber): Result[void, common.BlockNumber] = - # *Can* we do anything to verify this header, given that all we know - # is the desiredBlockNumber and we want to run statelessly so we don't - # know what block hash we want? - ok() - -proc storeBlockHeader(chainDB: CoreDbRef, header: common.BlockHeader) = - chainDB.persistHeaderToDbWithoutSetHeadOrScore(header) - -proc assertThatWeHaveStoredBlockHeader(chainDB: CoreDbRef, blockNumber: common.BlockNumber, header: common.BlockHeader) = - let h = chainDB.getBlockHash(blockNumber) - doAssert(h == header.blockHash, "stored the block header for block " & $(blockNumber)) - -proc raiseExceptionIfError[V, E](whatAreWeVerifying: V, r: Result[void, E]) = - if r.isErr: - error("async code failed to verify", whatAreWeVerifying=whatAreWeVerifying, err=r.error) - raise newException(CatchableError, "async code failed to verify: " & $(whatAreWeVerifying) & ", error is: " & $(r.error)) - -const shouldDoUnnecessarySanityChecks = true - -# This proc fetches both the account and also optionally some of its slots, because that's what eth_getProof can do. -proc ifNecessaryGetAccountAndSlots*(client: RpcClient, db: CoreDbRef, blockNumber: common.BlockNumber, stateRoot: common.Hash256, address: EthAddress, slots: seq[UInt256], justCheckingAccount: bool, justCheckingSlots: bool, newStateRootForSanityChecking: common.Hash256): Future[void] {.async.} = - let trie = initAccountsTrie(db, stateRoot, false) # important for sanity checks - let trie2 = initAccountsTrie(db, newStateRootForSanityChecking, false) # important for sanity checks - let doesAccountActuallyNeedToBeFetched = not trie.hasAllNodesForAccount(address) - let slotsToActuallyFetch = slots.filter(proc(slot: UInt256): bool = not (trie.hasAllNodesForStorageSlot(address, slot))) - if (not doesAccountActuallyNeedToBeFetched) and (slotsToActuallyFetch.len == 0): - # Already have them, no need to fetch either the account or the slots - discard - else: - let (acc, accProof, storageProofs) = await fetchAccountAndSlots(client, address, slotsToActuallyFetch, blockNumber) - - # We need to verify the proof even if we already had this account, - # to make sure the data is valid. - let accountVerificationRes = verifyFetchedAccount(stateRoot, address, acc, accProof) - let whatAreWeVerifying = ("account proof", address, acc) - raiseExceptionIfError(whatAreWeVerifying, accountVerificationRes) - - if not doesAccountActuallyNeedToBeFetched: - # We already had the account, no need to populate the DB with it again. - discard - else: - if not justCheckingAccount: - populateDbWithBranch(db, accProof) - if shouldDoUnnecessarySanityChecks: - assertThatWeHaveStoredAccount(trie, address, acc, false) - if doesAccountActuallyNeedToBeFetched: # this second check makes no sense if it's not the first time - assertThatWeHaveStoredAccount(trie2, address, acc, true) - - doAssert(slotsToActuallyFetch.len == storageProofs.len, "We should get back the same number of storage proofs as slots that we asked for. I think.") - - for storageProof in storageProofs: - let slot: UInt256 = storageProof.key - let fetchedVal: UInt256 = storageProof.value - let storageMptNodes: seq[seq[byte]] = storageProof.proof.mapIt(distinctBase(it)) - let storageVerificationRes = verifyFetchedSlot(acc.storageRoot, slot, fetchedVal, storageMptNodes) - let whatAreWeVerifying = ("storage proof", address, acc, slot, fetchedVal) - raiseExceptionIfError(whatAreWeVerifying, storageVerificationRes) - - if not justCheckingSlots: - populateDbWithBranch(db, storageMptNodes) - - # I believe this is done so that we can iterate over the slots. See - # persistStorage in `db/ledger`. - let slotAsKey = createTrieKeyFromSlot(slot) - let slotHash = keccakHash(slotAsKey) - let slotEncoded = rlp.encode(slot) - db.kvt.put(slotHashToSlotKey(slotHash.data).toOpenArray, slotEncoded) - - if shouldDoUnnecessarySanityChecks: - assertThatWeHaveStoredSlot(trie, address, acc, slot, fetchedVal, false) - assertThatWeHaveStoredSlot(trie2, address, acc, slot, fetchedVal, true) - -proc ifNecessaryGetCode*(client: RpcClient, db: CoreDbRef, blockNumber: common.BlockNumber, stateRoot: common.Hash256, address: EthAddress, justChecking: bool, newStateRootForSanityChecking: common.Hash256): Future[void] {.async.} = - await ifNecessaryGetAccountAndSlots(client, db, blockNumber, stateRoot, address, @[], false, false, newStateRootForSanityChecking) # to make sure we've got the codeHash - let trie = initAccountsTrie(db, stateRoot, false) # important for sanity checks - - let acc = ifNodesExistGetAccount(trie, address).get - let desiredCodeHash = acc.codeHash - - let p = (blockNumber, address) - if not(trie.hasAllNodesForCode(address)): - let fetchedCode = await fetchAndVerifyCode(client, p, desiredCodeHash) - - if not justChecking: - storeCode(trie, p, desiredCodeHash, fetchedCode) - if shouldDoUnnecessarySanityChecks: - assertThatWeHaveStoredCode(trie, p, desiredCodeHash) - -proc ifNecessaryGetBlockHeaderByNumber*(client: RpcClient, chainDB: CoreDbRef, blockNumber: common.BlockNumber, justChecking: bool): Future[void] {.async.} = - let maybeHeaderAndHash = chainDB.getBlockHeaderWithHash(blockNumber) - if maybeHeaderAndHash.isNone: - let fetchedHeader = await fetchBlockHeaderWithNumber(client, blockNumber) - let headerVerificationRes = verifyFetchedBlockHeader(fetchedHeader, blockNumber) - let whatAreWeVerifying = ("block header by number", blockNumber, fetchedHeader) - raiseExceptionIfError(whatAreWeVerifying, headerVerificationRes) - - if not justChecking: - storeBlockHeader(chainDB, fetchedHeader) - if shouldDoUnnecessarySanityChecks: - assertThatWeHaveStoredBlockHeader(chainDB, blockNumber, fetchedHeader) - -# Used in asynchronous on-demand-data-fetching mode. -proc realAsyncDataSource*(peerPool: PeerPool, client: RpcClient, justChecking: bool): AsyncDataSource = - AsyncDataSource( - ifNecessaryGetAccount: (proc(db: CoreDbRef, blockNumber: common.BlockNumber, stateRoot: common.Hash256, address: EthAddress, newStateRootForSanityChecking: common.Hash256): Future[void] {.async.} = - await ifNecessaryGetAccountAndSlots(client, db, blockNumber, stateRoot, address, @[], false, false, newStateRootForSanityChecking) - ), - ifNecessaryGetSlots: (proc(db: CoreDbRef, blockNumber: common.BlockNumber, stateRoot: common.Hash256, address: EthAddress, slots: seq[UInt256], newStateRootForSanityChecking: common.Hash256): Future[void] {.async.} = - await ifNecessaryGetAccountAndSlots(client, db, blockNumber, stateRoot, address, slots, false, false, newStateRootForSanityChecking) - ), - ifNecessaryGetCode: (proc(db: CoreDbRef, blockNumber: common.BlockNumber, stateRoot: common.Hash256, address: EthAddress, newStateRootForSanityChecking: common.Hash256): Future[void] {.async.} = - await ifNecessaryGetCode(client, db, blockNumber, stateRoot, address, justChecking, newStateRootForSanityChecking) - ), - ifNecessaryGetBlockHeaderByNumber: (proc(chainDB: CoreDbRef, blockNumber: common.BlockNumber): Future[void] {.async.} = - await ifNecessaryGetBlockHeaderByNumber(client, chainDB, blockNumber, justChecking) - ), - - # FIXME-Adam: This will be needed later, but for now let's just get the basic methods in place. - #fetchNodes: (proc(stateRoot: Hash256, paths: seq[seq[seq[byte]]], nodeHashes: seq[Hash256]): Future[seq[seq[byte]]] {.async.} = - # return await fetchNodes(peerPool, stateRoot, paths, nodeHashes) - #), - - fetchBlockHeaderWithHash: (proc(h: common.Hash256): Future[common.BlockHeader] {.async.} = - return await fetchBlockHeaderWithHash(client, h) - ), - fetchBlockHeaderWithNumber: (proc(n: common.BlockNumber): Future[common.BlockHeader] {.async.} = - return await fetchBlockHeaderWithNumber(client, n) - ), - fetchBlockHeaderAndBodyWithHash: (proc(h: common.Hash256): Future[(common.BlockHeader, BlockBody)] {.async.} = - return await fetchBlockHeaderAndBodyWithHash(client, h) - ), - fetchBlockHeaderAndBodyWithNumber: (proc(n: common.BlockNumber): Future[(common.BlockHeader, BlockBody)] {.async.} = - return await fetchBlockHeaderAndBodyWithNumber(client, n) - ) - ) diff --git a/nimbus/evm/async/data_sources/json_rpc_data_source/currently_unused.nim b/nimbus/evm/async/data_sources/json_rpc_data_source/currently_unused.nim deleted file mode 100644 index 609ee3d964..0000000000 --- a/nimbus/evm/async/data_sources/json_rpc_data_source/currently_unused.nim +++ /dev/null @@ -1,133 +0,0 @@ -# Nimbus -# Copyright (c) 2023-2024 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. - -import - std/[sequtils, typetraits, options, times, json], - chronicles, - chronos, - nimcrypto, - stint, - stew/byteutils, - json_rpc/rpcclient, - eth/common, - eth/rlp, - eth/trie/hexary_proof_verification, - eth/p2p, - eth/p2p/rlpx, - eth/p2p/private/p2p_types, - #../../../sync/protocol, - ../../../../db/[core_db, distinct_tries, incomplete_db, storage_types], - ../../data_sources, - ../../../../beacon/web3_eth_conv, - web3/conversions, - web3 - -when defined(legacy_eth66_enabled): - from ../../../sync/protocol/eth66 import getNodeData - -# Comment extracted from `json_rpc_data_source.nim` line 83 -# --------------------------------------------------------- - -proc parseBlockBodyAndFetchUncles(rpcClient: RpcClient, r: JsonNode): Future[BlockBody] {.async.} = - var body: BlockBody - for tn in r["transactions"].getElems: - body.transactions.add(parseTransaction(tn)) - for un in r["uncles"].getElems: - let uncleHash: Hash256 = un.getStr.ethHash - let uncleHeader = await fetchBlockHeaderWithHash(rpcClient, uncleHash) - body.uncles.add(uncleHeader) - return body - -proc fetchBlockHeaderAndBodyWithHash*(rpcClient: RpcClient, h: Hash256): Future[(BlockHeader, BlockBody)] {.async.} = - let t0 = now() - let r = request("eth_getBlockByHash", %[%h.prefixHex, %true], some(rpcClient)) - durationSpentDoingFetches += now() - t0 - fetchCounter += 1 - if r.kind == JNull: - error "requested block not available", blockHash=h - raise newException(ValueError, "Error when retrieving block header and body") - let header = parseBlockHeader(r) - let body = await parseBlockBodyAndFetchUncles(rpcClient, r) - return (header, body) - -proc fetchBlockHeaderAndBodyWithNumber*(rpcClient: RpcClient, n: BlockNumber): Future[(BlockHeader, BlockBody)] {.async.} = - let t0 = now() - let r = request("eth_getBlockByNumber", %[%n.prefixHex, %true], some(rpcClient)) - durationSpentDoingFetches += now() - t0 - fetchCounter += 1 - if r.kind == JNull: - error "requested block not available", blockNumber=n - raise newException(ValueError, "Error when retrieving block header and body") - let header = parseBlockHeader(r) - let body = await parseBlockBodyAndFetchUncles(rpcClient, r) - return (header, body) - - -# Comment extracted from `json_rpc_data_source.nim` line 131 -# ---------------------------------------------------------- - -const bytesLimit = 2 * 1024 * 1024 -const maxNumberOfPeersToAttempt = 3 - -proc fetchUsingGetTrieNodes(peer: Peer, stateRoot: common.Hash256, paths: seq[SnapTriePaths]): Future[seq[seq[byte]]] {.async.} = - let r = await peer.getTrieNodes(stateRoot, paths, bytesLimit) - if r.isNone: - raise newException(CatchableError, "AARDVARK: received None in GetTrieNodes response") - else: - return r.get.nodes - -proc fetchUsingGetNodeData(peer: Peer, nodeHashes: seq[common.Hash256]): Future[seq[seq[byte]]] {.async.} = - - let r: Option[seq[seq[byte]]] = none[seq[seq[byte]]]() # AARDVARK await peer.getNodeData(nodeHashes) - if r.isNone: - raise newException(CatchableError, "AARDVARK: received None in GetNodeData response") - else: - echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA fetchUsingGetNodeData received nodes: " & $(r.get.data) - return r.get.data - - # AARDVARK whatever - return @[] - -proc findPeersAndMakeSomeCalls[R](peerPool: PeerPool, protocolName: string, protocolType: typedesc, initiateAttempt: (proc(p: Peer): Future[R] {.gcsafe, raises: [].})): Future[seq[Future[R]]] {.async.} = - var attempts: seq[Future[R]] - while true: - #info("AARDVARK: findPeersAndMakeSomeCalls about to loop through the peer pool", count=peerPool.connectedNodes.len) - for nodeOfSomeSort, peer in peerPool.connectedNodes: - if peer.supports(protocolType): - info("AARDVARK: findPeersAndMakeSomeCalls calling peer", protocolName, peer) - attempts.add(initiateAttempt(peer)) - if attempts.len >= maxNumberOfPeersToAttempt: - break - #else: - # info("AARDVARK: peer does not support protocol", protocolName, peer) - if attempts.len == 0: - warn("AARDVARK: findPeersAndMakeSomeCalls did not find any peers; waiting and trying again", protocolName, totalPeerPoolSize=peerPool.connectedNodes.len) - await sleepAsync(chronos.seconds(5)) - else: - if attempts.len < maxNumberOfPeersToAttempt: - warn("AARDVARK: findPeersAndMakeSomeCalls did not find enough peers, but found some", protocolName, totalPeerPoolSize=peerPool.connectedNodes.len, found=attempts.len) - break - return attempts - -proc findPeersAndMakeSomeAttemptsToCallGetTrieNodes(peerPool: PeerPool, stateRoot: common.Hash256, paths: seq[SnapTriePaths]): Future[seq[Future[seq[seq[byte]]]]] = - findPeersAndMakeSomeCalls(peerPool, "snap", protocol.snap, (proc(peer: Peer): Future[seq[seq[byte]]] = fetchUsingGetTrieNodes(peer, stateRoot, paths))) - -proc findPeersAndMakeSomeAttemptsToCallGetNodeData(peerPool: PeerPool, stateRoot: Hash256, nodeHashes: seq[Hash256]): Future[seq[Future[seq[seq[byte]]]]] = - findPeersAndMakeSomeCalls(peerPool, "eth66", eth66, (proc(peer: Peer): Future[seq[seq[byte]]] = fetchUsingGetNodeData(peer, nodeHashes))) - -proc fetchNodes(peerPool: PeerPool, stateRoot: common.Hash256, paths: seq[SnapTriePaths], nodeHashes: seq[common.Hash256]): Future[seq[seq[byte]]] {.async.} = - let attempts = await findPeersAndMakeSomeAttemptsToCallGetTrieNodes(peerPool, stateRoot, paths) - #let attempts = await findPeersAndMakeSomeAttemptsToCallGetNodeData(peerPool, stateRoot, nodeHashes) - let completedAttempt = await one(attempts) - let nodes: seq[seq[byte]] = completedAttempt.read - info("AARDVARK: fetchNodes received nodes", nodes) - return nodes - -# End diff --git a/nimbus/evm/async/operations.nim b/nimbus/evm/async/operations.nim deleted file mode 100644 index f4f4c16335..0000000000 --- a/nimbus/evm/async/operations.nim +++ /dev/null @@ -1,63 +0,0 @@ -# Nimbus -# Copyright (c) 2023 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. - -import - chronos, - stint, - eth/common, - ../../common as dot_common, - ../../db/ledger, - ../types, - ./data_sources - - - -proc ifNecessaryGetAccount*(vmState: BaseVMState, address: EthAddress): Future[void] {.async.} = - if vmState.com.db.localDbOnly: return - await vmState.asyncFactory.ifNecessaryGetAccount(vmState.com.db, vmState.parent.blockNumber, vmState.parent.stateRoot, address, vmState.stateDB.rawRootHash) - -proc ifNecessaryGetCode*(vmState: BaseVMState, address: EthAddress): Future[void] {.async.} = - if vmState.com.db.localDbOnly: return - await vmState.asyncFactory.ifNecessaryGetCode(vmState.com.db, vmState.parent.blockNumber, vmState.parent.stateRoot, address, vmState.stateDB.rawRootHash) - -proc ifNecessaryGetSlots*(vmState: BaseVMState, address: EthAddress, slots: seq[UInt256]): Future[void] {.async.} = - if vmState.com.db.localDbOnly: return - await vmState.asyncFactory.ifNecessaryGetSlots(vmState.com.db, vmState.parent.blockNumber, vmState.parent.stateRoot, address, slots, vmState.stateDB.rawRootHash) - -proc ifNecessaryGetSlot*(vmState: BaseVMState, address: EthAddress, slot: UInt256): Future[void] {.async.} = - if vmState.com.db.localDbOnly: return - await ifNecessaryGetSlots(vmState, address, @[slot]) - -proc ifNecessaryGetBlockHeaderByNumber*(vmState: BaseVMState, blockNumber: BlockNumber): Future[void] {.async.} = - if vmState.com.db.localDbOnly: return - await vmState.asyncFactory.ifNecessaryGetBlockHeaderByNumber(vmState.com.db, blockNumber) - -#[ -FIXME-Adam: This is for later. -proc fetchAndPopulateNodes*(vmState: BaseVMState, paths: seq[seq[seq[byte]]], nodeHashes: seq[Hash256]): Future[void] {.async.} = - if vmState.asyncFactory.maybeDataSource.isSome: - # let stateRoot = vmState.stateDB.rawRootHash # FIXME-Adam: this might not be right, huh? the peer might expect the parent block's final stateRoot, not this weirdo intermediate one - let stateRoot = vmState.parent.stateRoot - let nodes = await vmState.asyncFactory.maybeDataSource.get.fetchNodes(stateRoot, paths, nodeHashes) - populateDbWithNodes(vmState.stateDB.rawDb, nodes) -]# - - -# Sometimes it's convenient to be able to do multiple at once. - -proc ifNecessaryGetAccounts*(vmState: BaseVMState, addresses: seq[EthAddress]): Future[void] {.async.} = - if vmState.com.db.localDbOnly: return - for address in addresses: - await ifNecessaryGetAccount(vmState, address) - -proc ifNecessaryGetCodeForAccounts*(vmState: BaseVMState, addresses: seq[EthAddress]): Future[void] {.async.} = - if vmState.com.db.localDbOnly: return - for address in addresses: - await ifNecessaryGetCode(vmState, address) diff --git a/nimbus/evm/interpreter/op_handlers/oph_blockdata.nim b/nimbus/evm/interpreter/op_handlers/oph_blockdata.nim index a0caffa6eb..29d287ae13 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_blockdata.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_blockdata.nim @@ -12,76 +12,78 @@ ## =============================== ## +{.push raises: [].} + import eth/common, ../../computation, ../../stack, - ../../async/operations, ../utils/utils_numeric, ../op_codes, ./oph_defs -{.push raises: [CatchableError].} # basically the annotation type of a `Vm2OpFn` - when not defined(evmc_enabled): import ../../state +# Annotation helpers +{.pragma: catchRaise, gcsafe, raises: [CatchableError].} + # ------------------------------------------------------------------------------ # Private, op handlers implementation # ------------------------------------------------------------------------------ const - blockhashOp: Vm2OpFn = proc (k: var Vm2Ctx) = + blockhashOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x40, Get the hash of one of the 256 most recent complete blocks. let cpt = k.cpt let (blockNumber) = cpt.stack.popInt(1) - cpt.asyncChainToRaise(ifNecessaryGetBlockHeaderByNumber(cpt.vmState, blockNumber), [CatchableError]): + block: cpt.stack.push: cpt.getBlockHash(blockNumber) - coinBaseOp: Vm2OpFn = proc (k: var Vm2Ctx) = + coinBaseOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x41, Get the block's beneficiary address. k.cpt.stack.push: k.cpt.getCoinbase - timestampOp: Vm2OpFn = proc (k: var Vm2Ctx) = + timestampOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x42, Get the block's timestamp. k.cpt.stack.push: k.cpt.getTimestamp - blocknumberOp: Vm2OpFn = proc (k: var Vm2Ctx) = + blocknumberOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x43, Get the block's number. k.cpt.stack.push: k.cpt.getBlockNumber - difficultyOp: Vm2OpFn = proc (k: var Vm2Ctx) = + difficultyOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x44, Get the block's difficulty k.cpt.stack.push: k.cpt.getDifficulty - gasLimitOp: Vm2OpFn = proc (k: var Vm2Ctx) = + gasLimitOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x45, Get the block's gas limit k.cpt.stack.push: k.cpt.getGasLimit - chainIdOp: Vm2OpFn = proc (k: var Vm2Ctx) = + chainIdOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x46, Get current chain’s EIP-155 unique identifier. k.cpt.stack.push: k.cpt.getChainId - selfBalanceOp: Vm2OpFn = proc (k: var Vm2Ctx) {.gcsafe, raises:[].} = + selfBalanceOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x47, Get current contract's balance. let cpt = k.cpt - cpt.asyncChainToRaise(ifNecessaryGetAccount(cpt.vmState, cpt.msg.contractAddress), [CatchableError]): + block: cpt.stack.push: cpt.getBalance(cpt.msg.contractAddress) - baseFeeOp: Vm2OpFn = proc (k: var Vm2Ctx) = + baseFeeOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x48, Get the block's base fee. k.cpt.stack.push: k.cpt.getBaseFee - blobHashOp: Vm2OpFn = proc (k: var Vm2Ctx) = + blobHashOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x49, Get current transaction's EIP-4844 versioned hash. let index = k.cpt.stack.popInt().safeInt let len = k.cpt.getVersionedHashesLen @@ -93,7 +95,7 @@ const k.cpt.stack.push: 0 - blobBaseFeeOp: Vm2OpFn = proc (k: var Vm2Ctx) = + blobBaseFeeOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x4a, Get the block's base fee. k.cpt.stack.push: k.cpt.getBlobBaseFee diff --git a/nimbus/evm/interpreter/op_handlers/oph_call.nim b/nimbus/evm/interpreter/op_handlers/oph_call.nim index a5ff0fb602..41c69a8af3 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_call.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_call.nim @@ -12,7 +12,7 @@ ## ==================================== ## -{.push raises: [CatchableError].} # basically the annotation type of a `Vm2OpFn` +{.push raises: [].} import ../../../constants, @@ -22,7 +22,6 @@ import ../../memory, ../../stack, ../../types, - ../../async/operations, ../gas_costs, ../gas_meter, ../op_codes, @@ -38,6 +37,9 @@ when not defined(evmc_enabled): ../../state, ../../../db/ledger +# Annotation helpers +{.pragma: catchRaise, gcsafe, raises: [CatchableError].} + # ------------------------------------------------------------------------------ # Private # ------------------------------------------------------------------------------ @@ -59,7 +61,7 @@ type gasCallEIP2929: GasInt -proc updateStackAndParams(q: var LocalParams; c: Computation) = +proc updateStackAndParams(q: var LocalParams; c: Computation) {.catchRaise.} = c.stack.push(0) let @@ -91,7 +93,7 @@ proc updateStackAndParams(q: var LocalParams; c: Computation) = q.gasCallEIP2929 = ColdAccountAccessCost - WarmStorageReadCost -proc callParams(c: Computation): LocalParams = +proc callParams(c: Computation): LocalParams {.catchRaise.} = ## Helper for callOp() result.gas = c.stack.popInt() result.codeAddress = c.stack.popAddress() @@ -108,13 +110,13 @@ proc callParams(c: Computation): LocalParams = result.updateStackAndParams(c) -proc callCodeParams(c: Computation): LocalParams = +proc callCodeParams(c: Computation): LocalParams {.catchRaise.} = ## Helper for callCodeOp() result = c.callParams result.contractAddress = c.msg.contractAddress -proc delegateCallParams(c: Computation): LocalParams = +proc delegateCallParams(c: Computation): LocalParams {.catchRaise.} = ## Helper for delegateCall() result.gas = c.stack.popInt() result.codeAddress = c.stack.popAddress() @@ -131,7 +133,7 @@ proc delegateCallParams(c: Computation): LocalParams = result.updateStackAndParams(c) -proc staticCallParams(c: Computation): LocalParams = +proc staticCallParams(c: Computation): LocalParams {.catchRaise.} = ## Helper for staticCall() result.gas = c.stack.popInt() result.codeAddress = c.stack.popAddress() @@ -166,7 +168,7 @@ when evmc_enabled: c.res.release(c.res) else: - proc execSubCall(c: Computation; childMsg: Message; memPos, memLen: int) {.raises: [].} = + proc execSubCall(c: Computation; childMsg: Message; memPos, memLen: int) = ## Call new VM -- helper for `Call`-like operations # need to provide explicit and for capturing in chainTo proc() @@ -192,7 +194,7 @@ else: # ------------------------------------------------------------------------------ const - callOp: Vm2OpFn = proc(k: var Vm2Ctx) = + callOp: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## 0xf1, Message-Call into an account let cpt = k.cpt @@ -204,8 +206,8 @@ const let p = cpt.callParams - cpt.asyncChainTo(ifNecessaryGetAccounts(cpt.vmState, @[p.sender])): - cpt.asyncChainToRaise(ifNecessaryGetCodeForAccounts(cpt.vmState, @[p.contractAddress, p.codeAddress]), [CatchableError]): + block: + block: var (gasCost, childGasLimit) = cpt.gasCosts[Call].c_handler( p.value, GasParams( @@ -277,14 +279,14 @@ const # --------------------- - callCodeOp: Vm2OpFn = proc(k: var Vm2Ctx) = + callCodeOp: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## 0xf2, Message-call into this account with an alternative account's code. let cpt = k.cpt p = cpt.callCodeParams - cpt.asyncChainTo(ifNecessaryGetAccounts(cpt.vmState, @[p.sender])): - cpt.asyncChainToRaise(ifNecessaryGetCodeForAccounts(cpt.vmState, @[p.contractAddress, p.codeAddress]), [CatchableError]): + block: + block: var (gasCost, childGasLimit) = cpt.gasCosts[CallCode].c_handler( p.value, GasParams( @@ -356,15 +358,15 @@ const # --------------------- - delegateCallOp: Vm2OpFn = proc(k: var Vm2Ctx) = + delegateCallOp: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## 0xf4, Message-call into this account with an alternative account's ## code, but persisting the current values for sender and value. let cpt = k.cpt p = cpt.delegateCallParams - cpt.asyncChainTo(ifNecessaryGetAccounts(cpt.vmState, @[p.sender])): - cpt.asyncChainToRaise(ifNecessaryGetCodeForAccounts(cpt.vmState, @[p.contractAddress, p.codeAddress]), [CatchableError]): + block: + block: var (gasCost, childGasLimit) = cpt.gasCosts[DelegateCall].c_handler( p.value, GasParams( @@ -430,15 +432,15 @@ const # --------------------- - staticCallOp: Vm2OpFn = proc(k: var Vm2Ctx) = + staticCallOp: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## 0xfa, Static message-call into an account. let cpt = k.cpt p = cpt.staticCallParams - cpt.asyncChainTo(ifNecessaryGetAccounts(cpt.vmState, @[p.sender])): - cpt.asyncChainToRaise(ifNecessaryGetCodeForAccounts(cpt.vmState, @[p.contractAddress, p.codeAddress]), [CatchableError]): + block: + block: var (gasCost, childGasLimit) = cpt.gasCosts[StaticCall].c_handler( p.value, GasParams( diff --git a/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim b/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim index adf1e00a13..1f3b5d0185 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_envinfo.nim @@ -12,13 +12,14 @@ ## ============================================== ## +{.push raises: [].} + import ../../../errors, ../../code_stream, ../../computation, ../../memory, ../../stack, - ../../async/operations, ../gas_costs, ../op_codes, ../utils/utils_numeric, @@ -28,37 +29,38 @@ import stint, strformat -{.push raises: [CatchableError].} # basically the annotation type of a `Vm2OpFn` - when not defined(evmc_enabled): import ../../state +# Annotation helpers +{.pragma: catchRaise, gcsafe, raises: [CatchableError].} + # ------------------------------------------------------------------------------ # Private, op handlers implementation # ------------------------------------------------------------------------------ const - addressOp: Vm2OpFn = proc (k: var Vm2Ctx) = + addressOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x30, Get address of currently executing account. k.cpt.stack.push: k.cpt.msg.contractAddress # ------------------ - balanceOp: Vm2OpFn = proc (k: var Vm2Ctx) = + balanceOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x31, Get balance of the given account. let cpt = k.cpt let address = cpt.stack.popAddress - cpt.asyncChainToRaise(ifNecessaryGetAccount(cpt.vmState, address), [CatchableError]): + block: cpt.stack.push: cpt.getBalance(address) - balanceEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) = + balanceEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x31, EIP292: Get balance of the given account for Berlin and later let cpt = k.cpt let address = cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetAccount(cpt.vmState, address), [CatchableError]): + block: let gasCost = cpt.gasEip2929AccountCheck(address) cpt.opcodeGastCost(Balance, gasCost, reason = "Balance EIP2929") cpt.stack.push: @@ -66,23 +68,23 @@ const # ------------------ - originOp: Vm2OpFn = proc (k: var Vm2Ctx) = + originOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x32, Get execution origination address. k.cpt.stack.push: k.cpt.getOrigin() - callerOp: Vm2OpFn = proc (k: var Vm2Ctx) = + callerOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x33, Get caller address. k.cpt.stack.push: k.cpt.msg.sender - callValueOp: Vm2OpFn = proc (k: var Vm2Ctx) = + callValueOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x34, Get deposited value by the instruction/transaction ## responsible for this execution k.cpt.stack.push: k.cpt.msg.value - callDataLoadOp: Vm2OpFn = proc (k: var Vm2Ctx) = + callDataLoadOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x35, Get input data of current environment let (startPos) = k.cpt.stack.popInt(1) let start = startPos.cleanMemRef @@ -102,13 +104,13 @@ const value - callDataSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) = + callDataSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x36, Get size of input data in current environment. k.cpt.stack.push: k.cpt.msg.data.len.u256 - callDataCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) = + callDataCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x37, Copy input data in current environment to memory. let (memStartPos, copyStartPos, size) = k.cpt.stack.popInt(3) @@ -123,18 +125,19 @@ const k.cpt.memory.writePadded(k.cpt.msg.data, memPos, copyPos, len) - codeSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) {.gcsafe, raises:[].} = + codeSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x38, Get size of code running in current environment. let cpt = k.cpt - cpt.asyncChainToRaise(ifNecessaryGetCode(cpt.vmState, cpt.msg.contractAddress), [FullStack]): + block: cpt.stack.push: cpt.code.len - codeCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) {.gcsafe, raises:[].} = + codeCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x39, Copy code running in current environment to memory. let cpt = k.cpt - cpt.asyncChainToRaise(ifNecessaryGetCode(cpt.vmState, cpt.msg.contractAddress), [CatchableError]): + + block: let (memStartPos, copyStartPos, size) = cpt.stack.popInt(3) # TODO tests: https://github.com/status-im/nimbus/issues/67 @@ -147,27 +150,27 @@ const cpt.memory.writePadded(cpt.code.bytes, memPos, copyPos, len) - gasPriceOp: Vm2OpFn = proc (k: var Vm2Ctx) = + gasPriceOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3A, Get price of gas in current environment. k.cpt.stack.push: k.cpt.getGasPrice() # ----------- - extCodeSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) = + extCodeSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3b, Get size of an account's code let cpt = k.cpt let address = k.cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetCode(cpt.vmState, address), [CatchableError]): + block: cpt.stack.push: cpt.getCodeSize(address) - extCodeSizeEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) = + extCodeSizeEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3b, Get size of an account's code let cpt = k.cpt let address = cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetCode(cpt.vmState, address), [CatchableError]): + block: let gasCost = cpt.gasEip2929AccountCheck(address) cpt.opcodeGastCost(ExtCodeSize, gasCost, reason = "ExtCodeSize EIP2929") cpt.stack.push: @@ -175,12 +178,12 @@ const # ----------- - extCodeCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) = + extCodeCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3c, Copy an account's code to memory. let cpt = k.cpt let address = cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetCode(cpt.vmState, address), [CatchableError]): + block: let (memStartPos, codeStartPos, size) = cpt.stack.popInt(3) let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef) @@ -193,12 +196,12 @@ const cpt.memory.writePadded(codeBytes, memPos, codePos, len) - extCodeCopyEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) = + extCodeCopyEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3c, Copy an account's code to memory. let cpt = k.cpt let address = cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetCode(cpt.vmState, address), [CatchableError]): + block: let (memStartPos, codeStartPos, size) = cpt.stack.popInt(3) let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef) @@ -212,14 +215,14 @@ const # ----------- - returnDataSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) = + returnDataSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3d, Get size of output data from the previous call from the ## current environment. k.cpt.stack.push: k.cpt.returnData.len - returnDataCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) = + returnDataCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3e, Copy output data from the previous call to memory. let (memStartPos, copyStartPos, size) = k.cpt.stack.popInt(3) @@ -241,20 +244,20 @@ const # --------------- - extCodeHashOp: Vm2OpFn = proc (k: var Vm2Ctx) = + extCodeHashOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3f, Returns the keccak256 hash of a contract’s code let cpt = k.cpt let address = k.cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetCode(cpt.vmState, address), [CatchableError]): + block: cpt.stack.push: cpt.getCodeHash(address) - extCodeHashEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) = + extCodeHashEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x3f, EIP2929: Returns the keccak256 hash of a contract’s code let cpt = k.cpt let address = k.cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetCode(cpt.vmState, address), [CatchableError]): + block: let gasCost = cpt.gasEip2929AccountCheck(address) cpt.opcodeGastCost(ExtCodeHash, gasCost, reason = "ExtCodeHash EIP2929") diff --git a/nimbus/evm/interpreter/op_handlers/oph_helpers.nim b/nimbus/evm/interpreter/op_handlers/oph_helpers.nim index 4ca2f4d0e7..57ea048f65 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_helpers.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_helpers.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2021-2023 Status Research & Development GmbH +# Copyright (c) 2021-2024 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) @@ -64,7 +64,7 @@ proc gasEip2929AccountCheck*(c: Computation; address: EthAddress, slot: UInt256) else: WarmStorageReadCost -template checkInStaticContext*(c: Computation) = +proc checkInStaticContext*(c: Computation) {.gcsafe, raises: [CatchableError].} = ## Verify static context in handler function, raise an error otherwise if EVMC_STATIC in c.msg.flags: # TODO: if possible, this check only appear diff --git a/nimbus/evm/interpreter/op_handlers/oph_memory.nim b/nimbus/evm/interpreter/op_handlers/oph_memory.nim index ab0fa1a702..9dda1086cb 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_memory.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_memory.nim @@ -12,9 +12,10 @@ ## =============================================================== ## +{.push raises: [].} + import ../../../errors, - ../../async/operations, ../../code_stream, ../../computation, ../../memory, @@ -36,12 +37,15 @@ when not defined(evmc_enabled): ../../state, ../../../db/ledger +# Annotation helpers +{.pragma: catchRaise, gcsafe, raises: [CatchableError].} + # ------------------------------------------------------------------------------ # Private helpers # ------------------------------------------------------------------------------ when evmc_enabled: - proc sstoreEvmc(c: Computation, slot, newValue: UInt256, coldAccess = 0.GasInt) = + proc sstoreEvmc(c: Computation, slot, newValue: UInt256, coldAccess = 0.GasInt) {.catchRaise.} = let status = c.host.setStorage(c.msg.contractAddress, slot, newValue) gasParam = GasParams(kind: Op.Sstore, s_status: status) @@ -50,7 +54,7 @@ when evmc_enabled: c.opcodeGastCost(Sstore, gasCost, "SSTORE") else: - proc sstoreImpl(c: Computation, slot, newValue: UInt256) = + proc sstoreImpl(c: Computation, slot, newValue: UInt256) {.catchRaise.} = let currentValue = c.getStorage(slot) gasParam = GasParams( @@ -68,7 +72,7 @@ else: db.setStorage(c.msg.contractAddress, slot, newValue) - proc sstoreNetGasMeteringImpl(c: Computation; slot, newValue: UInt256, coldAccess = 0.GasInt) = + proc sstoreNetGasMeteringImpl(c: Computation; slot, newValue: UInt256, coldAccess = 0.GasInt) {.catchRaise.} = let stateDB = c.vmState.readOnlyStateDB currentValue = c.getStorage(slot) @@ -100,7 +104,7 @@ template sstoreEvmcOrNetGasMetering(cpt, slot, newValue: untyped, coldAccess = 0 else: sstoreNetGasMeteringImpl(cpt, slot, newValue, coldAccess) -proc jumpImpl(c: Computation; jumpTarget: UInt256) = +proc jumpImpl(c: Computation; jumpTarget: UInt256) {.catchRaise.} = if jumpTarget >= c.code.len.u256: raise newException( InvalidJumpDestination, "Invalid Jump Destination") @@ -122,11 +126,11 @@ proc jumpImpl(c: Computation; jumpTarget: UInt256) = # ------------------------------------------------------------------------------ const - popOp: Vm2OpFn = proc (k: var Vm2Ctx) = + popOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x50, Remove item from stack. discard k.cpt.stack.popInt - mloadOp: Vm2OpFn = proc (k: var Vm2Ctx) = + mloadOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x51, Load word from memory let (memStartPos) = k.cpt.stack.popInt(1) @@ -140,7 +144,7 @@ const k.cpt.memory.read(memPos, 32) - mstoreOp: Vm2OpFn = proc (k: var Vm2Ctx) = + mstoreOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x52, Save word to memory let (memStartPos, value) = k.cpt.stack.popInt(2) @@ -153,7 +157,7 @@ const k.cpt.memory.write(memPos, value.toBytesBE) - mstore8Op: Vm2OpFn = proc (k: var Vm2Ctx) = + mstore8Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x53, Save byte to memory let (memStartPos, value) = k.cpt.stack.popInt(2) @@ -167,20 +171,20 @@ const # ------- - sloadOp: Vm2OpFn = proc (k: var Vm2Ctx) = + sloadOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x54, Load word from storage. let cpt = k.cpt # so it can safely be captured by the asyncChainTo closure below let (slot) = cpt.stack.popInt(1) - cpt.asyncChainToRaise(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot), [CatchableError]): + block: cpt.stack.push: cpt.getStorage(slot) - sloadEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) = + sloadEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x54, EIP2929: Load word from storage for Berlin and later let cpt = k.cpt let (slot) = cpt.stack.popInt(1) - cpt.asyncChainToRaise(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot), [CatchableError]): + block: let gasCost = cpt.gasEip2929AccountCheck(cpt.msg.contractAddress, slot) cpt.opcodeGastCost(Sload, gasCost, reason = "sloadEIP2929") cpt.stack.push: @@ -188,27 +192,27 @@ const # ------- - sstoreOp: Vm2OpFn = proc (k: var Vm2Ctx) = + sstoreOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x55, Save word to storage. let cpt = k.cpt let (slot, newValue) = cpt.stack.popInt(2) checkInStaticContext(cpt) - cpt.asyncChainToRaise(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot), [CatchableError]): + block: sstoreEvmcOrSstore(cpt, slot, newValue) - sstoreEIP1283Op: Vm2OpFn = proc (k: var Vm2Ctx) = + sstoreEIP1283Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x55, EIP1283: sstore for Constantinople and later let cpt = k.cpt let (slot, newValue) = cpt.stack.popInt(2) checkInStaticContext(cpt) - cpt.asyncChainToRaise(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot), [CatchableError]): + block: sstoreEvmcOrNetGasMetering(cpt, slot, newValue) - sstoreEIP2200Op: Vm2OpFn = proc (k: var Vm2Ctx) = + sstoreEIP2200Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x55, EIP2200: sstore for Istanbul and later let cpt = k.cpt let (slot, newValue) = cpt.stack.popInt(2) @@ -221,11 +225,11 @@ const OutOfGas, "Gas not enough to perform EIP2200 SSTORE") - cpt.asyncChainToRaise(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot), [CatchableError]): + block: sstoreEvmcOrNetGasMetering(cpt, slot, newValue) - sstoreEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) = + sstoreEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x55, EIP2929: sstore for Berlin and later let cpt = k.cpt let (slot, newValue) = cpt.stack.popInt(2) @@ -237,7 +241,7 @@ const if cpt.gasMeter.gasRemaining <= SentryGasEIP2200: raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE") - cpt.asyncChainToRaise(ifNecessaryGetSlot(cpt.vmState, cpt.msg.contractAddress, slot), [CatchableError]): + block: var coldAccessGas = 0.GasInt when evmc_enabled: if cpt.host.accessStorage(cpt.msg.contractAddress, slot) == EVMC_ACCESS_COLD: @@ -252,47 +256,47 @@ const # ------- - jumpOp: Vm2OpFn = proc (k: var Vm2Ctx) = + jumpOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x56, Alter the program counter let (jumpTarget) = k.cpt.stack.popInt(1) jumpImpl(k.cpt, jumpTarget) - jumpIOp: Vm2OpFn = proc (k: var Vm2Ctx) = + jumpIOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x57, Conditionally alter the program counter. let (jumpTarget, testedValue) = k.cpt.stack.popInt(2) if testedValue.isZero.not: jumpImpl(k.cpt, jumpTarget) - pcOp: Vm2OpFn = proc (k: var Vm2Ctx) = + pcOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x58, Get the value of the program counter prior to the increment ## corresponding to this instruction. k.cpt.stack.push: max(k.cpt.code.pc - 1, 0) - msizeOp: Vm2OpFn = proc (k: var Vm2Ctx) = + msizeOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x59, Get the size of active memory in bytes. k.cpt.stack.push: k.cpt.memory.len - gasOp: Vm2OpFn = proc (k: var Vm2Ctx) = + gasOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x5a, Get the amount of available gas, including the corresponding ## reduction for the cost of this instruction. k.cpt.stack.push: k.cpt.gasMeter.gasRemaining - jumpDestOp: Vm2OpFn = proc (k: var Vm2Ctx) {.gcsafe, raises:[].} = + jumpDestOp: Vm2OpFn = proc (k: var Vm2Ctx) = ## 0x5b, Mark a valid destination for jumps. This operation has no effect ## on machine state during execution. discard - tloadOp: Vm2OpFn = proc (k: var Vm2Ctx) = + tloadOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x5c, Load word from transient storage. let slot = k.cpt.stack.popInt() val = k.cpt.getTransientStorage(slot) k.cpt.stack.push: val - tstoreOp: Vm2OpFn = proc (k: var Vm2Ctx) = + tstoreOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x5d, Save word to transient storage. checkInStaticContext(k.cpt) @@ -301,7 +305,7 @@ const val = k.cpt.stack.popInt() k.cpt.setTransientStorage(slot, val) - mCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) = + mCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) {.catchRaise.} = ## 0x5e, Copy memory let (dst, src, size) = k.cpt.stack.popInt(3) diff --git a/nimbus/evm/interpreter/op_handlers/oph_sysops.nim b/nimbus/evm/interpreter/op_handlers/oph_sysops.nim index db0ea1ba6d..03a233e270 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_sysops.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_sysops.nim @@ -12,13 +12,14 @@ ## ====================================== ## +{.push raises: [].} + import ../../../errors, ../../computation, ../../memory, ../../stack, ../../types, - ../../async/operations, ../gas_costs, ../op_codes, ../utils/utils_numeric, @@ -27,19 +28,20 @@ import eth/common, stint -{.push raises: [CatchableError].} # basically the annotation type of a `Vm2OpFn` - when not defined(evmc_enabled): import ../../state, ../../../db/ledger +# Annotation helpers +{.pragma: catchRaise, gcsafe, raises: [CatchableError].} + # ------------------------------------------------------------------------------ # Private # ------------------------------------------------------------------------------ const - returnOp: Vm2OpFn = proc(k: var Vm2Ctx) = + returnOp: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## 0xf3, Halt execution returning output data. let (startPos, size) = k.cpt.stack.popInt(2) @@ -51,7 +53,7 @@ const k.cpt.output = k.cpt.memory.read(pos, len) - revertOp: Vm2OpFn = proc(k: var Vm2Ctx) = + revertOp: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## 0xfd, Halt execution reverting state changes but returning data ## and remaining gas. let (startPos, size) = k.cpt.stack.popInt(2) @@ -67,7 +69,7 @@ const k.cpt.setError(EVMC_REVERT, "REVERT opcode executed", false) - invalidOp: Vm2OpFn = proc(k: var Vm2Ctx) = + invalidOp: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = raise newException(InvalidInstruction, "Invalid instruction, received an opcode " & "not implemented in the current fork. " & @@ -75,23 +77,23 @@ const # ----------- - selfDestructOp: Vm2OpFn = proc(k: var Vm2Ctx) = + selfDestructOp: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## 0xff, Halt execution and register account for later deletion. let cpt = k.cpt let beneficiary = cpt.stack.popAddress() when defined(evmc_enabled): - cpt.asyncChainToRaise(ifNecessaryGetAccount(cpt.vmState, beneficiary), [CatchableError]): + block: cpt.selfDestruct(beneficiary) else: - cpt.asyncChainTo(ifNecessaryGetAccount(cpt.vmState, beneficiary)): + block: cpt.selfDestruct(beneficiary) - selfDestructEIP150Op: Vm2OpFn = proc(k: var Vm2Ctx) = + selfDestructEIP150Op: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## selfDestructEip150 (auto generated comment) let cpt = k.cpt let beneficiary = cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetAccount(cpt.vmState, beneficiary), [CatchableError]): + block: let gasParams = GasParams( kind: SelfDestruct, sd_condition: not cpt.accountExists(beneficiary)) @@ -103,13 +105,13 @@ const cpt.selfDestruct(beneficiary) - selfDestructEIP161Op: Vm2OpFn = proc(k: var Vm2Ctx) = + selfDestructEIP161Op: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## selfDestructEip161 (auto generated comment) let cpt = k.cpt checkInStaticContext(cpt) let beneficiary = cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetAccount(cpt.vmState, beneficiary), [CatchableError]): + block: let isDead = not cpt.accountExists(beneficiary) balance = cpt.getBalance(cpt.msg.contractAddress) @@ -125,13 +127,13 @@ const cpt.selfDestruct(beneficiary) - selfDestructEIP2929Op: Vm2OpFn = proc(k: var Vm2Ctx) = + selfDestructEIP2929Op: Vm2OpFn = proc(k: var Vm2Ctx) {.catchRaise.} = ## selfDestructEIP2929 (auto generated comment) let cpt = k.cpt checkInStaticContext(cpt) let beneficiary = cpt.stack.popAddress() - cpt.asyncChainToRaise(ifNecessaryGetAccount(cpt.vmState, beneficiary), [CatchableError]): + block: let isDead = not cpt.accountExists(beneficiary) balance = cpt.getBalance(cpt.msg.contractAddress) diff --git a/nimbus/evm/interpreter_dispatch.nim b/nimbus/evm/interpreter_dispatch.nim index a6e5795a54..ebb0e57389 100644 --- a/nimbus/evm/interpreter_dispatch.nim +++ b/nimbus/evm/interpreter_dispatch.nim @@ -19,7 +19,6 @@ import ".."/[constants, db/ledger], "."/[code_stream, computation], "."/[message, precompiles, state, types], - ./async/operations, ./interpreter/[op_dispatcher, gas_costs] {.push raises: [].} @@ -325,47 +324,6 @@ else: c.dispose() (before, shouldPrepareTracer, c.parent, c) = (false, true, nil.Computation, c.parent) -# FIXME-duplicatedForAsync -# -# In the long run I'd like to make some clever macro/template to -# eliminate the duplication between the synchronous and -# asynchronous versions. But for now let's stick with this for -# simplicity. -# -# Also, I've based this on the recursive one (above), which I think -# is okay because the "async" pragma is going to rewrite this whole -# thing to use callbacks anyway. But maybe I'm wrong? It isn't hard -# to write the async version of the iterative one, but this one is -# a bit shorter and feels cleaner, so if it works just as well I'd -# rather use this one. --Adam -proc asyncExecCallOrCreate*(c: Computation): Future[void] {.async.} = - defer: c.dispose() - - await ifNecessaryGetCode(c.vmState, c.msg.contractAddress) - - if c.beforeExec(): - return - c.executeOpcodes() - while not c.continuation.isNil: - # If there's a continuation, then it's because there's either - # a child (i.e. call or create) or a pendingAsyncOperation. - if not c.pendingAsyncOperation.isNil: - let p = c.pendingAsyncOperation - c.pendingAsyncOperation = nil - await p - c.executeOpcodes(false) - else: - when evmc_enabled: - # FIXME-asyncAndEvmc - # Note that this is NOT async. I'm not sure how/whether I - # can do EVMC asynchronously. - c.res = c.host.call(c.child[]) - else: - await asyncExecCallOrCreate(c.child) - c.child = nil - c.executeOpcodes() - c.afterExec() - # ------------------------------------------------------------------------------ # End # ------------------------------------------------------------------------------ diff --git a/nimbus/evm/state.nim b/nimbus/evm/state.nim index d8189baf72..03dcc60c15 100644 --- a/nimbus/evm/state.nim +++ b/nimbus/evm/state.nim @@ -16,7 +16,6 @@ import ../../stateless/[witness_from_tree, witness_types, multi_keys], ../db/ledger, ../common/[common, evmforks], - ./async/data_sources, ./interpreter/[op_codes, gas_costs], ./types @@ -27,7 +26,6 @@ proc init( blockCtx: BlockContext; com: CommonRef; tracer: TracerRef, - asyncFactory: AsyncOperationFactory = AsyncOperationFactory(maybeDataSource: none[AsyncDataSource]()), flags: set[VMFlag] = self.flags) {.gcsafe.} = ## Initialisation helper @@ -37,7 +35,6 @@ proc init( self.com = com self.tracer = tracer self.stateDB = ac - self.asyncFactory = asyncFactory self.flags = flags func blockCtx(com: CommonRef, header: BlockHeader): @@ -218,23 +215,6 @@ proc init*( tracer = tracer) return true -proc statelessInit*( - vmState: BaseVMState; - parent: BlockHeader; ## parent header, account sync position - header: BlockHeader; ## header with tx environment data fields - com: CommonRef; ## block chain config - asyncFactory: AsyncOperationFactory; - tracer: TracerRef = nil): bool - {.gcsafe, raises: [CatchableError].} = - vmState.init( - ac = com.ledgerType.init(com.db, parent.stateRoot), - parent = parent, - blockCtx = com.blockCtx(header), - com = com, - tracer = tracer, - asyncFactory = asyncFactory) - return true - proc coinbase*(vmState: BaseVMState): EthAddress = vmState.blockCtx.coinbase diff --git a/nimbus/evm/state_transactions.nim b/nimbus/evm/state_transactions.nim index 81b63105c4..f7b3d579a3 100644 --- a/nimbus/evm/state_transactions.nim +++ b/nimbus/evm/state_transactions.nim @@ -9,7 +9,6 @@ # according to those terms. import - chronos, eth/common/eth_types, ../constants, ../db/ledger, @@ -63,9 +62,3 @@ template execSysCall*(c: Computation) = # A syscall to EVM doesn't require # a pre or post ceremony c.execCallOrCreate() - -# FIXME-duplicatedForAsync -proc asyncExecComputation*(c: Computation): Future[void] {.async.} = - c.preExecComputation() - await c.asyncExecCallOrCreate() - c.postExecComputation() diff --git a/nimbus/evm/types.nim b/nimbus/evm/types.nim index 2459f1c479..042ae26f89 100644 --- a/nimbus/evm/types.nim +++ b/nimbus/evm/types.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2018-2023 Status Research & Development GmbH +# Copyright (c) 2018-2024 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) @@ -13,7 +13,6 @@ import json_rpc/rpcclient, "."/[stack, memory, code_stream], ./interpreter/[gas_costs, op_codes], - ./async/data_sources, ../db/ledger, ../common/[common, evmforks] @@ -70,7 +69,6 @@ type receipts* : seq[Receipt] cumulativeGasUsed*: GasInt gasCosts* : GasCosts - asyncFactory* : AsyncOperationFactory Computation* = ref object # The execution computation diff --git a/nimbus/nimbus.nim b/nimbus/nimbus.nim index 9ce969af50..e6e57ca910 100644 --- a/nimbus/nimbus.nim +++ b/nimbus/nimbus.nim @@ -29,9 +29,7 @@ import ./core/clique/clique_sealer, ./sync/protocol, ./sync/handlers, - ./sync/stateless, - ./sync/protocol/les_protocol, - ./evm/async/data_sources/json_rpc_data_source + ./sync/protocol/les_protocol when defined(evmc_enabled): import transaction/evmc_dynamic_loader @@ -165,9 +163,6 @@ proc setupP2P(nimbus: NimbusNode, conf: NimbusConf, # nimbus.snapSyncRef = SnapSyncRef.init( # nimbus.ethNode, nimbus.chainRef, nimbus.ctx.rng, conf.maxPeers, # tickerOK, exCtrlFile) - of SyncMode.Stateless: - # FIXME-Adam: what needs to go here? - nimbus.statelessSyncRef = StatelessSyncRef.init() of SyncMode.Default: if com.forkGTE(MergeFork): nimbus.beaconSyncRef = BeaconSyncRef.init( @@ -194,21 +189,12 @@ proc setupP2P(nimbus: NimbusNode, conf: NimbusConf, case conf.syncMode: #of SyncMode.Snap: # waitForPeers = false - of SyncMode.Stateless: - waitForPeers = false of SyncMode.Full, SyncMode.Default: discard nimbus.networkLoop = nimbus.ethNode.connectToNetwork( enableDiscovery = conf.discovery != DiscoveryType.None, waitForPeers = waitForPeers) -proc maybeStatelessAsyncDataSource*(nimbus: NimbusNode, conf: NimbusConf): Option[AsyncDataSource] = - if conf.syncMode == SyncMode.Stateless: - let rpcClient = waitFor(makeAnRpcClient(conf.statelessModeDataSourceUrl)) - let asyncDataSource = realAsyncDataSource(nimbus.ethNode.peerPool, rpcClient, false) - some(asyncDataSource) - else: - none[AsyncDataSource]() proc localServices(nimbus: NimbusNode, conf: NimbusConf, com: CommonRef, protocols: set[ProtocolFlag]) = @@ -332,8 +318,6 @@ proc start(nimbus: NimbusNode, conf: NimbusConf) = cast[pointer](nimbus.legaSyncRef)) of SyncMode.Full: nimbus.fullSyncRef.start - of SyncMode.Stateless: - nimbus.statelessSyncRef.start #of SyncMode.Snap: # nimbus.snapSyncRef.start diff --git a/nimbus/nimbus_desc.nim b/nimbus/nimbus_desc.nim index cb72861b30..58734af1ef 100644 --- a/nimbus/nimbus_desc.nim +++ b/nimbus/nimbus_desc.nim @@ -19,7 +19,6 @@ import ./sync/beacon, ./sync/legacy, # ./sync/snap, # -- todo - ./sync/stateless, ./sync/full, ./beacon/beacon_engine, ./common, @@ -37,7 +36,6 @@ export beacon, legacy, #snap, - stateless, full, beacon_engine, common, @@ -62,7 +60,6 @@ type # snapSyncRef*: SnapSyncRef # -- todo fullSyncRef*: FullSyncRef beaconSyncRef*: BeaconSyncRef - statelessSyncRef*: StatelessSyncRef beaconEngine*: BeaconEngineRef metricsServer*: MetricsHttpServerRef @@ -80,8 +77,6 @@ proc stop*(nimbus: NimbusNode, conf: NimbusConf) {.async, gcsafe.} = await nimbus.networkLoop.cancelAndWait() if nimbus.peerManager.isNil.not: await nimbus.peerManager.stop() - if nimbus.statelessSyncRef.isNil.not: - nimbus.statelessSyncRef.stop() #if nimbus.snapSyncRef.isNil.not: # nimbus.snapSyncRef.stop() if nimbus.fullSyncRef.isNil.not: diff --git a/nimbus/stateless_runner.nim b/nimbus/stateless_runner.nim deleted file mode 100644 index 0655a24449..0000000000 --- a/nimbus/stateless_runner.nim +++ /dev/null @@ -1,139 +0,0 @@ -# Nimbus -# Copyright (c) 2023-2024 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. - -import - std/[options, times], - chronicles, - chronos, - nimcrypto, - stew/results, - json_rpc/rpcclient, - eth/[common/eth_types, p2p], - ./core/chain/chain_desc, - ./core/executor/process_block, - ./db/[core_db, ledger], - ./evm/async/[data_sources, operations, data_sources/json_rpc_data_source], - "."/[vm_state, vm_types] - -from strutils import parseInt, startsWith -from common/common import initializeEmptyDb - -proc coinbasesOfThisBlockAndUncles(header: BlockHeader, body: BlockBody): seq[EthAddress] = - result.add header.coinbase - for uncle in body.uncles: - result.add(uncle.coinbase) - -proc createVmStateForStatelessMode*(com: CommonRef, header: BlockHeader, body: BlockBody, - parentHeader: BlockHeader, asyncFactory: AsyncOperationFactory): Result[BaseVMState, string] - {.inline.} = - let vmState = BaseVMState() - if not vmState.statelessInit(parentHeader, header, com, asyncFactory): - return err("Cannot initialise VmState for block number " & $(header.blockNumber)) - waitFor(ifNecessaryGetAccounts(vmState, coinbasesOfThisBlockAndUncles(header, body))) - ok(vmState) - - - -proc statelesslyRunBlock*(asyncDataSource: AsyncDataSource, com: CommonRef, header: BlockHeader, body: BlockBody): Result[Hash256, string] = - try: - let t0 = now() - - # FIXME-Adam: this doesn't feel like the right place for this; where should it go? - com.db.compensateLegacySetup() - - let blockHash: Hash256 = header.blockHash - - let asyncFactory = AsyncOperationFactory(maybeDataSource: some(asyncDataSource)) - - let parentHeader = waitFor(asyncDataSource.fetchBlockHeaderWithHash(header.parentHash)) - com.db.persistHeaderToDbWithoutSetHeadOrScore(parentHeader) - - info("statelessly running block", blockNumber=header.blockNumber, blockHash=blockHash, parentHash=header.parentHash, parentStateRoot=parentHeader.stateRoot, desiredNewStateRoot=header.stateRoot) - - let vmState = createVmStateForStatelessMode(com, header, body, parentHeader, asyncFactory).get - let vres = processBlock(vmState, header, body) - - let elapsedTime = now() - t0 - - let headerStateRoot = header.stateRoot - let vmStateRoot = rootHash(vmState.stateDB) - info("finished statelessly running the block", vres=vres, elapsedTime=elapsedTime, durationSpentDoingFetches=durationSpentDoingFetches, fetchCounter=fetchCounter, headerStateRoot=headerStateRoot, vmStateRoot=vmStateRoot) - if headerStateRoot != vmStateRoot: - return err("State roots do not match: header says " & $(headerStateRoot) & ", vmState says " & $(vmStateRoot)) - else: - if vres == ValidationResult.OK: - return ok(blockHash) - else: - return err("Error while statelessly running a block") - except: - let ex = getCurrentException() - echo getStackTrace(ex) - error "Got an exception while statelessly running a block", exMsg = ex.msg - return err("Error while statelessly running a block: " & $(ex.msg)) - -proc statelesslyRunBlock*(asyncDataSource: AsyncDataSource, com: CommonRef, blockHash: Hash256): Result[Hash256, string] = - let (header, body) = waitFor(asyncDataSource.fetchBlockHeaderAndBodyWithHash(blockHash)) - let r = statelesslyRunBlock(asyncDataSource, com, header, body) - if r.isErr: - error("stateless execution failed", hash=blockHash, error=r.error) - else: - info("stateless execution succeeded", hash=blockHash, resultingHash=r.value) - return r - -proc fetchBlockHeaderAndBodyForHashOrNumber(asyncDataSource: AsyncDataSource, hashOrNum: string): Future[(BlockHeader, BlockBody)] {.async.} = - if hashOrNum.startsWith("0x"): - return await asyncDataSource.fetchBlockHeaderAndBodyWithHash(hashOrNum.toHash) - else: - return await asyncDataSource.fetchBlockHeaderAndBodyWithNumber(u256(parseInt(hashOrNum))) - -proc statelesslyRunSequentialBlocks*(asyncDataSource: AsyncDataSource, com: CommonRef, initialBlockNumber: BlockNumber): Result[Hash256, string] = - info("sequential stateless execution beginning", initialBlockNumber=initialBlockNumber) - var n = initialBlockNumber - while true: - let (header, body) = waitFor(asyncDataSource.fetchBlockHeaderAndBodyWithNumber(n)) - let r = statelesslyRunBlock(asyncDataSource, com, header, body) - if r.isErr: - error("stateless execution failed", n=n, h=header.blockHash, error=r.error) - return r - else: - info("stateless execution succeeded", n=n, h=header.blockHash, resultingHash=r.value) - n = n + 1 - -proc statelesslyRunBlock*(asyncDataSource: AsyncDataSource, com: CommonRef, hashOrNum: string): Result[Hash256, string] = - let (header, body) = waitFor(fetchBlockHeaderAndBodyForHashOrNumber(asyncDataSource, hashOrNum)) - return statelesslyRunBlock(asyncDataSource, com, header, body) - - -proc statelesslyRunTransaction*(asyncDataSource: AsyncDataSource, com: CommonRef, headerHash: Hash256, tx: Transaction) = - let t0 = now() - - let (header, body) = waitFor(asyncDataSource.fetchBlockHeaderAndBodyWithHash(headerHash)) - - # FIXME-Adam: this doesn't feel like the right place for this; where should it go? - com.db.compensateLegacySetup() - - #let blockHash: Hash256 = header.blockHash - - let transaction = com.db.beginTransaction() - defer: transaction.rollback() # intentionally throwing away the result of this execution - - let asyncFactory = AsyncOperationFactory(maybeDataSource: some(asyncDataSource)) - let parentHeader = waitFor(asyncDataSource.fetchBlockHeaderWithHash(header.parentHash)) - com.db.persistHeaderToDbWithoutSetHeadOrScore(parentHeader) - - let vmState = createVmStateForStatelessMode(com, header, body, parentHeader, asyncFactory).get - - let r = processTransactions(vmState, header, @[tx]) - if r.isErr: - error("error statelessly running tx", tx=tx, error=r.error) - else: - let elapsedTime = now() - t0 - let gasUsed = vmState.cumulativeGasUsed - info("finished statelessly running the tx", elapsedTime=elapsedTime, gasUsed=gasUsed) diff --git a/nimbus/sync/stateless.nim b/nimbus/sync/stateless.nim deleted file mode 100644 index 58b909ef05..0000000000 --- a/nimbus/sync/stateless.nim +++ /dev/null @@ -1,40 +0,0 @@ -# Nimbus -# Copyright (c) 2023 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. - -{.push raises: [].} - -import - eth/[p2p], - chronicles, - stew/[interval_set], - "."/[sync_desc] - -logScope: - topics = "stateless-sync" - -type - StatelessSyncRef* = ref object - # FIXME-Adam: what needs to go in here? - - -# ------------------------------------------------------------------------------ -# Public functions -# ------------------------------------------------------------------------------ - -proc init*(T: type StatelessSyncRef): T = - new result - - -proc start*(ctx: StatelessSyncRef) = - # FIXME-Adam: What do I need here, if anything? - discard - -proc stop*(ctx: StatelessSyncRef) = - discard diff --git a/nimbus/transaction/call_common.nim b/nimbus/transaction/call_common.nim index 46b5569c77..74fd169bfa 100644 --- a/nimbus/transaction/call_common.nim +++ b/nimbus/transaction/call_common.nim @@ -14,7 +14,6 @@ import ".."/[vm_types, vm_state, vm_computation, vm_state_transactions], ".."/[vm_internals, vm_precompiles, vm_gas_costs], ".."/[db/ledger], - ../evm/async/operations, ../common/evmforks, ../core/eip4844, ./host_types @@ -306,20 +305,3 @@ proc runComputation*(call: CallParams): CallResult execComputation(host.computation) finishRunningComputation(host, call) - -# FIXME-duplicatedForAsync -proc asyncRunComputation*(call: CallParams): Future[CallResult] {.async.} = - # This has to come before the newComputation call inside setupHost. - if not call.isCreate: - await ifNecessaryGetCodeForAccounts(call.vmState, @[call.to.toEvmc.fromEvmc]) - - let host = setupHost(call) - prepareToRunComputation(host, call) - - # FIXME-asyncAndEvmc: I'm not sure what to do with EVMC at the moment. - # when defined(evmc_enabled): - # doExecEvmc(host, call) - # else: - await asyncExecComputation(host.computation) - - return finishRunningComputation(host, call) diff --git a/nimbus/transaction/call_evm.nim b/nimbus/transaction/call_evm.nim index 7a6fe9cdbd..07d4d384e4 100644 --- a/nimbus/transaction/call_evm.nim +++ b/nimbus/transaction/call_evm.nim @@ -197,8 +197,3 @@ proc testCallEvm*(tx: Transaction, sender: EthAddress, vmState: BaseVMState, for {.gcsafe, raises: [CatchableError].} = let call = callParamsForTest(tx, sender, vmState, fork) runComputation(call) - -# FIXME-duplicatedForAsync -proc asyncTestCallEvm*(tx: Transaction, sender: EthAddress, vmState: BaseVMState, fork: EVMFork): Future[CallResult] {.async.} = - let call = callParamsForTest(tx, sender, vmState, fork) - return await asyncRunComputation(call) diff --git a/nimbus/vm_state.nim b/nimbus/vm_state.nim index 37c2a4e8ab..caf6a7ece3 100644 --- a/nimbus/vm_state.nim +++ b/nimbus/vm_state.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2018 Status Research & Development GmbH +# Copyright (c) 2021-2024 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) @@ -28,7 +28,6 @@ export vms.getAncestorHash, vms.getAndClearLogEntries, vms.init, - vms.statelessInit, vms.mutateStateDB, vms.new, vms.reinit, diff --git a/nimbus/vm_state_transactions.nim b/nimbus/vm_state_transactions.nim index 24ff655f1a..485c0a4feb 100644 --- a/nimbus/vm_state_transactions.nim +++ b/nimbus/vm_state_transactions.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2018 Status Research & Development GmbH +# Copyright (c) 2021-2024 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) @@ -12,7 +12,6 @@ import evm/state_transactions as vmx export - vmx.asyncExecComputation, vmx.execComputation, vmx.execSysCall