2021-11-24 11:12:25 +00:00
|
|
|
# Nimbus
|
2024-02-28 17:31:45 +00:00
|
|
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
2021-11-24 11:12:25 +00:00
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
2023-01-31 12:38:08 +00:00
|
|
|
{.push raises: [].}
|
2021-11-24 11:12:25 +00:00
|
|
|
|
2024-05-17 15:20:57 +00:00
|
|
|
import
|
|
|
|
std/[os, strutils],
|
|
|
|
chronicles,
|
|
|
|
eth/common,
|
|
|
|
stew/[io2, arrayops],
|
|
|
|
eth/p2p/discoveryv5/enr
|
|
|
|
|
2024-05-22 01:22:07 +00:00
|
|
|
func fromBytes*(T: type KeccakHash, hash: openArray[byte]): T =
|
2024-05-17 15:20:57 +00:00
|
|
|
doAssert(hash.len() == 32)
|
|
|
|
KeccakHash(data: array[32, byte].initCopyFrom(hash))
|
2021-11-24 11:12:25 +00:00
|
|
|
|
|
|
|
iterator strippedLines(filename: string): string {.raises: [ref IOError].} =
|
|
|
|
for line in lines(filename):
|
|
|
|
let stripped = strip(line)
|
|
|
|
if stripped.startsWith('#'): # Comments
|
|
|
|
continue
|
|
|
|
|
|
|
|
if stripped.len > 0:
|
|
|
|
yield stripped
|
|
|
|
|
2024-02-28 17:31:45 +00:00
|
|
|
proc addBootstrapNode(bootstrapAddr: string, bootstrapEnrs: var seq[Record]) =
|
2024-06-27 15:59:08 +00:00
|
|
|
let res = enr.Record.fromURI(bootstrapAddr)
|
|
|
|
if res.isOk():
|
|
|
|
bootstrapEnrs.add res.value
|
2021-11-24 11:12:25 +00:00
|
|
|
else:
|
2024-06-27 15:59:08 +00:00
|
|
|
warn "Ignoring invalid bootstrap ENR", bootstrapAddr, error = $res.error
|
2021-11-24 11:12:25 +00:00
|
|
|
|
2024-02-28 17:31:45 +00:00
|
|
|
proc loadBootstrapFile*(bootstrapFile: string, bootstrapEnrs: var seq[Record]) =
|
|
|
|
if bootstrapFile.len == 0:
|
|
|
|
return
|
2021-11-24 11:12:25 +00:00
|
|
|
let ext = splitFile(bootstrapFile).ext
|
2024-02-28 17:31:45 +00:00
|
|
|
if cmpIgnoreCase(ext, ".txt") == 0 or cmpIgnoreCase(ext, ".enr") == 0:
|
2021-11-24 11:12:25 +00:00
|
|
|
try:
|
|
|
|
for ln in strippedLines(bootstrapFile):
|
|
|
|
addBootstrapNode(ln, bootstrapEnrs)
|
|
|
|
except IOError as e:
|
|
|
|
fatal "Could not read bootstrap file", msg = e.msg
|
|
|
|
quit 1
|
|
|
|
else:
|
|
|
|
fatal "Unknown bootstrap file format", ext
|
|
|
|
quit 1
|
2022-02-17 13:13:39 +00:00
|
|
|
|
|
|
|
# Note:
|
|
|
|
# Currently just works with the network private key stored as hex in a file.
|
|
|
|
# In the future it would be nice to re-use keystore from nimbus-eth2 for this.
|
|
|
|
# However that would require the pull the keystore.nim and parts of
|
|
|
|
# keystore_management.nim out of nimbus-eth2.
|
|
|
|
proc getPersistentNetKey*(
|
2024-02-28 17:31:45 +00:00
|
|
|
rng: var HmacDrbgContext, keyFilePath: string
|
|
|
|
): tuple[key: PrivateKey, newNetKey: bool] =
|
2022-03-18 12:06:57 +00:00
|
|
|
logScope:
|
|
|
|
key_file = keyFilePath
|
|
|
|
|
2022-02-17 13:13:39 +00:00
|
|
|
if fileAccessible(keyFilePath, {AccessFlags.Find}):
|
2022-03-18 12:06:57 +00:00
|
|
|
info "Network key file is present, reading key"
|
2022-02-17 13:13:39 +00:00
|
|
|
|
|
|
|
let readResult = readAllChars(keyFilePath)
|
|
|
|
if readResult.isErr():
|
2024-02-28 17:31:45 +00:00
|
|
|
fatal "Could not load network key file", error = ioErrorMsg(readResult.error)
|
2022-02-17 13:13:39 +00:00
|
|
|
quit QuitFailure
|
|
|
|
|
|
|
|
let netKeyInHex = readResult.get()
|
|
|
|
if netKeyInHex.len() == 64:
|
2022-09-10 19:00:27 +00:00
|
|
|
let netKey = PrivateKey.fromHex(netKeyInHex)
|
2022-02-17 13:13:39 +00:00
|
|
|
if netKey.isOk():
|
2022-03-18 12:06:57 +00:00
|
|
|
info "Network key was successfully read"
|
2023-09-25 19:08:10 +00:00
|
|
|
(netKey.get(), false)
|
2022-02-17 13:13:39 +00:00
|
|
|
else:
|
2022-03-18 12:06:57 +00:00
|
|
|
fatal "Invalid private key from file", error = netKey.error
|
2022-02-17 13:13:39 +00:00
|
|
|
quit QuitFailure
|
|
|
|
else:
|
2022-03-18 12:06:57 +00:00
|
|
|
fatal "Invalid length of private in file"
|
2022-02-17 13:13:39 +00:00
|
|
|
quit QuitFailure
|
|
|
|
else:
|
2022-03-18 12:06:57 +00:00
|
|
|
info "Network key file is missing, creating a new one"
|
2022-02-17 13:13:39 +00:00
|
|
|
let key = PrivateKey.random(rng)
|
|
|
|
|
2022-04-13 09:17:07 +00:00
|
|
|
if (let res = io2.writeFile(keyFilePath, $key); res.isErr):
|
2024-02-28 17:31:45 +00:00
|
|
|
fatal "Failed to write the network key file", error = ioErrorMsg(res.error)
|
2022-02-17 13:13:39 +00:00
|
|
|
quit 1
|
|
|
|
|
2022-03-18 12:06:57 +00:00
|
|
|
info "New network key file was created"
|
2022-02-17 13:13:39 +00:00
|
|
|
|
2023-09-25 19:08:10 +00:00
|
|
|
(key, true)
|
|
|
|
|
|
|
|
proc getPersistentEnr*(enrFilePath: string): Opt[enr.Record] =
|
|
|
|
logScope:
|
|
|
|
enr_file = enrFilePath
|
|
|
|
|
|
|
|
if fileAccessible(enrFilePath, {AccessFlags.Find}):
|
|
|
|
info "ENR file is present, reading ENR"
|
|
|
|
|
|
|
|
let readResult = readAllChars(enrFilePath)
|
|
|
|
if readResult.isErr():
|
2024-02-28 17:31:45 +00:00
|
|
|
warn "Could not load ENR file", error = ioErrorMsg(readResult.error)
|
2023-09-25 19:08:10 +00:00
|
|
|
return Opt.none(enr.Record)
|
|
|
|
|
|
|
|
let enrUri = readResult.get()
|
|
|
|
|
|
|
|
var record: enr.Record
|
|
|
|
# TODO: This old API of var passing is very error prone and should be
|
|
|
|
# changed in nim-eth.
|
2024-06-27 15:59:08 +00:00
|
|
|
let res = enr.Record.fromURI(enrUri)
|
|
|
|
if res.isErr():
|
2023-09-25 19:08:10 +00:00
|
|
|
warn "Could not decode ENR from ENR file"
|
2024-06-27 15:59:08 +00:00
|
|
|
Opt.none(enr.Record)
|
2023-09-25 19:08:10 +00:00
|
|
|
else:
|
2024-06-27 15:59:08 +00:00
|
|
|
Opt.some(res.value)
|
2023-09-25 19:08:10 +00:00
|
|
|
else:
|
|
|
|
warn "Could not find ENR file. Was it manually deleted?"
|
2024-06-27 15:59:08 +00:00
|
|
|
Opt.none(enr.Record)
|