Added Discovery4Service as working prototype.

This commit is contained in:
cheatfate 2018-05-02 18:01:10 +03:00
parent 155287c21b
commit bb49e935f6
5 changed files with 214 additions and 14 deletions

View File

@ -11,7 +11,8 @@ requires "nim >= 0.18.1",
"https://github.com/cheatfate/nimcrypto",
"https://github.com/status-im/nim-rlp",
"https://github.com/status-im/nim-ttmath",
"https://github.com/status-im/nim-eth-p2p"
"https://github.com/status-im/nim-eth-p2p",
"https://github.com/status-im/nim-eth-keyfile"
proc test(name: string, lang = "cpp") =
if not dirExists "build":

View File

@ -7,7 +7,8 @@
# This file may not be copied, modified, or distributed except according to
# those terms.
import parseopt, strutils, net, ethp2p
import parseopt, strutils, net, ethp2p, eth_keyfile, eth_keys, json,
nimcrypto
const
NimbusName* = "Nimbus"
@ -68,13 +69,14 @@ type
NetConfiguration* = object
## Network configuration object
flags*: set[NetworkFlags]
bootNodes: seq[ENode]
bootNodes4: seq[ENode]
bootNodes5: seq[ENode]
bindPort: uint16
maxPeers: int
maxPendingPeers: int
nodeKey: string
bootNodes*: seq[ENode]
bootNodes4*: seq[ENode]
bootNodes5*: seq[ENode]
bindPort*: uint16
discPort*: uint16
maxPeers*: int
maxPendingPeers*: int
nodeKey*: PrivateKey
DebugConfiguration* = object
## Debug configuration object
@ -108,6 +110,7 @@ proc initConfiguration(): NimbusConfiguration =
result.net.maxPeers = 25
result.net.maxPendingPeers = 0
result.net.bindPort = 30303'u16
result.net.discPort = 30303'u16
## Debug defaults
result.debug.flags = {}
@ -175,6 +178,38 @@ proc processENodesList(v: string, o: var seq[ENode]): ConfigStatus =
else:
break
proc processPrivateKey(v: string, o: var PrivateKey): ConfigStatus =
## Convert hexadecimal string to private key object.
try:
o = initPrivateKey(v)
result = Success
except:
result = ErrorParseOption
# proc processHexBytes(v: string, o: var seq[byte]): ConfigStatus =
# ## Convert hexadecimal string to seq[byte].
# try:
# o = fromHex(v)
# result = Success
# except:
# result = ErrorParseOption
# proc processHexString(v: string, o: var string): ConfigStatus =
# ## Convert hexadecimal string to string.
# try:
# o = parseHexStr(v)
# result = Success
# except:
# result = ErrorParseOption
# proc processJson(v: string, o: var JsonNode): ConfigStatus =
# ## Convert string to JSON.
# try:
# o = parseJson(v)
# result = Success
# except:
# result = ErrorParseOption
proc processRpcArguments(key, value: string): ConfigStatus =
## Processes only `RPC` related command line options
result = Success
@ -230,6 +265,11 @@ proc processNetArguments(key, value: string): ConfigStatus =
result = processInteger(value, res)
if result == Success:
config.net.bindPort = uint16(res and 0xFFFF)
elif skey == "discport":
var res = 0
result = processInteger(value, res)
if result == Success:
config.net.discPort = uint16(res and 0xFFFF)
elif skey == "maxpeers":
var res = 0
result = processInteger(value, res)
@ -240,6 +280,11 @@ proc processNetArguments(key, value: string): ConfigStatus =
result = processInteger(value, res)
if result == Success:
config.net.maxPendingPeers = res
elif skey == "nodekey":
var res: PrivateKey
result = processPrivateKey(value, res)
if result == Success:
config.net.nodeKey = res
else:
result = EmptyOption
@ -287,15 +332,20 @@ proc getHelpString*(): string =
USAGE:
nimbus [options]
ETHEREUM OPTIONS:
--keyfile:<value> Use keyfile storage file
NETWORKING OPTIONS:
--bootnodes:<value> Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)
--bootnodesv4:<value> Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)
--botnoodesv5:<value> Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)
--port:<value> Network listening port (default: 30303)
--port:<value> Network listening TCP port (default: 30303)
--discport:<value> Netowkr listening UDP port (default: 30303)
--maxpeers:<value> Maximum number of network peers (default: 25)
--maxpendpeers:<value> Maximum number of pending connection attempts (default: 0)
--nodiscover Disables the peer discovery mechanism (manual peer addition)
--v5discover Enables the experimental RLPx V5 (Topic Discovery) mechanism
--nodekey:<value> P2P node private key (as hexadecimal string)
--testnet Use Ethereum Test Network
--mainnet Use Ethereum Main Network
--localnet Use local network only

View File

@ -8,14 +8,20 @@
# those terms.
import config, asyncdispatch
import p2p/service, p2p/disc4service
when isMainModule:
var message: string
if processArguments(message) != Success:
if processArguments(message) != ConfigStatus.Success:
echo message
quit(QuitFailure)
else:
if len(message) > 0:
echo message
echo dumpConfiguration()
var disc4: Discovery4Service
echo disc4.init()
echo disc4.configure()
echo disc4.errorMessage()
echo disc4.start()
echo disc4.errorMessage()

88
src/p2p/disc4service.nim Normal file
View File

@ -0,0 +1,88 @@
# Nimbus
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
import asyncdispatch, net # stdlib modules
import ethp2p, eth_keys, nimcrypto # external modules
import service, ../config # internal modules
type
Discovery4Service* = object of NetworkService
address: Address
dproto: DiscoveryProtocol
bootnodes: seq[ENode]
proc init*(s: var Discovery4Service): ServiceStatus =
s.id = "Nimbus.Discovery.4"
s.flags = {}
s.state = Stopped
s.error = ""
result = ServiceStatus.Success
proc configure*(s: var Discovery4Service): ServiceStatus =
let conf = getConfiguration()
cleanError(s)
checkState(s, {Stopped, Paused})
var bootnodes = newSeq[ENode]()
if TestNet in conf.net.flags:
for item in ROPSTEN_BOOTNODES:
bootnodes.add(initENode(item))
elif MainNet in conf.net.flags:
for item in MAINNET_BOOTNODES:
bootnodes.add(initENode(item))
for item in conf.net.bootNodes:
bootnodes.add(item)
for item in conf.net.bootNodes4:
bootnodes.add(item)
if isFullZero(conf.net.nodeKey):
s.setFailure("P2P Node private key is not set!")
return ServiceStatus.Error
if Configured notin s.flags:
s.address.ip = parseIpAddress("0.0.0.0")
s.address.tcpPort = Port(conf.net.bindPort)
s.address.udpPort = Port(conf.net.discPort)
s.dproto = newDiscoveryProtocol(conf.net.nodeKey, s.address, bootnodes)
s.flags.incl(Configured)
result = ServiceStatus.Success
proc start*(s: var Discovery4Service): ServiceStatus =
cleanError(s)
checkState(s, {Stopped})
checkFlags(s, {Configured}, "not configured!")
try:
s.dproto.open()
waitFor s.dproto.bootstrap()
except ValueError as e:
s.setFailure(e.msg)
result = ServiceStatus.Error
except OSError as e:
s.setFailure(e.msg)
result = ServiceStatus.Error
result = ServiceStatus.Success
proc stop*(s: var Discovery4Service): ServiceStatus =
cleanError(s)
checkState(s, {Running, Paused})
checkFlags(s, {Configured}, "not configured!")
result = ServiceStatus.Success
proc pause*(s: var Discovery4Service): ServiceStatus =
cleanError(s)
checkState(s, {Running})
s.state = Paused
result = ServiceStatus.Success
proc resume*(s: var Discovery4Service): ServiceStatus =
cleanError(s)
checkState(s, {Paused})
result = ServiceStatus.Success

55
src/p2p/service.nim Normal file
View File

@ -0,0 +1,55 @@
# Nimbus
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
type
ServiceState* = enum
Stopped,
Starting,
Running,
Pausing,
Paused,
Resuming,
Failure
ServiceStatus* = enum
Success,
Error
ServiceFlags* = enum
Configured
NetworkService* = object of RootObj
id*: string
flags*: set[ServiceFlags]
state*: ServiceState
error*: string
template checkState*(s: var NetworkService,
need: set[ServiceState]) =
if s.state notin need:
s.error = "Service [" & s.id & "] state is {" & $s.state & "} but " &
$need & " required!"
return(Error)
template cleanError*(s: var NetworkService) =
s.error.setLen(0)
template checkFlags*(s: var NetworkService,
need: set[ServiceFlags],
msg: string) =
if s.flags * need != need:
s.error = "Service [" & s.id & "] is " & msg
return(Error)
template setFailure*(s: var NetworkService, msg: string) =
s.state = Failure
s.error = "Service [" & s.id & "] returns error: " & msg
template errorMessage*(s: NetworkService): string =
s.error