Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discv5 factorize #480

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
65 changes: 1 addition & 64 deletions eth/p2p/discoveryv5/encoding.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import
std/[tables, options, hashes, net],
nimcrypto, stint, chronicles, bearssl, stew/[results, byteutils], metrics,
".."/../[rlp, keys],
"."/[messages, node, enr, hkdf, sessions]
"."/[messages, messages_encoding, node, enr, hkdf, sessions]

from stew/objects import checkedEnumAssign

Expand Down Expand Up @@ -367,50 +367,6 @@ proc decodeHeader*(id: NodeId, iv, maskedHeader: openArray[byte]):
ok((StaticHeader(authdataSize: authdataSize, flag: flag, nonce: nonce),
staticHeader & authdata))

proc decodeMessage*(body: openArray[byte]): DecodeResult[Message] =
## Decodes to the specific `Message` type.
if body.len < 1:
return err("No message data")

var kind: MessageKind
if not checkedEnumAssign(kind, body[0]):
return err("Invalid message type")

var message = Message(kind: kind)
var rlp = rlpFromBytes(body.toOpenArray(1, body.high))
if rlp.enterList:
try:
message.reqId = rlp.read(RequestId)
except RlpError, ValueError:
return err("Invalid request-id")

proc decode[T](rlp: var Rlp, v: var T)
{.nimcall, raises:[RlpError, ValueError, Defect].} =
for k, v in v.fieldPairs:
v = rlp.read(typeof(v))

try:
case kind
of unused: return err("Invalid message type")
of ping: rlp.decode(message.ping)
of pong: rlp.decode(message.pong)
of findNode: rlp.decode(message.findNode)
of nodes: rlp.decode(message.nodes)
of talkReq: rlp.decode(message.talkReq)
of talkResp: rlp.decode(message.talkResp)
of regTopic, ticket, regConfirmation, topicQuery:
# We just pass the empty type of this message without attempting to
# decode, so that the protocol knows what was received.
# But we ignore the message as per specification as "the content and
# semantics of this message are not final".
discard
except RlpError, ValueError:
return err("Invalid message encoding")

ok(message)
else:
err("Invalid message encoding: no rlp list")

proc decodeMessagePacket(c: var Codec, fromAddr: Address, nonce: AESGCMNonce,
iv, header, ct: openArray[byte]): DecodeResult[Packet] =
# We now know the exact size that the header should be
Expand Down Expand Up @@ -602,22 +558,3 @@ proc decodePacket*(c: var Codec, fromAddr: Address, input: openArray[byte]):
return decodeHandshakePacket(c, fromAddr, staticHeader.nonce,
input.toOpenArray(0, ivSize - 1), header,
input.toOpenArray(ivSize + header.len, input.high))

proc init*(T: type RequestId, rng: var BrHmacDrbgContext): T =
var reqId = RequestId(id: newSeq[byte](8)) # RequestId must be <= 8 bytes
brHmacDrbgGenerate(rng, reqId.id)
reqId

proc numFields(T: typedesc): int =
for k, v in fieldPairs(default(T)): inc result

proc encodeMessage*[T: SomeMessage](p: T, reqId: RequestId): seq[byte] =
result = newSeqOfCap[byte](64)
result.add(messageKind(T).ord)

const sz = numFields(T)
var writer = initRlpList(sz + 1)
writer.append(reqId)
for k, v in fieldPairs(p):
writer.append(v)
result.add(writer.finish())
2 changes: 1 addition & 1 deletion eth/p2p/discoveryv5/enr.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import
stew/shims/net, stew/[base64, results], nimcrypto,
".."/../[rlp, keys]

export options, results, keys
export options, results

const
maxEnrSize = 300 ## Maximum size of an encoded node record, in bytes.
Expand Down
8 changes: 7 additions & 1 deletion eth/p2p/discoveryv5/messages.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
import
std/[hashes, net],
stew/arrayops,
../../rlp, ./enr
".."/../[rlp, keys],
./enr

type
MessageKind* = enum
Expand Down Expand Up @@ -142,3 +143,8 @@ proc append*(writer: var RlpWriter, ip: IpAddress) =

proc hash*(reqId: RequestId): Hash =
hash(reqId.id)

proc init*(T: type RequestId, rng: var BrHmacDrbgContext): T =
var reqId = RequestId(id: newSeq[byte](8)) # RequestId must be <= 8 bytes
brHmacDrbgGenerate(rng, reqId.id)
reqId
67 changes: 67 additions & 0 deletions eth/p2p/discoveryv5/messages_encoding.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import
".."/../[rlp],
"."/[messages, enr]

from stew/objects import checkedEnumAssign

type
DecodeResult*[T] = Result[T, cstring]

proc numFields(T: typedesc): int =
for k, v in fieldPairs(default(T)): inc result

proc encodeMessage*[T: SomeMessage](p: T, reqId: RequestId): seq[byte] =
result = newSeqOfCap[byte](64)
result.add(messageKind(T).ord)

const sz = numFields(T)
var writer = initRlpList(sz + 1)
writer.append(reqId)
for k, v in fieldPairs(p):
writer.append(v)
result.add(writer.finish())

proc decodeMessage*(body: openArray[byte]): DecodeResult[Message] =
## Decodes to the specific `Message` type.
if body.len < 1:
return err("No message data")

var kind: MessageKind
if not checkedEnumAssign(kind, body[0]):
return err("Invalid message type")

var message = Message(kind: kind)
var rlp = rlpFromBytes(body.toOpenArray(1, body.high))
if rlp.enterList:
try:
message.reqId = rlp.read(RequestId)
except RlpError, ValueError:
return err("Invalid request-id")

proc decode[T](rlp: var Rlp, v: var T)
{.nimcall, raises:[RlpError, ValueError, Defect].} =
for k, v in v.fieldPairs:
v = rlp.read(typeof(v))

try:
case kind
of unused: return err("Invalid message type")
of ping: rlp.decode(message.ping)
of pong: rlp.decode(message.pong)
of findNode: rlp.decode(message.findNode)
of nodes: rlp.decode(message.nodes)
of talkReq: rlp.decode(message.talkReq)
of talkResp: rlp.decode(message.talkResp)
of regTopic, ticket, regConfirmation, topicQuery:
# We just pass the empty type of this message without attempting to
# decode, so that the protocol knows what was received.
# But we ignore the message as per specification as "the content and
# semantics of this message are not final".
discard
except RlpError, ValueError:
return err("Invalid message encoding")

ok(message)
else:
err("Invalid message encoding: no rlp list")

Loading