Initial commit.

3 common RPC procedures implemented.
This commit is contained in:
cheatfate 2018-06-13 14:13:29 +03:00
parent 8528f1b704
commit 5e7f2c990d
4 changed files with 154 additions and 95 deletions

View File

@ -13,6 +13,8 @@ requires "nim >= 0.18.1",
"stint", "stint",
"https://github.com/status-im/nim-eth-common", "https://github.com/status-im/nim-eth-common",
"https://github.com/status-im/nim-eth-p2p", "https://github.com/status-im/nim-eth-p2p",
"https://github.com/status-im/nim-asyncdispatch2",
"https://github.com/status-im/nim-eth-rpc",
"https://github.com/status-im/nim-eth-keyfile" "https://github.com/status-im/nim-eth-keyfile"
proc test(name: string, lang = "c") = proc test(name: string, lang = "c") =

View File

@ -7,8 +7,8 @@
# This file may not be copied, modified, or distributed except according to # This file may not be copied, modified, or distributed except according to
# those terms. # those terms.
import parseopt, strutils, net, ethp2p, eth_keyfile, eth_keys, json, import parseopt, strutils
nimcrypto import asyncdispatch2, eth_keys, ethp2p
const const
NimbusName* = "Nimbus" NimbusName* = "Nimbus"
@ -29,6 +29,14 @@ const
NimbusVersion* = $NimbusMajor & "." & $NimbusMinor & "." & $NimbusPatch NimbusVersion* = $NimbusMajor & "." & $NimbusMinor & "." & $NimbusPatch
## is the version of Nimbus as a string. ## is the version of Nimbus as a string.
NimbusIdent* = NimbusName & "/" & NimbusVersion
## project ident name for networking services
NimbusHeader* = NimbusName & " Version " & NimbusVersion &
" [" & hostOS & ": " & hostCPU & "]\r\n" &
NimbusCopyright
## command line nimbus header
type type
ConfigStatus* = enum ConfigStatus* = enum
## Configuration status flags ## Configuration status flags
@ -36,6 +44,7 @@ type
EmptyOption, ## No options in category EmptyOption, ## No options in category
ErrorUnknownOption, ## Unknown option in command line found ErrorUnknownOption, ## Unknown option in command line found
ErrorParseOption, ## Error in parsing command line option ErrorParseOption, ## Error in parsing command line option
ErrorIncorrectOption, ## Option has incorrect value
Error ## Unspecified error Error ## Unspecified error
RpcFlags* {.pure.} = enum RpcFlags* {.pure.} = enum
@ -45,16 +54,15 @@ type
RpcConfiguration* = object RpcConfiguration* = object
## JSON-RPC configuration object ## JSON-RPC configuration object
flags*: set[RpcFlags] ## RPC flags flags*: set[RpcFlags] ## RPC flags
bindAddress*: IpAddress ## RPC bind address binds*: seq[TransportAddress] ## RPC bind address
bindPort*: uint16 ## RPC bind port
allowedIPs*: seq[IpAddress] ## Sequence of allowed IP addresses
username*: string ## RPC authorization username
password*: string ## RPC authorization password
NetworkFlags* = enum NetworkFlags* = enum
## Ethereum network flags ## Ethereum network flags
LocalNet, ## Use local network only RopstenNet, ## Use test Ropsten network
TestNet, ## Use test network only RinkebyNet, ## Use test Rinkeby network
MordenNet, ## Use test Morden network
KovanNet, ## Use test Kovan network
CustomNet, ## Use custom network
MainNet, ## Use main network only MainNet, ## Use main network only
NoDiscover, ## Peer discovery disabled NoDiscover, ## Peer discovery disabled
V5Discover, ## Dicovery V5 enabled V5Discover, ## Dicovery V5 enabled
@ -76,6 +84,7 @@ type
discPort*: uint16 discPort*: uint16
maxPeers*: int maxPeers*: int
maxPendingPeers*: int maxPendingPeers*: int
networkId*: int
nodeKey*: PrivateKey nodeKey*: PrivateKey
DebugConfiguration* = object DebugConfiguration* = object
@ -96,14 +105,10 @@ proc initConfiguration(): NimbusConfiguration =
## RPC defaults ## RPC defaults
result.rpc.flags = {} result.rpc.flags = {}
result.rpc.bindAddress = parseIpAddress("127.0.0.1") result.rpc.binds = @[initTAddress("127.0.0.1:8545")]
result.rpc.bindPort = uint16(7654)
result.rpc.username = ""
result.rpc.password = ""
result.rpc.allowedIPs = newSeq[IpAddress]()
## Network defaults ## Network defaults
result.net.flags = {TestNet} result.net.flags = {RopstenNet}
result.net.bootNodes = newSeq[ENode]() result.net.bootNodes = newSeq[ENode]()
result.net.bootNodes4 = newSeq[ENode]() result.net.bootNodes4 = newSeq[ENode]()
result.net.bootNodes5 = newSeq[ENode]() result.net.bootNodes5 = newSeq[ENode]()
@ -136,26 +141,28 @@ proc processInteger(v: string, o: var int): ConfigStatus =
except: except:
result = ErrorParseOption result = ErrorParseOption
proc processIpAddress(v: string, o: var IpAddress): ConfigStatus = proc processAddressPortsList(v: string,
## Convert string to IpAddress. o: var seq[TransportAddress]): ConfigStatus =
try: var list = newSeq[string]()
o = parseIpAddress(v)
result = Success
except:
result = ErrorParseOption
proc processAddressesList(v: string, o: var seq[IpAddress]): ConfigStatus =
## Convert comma-separated list of strings to list of IpAddress.
var
address: IpAddress
list = newSeq[string]()
processList(v, list) processList(v, list)
for item in list: for item in list:
result = processIpAddress(item, address) var tas4: seq[TransportAddress]
if result == Success: var tas6: seq[TransportAddress]
o.add(address) try:
else: tas4 = resolveTAddress(item, IpAddressFamily.IPv4)
except:
discard
try:
tas6 = resolveTAddress(item, IpAddressFamily.IPv6)
except:
discard
if len(tas4) == 0 and len(tas6) == 0:
result = ErrorParseOption
break break
else:
for a in tas4: o.add(a)
for a in tas6: o.add(a)
result = Success
proc processENode(v: string, o: var ENode): ConfigStatus = proc processENode(v: string, o: var ENode): ConfigStatus =
## Convert string to ENode. ## Convert string to ENode.
@ -218,21 +225,32 @@ proc processRpcArguments(key, value: string): ConfigStatus =
if skey == "rpc": if skey == "rpc":
config.rpc.flags.incl(Enabled) config.rpc.flags.incl(Enabled)
elif skey == "rpcbind": elif skey == "rpcbind":
result = processIpAddress(value, config.rpc.bindAddress) config.rpc.binds.setLen(0)
elif skey == "rpcport": result = processAddressPortsList(value, config.rpc.binds)
var res = 0
result = processInteger(value, res)
if result == Success:
config.rpc.bindPort = uint16(res and 0xFFFF)
elif skey == "rpcuser":
config.rpc.username = value
elif skey == "rpcpassword":
config.rpc.password = value
elif skey == "rpcallowip":
result = processAddressesList(value, config.rpc.allowedIPs)
else: else:
result = EmptyOption result = EmptyOption
proc setNetwork(conf: var NetConfiguration, network: NetworkFlags,
id: int = 0) =
conf.flags.excl({MainNet, MordenNet, RopstenNet, RinkebyNet, KovanNet,
CustomNet})
conf.flags.incl(network)
case network
of MainNet:
conf.networkId = 1
of MordenNet:
conf.networkId = 2
of RopstenNet:
conf.networkId = 3
of RinkebyNet:
conf.networkId = 4
of KovanNet:
conf.networkId = 42
of CustomNet:
conf.networkId = id
else:
discard
proc processNetArguments(key, value: string): ConfigStatus = proc processNetArguments(key, value: string): ConfigStatus =
## Processes only `Networking` related command line options ## Processes only `Networking` related command line options
result = Success result = Success
@ -245,17 +263,34 @@ proc processNetArguments(key, value: string): ConfigStatus =
elif skey == "bootnodesv5": elif skey == "bootnodesv5":
result = processENodesList(value, config.net.bootNodes5) result = processENodesList(value, config.net.bootNodes5)
elif skey == "testnet": elif skey == "testnet":
config.net.flags.incl(TestNet) config.net.setNetwork(RopstenNet)
config.net.flags.excl(LocalNet)
config.net.flags.excl(MainNet)
elif skey == "localnet":
config.net.flags.incl(LocalNet)
config.net.flags.excl(TestNet)
config.net.flags.excl(MainNet)
elif skey == "mainnet": elif skey == "mainnet":
config.net.flags.incl(MainNet) config.net.setNetwork(MainNet)
config.net.flags.excl(LocalNet) elif skey == "ropsten":
config.net.flags.excl(TestNet) config.net.setNetwork(RopstenNet)
elif skey == "rinkeby":
config.net.setNetwork(RinkebyNet)
elif skey == "morden":
config.net.setNetwork(MordenNet)
elif skey == "kovan":
config.net.setNetwork(KovanNet)
elif skey == "networkid":
var res = 0
result = processInteger(value, res)
if result == Success:
case res
of 1:
config.net.setNetwork(MainNet)
of 2:
config.net.setNetwork(MordenNet)
of 3:
config.net.setNetwork(RopstenNet)
of 4:
config.net.setNetwork(RinkebyNet)
of 42:
config.net.setNetwork(KovanNet)
else:
config.net.setNetwork(CustomNet, res)
elif skey == "nodiscover": elif skey == "nodiscover":
config.net.flags.incl(NoDiscover) config.net.flags.incl(NoDiscover)
elif skey == "v5discover": elif skey == "v5discover":
@ -321,13 +356,13 @@ template checkArgument(a, b, c, e: untyped) =
(e) = "Error processing option [" & key & "] with value [" & value & "]" (e) = "Error processing option [" & key & "] with value [" & value & "]"
result = res result = res
break break
elif res == ErrorIncorrectOption:
proc getVersionString*(): string = (e) = "Incorrect value for option [" & key & "] value [" & value & "]"
result = NimbusName & ", " & NimbusVersion & "\n" & NimbusCopyright & "\n" result = res
break
proc getHelpString*(): string = proc getHelpString*(): string =
result = getVersionString() result = """
result &= """
USAGE: USAGE:
nimbus [options] nimbus [options]
@ -346,17 +381,16 @@ NETWORKING OPTIONS:
--nodiscover Disables the peer discovery mechanism (manual peer addition) --nodiscover Disables the peer discovery mechanism (manual peer addition)
--v5discover Enables the experimental RLPx V5 (Topic Discovery) mechanism --v5discover Enables the experimental RLPx V5 (Topic Discovery) mechanism
--nodekey:<value> P2P node private key (as hexadecimal string) --nodekey:<value> P2P node private key (as hexadecimal string)
--testnet Use Ethereum Test Network --testnet Use Ethereum Ropsten Test Network (default)
--rinkeby Use Ethereum Rinkeby Test Network
--ropsten Use Ethereum Test Network (Ropsten Network)
--mainnet Use Ethereum Main Network --mainnet Use Ethereum Main Network
--localnet Use local network only --morden Use Ethereum Morden Test Network
--networkid:<value> Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 3)
API AND CONSOLE OPTIONS: API AND CONSOLE OPTIONS:
--rpc Enable the HTTP-RPC server --rpc Enable the HTTP-RPC server
--rpcbind:<value> HTTP-RPC server will bind to given address (default: 127.0.0.1) --rpcbind:<value> HTTP-RPC server will bind to given comma separated address:port pairs (default: 127.0.0.1:8545)
--rpcport:<value> HTTP-RPC server listening port (default: 7654)
--rpcuser:<value> HTTP-RPC authorization username
--rpcpassword:<value> HTTP-RPC authorization password
--rpcallowip:<value> Allow HTTP-RPC connections from specified IP addresses
LOGGING AND DEBUGGING OPTIONS: LOGGING AND DEBUGGING OPTIONS:
--debug Enable debug mode --debug Enable debug mode
@ -379,7 +413,7 @@ proc processArguments*(msg: var string): ConfigStatus =
result = Success result = Success
break break
of "version", "ver", "v": of "version", "ver", "v":
msg = getVersionString() msg = NimbusVersion
result = Success result = Success
break break
else: else:

View File

@ -7,11 +7,13 @@
# This file may not be copied, modified, or distributed except according to # This file may not be copied, modified, or distributed except according to
# those terms. # those terms.
import config, asyncdispatch import strutils
import p2p/service, p2p/disc4service import asyncdispatch2, eth-rpc/server
import config, rpc/common
when isMainModule: when isMainModule:
var message: string var message: string
echo NimbusHeader
if processArguments(message) != ConfigStatus.Success: if processArguments(message) != ConfigStatus.Success:
echo message echo message
quit(QuitFailure) quit(QuitFailure)
@ -19,12 +21,11 @@ when isMainModule:
if len(message) > 0: if len(message) > 0:
echo message echo message
var disc4: Discovery4Service var conf = getConfiguration()
if disc4.init() != ServiceStatus.Success: if RpcFlags.Enabled in conf.rpc.flags:
quit(QuitFailure) var rpcserver = newRpcServer(conf.rpc.binds)
if disc4.configure() != ServiceStatus.Success: setupCommonRPC(rpcserver)
echo disc4.errorMessage() rpcserver.start()
quit(QuitFailure)
if disc4.start() != ServiceStatus.Success: while true:
echo disc4.errorMessage() poll()
quit(QuitFailure)

22
nimbus/rpc/common.nim Normal file
View File

@ -0,0 +1,22 @@
# 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 eth-rpc/server, nimcrypto
import ../config
proc setupCommonRPC*(server: RpcServer) =
server.rpc("web3_clientVersion") do() -> string:
result = NimbusIdent
server.rpc("web3_sha3") do(data: string) -> string:
var rawdata = fromHex(data)
result = "0x" & $keccak_256.digest(rawdata)
server.rpc("net_version") do() -> int:
let conf = getConfiguration()
result = conf.net.networkId