mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-06-27 12:59:30 +00:00
102 lines
3.7 KiB
Nim
102 lines
3.7 KiB
Nim
# Presets are hard-coded configuration bundles that get compiled into code. They can refer
|
|
# to different things, but the canonical example are sets of bootstrap nodes that define
|
|
# logically different networks; e.g., "logos.dev" and "logos.test" refer to the Logos
|
|
# devnet and latest testnet, respectively.
|
|
import std/options
|
|
import std/strutils
|
|
import std/json
|
|
|
|
import pkg/chronicles
|
|
import pkg/codexdht/discv5/protocol
|
|
import pkg/libp2p/[errors, routing_record]
|
|
import pkg/results
|
|
import pkg/stew/base64
|
|
|
|
# A NetworkPreset is a set of bootstrap nodes (represented
|
|
# by their signed peer records) along with some description metadata.
|
|
type NetworkPreset* = object
|
|
name*: string
|
|
description*: string
|
|
unparsedRecords: seq[string]
|
|
|
|
proc init*(
|
|
T: type NetworkPreset, name: string, description: string, records: seq[string]
|
|
): T =
|
|
result.name = name
|
|
result.description = description
|
|
|
|
# We have to delay parsing of records to runtime because
|
|
# of https://github.com/nim-lang/Nim/issues/23468
|
|
result.unparsedRecords = records
|
|
|
|
func `$`*(preset: NetworkPreset): string =
|
|
"[" & preset.name & "]: " & preset.description
|
|
|
|
func describePresets(presets: openArray[NetworkPreset]): string =
|
|
result = ""
|
|
for preset in presets:
|
|
result &= $preset & "; "
|
|
|
|
proc parse*(T: type SignedPeerRecord, p: string): Result[SignedPeerRecord, string] =
|
|
var res: SignedPeerRecord
|
|
try:
|
|
if not res.fromURI(p):
|
|
return err("The uri is not a valid SignedPeerRecord: " & p)
|
|
return ok(res)
|
|
except LPError, Base64Error:
|
|
let e = getCurrentException()
|
|
return err(e.msg)
|
|
|
|
proc `bootstrapNodes`*(self: NetworkPreset): seq[SignedPeerRecord] =
|
|
for record in self.unparsedRecords:
|
|
# Having an invalid SPR in a hardcoded config is a bug, a+
|
|
# it should crash the node.
|
|
result.add(parse(SignedPeerRecord, record).tryGet())
|
|
|
|
# Bootstrap node SPRs live in a single source-of-truth config file at the repo
|
|
# root. staticRead embeds it into the binary at build time, so the node remains
|
|
# self-contained (the file is not needed alongside the binary at runtime). The
|
|
# same file is read at runtime by the bootstrap liveness checker (tools/check_spr).
|
|
const networkPresetsJson = staticRead("../network_presets.json")
|
|
|
|
proc parsePresetsJson(jsonStr: string): seq[NetworkPreset] =
|
|
let root = parseJson(jsonStr)
|
|
for p in root["presets"].items:
|
|
var records: seq[string]
|
|
for r in p["records"].items:
|
|
records.add(r.getStr)
|
|
result.add(NetworkPreset.init(p["name"].getStr, p["description"].getStr, records))
|
|
|
|
const NetworkPresets* = parsePresetsJson(networkPresetsJson)
|
|
|
|
proc loadNetworkPresets*(path: string): seq[NetworkPreset] =
|
|
## Runtime loader for the same bootstrap-node config file embedded at compile
|
|
## time into `NetworkPresets`. Used by the bootstrap liveness checker so the
|
|
## node and the checker share one source of truth.
|
|
parsePresetsJson(readFile(path))
|
|
|
|
proc rawRecords*(self: NetworkPreset): seq[string] =
|
|
## The unparsed `spr:` strings for this preset (for tooling that wants to
|
|
## handle parse failures per-record instead of crashing).
|
|
self.unparsedRecords
|
|
|
|
proc `default`*(presets: openArray[NetworkPreset]): NetworkPreset =
|
|
presets[0]
|
|
|
|
# Precomputes those as as consts so we can use them in nim-confutils CLI
|
|
# help strings.
|
|
const
|
|
NetworkPresetsDescription* = describePresets(NetworkPresets)
|
|
DefaultNetworkPreset* = NetworkPresets.default
|
|
|
|
proc find*(presets: openArray[NetworkPreset], p: string): Option[NetworkPreset] =
|
|
for preset in presets:
|
|
if preset.name == p:
|
|
return some(preset)
|
|
return none(NetworkPreset)
|
|
|
|
proc findByPrefix*(presets: openArray[NetworkPreset], val: string): seq[string] =
|
|
for p in presets:
|
|
if p.name.startsWith(val):
|
|
result.add p.name
|