Skip to content

Commit

Permalink
enhance net-key command line option to accept random, hex, and path
Browse files Browse the repository at this point in the history
- previously it only accept hex
- fix #587
  • Loading branch information
jangko committed Jul 28, 2022
1 parent a7494e1 commit f3512ab
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 27 deletions.
13 changes: 8 additions & 5 deletions nimbus/config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,14 @@ type
defaultValueDesc: $DiscoveryType.V4
name: "discovery" .}: DiscoveryType

nodeKeyHex* {.
desc: "P2P node private key (as 32 bytes hex string)"
defaultValue: ""
defaultValueDesc: "random"
name: "node-key" .}: string
netKey* {.
desc: "P2P ethereum node (secp256k1) private key (random, path, hex)"
longDesc:
"- random: generate random network key for this node instance\n" &
"- path : path to where the private key will be loaded or auto generated\n" &
"- hex : 32 bytes hex of network private key"
defaultValue: "random"
name: "net-key" .}: string

agentString* {.
desc: "Node agent string which is used as identifier in network"
Expand Down
48 changes: 41 additions & 7 deletions nimbus/context.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
# those terms.

import
std/[strutils, os],
accounts/manager,
stew/results,
stew/[results, io2, byteutils],
eth/keys

export manager
Expand All @@ -32,12 +33,45 @@ proc randomPrivateKey*(ctx: EthContext): PrivateKey =
proc randomKeyPair*(ctx: EthContext): KeyPair =
random(KeyPair, ctx.rng[])

proc hexToKeyPair*(ctx: EthContext, hexPrivateKey: string): Result[KeyPair, string] =
if hexPrivateKey.len == 0:
proc containsOnlyHexDigits(hex: string): bool =
const HexDigitsX = HexDigits + {'x'}
for c in hex:
if c notin HexDigitsX:
return false
true

proc getNetKeys*(ctx: EthContext, netKey, dataDir: string): Result[KeyPair, string] =
if netKey.len == 0 or netKey == "random":
let privateKey = ctx.randomPrivateKey()
ok(privateKey.toKeyPair())
else:
let res = PrivateKey.fromHex(hexPrivateKey)
return ok(privateKey.toKeyPair())
elif netKey.len in {64, 66} and netKey.containsOnlyHexDigits:
let res = PrivateKey.fromHex(netKey)
if res.isErr:
return err($res.error)
ok(res.get().toKeyPair())
return ok(res.get().toKeyPair())
else:
# TODO: should we secure the private key with
# keystore encryption?
if fileAccessible(netKey, {AccessFlags.Find}):
try:
let lines = netKey.readLines(1)
if lines.len == 0:
return err("empty network key file")
let rc = PrivateKey.fromHex(lines[0])
if rc.isErr:
return err($rc.error)
return ok(rc.get().toKeyPair())
except IOError as e:
return err("cannot open network key file: " & e.msg)
except ValueError as ex:
return err("invalid hex string in network key file: " & ex.msg)
else:
let privateKey = ctx.randomPrivateKey()

try:
createDir(netKey.splitFile.dir)
netKey.writeFile(privateKey.toRaw.to0xHex)
except IOError as e:
return err("could not write network key file: " & e.msg)

return ok(privateKey.toKeyPair())
26 changes: 15 additions & 11 deletions nimbus/nimbus.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import
metrics,
metrics/[chronos_httpserver, chronicles_support],
stew/shims/net as stewNet,
websock/types as ws,
websock/websock as ws,
"."/[conf_utils, config, constants, context, genesis, sealer, utils, version],
./db/[storage_types, db_chain, select_backend],
./graphql/ethapi,
Expand Down Expand Up @@ -69,21 +69,21 @@ proc manageAccounts(nimbus: NimbusNode, conf: NimbusConf) =
if string(conf.keyStore).len > 0:
let res = nimbus.ctx.am.loadKeystores(string conf.keyStore)
if res.isErr:
echo res.error()
fatal "Load keystore error", msg = res.error()
quit(QuitFailure)

if string(conf.importKey).len > 0:
let res = nimbus.ctx.am.importPrivateKey(string conf.importKey)
if res.isErr:
echo res.error()
fatal "Import private key error", msg = res.error()
quit(QuitFailure)

proc setupP2P(nimbus: NimbusNode, conf: NimbusConf,
chainDB: BaseChainDB, protocols: set[ProtocolFlag]) =
## Creating P2P Server
let kpres = nimbus.ctx.hexToKeyPair(conf.nodeKeyHex)
let kpres = nimbus.ctx.getNetKeys(conf.netKey, conf.dataDir.string)
if kpres.isErr:
echo kpres.error()
fatal "Get network keys error", msg = kpres.error
quit(QuitFailure)

let keypair = kpres.get()
Expand Down Expand Up @@ -117,7 +117,8 @@ proc setupP2P(nimbus: NimbusNode, conf: NimbusConf,
addAllCapabilities = false, minPeers = conf.maxPeers,
bootstrapNodes = bootstrapNodes,
bindUdpPort = conf.udpPort, bindTcpPort = conf.tcpPort,
bindIp = conf.listenAddress)
bindIp = conf.listenAddress,
rng = nimbus.ctx.rng)

# Add protocol capabilities based on protocol flags
if ProtocolFlag.Eth in protocols:
Expand Down Expand Up @@ -187,12 +188,12 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,
discard setTimer(Moment.fromNow(conf.logMetricsInterval.seconds), logMetrics)
discard setTimer(Moment.fromNow(conf.logMetricsInterval.seconds), logMetrics)

# Provide JWT authentication handler for websockets
# Provide JWT authentication handler for rpcHttpServer
let jwtKey = block:
# Create or load shared secret
let rc = nimbus.ctx.rng.jwtSharedSecret(conf)
if rc.isErr:
error "Failed create or load shared secret",
fatal "Failed create or load shared secret",
msg = $(rc.unsafeError) # avoid side effects
quit(QuitFailure)
rc.value
Expand Down Expand Up @@ -250,7 +251,10 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,
# Construct server object
nimbus.wsRpcServer = newRpcWebSocketServer(
initTAddress(conf.wsAddress, conf.wsPort),
authHooks = hooks
authHooks = hooks,
# yuck, we should remove this ugly cast when
# we fix nim-websock
rng = cast[ws.Rng](nimbus.ctx.rng)
)
setupCommonRpc(nimbus.ethNode, conf, nimbus.wsRpcServer)

Expand Down Expand Up @@ -284,7 +288,7 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,

let rs = validateSealer(conf, nimbus.ctx, nimbus.chainRef)
if rs.isErr:
echo rs.error
fatal "Engine signer validation error", msg = rs.error
quit(QuitFailure)

proc signFunc(signer: EthAddress, message: openArray[byte]): Result[RawSignature, cstring] {.gcsafe.} =
Expand All @@ -297,7 +301,7 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,

nimbus.chainRef.clique.authorize(conf.engineSigner, signFunc)

# always create sealing engine instanca but not always run it
# always create sealing engine instance but not always run it
# e.g. engine api need sealing engine without it running
var initialState = EngineStopped
if chainDB.headTotalDifficulty() > chainDB.ttd:
Expand Down
39 changes: 37 additions & 2 deletions tests/test_configuration.nim
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import
std/[os],
pkg/[unittest2, confutils],
eth/[p2p, common],
../nimbus/[config, chain_config],
eth/[p2p, common, keys],
stew/byteutils,
../nimbus/[config, chain_config, context],
./test_helpers

proc `==`(a, b: ChainId): bool =
Expand Down Expand Up @@ -207,5 +208,39 @@ proc configurationMain*() =
check conf.engineApiEnabled == false
check conf.rpcEnabled == false

let ctx = newEthContext()
test "net-key random":
let conf = makeConfig(@["--net-key:random"])
check conf.netKey == "random"
let rc = ctx.getNetKeys(conf.netKey, conf.dataDir.string)
check rc.isOk

test "net-key hex without 0x prefix":
let conf = makeConfig(@["--net-key:9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"])
check conf.netKey == "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"
let rc = ctx.getNetKeys(conf.netKey, conf.dataDir.string)
check rc.isOk
let pkhex = rc.get.seckey.toRaw.to0xHex
check pkhex == "0x9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"

test "net-key hex with 0x prefix":
let conf = makeConfig(@["--net-key:0x9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"])
check conf.netKey == "0x9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"
let rc = ctx.getNetKeys(conf.netKey, conf.dataDir.string)
check rc.isOk
let pkhex = rc.get.seckey.toRaw.to0xHex
check pkhex == "0x9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"

test "net-key path":
let conf = makeConfig(@["--net-key:nimcache/key.txt"])
check conf.netKey == "nimcache/key.txt"
let rc1 = ctx.getNetKeys(conf.netKey, conf.dataDir.string)
check rc1.isOk
let pkhex1 = rc1.get.seckey.toRaw.to0xHex
let rc2 = ctx.getNetKeys(conf.netKey, conf.dataDir.string)
check rc2.isOk
let pkhex2 = rc2.get.seckey.toRaw.to0xHex
check pkhex1 == pkhex2

when isMainModule:
configurationMain()
2 changes: 1 addition & 1 deletion tests/test_helpers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ proc hashLogEntries*(logs: seq[Log]): string =
proc setupEthNode*(
conf: NimbusConf, ctx: EthContext,
capabilities: varargs[ProtocolInfo, `protocolInfo`]): EthereumNode =
let keypair = ctx.hexToKeyPair(conf.nodeKeyHex).tryGet()
let keypair = ctx.getNetKeys(conf.netKey, conf.dataDir.string).tryGet()
let srvAddress = Address(
ip: conf.listenAddress, tcpPort: conf.tcpPort, udpPort: conf.udpPort)

Expand Down
2 changes: 1 addition & 1 deletion vendor/nim-json-rpc

0 comments on commit f3512ab

Please sign in to comment.