From 533bd6caf494e970b4a2b781df1fe609b8546835 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Wed, 20 Jun 2018 20:27:32 +0300 Subject: [PATCH] Integrated P2P & RPC servers. --- nimbus.nimble | 1 + nimbus/config.nim | 337 +++++++++++++++++++++++------------- nimbus/nimbus.nim | 98 +++++++++-- nimbus/p2p/disc4service.nim | 88 ---------- nimbus/p2p/service.nim | 55 ------ nimbus/rpc/common.nim | 18 ++ nimbus/rpc/p2p.nim | 15 ++ 7 files changed, 337 insertions(+), 275 deletions(-) delete mode 100644 nimbus/p2p/disc4service.nim delete mode 100644 nimbus/p2p/service.nim create mode 100644 nimbus/rpc/common.nim create mode 100644 nimbus/rpc/p2p.nim diff --git a/nimbus.nimble b/nimbus.nimble index 5e8f910d2..5d2559518 100644 --- a/nimbus.nimble +++ b/nimbus.nimble @@ -13,6 +13,7 @@ requires "nim >= 0.18.1", "rlp", "stint", "https://github.com/status-im/nim-eth-common", + "https://github.com/status-im/nim-eth-rpc", "eth_p2p", "eth_keyfile" diff --git a/nimbus/config.nim b/nimbus/config.nim index 4d261d008..a2eb49e7a 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, eth_p2p, eth_keyfile, eth_keys, json, - nimcrypto +import parseopt, strutils +import asyncdispatch2, eth_keys, eth_p2p const NimbusName* = "Nimbus" @@ -29,97 +29,114 @@ const NimbusVersion* = $NimbusMajor & "." & $NimbusMinor & "." & $NimbusPatch ## is the version of Nimbus as a string. + NimbusHeader* = NimbusName & " Version " & NimbusVersion & + " [" & hostOS & ": " & hostCPU & "]\r\n" & + NimbusCopyright + ## is the header which printed, when nimbus binary got executed + + NimbusIdent* = "$1/$2 ($3/$4)" % [NimbusName, NimbusVersion, hostCPU, hostOS] + ## project ident name for networking services + +const + MainnetBootnodes = [ + "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303" , # IE + "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", # US-WEST + "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", # BR + "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", # AU + "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", # SG + "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303" # DE + ] + + RopstenBootnodes = [ + "enode://30b7ab30a01c124a6cceca36863ece12c4f5fa68e3ba9b0b51407ccc002eeed3b3102d20a88f1c1d3c3154e2449317b8ef95090e77b312d5cc39354f86d5d606@52.176.7.10:30303", # US-Azure geth + "enode://865a63255b3bb68023b6bffd5095118fcc13e79dcf014fe4e47e065c350c7cc72af2e53eff895f11ba1bbb6a2b33271c1116ee870f266618eadfc2e78aa7349c@52.176.100.77:30303", # US-Azure parity + "enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303", # Parity + "enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303" # @gpip + ] + + RinkebyBootnodes = [ + "enode://a24ac7c5484ef4ed0c5eb2d36620ba4e4aa13b8c84684e1b4aab0cebea2ae45cb4d375b77eab56516d34bfbd3c1a833fc51296ff084b770b94fb9028c4d25ccf@52.169.42.101:30303", # IE + "enode://343149e4feefa15d882d9fe4ac7d88f885bd05ebb735e547f12e12080a9fa07c8014ca6fd7f373123488102fe5e34111f8509cf0b7de3f5b44339c9f25e87cb8@52.3.158.184:30303", # INFURA + "enode://b6b28890b006743680c52e64e0d16db57f28124885595fa03a562be1d2bf0f3a1da297d56b13da25fb992888fd556d4c1a27b1f39d531bde7de1921c90061cc6@159.89.28.211:30303", # AKASHA + ] + + DiscoveryV5Bootnodes = [ + "enode://06051a5573c81934c9554ef2898eb13b33a34b94cf36b202b69fde139ca17a85051979867720d4bdae4323d4943ddf9aeeb6643633aa656e0be843659795007a@35.177.226.168:30303", + "enode://0cc5f5ffb5d9098c8b8c62325f3797f56509bff942704687b6530992ac706e2cb946b90a34f1f19548cd3c7baccbcaea354531e5983c7d1bc0dee16ce4b6440b@40.118.3.223:30304", + "enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30306", + "enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30307" + ] + + KovanBootnodes = [ + "enode://56abaf065581a5985b8c5f4f88bd202526482761ba10be9bfdcd14846dd01f652ec33fde0f8c0fd1db19b59a4c04465681fcef50e11380ca88d25996191c52de@40.71.221.215:30303", + "enode://d07827483dc47b368eaf88454fb04b41b7452cf454e194e2bd4c14f98a3278fed5d819dbecd0d010407fc7688d941ee1e58d4f9c6354d3da3be92f55c17d7ce3@52.166.117.77:30303", + "enode://8fa162563a8e5a05eef3e1cd5abc5828c71344f7277bb788a395cce4a0e30baf2b34b92fe0b2dbbba2313ee40236bae2aab3c9811941b9f5a7e8e90aaa27ecba@52.165.239.18:30303", + "enode://7e2e7f00784f516939f94e22bdc6cf96153603ca2b5df1c7cc0f90a38e7a2f218ffb1c05b156835e8b49086d11fdd1b3e2965be16baa55204167aa9bf536a4d9@52.243.47.56:30303", + "enode://0518a3d35d4a7b3e8c433e7ffd2355d84a1304ceb5ef349787b556197f0c87fad09daed760635b97d52179d645d3e6d16a37d2cc0a9945c2ddf585684beb39ac@40.68.248.100:30303" + ] + 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 - flags*: set[NetworkFlags] - bootNodes*: seq[ENode] - bootNodes4*: seq[ENode] - bootNodes5*: seq[ENode] - bindPort*: uint16 - discPort*: uint16 - maxPeers*: int - maxPendingPeers*: int - nodeKey*: PrivateKey + flags*: set[NetworkFlags] ## Network flags + bootNodes*: seq[ENode] ## List of bootnodes + bindPort*: uint16 ## Main TCP bind port + discPort*: uint16 ## Discovery UDP bind port + maxPeers*: int ## Maximum allowed number of peers + maxPendingPeers*: int ## Maximum allowed pending peers + networkId*: int ## Network ID as integer + ident*: string ## Server ident name string + nodeKey*: PrivateKey ## Server private key DebugConfiguration* = object ## Debug configuration object - flags*: set[DebugFlags] + flags*: set[DebugFlags] ## Debug flags 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 -proc initConfiguration(): NimbusConfiguration = - ## Allocates and initializes `NimbusConfiguration` with default values - result = new 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]() - - ## Network defaults - result.net.flags = {TestNet} - result.net.bootNodes = newSeq[ENode]() - result.net.bootNodes4 = newSeq[ENode]() - result.net.bootNodes5 = newSeq[ENode]() - result.net.maxPeers = 25 - result.net.maxPendingPeers = 0 - result.net.bindPort = 30303'u16 - result.net.discPort = 30303'u16 - - ## Debug defaults - result.debug.flags = {} - -proc getConfiguration*(): NimbusConfiguration = - ## Retreive current configuration object `NimbusConfiguration`. - if isNil(nimbusConfig): - nimbusConfig = initConfiguration() - result = nimbusConfig +proc getConfiguration*(): NimbusConfiguration {.gcsafe.} proc processList(v: string, o: var seq[string]) = ## Process comma-separated list of strings. @@ -136,26 +153,29 @@ 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 = + ## Convert ;...; to list of `TransportAddress`. + 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 +238,47 @@ 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 +template setBootnodes(onodes, nodes: untyped): untyped = + var node: ENode + for item in (nodes): + doAssert(processENode(item, node) == Success) + (onodes).add(node) + +proc setNetwork(conf: var NetConfiguration, network: NetworkFlags, + id: int = 0) = + ## Set network id and default network bootnodes + conf.flags.excl({MainNet, MordenNet, RopstenNet, RinkebyNet, KovanNet, + CustomNet}) + conf.flags.incl(network) + case network + of MainNet: + conf.networkId = 1 + conf.bootNodes.setLen(0) + conf.bootNodes.setBootnodes(MainnetBootnodes) + of MordenNet: + conf.networkId = 2 + of RopstenNet: + conf.networkId = 3 + conf.bootNodes.setLen(0) + conf.bootNodes.setBootnodes(RopstenBootnodes) + of RinkebyNet: + conf.networkId = 4 + conf.bootNodes.setLen(0) + conf.bootNodes.setBootnodes(RinkebyBootnodes) + of KovanNet: + conf.networkId = 42 + conf.bootNodes.setLen(0) + conf.bootNodes.setBootnodes(KovanBootnodes) + of CustomNet: + conf.networkId = id + else: + discard + proc processNetArguments(key, value: string): ConfigStatus = ## Processes only `Networking` related command line options result = Success @@ -241,25 +287,44 @@ proc processNetArguments(key, value: string): ConfigStatus = if skey == "bootnodes": result = processENodesList(value, config.net.bootnodes) elif skey == "bootnodesv4": - result = processENodesList(value, config.net.bootNodes4) + result = processENodesList(value, config.net.bootNodes) elif skey == "bootnodesv5": - result = processENodesList(value, config.net.bootNodes5) + result = processENodesList(value, config.net.bootNodes) 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": config.net.flags.incl(V5Discover) + config.net.bootNodes.setLen(0) + config.net.bootNodes.setBootnodes(DiscoveryV5Bootnodes) elif skey == "port": var res = 0 result = processInteger(value, res) @@ -285,6 +350,8 @@ proc processNetArguments(key, value: string): ConfigStatus = result = processPrivateKey(value, res) if result == Success: config.net.nodeKey = res + elif skey == "ident": + config.net.ident = value else: result = EmptyOption @@ -314,6 +381,7 @@ proc dumpConfiguration*(): string = result = repr config template checkArgument(a, b, c, e: untyped) = + ## Checks if arguments got processed successfully var res = (a)(string((b)), string((c))) if res == Success: continue @@ -321,13 +389,37 @@ template checkArgument(a, b, c, e: untyped) = (e) = "Error processing option [" & key & "] with value [" & value & "]" result = res break + elif res == ErrorIncorrectOption: + (e) = "Incorrect value for option [" & key & "] value [" & value & "]" + result = res + break -proc getVersionString*(): string = - result = NimbusName & ", " & NimbusVersion & "\n" & NimbusCopyright & "\n" +proc initConfiguration(): NimbusConfiguration = + ## Allocates and initializes `NimbusConfiguration` with default values + result = new NimbusConfiguration + ## RPC defaults + result.rpc.flags = {} + result.rpc.binds = @[initTAddress("127.0.0.1:8545")] + + ## Network defaults + result.net.setNetwork(RopstenNet) + result.net.maxPeers = 25 + result.net.maxPendingPeers = 0 + result.net.bindPort = 30303'u16 + result.net.discPort = 30303'u16 + result.net.ident = NimbusIdent + + ## Debug defaults + result.debug.flags = {} + +proc getConfiguration*(): NimbusConfiguration = + ## Retreive current configuration object `NimbusConfiguration`. + if isNil(nimbusConfig): + nimbusConfig = initConfiguration() + result = nimbusConfig proc getHelpString*(): string = - result = getVersionString() - result &= """ + result = """ USAGE: nimbus [options] @@ -340,31 +432,34 @@ NETWORKING OPTIONS: --bootnodesv4: Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes) --botnoodesv5: Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes) --port: Network listening TCP port (default: 30303) - --discport: Netowkr listening UDP port (default: 30303) + --discport: Network listening UDP port (default: 30303) --maxpeers: Maximum number of network peers (default: 25) --maxpendpeers: 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: 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) + --ident: Client identifier (default is '$1') 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 --test: Perform specified test -""" +""" % [ + NimbusIdent + ] proc processArguments*(msg: var string): ConfigStatus = ## Process command line argument and update `NimbusConfiguration`. + discard getConfiguration() var opt = initOptParser() var length = 0 for kind, key, value in opt.getopt(): @@ -379,7 +474,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 e8bc4c6e8..4de068fbe 100644 --- a/nimbus/nimbus.nim +++ b/nimbus/nimbus.nim @@ -7,24 +7,100 @@ # This file may not be copied, modified, or distributed except according to # those terms. -import config -import p2p/service, p2p/disc4service +import strutils, net +import asyncdispatch2, rpcserver, eth_p2p, eth_keys +import config, rpc/common, rpc/p2p + +## TODO: +## * No IPv6 support +## * No multiple bind addresses support +## * No database support + +when not defined(windows): + from posix import SIGINT, SIGTERM + +type + NimbusState = enum + Starting, Running, Stopping, Stopped + + NimbusObject = ref object + rpcServer*: RpcServer + p2pServer*: P2PServer + state*: NimbusState + +proc start(): NimbusObject = + var nimbus = NimbusObject() + var conf = getConfiguration() + + ## Creating RPC Server + if RpcFlags.Enabled in conf.rpc.flags: + nimbus.rpcServer = newRpcServer(conf.rpc.binds) + setupCommonRpc(nimbus.rpcServer) + + ## Creating P2P Server + if conf.net.nodekey.isZeroKey(): + conf.net.nodekey = newPrivateKey() + + var keypair: KeyPair + keypair.seckey = conf.net.nodekey + keypair.pubkey = conf.net.nodekey.getPublicKey() + + var address: Address + address.ip = parseIpAddress("0.0.0.0") + address.tcpPort = Port(conf.net.bindPort) + address.udpPort = Port(conf.net.discPort) + + nimbus.p2pServer = newP2PServer(keypair, address, nil, conf.net.bootNodes, + conf.net.ident, conf.net.networkId) + + if RpcFlags.Enabled in conf.rpc.flags: + setupP2PRpc(nimbus.p2pServer, nimbus.rpcServer) + + ## Starting servers + nimbus.state = Starting + if RpcFlags.Enabled in conf.rpc.flags: + nimbus.rpcServer.rpc("admin_quit") do() -> string: + nimbus.state = Stopping + result = "EXITING" + nimbus.rpcServer.start() + nimbus.p2pServer.start() + nimbus.state = Running + result = nimbus + +proc stop*(nimbus: NimbusObject) {.async.} = + echo "Graceful shutdown" + nimbus.rpcServer.stop() + +proc process*(nimbus: NimbusObject) = + if nimbus.state == Running: + when not defined(windows): + proc signalBreak(udata: pointer) = + nimbus.state = Stopping + # Adding SIGINT, SIGTERM handlers + discard addSignal(SIGINT, signalBreak) + discard addSignal(SIGTERM, signalBreak) + + # Main loop + while nimbus.state == Running: + poll() + + # Stop loop + waitFor nimbus.stop() when isMainModule: var message: string + + ## Pring Nimbus header + echo NimbusHeader + + ## Processing command line arguments if processArguments(message) != ConfigStatus.Success: echo message quit(QuitFailure) else: if len(message) > 0: echo message + quit(QuitSuccess) - 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 nimbus = start() + nimbus.process() diff --git a/nimbus/p2p/disc4service.nim b/nimbus/p2p/disc4service.nim deleted file mode 100644 index 8ed8099db..000000000 --- a/nimbus/p2p/disc4service.nim +++ /dev/null @@ -1,88 +0,0 @@ -# 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 eth_p2p, 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 diff --git a/nimbus/p2p/service.nim b/nimbus/p2p/service.nim deleted file mode 100644 index 01813cfdb..000000000 --- a/nimbus/p2p/service.nim +++ /dev/null @@ -1,55 +0,0 @@ -# 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 \ No newline at end of file diff --git a/nimbus/rpc/common.nim b/nimbus/rpc/common.nim new file mode 100644 index 000000000..420af499f --- /dev/null +++ b/nimbus/rpc/common.nim @@ -0,0 +1,18 @@ +# 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) diff --git a/nimbus/rpc/p2p.nim b/nimbus/rpc/p2p.nim new file mode 100644 index 000000000..c4015cb8d --- /dev/null +++ b/nimbus/rpc/p2p.nim @@ -0,0 +1,15 @@ +# 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 nimcrypto, eth-rpc/server, eth_p2p +import ../config + +proc setupP2PRPC*(server: P2PServer, rpcsrv: RpcServer) = + rpcsrv.rpc("net_version") do() -> int: + let conf = getConfiguration() + result = conf.net.networkId