diff --git a/eth/p2p/discoveryv5/discovery_db.nim b/eth/p2p/discoveryv5/discovery_db.nim index 0fa0ed1..4552f9d 100644 --- a/eth/p2p/discoveryv5/discovery_db.nim +++ b/eth/p2p/discoveryv5/discovery_db.nim @@ -1,4 +1,5 @@ -import types +import std/net +import types, ../enode import eth/trie/db type @@ -11,18 +12,28 @@ type proc init*(T: type DiscoveryDB, backend: TrieDatabaseRef): DiscoveryDB = T(backend: backend) -proc makeKey(id: NodeId, address: int): array[1 + sizeof(id) + sizeof(address), byte] = +const keySize = 1 + # unique triedb prefix (kNodeToKeys) + sizeof(NodeId) + + 16 + # max size of ip address (ipv6) + 2 # Sizeof port + +proc makeKey(id: NodeId, address: Address): array[keySize, byte] = result[0] = byte(kNodeToKeys) copyMem(addr result[1], unsafeAddr id, sizeof(id)) - copyMem(addr result[sizeof(id) + 1], unsafeAddr address, sizeof(address)) + case address.ip.family + of IpAddressFamily.IpV4: + copyMem(addr result[sizeof(id) + 1], unsafeAddr address.ip.address_v4, sizeof(address.ip.address_v4)) + of IpAddressFamily.IpV6: + copyMem(addr result[sizeof(id) + 1], unsafeAddr address.ip.address_v6, sizeof(address.ip.address_v6)) + copyMem(addr result[sizeof(id) + 1 + sizeof(address.ip.address_v6)], unsafeAddr address.udpPort, sizeof(address.udpPort)) -method storeKeys*(db: DiscoveryDB, id: NodeId, address: int, r, w: array[16, byte]) = +method storeKeys*(db: DiscoveryDB, id: NodeId, address: Address, r, w: array[16, byte]) = var value: array[sizeof(r) + sizeof(w), byte] value[0 .. 15] = r value[16 .. ^1] = w db.backend.put(makeKey(id, address), value) -method loadKeys*(db: DiscoveryDB, id: NodeId, address: int, r, w: var array[16, byte]): bool = +method loadKeys*(db: DiscoveryDB, id: NodeId, address: Address, r, w: var array[16, byte]): bool = let res = db.backend.get(makeKey(id, address)) if res.len == sizeof(r) + sizeof(w): copyMem(addr r[0], unsafeAddr res[0], sizeof(r)) diff --git a/eth/p2p/discoveryv5/encoding.nim b/eth/p2p/discoveryv5/encoding.nim index e5cbd1d..b9292e8 100644 --- a/eth/p2p/discoveryv5/encoding.nim +++ b/eth/p2p/discoveryv5/encoding.nim @@ -1,5 +1,5 @@ import tables -import types, node, enr, hkdf, eth/[rlp, keys], nimcrypto, stint +import types, node, enr, hkdf, ../enode, eth/[rlp, keys], nimcrypto, stint const idNoncePrefix = "discovery-id-nonce" @@ -114,7 +114,7 @@ proc packetTag(destNode, srcNode: NodeID): array[32, byte] = let destidHash = sha256.digest(destId) result = srcId xor destidHash.data -proc encodeEncrypted*(c: Codec, toNode: Node, toAddr: int, packetData: seq[byte], challenge: Whoareyou): (seq[byte], array[gcmNonceSize, byte]) = +proc encodeEncrypted*(c: Codec, toNode: Node, packetData: seq[byte], challenge: Whoareyou): (seq[byte], array[gcmNonceSize, byte]) = var nonce: array[gcmNonceSize, byte] randomBytes(nonce) var headEnc: seq[byte] @@ -127,14 +127,14 @@ proc encodeEncrypted*(c: Codec, toNode: Node, toAddr: int, packetData: seq[byte] # We might not have the node's keys if the handshake hasn't been performed # yet. That's fine, we will be responded with whoareyou. - discard c.db.loadKeys(toNode.id, toAddr, readKey, writeKey) + discard c.db.loadKeys(toNode.id, toNode.address, readKey, writeKey) else: var sec: HandshakeSecrets headEnc = c.makeAuthHeader(toNode, nonce, sec, challenge) writeKey = sec.writeKey - c.db.storeKeys(toNode.id, toAddr, sec.readKey, sec.writeKey) + c.db.storeKeys(toNode.id, toNode.address, sec.readKey, sec.writeKey) var body = packetData let tag = packetTag(toNode.id, c.localNode.id) @@ -201,7 +201,7 @@ proc decodeAuthResp(c: Codec, fromId: NodeId, head: AuthHeader, challenge: Whoar newNode = newNode(authResp.record) return true -proc decodeEncrypted*(c: var Codec, fromId: NodeID, fromAddr: int, input: seq[byte], authTag: var array[12, byte], newNode: var Node, packet: var Packet): bool = +proc decodeEncrypted*(c: var Codec, fromId: NodeID, fromAddr: Address, input: seq[byte], authTag: var array[12, byte], newNode: var Node, packet: var Packet): bool = let input = input.toRange var r = rlpFromBytes(input[32 .. ^1]) let authEndPos = r.currentElemEnd diff --git a/eth/p2p/discoveryv5/node.nim b/eth/p2p/discoveryv5/node.nim index 03d4439..047709e 100644 --- a/eth/p2p/discoveryv5/node.nim +++ b/eth/p2p/discoveryv5/node.nim @@ -45,6 +45,8 @@ proc newNode*(r: Record): Node = proc hash*(n: Node): hashes.Hash = hash(n.node.pubkey.data) proc `==`*(a, b: Node): bool = (a.isNil and b.isNil) or (not a.isNil and not b.isNil and a.node.pubkey == b.node.pubkey) +proc address*(n: Node): Address {.inline.} = n.node.address + proc `$`*(n: Node): string = if n == nil: "Node[local]" diff --git a/eth/p2p/discoveryv5/protocol.nim b/eth/p2p/discoveryv5/protocol.nim index d926737..0ff0d3e 100644 --- a/eth/p2p/discoveryv5/protocol.nim +++ b/eth/p2p/discoveryv5/protocol.nim @@ -92,7 +92,7 @@ proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId, authTag: array proc sendNodes(d: Protocol, toNode: Node, reqId: RequestId, nodes: openarray[Node]) = proc sendNodes(d: Protocol, toNode: Node, packet: NodesPacket, reqId: RequestId) {.nimcall.} = - let (data, _) = d.codec.encodeEncrypted(toNode, 12345, encodePacket(packet, reqId), challenge = nil) + let (data, _) = d.codec.encodeEncrypted(toNode, encodePacket(packet, reqId), challenge = nil) d.send(toNode, data) const maxNodesPerPacket = 3 @@ -109,7 +109,8 @@ proc sendNodes(d: Protocol, toNode: Node, reqId: RequestId, nodes: openarray[Nod if packet.enrs.len != 0: d.sendNodes(toNode, packet, reqId) -proc handlePing(d: Protocol, fromNode: Node, a: Address, ping: PingPacket, reqId: RequestId) = +proc handlePing(d: Protocol, fromNode: Node, ping: PingPacket, reqId: RequestId) = + let a = fromNode.address var pong: PongPacket pong.enrSeq = ping.enrSeq pong.ip = case a.ip.family @@ -117,10 +118,10 @@ proc handlePing(d: Protocol, fromNode: Node, a: Address, ping: PingPacket, reqId of IpAddressFamily.IPv6: @(a.ip.address_v6) pong.port = a.udpPort.uint16 - let (data, _) = d.codec.encodeEncrypted(fromNode, 12345, encodePacket(pong, reqId), challenge = nil) + let (data, _) = d.codec.encodeEncrypted(fromNode, encodePacket(pong, reqId), challenge = nil) d.send(fromNode, data) -proc handleFindNode(d: Protocol, fromNode: Node, a: Address, fn: FindNodePacket, reqId: RequestId) = +proc handleFindNode(d: Protocol, fromNode: Node, fn: FindNodePacket, reqId: RequestId) = if fn.distance == 0: d.sendNodes(fromNode, reqId, [d.localNode]) else: @@ -142,7 +143,7 @@ proc receive*(d: Protocol, a: Address, msg: Bytes) {.gcsafe.} = if d.pendingRequests.take(whoareyou.authTag, pr): let toNode = pr.node - let (data, _) = d.codec.encodeEncrypted(toNode, 12345, pr.packet, challenge = whoareyou) + let (data, _) = d.codec.encodeEncrypted(toNode, pr.packet, challenge = whoareyou) d.send(toNode, data) else: @@ -155,7 +156,7 @@ proc receive*(d: Protocol, a: Address, msg: Bytes) {.gcsafe.} = var node: Node var packet: Packet - if d.codec.decodeEncrypted(sender, 12345, msg, authTag, node, packet): + if d.codec.decodeEncrypted(sender, a, msg, authTag, node, packet): if node.isNil: node = d.routingTable.getNode(sender) else: @@ -166,9 +167,9 @@ proc receive*(d: Protocol, a: Address, msg: Bytes) {.gcsafe.} = case packet.kind of ping: - d.handlePing(node, a, packet.ping, packet.reqId) + d.handlePing(node, packet.ping, packet.reqId) of findNode: - d.handleFindNode(node, a, packet.findNode, packet.reqId) + d.handleFindNode(node, packet.findNode, packet.reqId) else: var waiter: Future[Option[Packet]] if d.awaitedPackets.take((node, packet.reqId), waiter): @@ -212,7 +213,7 @@ proc waitNodes(d: Protocol, fromNode: Node, reqId: RequestId): Future[seq[Node]] proc findNode(d: Protocol, toNode: Node, distance: uint32): Future[seq[Node]] {.async.} = let reqId = newRequestId() let packet = encodePacket(FindNodePacket(distance: distance), reqId) - let (data, nonce) = d.codec.encodeEncrypted(toNode, 12345, packet, challenge = nil) + let (data, nonce) = d.codec.encodeEncrypted(toNode, packet, challenge = nil) d.pendingRequests[nonce] = PendingRequest(node: toNode, packet: packet) d.send(toNode, data) result = await d.waitNodes(toNode, reqId) @@ -323,7 +324,7 @@ when isMainModule: result.add(d) proc addNode(d: openarray[Protocol], enr: string) = - for dd in d: dd.addNode(enr) + for dd in d: dd.addNode(EnrUri(enr)) proc test() {.async.} = block: diff --git a/eth/p2p/discoveryv5/types.nim b/eth/p2p/discoveryv5/types.nim index 0277f1e..293e81d 100644 --- a/eth/p2p/discoveryv5/types.nim +++ b/eth/p2p/discoveryv5/types.nim @@ -68,8 +68,8 @@ template packetKind*(T: typedesc[SomePacket]): PacketKind = elif T is FindNodePacket: findNode elif T is NodesPacket: nodes -method storeKeys*(db: Database, id: NodeId, address: int, r, w: array[16, byte]) {.base.} = discard -method loadKeys*(db: Database, id: NodeId, address: int, r, w: var array[16, byte]): bool {.base.} = discard +method storeKeys*(db: Database, id: NodeId, address: Address, r, w: array[16, byte]) {.base.} = discard +method loadKeys*(db: Database, id: NodeId, address: Address, r, w: var array[16, byte]): bool {.base.} = discard proc toBytes*(id: NodeId): array[32, byte] {.inline.} = id.toByteArrayBE()