diff --git a/eth/keyfile/keyfile.nim b/eth/keyfile/keyfile.nim index 241e6ff..da8a9ac 100644 --- a/eth/keyfile/keyfile.nim +++ b/eth/keyfile/keyfile.nim @@ -93,10 +93,7 @@ type KfResult*[T] = Result[T, KeyFileError] proc mapErrTo[T, E](r: Result[T, E], v: static KeyFileError): KfResult[T] = - if r.isOk: - ok(r.value) - else: - err(v) + r.mapErr(proc (e: E): KeyFileError = v) const SupportedHashes = [ diff --git a/eth/p2p.nim b/eth/p2p.nim index 96e0374..8d1ced7 100644 --- a/eth/p2p.nim +++ b/eth/p2p.nim @@ -106,7 +106,7 @@ proc newEthereumNode*( result.protocolVersion = if useCompression: devp2pSnappyVersion else: devp2pVersion - result.protocolStates.newSeq protocolCount() + result.protocolStates.newSeq allProtocols.len result.peerPool = newPeerPool( result, networkId, keys, nil, clientId, minPeers = minPeers) @@ -114,8 +114,8 @@ proc newEthereumNode*( result.peerPool.discovery = result.discovery if addAllCapabilities: - for cap in protocols(): - result.addCapability(cap) + for p in allProtocols: + result.addCapability(p) proc processIncoming(server: StreamServer, remote: StreamTransport): Future[void] {.async, gcsafe.} = diff --git a/eth/p2p/discovery.nim b/eth/p2p/discovery.nim index f1139c1..acff0ef 100644 --- a/eth/p2p/discovery.nim +++ b/eth/p2p/discovery.nim @@ -132,8 +132,7 @@ proc sendNeighbours*(d: DiscoveryProtocol, node: Node, neighbours: seq[Node]) = const MAX_NEIGHBOURS_PER_PACKET = 12 # TODO: Implement a smarter way to compute it type Neighbour = tuple[ip: IpAddress, udpPort, tcpPort: Port, pk: PublicKey] var nodes = newSeqOfCap[Neighbour](MAX_NEIGHBOURS_PER_PACKET) - when not defined(nimSeqsV2): - shallow(nodes) + shallow(nodes) template flush() = block: diff --git a/eth/p2p/discoveryv5/protocol.nim b/eth/p2p/discoveryv5/protocol.nim index ffde614..0ad9d74 100644 --- a/eth/p2p/discoveryv5/protocol.nim +++ b/eth/p2p/discoveryv5/protocol.nim @@ -211,7 +211,7 @@ proc randomNodes*(d: Protocol, maxAmount: int): seq[Node] = d.routingTable.randomNodes(maxAmount) proc randomNodes*(d: Protocol, maxAmount: int, - pred: proc(x: Node): bool {.gcsafe, noSideEffect, raises:[Defect].}): seq[Node] = + pred: proc(x: Node): bool {.gcsafe, noSideEffect.}): seq[Node] = ## Get a `maxAmount` of random nodes from the local routing table with the ## `pred` predicate function applied as filter on the nodes selected. d.routingTable.randomNodes(maxAmount, pred) diff --git a/eth/p2p/discoveryv5/routing_table.nim b/eth/p2p/discoveryv5/routing_table.nim index f837b96..00f2965 100644 --- a/eth/p2p/discoveryv5/routing_table.nim +++ b/eth/p2p/discoveryv5/routing_table.nim @@ -482,10 +482,10 @@ proc len*(r: RoutingTable): int = proc moveRight[T](arr: var openArray[T], a, b: int) = ## In `arr` move elements in range [a, b] right by 1. var t: T - t = system.move(arr[b + 1]) + shallowCopy(t, arr[b + 1]) for i in countdown(b, a): - arr[i + 1] = system.move(arr[i]) - arr[a] = system.move(t) + shallowCopy(arr[i + 1], arr[i]) + shallowCopy(arr[a], t) proc setJustSeen*(r: RoutingTable, n: Node) = ## Move `n` to the head (most recently seen) of its bucket. @@ -512,7 +512,7 @@ proc nodeToRevalidate*(r: RoutingTable): Node = return b.nodes[^1] proc randomNodes*(r: RoutingTable, maxAmount: int, - pred: proc(x: Node): bool {.gcsafe, noSideEffect, raises:[Defect].} = nil): seq[Node] = + pred: proc(x: Node): bool {.gcsafe, noSideEffect.} = nil): seq[Node] = ## Get a `maxAmount` of random nodes from the routing table with the `pred` ## predicate function applied as filter on the nodes selected. var maxAmount = maxAmount diff --git a/eth/p2p/p2p_backends_helpers.nim b/eth/p2p/p2p_backends_helpers.nim index d628b6f..75f4750 100644 --- a/eth/p2p/p2p_backends_helpers.nim +++ b/eth/p2p/p2p_backends_helpers.nim @@ -1,33 +1,9 @@ -let protocolManager = ProtocolManager() +var + gProtocols: seq[ProtocolInfo] # The variables above are immutable RTTI information. We need to tell # Nim to not consider them GcSafe violations: - -proc registerProtocol*(proto: ProtocolInfo) {.gcsafe.} = - {.gcsafe.}: - proto.index = protocolManager.protocols.len - if proto.name == "p2p": - doAssert(proto.index == 0) - protocolManager.protocols.add proto - -proc protocolCount*(): int {.gcsafe.} = - {.gcsafe.}: - protocolManager.protocols.len - -proc getProtocol*(index: int): ProtocolInfo {.gcsafe.} = - {.gcsafe.}: - protocolManager.protocols[index] - -iterator protocols*(): ProtocolInfo {.gcsafe.} = - {.gcsafe.}: - for x in protocolManager.protocols: - yield x - -template getProtocol*(Protocol: type): ProtocolInfo = - getProtocol(Protocol.index) - -template devp2pInfo*(): ProtocolInfo = - getProtocol(0) +template allProtocols*: auto = {.gcsafe.}: gProtocols proc getState*(peer: Peer, proto: ProtocolInfo): RootRef = peer.protocolStates[proto.index] @@ -59,8 +35,9 @@ proc initProtocolState*[T](state: T, x: Peer|EthereumNode) proc initProtocolStates(peer: Peer, protocols: openArray[ProtocolInfo]) {.raises: [Defect].} = # Initialize all the active protocol states - newSeq(peer.protocolStates, protocolCount()) + newSeq(peer.protocolStates, allProtocols.len) for protocol in protocols: let peerStateInit = protocol.peerStateInitializer if peerStateInit != nil: peer.protocolStates[protocol.index] = peerStateInit(peer) + diff --git a/eth/p2p/p2p_protocol_dsl.nim b/eth/p2p/p2p_protocol_dsl.nim index 7961f3d..bee4e1b 100644 --- a/eth/p2p/p2p_protocol_dsl.nim +++ b/eth/p2p/p2p_protocol_dsl.nim @@ -1,7 +1,7 @@ {.push raises: [Defect].} import - std/[options, sequtils, macrocache], + std/[options, sequtils], stew/shims/macros, chronos, faststreams/outputs type @@ -76,7 +76,7 @@ type # Cached properties nameIdent*: NimNode - protocolInfo*: NimNode + protocolInfoVar*: NimNode # All messages messages*: seq[Message] @@ -146,9 +146,6 @@ let PROTO {.compileTime.} = ident "PROTO" MSG {.compileTime.} = ident "MSG" -const - protocolCounter = CacheCounter"protocolCounter" - template Opt(T): auto = newTree(nnkBracketExpr, Option, T) template Fut(T): auto = newTree(nnkBracketExpr, Future, T) @@ -256,7 +253,7 @@ proc refreshParam(n: NimNode): NimNode = result = copyNimTree(n) if n.kind == nnkIdentDefs: for i in 0..= 0 - let dpInfo = devp2pInfo() - if msgId <= dpInfo.messages[^1].id: - return (dpInfo, dpInfo.messages[msgId]) + if msgId <= devp2pInfo.messages[^1].id: + return (devp2pInfo, addr devp2pInfo.messages[msgId]) if msgId < peer.dispatcher.messages.len: - let numProtocol = protocolCount() - for i in 0 ..< numProtocol: - let protocol = getProtocol(i) + for i in 0 ..< allProtocols.len: let offset = peer.dispatcher.protocolOffsets[i] if offset != -1 and - offset + protocol.messages[^1].id >= msgId: - return (protocol, peer.dispatcher.messages[msgId]) + offset + allProtocols[i].messages[^1].id >= msgId: + return (allProtocols[i], peer.dispatcher.messages[msgId]) # Protocol info objects # proc initProtocol(name: string, version: int, peerInit: PeerStateInitializer, - networkInit: NetworkStateInitializer): ProtocolInfo = - ProtocolInfo( - name : name, - version : version, - messages: @[], - peerStateInitializer: peerInit, - networkStateInitializer: networkInit - ) + networkInit: NetworkStateInitializer): ProtocolInfoObj = + result.name = name + result.version = version + result.messages = @[] + result.peerStateInitializer = peerInit + result.networkStateInitializer = networkInit proc setEventHandlers(p: ProtocolInfo, handshake: HandshakeStep, @@ -323,6 +321,16 @@ proc registerMsg(protocol: ProtocolInfo, requestResolver: requestResolver, nextMsgResolver: nextMsgResolver) +proc registerProtocol(protocol: ProtocolInfo) = + # TODO: This can be done at compile-time in the future + if protocol.name != "p2p": + let pos = lowerBound(gProtocols, protocol) + gProtocols.insert(protocol, pos) + for i in 0 ..< gProtocols.len: + gProtocols[i].index = i + else: + gDevp2pInfo = protocol + # Message composition and encryption # @@ -965,7 +973,7 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend = quote: return `sendCall` let perPeerMsgIdValue = if isSubprotocol: - newCall(perPeerMsgIdImpl, peerVar, protocol.protocolInfo, newLit(msgId)) + newCall(perPeerMsgIdImpl, peerVar, protocol.protocolInfoVar, newLit(msgId)) else: newLit(msgId) @@ -1001,7 +1009,7 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend = protocol.outProcRegistrations.add( newCall(registerMsg, - protocolVar, + protocol.protocolInfoVar, newLit(msgId), newLit(msgName), thunkName, @@ -1055,7 +1063,7 @@ proc removePeer(network: EthereumNode, peer: Peer) = proc callDisconnectHandlers(peer: Peer, reason: DisconnectionReason): Future[void] {.async.} = - var futures = newSeqOfCap[Future[void]](protocolCount()) + var futures = newSeqOfCap[Future[void]](allProtocols.len) for protocol in peer.dispatcher.activeProtocols: if protocol.disconnectHandler != nil: @@ -1136,7 +1144,7 @@ proc postHelloSteps(peer: Peer, h: DevP2P.hello) {.async.} = # chance to send any initial packages they might require over # the network and to yield on their `nextMsg` waits. # - var subProtocolsHandshakes = newSeqOfCap[Future[void]](protocolCount()) + var subProtocolsHandshakes = newSeqOfCap[Future[void]](allProtocols.len) for protocol in peer.dispatcher.activeProtocols: if protocol.handshake != nil: subProtocolsHandshakes.add((protocol.handshake)(peer)) diff --git a/eth/utp/growable_buffer.nim b/eth/utp/growable_buffer.nim index a34d479..093ce5b 100644 --- a/eth/utp/growable_buffer.nim +++ b/eth/utp/growable_buffer.nim @@ -21,9 +21,6 @@ type items: seq[Option[A]] mask: uint32 -when not defined(nimHasEffectsOfs): - template effectsOf(f: untyped) {.pragma.} - # provided size will always be adjusted to next power of two proc init*[A](T: type GrowableCircularBuffer[A], size: uint32 = 16): T = let powOfTwoSize = nextPowerOfTwo(int(size)) @@ -47,13 +44,11 @@ proc delete*[A](buff: var GrowableCircularBuffer[A], i: uint32) = proc hasKey*[A](buff: GrowableCircularBuffer[A], i: uint32): bool = buff.get(i).isSome() -proc exists*[A](buff: GrowableCircularBuffer[A], i: uint32, - check: proc (x: A): bool): bool {.gcsafe, effectsOf: check.} = +proc exists*[A](buff: GrowableCircularBuffer[A], i: uint32, check: proc (x: A): bool): bool = let maybeElem = buff.get(i) if (maybeElem.isSome()): let elem = maybeElem.unsafeGet() - {.gcsafe.}: - check(elem) + check(elem) else: false diff --git a/tests/p2p/eth_protocol.nim b/tests/p2p/eth_protocol.nim index 3359efe..795f3db 100644 --- a/tests/p2p/eth_protocol.nim +++ b/tests/p2p/eth_protocol.nim @@ -6,7 +6,7 @@ import # real eth protocol implementation is in nimbus-eth1 repo type - PeerState = ref object of RootRef + PeerState = ref object initialized*: bool p2pProtocol eth(version = 63, diff --git a/tests/p2p/test_protocol_handlers.nim b/tests/p2p/test_protocol_handlers.nim index cc39394..eeda088 100644 --- a/tests/p2p/test_protocol_handlers.nim +++ b/tests/p2p/test_protocol_handlers.nim @@ -16,12 +16,9 @@ import ./p2p_test_helper type - network = ref object of RootRef + network = ref object count*: int - PeerState = ref object of RootRef - status*: string - p2pProtocol abc(version = 1, rlpxName = "abc", networkState = network): @@ -36,18 +33,15 @@ p2pProtocol abc(version = 1, p2pProtocol xyz(version = 1, rlpxName = "xyz", - networkState = network, - peerState = PeerState): + networkState = network): onPeerConnected do (peer: Peer): peer.networkState.count += 1 - peer.state.status = "connected" onPeerDisconnected do (peer: Peer, reason: DisconnectionReason) {.gcsafe.}: peer.networkState.count -= 1 if true: raise newException(CatchableError, "Fake xyz exception") - peer.state.status = "disconnected" p2pProtocol hah(version = 1, rlpxName = "hah", @@ -73,7 +67,6 @@ suite "Testing protocol handlers": let peer = await node1.rlpxConnect(newNode(node2.toENode())) check: peer.isNil == false - peer.state(xyz).status == "connected" await peer.disconnect(SubprotocolReason, true) check: @@ -81,7 +74,6 @@ suite "Testing protocol handlers": # handlers, each handler still ran node1.protocolState(abc).count == 0 node1.protocolState(xyz).count == 0 - peer.state(xyz).status == "connected" asyncTest "Failing connection handler": let rng = newRng()