mirror of https://github.com/status-im/nim-eth.git
Bunch of renames to use same nomenclature as spec
This commit is contained in:
parent
09a127ef1b
commit
3a6d4336bc
|
@ -45,7 +45,7 @@ type
|
||||||
HandshakeError,
|
HandshakeError,
|
||||||
PacketError,
|
PacketError,
|
||||||
DecryptError,
|
DecryptError,
|
||||||
UnsupportedPacketType
|
UnsupportedMessage
|
||||||
|
|
||||||
DecodeResult*[T] = Result[T, DecodeError]
|
DecodeResult*[T] = Result[T, DecodeError]
|
||||||
EncodeResult*[T] = Result[T, cstring]
|
EncodeResult*[T] = Result[T, cstring]
|
||||||
|
@ -90,7 +90,7 @@ proc encryptGCM*(key, nonce, pt, authData: openarray[byte]):
|
||||||
ectx.getTag(result.toOpenArray(pt.len, result.high))
|
ectx.getTag(result.toOpenArray(pt.len, result.high))
|
||||||
ectx.clear()
|
ectx.clear()
|
||||||
|
|
||||||
proc makeAuthHeader(c: Codec,
|
proc encodeAuthHeader(c: Codec,
|
||||||
toId: NodeID,
|
toId: NodeID,
|
||||||
nonce: array[gcmNonceSize, byte],
|
nonce: array[gcmNonceSize, byte],
|
||||||
handshakeSecrets: var HandshakeSecrets,
|
handshakeSecrets: var HandshakeSecrets,
|
||||||
|
@ -132,10 +132,10 @@ proc packetTag(destNode, srcNode: NodeID): PacketTag {.raises:[].} =
|
||||||
destidHash = sha256.digest(destId)
|
destidHash = sha256.digest(destId)
|
||||||
result = srcId xor destidHash.data
|
result = srcId xor destidHash.data
|
||||||
|
|
||||||
proc encodeEncrypted*(c: Codec,
|
proc encodePacket*(c: Codec,
|
||||||
toId: NodeID,
|
toId: NodeID,
|
||||||
toAddr: Address,
|
toAddr: Address,
|
||||||
packetData: seq[byte],
|
message: seq[byte],
|
||||||
challenge: Whoareyou):
|
challenge: Whoareyou):
|
||||||
EncodeResult[(seq[byte], array[gcmNonceSize, byte])] =
|
EncodeResult[(seq[byte], array[gcmNonceSize, byte])] =
|
||||||
var nonce: array[gcmNonceSize, byte]
|
var nonce: array[gcmNonceSize, byte]
|
||||||
|
@ -155,21 +155,19 @@ proc encodeEncrypted*(c: Codec,
|
||||||
discard c.db.loadKeys(toId, toAddr, readKey, writeKey)
|
discard c.db.loadKeys(toId, toAddr, readKey, writeKey)
|
||||||
else:
|
else:
|
||||||
var sec: HandshakeSecrets
|
var sec: HandshakeSecrets
|
||||||
headEnc = ? c.makeAuthHeader(toId, nonce, sec, challenge)
|
headEnc = ? c.encodeAuthHeader(toId, nonce, sec, challenge)
|
||||||
|
|
||||||
writeKey = sec.writeKey
|
writeKey = sec.writeKey
|
||||||
# TODO: is it safe to ignore the error here?
|
# TODO: is it safe to ignore the error here?
|
||||||
discard c.db.storeKeys(toId, toAddr, sec.readKey, sec.writeKey)
|
discard c.db.storeKeys(toId, toAddr, sec.readKey, sec.writeKey)
|
||||||
|
|
||||||
var body = packetData
|
|
||||||
let tag = packetTag(toId, c.localNode.id)
|
let tag = packetTag(toId, c.localNode.id)
|
||||||
|
|
||||||
var headBuf = newSeqOfCap[byte](tag.len + headEnc.len)
|
var packet = newSeqOfCap[byte](tag.len + headEnc.len)
|
||||||
headBuf.add(tag)
|
packet.add(tag)
|
||||||
headBuf.add(headEnc)
|
packet.add(headEnc)
|
||||||
|
packet.add(encryptGCM(writeKey, nonce, message, tag))
|
||||||
headBuf.add(encryptGCM(writeKey, nonce, body, tag))
|
ok((packet, nonce))
|
||||||
ok((headBuf, nonce))
|
|
||||||
|
|
||||||
proc decryptGCM*(key: AesKey, nonce, ct, authData: openarray[byte]):
|
proc decryptGCM*(key: AesKey, nonce, ct, authData: openarray[byte]):
|
||||||
Option[seq[byte]] {.raises:[].} =
|
Option[seq[byte]] {.raises:[].} =
|
||||||
|
@ -190,20 +188,20 @@ proc decryptGCM*(key: AesKey, nonce, ct, authData: openarray[byte]):
|
||||||
|
|
||||||
return some(res)
|
return some(res)
|
||||||
|
|
||||||
proc decodePacketBody(body: openarray[byte]):
|
proc decodeMessage(body: openarray[byte]):
|
||||||
DecodeResult[Packet] {.raises:[Defect].} =
|
DecodeResult[Message] {.raises:[Defect].} =
|
||||||
if body.len < 1:
|
if body.len < 1:
|
||||||
return err(PacketError)
|
return err(PacketError)
|
||||||
|
|
||||||
if body[0] < PacketKind.low.byte or body[0] > PacketKind.high.byte:
|
if body[0] < MessageKind.low.byte or body[0] > MessageKind.high.byte:
|
||||||
return err(PacketError)
|
return err(PacketError)
|
||||||
|
|
||||||
let kind = cast[PacketKind](body[0])
|
let kind = cast[MessageKind](body[0])
|
||||||
var packet = Packet(kind: kind)
|
var message = Message(kind: kind)
|
||||||
var rlp = rlpFromBytes(body.toOpenArray(1, body.high))
|
var rlp = rlpFromBytes(body.toOpenArray(1, body.high))
|
||||||
if rlp.enterList:
|
if rlp.enterList:
|
||||||
try:
|
try:
|
||||||
packet.reqId = rlp.read(RequestId)
|
message.reqId = rlp.read(RequestId)
|
||||||
except RlpError:
|
except RlpError:
|
||||||
return err(PacketError)
|
return err(PacketError)
|
||||||
|
|
||||||
|
@ -215,17 +213,17 @@ proc decodePacketBody(body: openarray[byte]):
|
||||||
try:
|
try:
|
||||||
case kind
|
case kind
|
||||||
of unused: return err(PacketError)
|
of unused: return err(PacketError)
|
||||||
of ping: rlp.decode(packet.ping)
|
of ping: rlp.decode(message.ping)
|
||||||
of pong: rlp.decode(packet.pong)
|
of pong: rlp.decode(message.pong)
|
||||||
of findNode: rlp.decode(packet.findNode)
|
of findNode: rlp.decode(message.findNode)
|
||||||
of nodes: rlp.decode(packet.nodes)
|
of nodes: rlp.decode(message.nodes)
|
||||||
of regtopic, ticket, regconfirmation, topicquery:
|
of regtopic, ticket, regconfirmation, topicquery:
|
||||||
# TODO: Implement support for topic advertisement
|
# TODO: Implement support for topic advertisement
|
||||||
return err(UnsupportedPacketType)
|
return err(UnsupportedMessage)
|
||||||
except RlpError, ValueError:
|
except RlpError, ValueError:
|
||||||
return err(PacketError)
|
return err(PacketError)
|
||||||
|
|
||||||
ok(packet)
|
ok(message)
|
||||||
else:
|
else:
|
||||||
err(PacketError)
|
err(PacketError)
|
||||||
|
|
||||||
|
@ -266,12 +264,12 @@ proc decodeAuthResp(c: Codec, fromId: NodeId, head: AuthHeader,
|
||||||
except KeyError, ValueError:
|
except KeyError, ValueError:
|
||||||
err(HandshakeError)
|
err(HandshakeError)
|
||||||
|
|
||||||
proc decodeEncrypted*(c: var Codec,
|
proc decodePacket*(c: var Codec,
|
||||||
fromId: NodeID,
|
fromId: NodeID,
|
||||||
fromAddr: Address,
|
fromAddr: Address,
|
||||||
input: openArray[byte],
|
input: openArray[byte],
|
||||||
authTag: var AuthTag,
|
authTag: var AuthTag,
|
||||||
newNode: var Node): DecodeResult[Packet] =
|
newNode: var Node): DecodeResult[Message] =
|
||||||
var r = rlpFromBytes(input.toOpenArray(tagSize, input.high))
|
var r = rlpFromBytes(input.toOpenArray(tagSize, input.high))
|
||||||
var auth: AuthHeader
|
var auth: AuthHeader
|
||||||
|
|
||||||
|
@ -327,15 +325,15 @@ proc decodeEncrypted*(c: var Codec,
|
||||||
|
|
||||||
let headSize = tagSize + r.position
|
let headSize = tagSize + r.position
|
||||||
|
|
||||||
let body = decryptGCM(
|
let message = decryptGCM(
|
||||||
readKey, auth.auth,
|
readKey, auth.auth,
|
||||||
input.toOpenArray(headSize, input.high),
|
input.toOpenArray(headSize, input.high),
|
||||||
input.toOpenArray(0, tagSize - 1))
|
input.toOpenArray(0, tagSize - 1))
|
||||||
if body.isNone():
|
if message.isNone():
|
||||||
discard c.db.deleteKeys(fromId, fromAddr)
|
discard c.db.deleteKeys(fromId, fromAddr)
|
||||||
return err(DecryptError)
|
return err(DecryptError)
|
||||||
|
|
||||||
decodePacketBody(body.get())
|
decodeMessage(message.get())
|
||||||
|
|
||||||
proc newRequestId*(): Result[RequestId, cstring] {.raises:[].} =
|
proc newRequestId*(): Result[RequestId, cstring] {.raises:[].} =
|
||||||
var id: RequestId
|
var id: RequestId
|
||||||
|
@ -347,10 +345,10 @@ proc newRequestId*(): Result[RequestId, cstring] {.raises:[].} =
|
||||||
proc numFields(T: typedesc): int {.raises:[].} =
|
proc numFields(T: typedesc): int {.raises:[].} =
|
||||||
for k, v in fieldPairs(default(T)): inc result
|
for k, v in fieldPairs(default(T)): inc result
|
||||||
|
|
||||||
proc encodePacket*[T: SomePacket](p: T, reqId: RequestId):
|
proc encodeMessage*[T: SomeMessage](p: T, reqId: RequestId):
|
||||||
seq[byte] {.raises:[].} =
|
seq[byte] {.raises:[].} =
|
||||||
result = newSeqOfCap[byte](64)
|
result = newSeqOfCap[byte](64)
|
||||||
result.add(packetKind(T).ord)
|
result.add(messageKind(T).ord)
|
||||||
|
|
||||||
const sz = numFields(T)
|
const sz = numFields(T)
|
||||||
var writer = initRlpList(sz + 1)
|
var writer = initRlpList(sz + 1)
|
||||||
|
|
|
@ -89,7 +89,7 @@ const
|
||||||
alpha = 3 ## Kademlia concurrency factor
|
alpha = 3 ## Kademlia concurrency factor
|
||||||
lookupRequestLimit = 3
|
lookupRequestLimit = 3
|
||||||
findNodeResultLimit = 15 # applies in FINDNODE handler
|
findNodeResultLimit = 15 # applies in FINDNODE handler
|
||||||
maxNodesPerPacket = 3
|
maxNodesPerMessage = 3
|
||||||
lookupInterval = 60.seconds ## Interval of launching a random lookup to
|
lookupInterval = 60.seconds ## Interval of launching a random lookup to
|
||||||
## populate the routing table. go-ethereum seems to do 3 runs every 30
|
## populate the routing table. go-ethereum seems to do 3 runs every 30
|
||||||
## minutes. Trinity starts one every minute.
|
## minutes. Trinity starts one every minute.
|
||||||
|
@ -111,14 +111,14 @@ type
|
||||||
db: Database
|
db: Database
|
||||||
routingTable: RoutingTable
|
routingTable: RoutingTable
|
||||||
codec*: Codec
|
codec*: Codec
|
||||||
awaitedPackets: Table[(NodeId, RequestId), Future[Option[Packet]]]
|
awaitedMessages: Table[(NodeId, RequestId), Future[Option[Message]]]
|
||||||
lookupLoop: Future[void]
|
lookupLoop: Future[void]
|
||||||
revalidateLoop: Future[void]
|
revalidateLoop: Future[void]
|
||||||
bootstrapRecords*: seq[Record]
|
bootstrapRecords*: seq[Record]
|
||||||
|
|
||||||
PendingRequest = object
|
PendingRequest = object
|
||||||
node: Node
|
node: Node
|
||||||
packet: seq[byte]
|
message: seq[byte]
|
||||||
|
|
||||||
RandomSourceDepleted* = object of CatchableError
|
RandomSourceDepleted* = object of CatchableError
|
||||||
|
|
||||||
|
@ -173,13 +173,13 @@ proc whoareyouMagic(toNode: NodeId): array[magicSize, byte] =
|
||||||
for i, c in prefix: data[sizeof(toNode) + i] = byte(c)
|
for i, c in prefix: data[sizeof(toNode) + i] = byte(c)
|
||||||
sha256.digest(data).data
|
sha256.digest(data).data
|
||||||
|
|
||||||
proc isWhoAreYou(d: Protocol, msg: openArray[byte]): bool =
|
proc isWhoAreYou(d: Protocol, packet: openArray[byte]): bool =
|
||||||
if msg.len > d.whoareyouMagic.len:
|
if packet.len > d.whoareyouMagic.len:
|
||||||
result = d.whoareyouMagic == msg.toOpenArray(0, magicSize - 1)
|
result = d.whoareyouMagic == packet.toOpenArray(0, magicSize - 1)
|
||||||
|
|
||||||
proc decodeWhoAreYou(d: Protocol, msg: openArray[byte]): Whoareyou =
|
proc decodeWhoAreYou(d: Protocol, packet: openArray[byte]): Whoareyou =
|
||||||
result = Whoareyou()
|
result = Whoareyou()
|
||||||
result[] = rlp.decode(msg.toOpenArray(magicSize, msg.high), WhoareyouObj)
|
result[] = rlp.decode(packet.toOpenArray(magicSize, packet.high), WhoareyouObj)
|
||||||
|
|
||||||
proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId, authTag: AuthTag) =
|
proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId, authTag: AuthTag) =
|
||||||
trace "sending who are you", to = $toNode, toAddress = $address
|
trace "sending who are you", to = $toNode, toAddress = $address
|
||||||
|
@ -210,39 +210,39 @@ proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId, authTag: AuthT
|
||||||
proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, reqId: RequestId,
|
proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, reqId: RequestId,
|
||||||
nodes: openarray[Node]) =
|
nodes: openarray[Node]) =
|
||||||
proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address,
|
proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address,
|
||||||
packet: NodesPacket, reqId: RequestId) {.nimcall.} =
|
message: NodesMessage, reqId: RequestId) {.nimcall.} =
|
||||||
let (data, _) = d.codec.encodeEncrypted(toId, toAddr,
|
let (data, _) = d.codec.encodePacket(toId, toAddr,
|
||||||
encodePacket(packet, reqId), challenge = nil).tryGet()
|
encodeMessage(message, reqId), challenge = nil).tryGet()
|
||||||
d.send(toAddr, data)
|
d.send(toAddr, data)
|
||||||
|
|
||||||
var packet: NodesPacket
|
var message: NodesMessage
|
||||||
packet.total = ceil(nodes.len / maxNodesPerPacket).uint32
|
message.total = ceil(nodes.len / maxNodesPerMessage).uint32
|
||||||
|
|
||||||
for i in 0 ..< nodes.len:
|
for i in 0 ..< nodes.len:
|
||||||
packet.enrs.add(nodes[i].record)
|
message.enrs.add(nodes[i].record)
|
||||||
if packet.enrs.len == 3:
|
if message.enrs.len == 3: # TODO: Uh, what is this?
|
||||||
d.sendNodes(toId, toAddr, packet, reqId)
|
d.sendNodes(toId, toAddr, message, reqId)
|
||||||
packet.enrs.setLen(0)
|
message.enrs.setLen(0)
|
||||||
|
|
||||||
if packet.enrs.len != 0:
|
if message.enrs.len != 0:
|
||||||
d.sendNodes(toId, toAddr, packet, reqId)
|
d.sendNodes(toId, toAddr, message, reqId)
|
||||||
|
|
||||||
proc handlePing(d: Protocol, fromId: NodeId, fromAddr: Address,
|
proc handlePing(d: Protocol, fromId: NodeId, fromAddr: Address,
|
||||||
ping: PingPacket, reqId: RequestId) =
|
ping: PingMessage, reqId: RequestId) =
|
||||||
let a = fromAddr
|
let a = fromAddr
|
||||||
var pong: PongPacket
|
var pong: PongMessage
|
||||||
pong.enrSeq = ping.enrSeq
|
pong.enrSeq = ping.enrSeq
|
||||||
pong.ip = case a.ip.family
|
pong.ip = case a.ip.family
|
||||||
of IpAddressFamily.IPv4: @(a.ip.address_v4)
|
of IpAddressFamily.IPv4: @(a.ip.address_v4)
|
||||||
of IpAddressFamily.IPv6: @(a.ip.address_v6)
|
of IpAddressFamily.IPv6: @(a.ip.address_v6)
|
||||||
pong.port = a.udpPort.uint16
|
pong.port = a.udpPort.uint16
|
||||||
|
|
||||||
let (data, _) = d.codec.encodeEncrypted(fromId, fromAddr,
|
let (data, _) = d.codec.encodePacket(fromId, fromAddr,
|
||||||
encodePacket(pong, reqId), challenge = nil).tryGet()
|
encodeMessage(pong, reqId), challenge = nil).tryGet()
|
||||||
d.send(fromAddr, data)
|
d.send(fromAddr, data)
|
||||||
|
|
||||||
proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address,
|
proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address,
|
||||||
fn: FindNodePacket, reqId: RequestId) =
|
fn: FindNodeMessage, reqId: RequestId) =
|
||||||
if fn.distance == 0:
|
if fn.distance == 0:
|
||||||
d.sendNodes(fromId, fromAddr, reqId, [d.localNode])
|
d.sendNodes(fromId, fromAddr, reqId, [d.localNode])
|
||||||
else:
|
else:
|
||||||
|
@ -250,7 +250,7 @@ proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address,
|
||||||
d.sendNodes(fromId, fromAddr, reqId,
|
d.sendNodes(fromId, fromAddr, reqId,
|
||||||
d.routingTable.neighboursAtDistance(distance))
|
d.routingTable.neighboursAtDistance(distance))
|
||||||
|
|
||||||
proc receive*(d: Protocol, a: Address, msg: openArray[byte]) {.gcsafe,
|
proc receive*(d: Protocol, a: Address, packet: openArray[byte]) {.gcsafe,
|
||||||
raises: [
|
raises: [
|
||||||
Defect,
|
Defect,
|
||||||
# TODO This is now coming from Chronos's callSoon
|
# TODO This is now coming from Chronos's callSoon
|
||||||
|
@ -260,37 +260,37 @@ proc receive*(d: Protocol, a: Address, msg: openArray[byte]) {.gcsafe,
|
||||||
IOError,
|
IOError,
|
||||||
TransportAddressError,
|
TransportAddressError,
|
||||||
].} =
|
].} =
|
||||||
if msg.len < tagSize: # or magicSize, can be either
|
if packet.len < tagSize: # or magicSize, can be either
|
||||||
return # Invalid msg
|
return # Invalid packet
|
||||||
|
|
||||||
# debug "Packet received: ", length = msg.len
|
# debug "Packet received: ", length = packet.len
|
||||||
|
|
||||||
if d.isWhoAreYou(msg):
|
if d.isWhoAreYou(packet):
|
||||||
trace "Received whoareyou", localNode = $d.localNode, address = a
|
trace "Received whoareyou", localNode = $d.localNode, address = a
|
||||||
let whoareyou = d.decodeWhoAreYou(msg)
|
let whoareyou = d.decodeWhoAreYou(packet)
|
||||||
var pr: PendingRequest
|
var pr: PendingRequest
|
||||||
if d.pendingRequests.take(whoareyou.authTag, pr):
|
if d.pendingRequests.take(whoareyou.authTag, pr):
|
||||||
let toNode = pr.node
|
let toNode = pr.node
|
||||||
whoareyou.pubKey = toNode.node.pubkey # TODO: Yeah, rather ugly this.
|
whoareyou.pubKey = toNode.node.pubkey # TODO: Yeah, rather ugly this.
|
||||||
try:
|
try:
|
||||||
let (data, _) = d.codec.encodeEncrypted(toNode.id, toNode.address,
|
let (data, _) = d.codec.encodePacket(toNode.id, toNode.address,
|
||||||
pr.packet, challenge = whoareyou).tryGet()
|
pr.message, challenge = whoareyou).tryGet()
|
||||||
d.send(toNode, data)
|
d.send(toNode, data)
|
||||||
except RandomSourceDepleted:
|
except RandomSourceDepleted:
|
||||||
debug "Failed to respond to a who-you-are msg " &
|
debug "Failed to respond to a who-you-are packet " &
|
||||||
"due to randomness source depletion."
|
"due to randomness source depletion."
|
||||||
|
|
||||||
else:
|
else:
|
||||||
var tag: array[tagSize, byte]
|
var tag: array[tagSize, byte]
|
||||||
tag[0 .. ^1] = msg.toOpenArray(0, tagSize - 1)
|
tag[0 .. ^1] = packet.toOpenArray(0, tagSize - 1)
|
||||||
let senderData = tag xor d.idHash
|
let senderData = tag xor d.idHash
|
||||||
let sender = readUintBE[256](senderData)
|
let sender = readUintBE[256](senderData)
|
||||||
|
|
||||||
var authTag: AuthTag
|
var authTag: AuthTag
|
||||||
var node: Node
|
var node: Node
|
||||||
let decoded = d.codec.decodeEncrypted(sender, a, msg, authTag, node)
|
let decoded = d.codec.decodePacket(sender, a, packet, authTag, node)
|
||||||
if decoded.isOk:
|
if decoded.isOk:
|
||||||
let packet = decoded[]
|
let message = decoded[]
|
||||||
if not node.isNil:
|
if not node.isNil:
|
||||||
# Not filling table with nodes without correct IP in the ENR
|
# Not filling table with nodes without correct IP in the ENR
|
||||||
if a.ip == node.address.ip:
|
if a.ip == node.address.ip:
|
||||||
|
@ -298,24 +298,25 @@ proc receive*(d: Protocol, a: Address, msg: openArray[byte]) {.gcsafe,
|
||||||
localNode = $d.localNode
|
localNode = $d.localNode
|
||||||
discard d.routingTable.addNode(node)
|
discard d.routingTable.addNode(node)
|
||||||
|
|
||||||
case packet.kind
|
case message.kind
|
||||||
of ping:
|
of ping:
|
||||||
d.handlePing(sender, a, packet.ping, packet.reqId)
|
d.handlePing(sender, a, message.ping, message.reqId)
|
||||||
of findNode:
|
of findNode:
|
||||||
d.handleFindNode(sender, a, packet.findNode, packet.reqId)
|
d.handleFindNode(sender, a, message.findNode, message.reqId)
|
||||||
else:
|
else:
|
||||||
var waiter: Future[Option[Packet]]
|
var waiter: Future[Option[Message]]
|
||||||
if d.awaitedPackets.take((sender, packet.reqId), waiter):
|
if d.awaitedMessages.take((sender, message.reqId), waiter):
|
||||||
waiter.complete(packet.some)
|
waiter.complete(some(message))
|
||||||
else:
|
else:
|
||||||
debug "TODO: handle packet: ", packet = packet.kind, origin = a
|
trace "Timed out or unrequested message", message = message.kind,
|
||||||
|
origin = a
|
||||||
elif decoded.error == DecodeError.DecryptError:
|
elif decoded.error == DecodeError.DecryptError:
|
||||||
debug "Could not decrypt packet, respond with whoareyou",
|
debug "Could not decrypt packet, respond with whoareyou",
|
||||||
localNode = $d.localNode, address = a
|
localNode = $d.localNode, address = a
|
||||||
# only sendingWhoareyou in case it is a decryption failure
|
# only sendingWhoareyou in case it is a decryption failure
|
||||||
d.sendWhoareyou(a, sender, authTag)
|
d.sendWhoareyou(a, sender, authTag)
|
||||||
elif decoded.error == DecodeError.UnsupportedPacketType:
|
elif decoded.error == DecodeError.UnsupportedMessage:
|
||||||
# Still adding the node in case failure is because of unsupported packet.
|
# Still adding the node in case failure is because of unsupported message.
|
||||||
if not node.isNil:
|
if not node.isNil:
|
||||||
if a.ip == node.address.ip:
|
if a.ip == node.address.ip:
|
||||||
debug "Adding new node to routing table", node = $node,
|
debug "Adding new node to routing table", node = $node,
|
||||||
|
@ -361,32 +362,32 @@ proc validIp(sender, address: IpAddress): bool =
|
||||||
# TODO: This could be improved to do the clean-up immediatily in case a non
|
# TODO: This could be improved to do the clean-up immediatily in case a non
|
||||||
# whoareyou response does arrive, but we would need to store the AuthTag
|
# whoareyou response does arrive, but we would need to store the AuthTag
|
||||||
# somewhere
|
# somewhere
|
||||||
proc registerRequest(d: Protocol, n: Node, packet: seq[byte], nonce: AuthTag) =
|
proc registerRequest(d: Protocol, n: Node, message: seq[byte], nonce: AuthTag) =
|
||||||
let request = PendingRequest(node: n, packet: packet)
|
let request = PendingRequest(node: n, message: message)
|
||||||
if not d.pendingRequests.hasKeyOrPut(nonce, request):
|
if not d.pendingRequests.hasKeyOrPut(nonce, request):
|
||||||
sleepAsync(responseTimeout).addCallback() do(data: pointer):
|
sleepAsync(responseTimeout).addCallback() do(data: pointer):
|
||||||
d.pendingRequests.del(nonce)
|
d.pendingRequests.del(nonce)
|
||||||
|
|
||||||
proc waitPacket(d: Protocol, fromNode: Node, reqId: RequestId): Future[Option[Packet]] =
|
proc waitMessage(d: Protocol, fromNode: Node, reqId: RequestId): Future[Option[Message]] =
|
||||||
result = newFuture[Option[Packet]]("waitPacket")
|
result = newFuture[Option[Message]]("waitMessage")
|
||||||
let res = result
|
let res = result
|
||||||
let key = (fromNode.id, reqId)
|
let key = (fromNode.id, reqId)
|
||||||
sleepAsync(responseTimeout).addCallback() do(data: pointer):
|
sleepAsync(responseTimeout).addCallback() do(data: pointer):
|
||||||
d.awaitedPackets.del(key)
|
d.awaitedMessages.del(key)
|
||||||
if not res.finished:
|
if not res.finished:
|
||||||
res.complete(none(Packet))
|
res.complete(none(Message))
|
||||||
d.awaitedPackets[key] = result
|
d.awaitedMessages[key] = result
|
||||||
|
|
||||||
proc addNodesFromENRs(result: var seq[Node], enrs: openarray[Record]) =
|
proc addNodesFromENRs(result: var seq[Node], enrs: openarray[Record]) =
|
||||||
for r in enrs: result.add(newNode(r))
|
for r in enrs: result.add(newNode(r))
|
||||||
|
|
||||||
proc waitNodes(d: Protocol, fromNode: Node, reqId: RequestId): Future[seq[Node]] {.async.} =
|
proc waitNodes(d: Protocol, fromNode: Node, reqId: RequestId): Future[seq[Node]] {.async.} =
|
||||||
var op = await d.waitPacket(fromNode, reqId)
|
var op = await d.waitMessage(fromNode, reqId)
|
||||||
if op.isSome and op.get.kind == nodes:
|
if op.isSome and op.get.kind == nodes:
|
||||||
result.addNodesFromENRs(op.get.nodes.enrs)
|
result.addNodesFromENRs(op.get.nodes.enrs)
|
||||||
let total = op.get.nodes.total
|
let total = op.get.nodes.total
|
||||||
for i in 1 ..< total:
|
for i in 1 ..< total:
|
||||||
op = await d.waitPacket(fromNode, reqId)
|
op = await d.waitMessage(fromNode, reqId)
|
||||||
if op.isSome and op.get.kind == nodes:
|
if op.isSome and op.get.kind == nodes:
|
||||||
result.addNodesFromENRs(op.get.nodes.enrs)
|
result.addNodesFromENRs(op.get.nodes.enrs)
|
||||||
else:
|
else:
|
||||||
|
@ -395,27 +396,27 @@ proc waitNodes(d: Protocol, fromNode: Node, reqId: RequestId): Future[seq[Node]]
|
||||||
proc sendPing(d: Protocol, toNode: Node): RequestId =
|
proc sendPing(d: Protocol, toNode: Node): RequestId =
|
||||||
let
|
let
|
||||||
reqId = newRequestId().tryGet()
|
reqId = newRequestId().tryGet()
|
||||||
ping = PingPacket(enrSeq: d.localNode.record.seqNum)
|
ping = PingMessage(enrSeq: d.localNode.record.seqNum)
|
||||||
packet = encodePacket(ping, reqId)
|
message = encodeMessage(ping, reqId)
|
||||||
(data, nonce) = d.codec.encodeEncrypted(toNode.id, toNode.address, packet,
|
(data, nonce) = d.codec.encodePacket(toNode.id, toNode.address, message,
|
||||||
challenge = nil).tryGet()
|
challenge = nil).tryGet()
|
||||||
d.registerRequest(toNode, packet, nonce)
|
d.registerRequest(toNode, message, nonce)
|
||||||
d.send(toNode, data)
|
d.send(toNode, data)
|
||||||
return reqId
|
return reqId
|
||||||
|
|
||||||
proc ping*(d: Protocol, toNode: Node): Future[Option[PongPacket]] {.async.} =
|
proc ping*(d: Protocol, toNode: Node): Future[Option[PongMessage]] {.async.} =
|
||||||
let reqId = d.sendPing(toNode)
|
let reqId = d.sendPing(toNode)
|
||||||
let resp = await d.waitPacket(toNode, reqId)
|
let resp = await d.waitMessage(toNode, reqId)
|
||||||
|
|
||||||
if resp.isSome() and resp.get().kind == pong:
|
if resp.isSome() and resp.get().kind == pong:
|
||||||
return some(resp.get().pong)
|
return some(resp.get().pong)
|
||||||
|
|
||||||
proc sendFindNode(d: Protocol, toNode: Node, distance: uint32): RequestId =
|
proc sendFindNode(d: Protocol, toNode: Node, distance: uint32): RequestId =
|
||||||
let reqId = newRequestId().tryGet()
|
let reqId = newRequestId().tryGet()
|
||||||
let packet = encodePacket(FindNodePacket(distance: distance), reqId)
|
let message = encodeMessage(FindNodeMessage(distance: distance), reqId)
|
||||||
let (data, nonce) = d.codec.encodeEncrypted(toNode.id, toNode.address, packet,
|
let (data, nonce) = d.codec.encodePacket(toNode.id, toNode.address, message,
|
||||||
challenge = nil).tryGet()
|
challenge = nil).tryGet()
|
||||||
d.registerRequest(toNode, packet, nonce)
|
d.registerRequest(toNode, message, nonce)
|
||||||
|
|
||||||
d.send(toNode, data)
|
d.send(toNode, data)
|
||||||
return reqId
|
return reqId
|
||||||
|
|
|
@ -27,9 +27,9 @@ type
|
||||||
|
|
||||||
Database* = ref object of RootRef
|
Database* = ref object of RootRef
|
||||||
|
|
||||||
PacketKind* = enum
|
MessageKind* = enum
|
||||||
# TODO This is needed only to make Nim 1.0.4 happy
|
# TODO This is needed only to make Nim 1.0.4 happy
|
||||||
# Without it, the `PacketKind` type cannot be used as
|
# Without it, the `MessageKind` type cannot be used as
|
||||||
# a discriminator in case objects.
|
# a discriminator in case objects.
|
||||||
unused = 0x00
|
unused = 0x00
|
||||||
|
|
||||||
|
@ -44,43 +44,43 @@ type
|
||||||
|
|
||||||
RequestId* = uint64
|
RequestId* = uint64
|
||||||
|
|
||||||
PingPacket* = object
|
PingMessage* = object
|
||||||
enrSeq*: uint64
|
enrSeq*: uint64
|
||||||
|
|
||||||
PongPacket* = object
|
PongMessage* = object
|
||||||
enrSeq*: uint64
|
enrSeq*: uint64
|
||||||
ip*: seq[byte]
|
ip*: seq[byte]
|
||||||
port*: uint16
|
port*: uint16
|
||||||
|
|
||||||
FindNodePacket* = object
|
FindNodeMessage* = object
|
||||||
distance*: uint32
|
distance*: uint32
|
||||||
|
|
||||||
NodesPacket* = object
|
NodesMessage* = object
|
||||||
total*: uint32
|
total*: uint32
|
||||||
enrs*: seq[Record]
|
enrs*: seq[Record]
|
||||||
|
|
||||||
SomePacket* = PingPacket or PongPacket or FindNodePacket or NodesPacket
|
SomeMessage* = PingMessage or PongMessage or FindNodeMessage or NodesMessage
|
||||||
|
|
||||||
Packet* = object
|
Message* = object
|
||||||
reqId*: RequestId
|
reqId*: RequestId
|
||||||
case kind*: PacketKind
|
case kind*: MessageKind
|
||||||
of ping:
|
of ping:
|
||||||
ping*: PingPacket
|
ping*: PingMessage
|
||||||
of pong:
|
of pong:
|
||||||
pong*: PongPacket
|
pong*: PongMessage
|
||||||
of findnode:
|
of findnode:
|
||||||
findNode*: FindNodePacket
|
findNode*: FindNodeMessage
|
||||||
of nodes:
|
of nodes:
|
||||||
nodes*: NodesPacket
|
nodes*: NodesMessage
|
||||||
else:
|
else:
|
||||||
# TODO: Define the rest
|
# TODO: Define the rest
|
||||||
discard
|
discard
|
||||||
|
|
||||||
template packetKind*(T: typedesc[SomePacket]): PacketKind =
|
template messageKind*(T: typedesc[SomeMessage]): MessageKind =
|
||||||
when T is PingPacket: ping
|
when T is PingMessage: ping
|
||||||
elif T is PongPacket: pong
|
elif T is PongMessage: pong
|
||||||
elif T is FindNodePacket: findNode
|
elif T is FindNodeMessage: findNode
|
||||||
elif T is NodesPacket: nodes
|
elif T is NodesMessage: nodes
|
||||||
|
|
||||||
method storeKeys*(db: Database, id: NodeId, address: Address, r, w: AesKey):
|
method storeKeys*(db: Database, id: NodeId, address: Address, r, w: AesKey):
|
||||||
bool {.base, raises: [Defect].} = discard
|
bool {.base, raises: [Defect].} = discard
|
||||||
|
|
|
@ -86,33 +86,33 @@ suite "Discovery v5 Packet Encodings":
|
||||||
|
|
||||||
suite "Discovery v5 Protocol Message Encodings":
|
suite "Discovery v5 Protocol Message Encodings":
|
||||||
test "Ping Request":
|
test "Ping Request":
|
||||||
var p: PingPacket
|
var p: PingMessage
|
||||||
p.enrSeq = 1
|
p.enrSeq = 1
|
||||||
var reqId: RequestId = 1
|
var reqId: RequestId = 1
|
||||||
check encodePacket(p, reqId).toHex == "01c20101"
|
check encodeMessage(p, reqId).toHex == "01c20101"
|
||||||
|
|
||||||
test "Pong Response":
|
test "Pong Response":
|
||||||
var p: PongPacket
|
var p: PongMessage
|
||||||
p.enrSeq = 1
|
p.enrSeq = 1
|
||||||
p.port = 5000
|
p.port = 5000
|
||||||
p.ip = @[127.byte, 0, 0, 1]
|
p.ip = @[127.byte, 0, 0, 1]
|
||||||
var reqId: RequestId = 1
|
var reqId: RequestId = 1
|
||||||
check encodePacket(p, reqId).toHex == "02ca0101847f000001821388"
|
check encodeMessage(p, reqId).toHex == "02ca0101847f000001821388"
|
||||||
|
|
||||||
test "FindNode Request":
|
test "FindNode Request":
|
||||||
var p: FindNodePacket
|
var p: FindNodeMessage
|
||||||
p.distance = 0x0100
|
p.distance = 0x0100
|
||||||
var reqId: RequestId = 1
|
var reqId: RequestId = 1
|
||||||
check encodePacket(p, reqId).toHex == "03c401820100"
|
check encodeMessage(p, reqId).toHex == "03c401820100"
|
||||||
|
|
||||||
test "Nodes Response (empty)":
|
test "Nodes Response (empty)":
|
||||||
var p: NodesPacket
|
var p: NodesMessage
|
||||||
p.total = 0x1
|
p.total = 0x1
|
||||||
var reqId: RequestId = 1
|
var reqId: RequestId = 1
|
||||||
check encodePacket(p, reqId).toHex == "04c30101c0"
|
check encodeMessage(p, reqId).toHex == "04c30101c0"
|
||||||
|
|
||||||
test "Nodes Response (multiple)":
|
test "Nodes Response (multiple)":
|
||||||
var p: NodesPacket
|
var p: NodesMessage
|
||||||
p.total = 0x1
|
p.total = 0x1
|
||||||
var e1, e2: Record
|
var e1, e2: Record
|
||||||
check e1.fromURI("enr:-HW4QBzimRxkmT18hMKaAL3IcZF1UcfTMPyi3Q1pxwZZbcZVRI8DC5infUAB_UauARLOJtYTxaagKoGmIjzQxO2qUygBgmlkgnY0iXNlY3AyNTZrMaEDymNMrg1JrLQB2KTGtv6MVbcNEVv0AHacwUAPMljNMTg")
|
check e1.fromURI("enr:-HW4QBzimRxkmT18hMKaAL3IcZF1UcfTMPyi3Q1pxwZZbcZVRI8DC5infUAB_UauARLOJtYTxaagKoGmIjzQxO2qUygBgmlkgnY0iXNlY3AyNTZrMaEDymNMrg1JrLQB2KTGtv6MVbcNEVv0AHacwUAPMljNMTg")
|
||||||
|
@ -120,7 +120,7 @@ suite "Discovery v5 Protocol Message Encodings":
|
||||||
|
|
||||||
p.enrs = @[e1, e2]
|
p.enrs = @[e1, e2]
|
||||||
var reqId: RequestId = 1
|
var reqId: RequestId = 1
|
||||||
check encodePacket(p, reqId).toHex == "04f8f20101f8eef875b8401ce2991c64993d7c84c29a00bdc871917551c7d330fca2dd0d69c706596dc655448f030b98a77d4001fd46ae0112ce26d613c5a6a02a81a6223cd0c4edaa53280182696482763489736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138f875b840d7f1c39e376297f81d7297758c64cb37dcc5c3beea9f57f7ce9695d7d5a67553417d719539d6ae4b445946de4d99e680eb8063f29485b555d45b7df16a1850130182696482763489736563703235366b31a1030e2cb74241c0c4fc8e8166f1a79a05d5b0dd95813a74b094529f317d5c39d235"
|
check encodeMessage(p, reqId).toHex == "04f8f20101f8eef875b8401ce2991c64993d7c84c29a00bdc871917551c7d330fca2dd0d69c706596dc655448f030b98a77d4001fd46ae0112ce26d613c5a6a02a81a6223cd0c4edaa53280182696482763489736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138f875b840d7f1c39e376297f81d7297758c64cb37dcc5c3beea9f57f7ce9695d7d5a67553417d719539d6ae4b445946de4d99e680eb8063f29485b555d45b7df16a1850130182696482763489736563703235366b31a1030e2cb74241c0c4fc8e8166f1a79a05d5b0dd95813a74b094529f317d5c39d235"
|
||||||
|
|
||||||
suite "Discovery v5 Cryptographic Primitives":
|
suite "Discovery v5 Cryptographic Primitives":
|
||||||
test "ECDH":
|
test "ECDH":
|
||||||
|
|
Loading…
Reference in New Issue