diff --git a/hive_integration/README.md b/hive_integration/README.md index 278b1f10f..756315a51 100644 --- a/hive_integration/README.md +++ b/hive_integration/README.md @@ -4,7 +4,7 @@ This is a short manual to help you quickly setup and run Hive. For more detailed information please read the [hive documentation](https://github.com/ethereum/hive/blob/master/docs/overview.md). -## Prerequisities +## Prerequisites - A Linux machine. Trust me, it does not work on Windows or MacOS. - Or Linux inside a VM (e.g. VirtualBox) on Windows or MacOS. diff --git a/nimbus/config.nim b/nimbus/config.nim index eba30a5f7..9b181577d 100644 --- a/nimbus/config.nim +++ b/nimbus/config.nim @@ -495,13 +495,12 @@ type name: "engine-api-ws" .}: bool allowedOrigins* {. - desc: "Comma separated list of domains from which to accept cross origin requests" + desc: "Comma-separated list of domains from which to accept cross origin requests" defaultValue: @[] defaultValueDesc: "*" name: "allowed-origins" .}: seq[string] - # github.com/ethereum/execution-apis/ - # /blob/v1.0.0-alpha.8/src/engine/authentication.md#key-distribution + # https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.4/src/engine/authentication.md#key-distribution jwtSecret* {. desc: "Path to a file containing a 32 byte hex-encoded shared secret" & " needed for websocket authentication. By default, the secret key" & diff --git a/nimbus/db/aristo/README.md b/nimbus/db/aristo/README.md index ba38dcbe7..22173d3e6 100644 --- a/nimbus/db/aristo/README.md +++ b/nimbus/db/aristo/README.md @@ -433,7 +433,7 @@ database, the above architecture mutates to When looked at descriptor API there are no changes when accessing data via *db1*, *db2*, or *db3*. In a different, more algebraic notation, the above -tansformation is written as +transformation is written as | tx1, ø | (8) | tx2, ø | PBE diff --git a/nimbus/sync/protocol.nim b/nimbus/sync/protocol.nim index bfc4df520..7510140e8 100644 --- a/nimbus/sync/protocol.nim +++ b/nimbus/sync/protocol.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2021-2024 Status Research & Development GmbH +# Copyright (c) 2021-2025 Status Research & Development GmbH # Licensed and distributed under either of # * MIT license (license terms in the root directory or at # https://opensource.org/licenses/MIT). @@ -11,43 +11,20 @@ ## Provision of `eth` and `snap` protocol version parameters ## ## `Eth` related parameters: -## `ethVersions`: seq[int] -- constant list of all available versions ## `eth` -- type symbol of default version ## `proto_eth` -- export of default version directives ## -## `Snap` related parameters: -## `snap` -- type symbol of default version -## `proto_snap` -- export of default version directives -## ..aliases.. -- type names, syntactic sugar (see below) -## + +{.push raises: [].} import ./protocol/eth68 as proto_eth type eth* = eth68 -# --------------- - import ./protocol/snap1 as proto_snap export proto_eth, proto_snap - -type - snap* = snap1 - - SnapAccountRange* = accountRangeObj - ## Syntactic sugar, type defined in `snap1` - - SnapStorageRanges* = storageRangesObj - ## Ditto - - SnapByteCodes* = byteCodesObj - ## Ditto - - SnapTrieNodes* = trieNodesObj - ## Ditto - -# End diff --git a/nimbus/sync/protocol/snap/snap_types.nim b/nimbus/sync/protocol/snap/snap_types.nim deleted file mode 100644 index 480d787c6..000000000 --- a/nimbus/sync/protocol/snap/snap_types.nim +++ /dev/null @@ -1,225 +0,0 @@ -# Nimbus -# 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) -# * 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 - std/[hashes, sequtils], - results, - chronicles, - eth/common, - ../../../constants - -logScope: - topics = "snap-wire" - -type - SnapAccount* = object - accHash*: Hash32 - accBody* {.rlpCustomSerialization.}: Account - - SnapProof* = distinct seq[byte] - ## Rlp coded node data, to be handled different from a generic `Blob` - - SnapProofNodes* = object - ## Wrapper around `seq[SnapProof]` for controlling serialisation. - nodes*: seq[SnapProof] - - SnapStorage* = object - slotHash*: Hash32 - slotData*: seq[byte] - - SnapTriePaths* = object - accPath*: seq[byte] - slotPaths*: seq[seq[byte]] - - SnapWireBase* = ref object of RootRef - - SnapPeerState* = ref object of RootRef - -# ------------------------------------------------------------------------------ -# Public `SnapProof` type helpers -# ------------------------------------------------------------------------------ - -proc to*(data: seq[byte]; T: type SnapProof): T = data.T -proc to*(node: SnapProof; T: type seq[byte]): T = node.T - -proc hash*(sp: SnapProof): Hash = - ## Mixin for Table/HashSet - sp.to(seq[byte]).hash - -proc `==`*(a,b: SnapProof): bool = - ## Mixin for Table/HashSet - a.to(seq[byte]) == b.to(seq[byte]) - -# ------------------------------------------------------------------------------ -# Public serialisation helpers -# ------------------------------------------------------------------------------ - -# The `snap` protocol represents `Account` differently from the regular RLP -# serialisation used in `eth` protocol as well as the canonical Merkle hash -# over all accounts. In `snap`, empty storage hash and empty code hash are -# each represented by an RLP zero-length string instead of the full hash. This -# avoids transmitting these hashes in about 90% of accounts. We need to -# recognise or set these hashes in `Account` when serialising RLP for `snap`. - -proc snapRead*( - rlp: var Rlp; - T: type Account; - strict: static[bool] = false; - ): T - {.gcsafe, raises: [RlpError]} = - ## RLP decoding for `Account`. The `snap` RLP representation of the account - ## differs from standard `Account` RLP. Empty storage hash and empty code - ## hash are each represented by an RLP zero-length string instead of the - ## full hash. - ## - ## Normally, this read function will silently handle standard encodinig and - ## `snap` enciding. Setting the argument strict as `false` the function will - ## throw an exception if `snap` encoding is violated. - rlp.tryEnterList() - result.nonce = rlp.read(typeof(result.nonce)) - result.balance = rlp.read(typeof(result.balance)) - if rlp.blobLen != 0 or not rlp.isBlob: - result.storageRoot = rlp.read(typeof(result.storageRoot)) - when strict: - if result.storageRoot == EMPTY_ROOT_HASH: - raise newException(RlpTypeMismatch, - "EMPTY_ROOT_HASH not encoded as empty string in Snap protocol") - else: - rlp.skipElem() - result.storageRoot = EMPTY_ROOT_HASH - if rlp.blobLen != 0 or not rlp.isBlob: - result.codeHash = rlp.read(typeof(result.codeHash)) - when strict: - if result.codeHash == EMPTY_CODE_HASH: - raise newException(RlpTypeMismatch, - "EMPTY_SHA3 not encoded as empty string in Snap protocol") - else: - rlp.skipElem() - result.codeHash = EMPTY_CODE_HASH - -proc snapAppend*( - writer: var RlpWriter; - account: Account; - ) = - ## RLP encoding for `Account`. The snap RLP representation of the account - ## differs from standard `Account` RLP. Empty storage hash and empty code - ## hash are each represented by an RLP zero-length string instead of the - ## full hash. - writer.startList(4) - writer.append(account.nonce) - writer.append(account.balance) - if account.storageRoot == EMPTY_ROOT_HASH: - writer.append("") - else: - writer.append(account.storageRoot) - if account.codeHash == EMPTY_CODE_HASH: - writer.append("") - else: - writer.append(account.codeHash) - -# --------------------- - -proc snapRead*( - rlp: var Rlp; - T: type SnapProofNodes; - ): T - {.gcsafe, raises: [RlpError].} = - ## RLP decoding for a wrapped `SnapProof` sequence. This extra wrapper is - ## needed as the `SnapProof` items are `Blob` items at heart which is also - ## the serialised destination data type. - if rlp.isList: - for w in rlp.items: - result.nodes.add w.rawData.toSeq.to(SnapProof) - elif rlp.isBlob: - result.nodes.add rlp.rawData.toSeq.to(SnapProof) - -proc snapAppend*(writer: var RlpWriter; spn: SnapProofNodes) = - ## RLP encoding for a wrapped `SnapProof` sequence. This extra wrapper is - ## needed as the `SnapProof` items are `Blob` items at heart which is also - ## the serialised destination data type. - writer.startList spn.nodes.len - for w in spn.nodes: - writer.appendRawBytes w.to(seq[byte]) - -# --------------------- - -proc snapRead*( - rlp: var Rlp; - T: type SnapTriePaths; - ): T - {.gcsafe, raises: [RlpError].} = - ## RLP decoding - if not rlp.isList: - raise newException(RlpTypeMismatch, "List expected") - var first = true - for w in rlp.items: - if first: - result.accPath = rlp.read(seq[byte]) - first = false - else: - result.slotPaths.add rlp.read(seq[byte]) - -proc snapAppend*(writer: var RlpWriter; stn: SnapTriePaths) = - ## RLP encoding - writer.startList(1 + stn.slotPaths.len) - writer.append(stn.accPath) - for w in stn.slotPaths: - writer.append(w) - -# ------------------------------------------------------------------------------ -# Public service stubs -# ------------------------------------------------------------------------------ - -proc notImplemented(name: string) = - debug "Method not implemented", meth = name - -method getAccountRange*( - ctx: SnapWireBase; - root: Hash32; - origin: openArray[byte]; - limit: openArray[byte]; - replySizeMax: uint64; - ): Result[(seq[SnapAccount], SnapProofNodes), string] - {.base, gcsafe.} = - notImplemented("getAccountRange") - -method getStorageRanges*( - ctx: SnapWireBase; - root: Hash32; - accounts: openArray[Hash32]; - origin: openArray[byte]; - limit: openArray[byte]; - replySizeMax: uint64; - ): Result[(seq[seq[SnapStorage]], SnapProofNodes), string] - {.base, gcsafe.} = - notImplemented("getStorageRanges") - -method getByteCodes*( - ctx: SnapWireBase; - nodes: openArray[Hash32]; - replySizeMax: uint64; - ): Result[seq[seq[byte]], string] - {.base, gcsafe.} = - notImplemented("getByteCodes") - -method getTrieNodes*( - ctx: SnapWireBase; - root: Hash32; - pathGroups: openArray[SnapTriePaths]; - replySizeMax: uint64; - ): Result[seq[seq[byte]], string] - {.base, gcsafe.} = - notImplemented("getTrieNodes") - -# ------------------------------------------------------------------------------ -# End -# ------------------------------------------------------------------------------ diff --git a/nimbus/sync/protocol/snap1.nim b/nimbus/sync/protocol/snap1.nim index 9d5925910..817e694c8 100644 --- a/nimbus/sync/protocol/snap1.nim +++ b/nimbus/sync/protocol/snap1.nim @@ -1,6 +1,4 @@ -# Nimbus - Ethereum Snap Protocol (SNAP), version 1 -# -# Copyright (c) 2021-2024 Status Research & Development GmbH +# Copyright (c) 2021-2025 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) @@ -9,223 +7,39 @@ # at your option. This file may not be copied, modified, or distributed # except according to those terms. -## This module implements Ethereum Snapshot Protocol version 1, `snap/1`. -## Specification: -## `snap/1 `_ +{.push raises: [].} -import - std/options, - chronicles, - chronos, - eth/[common, p2p, p2p/private/p2p_types], - ./snap/snap_types, - ../../constants +from eth/common import Account, Hash32 -export - snap_types +type + SnapAccount = object + accHash: Hash32 + accBody: Account -logScope: - topics = "snap1" + SnapProof* = distinct seq[byte] + ## RLP-coded node data, to be handled differently from a generic `Blob` -const - snapVersion* = 1 - prettySnapProtoName* = "[snap/" & $snapVersion & "]" + SnapProofNodes = object + ## Wrapper around `seq[SnapProof]` for controlling serialisation. + nodes: seq[SnapProof] - # Pickeled tracer texts - trSnapRecvReceived* = - "<< " & prettySnapProtoName & " Received " - trSnapRecvProtocolViolation* = - "<< " & prettySnapProtoName & " Protocol violation, " - trSnapRecvError* = - "<< " & prettySnapProtoName & " Error " - trSnapRecvTimeoutWaiting* = - "<< " & prettySnapProtoName & " Timeout waiting " + SnapStorage* = object + slotHash*: Hash32 + slotData*: seq[byte] - trSnapSendSending* = - ">> " & prettySnapProtoName & " Sending " - trSnapSendReplying* = - ">> " & prettySnapProtoName & " Replying " + SnapAccountRange* = object + accounts: seq[SnapAccount] + proof: SnapProofNodes + SnapStorageRanges* = object + slotLists: seq[seq[SnapStorage]] + proof: SnapProofNodes -proc read(rlp: var Rlp, t: var SnapAccount, T: type Account): T = - ## RLP mixin, decoding - rlp.snapRead T + SnapByteCodes* = object + codes: seq[seq[byte]] -proc read(rlp: var Rlp; T: type SnapProofNodes): T = - ## RLP mixin, decoding - rlp.snapRead T + SnapTrieNodes* = object + nodes: seq[seq[byte]] -proc read(rlp: var Rlp; T: type SnapTriePaths): T = - ## RLP mixin, decoding - rlp.snapRead T - -proc append(writer: var RlpWriter, t: SnapAccount, account: Account) = - ## RLP mixin, encoding - writer.snapAppend account - -proc append(writer: var RlpWriter; spn: SnapProofNodes) = - ## RLP mixin, encoding - writer.snapAppend spn - -proc append(writer: var RlpWriter; stn: SnapTriePaths) = - ## RLP mixin, encoding - writer.snapAppend stn - -template handleHandlerError(x: untyped) = - if x.isErr: - raise newException(EthP2PError, x.error) - -p2pProtocol snap1(version = snapVersion, - rlpxName = "snap", - peerState = SnapPeerState, - networkState = SnapWireBase, - useRequestIds = true): - - requestResponse: - # User message 0x00: GetAccountRange. - proc getAccountRange( - peer: Peer; - root: Hash32; - origin: openArray[byte]; - limit: openArray[byte]; - replySizeMax: uint64; - ) = - trace trSnapRecvReceived & "GetAccountRange (0x00)", peer, root, - nOrigin=origin.len, nLimit=limit.len, replySizeMax - - let - ctx = peer.networkState() - res = ctx.getAccountRange( - root, origin, limit, replySizeMax) - handleHandlerError(res) - - let - (accounts, proof) = res.get - # For logging only - nAccounts = accounts.len - nProof = proof.nodes.len - - if nAccounts == 0 and nProof == 0: - trace trSnapSendReplying & "EMPTY AccountRange (0x01)", peer - else: - trace trSnapSendReplying & "AccountRange (0x01)", peer, - nAccounts, nProof - - await response.send(accounts, proof) - - # User message 0x01: AccountRange. - proc accountRange( - peer: Peer; - accounts: openArray[SnapAccount]; - proof: SnapProofNodes) - - - requestResponse: - # User message 0x02: GetStorageRanges. - proc getStorageRanges( - peer: Peer; - root: Hash32; - accounts: openArray[Hash32]; - origin: openArray[byte]; - limit: openArray[byte]; - replySizeMax: uint64; - ) = - trace trSnapRecvReceived & "GetStorageRanges (0x02)", peer, root, - nAccounts=accounts.len, nOrigin=origin.len, nLimit=limit.len, - replySizeMax - - let - ctx = peer.networkState() - res = ctx.getStorageRanges( - root, accounts, origin, limit, replySizeMax) - handleHandlerError(res) - - let - (slots, proof) = res.get - # For logging only - nSlots = slots.len - nProof = proof.nodes.len - - if nSlots == 0 and nProof == 0: - trace trSnapSendReplying & "EMPTY StorageRanges (0x03)", peer - else: - trace trSnapSendReplying & "StorageRanges (0x03)", peer, - nSlots, nProof - - await response.send(slots, proof) - - # User message 0x03: StorageRanges. - # Note: See comments in this file for a list of Geth quirks to expect. - proc storageRanges( - peer: Peer; - slotLists: openArray[seq[SnapStorage]]; - proof: SnapProofNodes) - - - requestResponse: - # User message 0x04: GetByteCodes. - proc getByteCodes( - peer: Peer; - nodes: openArray[Hash32]; - replySizeMax: uint64; - ) = - trace trSnapRecvReceived & "GetByteCodes (0x04)", peer, - nNodes=nodes.len, replySizeMax - - let - ctx = peer.networkState() - codes = ctx.getByteCodes(nodes, replySizeMax) - - handleHandlerError(codes) - - let - # For logging only - nCodes = codes.get.len - - if nCodes == 0: - trace trSnapSendReplying & "EMPTY ByteCodes (0x05)", peer - else: - trace trSnapSendReplying & "ByteCodes (0x05)", peer, nCodes - - await response.send(codes.get) - - # User message 0x05: ByteCodes. - proc byteCodes( - peer: Peer; - codes: openArray[seq[byte]]) - - - requestResponse: - # User message 0x06: GetTrieNodes. - proc getTrieNodes( - peer: Peer; - root: Hash32; - pathGroups: openArray[SnapTriePaths]; - replySizeMax: uint64; - ) = - trace trSnapRecvReceived & "GetTrieNodes (0x06)", peer, root, - nPathGroups=pathGroups.len, replySizeMax - - let - ctx = peer.networkState() - nodes = ctx.getTrieNodes(root, pathGroups, replySizeMax) - - handleHandlerError(nodes) - - let - # For logging only - nNodes = nodes.get.len - - if nNodes == 0: - trace trSnapSendReplying & "EMPTY TrieNodes (0x07)", peer - else: - trace trSnapSendReplying & "TrieNodes (0x07)", peer, nNodes - - await response.send(nodes.get) - - # User message 0x07: TrieNodes. - proc trieNodes( - peer: Peer; - nodes: openArray[seq[byte]]) - -# End +func to*(data: seq[byte]; T: type SnapProof): T = data.T +func to*(node: SnapProof; T: type seq[byte]): T = node.T