diff --git a/eth/p2p/p2p_protocol_dsl.nim b/eth/p2p/p2p_protocol_dsl.nim index 69aa209..86066aa 100644 --- a/eth/p2p/p2p_protocol_dsl.nim +++ b/eth/p2p/p2p_protocol_dsl.nim @@ -22,6 +22,7 @@ type response*: Message userHandler*: NimNode initResponderCall*: NimNode + outputParamDef*: NimNode Request* = ref object queries*: seq[Message] @@ -127,7 +128,9 @@ let peerVar* {.compileTime.} = ident "peer" responseVar* {.compileTime.} = ident "response" streamVar* {.compileTime.} = ident "stream" + protocolVar* {.compileTime.} = ident "protocol" deadlineVar* {.compileTime.} = ident "deadline" + timeoutVar* {.compileTime.} = ident "timeout" perProtocolMsgIdVar* {.compileTime.} = ident "perProtocolMsgId" currentProtocolSym* {.compileTime.} = ident "CurrentProtocol" resultIdent* {.compileTime.} = ident "result" @@ -138,12 +141,18 @@ let Void {.compileTime.} = ident "void" writeField {.compileTime.} = ident "writeField" + PROTO {.compileTime.} = ident "PROTO" + MSG {.compileTime.} = ident "MSG" + template Opt(T): auto = newTree(nnkBracketExpr, Option, T) template Fut(T): auto = newTree(nnkBracketExpr, Future, T) proc initFuture*[T](loc: var Future[T]) = loc = newFuture[T]() +proc isRlpx*(p: P2PProtocol): bool = + p.rlpxName.len > 0 + template applyDecorator(p: NimNode, decorator: NimNode) = if decorator.kind != nnkNilLit: p.pragma.insert(0, decorator) @@ -152,7 +161,7 @@ when tracingEnabled: proc logSentMsgFields(peer: NimNode, protocolInfo: NimNode, msgName: string, - fields: openarray[NimNode]): NimNode = + fields: openArray[NimNode]): NimNode = ## This generates the tracing code inserted in the message sending procs ## `fields` contains all the params that were serialized in the message let @@ -206,6 +215,49 @@ proc nameOrNil*(procDef: NimNode): NimNode = else: newNilLit() +proc isOutputParamName(paramName: NimNode): bool = + eqIdent(paramName, "output") or eqIdent(paramName, "response") + +proc isOutputParam(param: NimNode): bool = + param.len > 0 and param[0].skipPragma.isOutputParamName + +proc getOutputParam(procDef: NimNode): NimNode = + let params = procDef.params + for i in countdown(params.len - 1, 1): + let param = params[i] + if isOutputParam(param): + return param + +proc outputParam*(msg: Message): NimNode = + case msg.kind + of msgRequest: + outputParam(msg.response) + of msgResponse: + msg.outputParamDef + else: + raiseAssert "Only requests (and the attached responses) can have output parameters" + +proc outputParamIdent*(msg: Message): NimNode = + let outputParam = msg.outputParam + if outputParam != nil: + return outputParam[0].skipPragma + +proc outputParamType*(msg: Message): NimNode = + let outputParam = msg.outputParam + if outputParam != nil: + return outputParam[1] + +iterator typedInputParams(procDef: NimNode, skip = 0): (NimNode, NimNode) = + for paramName, paramType in typedParams(procDef, skip): + if not isOutputParamName(paramName): + yield (paramName, paramType) + +proc copyInputParams(params: NimNode): NimNode = + result = newTree(params.kind) + for param in params: + if not isOutputParam(param): + result.add param + proc chooseFieldType(n: NimNode): NimNode = ## Examines the parameter types used in the message signature ## and selects the corresponding field type for use in the @@ -213,7 +265,7 @@ proc chooseFieldType(n: NimNode): NimNode = ## ## For now, only openarray types are remapped to sequences. result = n - if n.kind == nnkBracketExpr and eqIdent(n[0], "openarray"): + if n.kind == nnkBracketExpr and eqIdent(n[0], "openArray"): result = n.copyNimTree result[0] = ident("seq") @@ -257,7 +309,6 @@ proc init*(T: type P2PProtocol, backendFactory: BackendFactory, result.backend = backendFactory(result) assert(not result.backend.implementProtocolInit.isNil) - assert(not result.backend.ResponderType.isNil) if result.backend.ReqIdType.isNil: result.backend.ReqIdType = ident "int" @@ -267,12 +318,18 @@ proc init*(T: type P2PProtocol, backendFactory: BackendFactory, if not result.backend.afterProtocolInit.isNil: result.backend.afterProtocolInit(result) +proc isFuture(t: NimNode): bool = + t.kind == nnkBracketExpr and eqIdent(t[0], "Future") + + proc augmentUserHandler(p: P2PProtocol, userHandlerProc: NimNode, msgId = -1) = ## This procs adds a set of common helpers available in all messages handlers ## (e.g. `perProtocolMsgId`, `peer.state`, etc). userHandlerProc.addPragma ident"gcsafe" - userHandlerProc.addPragma ident"async" + + if p.isRlpx: + userHandlerProc.addPragma ident"async" var getState = ident"getState" @@ -295,7 +352,7 @@ proc augmentUserHandler(p: P2PProtocol, userHandlerProc: NimNode, msgId = -1) = prelude.add quote do: type `currentProtocolSym` = `protocolNameIdent` - if msgId >= 0: + if msgId >= 0 and p.isRlpx: prelude.add quote do: const `perProtocolMsgIdVar` = `msgId` @@ -303,13 +360,13 @@ proc augmentUserHandler(p: P2PProtocol, userHandlerProc: NimNode, msgId = -1) = # inside each user message handler proc (e.g. peer.state.foo = bar) if PeerStateType != nil: prelude.add quote do: - template state(p: `PeerType`): `PeerStateType` = - cast[`PeerStateType`](`getState`(p, `protocolInfoVar`)) + template state(`peerVar`: `PeerType`): `PeerStateType` = + cast[`PeerStateType`](`getState`(`peerVar`, `protocolInfoVar`)) if NetworkStateType != nil: prelude.add quote do: - template networkState(p: `PeerType`): `NetworkStateType` = - cast[`NetworkStateType`](`getNetworkState`(p.network, `protocolInfoVar`)) + template networkState(`peerVar`: `PeerType`): `NetworkStateType` = + cast[`NetworkStateType`](`getNetworkState`(`peerVar`.network, `protocolInfoVar`)) proc addPreludeDefs*(userHandlerProc: NimNode, definitions: NimNode) = userHandlerProc.body[0].add definitions @@ -322,32 +379,16 @@ proc eventHandlerToProc(p: P2PProtocol, doBlock: NimNode, handlerName: string): result.name = ident(p.name & handlerName) # genSym(nskProc, p.name & handlerName) p.augmentUserHandler result -proc ensureTimeoutParam(procDef: NimNode, timeouts: int64): NimNode = - ## Make sure the messages has a timeout parameter and it has the correct type. - ## The parameter will be removed from the signature and returned for caching - ## in the Message's timeoutParam field. It is needed only for the send procs. +proc addTimeoutParam(procDef: NimNode, defaultValue: int64) = var Duration = bindSym"Duration" milliseconds = bindSym"milliseconds" lastParam = procDef.params[^1] - if eqIdent(lastParam[0], "timeout"): - if lastParam[2].kind == nnkEmpty: - error "You must specify a default value for the `timeout` parameter", lastParam - lastParam[2] = newCall(milliseconds, newLit(100))# newCall(Duration, lastParam[2]) - if lastParam[1].kind == nnkEmpty: - lastParam[1] = Duration - elif not eqIdent(lastParam[1], "Duration"): - error "The timeout parameter should be of type 'chronos.Duration'", lastParam[1] - - result = lastParam - procDef.params.del(procDef.params.len - 1) - - else: - result = newTree(nnkIdentDefs, - ident"timeout", - Duration, - newCall(milliseconds, newLit(timeouts))) + procDef.params.add newTree(nnkIdentDefs, + timeoutVar, + Duration, + newCall(milliseconds, newLit(defaultValue))) proc hasReqId*(msg: Message): bool = msg.protocol.useRequestIds and msg.kind in {msgRequest, msgResponse} @@ -357,9 +398,11 @@ proc ResponderType(msg: Message): NimNode = newTree(nnkBracketExpr, msg.protocol.backend.ResponderType, resp.strongRecName) +proc needsSingleParamInlining(msg: Message): bool = + msg.recBody.kind == nnkDistinctTy + proc newMsg(protocol: P2PProtocol, kind: MessageKind, id: int, - procDef: NimNode, timeoutParam: NimNode = nil, - response: Message = nil): Message = + procDef: NimNode, response: Message = nil): Message = if procDef[0].kind == nnkPostfix: error("p2pProcotol procs are public by default. " & @@ -373,7 +416,7 @@ proc newMsg(protocol: P2PProtocol, kind: MessageKind, id: int, strongRecName = ident(msgName & "Obj") recName = strongRecName - for param, paramType in procDef.typedParams(skip = 1): + for param, paramType in procDef.typedInputParams(skip = 1): recFields.add newTree(nnkIdentDefs, newTree(nnkPostfix, ident("*"), param), # The fields are public chooseFieldType(paramType), # some types such as openarray @@ -397,14 +440,13 @@ proc newMsg(protocol: P2PProtocol, kind: MessageKind, id: int, recName: recName, strongRecName: strongRecName, recBody: recBody, - timeoutParam: timeoutParam, response: response) if procDef.body.kind != nnkEmpty: var userHandler = copy procDef protocol.augmentUserHandler userHandler, id - userHandler.name = genSym(nskProc, msgName) + userHandler.name = ident(msgName & "UserHandler") # Request and Response handlers get an extra `reqId` parameter if the # protocol uses them: @@ -412,7 +454,7 @@ proc newMsg(protocol: P2PProtocol, kind: MessageKind, id: int, userHandler.params.insert(2, newIdentDefs(reqIdVar, protocol.backend.ReqIdType)) # All request handlers get an automatically inserter `response` variable: - if kind == msgRequest: + if kind == msgRequest and protocol.isRlpx: assert response != nil let peerParam = userHandler.params[1][0] @@ -436,6 +478,39 @@ proc newMsg(protocol: P2PProtocol, kind: MessageKind, id: int, protocol.messages.add result +proc isVoid(t: NimNode): bool = + t.kind == nnkEmpty or eqIdent(t, "void") + +proc addMsg(p: P2PProtocol, id: int, procDef: NimNode) = + var + returnType = procDef.params[0] + hasReturnValue = not isVoid(returnType) + outputParam = procDef.getOutputParam() + + if outputParam != nil: + if hasReturnValue: + error "A request proc should either use a return value or an output parameter" + returnType = outputParam[1] + hasReturnValue = true + + if hasReturnValue: + let + responseIdent = ident($procDef.name & "Response") + response = Message(protocol: p, + id: -1, # TODO: Implement the message IDs in RLPx-specific way + ident: responseIdent, + kind: msgResponse, + recName: returnType, + strongRecName: returnType, + recBody: returnType, + outputParamDef: outputParam) + + p.messages.add response + let msg = p.newMsg(msgRequest, id, procDef, response = response) + p.requests.add Request(queries: @[msg], response: response) + else: + p.notifications.add p.newMsg(msgNotification, id, procDef) + proc identWithExportMarker*(msg: Message): NimNode = newTree(nnkPostfix, ident("*"), msg.ident) @@ -475,19 +550,20 @@ proc createSendProc*(msg: Message, name, newEmptyNode(), newEmptyNode(), - copy msg.procDef.params, + copyInputParams msg.procDef.params, pragmas, newEmptyNode(), newStmtList()) ## body if proctype == nnkProcDef: for p in msg.procDef.pragma: - def.addPragma p + if not eqIdent(p, "async"): + def.addPragma p result.msg = msg result.def = def - for param, paramType in def.typedParams(): + for param, paramType in def.typedInputParams(): if result.peerParam.isNil: result.peerParam = param else: @@ -496,26 +572,25 @@ proc createSendProc*(msg: Message, case msg.kind of msgHandshake, msgRequest: # Add a timeout parameter for all request procs - let timeout = copy msg.timeoutParam - def[3].add timeout - result.timeoutParam = timeout[0] + def.addTimeoutParam(msg.protocol.timeouts) of msgResponse: - # A response proc must be called with a response object that originates - # from a certain request. Here we change the Peer parameter at position - # 1 to the correct strongly-typed ResponderType. The incoming procs still - # gets the normal Peer paramter. - let - ResponderType = msg.ResponderType - sendProcName = msg.ident + if msg.ResponderType != nil: + # A response proc must be called with a response object that originates + # from a certain request. Here we change the Peer parameter at position + # 1 to the correct strongly-typed ResponderType. The incoming procs still + # gets the normal Peer paramter. + let + ResponderType = msg.ResponderType + sendProcName = msg.ident - def[3][1][1] = ResponderType + def[3][1][1] = ResponderType - # We create a helper that enables the `response.send()` syntax - # inside the user handler of the request proc: - result.extraDefs = quote do: - template send*(r: `ResponderType`, args: varargs[untyped]): auto = - `sendProcName`(r, args) + # We create a helper that enables the `response.send()` syntax + # inside the user handler of the request proc: + result.extraDefs = quote do: + template send*(r: `ResponderType`, args: varargs[untyped]): auto = + `sendProcName`(r, args) of msgNotification: discard @@ -546,7 +621,7 @@ proc setBody*(sendProc: SendProc, body: NimNode) = if sendProc.extraDefs != nil: msg.protocol.outSendProcs.add sendProc.extraDefs -proc writeParamsAsRecord*(params: openarray[NimNode], +proc writeParamsAsRecord*(params: openArray[NimNode], outputStream, Format, RecordType: NimNode): NimNode = if params.len == 0: return newStmtList() @@ -584,10 +659,19 @@ proc useStandardBody*(sendProc: SendProc, sendCallGenerator: proc (peer, bytes: NimNode): NimNode) = let msg = sendProc.msg - outputStream = ident "outputStream" msgBytes = ident "msgBytes" - recipient = sendProc.peerParam + sendCall = sendCallGenerator(recipient, msgBytes) + + if sendProc.msgParams.len == 0: + sendProc.setBody quote do: + var `msgBytes`: seq[byte] + `sendCall` + return + + let + outputStream = ident "outputStream" + msgRecName = msg.recName Format = msg.protocol.backend.SerializationFormat @@ -602,8 +686,6 @@ proc useStandardBody*(sendProc: SendProc, appendParams = newStmtList() - sendCall = sendCallGenerator(recipient, msgBytes) - tracing = when not tracingEnabled: newStmtList() else: @@ -655,27 +737,32 @@ proc defineThunk*(msg: Message, thunk: NimNode) = protocol.outRecvProcs.add thunk proc genUserHandlerCall*(msg: Message, receivedMsg: NimNode, - leadingParams: varargs[NimNode]): NimNode = + leadingParams: openArray[NimNode], + outputParam: NimNode = nil): NimNode = if msg.userHandler == nil: return newStmtList() result = newCall(msg.userHandler.name, leadingParams) - var params = toSeq(msg.procDef.typedParams(skip = 1)) - if params.len == 1 and msg.protocol.useSingleRecordInlining: + if msg.needsSingleParamInlining: result.add receivedMsg else: + var params = toSeq(msg.procDef.typedInputParams(skip = 1)) for p in params: result.add newDotExpr(receivedMsg, p[0]) + if outputParam != nil: + result.add outputParam + proc genAwaitUserHandler*(msg: Message, receivedMsg: NimNode, - leadingParams: varargs[NimNode]): NimNode = - result = msg.genUserHandlerCall(receivedMsg, leadingParams) + leadingParams: openArray[NimNode], + outputParam: NimNode = nil): NimNode = + result = msg.genUserHandlerCall(receivedMsg, leadingParams, outputParam) if result.len > 0: result = newCall("await", result) -proc appendAllParams*(node: NimNode, procDef: NimNode, skipFirst = 0): NimNode = +proc appendAllInputParams*(node: NimNode, procDef: NimNode): NimNode = result = node - for p, _ in procDef.typedParams(skip = skipFirst): + for p, _ in procDef.typedInputParams(): result.add p proc paramNames*(procDef: NimNode, skipFirst = 0): seq[NimNode] = @@ -696,22 +783,20 @@ proc createHandshakeTemplate*(msg: Message, nextMsg: NimNode): SendProc = let handshakeExchanger = msg.createSendProc(procType = nnkTemplateDef) - forwardCall = newCall(rawSendProc).appendAllParams(handshakeExchanger.def) + forwardCall = newCall(rawSendProc).appendAllInputParams(handshakeExchanger.def) peerValue = forwardCall[1] - timeoutValue = msg.timeoutParam[0] - peerVarSym = genSym(nskLet, "peer") msgRecName = msg.recName - forwardCall[1] = peerVarSym + forwardCall[1] = peerVar forwardCall.del(forwardCall.len - 1) handshakeExchanger.setBody quote do: - let `peerVarSym` = `peerValue` + let `peerVar` = `peerValue` let sendingFuture = `forwardCall` - `handshakeImpl`(`peerVarSym`, + `handshakeImpl`(`peerVar`, sendingFuture, - `nextMsg`(`peerVarSym`, `msgRecName`), - `timeoutValue`) + `nextMsg`(`peerVar`, `msgRecName`), + `timeoutVar`) return handshakeExchanger @@ -762,9 +847,7 @@ proc processProtocolBody*(p: P2PProtocol, protocolBody: NimNode) = let responseMsg = p.newMsg(msgResponse, nextId + procs.len - 1, procs[^1]) for i in 0 .. procs.len - 2: - var timeout = ensureTimeoutParam(procs[i], p.timeouts) - queries.add p.newMsg(msgRequest, nextId + i, procs[i], timeout, - response = responseMsg) + queries.add p.newMsg(msgRequest, nextId + i, procs[i], response = responseMsg) p.requests.add Request(queries: queries, response: responseMsg) @@ -778,8 +861,7 @@ proc processProtocolBody*(p: P2PProtocol, protocolBody: NimNode) = if p.handshake != nil: error "The handshake for the protocol is already defined", n - var timeout = ensureTimeoutParam(procs[0], p.timeouts) - p.handshake = p.newMsg(msgHandshake, nextId, procs[0], timeout) + p.handshake = p.newMsg(msgHandshake, nextId, procs[0]) inc nextId elif eqIdent(n[0], "onPeerConnected"): @@ -791,8 +873,8 @@ proc processProtocolBody*(p: P2PProtocol, protocolBody: NimNode) = else: error(repr(n) & " is not a recognized call in P2P protocol definitions", n) - of nnkProcDef: - p.notifications.add p.newMsg(msgNotification, nextId, n) + of nnkProcDef, nnkIteratorDef: + p.addMsg(nextId, n) inc nextId of nnkCommentStmt: @@ -815,13 +897,16 @@ proc genTypeSection*(p: P2PProtocol): NimNode = if peerState != nil: result.add quote do: - template State*(P: type `protocolName`): type = `peerState` + template State*(`PROTO`: type `protocolName`): type = `peerState` if networkState != nil: result.add quote do: - template NetworkState*(P: type `protocolName`): type = `networkState` + template NetworkState*(`PROTO`: type `protocolName`): type = `networkState` for msg in p.messages: + if msg.procDef == nil: + continue + let msgId = msg.id msgName = msg.ident @@ -835,42 +920,34 @@ proc genTypeSection*(p: P2PProtocol): NimNode = # Add a helper template for accessing the message type: # e.g. p2p.hello: - template `msgName`*(T: type `protocolName`): type = `msgRecName` + template `msgName`*(`PROTO`: type `protocolName`): type = `msgRecName` # Add a helper template for obtaining the message Id for # a particular message type: - template msgId*(T: type `msgStrongRecName`): int = `msgId` - template msgProtocol*(T: type `msgStrongRecName`): type = `protocolName` - template RecType*(T: type `msgStrongRecName`): untyped = `msgRecName` + template msgProtocol*(`MSG`: type `msgStrongRecName`): type = `protocolName` + template RecType*(`MSG`: type `msgStrongRecName`): untyped = `msgRecName` + + if p.isRlpx: + result.add quote do: + template msgId*(`MSG`: type `msgStrongRecName`): int = `msgId` proc genCode*(p: P2PProtocol): NimNode = - # TODO: try switching to a simpler for msg in p.messages: loop - when true: - for msg in p.messages: - p.backend.implementMsg msg - else: - if p.handshake != nil: - p.backend.implementMsg p.handshake - - for msg in p.notifications: - p.backend.implementMsg msg - - for req in p.requests: - p.backend.implementMsg req.response - for query in req.queries: p.backend.implementMsg(query) + for msg in p.messages: + p.backend.implementMsg msg result = newStmtList() result.add p.genTypeSection() let protocolInfoVar = p.protocolInfoVar + protocolInfoVarObj = ident($protocolInfoVar & "Obj") protocolName = p.nameIdent protocolInit = p.backend.implementProtocolInit(p) result.add quote do: # One global variable per protocol holds the protocol run-time data - var p = `protocolInit` - var `protocolInfoVar` = addr p + var `protocolInfoVarObj` = `protocolInit` + var `protocolInfoVar` = addr `protocolInfoVarObj` # The protocol run-time data is available as a pseudo-field # (e.g. `p2p.protocolInfo`) @@ -919,9 +996,7 @@ macro emitForSingleBackend( peerState.getType, networkState.getType) result = p.genCode() - - when defined(debugP2pProtocol) or defined(debugMacros): - echo repr(result) + result.storeMacroResult true macro emitForAllBackends(backendSyms: typed, options: untyped, body: untyped): untyped = let name = $(options[0]) diff --git a/eth/p2p/rlpx.nim b/eth/p2p/rlpx.nim index bc01b9d..82d7b08 100644 --- a/eth/p2p/rlpx.nim +++ b/eth/p2p/rlpx.nim @@ -643,7 +643,7 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend = # assumes there is one outstanding request at a time (if there are # multiple requests we'll resolve them in FIFO order). let registerRequestCall = newCall(registerRequest, peerVar, - msg.timeoutParam[0], + timeoutVar, resultIdent, responseMsgId) if hasReqId: @@ -695,7 +695,7 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend = let awaitUserHandler = msg.genAwaitUserHandler(receivedMsg, userHandlerParams) - thunkName = ident(msgName & "_thunk") + thunkName = ident(msgName & "Thunk") msg.defineThunk quote do: proc `thunkName`(`peerVar`: `Peer`, _: int, data: Rlp) {.async, gcsafe.} = diff --git a/eth/p2p/rlpx.nim.generated.nim b/eth/p2p/rlpx.nim.generated.nim new file mode 100644 index 0000000..6ffa31d --- /dev/null +++ b/eth/p2p/rlpx.nim.generated.nim @@ -0,0 +1,196 @@ + +## Generated at line 781 +type + DevP2P* = object +type + helloObj* = object + version*: uint + clientId*: string + capabilities*: seq[Capability] + listenPort*: uint + nodeId*: array[RawPublicKeySize, byte] + +template hello*(PROTO: type DevP2P): type = + helloObj + +template msgProtocol*(MSG: type helloObj): type = + DevP2P + +template RecType*(MSG: type helloObj): untyped = + helloObj + +template msgId*(MSG: type helloObj): int = + 0 + +type + sendDisconnectMsgObj* = object + reason*: DisconnectionReasonList + +template sendDisconnectMsg*(PROTO: type DevP2P): type = + sendDisconnectMsgObj + +template msgProtocol*(MSG: type sendDisconnectMsgObj): type = + DevP2P + +template RecType*(MSG: type sendDisconnectMsgObj): untyped = + sendDisconnectMsgObj + +template msgId*(MSG: type sendDisconnectMsgObj): int = + 1 + +type + pingObj* = object + emptyList*: EmptyList + +template ping*(PROTO: type DevP2P): type = + pingObj + +template msgProtocol*(MSG: type pingObj): type = + DevP2P + +template RecType*(MSG: type pingObj): untyped = + pingObj + +template msgId*(MSG: type pingObj): int = + 2 + +type + pongObj* = object + emptyList*: EmptyList + +template pong*(PROTO: type DevP2P): type = + pongObj + +template msgProtocol*(MSG: type pongObj): type = + DevP2P + +template RecType*(MSG: type pongObj): untyped = + pongObj + +template msgId*(MSG: type pongObj): int = + 3 + +var DevP2PProtocolObj = initProtocol("p2p", 5, nil, nil) +var DevP2PProtocol = addr DevP2PProtocolObj +template protocolInfo*(P`gensym75730262: type DevP2P): auto = + DevP2PProtocol + +proc hello*(peerOrResponder: Peer; version: uint; clientId: string; + capabilities: seq[Capability]; listenPort: uint; + nodeId: array[RawPublicKeySize, byte]): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 0 + let perPeerMsgId = 0 + append(writer, perPeerMsgId) + startList(writer, 5) + append(writer, version) + append(writer, clientId) + append(writer, capabilities) + append(writer, listenPort) + append(writer, nodeId) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc sendDisconnectMsg*(peerOrResponder: Peer; reason: DisconnectionReasonList): Future[ + void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 1 + let perPeerMsgId = 1 + append(writer, perPeerMsgId) + append(writer, reason) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc ping*(peerOrResponder: Peer; emptyList: EmptyList): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 2 + let perPeerMsgId = 2 + append(writer, perPeerMsgId) + append(writer, emptyList) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc pong*(peerOrResponder: Peer; emptyList: EmptyList): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 3 + let perPeerMsgId = 3 + append(writer, perPeerMsgId) + append(writer, emptyList) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc sendDisconnectMsgUserHandler(peer: Peer; reason: DisconnectionReasonList) {. + gcsafe, async.} = + type + CurrentProtocol = DevP2P + const + perProtocolMsgId = 1 + trace "disconnect message received", reason = reason.value, peer + await peer.disconnect(reason.value, false) + +proc pingUserHandler(peer: Peer; emptyList: EmptyList) {.gcsafe, async.} = + type + CurrentProtocol = DevP2P + const + perProtocolMsgId = 2 + discard peer.pong(EmptyList()) + +proc pongUserHandler(peer: Peer; emptyList: EmptyList) {.gcsafe, async.} = + type + CurrentProtocol = DevP2P + const + perProtocolMsgId = 3 + discard + +proc helloThunk(peer: Peer; _`gensym75730215: int; data`gensym75730216: Rlp) {.async, + gcsafe.} = + var rlp = data`gensym75730216 + var msg {.noinit.}: helloObj + tryEnterList(rlp) + msg.version = checkedRlpRead(peer, rlp, uint) + msg.clientId = checkedRlpRead(peer, rlp, string) + msg.capabilities = checkedRlpRead(peer, rlp, seq[Capability]) + msg.listenPort = checkedRlpRead(peer, rlp, uint) + msg.nodeId = checkedRlpRead(peer, rlp, array[RawPublicKeySize, byte]) + +proc sendDisconnectMsgThunk(peer: Peer; _`gensym75730250: int; + data`gensym75730251: Rlp) {.async, gcsafe.} = + var rlp = data`gensym75730251 + var msg {.noinit.}: sendDisconnectMsgObj + msg.reason = checkedRlpRead(peer, rlp, DisconnectionReasonList) + await(sendDisconnectMsgUserHandler(peer, msg.reason)) + +proc pingThunk(peer: Peer; _`gensym75730252: int; data`gensym75730253: Rlp) {.async, + gcsafe.} = + var rlp = data`gensym75730253 + var msg {.noinit.}: pingObj + msg.emptyList = checkedRlpRead(peer, rlp, EmptyList) + await(pingUserHandler(peer, msg.emptyList)) + +proc pongThunk(peer: Peer; _`gensym75730254: int; data`gensym75730255: Rlp) {.async, + gcsafe.} = + var rlp = data`gensym75730255 + var msg {.noinit.}: pongObj + msg.emptyList = checkedRlpRead(peer, rlp, EmptyList) + await(pongUserHandler(peer, msg.emptyList)) + +registerMsg(DevP2PProtocol, 0, "hello", helloThunk, messagePrinter[helloObj], + requestResolver[helloObj], nextMsgResolver[helloObj]) +registerMsg(DevP2PProtocol, 1, "sendDisconnectMsg", sendDisconnectMsgThunk, + messagePrinter[sendDisconnectMsgObj], + requestResolver[sendDisconnectMsgObj], + nextMsgResolver[sendDisconnectMsgObj]) +registerMsg(DevP2PProtocol, 2, "ping", pingThunk, messagePrinter[pingObj], + requestResolver[pingObj], nextMsgResolver[pingObj]) +registerMsg(DevP2PProtocol, 3, "pong", pongThunk, messagePrinter[pongObj], + requestResolver[pongObj], nextMsgResolver[pongObj]) +setEventHandlers(DevP2PProtocol, nil, nil) +registerProtocol(DevP2PProtocol) \ No newline at end of file diff --git a/eth/p2p/rlpx_protocols/whisper_protocol.nim.generated.nim b/eth/p2p/rlpx_protocols/whisper_protocol.nim.generated.nim new file mode 100644 index 0000000..991e5a6 --- /dev/null +++ b/eth/p2p/rlpx_protocols/whisper_protocol.nim.generated.nim @@ -0,0 +1,662 @@ + +## Generated at line 119 +type + Whisper* = object +template State*(PROTO: type Whisper): type = + ref[WhisperPeer:ObjectType] + +template NetworkState*(PROTO: type Whisper): type = + ref[WhisperNetwork:ObjectType] + +type + statusObj* = object + protocolVersion*: uint + powConverted*: uint64 + bloom*: seq[byte] + isLightNode*: bool + +template status*(PROTO: type Whisper): type = + statusObj + +template msgProtocol*(MSG: type statusObj): type = + Whisper + +template RecType*(MSG: type statusObj): untyped = + statusObj + +template msgId*(MSG: type statusObj): int = + 0 + +type + messagesObj* = object + envelopes*: seq[Envelope] + +template messages*(PROTO: type Whisper): type = + messagesObj + +template msgProtocol*(MSG: type messagesObj): type = + Whisper + +template RecType*(MSG: type messagesObj): untyped = + messagesObj + +template msgId*(MSG: type messagesObj): int = + 1 + +type + powRequirementObj* = object + value*: uint64 + +template powRequirement*(PROTO: type Whisper): type = + powRequirementObj + +template msgProtocol*(MSG: type powRequirementObj): type = + Whisper + +template RecType*(MSG: type powRequirementObj): untyped = + powRequirementObj + +template msgId*(MSG: type powRequirementObj): int = + 2 + +type + bloomFilterExchangeObj* = object + bloom*: seq[byte] + +template bloomFilterExchange*(PROTO: type Whisper): type = + bloomFilterExchangeObj + +template msgProtocol*(MSG: type bloomFilterExchangeObj): type = + Whisper + +template RecType*(MSG: type bloomFilterExchangeObj): untyped = + bloomFilterExchangeObj + +template msgId*(MSG: type bloomFilterExchangeObj): int = + 3 + +type + p2pRequestObj* = object + envelope*: Envelope + +template p2pRequest*(PROTO: type Whisper): type = + p2pRequestObj + +template msgProtocol*(MSG: type p2pRequestObj): type = + Whisper + +template RecType*(MSG: type p2pRequestObj): untyped = + p2pRequestObj + +template msgId*(MSG: type p2pRequestObj): int = + 126 + +type + p2pMessageObj* = object + envelope*: Envelope + +template p2pMessage*(PROTO: type Whisper): type = + p2pMessageObj + +template msgProtocol*(MSG: type p2pMessageObj): type = + Whisper + +template RecType*(MSG: type p2pMessageObj): untyped = + p2pMessageObj + +template msgId*(MSG: type p2pMessageObj): int = + 127 + +type + batchAcknowledgedObj* = object + +template batchAcknowledged*(PROTO: type Whisper): type = + batchAcknowledgedObj + +template msgProtocol*(MSG: type batchAcknowledgedObj): type = + Whisper + +template RecType*(MSG: type batchAcknowledgedObj): untyped = + batchAcknowledgedObj + +template msgId*(MSG: type batchAcknowledgedObj): int = + 11 + +type + messageResponseObj* = object + +template messageResponse*(PROTO: type Whisper): type = + messageResponseObj + +template msgProtocol*(MSG: type messageResponseObj): type = + Whisper + +template RecType*(MSG: type messageResponseObj): untyped = + messageResponseObj + +template msgId*(MSG: type messageResponseObj): int = + 12 + +type + p2pSyncResponseObj* = object + +template p2pSyncResponse*(PROTO: type Whisper): type = + p2pSyncResponseObj + +template msgProtocol*(MSG: type p2pSyncResponseObj): type = + Whisper + +template RecType*(MSG: type p2pSyncResponseObj): untyped = + p2pSyncResponseObj + +template msgId*(MSG: type p2pSyncResponseObj): int = + 124 + +type + p2pSyncRequestObj* = object + +template p2pSyncRequest*(PROTO: type Whisper): type = + p2pSyncRequestObj + +template msgProtocol*(MSG: type p2pSyncRequestObj): type = + Whisper + +template RecType*(MSG: type p2pSyncRequestObj): untyped = + p2pSyncRequestObj + +template msgId*(MSG: type p2pSyncRequestObj): int = + 123 + +type + p2pRequestCompleteObj* = object + +template p2pRequestComplete*(PROTO: type Whisper): type = + p2pRequestCompleteObj + +template msgProtocol*(MSG: type p2pRequestCompleteObj): type = + Whisper + +template RecType*(MSG: type p2pRequestCompleteObj): untyped = + p2pRequestCompleteObj + +template msgId*(MSG: type p2pRequestCompleteObj): int = + 125 + +var WhisperProtocolObj = initProtocol("shh", 6, createPeerState[Peer, + ref[WhisperPeer:ObjectType]], createNetworkState[EthereumNode, + ref[WhisperNetwork:ObjectType]]) +var WhisperProtocol = addr WhisperProtocolObj +template protocolInfo*(P`gensym85175079: type Whisper): auto = + WhisperProtocol + +proc statusRawSender(peerOrResponder: Peer; protocolVersion: uint; + powConverted: uint64; bloom: seq[byte]; isLightNode: bool; + timeout: Duration = milliseconds(10000'i64)): Future[void] {. + gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 0 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 0) + append(writer, perPeerMsgId) + startList(writer, 4) + append(writer, protocolVersion) + append(writer, powConverted) + append(writer, bloom) + append(writer, isLightNode) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +template status*(peerOrResponder: Peer; protocolVersion: uint; powConverted: uint64; + bloom: seq[byte]; isLightNode: bool; + timeout: Duration = milliseconds(10000'i64)): Future[statusObj] = + let peer = peerOrResponder + let sendingFuture`gensym85175056 = statusRawSender(peer, protocolVersion, + powConverted, bloom, isLightNode) + handshakeImpl(peer, sendingFuture`gensym85175056, nextMsg(peer, statusObj), + timeout) + +proc messages*(peerOrResponder: Peer; envelopes: openarray[Envelope]): Future[void] {. + gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 1 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 1) + append(writer, perPeerMsgId) + append(writer, envelopes) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc powRequirement*(peerOrResponder: Peer; value: uint64): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 2 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 2) + append(writer, perPeerMsgId) + append(writer, value) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc bloomFilterExchange*(peerOrResponder: Peer; bloom: openArray[byte]): Future[void] {. + gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 3 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 3) + append(writer, perPeerMsgId) + append(writer, bloom) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc p2pRequest*(peerOrResponder: Peer; envelope: Envelope): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 126 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 126) + append(writer, perPeerMsgId) + append(writer, envelope) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc p2pMessage*(peerOrResponder: Peer; envelope: Envelope): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 127 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 127) + append(writer, perPeerMsgId) + append(writer, envelope) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc batchAcknowledged*(peerOrResponder: Peer): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 11 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 11) + append(writer, perPeerMsgId) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc messageResponse*(peerOrResponder: Peer): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 12 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 12) + append(writer, perPeerMsgId) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc p2pSyncResponse*(peerOrResponder: ResponderWithId[p2pSyncResponseObj]): Future[ + void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 124 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 124) + append(writer, perPeerMsgId) + append(writer, peerOrResponder.reqId) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +template send*(r`gensym85175073: ResponderWithId[p2pSyncResponseObj]; + args`gensym85175074: varargs[untyped]): auto = + p2pSyncResponse(r`gensym85175073, args`gensym85175074) + +proc p2pSyncRequest*(peerOrResponder: Peer; + timeout: Duration = milliseconds(10000'i64)): Future[ + Option[p2pSyncResponseObj]] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 123 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 123) + append(writer, perPeerMsgId) + initFuture result + let reqId = registerRequest(peer, timeout, result, perPeerMsgId + 1) + append(writer, reqId) + let msgBytes = finish(writer) + linkSendFailureToReqFuture(sendMsg(peer, msgBytes), result) + +proc p2pRequestComplete*(peerOrResponder: Peer): Future[void] {.gcsafe.} = + let peer = getPeer(peerOrResponder) + var writer = initRlpWriter() + const + perProtocolMsgId = 125 + let perPeerMsgId = perPeerMsgIdImpl(peer, WhisperProtocol, 125) + append(writer, perPeerMsgId) + let msgBytes = finish(writer) + return sendMsg(peer, msgBytes) + +proc messagesUserHandler(peer: Peer; envelopes: seq[Envelope]) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 1 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + if not peer.state.initialized: + warn "Handshake not completed yet, discarding messages" + return + for envelope in envelopes: + if not envelope.valid(): + warn "Expired or future timed envelope", peer + continue + let msg = initMessage(envelope) + if not msg.allowed(peer.networkState.config): + continue + if peer.state.received.containsOrIncl(msg.hash): + dropped_duplicate_envelopes.inc() + trace "Peer sending duplicate messages", peer, hash = $msg.hash + continue + if peer.networkState.queue[].add(msg): + peer.networkState.filters.notify(msg) + +proc powRequirementUserHandler(peer: Peer; value: uint64) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 2 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + if not peer.state.initialized: + warn "Handshake not completed yet, discarding powRequirement" + return + peer.state.powRequirement = cast[float64](value) + +proc bloomFilterExchangeUserHandler(peer: Peer; bloom: seq[byte]) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 3 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + if not peer.state.initialized: + warn "Handshake not completed yet, discarding bloomFilterExchange" + return + if bloom.len == bloomSize: + peer.state.bloom.bytesCopy(bloom) + +proc p2pRequestUserHandler(peer: Peer; envelope: Envelope) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 126 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + discard + +proc p2pMessageUserHandler(peer: Peer; envelope: Envelope) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 127 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + if peer.state.trusted: + let msg = Message(env: envelope, isP2P: true) + peer.networkState.filters.notify(msg) + +proc batchAcknowledgedUserHandler(peer: Peer) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 11 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + discard + +proc messageResponseUserHandler(peer: Peer) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 12 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + discard + +proc p2pSyncResponseUserHandler(peer: Peer; reqId: int) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 124 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + discard + +proc p2pSyncRequestUserHandler(peer: Peer; reqId: int) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 123 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + var response = init(ResponderWithId[p2pSyncResponseObj], peer, reqId) + discard + +proc p2pRequestCompleteUserHandler(peer: Peer) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + const + perProtocolMsgId = 125 + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + discard + +proc statusThunk(peer: Peer; _`gensym85175033: int; data`gensym85175034: Rlp) {.async, + gcsafe.} = + var rlp = data`gensym85175034 + var msg {.noinit.}: statusObj + tryEnterList(rlp) + msg.protocolVersion = checkedRlpRead(peer, rlp, uint) + msg.powConverted = checkedRlpRead(peer, rlp, uint64) + msg.bloom = checkedRlpRead(peer, rlp, seq[byte]) + msg.isLightNode = checkedRlpRead(peer, rlp, bool) + +proc messagesThunk(peer: Peer; _`gensym85175057: int; data`gensym85175058: Rlp) {. + async, gcsafe.} = + var rlp = data`gensym85175058 + var msg {.noinit.}: messagesObj + msg.envelopes = checkedRlpRead(peer, rlp, openarray[Envelope]) + await(messagesUserHandler(peer, msg.envelopes)) + +proc powRequirementThunk(peer: Peer; _`gensym85175059: int; data`gensym85175060: Rlp) {. + async, gcsafe.} = + var rlp = data`gensym85175060 + var msg {.noinit.}: powRequirementObj + msg.value = checkedRlpRead(peer, rlp, uint64) + await(powRequirementUserHandler(peer, msg.value)) + +proc bloomFilterExchangeThunk(peer: Peer; _`gensym85175061: int; + data`gensym85175062: Rlp) {.async, gcsafe.} = + var rlp = data`gensym85175062 + var msg {.noinit.}: bloomFilterExchangeObj + msg.bloom = checkedRlpRead(peer, rlp, openArray[byte]) + await(bloomFilterExchangeUserHandler(peer, msg.bloom)) + +proc p2pRequestThunk(peer: Peer; _`gensym85175063: int; data`gensym85175064: Rlp) {. + async, gcsafe.} = + var rlp = data`gensym85175064 + var msg {.noinit.}: p2pRequestObj + msg.envelope = checkedRlpRead(peer, rlp, Envelope) + await(p2pRequestUserHandler(peer, msg.envelope)) + +proc p2pMessageThunk(peer: Peer; _`gensym85175065: int; data`gensym85175066: Rlp) {. + async, gcsafe.} = + var rlp = data`gensym85175066 + var msg {.noinit.}: p2pMessageObj + msg.envelope = checkedRlpRead(peer, rlp, Envelope) + await(p2pMessageUserHandler(peer, msg.envelope)) + +proc batchAcknowledgedThunk(peer: Peer; _`gensym85175067: int; + data`gensym85175068: Rlp) {.async, gcsafe.} = + var rlp = data`gensym85175068 + var msg {.noinit.}: batchAcknowledgedObj + await(batchAcknowledgedUserHandler(peer)) + +proc messageResponseThunk(peer: Peer; _`gensym85175069: int; data`gensym85175070: Rlp) {. + async, gcsafe.} = + var rlp = data`gensym85175070 + var msg {.noinit.}: messageResponseObj + await(messageResponseUserHandler(peer)) + +proc p2pSyncResponseThunk(peer: Peer; _`gensym85175071: int; data`gensym85175072: Rlp) {. + async, gcsafe.} = + var rlp = data`gensym85175072 + var msg {.noinit.}: p2pSyncResponseObj + let reqId = read(rlp, int) + await(p2pSyncResponseUserHandler(peer, reqId)) + resolveResponseFuture(peer, perPeerMsgId(peer, p2pSyncResponseObj), addr(msg), + reqId) + +proc p2pSyncRequestThunk(peer: Peer; _`gensym85175075: int; data`gensym85175076: Rlp) {. + async, gcsafe.} = + var rlp = data`gensym85175076 + var msg {.noinit.}: p2pSyncRequestObj + let reqId = read(rlp, int) + await(p2pSyncRequestUserHandler(peer, reqId)) + +proc p2pRequestCompleteThunk(peer: Peer; _`gensym85175077: int; + data`gensym85175078: Rlp) {.async, gcsafe.} = + var rlp = data`gensym85175078 + var msg {.noinit.}: p2pRequestCompleteObj + await(p2pRequestCompleteUserHandler(peer)) + +registerMsg(WhisperProtocol, 0, "status", statusThunk, messagePrinter[statusObj], + requestResolver[statusObj], nextMsgResolver[statusObj]) +registerMsg(WhisperProtocol, 1, "messages", messagesThunk, + messagePrinter[messagesObj], requestResolver[messagesObj], + nextMsgResolver[messagesObj]) +registerMsg(WhisperProtocol, 2, "powRequirement", powRequirementThunk, + messagePrinter[powRequirementObj], + requestResolver[powRequirementObj], + nextMsgResolver[powRequirementObj]) +registerMsg(WhisperProtocol, 3, "bloomFilterExchange", bloomFilterExchangeThunk, + messagePrinter[bloomFilterExchangeObj], + requestResolver[bloomFilterExchangeObj], + nextMsgResolver[bloomFilterExchangeObj]) +registerMsg(WhisperProtocol, 126, "p2pRequest", p2pRequestThunk, + messagePrinter[p2pRequestObj], requestResolver[p2pRequestObj], + nextMsgResolver[p2pRequestObj]) +registerMsg(WhisperProtocol, 127, "p2pMessage", p2pMessageThunk, + messagePrinter[p2pMessageObj], requestResolver[p2pMessageObj], + nextMsgResolver[p2pMessageObj]) +registerMsg(WhisperProtocol, 11, "batchAcknowledged", batchAcknowledgedThunk, + messagePrinter[batchAcknowledgedObj], + requestResolver[batchAcknowledgedObj], + nextMsgResolver[batchAcknowledgedObj]) +registerMsg(WhisperProtocol, 12, "messageResponse", messageResponseThunk, + messagePrinter[messageResponseObj], + requestResolver[messageResponseObj], + nextMsgResolver[messageResponseObj]) +registerMsg(WhisperProtocol, 124, "p2pSyncResponse", p2pSyncResponseThunk, + messagePrinter[p2pSyncResponseObj], + requestResolver[p2pSyncResponseObj], + nextMsgResolver[p2pSyncResponseObj]) +registerMsg(WhisperProtocol, 123, "p2pSyncRequest", p2pSyncRequestThunk, + messagePrinter[p2pSyncRequestObj], + requestResolver[p2pSyncRequestObj], + nextMsgResolver[p2pSyncRequestObj]) +registerMsg(WhisperProtocol, 125, "p2pRequestComplete", p2pRequestCompleteThunk, + messagePrinter[p2pRequestCompleteObj], + requestResolver[p2pRequestCompleteObj], + nextMsgResolver[p2pRequestCompleteObj]) +proc WhisperPeerConnected(peer: Peer) {.gcsafe, async.} = + type + CurrentProtocol = Whisper + template state(peer: Peer): ref[WhisperPeer:ObjectType] = + cast[ref[WhisperPeer:ObjectType]](getState(peer, WhisperProtocol)) + + template networkState(peer: Peer): ref[WhisperNetwork:ObjectType] = + cast[ref[WhisperNetwork:ObjectType]](getNetworkState(peer.network, + WhisperProtocol)) + + trace "onPeerConnected Whisper" + let + whisperNet = peer.networkState + whisperPeer = peer.state + let m = await peer.status(whisperVersion, + cast[uint64](whisperNet.config.powRequirement), + @(whisperNet.config.bloom), + whisperNet.config.isLightNode, + timeout = chronos.milliseconds(5000)) + if m.protocolVersion == whisperVersion: + debug "Whisper peer", peer, whisperVersion + else: + raise newException(UselessPeerError, "Incompatible Whisper version") + whisperPeer.powRequirement = cast[float64](m.powConverted) + if m.bloom.len > 0: + if m.bloom.len != bloomSize: + raise newException(UselessPeerError, "Bloomfilter size mismatch") + else: + whisperPeer.bloom.bytesCopy(m.bloom) + else: + whisperPeer.bloom = fullBloom() + whisperPeer.isLightNode = m.isLightNode + if whisperPeer.isLightNode and whisperNet.config.isLightNode: + raise newException(UselessPeerError, "Two light nodes connected") + whisperPeer.received.init() + whisperPeer.trusted = false + whisperPeer.initialized = true + if not whisperNet.config.isLightNode: + traceAsyncErrors peer.run() + debug "Whisper peer initialized", peer + +setEventHandlers(WhisperProtocol, WhisperPeerConnected, nil) +registerProtocol(WhisperProtocol) \ No newline at end of file