Changes related to the new ETH interop spec

* RPC requests and responses with a single parameter are now inlined
This commit is contained in:
Zahary Karadjov 2019-09-08 17:56:10 -04:00
parent 98be627bcc
commit 14e99e0711
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
2 changed files with 58 additions and 30 deletions

View File

@ -1,5 +1,5 @@
import import
options, options, sequtils,
stew/shims/macros, chronos, faststreams/output_stream stew/shims/macros, chronos, faststreams/output_stream
type type
@ -15,7 +15,8 @@ type
kind*: MessageKind kind*: MessageKind
procDef*: NimNode procDef*: NimNode
timeoutParam*: NimNode timeoutParam*: NimNode
recIdent*: NimNode recName*: NimNode
strongRecName*: NimNode
recBody*: NimNode recBody*: NimNode
protocol*: P2PProtocol protocol*: P2PProtocol
response*: Message response*: Message
@ -346,7 +347,7 @@ proc hasReqId*(msg: Message): bool =
proc ResponderType(msg: Message): NimNode = proc ResponderType(msg: Message): NimNode =
var resp = if msg.kind == msgRequest: msg.response else: msg var resp = if msg.kind == msgRequest: msg.response else: msg
newTree(nnkBracketExpr, newTree(nnkBracketExpr,
msg.protocol.backend.ResponderType, resp.recIdent) msg.protocol.backend.ResponderType, resp.recName)
proc newMsg(protocol: P2PProtocol, kind: MessageKind, id: int, proc newMsg(protocol: P2PProtocol, kind: MessageKind, id: int,
procDef: NimNode, timeoutParam: NimNode = nil, procDef: NimNode, timeoutParam: NimNode = nil,
@ -361,18 +362,35 @@ proc newMsg(protocol: P2PProtocol, kind: MessageKind, id: int,
msgName = $msgIdent msgName = $msgIdent
recFields = newTree(nnkRecList) recFields = newTree(nnkRecList)
recBody = newTree(nnkObjectTy, newEmptyNode(), newEmptyNode(), recFields) recBody = newTree(nnkObjectTy, newEmptyNode(), newEmptyNode(), recFields)
recName = ident(msgName & "Obj") strongRecName = ident(msgName & "Obj")
recName = strongRecName
for param, paramType in procDef.typedParams(skip = 1): for param, paramType in procDef.typedParams(skip = 1):
recFields.add newTree(nnkIdentDefs, recFields.add newTree(nnkIdentDefs,
newTree(nnkPostfix, ident("*"), param), # The fields are public newTree(nnkPostfix, ident("*"), param), # The fields are public
chooseFieldType(paramType), # some types such as openarray chooseFieldType(paramType), # some types such as openarray
# are automatically remapped newEmptyNode()) # are automatically remapped
newEmptyNode())
result = Message(protocol: protocol, id: id, ident: msgIdent, kind: kind, if recFields.len == 1:
procDef: procDef, recIdent: recName, recBody: recBody, # When we have a single parameter, it's treated as the transferred message
timeoutParam: timeoutParam, response: response) # type. `recName` will be resolved to the message type that's intended
# for serialization while `strongRecName` will be a distinct type over
# which overloads such as `msgId` can be defined. We must use a distinct
# type because otherwise Nim may see multiple overloads defined over the
# same request parameter type and this will be an ambiguity error.
recName = recFields[0][1]
recBody = newTree(nnkDistinctTy, recName)
result = Message(protocol: protocol,
id: id,
ident: msgIdent,
kind: kind,
procDef: procDef,
recName: recName,
strongRecName: strongRecName,
recBody: recBody,
timeoutParam: timeoutParam,
response: response)
if procDef.body.kind != nnkEmpty: if procDef.body.kind != nnkEmpty:
var userHandler = copy procDef var userHandler = copy procDef
@ -482,9 +500,9 @@ proc createSendProc*(msg: Message,
def[3][0] = if procType == nnkMacroDef: def[3][0] = if procType == nnkMacroDef:
ident "untyped" ident "untyped"
elif msg.kind == msgRequest and not isRawSender: elif msg.kind == msgRequest and not isRawSender:
Fut(Opt(msg.response.recIdent)) Fut(Opt(msg.response.recName))
elif msg.kind == msgHandshake and not isRawSender: elif msg.kind == msgHandshake and not isRawSender:
Fut(msg.recIdent) Fut(msg.recName)
else: else:
Fut(Void) Fut(Void)
@ -518,13 +536,20 @@ proc writeParamsAsRecord*(params: openarray[NimNode],
writer, recordWriterCtx, writer, recordWriterCtx,
newLit($param), param) newLit($param), param)
result = quote do: if params.len > 1:
mixin init, writerType, beginRecord, endRecord result = quote do:
mixin init, writerType, beginRecord, endRecord
var `writer` = init(WriterType(`Format`), `outputStream`) var `writer` = init(WriterType(`Format`), `outputStream`)
var `recordWriterCtx` = beginRecord(`writer`, `RecordType`) var `recordWriterCtx` = beginRecord(`writer`, `RecordType`)
`appendParams` `appendParams`
endRecord(`writer`, `recordWriterCtx`) endRecord(`writer`, `recordWriterCtx`)
else:
let param = params[0]
result = quote do:
var `writer` = init(WriterType(`Format`), `outputStream`)
writeValue(`writer`, `param`)
proc useStandardBody*(sendProc: SendProc, proc useStandardBody*(sendProc: SendProc,
preSerializationStep: proc(stream: NimNode): NimNode, preSerializationStep: proc(stream: NimNode): NimNode,
@ -537,7 +562,7 @@ proc useStandardBody*(sendProc: SendProc,
initFuture = bindSym "initFuture" initFuture = bindSym "initFuture"
recipient = sendProc.peerParam recipient = sendProc.peerParam
msgRecName = msg.recIdent msgRecName = msg.recName
Format = msg.protocol.backend.SerializationFormat Format = msg.protocol.backend.SerializationFormat
preSerialization = if preSerializationStep.isNil: newStmtList() preSerialization = if preSerializationStep.isNil: newStmtList()
@ -591,7 +616,7 @@ proc createSerializer*(msg: Message, procType = nnkProcDef): NimNode =
serializer.msgParams, serializer.msgParams,
streamVar, streamVar,
msg.protocol.backend.SerializationFormat, msg.protocol.backend.SerializationFormat,
msg.recIdent) msg.recName)
return serializer.def return serializer.def
@ -612,10 +637,12 @@ proc genAwaitUserHandler*(msg: Message, receivedMsg: NimNode,
var userHandlerCall = newCall(msg.userHandler.name, leadingParams) var userHandlerCall = newCall(msg.userHandler.name, leadingParams)
for param, paramType in msg.procDef.typedParams(skip = 1): var params = toSeq(msg.procDef.typedParams(skip = 1))
# If there is user message handler, we'll place a call to it by if params.len > 1:
# unpacking the fields of the received message: for p in params:
userHandlerCall.add newDotExpr(receivedMsg, param) userHandlerCall.add newDotExpr(receivedMsg, p[0])
else:
userHandlerCall.add receivedMsg
return newCall("await", userHandlerCall) return newCall("await", userHandlerCall)
@ -646,7 +673,7 @@ proc createHandshakeTemplate*(msg: Message,
peerValue = forwardCall[1] peerValue = forwardCall[1]
timeoutValue = msg.timeoutParam[0] timeoutValue = msg.timeoutParam[0]
peerVarSym = genSym(nskLet, "peer") peerVarSym = genSym(nskLet, "peer")
msgRecName = msg.recIdent msgRecName = msg.recName
forwardCall[1] = peerVarSym forwardCall[1] = peerVarSym
forwardCall.del(forwardCall.len - 1) forwardCall.del(forwardCall.len - 1)
@ -771,12 +798,13 @@ proc genTypeSection*(p: P2PProtocol): NimNode =
let let
msgId = msg.id msgId = msg.id
msgName = msg.ident msgName = msg.ident
msgRecName = msg.recIdent msgRecName = msg.recName
msgStrongRecName = msg.strongRecName
msgRecBody = msg.recBody msgRecBody = msg.recBody
result.add quote do: result.add quote do:
# This is a type featuring a single field for each message param: # This is a type featuring a single field for each message param:
type `msgRecName`* = `msgRecBody` type `msgStrongRecName`* = `msgRecBody`
# Add a helper template for accessing the message type: # Add a helper template for accessing the message type:
# e.g. p2p.hello: # e.g. p2p.hello:
@ -784,8 +812,8 @@ proc genTypeSection*(p: P2PProtocol): NimNode =
# Add a helper template for obtaining the message Id for # Add a helper template for obtaining the message Id for
# a particular message type: # a particular message type:
template msgId*(T: type `msgRecName`): int = `msgId` template msgId*(T: type `msgStrongRecName`): int = `msgId`
template msgProtocol*(T: type `msgRecName`): type = `protocolName` template msgProtocol*(T: type `msgStrongRecName`): type = `protocolName`
proc genCode*(p: P2PProtocol): NimNode = proc genCode*(p: P2PProtocol): NimNode =
# TODO: try switching to a simpler for msg in p.messages: loop # TODO: try switching to a simpler for msg in p.messages: loop

View File

@ -609,9 +609,9 @@ proc p2pProtocolBackendImpl*(protocol: P2PProtocol): Backend =
msgId = msg.id msgId = msg.id
msgIdent = msg.ident msgIdent = msg.ident
msgName = $msgIdent msgName = $msgIdent
msgRecName = msg.recIdent msgRecName = msg.recName
responseMsgId = if msg.response != nil: msg.response.id else: -1 responseMsgId = if msg.response != nil: msg.response.id else: -1
ResponseRecord = if msg.response != nil: msg.response.recIdent else: nil ResponseRecord = if msg.response != nil: msg.response.recName else: nil
hasReqId = msg.hasReqId hasReqId = msg.hasReqId
protocol = msg.protocol protocol = msg.protocol
userPragmas = msg.procDef.pragma userPragmas = msg.procDef.pragma