From 6fb48517bae673481d58a545284b0288844c2a66 Mon Sep 17 00:00:00 2001 From: Jordan Hrycaj Date: Fri, 20 Jan 2023 15:01:29 +0000 Subject: [PATCH] Add snap protocol service stub (#1438) * Cosmetics, update logger `topics` * Clean up sync/start methods in nimbus why: * The `protocols` list selects served (as opposed to sync) protocols only. * The `SyncMode.Default` object is allocated with the other possible sync mode objects. * Add snap service stub to `nimbus` * Provide full set of snap response handler stubs * Bicarb for the latest CI hiccup why: Might be a change in the CI engine for MacOS. --- .github/workflows/ci.yml | 7 + nimbus/config.nim | 12 +- nimbus/nimbus.nim | 60 ++++--- nimbus/sync/handlers/eth.nim | 25 ++- nimbus/sync/handlers/setup.nim | 29 +++- nimbus/sync/handlers/snap.nim | 120 ++++++++++++++ nimbus/sync/legacy.nim | 2 +- nimbus/sync/protocol/eth/eth_types.nim | 2 +- nimbus/sync/protocol/eth66.nim | 2 +- nimbus/sync/protocol/eth67.nim | 2 +- nimbus/sync/protocol/snap/snap_types.nim | 74 +++++++++ nimbus/sync/protocol/snap1.nim | 200 +++++++++++++---------- nimbus/sync/snap.nim | 2 +- 13 files changed, 406 insertions(+), 131 deletions(-) create mode 100644 nimbus/sync/handlers/snap.nim create mode 100644 nimbus/sync/protocol/snap/snap_types.nim diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ff4bfc13..3cd3d933c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,6 +129,13 @@ jobs: chmod 755 external/bin/gcc external/bin/g++ echo '${{ github.workspace }}/external/bin' >> $GITHUB_PATH + - name: Install build dependencies (Macos) + # Some home brew modules were reported missing + if: runner.os == 'Macos' + run: | + HOMEBREW_NO_INSTALL_CLEANUP=1 brew install gnu-getopt + brew link --force gnu-getopt + - name: Restore rocksdb from cache (Macos/Linux) if: runner.os != 'Windows' id: rocksdb-cache diff --git a/nimbus/config.nim b/nimbus/config.nim index 9366369bb..bb5c12723 100644 --- a/nimbus/config.nim +++ b/nimbus/config.nim @@ -120,6 +120,7 @@ type ProtocolFlag* {.pure.} = enum ## Protocol flags Eth ## enable eth subprotocol + Snap ## enable snap sub-protocol Les ## enable les subprotocol RpcFlag* {.pure.} = enum @@ -169,7 +170,7 @@ type "- default -- legacy sync mode\n" & "- full -- full blockchain archive\n" & "- snap -- experimental snap mode (development only)\n" & - "- snapCtx -- snap considering possible recovery context\n" + "- snapCtx -- snap considering possible recovery context" defaultValue: SyncMode.Default defaultValueDesc: $SyncMode.Default abbr: "y" @@ -347,7 +348,8 @@ type name: "agent-string" .}: string protocols {. - desc: "Enable specific set of protocols (available: Eth, Les)" + desc: "Enable specific set of server protocols (available: Eth, " & + " Snap, Les, None.) This will not affect the sync mode" defaultValue: @[] defaultValueDesc: $ProtocolFlag.Eth name: "protocols" .}: seq[string] @@ -622,13 +624,19 @@ proc getProtocolFlags*(conf: NimbusConf): set[ProtocolFlag] = if conf.protocols.len == 0: return {ProtocolFlag.Eth} + var noneOk = false for item in repeatingList(conf.protocols): case item.toLowerAscii() of "eth": result.incl ProtocolFlag.Eth of "les": result.incl ProtocolFlag.Les + of "snap": result.incl ProtocolFlag.Snap + of "none": noneOk = true else: error "Unknown protocol", name=item quit QuitFailure + if noneOk and 0 < result.len: + error "Setting none contradicts wire protocols", names=result + quit QuitFailure proc getRpcFlags(api: openArray[string]): set[RpcFlag] = if api.len == 0: diff --git a/nimbus/nimbus.nim b/nimbus/nimbus.nim index 8a6931266..7e95ac0cd 100644 --- a/nimbus/nimbus.nim +++ b/nimbus/nimbus.nim @@ -57,6 +57,7 @@ type networkLoop: Future[void] dbBackend: ChainDB peerManager: PeerManagerRef + legaSyncRef: LegacySyncRef snapSyncRef: SnapSyncRef fullSyncRef: FullSyncRef merger: MergerRef @@ -145,38 +146,45 @@ proc setupP2P(nimbus: NimbusNode, conf: NimbusConf, rng = nimbus.ctx.rng) # Add protocol capabilities based on protocol flags - if ProtocolFlag.Eth in protocols: - nimbus.ethNode.addEthHandlerCapability( - nimbus.chainRef, - nimbus.txPool, - nimbus.ethNode.peerPool - ) - case conf.syncMode: - of SyncMode.Snap, SyncMode.SnapCtx: - nimbus.ethNode.addCapability protocol.snap - of SyncMode.Full, SyncMode.Default: - discard - - if ProtocolFlag.Les in protocols: - nimbus.ethNode.addCapability les + for w in protocols: + case w: # handle all possibilities + of ProtocolFlag.Eth: + nimbus.ethNode.addEthHandlerCapability( + nimbus.ethNode.peerPool, + nimbus.chainRef, + nimbus.txPool) + of ProtocolFlag.Les: + nimbus.ethNode.addCapability les + of ProtocolFlag.Snap: + nimbus.ethNode.addSnapHandlerCapability( + nimbus.ethNode.peerPool, + nimbus.chainRef) # Early-initialise "--snap-sync" before starting any network connections. - if ProtocolFlag.Eth in protocols: + block: let tickerOK = conf.logLevel in {LogLevel.INFO, LogLevel.DEBUG, LogLevel.TRACE} + # Minimal capability needed for sync only + if ProtocolFlag.Eth notin protocols: + nimbus.ethNode.addEthHandlerCapability( + nimbus.ethNode.peerPool, + nimbus.chainRef) case conf.syncMode: of SyncMode.Full: nimbus.fullSyncRef = FullSyncRef.init( nimbus.ethNode, nimbus.chainRef, nimbus.ctx.rng, conf.maxPeers, tickerOK) - nimbus.fullSyncRef.start of SyncMode.Snap, SyncMode.SnapCtx: + # Minimal capability needed for sync only + if ProtocolFlag.Snap notin protocols: + nimbus.ethNode.addSnapHandlerCapability( + nimbus.ethNode.peerPool) nimbus.snapSyncRef = SnapSyncRef.init( nimbus.ethNode, nimbus.chainRef, nimbus.ctx.rng, conf.maxPeers, nimbus.dbBackend, tickerOK, noRecovery = (conf.syncMode==SyncMode.Snap)) - nimbus.snapSyncRef.start of SyncMode.Default: - discard + nimbus.legaSyncRef = LegacySyncRef.new( + nimbus.ethNode, nimbus.chainRef) # Connect directly to the static nodes let staticPeers = conf.getStaticPeers() @@ -406,20 +414,18 @@ proc start(nimbus: NimbusNode, conf: NimbusConf) = setupP2P(nimbus, conf, protocols) localServices(nimbus, conf, com, protocols) - if ProtocolFlag.Eth in protocols and conf.maxPeers > 0: + if conf.maxPeers > 0: case conf.syncMode: of SyncMode.Default: - let syncer = LegacySyncRef.new(nimbus.ethNode, nimbus.chainRef) - syncer.start - + nimbus.legaSyncRef.start nimbus.ethNode.setEthHandlerNewBlocksAndHashes( legacy.newBlockHandler, legacy.newBlockHashesHandler, - cast[pointer](syncer) - ) - - of SyncMode.Full, SyncMode.Snap, SyncMode.SnapCtx: - discard + cast[pointer](nimbus.legaSyncRef)) + of SyncMode.Full: + nimbus.fullSyncRef.start + of SyncMode.Snap, SyncMode.SnapCtx: + nimbus.snapSyncRef.start if nimbus.state == Starting: # it might have been set to "Stopping" with Ctrl+C diff --git a/nimbus/sync/handlers/eth.nim b/nimbus/sync/handlers/eth.nim index ee5574316..4d68b2950 100644 --- a/nimbus/sync/handlers/eth.nim +++ b/nimbus/sync/handlers/eth.nim @@ -44,12 +44,17 @@ type arg: pointer handler: NewBlockHashesHandler + EthWireRunState = enum + Enabled + Suspended + NotAvailable + EthWireRef* = ref object of EthWireBase db: ChainDBRef chain: ChainRef txPool: TxPoolRef peerPool: PeerPool - disableTxPool: bool + enableTxPool: EthWireRunState knownByPeer: Table[Peer, HashToTime] pending: HashSet[Hash256] lastCleanup: Time @@ -296,7 +301,9 @@ proc fetchTransactions(ctx: EthWireRef, reqHashes: seq[Hash256], peer: Peer): Fu # ------------------------------------------------------------------------------ proc onPeerConnected(ctx: EthWireRef, peer: Peer) = - if ctx.disableTxPool: + if ctx.enableTxPool != Enabled: + when trMissingOrDisabledGossipOk: + notEnabled("onPeerConnected") return var txHashes = newSeqOfCap[Hash256](ctx.txPool.numTxs) @@ -341,8 +348,11 @@ proc new*(_: type EthWireRef, chain: chain, txPool: txPool, peerPool: peerPool, - lastCleanup: getTime(), - ) + lastCleanup: getTime()) + if txPool.isNil: + ctx.enableTxPool = NotAvailable + when trMissingOrDisabledGossipOk: + trace "New eth handler, minimal/outbound support only" ctx.setupPeerObserver() ctx @@ -368,7 +378,8 @@ proc setNewBlockHashesHandler*(ctx: EthWireRef, handler: NewBlockHashesHandler, # ------------------------------------------------------------------------------ proc txPoolEnabled*(ctx: EthWireRef; ena: bool) = - ctx.disableTxPool = not ena + if ctx.enableTxPool != NotAvailable: + ctx.enableTxPool = if ena: Enabled else: Suspended method getStatus*(ctx: EthWireRef): EthState {.gcsafe, raises: [Defect,RlpError,EVMError].} = @@ -440,7 +451,7 @@ method getBlockHeaders*(ctx: EthWireRef, req: BlocksRequest): seq[BlockHeader] method handleAnnouncedTxs*(ctx: EthWireRef, peer: Peer, txs: openArray[Transaction]) {.gcsafe, raises: [Defect,CatchableError].} = - if ctx.disableTxPool: + if ctx.enableTxPool != Enabled: when trMissingOrDisabledGossipOk: notEnabled("handleAnnouncedTxs") return @@ -482,7 +493,7 @@ method handleAnnouncedTxs*(ctx: EthWireRef, peer: Peer, txs: openArray[Transacti method handleAnnouncedTxsHashes*(ctx: EthWireRef, peer: Peer, txHashes: openArray[Hash256]) {.gcsafe, raises: [Defect,CatchableError].} = - if ctx.disableTxPool: + if ctx.enableTxPool != Enabled: when trMissingOrDisabledGossipOk: notEnabled("handleAnnouncedTxsHashes") return diff --git a/nimbus/sync/handlers/setup.nim b/nimbus/sync/handlers/setup.nim index 2d671b6b9..b78b19d5d 100644 --- a/nimbus/sync/handlers/setup.nim +++ b/nimbus/sync/handlers/setup.nim @@ -12,7 +12,8 @@ import eth/p2p, ../../core/[chain, tx_pool], ../protocol, - ./eth as handlers_eth + ./eth as handlers_eth, + ./snap as handlers_snap {.used, push raises: [Defect].} @@ -24,27 +25,39 @@ proc setEthHandlerNewBlocksAndHashes*( node: var EthereumNode; blockHandler: NewBlockHandler; hashesHandler: NewBlockHashesHandler; - arg: pointer) - {.gcsafe, raises: [Defect,CatchableError].} = + arg: pointer; + ) {.gcsafe, raises: [Defect,CatchableError].} = let w = EthWireRef(node.protocolState protocol.eth) w.setNewBlockHandler(blockHandler, arg) w.setNewBlockHashesHandler(hashesHandler, arg) proc addEthHandlerCapability*( node: var EthereumNode; + peerPool: PeerPool; chain: ChainRef; - txPool: TxPoolRef; - peerPool: PeerPool) = - ## Install handler + txPool = TxPoolRef(nil); + ) = + ## Install `eth` handlers. Passing `txPool` as `nil` installs the handler + ## in minimal/outbound mode. node.addCapability( protocol.eth, EthWireRef.new(chain, txPool, peerPool)) - + # ------------------------------------------------------------------------------ # Public functions: convenience mappings for `snap` # ------------------------------------------------------------------------------ -# To do ... +proc addSnapHandlerCapability*( + node: var EthereumNode; + peerPool: PeerPool; + chain = ChainRef(nil); + ) = + ## Install `snap` handlers,Passing `chein` as `nil` installs the handler + ## in minimal/outbound mode. + if chain.isNil: + node.addCapability protocol.snap + else: + node.addCapability(protocol.snap, SnapWireRef.init(chain, peerPool)) # ------------------------------------------------------------------------------ # End diff --git a/nimbus/sync/handlers/snap.nim b/nimbus/sync/handlers/snap.nim new file mode 100644 index 000000000..dfd4483c0 --- /dev/null +++ b/nimbus/sync/handlers/snap.nim @@ -0,0 +1,120 @@ +# Nimbus +# Copyright (c) 2018-2021 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 + chronicles, + chronos, + eth/[p2p, p2p/peer_pool], + ../protocol, + ../protocol/[snap/snap_types, trace_config], + ../../core/chain + +{.push raises: [Defect].} + +logScope: + topics = "wire-protocol" + +type + SnapWireRef* = ref object of SnapWireBase + chain: ChainRef + peerPool: PeerPool + +# ------------------------------------------------------------------------------ +# Private functions: helper functions +# ------------------------------------------------------------------------------ + +proc notImplemented(name: string) = + debug "snapWire: hHandler method not implemented", meth=name + +# ------------------------------------------------------------------------------ +# Private functions: peer observer +# ------------------------------------------------------------------------------ + +#proc onPeerConnected(ctx: SnapWireRef, peer: Peer) = +# debug "snapWire: add peer", peer +# discard +# +#proc onPeerDisconnected(ctx: SnapWireRef, peer: Peer) = +# debug "snapWire: remove peer", peer +# discard +# +#proc setupPeerObserver(ctx: SnapWireRef) = +# var po = PeerObserver( +# onPeerConnected: +# proc(p: Peer) {.gcsafe.} = +# ctx.onPeerConnected(p), +# onPeerDisconnected: +# proc(p: Peer) {.gcsafe.} = +# ctx.onPeerDisconnected(p)) +# po.setProtocol protocol.snap +# ctx.peerPool.addObserver(ctx, po) + +# ------------------------------------------------------------------------------ +# Public constructor/destructor +# ------------------------------------------------------------------------------ + +proc init*( + T: type SnapWireRef; + chain: ChainRef; + peerPool: PeerPool; + ): T = + ## Constructor (uses `init()` as suggested in style guide.) + let ctx = T( + chain: chain, + peerPool: peerPool) + + #ctx.setupPeerObserver() + ctx + +# ------------------------------------------------------------------------------ +# Public functions: snap wire protocol handlers +# ------------------------------------------------------------------------------ + +method getAccountRange*( + ctx: SnapWireRef; + root: Hash256; + origin: Hash256; + limit: Hash256; + replySizeMax: uint64; + ): (seq[SnapAccount], SnapAccountProof) + {.gcsafe.} = + notImplemented("getAccountRange") + +method getStorageRanges*( + ctx: SnapWireRef; + root: Hash256; + accounts: openArray[Hash256]; + origin: openArray[byte]; + limit: openArray[byte]; + replySizeMax: uint64; + ): (seq[seq[SnapStorage]], SnapStorageProof) + {.gcsafe.} = + notImplemented("getStorageRanges") + +method getByteCodes*( + ctx: SnapWireRef; + nodes: openArray[Hash256]; + replySizeMax: uint64; + ): seq[Blob] + {.gcsafe.} = + notImplemented("getByteCodes") + +method getTrieNodes*( + ctx: SnapWireRef; + root: Hash256; + paths: openArray[seq[Blob]]; + replySizeMax: uint64; + ): seq[Blob] + {.gcsafe.} = + notImplemented("getTrieNodes") + +# ------------------------------------------------------------------------------ +# End +# ------------------------------------------------------------------------------ diff --git a/nimbus/sync/legacy.nim b/nimbus/sync/legacy.nim index e1ba24b9d..3bd2aa4c0 100644 --- a/nimbus/sync/legacy.nim +++ b/nimbus/sync/legacy.nim @@ -26,7 +26,7 @@ import {.push raises:[Defect].} logScope: - topics = "fast-sync" + topics = "legacy-sync" const minPeersToStartSync* = 2 # Wait for consensus of at least this diff --git a/nimbus/sync/protocol/eth/eth_types.nim b/nimbus/sync/protocol/eth/eth_types.nim index d18c41ce3..becc91afa 100644 --- a/nimbus/sync/protocol/eth/eth_types.nim +++ b/nimbus/sync/protocol/eth/eth_types.nim @@ -20,7 +20,7 @@ type bestBlockHash*: Hash256 forkId*: ChainForkId - PeerState* = ref object of RootRef + EthPeerState* = ref object of RootRef initialized*: bool bestBlockHash*: Hash256 bestDifficulty*: DifficultyInt diff --git a/nimbus/sync/protocol/eth66.nim b/nimbus/sync/protocol/eth66.nim index 90ebd5a87..4e1809477 100644 --- a/nimbus/sync/protocol/eth66.nim +++ b/nimbus/sync/protocol/eth66.nim @@ -75,7 +75,7 @@ const p2pProtocol eth66(version = ethVersion, rlpxName = "eth", - peerState = PeerState, + peerState = EthPeerState, networkState = EthWireBase, useRequestIds = true): diff --git a/nimbus/sync/protocol/eth67.nim b/nimbus/sync/protocol/eth67.nim index 73fdc0e0b..e72676798 100644 --- a/nimbus/sync/protocol/eth67.nim +++ b/nimbus/sync/protocol/eth67.nim @@ -75,7 +75,7 @@ const p2pProtocol eth67(version = ethVersion, rlpxName = "eth", - peerState = PeerState, + peerState = EthPeerState, networkState = EthWireBase, useRequestIds = true): diff --git a/nimbus/sync/protocol/snap/snap_types.nim b/nimbus/sync/protocol/snap/snap_types.nim new file mode 100644 index 000000000..d3309f1e6 --- /dev/null +++ b/nimbus/sync/protocol/snap/snap_types.nim @@ -0,0 +1,74 @@ +# Nimbus +# Copyright (c) 2018-2021 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 + chronicles, + eth/[common, p2p, p2p/private/p2p_types] +# ../../types + +type + SnapAccount* = object + accHash*: Hash256 + accBody* {.rlpCustomSerialization.}: Account + + SnapAccountProof* = seq[Blob] + + SnapStorage* = object + slotHash*: Hash256 + slotData*: Blob + + SnapStorageProof* = seq[Blob] + + SnapWireBase* = ref object of RootRef + + SnapPeerState* = ref object of RootRef + +proc notImplemented(name: string) = + debug "Method not implemented", meth = name + +method getAccountRange*( + ctx: SnapWireBase; + root: Hash256; + origin: Hash256; + limit: Hash256; + replySizeMax: uint64; + ): (seq[SnapAccount], SnapAccountProof) + {.base.} = + notImplemented("getAccountRange") + +method getStorageRanges*( + ctx: SnapWireBase; + root: Hash256; + accounts: openArray[Hash256]; + origin: openArray[byte]; + limit: openArray[byte]; + replySizeMax: uint64; + ): (seq[seq[SnapStorage]], SnapStorageProof) + {.base.} = + notImplemented("getStorageRanges") + +method getByteCodes*( + ctx: SnapWireBase; + nodes: openArray[Hash256]; + replySizeMax: uint64; + ): seq[Blob] + {.base.} = + notImplemented("getByteCodes") + +method getTrieNodes*( + ctx: SnapWireBase; + root: Hash256; + paths: openArray[seq[Blob]]; + replySizeMax: uint64; + ): seq[Blob] + {.base.} = + notImplemented("getTrieNodes") + +# End diff --git a/nimbus/sync/protocol/snap1.nim b/nimbus/sync/protocol/snap1.nim index d024ad47c..4ec8cc552 100644 --- a/nimbus/sync/protocol/snap1.nim +++ b/nimbus/sync/protocol/snap1.nim @@ -139,25 +139,14 @@ import chronos, eth/[common, p2p, p2p/private/p2p_types], nimcrypto/hash, - stew/byteutils, - ../../constants, - ./trace_config + ./snap/snap_types, + ../../constants + +export + snap_types logScope: - topics = "datax" - -type - SnapAccount* = object - accHash*: Hash256 - accBody* {.rlpCustomSerialization.}: Account - - SnapAccountProof* = seq[Blob] - - SnapStorage* = object - slotHash*: Hash256 - slotData*: Blob - - SnapStorageProof* = seq[Blob] + topics = "snap1" const snapVersion* = 1 @@ -245,98 +234,145 @@ proc append(rlpWriter: var RlpWriter, t: SnapAccount, account: Account) = p2pProtocol snap1(version = snapVersion, rlpxName = "snap", + peerState = SnapPeerState, + networkState = SnapWireBase, useRequestIds = true): requestResponse: # User message 0x00: GetAccountRange. # Note: `origin` and `limit` differs from the specification to match Geth. - proc getAccountRange(peer: Peer, rootHash: Hash256, origin: Hash256, - limit: Hash256, responseBytes: uint64) = - trace trSnapRecvReceived & "GetAccountRange (0x00)", peer, - accountRange=[origin,limit], stateRoot=($rootHash), responseBytes + proc getAccountRange( + peer: Peer; + root: Hash256; + origin: Hash256; + limit: Hash256; + replySizeMax: uint64; + ) = + trace trSnapRecvReceived & "GetAccountRange (0x00)", peer, root, + origin, limit, replySizeMax - trace trSnapSendReplying & "EMPTY AccountRange (0x01)", peer, sent=0 - await response.send(@[], @[]) + let + ctx = peer.networkState() + (accounts, proof) = ctx.getAccountRange( + root, origin, limit, replySizeMax) + + # For logging only + nAccounts = accounts.len + nProof = proof.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: seq[SnapAccount], - proof: SnapAccountProof) + proc accountRange( + peer: Peer; + accounts: seq[SnapAccount]; + proof: SnapAccountProof) + requestResponse: # User message 0x02: GetStorageRanges. # Note: `origin` and `limit` differs from the specification to match Geth. - proc getStorageRanges(peer: Peer, rootHash: Hash256, - accounts: openArray[Hash256], origin: openArray[byte], - limit: openArray[byte], responseBytes: uint64) = - when trSnapTracePacketsOk: - var definiteFullRange = ((origin.len == 32 or origin.len == 0) and - (limit.len == 32 or limit.len == 0)) - if definiteFullRange: - for i in 0 ..< origin.len: - if origin[i] != 0x00: - definiteFullRange = false - break - if definiteFullRange: - for i in 0 ..< limit.len: - if limit[i] != 0xff: - definiteFullRange = false - break + proc getStorageRanges( + peer: Peer; + root: Hash256; + accounts: openArray[Hash256]; + origin: openArray[byte]; + limit: openArray[byte]; + replySizeMax: uint64; + ) = + trace trSnapRecvReceived & "GetStorageRanges (0x02)", peer, root, + nAccounts=accounts.len, nOrigin=origin.len, nLimit=limit.len, + replySizeMax - template describe(value: openArray[byte]): string = - if value.len == 0: "(empty)" - elif value.len == 32: value.toHex - else: "(non-standard-len=" & $value.len & ')' & value.toHex + let + ctx = peer.networkState() + (slots, proof) = ctx.getStorageRanges( + root, accounts, origin, limit, replySizeMax) - if definiteFullRange: - # Fetching storage for multiple accounts. - trace trSnapRecvReceived & "GetStorageRanges/A (0x02)", peer, - accountPaths=accounts.len, - stateRoot=($rootHash), responseBytes - elif accounts.len == 1: - # Fetching partial storage for one account, aka. "large contract". - trace trSnapRecvReceived & "GetStorageRanges/S (0x02)", peer, - accountPaths=1, - storageRange=(describe(origin) & '-' & describe(limit)), - stateRoot=($rootHash), responseBytes - else: - # This branch is separated because these shouldn't occur. It's not - # really specified what happens when there are multiple accounts and - # non-default path range. - trace trSnapRecvReceived & "GetStorageRanges/AS?? (0x02)", peer, - accountPaths=accounts.len, - storageRange=(describe(origin) & '-' & describe(limit)), - stateRoot=($rootHash), responseBytes + # For logging only + nSlots = slots.len + nProof = proof.len - trace trSnapSendReplying & "EMPTY StorageRanges (0x03)", peer, sent=0 - await response.send(@[], @[]) + 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: SnapStorageProof) + proc storageRanges( + peer: Peer; + slotLists: openArray[seq[SnapStorage]]; + proof: SnapStorageProof) + - # User message 0x04: GetByteCodes. requestResponse: - proc getByteCodes(peer: Peer, nodeHashes: openArray[Hash256], - responseBytes: uint64) = + # User message 0x04: GetByteCodes. + proc getByteCodes( + peer: Peer; + nodes: openArray[Hash256]; + replySizeMax: uint64; + ) = trace trSnapRecvReceived & "GetByteCodes (0x04)", peer, - hashes=nodeHashes.len, responseBytes + nNodes=nodes.len, replySizeMax - trace trSnapSendReplying & "EMPTY ByteCodes (0x05)", peer, sent=0 + let + ctx = peer.networkState() + codes = ctx.getByteCodes(nodes, replySizeMax) + + # For logging only + nCodes = codes.len + + if nCodes == 0: + trace trSnapSendReplying & "EMPTY ByteCodes (0x05)", peer + else: + trace trSnapSendReplying & "ByteCodes (0x05)", peer, nCodes + await response.send(@[]) # User message 0x05: ByteCodes. - proc byteCodes(peer: Peer, codes: openArray[Blob]) + proc byteCodes( + peer: Peer; + codes: openArray[Blob]) + - # User message 0x06: GetTrieNodes. requestResponse: - proc getTrieNodes(peer: Peer, rootHash: Hash256, - paths: openArray[seq[Blob]], responseBytes: uint64) = - trace trSnapRecvReceived & "GetTrieNodes (0x06)", peer, - nodePaths=paths.len, stateRoot=($rootHash), responseBytes + # User message 0x06: GetTrieNodes. + proc getTrieNodes( + peer: Peer; + root: Hash256; + paths: openArray[seq[Blob]]; + replySizeMax: uint64; + ) = + trace trSnapRecvReceived & "GetTrieNodes (0x06)", peer, root, + nPaths=paths.len, replySizeMax - trace trSnapSendReplying & "EMPTY TrieNodes (0x07)", peer, sent=0 - await response.send(@[]) + let + ctx = peer.networkState() + nodes = ctx.getTrieNodes(root, paths, replySizeMax) + + # For logging only + nNodes = nodes.len + + if nNodes == 0: + trace trSnapSendReplying & "EMPTY TrieNodes (0x07)", peer + else: + trace trSnapSendReplying & "TrieNodes (0x07)", peer, nNodes + + await response.send(nodes) # User message 0x07: TrieNodes. - proc trieNodes(peer: Peer, nodes: openArray[Blob]) + proc trieNodes( + peer: Peer; + nodes: openArray[Blob]) + +# End diff --git a/nimbus/sync/snap.nim b/nimbus/sync/snap.nim index 35f53400f..86b55d5f1 100644 --- a/nimbus/sync/snap.nim +++ b/nimbus/sync/snap.nim @@ -122,7 +122,7 @@ proc init*( result.ctx.data.rng = rng result.ctx.data.dbBackend = dbBackend result.ctx.data.noRecovery = noRecovery - # Required to have been initialised via `addCapability()` + # Required to have been initialised via `addEthHandlerCapability()` doAssert not result.ctx.ethWireCtx.isNil proc start*(ctx: SnapSyncRef) =