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
|
||||
# Status Research & Development GmbH
|
||||
#
|
||||
# See the file "LICENSE", included in this
|
||||
# distribution, for details about the copyright.
|
||||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
#
|
||||
|
||||
import ethp2p/ecc, ethp2p/ecies, ethp2p/auth, ethp2p/hexdump
|
||||
export ecc, ecies, auth, hexdump
|
||||
import ethp2p/ecies, ethp2p/auth, ethp2p/hexdump, ethp2p/enode
|
||||
export ecies, auth, enode, hexdump
|
||||
|
|
|
@ -9,7 +9,7 @@ skipDirs = @["tests", "Nim"]
|
|||
|
||||
requires "nim > 0.18.0",
|
||||
"rlp >= 1.0.1",
|
||||
"nimcrypto >= 0.3.0",
|
||||
"https://github.com/cheatfate/nimcrypto",
|
||||
"secp256k1 >= 0.1.0",
|
||||
"eth_keys",
|
||||
"ranges",
|
||||
|
@ -22,4 +22,5 @@ task test, "Runs the test suite":
|
|||
runTest "testecies"
|
||||
runTest "testauth"
|
||||
runTest "testcrypt"
|
||||
runTest "testenode"
|
||||
runTest("tdiscovery", "cpp")
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
# (c) Copyright 2018
|
||||
# Status Research & Development GmbH
|
||||
#
|
||||
# See the file "LICENSE", included in this
|
||||
# distribution, for details about the copyright.
|
||||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
#
|
||||
|
||||
## This module implements Ethereum authentication
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
# (c) Copyright 2018
|
||||
# Status Research & Development GmbH
|
||||
#
|
||||
# See the file "LICENSE", included in this
|
||||
# distribution, for details about the copyright.
|
||||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
#
|
||||
|
||||
## This module implements ECIES method encryption/decryption.
|
||||
|
|
|
@ -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
|
||||
# Status Research & Development GmbH
|
||||
#
|
||||
# See the file "LICENSE", included in this
|
||||
# distribution, for details about the copyright.
|
||||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
#
|
||||
|
||||
## This module implements RLPx cryptography
|
||||
|
|
|
@ -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…
Reference in New Issue