mirror of
https://github.com/status-im/nim-eth.git
synced 2025-02-04 10:24:10 +00:00
2c236f6495
Currently only setting `--styleCheck:hint` as there are some dependency fixes required and the compiler seems to trip over the findnode MessageKind, findnode Message field and the findNode proc. Also over protocol.Protocol usage.
145 lines
3.7 KiB
Nim
145 lines
3.7 KiB
Nim
# nim-eth - Node Discovery Protocol v5
|
|
# Copyright (c) 2020-2021 Status Research & Development GmbH
|
|
# Licensed and distributed under either of
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
#
|
|
## Discovery v5 Protocol Messages as specified at
|
|
## https://github.com/ethereum/devp2p/blob/master/discv5/discv5-wire.md#protocol-messages
|
|
## These messages get RLP encoded.
|
|
##
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
import
|
|
std/[hashes, net],
|
|
stew/arrayops,
|
|
../../rlp, ./enr
|
|
|
|
type
|
|
MessageKind* = enum
|
|
# TODO This is needed only to make Nim 1.2.6 happy
|
|
# Without it, the `MessageKind` type cannot be used as
|
|
# a discriminator in case objects.
|
|
unused = 0x00
|
|
|
|
ping = 0x01
|
|
pong = 0x02
|
|
findnode = 0x03
|
|
nodes = 0x04
|
|
talkreq = 0x05
|
|
talkresp = 0x06
|
|
regtopic = 0x07
|
|
ticket = 0x08
|
|
regconfirmation = 0x09
|
|
topicquery = 0x0A
|
|
|
|
RequestId* = object
|
|
id*: seq[byte]
|
|
|
|
PingMessage* = object
|
|
enrSeq*: uint64
|
|
|
|
PongMessage* = object
|
|
enrSeq*: uint64
|
|
ip*: IpAddress
|
|
port*: uint16
|
|
|
|
FindNodeMessage* = object
|
|
distances*: seq[uint16]
|
|
|
|
NodesMessage* = object
|
|
total*: uint32
|
|
enrs*: seq[Record]
|
|
|
|
TalkReqMessage* = object
|
|
protocol*: seq[byte]
|
|
request*: seq[byte]
|
|
|
|
TalkRespMessage* = object
|
|
response*: seq[byte]
|
|
|
|
# Not implemented, specification is not final here.
|
|
RegTopicMessage* = object
|
|
TicketMessage* = object
|
|
RegConfirmationMessage* = object
|
|
TopicQueryMessage* = object
|
|
|
|
SomeMessage* = PingMessage or PongMessage or FindNodeMessage or NodesMessage or
|
|
TalkReqMessage or TalkRespMessage
|
|
|
|
Message* = object
|
|
reqId*: RequestId
|
|
case kind*: MessageKind
|
|
of ping:
|
|
ping*: PingMessage
|
|
of pong:
|
|
pong*: PongMessage
|
|
of findnode:
|
|
findnode*: FindNodeMessage
|
|
of nodes:
|
|
nodes*: NodesMessage
|
|
of talkreq:
|
|
talkreq*: TalkReqMessage
|
|
of talkresp:
|
|
talkresp*: TalkRespMessage
|
|
of regtopic:
|
|
regtopic*: RegTopicMessage
|
|
of ticket:
|
|
ticket*: TicketMessage
|
|
of regconfirmation:
|
|
regconfirmation*: RegConfirmationMessage
|
|
of topicquery:
|
|
topicquery*: TopicQueryMessage
|
|
else:
|
|
discard
|
|
|
|
template messageKind*(T: typedesc[SomeMessage]): MessageKind =
|
|
when T is PingMessage: ping
|
|
elif T is PongMessage: pong
|
|
elif T is FindNodeMessage: findnode
|
|
elif T is NodesMessage: nodes
|
|
elif T is TalkReqMessage: talkreq
|
|
elif T is TalkRespMessage: talkresp
|
|
|
|
proc read*(rlp: var Rlp, T: type RequestId): T
|
|
{.raises: [ValueError, RlpError, Defect].} =
|
|
mixin read
|
|
var reqId: RequestId
|
|
reqId.id = rlp.toBytes()
|
|
if reqId.id.len > 8:
|
|
raise newException(ValueError, "RequestId is > 8 bytes")
|
|
rlp.skipElem()
|
|
|
|
reqId
|
|
|
|
proc append*(writer: var RlpWriter, value: RequestId) =
|
|
writer.append(value.id)
|
|
|
|
proc read*(rlp: var Rlp, T: type IpAddress): T
|
|
{.raises: [RlpError, Defect].} =
|
|
let ipBytes = rlp.toBytes()
|
|
rlp.skipElem()
|
|
|
|
if ipBytes.len == 4:
|
|
var ip: array[4, byte]
|
|
discard copyFrom(ip, ipBytes)
|
|
IpAddress(family: IPv4, address_v4: ip)
|
|
elif ipBytes.len == 16:
|
|
var ip: array[16, byte]
|
|
discard copyFrom(ip, ipBytes)
|
|
IpAddress(family: IPv6, address_v6: ip)
|
|
else:
|
|
raise newException(RlpTypeMismatch,
|
|
"Amount of bytes for IP address is different from 4 or 16")
|
|
|
|
proc append*(writer: var RlpWriter, ip: IpAddress) =
|
|
case ip.family:
|
|
of IpAddressFamily.IPv4:
|
|
writer.append(ip.address_v4)
|
|
of IpAddressFamily.IPv6: writer.append(ip.address_v6)
|
|
|
|
proc hash*(reqId: RequestId): Hash =
|
|
hash(reqId.id)
|