rm PoW hash function and validation support (#2372)
This commit is contained in:
parent
69044dda60
commit
e1bb65fdfa
|
@ -113,11 +113,6 @@
|
|||
url = https://github.com/status-im/nimbus-build-system.git
|
||||
ignore = dirty
|
||||
branch = master
|
||||
[submodule "vendor/ethash"]
|
||||
path = vendor/ethash
|
||||
url = https://github.com/status-im/nim-ethash
|
||||
ignore = dirty
|
||||
branch = master
|
||||
[submodule "vendor/nim-evmc"]
|
||||
path = vendor/nim-evmc
|
||||
url = https://github.com/status-im/nim-evmc
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
import
|
||||
chronicles,
|
||||
eth/trie/trie_defs,
|
||||
../core/[pow, casper],
|
||||
../core/casper,
|
||||
../db/[core_db, ledger, storage_types],
|
||||
../utils/[utils, ec_recover],
|
||||
".."/[constants, errors],
|
||||
|
@ -81,9 +81,6 @@ type
|
|||
## installing a snapshot pivot. The default value for this field is
|
||||
## `GENESIS_PARENT_HASH` to start at the very beginning.
|
||||
|
||||
pow: PowRef
|
||||
## Wrapper around `hashimotoLight()` and lookup cache
|
||||
|
||||
pos: CasperRef
|
||||
## Proof Of Stake descriptor
|
||||
|
||||
|
@ -141,9 +138,6 @@ proc init(com : CommonRef,
|
|||
com.networkId = networkId
|
||||
com.syncProgress= SyncProgress()
|
||||
com.pruneHistory= pruneHistory
|
||||
|
||||
# Always initialise the PoW epoch cache even though it migh no be used
|
||||
com.pow = PowRef.new
|
||||
com.pos = CasperRef.new
|
||||
|
||||
# com.currentFork and com.consensusType
|
||||
|
@ -253,7 +247,6 @@ func clone*(com: CommonRef, db: CoreDbRef): CommonRef =
|
|||
networkId : com.networkId,
|
||||
currentFork : com.currentFork,
|
||||
consensusType: com.consensusType,
|
||||
pow : com.pow,
|
||||
pos : com.pos,
|
||||
pruneHistory : com.pruneHistory)
|
||||
|
||||
|
@ -396,10 +389,6 @@ func startOfHistory*(com: CommonRef): Hash256 =
|
|||
## Getter
|
||||
com.startOfHistory
|
||||
|
||||
func pow*(com: CommonRef): PowRef =
|
||||
## Getter
|
||||
com.pow
|
||||
|
||||
func pos*(com: CommonRef): CasperRef =
|
||||
## Getter
|
||||
com.pos
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
import
|
||||
../../common/common,
|
||||
../../utils/utils,
|
||||
../../vm_types,
|
||||
../pow
|
||||
../../vm_types
|
||||
|
||||
export
|
||||
common
|
||||
|
@ -41,7 +40,7 @@ type
|
|||
# Public constructors
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc newChain*(com: CommonRef,
|
||||
func newChain*(com: CommonRef,
|
||||
extraValidation: bool,
|
||||
vmState = BaseVMState(nil)): ChainRef =
|
||||
## Constructor for the `Chain` descriptor object.
|
||||
|
@ -65,27 +64,23 @@ func newChain*(com: CommonRef): ChainRef =
|
|||
# ------------------------------------------------------------------------------
|
||||
# Public `Chain` getters
|
||||
# ------------------------------------------------------------------------------
|
||||
proc vmState*(c: ChainRef): BaseVMState =
|
||||
func vmState*(c: ChainRef): BaseVMState =
|
||||
## Getter
|
||||
c.vmState
|
||||
|
||||
proc pow*(c: ChainRef): PowRef =
|
||||
## Getter
|
||||
c.com.pow
|
||||
|
||||
proc db*(c: ChainRef): CoreDbRef =
|
||||
func db*(c: ChainRef): CoreDbRef =
|
||||
## Getter
|
||||
c.com.db
|
||||
|
||||
proc com*(c: ChainRef): CommonRef =
|
||||
func com*(c: ChainRef): CommonRef =
|
||||
## Getter
|
||||
c.com
|
||||
|
||||
proc extraValidation*(c: ChainRef): bool =
|
||||
func extraValidation*(c: ChainRef): bool =
|
||||
## Getter
|
||||
c.extraValidation
|
||||
|
||||
proc verifyFrom*(c: ChainRef): BlockNumber =
|
||||
func verifyFrom*(c: ChainRef): BlockNumber =
|
||||
## Getter
|
||||
c.verifyFrom
|
||||
|
||||
|
@ -100,12 +95,12 @@ proc currentBlock*(c: ChainRef): BlockHeader
|
|||
# Public `Chain` setters
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc `extraValidation=`*(c: ChainRef; extraValidation: bool) =
|
||||
func `extraValidation=`*(c: ChainRef; extraValidation: bool) =
|
||||
## Setter. If set `true`, the assignment value `extraValidation` enables
|
||||
## extra block chain validation.
|
||||
c.extraValidation = extraValidation
|
||||
|
||||
proc `verifyFrom=`*(c: ChainRef; verifyFrom: BlockNumber) =
|
||||
func `verifyFrom=`*(c: ChainRef; verifyFrom: BlockNumber) =
|
||||
## Setter. The assignment value `verifyFrom` defines the first block where
|
||||
## validation should start if the `Clique` field `extraValidation` was set
|
||||
## `true`.
|
||||
|
|
|
@ -1,211 +0,0 @@
|
|||
# Nimbus
|
||||
# Copyright (c) 2018-2024 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.
|
||||
|
||||
## Block PoW Support (Verifying & Mining)
|
||||
## ======================================
|
||||
##
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
std/[options, strutils],
|
||||
../utils/utils,
|
||||
./pow/pow_cache,
|
||||
eth/[common, keys, p2p, rlp],
|
||||
stew/endians2,
|
||||
ethash,
|
||||
stint
|
||||
|
||||
type
|
||||
PowDigest = tuple ##\
|
||||
## Return value from the `hashimotoLight()` function
|
||||
mixDigest: Hash256
|
||||
value : Hash256
|
||||
|
||||
PowSpecs* = object ##\
|
||||
## Relevant block header parts for PoW mining & verifying. This object
|
||||
## might be more useful for testing and debugging than for production.
|
||||
number* : BlockNumber
|
||||
miningHash*: Hash256
|
||||
nonce : BlockNonce
|
||||
mixHash* : Hash256
|
||||
difficulty : DifficultyInt
|
||||
|
||||
PowHeader = object ##\
|
||||
## Stolen from `p2p/validate.MiningHeader`
|
||||
parentHash : Hash256
|
||||
ommersHash : Hash256
|
||||
coinbase : EthAddress
|
||||
stateRoot : Hash256
|
||||
txRoot : Hash256
|
||||
receiptsRoot: Hash256
|
||||
logsBloom : common.BloomFilter
|
||||
difficulty : DifficultyInt
|
||||
number : BlockNumber
|
||||
gasLimit : GasInt
|
||||
gasUsed : GasInt
|
||||
timestamp : EthTime
|
||||
extraData : Blob
|
||||
|
||||
PowRef* = ref object of RootObj ##\
|
||||
## PoW context descriptor
|
||||
lightByEpoch: PowCacheRef ## PoW cache indexed by epoch
|
||||
|
||||
# You should only create one instance of the RNG per application / library
|
||||
# Ref is used so that it can be shared between components
|
||||
rng: ref HmacDrbgContext
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private functions: RLP support
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
func append(w: var RlpWriter; specs: PowSpecs) =
|
||||
## RLP support
|
||||
w.startList(5)
|
||||
w.append(HashOrNum(isHash: false, number: specs.number))
|
||||
w.append(HashOrNum(isHash: true, hash: specs.miningHash))
|
||||
w.append(specs.nonce.toUint)
|
||||
w.append(HashOrNum(isHash: true, hash: specs.mixHash))
|
||||
w.append(specs.difficulty)
|
||||
|
||||
func read(rlp: var Rlp; Q: type PowSpecs): Q
|
||||
{.raises: [RlpError].} =
|
||||
## RLP support
|
||||
rlp.tryEnterList()
|
||||
result.number = rlp.read(HashOrNum).number
|
||||
result.miningHash = rlp.read(HashOrNum).hash
|
||||
result.nonce = rlp.read(uint64).toBlockNonce
|
||||
result.mixHash = rlp.read(HashOrNum).hash
|
||||
result.difficulty = rlp.read(DifficultyInt)
|
||||
|
||||
func rlpTextEncode(specs: PowSpecs): string =
|
||||
"specs #" & $specs.number & " " & rlp.encode(specs).toHex
|
||||
|
||||
func decodeRlpText(data: string): PowSpecs
|
||||
{.raises: [CatchableError].} =
|
||||
if 180 < data.len and data[0 .. 6] == "specs #":
|
||||
let hexData = data.split
|
||||
if hexData.len == 3:
|
||||
var rlpData = hexData[2].rlpFromHex
|
||||
result = rlpData.read(PowSpecs)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
func miningHash(header: BlockHeader): Hash256 =
|
||||
## Calculate hash from mining relevant fields of the argument `header`
|
||||
let miningHeader = PowHeader(
|
||||
parentHash: header.parentHash,
|
||||
ommersHash: header.ommersHash,
|
||||
coinbase: header.coinbase,
|
||||
stateRoot: header.stateRoot,
|
||||
txRoot: header.txRoot,
|
||||
receiptsRoot:header.receiptsRoot,
|
||||
logsBloom: header.logsBloom,
|
||||
difficulty: header.difficulty,
|
||||
number: header.number,
|
||||
gasLimit: header.gasLimit,
|
||||
gasUsed: header.gasUsed,
|
||||
timestamp: header.timestamp,
|
||||
extraData: header.extraData)
|
||||
|
||||
rlpHash(miningHeader)
|
||||
|
||||
# ---------------
|
||||
|
||||
proc init(tm: PowRef; light: Option[PowCacheRef]) =
|
||||
## Constructor
|
||||
tm.rng = newRng()
|
||||
|
||||
if light.isSome:
|
||||
tm.lightByEpoch = light.get
|
||||
else:
|
||||
tm.lightByEpoch = PowCacheRef.new
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, Constructor
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc new*(T: type PowRef; cache: PowCacheRef): T =
|
||||
## Constructor
|
||||
new result
|
||||
result.init(some(cache))
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
func getPowSpecs*(header: BlockHeader): PowSpecs =
|
||||
## Extracts relevant parts from the `header` argument that are needed
|
||||
## for mining or pow verification. This function might be more useful for
|
||||
## testing and debugging than for production.
|
||||
PowSpecs(
|
||||
number: header.number,
|
||||
miningHash: header.miningHash,
|
||||
nonce: header.nonce,
|
||||
mixHash: header.mixHash,
|
||||
difficulty: header.difficulty)
|
||||
|
||||
func getPowCacheLookup*(tm: PowRef;
|
||||
blockNumber: BlockNumber): (uint64, Hash256)
|
||||
{.gcsafe, raises: [KeyError].} =
|
||||
## Returns the pair `(size,digest)` derived from the lookup cache for the
|
||||
## `hashimotoLight()` function for the given block number. The `size` is the
|
||||
## full size of the dataset (the cache represents) as passed on to the
|
||||
## `hashimotoLight()` function. The `digest` is a hash derived from the
|
||||
## cache that would be passed on to `hashimotoLight()`.
|
||||
##
|
||||
## This function is intended for error reporting and might also be useful
|
||||
## for testing and debugging.
|
||||
let ds = tm.lightByEpoch.get(blockNumber)
|
||||
if ds == nil:
|
||||
raise newException(KeyError, "block not found")
|
||||
|
||||
result[0] = ds.size
|
||||
result[1] = withKeccakHash:
|
||||
for a in ds.data:
|
||||
h.update(a.data)
|
||||
|
||||
# ------------------------
|
||||
|
||||
func getPowDigest(tm: PowRef; blockNumber: BlockNumber;
|
||||
powHeaderDigest: Hash256; nonce: BlockNonce): PowDigest =
|
||||
## Calculate the expected value of `header.mixHash` using the
|
||||
## `hashimotoLight()` library method.
|
||||
let
|
||||
ds = tm.lightByEpoch.get(blockNumber)
|
||||
u64Nonce = uint64.fromBytesBE(nonce)
|
||||
hashimotoLight(ds.size, ds.data, powHeaderDigest, u64Nonce)
|
||||
|
||||
func getPowDigest*(tm: PowRef; header: BlockHeader): PowDigest =
|
||||
## Variant of `getPowDigest()`
|
||||
tm.getPowDigest(header.number, header.miningHash, header.nonce)
|
||||
|
||||
func getPowDigest*(tm: PowRef; specs: PowSpecs): PowDigest =
|
||||
## Variant of `getPowDigest()`
|
||||
tm.getPowDigest(specs.number, specs.miningHash, specs.nonce)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, debugging & testing
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
func dumpPowSpecs*(specs: PowSpecs): string =
|
||||
## Text representation of `PowSpecs` argument object
|
||||
specs.rlpTextEncode
|
||||
|
||||
func undumpPowSpecs*(data: string): PowSpecs
|
||||
{.raises: [CatchableError].} =
|
||||
## Recover `PowSpecs` object from text representation
|
||||
data.decodeRlpText
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
|
@ -1,116 +0,0 @@
|
|||
# Nimbus
|
||||
# Copyright (c) 2018-2024 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.
|
||||
|
||||
## LRU Cache for Epoch Indexed Hashimoto Cache
|
||||
## ============================================
|
||||
##
|
||||
## This module uses the eth-block number (mapped to epoch) to hold and re-use
|
||||
## the cache needed for running the `hasimotoLight()` proof-of-work function.
|
||||
|
||||
import
|
||||
eth/common,
|
||||
ethash,
|
||||
stew/keyed_queue
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
type
|
||||
PowCacheItemRef* = ref object
|
||||
size*: uint64
|
||||
data*: seq[MDigest[512]]
|
||||
|
||||
PowCacheStats* = tuple
|
||||
maxItems: int
|
||||
size: int
|
||||
|
||||
PowCache* = object
|
||||
cacheMax: int
|
||||
cache: KeyedQueue[uint64,PowCacheItemRef]
|
||||
|
||||
PowCacheRef* = ref PowCache
|
||||
|
||||
const
|
||||
nItemsMax = 10
|
||||
nItemsInit = 2
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private helpers
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc toKey(bn: BlockNumber): uint64 =
|
||||
bn div EPOCH_LENGTH
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, constructor
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc init*(pc: var PowCache; maxItems = nItemsMax) =
|
||||
## Constructor for PoW cache
|
||||
pc.cacheMax = maxItems
|
||||
pc.cache.init(nItemsInit)
|
||||
|
||||
proc init*(T: type PowCache; maxItems = nItemsMax): T =
|
||||
## Constructor variant
|
||||
result.init(maxItems)
|
||||
|
||||
proc new*(T: type PowCacheRef; maxItems = nItemsMax): T =
|
||||
## Constructor variant
|
||||
new result
|
||||
result[].init(maxItems)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, constructor
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc get*(pc: var PowCache; bn: BlockNumber): PowCacheItemRef =
|
||||
## Return a cache derived from argument `blockNumber` ready to be used
|
||||
## for the `hashimotoLight()` method.
|
||||
let
|
||||
key = bn.toKey
|
||||
rc = pc.cache.lruFetch(key)
|
||||
|
||||
if rc.isOk:
|
||||
return rc.value
|
||||
|
||||
let
|
||||
# note that `getDataSize()` and `getCacheSize()` depend on
|
||||
# `key * EPOCH_LENGTH` rather than the original block number.
|
||||
top = key * EPOCH_LENGTH
|
||||
pair = PowCacheItemRef(
|
||||
size: top.getDataSize,
|
||||
data: top.getCacheSize.mkcache(top.getSeedhash))
|
||||
|
||||
pc.cache.lruAppend(key, pair, pc.cacheMax)
|
||||
|
||||
proc get*(pcr: PowCacheRef; bn: BlockNumber): PowCacheItemRef =
|
||||
## Variant of `getCache()`
|
||||
pcr[].get(bn)
|
||||
|
||||
proc hasItem*(pc: var PowCache; bn: BlockNumber): bool =
|
||||
## Returns true if there is a cache entry for argument `bn`.
|
||||
pc.cache.hasKey(bn.toKey)
|
||||
|
||||
proc hasItem*(pcr: PowCacheRef; bn: BlockNumber): bool =
|
||||
## Variant of `hasItem()`
|
||||
pcr[].hasItem(bn)
|
||||
|
||||
# -------------------------
|
||||
|
||||
proc stats*(pc: var PowCache): PowCacheStats =
|
||||
## Return current cache sizes
|
||||
result = (maxItems: pc.cacheMax, size: pc.cache.len)
|
||||
|
||||
proc stats*(pcr: PowCacheRef): PowCacheStats =
|
||||
## Variant of `stats()`
|
||||
pcr[].stats
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
|
@ -18,7 +18,6 @@ import
|
|||
../utils/utils,
|
||||
"."/[dao, eip4844, gaslimit, withdrawals],
|
||||
./pow/[difficulty, header],
|
||||
./pow,
|
||||
nimcrypto/utils as cryptoutils,
|
||||
stew/objects,
|
||||
results
|
||||
|
@ -34,35 +33,9 @@ const
|
|||
byteutils.hexToByteArray[13](DAOForkBlockExtra).toSeq
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Pivate validator functions
|
||||
# Private validator functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc validateSeal(pow: PowRef; header: BlockHeader): Result[void,string] =
|
||||
try:
|
||||
let (expmixHash, miningValue) = pow.getPowDigest(header)
|
||||
|
||||
if expmixHash != header.mixHash:
|
||||
let
|
||||
miningHash = header.getPowSpecs.miningHash
|
||||
(size, cachedHash) = try: pow.getPowCacheLookup(header.number)
|
||||
except KeyError: return err("Unknown block")
|
||||
except CatchableError as e: return err(e.msg)
|
||||
return err("mixHash mismatch. actual=$1, expected=$2," &
|
||||
" blockNumber=$3, miningHash=$4, nonce=$5, difficulty=$6," &
|
||||
" size=$7, cachedHash=$8" % [
|
||||
$header.mixHash, $expmixHash, $header.number,
|
||||
$miningHash, header.nonce.toHex, $header.difficulty,
|
||||
$size, $cachedHash])
|
||||
|
||||
let value = UInt256.fromBytesBE(miningValue.data)
|
||||
if value > UInt256.high div header.difficulty:
|
||||
return err("mining difficulty error")
|
||||
|
||||
except CatchableError as err:
|
||||
return err(err.msg)
|
||||
|
||||
ok()
|
||||
|
||||
proc validateHeader(
|
||||
com: CommonRef;
|
||||
blk: EthBlock;
|
||||
|
@ -118,9 +91,6 @@ proc validateHeader(
|
|||
if header.difficulty < calcDiffc:
|
||||
return err("provided header difficulty is too low")
|
||||
|
||||
if checkSealOK:
|
||||
return com.pow.validateSeal(header)
|
||||
|
||||
? com.validateWithdrawals(header, blk.withdrawals)
|
||||
? com.validateEip4844Header(header, parentHeader, blk.transactions)
|
||||
? com.validateGasLimitOrBaseFee(header, parentHeader)
|
||||
|
@ -195,10 +165,6 @@ proc validateUncles(com: CommonRef; header: BlockHeader;
|
|||
if uncle.timestamp <= parent.timestamp:
|
||||
return err("Uncle's parent must me older")
|
||||
|
||||
# Now perform VM level validation of the uncle
|
||||
if checkSealOK:
|
||||
? com.pow.validateSeal(uncle)
|
||||
|
||||
let uncleParent = try:
|
||||
chainDB.getBlockHeader(uncle.parentHash)
|
||||
except BlockNotFound:
|
||||
|
|
|
@ -39,7 +39,6 @@ cliBuilder:
|
|||
./test_multi_keys,
|
||||
./test_misc,
|
||||
#./test_graphql, -- fails
|
||||
./test_pow,
|
||||
./test_configuration,
|
||||
#./test_txpool, -- fails
|
||||
./test_txpool2,
|
||||
|
|
Binary file not shown.
|
@ -1,109 +0,0 @@
|
|||
# Nimbus
|
||||
# Copyright (c) 2022-2024 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],
|
||||
./replay/[pp, gunzip],
|
||||
../nimbus/core/[pow, pow/pow_cache],
|
||||
eth/common,
|
||||
unittest2
|
||||
|
||||
const
|
||||
baseDir = [".", "tests", ".." / "tests", $DirSep] # path containg repo
|
||||
repoDir = ["replay"] # alternative repos
|
||||
|
||||
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
|
||||
pow = PowRef.new(powCache)
|
||||
|
||||
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.number:
|
||||
specsList.add specs
|
||||
check line == specs.dumpPowSpecs
|
||||
noisy.say "***", " block range #",
|
||||
specsList[0].number, " .. #", specsList[^1].number
|
||||
|
||||
# Adjust number of tests
|
||||
let
|
||||
startVerify = max(0, specsList.len - nVerify)
|
||||
nDoVerify = specsList.len - startVerify
|
||||
|
||||
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.mixHash
|
||||
|
||||
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.mixHash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 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
|
||||
# ------------------------------------------------------------------------------
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 953b8ed994d5f14569ca255cfe75bb4507025dcc
|
Loading…
Reference in New Issue