mirror of
https://github.com/status-im/nim-eth-p2p.git
synced 2025-02-18 01:36:32 +00:00
Add ENode type/procedures/tests.
Fixed header with proper licenses. Fixed nimble to allow ENode tests.
This commit is contained in:
parent
d567911c14
commit
950e0c2d46
@ -3,9 +3,10 @@
|
|||||||
# (c) Copyright 2018
|
# (c) Copyright 2018
|
||||||
# Status Research & Development GmbH
|
# Status Research & Development GmbH
|
||||||
#
|
#
|
||||||
# See the file "LICENSE", included in this
|
# Licensed under either of
|
||||||
# distribution, for details about the copyright.
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
|
# MIT license (LICENSE-MIT)
|
||||||
#
|
#
|
||||||
|
|
||||||
import ethp2p/ecc, ethp2p/ecies, ethp2p/auth, ethp2p/hexdump
|
import ethp2p/ecies, ethp2p/auth, ethp2p/hexdump, ethp2p/enode
|
||||||
export ecc, ecies, auth, hexdump
|
export ecies, auth, enode, hexdump
|
||||||
|
@ -9,7 +9,7 @@ skipDirs = @["tests", "Nim"]
|
|||||||
|
|
||||||
requires "nim > 0.18.0",
|
requires "nim > 0.18.0",
|
||||||
"rlp >= 1.0.1",
|
"rlp >= 1.0.1",
|
||||||
"nimcrypto >= 0.3.0",
|
"https://github.com/cheatfate/nimcrypto",
|
||||||
"secp256k1 >= 0.1.0",
|
"secp256k1 >= 0.1.0",
|
||||||
"eth_keys",
|
"eth_keys",
|
||||||
"ranges",
|
"ranges",
|
||||||
@ -22,4 +22,5 @@ task test, "Runs the test suite":
|
|||||||
runTest "testecies"
|
runTest "testecies"
|
||||||
runTest "testauth"
|
runTest "testauth"
|
||||||
runTest "testcrypt"
|
runTest "testcrypt"
|
||||||
|
runTest "testenode"
|
||||||
runTest("tdiscovery", "cpp")
|
runTest("tdiscovery", "cpp")
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
# (c) Copyright 2018
|
# (c) Copyright 2018
|
||||||
# Status Research & Development GmbH
|
# Status Research & Development GmbH
|
||||||
#
|
#
|
||||||
# See the file "LICENSE", included in this
|
# Licensed under either of
|
||||||
# distribution, for details about the copyright.
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
|
# MIT license (LICENSE-MIT)
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements Ethereum authentication
|
## This module implements Ethereum authentication
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
# (c) Copyright 2018
|
# (c) Copyright 2018
|
||||||
# Status Research & Development GmbH
|
# Status Research & Development GmbH
|
||||||
#
|
#
|
||||||
# See the file "LICENSE", included in this
|
# Licensed under either of
|
||||||
# distribution, for details about the copyright.
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
|
# MIT license (LICENSE-MIT)
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements ECIES method encryption/decryption.
|
## This module implements ECIES method encryption/decryption.
|
||||||
|
161
ethp2p/enode.nim
Normal file
161
ethp2p/enode.nim
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#
|
||||||
|
# Ethereum P2P
|
||||||
|
# (c) Copyright 2018
|
||||||
|
# Status Research & Development GmbH
|
||||||
|
#
|
||||||
|
# Licensed under either of
|
||||||
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
|
# MIT license (LICENSE-MIT)
|
||||||
|
#
|
||||||
|
|
||||||
|
import uri, eth_keys, strutils, net
|
||||||
|
|
||||||
|
type
|
||||||
|
ENodeStatus* = enum
|
||||||
|
## ENode status codes
|
||||||
|
Success, ## Conversion operation succeed
|
||||||
|
IncorrectNodeId, ## Incorrect public key supplied
|
||||||
|
IncorrectScheme, ## Incorrect URI scheme supplied
|
||||||
|
IncorrectIP, ## Incorrect IP address supplied
|
||||||
|
IncorrectPort, ## Incorrect TCP port supplied
|
||||||
|
IncorrectDiscPort, ## Incorrect UDP discovery port supplied
|
||||||
|
IncorrectUri, ## Incorrect URI supplied
|
||||||
|
IncompleteENode ## Incomplete ENODE object
|
||||||
|
|
||||||
|
Address* = object
|
||||||
|
## Network address object
|
||||||
|
ip*: IpAddress ## IPv4/IPv6 address
|
||||||
|
udpPort*: Port ## UDP discovery port number
|
||||||
|
tcpPort*: Port ## TCP port number
|
||||||
|
|
||||||
|
ENode* = object
|
||||||
|
## ENode object
|
||||||
|
pubkey*: PublicKey ## Node public key
|
||||||
|
address*: Address ## Node address
|
||||||
|
|
||||||
|
ENodeException* = object of Exception
|
||||||
|
|
||||||
|
proc raiseENodeError(status: ENodeStatus) =
|
||||||
|
if status == IncorrectIP:
|
||||||
|
raise newException(ENodeException, "Incorrect IP address")
|
||||||
|
elif status == IncorrectPort:
|
||||||
|
raise newException(ENodeException, "Incorrect port number")
|
||||||
|
elif status == IncorrectDiscPort:
|
||||||
|
raise newException(ENodeException, "Incorrect discovery port number")
|
||||||
|
elif status == IncorrectUri:
|
||||||
|
raise newException(ENodeException, "Incorrect URI")
|
||||||
|
elif status == IncorrectScheme:
|
||||||
|
raise newException(ENodeException, "Incorrect scheme")
|
||||||
|
elif status == IncorrectNodeId:
|
||||||
|
raise newException(ENodeException, "Incorrect node id")
|
||||||
|
elif status == IncompleteENode:
|
||||||
|
raise newException(ENodeException, "Incomplete enode")
|
||||||
|
|
||||||
|
proc initENode*(e: string, node: var ENode): ENodeStatus =
|
||||||
|
## Initialize ENode ``node`` from URI string ``uri``.
|
||||||
|
var
|
||||||
|
uport: int = 0
|
||||||
|
tport: int = 0
|
||||||
|
uri: Uri = initUri()
|
||||||
|
data: string
|
||||||
|
|
||||||
|
if len(e) == 0:
|
||||||
|
return IncorrectUri
|
||||||
|
|
||||||
|
parseUri(e, uri)
|
||||||
|
|
||||||
|
if len(uri.scheme) == 0 or uri.scheme.toLowerAscii() != "enode":
|
||||||
|
return IncorrectScheme
|
||||||
|
|
||||||
|
if len(uri.username) != 128:
|
||||||
|
return IncorrectNodeId
|
||||||
|
|
||||||
|
for i in uri.username:
|
||||||
|
if i notin {'A'..'F', 'a'..'f', '0'..'9'}:
|
||||||
|
return IncorrectNodeId
|
||||||
|
|
||||||
|
if len(uri.password) != 0 or len(uri.path) != 0 or len(uri.anchor) != 0:
|
||||||
|
return IncorrectUri
|
||||||
|
|
||||||
|
if len(uri.hostname) == 0:
|
||||||
|
return IncorrectIP
|
||||||
|
|
||||||
|
try:
|
||||||
|
if len(uri.port) == 0:
|
||||||
|
return IncorrectPort
|
||||||
|
tport = parseInt(uri.port)
|
||||||
|
if tport <= 0 or tport > 65535:
|
||||||
|
return IncorrectPort
|
||||||
|
except:
|
||||||
|
return IncorrectPort
|
||||||
|
|
||||||
|
if len(uri.query) > 0:
|
||||||
|
if not uri.query.toLowerAscii().startsWith("discport="):
|
||||||
|
return IncorrectDiscPort
|
||||||
|
try:
|
||||||
|
uport = parseInt(uri.query[9..^1])
|
||||||
|
if uport <= 0 or uport > 65535:
|
||||||
|
return IncorrectDiscPort
|
||||||
|
except:
|
||||||
|
return IncorrectDiscPort
|
||||||
|
else:
|
||||||
|
uport = tport
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = parseHexStr(uri.username)
|
||||||
|
if recoverPublicKey(cast[seq[byte]](data),
|
||||||
|
node.pubkey) != EthKeysStatus.Success:
|
||||||
|
return IncorrectNodeId
|
||||||
|
except:
|
||||||
|
return IncorrectNodeId
|
||||||
|
|
||||||
|
try:
|
||||||
|
node.address.ip = parseIpAddress(uri.hostname)
|
||||||
|
except:
|
||||||
|
zeroMem(addr node.pubkey, KeyLength * 2)
|
||||||
|
return IncorrectIP
|
||||||
|
|
||||||
|
node.address.tcpPort = Port(tport)
|
||||||
|
node.address.udpPort = Port(uport)
|
||||||
|
result = Success
|
||||||
|
|
||||||
|
proc initENode*(uri: string): ENode {.inline.} =
|
||||||
|
## Returns ENode object from URI string ``uri``.
|
||||||
|
let res = initENode(uri, result)
|
||||||
|
if res != Success:
|
||||||
|
raiseENodeError(res)
|
||||||
|
|
||||||
|
proc isCorrect*(n: ENode): bool =
|
||||||
|
## Returns ``true`` if ENode ``n`` is properly filled.
|
||||||
|
if n.address.ip.family notin {IpAddressFamily.IPv4, IpAddressFamily.IPv6}:
|
||||||
|
return false
|
||||||
|
if n.address.tcpPort == Port(0):
|
||||||
|
return false
|
||||||
|
if n.address.udpPort == Port(0):
|
||||||
|
return false
|
||||||
|
result = false
|
||||||
|
for i in n.pubkey.data:
|
||||||
|
if i != 0x00'u8:
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
|
||||||
|
proc `$`*(n: ENode): string =
|
||||||
|
## Returns string representation of ENode.
|
||||||
|
var ipaddr: string
|
||||||
|
if not isCorrect(n):
|
||||||
|
raiseENodeError(IncompleteENode)
|
||||||
|
if n.address.ip.family == IpAddressFamily.IPv4:
|
||||||
|
ipaddr = $(n.address.ip)
|
||||||
|
else:
|
||||||
|
ipaddr = "[" & $(n.address.ip) & "]"
|
||||||
|
result = newString(0)
|
||||||
|
result.add("enode://")
|
||||||
|
result.add($n.pubkey)
|
||||||
|
result.add("@")
|
||||||
|
result.add(ipaddr)
|
||||||
|
result.add(":")
|
||||||
|
result.add($int(n.address.tcpPort))
|
||||||
|
if uint16(n.address.udpPort) != uint16(n.address.tcpPort):
|
||||||
|
result.add("?")
|
||||||
|
result.add("discport=")
|
||||||
|
result.add($int(n.address.udpPort))
|
@ -3,8 +3,9 @@
|
|||||||
# (c) Copyright 2018
|
# (c) Copyright 2018
|
||||||
# Status Research & Development GmbH
|
# Status Research & Development GmbH
|
||||||
#
|
#
|
||||||
# See the file "LICENSE", included in this
|
# Licensed under either of
|
||||||
# distribution, for details about the copyright.
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
|
# MIT license (LICENSE-MIT)
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements RLPx cryptography
|
## This module implements RLPx cryptography
|
||||||
|
99
tests/testenode.nim
Normal file
99
tests/testenode.nim
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#
|
||||||
|
# Ethereum P2P
|
||||||
|
# (c) Copyright 2018
|
||||||
|
# Status Research & Development GmbH
|
||||||
|
#
|
||||||
|
# Licensed under either of
|
||||||
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
|
# MIT license (LICENSE-MIT)
|
||||||
|
|
||||||
|
import unittest, net, ethp2p/enode
|
||||||
|
|
||||||
|
suite "ENode":
|
||||||
|
test "Go-Ethereum tests":
|
||||||
|
const enodes = [
|
||||||
|
"http://foobar",
|
||||||
|
"enode://01010101@123.124.125.126:3",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
|
||||||
|
"01010101",
|
||||||
|
"enode://01010101",
|
||||||
|
"://foo",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
|
||||||
|
]
|
||||||
|
|
||||||
|
const results = [
|
||||||
|
IncorrectScheme,
|
||||||
|
IncorrectNodeId,
|
||||||
|
IncorrectIP,
|
||||||
|
IncorrectPort,
|
||||||
|
IncorrectDiscPort,
|
||||||
|
IncorrectScheme,
|
||||||
|
IncorrectNodeId,
|
||||||
|
IncorrectScheme,
|
||||||
|
ENodeStatus.Success,
|
||||||
|
ENodeStatus.Success,
|
||||||
|
ENodeStatus.Success,
|
||||||
|
ENodeStatus.Success
|
||||||
|
]
|
||||||
|
|
||||||
|
for index in 0..<len(enodes):
|
||||||
|
var node: ENode
|
||||||
|
let res = initENode(enodes[index], node)
|
||||||
|
check res == results[index]
|
||||||
|
if res == ENodeStatus.Success:
|
||||||
|
check enodes[index] == $node
|
||||||
|
|
||||||
|
test "Custom validation tests":
|
||||||
|
const enodes = [
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@256.0.0.1:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1.256.0.1:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1.1.256.1:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1.1.1.256:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439:@1.1.1.255:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439:bar@1.1.1.255:52150",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1.1.1.255:-1",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1.1.1.255:65536",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1.1.1.255:1024?discport=-1",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1.1.1.255:1024?discport=65536",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1.1.1.255:1024?discport=65535#bar",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@",
|
||||||
|
"enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a43Z@1.1.1.1:25?discport=22"
|
||||||
|
]
|
||||||
|
|
||||||
|
const results = [
|
||||||
|
IncorrectIP,
|
||||||
|
IncorrectIP,
|
||||||
|
IncorrectIP,
|
||||||
|
IncorrectIP,
|
||||||
|
Success,
|
||||||
|
IncorrectUri,
|
||||||
|
IncorrectPort,
|
||||||
|
IncorrectPort,
|
||||||
|
IncorrectDiscPort,
|
||||||
|
IncorrectDiscPort,
|
||||||
|
IncorrectUri,
|
||||||
|
IncorrectIP,
|
||||||
|
IncorrectNodeId
|
||||||
|
]
|
||||||
|
|
||||||
|
for index in 0..<len(enodes):
|
||||||
|
var node: ENode
|
||||||
|
let res = initENode(enodes[index], node)
|
||||||
|
check res == results[index]
|
||||||
|
|
||||||
|
test "isCorrect() tests":
|
||||||
|
var node: ENode
|
||||||
|
check isCorrect(node) == false
|
||||||
|
node.address.ip.family = IpAddressFamily.IPv4
|
||||||
|
check isCorrect(node) == false
|
||||||
|
node.address.tcpPort = Port(25)
|
||||||
|
check isCorrect(node) == false
|
||||||
|
node.address.udpPort = Port(25)
|
||||||
|
check isCorrect(node) == false
|
||||||
|
node.pubkey.data[0] = 1'u8
|
||||||
|
check isCorrect(node) == true
|
Loading…
x
Reference in New Issue
Block a user