enhance net-key command line option to accept random, hex, and path
- previously it only accept hex - fix #587
This commit is contained in:
parent
a087d65542
commit
a5d4759bfd
|
@ -317,11 +317,14 @@ type
|
||||||
defaultValueDesc: $DiscoveryType.V4
|
defaultValueDesc: $DiscoveryType.V4
|
||||||
name: "discovery" .}: DiscoveryType
|
name: "discovery" .}: DiscoveryType
|
||||||
|
|
||||||
nodeKeyHex* {.
|
netKey* {.
|
||||||
desc: "P2P node private key (as 32 bytes hex string)"
|
desc: "P2P ethereum node (secp256k1) private key (random, path, hex)"
|
||||||
defaultValue: ""
|
longDesc:
|
||||||
defaultValueDesc: "random"
|
"- random: generate random network key for this node instance\n" &
|
||||||
name: "node-key" .}: string
|
"- 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* {.
|
agentString* {.
|
||||||
desc: "Node agent string which is used as identifier in network"
|
desc: "Node agent string which is used as identifier in network"
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
# those terms.
|
# those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
std/[strutils, os],
|
||||||
accounts/manager,
|
accounts/manager,
|
||||||
stew/results,
|
stew/[results, io2, byteutils],
|
||||||
eth/keys
|
eth/keys
|
||||||
|
|
||||||
export manager
|
export manager
|
||||||
|
@ -32,12 +33,45 @@ proc randomPrivateKey*(ctx: EthContext): PrivateKey =
|
||||||
proc randomKeyPair*(ctx: EthContext): KeyPair =
|
proc randomKeyPair*(ctx: EthContext): KeyPair =
|
||||||
random(KeyPair, ctx.rng[])
|
random(KeyPair, ctx.rng[])
|
||||||
|
|
||||||
proc hexToKeyPair*(ctx: EthContext, hexPrivateKey: string): Result[KeyPair, string] =
|
proc containsOnlyHexDigits(hex: string): bool =
|
||||||
if hexPrivateKey.len == 0:
|
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()
|
let privateKey = ctx.randomPrivateKey()
|
||||||
ok(privateKey.toKeyPair())
|
return ok(privateKey.toKeyPair())
|
||||||
else:
|
elif netKey.len in {64, 66} and netKey.containsOnlyHexDigits:
|
||||||
let res = PrivateKey.fromHex(hexPrivateKey)
|
let res = PrivateKey.fromHex(netKey)
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
return err($res.error)
|
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())
|
||||||
|
|
|
@ -22,7 +22,7 @@ import
|
||||||
metrics,
|
metrics,
|
||||||
metrics/[chronos_httpserver, chronicles_support],
|
metrics/[chronos_httpserver, chronicles_support],
|
||||||
stew/shims/net as stewNet,
|
stew/shims/net as stewNet,
|
||||||
websock/types as ws,
|
websock/websock as ws,
|
||||||
"."/[conf_utils, config, constants, context, genesis, sealer, utils, version],
|
"."/[conf_utils, config, constants, context, genesis, sealer, utils, version],
|
||||||
./db/[storage_types, db_chain, select_backend],
|
./db/[storage_types, db_chain, select_backend],
|
||||||
./graphql/ethapi,
|
./graphql/ethapi,
|
||||||
|
@ -69,21 +69,21 @@ proc manageAccounts(nimbus: NimbusNode, conf: NimbusConf) =
|
||||||
if string(conf.keyStore).len > 0:
|
if string(conf.keyStore).len > 0:
|
||||||
let res = nimbus.ctx.am.loadKeystores(string conf.keyStore)
|
let res = nimbus.ctx.am.loadKeystores(string conf.keyStore)
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
echo res.error()
|
fatal "Load keystore error", msg = res.error()
|
||||||
quit(QuitFailure)
|
quit(QuitFailure)
|
||||||
|
|
||||||
if string(conf.importKey).len > 0:
|
if string(conf.importKey).len > 0:
|
||||||
let res = nimbus.ctx.am.importPrivateKey(string conf.importKey)
|
let res = nimbus.ctx.am.importPrivateKey(string conf.importKey)
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
echo res.error()
|
fatal "Import private key error", msg = res.error()
|
||||||
quit(QuitFailure)
|
quit(QuitFailure)
|
||||||
|
|
||||||
proc setupP2P(nimbus: NimbusNode, conf: NimbusConf,
|
proc setupP2P(nimbus: NimbusNode, conf: NimbusConf,
|
||||||
chainDB: BaseChainDB, protocols: set[ProtocolFlag]) =
|
chainDB: BaseChainDB, protocols: set[ProtocolFlag]) =
|
||||||
## Creating P2P Server
|
## Creating P2P Server
|
||||||
let kpres = nimbus.ctx.hexToKeyPair(conf.nodeKeyHex)
|
let kpres = nimbus.ctx.getNetKeys(conf.netKey, conf.dataDir.string)
|
||||||
if kpres.isErr:
|
if kpres.isErr:
|
||||||
echo kpres.error()
|
fatal "Get network keys error", msg = kpres.error
|
||||||
quit(QuitFailure)
|
quit(QuitFailure)
|
||||||
|
|
||||||
let keypair = kpres.get()
|
let keypair = kpres.get()
|
||||||
|
@ -117,7 +117,8 @@ proc setupP2P(nimbus: NimbusNode, conf: NimbusConf,
|
||||||
addAllCapabilities = false, minPeers = conf.maxPeers,
|
addAllCapabilities = false, minPeers = conf.maxPeers,
|
||||||
bootstrapNodes = bootstrapNodes,
|
bootstrapNodes = bootstrapNodes,
|
||||||
bindUdpPort = conf.udpPort, bindTcpPort = conf.tcpPort,
|
bindUdpPort = conf.udpPort, bindTcpPort = conf.tcpPort,
|
||||||
bindIp = conf.listenAddress)
|
bindIp = conf.listenAddress,
|
||||||
|
rng = nimbus.ctx.rng)
|
||||||
|
|
||||||
# Add protocol capabilities based on protocol flags
|
# Add protocol capabilities based on protocol flags
|
||||||
if ProtocolFlag.Eth in protocols:
|
if ProtocolFlag.Eth in protocols:
|
||||||
|
@ -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)
|
||||||
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:
|
let jwtKey = block:
|
||||||
# Create or load shared secret
|
# Create or load shared secret
|
||||||
let rc = nimbus.ctx.rng.jwtSharedSecret(conf)
|
let rc = nimbus.ctx.rng.jwtSharedSecret(conf)
|
||||||
if rc.isErr:
|
if rc.isErr:
|
||||||
error "Failed create or load shared secret",
|
fatal "Failed create or load shared secret",
|
||||||
msg = $(rc.unsafeError) # avoid side effects
|
msg = $(rc.unsafeError) # avoid side effects
|
||||||
quit(QuitFailure)
|
quit(QuitFailure)
|
||||||
rc.value
|
rc.value
|
||||||
|
@ -250,7 +251,10 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,
|
||||||
# Construct server object
|
# Construct server object
|
||||||
nimbus.wsRpcServer = newRpcWebSocketServer(
|
nimbus.wsRpcServer = newRpcWebSocketServer(
|
||||||
initTAddress(conf.wsAddress, conf.wsPort),
|
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)
|
setupCommonRpc(nimbus.ethNode, conf, nimbus.wsRpcServer)
|
||||||
|
|
||||||
|
@ -284,7 +288,7 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,
|
||||||
|
|
||||||
let rs = validateSealer(conf, nimbus.ctx, nimbus.chainRef)
|
let rs = validateSealer(conf, nimbus.ctx, nimbus.chainRef)
|
||||||
if rs.isErr:
|
if rs.isErr:
|
||||||
echo rs.error
|
fatal "Engine signer validation error", msg = rs.error
|
||||||
quit(QuitFailure)
|
quit(QuitFailure)
|
||||||
|
|
||||||
proc signFunc(signer: EthAddress, message: openArray[byte]): Result[RawSignature, cstring] {.gcsafe.} =
|
proc signFunc(signer: EthAddress, message: openArray[byte]): Result[RawSignature, cstring] {.gcsafe.} =
|
||||||
|
@ -297,7 +301,7 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,
|
||||||
|
|
||||||
nimbus.chainRef.clique.authorize(conf.engineSigner, signFunc)
|
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
|
# e.g. engine api need sealing engine without it running
|
||||||
var initialState = EngineStopped
|
var initialState = EngineStopped
|
||||||
if chainDB.headTotalDifficulty() > chainDB.ttd:
|
if chainDB.headTotalDifficulty() > chainDB.ttd:
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import
|
import
|
||||||
std/[os],
|
std/[os],
|
||||||
pkg/[unittest2, confutils],
|
pkg/[unittest2, confutils],
|
||||||
eth/[p2p, common],
|
eth/[p2p, common, keys],
|
||||||
../nimbus/[config, chain_config],
|
stew/byteutils,
|
||||||
|
../nimbus/[config, chain_config, context],
|
||||||
./test_helpers
|
./test_helpers
|
||||||
|
|
||||||
proc `==`(a, b: ChainId): bool =
|
proc `==`(a, b: ChainId): bool =
|
||||||
|
@ -208,5 +209,39 @@ proc configurationMain*() =
|
||||||
check conf.engineApiEnabled == false
|
check conf.engineApiEnabled == false
|
||||||
check conf.rpcEnabled == 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:
|
when isMainModule:
|
||||||
configurationMain()
|
configurationMain()
|
||||||
|
|
|
@ -278,7 +278,7 @@ proc hashLogEntries*(logs: seq[Log]): string =
|
||||||
proc setupEthNode*(
|
proc setupEthNode*(
|
||||||
conf: NimbusConf, ctx: EthContext,
|
conf: NimbusConf, ctx: EthContext,
|
||||||
capabilities: varargs[ProtocolInfo, `protocolInfo`]): EthereumNode =
|
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(
|
let srvAddress = Address(
|
||||||
ip: conf.listenAddress, tcpPort: conf.tcpPort, udpPort: conf.udpPort)
|
ip: conf.listenAddress, tcpPort: conf.tcpPort, udpPort: conf.udpPort)
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0fee4be2ccbbfa3f158b741c3a34b04130c8b424
|
Subproject commit 5ccdaed0adfb1534ee1d193fc6f97e7961008bbe
|
Loading…
Reference in New Issue