2021-12-10 08:49:57 +00:00
|
|
|
# Nimbus
|
|
|
|
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
|
|
|
# Licensed under either of
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
|
|
# http://opensource.org/licenses/MIT)
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except
|
|
|
|
# according to those terms.
|
|
|
|
|
|
|
|
import
|
|
|
|
std/[os, sequtils, strformat, strutils, times],
|
2022-03-16 09:13:17 +00:00
|
|
|
./replay/[pp, gunzip],
|
2022-12-02 04:39:12 +00:00
|
|
|
../nimbus/core/[pow, pow/pow_cache, pow/pow_dataset],
|
2021-12-10 08:49:57 +00:00
|
|
|
eth/[common],
|
|
|
|
unittest2
|
|
|
|
|
|
|
|
const
|
|
|
|
baseDir = [".", "tests", ".." / "tests", $DirSep] # path containg repo
|
2022-03-16 09:13:17 +00:00
|
|
|
repoDir = ["replay"] # alternative repos
|
2021-12-10 08:49:57 +00:00
|
|
|
|
|
|
|
specsDump = "mainspecs2k.txt.gz"
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Helpers
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
proc say*(noisy = false; pfx = "***"; args: varargs[string, `$`]) =
|
|
|
|
if noisy:
|
|
|
|
if args.len == 0:
|
|
|
|
echo "*** ", pfx
|
|
|
|
elif 0 < pfx.len and pfx[^1] != ' ':
|
|
|
|
echo pfx, " ", args.toSeq.join
|
|
|
|
else:
|
|
|
|
echo pfx, args.toSeq.join
|
|
|
|
|
|
|
|
proc findFilePath(file: string): string =
|
|
|
|
result = "?unknown?" / file
|
|
|
|
for dir in baseDir:
|
|
|
|
for repo in repoDir:
|
|
|
|
let path = dir / repo / file
|
|
|
|
if path.fileExists:
|
|
|
|
return path
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Test Runners
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
proc runPowTests(noisy = true; file = specsDump;
|
|
|
|
nVerify = int.high; nFakeMiner = 0, nRealMiner = 0) =
|
|
|
|
let
|
|
|
|
filePath = file.findFilePath
|
|
|
|
fileInfo = file.splitFile.name.split(".")[0]
|
|
|
|
|
|
|
|
powCache = PowCacheRef.new # so we can inspect the LRU caches
|
|
|
|
powDataset = PowDatasetRef.new(cache = powCache)
|
|
|
|
pow = PowRef.new(powCache, powDataset)
|
|
|
|
|
|
|
|
var
|
|
|
|
specsList: seq[PowSpecs]
|
|
|
|
|
|
|
|
suite &"PoW: Header test specs from {fileInfo} capture":
|
|
|
|
block:
|
|
|
|
test "Loading from capture":
|
|
|
|
for (lno,line) in gunzipLines(filePath):
|
|
|
|
let specs = line.undumpPowSpecs
|
|
|
|
if 0 < specs.blockNumber:
|
|
|
|
specsList.add specs
|
|
|
|
check line == specs.dumpPowSpecs
|
|
|
|
noisy.say "***", " block range #",
|
|
|
|
specsList[0].blockNumber, " .. #", specsList[^1].blockNumber
|
|
|
|
|
|
|
|
# Adjust number of tests
|
|
|
|
let
|
|
|
|
startVerify = max(0, specsList.len - nVerify)
|
|
|
|
startFakeMiner = max(0, specsList.len - nFakeMiner)
|
|
|
|
startRealMiner = max(0, specsList.len - nRealMiner)
|
|
|
|
|
|
|
|
nDoVerify = specsList.len - startVerify
|
|
|
|
nDoFakeMiner = specsList.len - startFakeMiner
|
|
|
|
nDoRealMiner = specsList.len - startRealMiner
|
|
|
|
|
|
|
|
backStep = 1u64 shl 11
|
|
|
|
|
|
|
|
block:
|
|
|
|
test &"Running single getPowDigest() to fill the cache":
|
|
|
|
if nVerify <= 0:
|
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
noisy.showElapsed(&"first getPowDigest() instance"):
|
|
|
|
let p = specsList[startVerify]
|
|
|
|
check pow.getPowDigest(p).mixDigest == p.mixDigest
|
|
|
|
|
|
|
|
|
|
|
|
test &"Running getPowDigest() on {nDoVerify} specs records":
|
|
|
|
if nVerify <= 0:
|
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
noisy.showElapsed(&"all {nDoVerify} getPowDigest() instances"):
|
|
|
|
for n in startVerify ..< specsList.len:
|
|
|
|
let p = specsList[n]
|
|
|
|
check pow.getPowDigest(p).mixDigest == p.mixDigest
|
|
|
|
|
|
|
|
|
|
|
|
test &"Generate PoW mining dataset (slow proocess)":
|
|
|
|
if nDoFakeMiner <= 0 and nRealMiner <= 0:
|
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
noisy.showElapsed "generate PoW dataset":
|
|
|
|
pow.generatePowDataset(specsList[startFakeMiner].blockNumber)
|
|
|
|
|
|
|
|
|
|
|
|
test &"Running getNonce() on {nDoFakeMiner} instances with start" &
|
|
|
|
&" nonce {backStep} before result":
|
|
|
|
if nDoFakeMiner <= 0:
|
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
noisy.showElapsed &"all {nDoFakeMiner} getNonce() instances":
|
|
|
|
for n in startFakeMiner ..< specsList.len:
|
|
|
|
let
|
|
|
|
p = specsList[n]
|
|
|
|
nonce = toBytesBE(uint64.fromBytesBE(p.nonce) - backStep)
|
|
|
|
check pow.getNonce(
|
|
|
|
p.blockNumber, p.miningHash, p.difficulty, nonce) == p.nonce
|
|
|
|
|
|
|
|
|
|
|
|
test &"Running getNonce() mining function" &
|
|
|
|
&" on {nDoRealMiner} specs records":
|
|
|
|
if nRealMiner <= 0:
|
|
|
|
skip()
|
|
|
|
else:
|
|
|
|
for n in startRealMiner ..< specsList.len:
|
|
|
|
let p = specsList[n]
|
|
|
|
noisy.say "***", " #", p.blockNumber, " needs ", p.nonce.pp
|
|
|
|
noisy.showElapsed("getNonce()"):
|
|
|
|
let nonce = pow.getNonce(p)
|
|
|
|
noisy.say "***", " got ", nonce.pp,
|
|
|
|
" after ", pow.nGetNonce, " attempts"
|
|
|
|
if nonce != p.nonce:
|
|
|
|
var q = p
|
|
|
|
q.nonce = nonce
|
|
|
|
check pow.getPowDigest(q).mixDigest == p.mixDigest
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Main function(s)
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
proc powMain*(noisy = defined(debug)) =
|
|
|
|
noisy.runPowTests(nVerify = 100)
|
|
|
|
|
|
|
|
when isMainModule:
|
|
|
|
# Note:
|
|
|
|
# 0 < nFakeMiner: allow ~20 minuntes for building lookup table
|
|
|
|
# 0 < nRealMiner: takes days/months/years ...
|
|
|
|
true.runPowTests(nVerify = 200, nFakeMiner = 200, nRealMiner = 5)
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|