92 lines
3.3 KiB
Nim
92 lines
3.3 KiB
Nim
|
# Nimbus
|
||
|
# Copyright (c) 2022 Status Research & Development GmbH
|
||
|
# 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.
|
||
|
|
||
|
# Tool to verify that certain Portal content is available on the network.
|
||
|
# Currently only supports checking `EpochAccumulator`s of the history network.
|
||
|
|
||
|
{.push raises: [Defect].}
|
||
|
|
||
|
import
|
||
|
confutils, chronicles, chronicles/topics_registry, stew/byteutils,
|
||
|
../network_metadata,
|
||
|
../network/history/[accumulator, history_content, history_network],
|
||
|
../rpc/portal_rpc_client
|
||
|
|
||
|
type
|
||
|
ContentVerifierConf* = object
|
||
|
logLevel* {.
|
||
|
defaultValue: LogLevel.INFO
|
||
|
defaultValueDesc: $LogLevel.INFO
|
||
|
desc: "Sets the log level"
|
||
|
name: "log-level" .}: LogLevel
|
||
|
|
||
|
rpcAddress* {.
|
||
|
desc: "Address of the JSON-RPC service"
|
||
|
defaultValue: "127.0.0.1"
|
||
|
name: "rpc-address" .}: string
|
||
|
|
||
|
rpcPort* {.
|
||
|
defaultValue: 8545
|
||
|
desc: "Port of the JSON-RPC service"
|
||
|
name: "rpc-port" .}: uint16
|
||
|
|
||
|
proc checkAccumulators(client: RpcClient) {.async.} =
|
||
|
let accumulator =
|
||
|
# Get it from binary file containing SSZ encoded accumulator
|
||
|
try:
|
||
|
SSZ.decode(finishedAccumulator, FinishedAccumulator)
|
||
|
except SszError as err:
|
||
|
raiseAssert "Invalid baked-in accumulator: " & err.msg
|
||
|
|
||
|
for i, hash in accumulator.historicalEpochs:
|
||
|
let root = Digest(data: hash)
|
||
|
let contentKey = ContentKey.init(epochAccumulator, root)
|
||
|
|
||
|
try:
|
||
|
let content = await client.portal_historyRecursiveFindContent(
|
||
|
contentKey.encode.asSeq().toHex())
|
||
|
|
||
|
let res = decodeSsz(hexToSeqByte(content), EpochAccumulator)
|
||
|
if res.isErr():
|
||
|
echo "[Invalid] EpochAccumulator number " & $i & ": " & $root & " error: " & res.error
|
||
|
else:
|
||
|
let epochAccumulator = res.get()
|
||
|
let resultingRoot = hash_tree_root(epochAccumulator)
|
||
|
if resultingRoot == root:
|
||
|
echo "[Available] EpochAccumulator number " & $i & ": " & $root
|
||
|
else:
|
||
|
echo "[Invalid] EpochAccumulator number " & $i & ": " & $root & " error: Invalid root"
|
||
|
except RpcPostError as e:
|
||
|
# RpcPostError when for example timing out on the request. Could retry
|
||
|
# in this case.
|
||
|
fatal "Error occured on JSON-RPC request", error = e.msg
|
||
|
quit 1
|
||
|
except ValueError as e:
|
||
|
# Either an error with the provided content key or the content was
|
||
|
# simply not available in the network
|
||
|
echo "[Not Available] EpochAccumulator number " & $i & ": " & $root & " error: " & e.msg
|
||
|
|
||
|
# Using the http connection re-use seems to slow down these sequentual
|
||
|
# requests considerably. Force a new connection setup by doing a close after
|
||
|
# each request.
|
||
|
await client.close()
|
||
|
|
||
|
proc run(config: ContentVerifierConf) {.async.} =
|
||
|
let client = newRpcHttpClient()
|
||
|
await client.connect(config.rpcAddress, Port(config.rpcPort), false)
|
||
|
|
||
|
await checkAccumulators(client)
|
||
|
|
||
|
when isMainModule:
|
||
|
{.pop.}
|
||
|
let config = ContentVerifierConf.load()
|
||
|
{.push raises: [Defect].}
|
||
|
|
||
|
setLogLevel(config.logLevel)
|
||
|
|
||
|
waitFor run(config)
|