mirror of https://github.com/status-im/nim-eth.git
Allow LibP2P to break the ties with RLPx by allowing more natural RPC syntax
Integrate the Stew macro printer and use to store the generated code for Whisper
This commit is contained in:
parent
9375ccc3a9
commit
218192aa09
|
@ -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])
|
||||
|
|
|
@ -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.} =
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
Loading…
Reference in New Issue