From 5e7f2c990d0fe00fc70ede09f48846a29c57cf3d Mon Sep 17 00:00:00 2001 From: cheatfate Date: Wed, 13 Jun 2018 14:13:29 +0300 Subject: [PATCH] Initial commit. 3 common RPC procedures implemented. --- nimbus.nimble | 2 + nimbus/config.nim | 202 ++++++++++++++++++++++++------------------ nimbus/nimbus.nim | 23 ++--- nimbus/rpc/common.nim | 22 +++++ 4 files changed, 154 insertions(+), 95 deletions(-) create mode 100644 nimbus/rpc/common.nim diff --git a/nimbus.nimble b/nimbus.nimble index 87e0e78c8..1269431bf 100644 --- a/nimbus.nimble +++ b/nimbus.nimble @@ -13,6 +13,8 @@ requires "nim >= 0.18.1", "stint", "https://github.com/status-im/nim-eth-common", "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" proc test(name: string, lang = "c") = diff --git a/nimbus/config.nim b/nimbus/config.nim index e8f4bc3ac..16cfa876f 100644 --- a/nimbus/config.nim +++ b/nimbus/config.nim @@ -7,8 +7,8 @@ # This file may not be copied, modified, or distributed except according to # those terms. -import parseopt, strutils, net, ethp2p, eth_keyfile, eth_keys, json, - nimcrypto +import parseopt, strutils +import asyncdispatch2, eth_keys, ethp2p const NimbusName* = "Nimbus" @@ -29,42 +29,50 @@ const NimbusVersion* = $NimbusMajor & "." & $NimbusMinor & "." & $NimbusPatch ## 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 ConfigStatus* = enum ## Configuration status flags - Success, ## Success - EmptyOption, ## No options in category - ErrorUnknownOption, ## Unknown option in command line found - ErrorParseOption, ## Error in parsing command line option - Error ## Unspecified error + Success, ## Success + EmptyOption, ## No options in category + ErrorUnknownOption, ## Unknown option in command line found + ErrorParseOption, ## Error in parsing command line option + ErrorIncorrectOption, ## Option has incorrect value + Error ## Unspecified error RpcFlags* {.pure.} = enum ## RPC flags - Enabled ## RPC enabled + Enabled ## RPC enabled RpcConfiguration* = object ## JSON-RPC configuration object - flags*: set[RpcFlags] ## RPC flags - bindAddress*: IpAddress ## 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 + flags*: set[RpcFlags] ## RPC flags + binds*: seq[TransportAddress] ## RPC bind address NetworkFlags* = enum ## Ethereum network flags - LocalNet, ## Use local network only - TestNet, ## Use test network only - MainNet, ## Use main network only - NoDiscover, ## Peer discovery disabled - V5Discover, ## Dicovery V5 enabled + RopstenNet, ## Use test Ropsten network + RinkebyNet, ## Use test Rinkeby network + MordenNet, ## Use test Morden network + KovanNet, ## Use test Kovan network + CustomNet, ## Use custom network + MainNet, ## Use main network only + NoDiscover, ## Peer discovery disabled + V5Discover, ## Dicovery V5 enabled DebugFlags* {.pure.} = enum ## Debug selection flags - Enabled, ## Debugging enabled - Test1, ## Test1 enabled - Test2, ## Test2 enabled - Test3 ## Test3 enabled + Enabled, ## Debugging enabled + Test1, ## Test1 enabled + Test2, ## Test2 enabled + Test3 ## Test3 enabled NetConfiguration* = object ## Network configuration object @@ -76,6 +84,7 @@ type discPort*: uint16 maxPeers*: int maxPendingPeers*: int + networkId*: int nodeKey*: PrivateKey DebugConfiguration* = object @@ -84,9 +93,9 @@ type NimbusConfiguration* = ref object ## Main Nimbus configuration object - rpc*: RpcConfiguration ## JSON-RPC configuration - net*: NetConfiguration ## Network configuration - debug*: DebugConfiguration ## Debug configuration + rpc*: RpcConfiguration ## JSON-RPC configuration + net*: NetConfiguration ## Network configuration + debug*: DebugConfiguration ## Debug configuration var nimbusConfig {.threadvar.}: NimbusConfiguration @@ -96,14 +105,10 @@ proc initConfiguration(): NimbusConfiguration = ## RPC defaults result.rpc.flags = {} - result.rpc.bindAddress = parseIpAddress("127.0.0.1") - result.rpc.bindPort = uint16(7654) - result.rpc.username = "" - result.rpc.password = "" - result.rpc.allowedIPs = newSeq[IpAddress]() + result.rpc.binds = @[initTAddress("127.0.0.1:8545")] ## Network defaults - result.net.flags = {TestNet} + result.net.flags = {RopstenNet} result.net.bootNodes = newSeq[ENode]() result.net.bootNodes4 = newSeq[ENode]() result.net.bootNodes5 = newSeq[ENode]() @@ -136,26 +141,28 @@ proc processInteger(v: string, o: var int): ConfigStatus = except: result = ErrorParseOption -proc processIpAddress(v: string, o: var IpAddress): ConfigStatus = - ## Convert string to IpAddress. - try: - 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]() +proc processAddressPortsList(v: string, + o: var seq[TransportAddress]): ConfigStatus = + var list = newSeq[string]() processList(v, list) for item in list: - result = processIpAddress(item, address) - if result == Success: - o.add(address) - else: + var tas4: seq[TransportAddress] + var tas6: seq[TransportAddress] + try: + 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 + 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 = ## Convert string to ENode. @@ -218,21 +225,32 @@ proc processRpcArguments(key, value: string): ConfigStatus = if skey == "rpc": config.rpc.flags.incl(Enabled) elif skey == "rpcbind": - result = processIpAddress(value, config.rpc.bindAddress) - elif skey == "rpcport": - 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) + config.rpc.binds.setLen(0) + result = processAddressPortsList(value, config.rpc.binds) else: 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 = ## Processes only `Networking` related command line options result = Success @@ -245,17 +263,34 @@ proc processNetArguments(key, value: string): ConfigStatus = elif skey == "bootnodesv5": result = processENodesList(value, config.net.bootNodes5) elif skey == "testnet": - config.net.flags.incl(TestNet) - 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) + config.net.setNetwork(RopstenNet) elif skey == "mainnet": - config.net.flags.incl(MainNet) - config.net.flags.excl(LocalNet) - config.net.flags.excl(TestNet) + config.net.setNetwork(MainNet) + elif skey == "ropsten": + 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": config.net.flags.incl(NoDiscover) elif skey == "v5discover": @@ -321,13 +356,13 @@ template checkArgument(a, b, c, e: untyped) = (e) = "Error processing option [" & key & "] with value [" & value & "]" result = res break - -proc getVersionString*(): string = - result = NimbusName & ", " & NimbusVersion & "\n" & NimbusCopyright & "\n" + elif res == ErrorIncorrectOption: + (e) = "Incorrect value for option [" & key & "] value [" & value & "]" + result = res + break proc getHelpString*(): string = - result = getVersionString() - result &= """ + result = """ USAGE: nimbus [options] @@ -346,17 +381,16 @@ NETWORKING OPTIONS: --nodiscover Disables the peer discovery mechanism (manual peer addition) --v5discover Enables the experimental RLPx V5 (Topic Discovery) mechanism --nodekey: 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 - --localnet Use local network only + --morden Use Ethereum Morden Test Network + --networkid: Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 3) API AND CONSOLE OPTIONS: --rpc Enable the HTTP-RPC server - --rpcbind: HTTP-RPC server will bind to given address (default: 127.0.0.1) - --rpcport: HTTP-RPC server listening port (default: 7654) - --rpcuser: HTTP-RPC authorization username - --rpcpassword: HTTP-RPC authorization password - --rpcallowip: Allow HTTP-RPC connections from specified IP addresses + --rpcbind: HTTP-RPC server will bind to given comma separated address:port pairs (default: 127.0.0.1:8545) LOGGING AND DEBUGGING OPTIONS: --debug Enable debug mode @@ -379,7 +413,7 @@ proc processArguments*(msg: var string): ConfigStatus = result = Success break of "version", "ver", "v": - msg = getVersionString() + msg = NimbusVersion result = Success break else: diff --git a/nimbus/nimbus.nim b/nimbus/nimbus.nim index ae78b5d8b..c0d520eb5 100644 --- a/nimbus/nimbus.nim +++ b/nimbus/nimbus.nim @@ -7,11 +7,13 @@ # This file may not be copied, modified, or distributed except according to # those terms. -import config, asyncdispatch -import p2p/service, p2p/disc4service +import strutils +import asyncdispatch2, eth-rpc/server +import config, rpc/common when isMainModule: var message: string + echo NimbusHeader if processArguments(message) != ConfigStatus.Success: echo message quit(QuitFailure) @@ -19,12 +21,11 @@ when isMainModule: if len(message) > 0: echo message - var disc4: Discovery4Service - if disc4.init() != ServiceStatus.Success: - quit(QuitFailure) - if disc4.configure() != ServiceStatus.Success: - echo disc4.errorMessage() - quit(QuitFailure) - if disc4.start() != ServiceStatus.Success: - echo disc4.errorMessage() - quit(QuitFailure) + var conf = getConfiguration() + if RpcFlags.Enabled in conf.rpc.flags: + var rpcserver = newRpcServer(conf.rpc.binds) + setupCommonRPC(rpcserver) + rpcserver.start() + + while true: + poll() diff --git a/nimbus/rpc/common.nim b/nimbus/rpc/common.nim new file mode 100644 index 000000000..c2bb8e4d3 --- /dev/null +++ b/nimbus/rpc/common.nim @@ -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