2023-11-01 03:32:09 +00:00
|
|
|
# Nimbus
|
2024-03-20 07:35:38 +00:00
|
|
|
# Copyright (c) 2019-2024 Status Research & Development GmbH
|
2023-11-01 03:32:09 +00:00
|
|
|
# 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.
|
|
|
|
|
2022-12-02 04:39:12 +00:00
|
|
|
import
|
2023-10-18 02:16:11 +00:00
|
|
|
std/[strutils, tables, os, json],
|
2022-12-02 04:39:12 +00:00
|
|
|
unittest2,
|
|
|
|
stew/byteutils,
|
|
|
|
../nimbus/core/pow/difficulty,
|
|
|
|
../nimbus/constants,
|
|
|
|
../nimbus/common/common,
|
2023-05-22 08:12:50 +00:00
|
|
|
./test_helpers
|
2019-08-23 15:54:25 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
Tester = object
|
|
|
|
parentTimestamp: int64
|
|
|
|
parentDifficulty: Uint256
|
|
|
|
parentUncles: Hash256
|
|
|
|
currentTimestamp: int64
|
|
|
|
currentBlockNumber: Uint256
|
|
|
|
currentDifficulty: Uint256
|
|
|
|
|
|
|
|
Tests = Table[string, Tester]
|
|
|
|
|
2023-05-22 08:12:50 +00:00
|
|
|
const
|
|
|
|
inputPath = "tests" / "fixtures" / "eth_tests" / "DifficultyTests"
|
|
|
|
|
2019-08-23 15:54:25 +00:00
|
|
|
proc hexOrInt64(data: JsonNode, key: string, hex: static[bool]): int64 =
|
|
|
|
when hex:
|
|
|
|
getHexadecimalInt data[key]
|
|
|
|
else:
|
|
|
|
int64(parseInt data[key].getStr)
|
|
|
|
|
|
|
|
proc hexOrInt256(data: JsonNode, key: string, hex: static[bool]): Uint256 =
|
|
|
|
when hex:
|
|
|
|
UInt256.fromHex data[key].getStr
|
|
|
|
else:
|
|
|
|
parse(data[key].getStr, Uint256)
|
|
|
|
|
2023-05-22 08:12:50 +00:00
|
|
|
proc parseHash(data: string): Hash256 =
|
|
|
|
case data
|
|
|
|
of "0x00": result = EMPTY_UNCLE_HASH
|
|
|
|
of "0x01": result.data[0] = 1.byte
|
|
|
|
else:
|
|
|
|
doAssert(false, "invalid uncle hash")
|
2019-08-23 15:54:25 +00:00
|
|
|
|
2023-05-22 08:12:50 +00:00
|
|
|
proc parseTests(testData: JSonNode): Tests =
|
|
|
|
const hex = true
|
2019-08-23 15:54:25 +00:00
|
|
|
result = initTable[string, Tester]()
|
|
|
|
var t: Tester
|
2023-05-22 08:12:50 +00:00
|
|
|
for title, data in testData:
|
2019-08-23 15:54:25 +00:00
|
|
|
t.parentTimestamp = hexOrInt64(data, "parentTimestamp", hex)
|
|
|
|
t.parentDifficulty = hexOrInt256(data, "parentDifficulty", hex)
|
2020-02-20 03:43:47 +00:00
|
|
|
let pu = data.fields.getOrDefault("parentUncles")
|
|
|
|
if pu.isNil:
|
|
|
|
t.parentUncles = EMPTY_UNCLE_HASH
|
|
|
|
else:
|
2023-05-22 08:12:50 +00:00
|
|
|
t.parentUncles = parseHash(pu.getStr)
|
2019-08-23 15:54:25 +00:00
|
|
|
t.currentTimestamp = hexOrInt64(data, "currentTimestamp", hex)
|
|
|
|
t.currentBlockNumber = hexOrInt256(data, "currentBlockNumber", hex)
|
|
|
|
t.currentDifficulty = hexOrInt256(data, "currentDifficulty", hex)
|
|
|
|
result[title] = t
|
|
|
|
|
2023-05-22 08:12:50 +00:00
|
|
|
proc calculator(revision: string, timestamp: EthTime, header: BlockHeader): DifficultyInt =
|
|
|
|
case revision
|
|
|
|
of "Homestead": result = calcDifficultyHomestead(timestamp, header)
|
|
|
|
of "GrayGlacier": result = calcDifficultyGrayGlacier(timestamp, header)
|
|
|
|
of "Frontier": result = calcDifficultyFrontier(timestamp, header)
|
|
|
|
of "Berlin": result = calcDifficultyMuirGlacier(timestamp, header)
|
|
|
|
of "Constantinople": result = calcDifficultyConstantinople(timestamp, header)
|
|
|
|
of "Byzantium": result = calcDifficultyByzantium(timestamp, header)
|
|
|
|
of "ArrowGlacier": result = calcDifficultyArrowGlacier(timestamp, header)
|
|
|
|
else:
|
|
|
|
doAssert(false, "unknown revision: " & revision)
|
|
|
|
|
|
|
|
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
|
|
|
var fixture: JsonNode
|
|
|
|
for _, child in fixtures:
|
|
|
|
fixture = child
|
|
|
|
break
|
|
|
|
|
|
|
|
for revision, child in fixture:
|
|
|
|
if revision == "_info":
|
|
|
|
continue
|
|
|
|
|
|
|
|
let tests = parseTests(child)
|
|
|
|
|
|
|
|
for title, t in tests:
|
|
|
|
let p = BlockHeader(
|
|
|
|
difficulty : t.parentDifficulty,
|
2023-10-18 02:16:11 +00:00
|
|
|
timestamp : EthTime(t.parentTimestamp),
|
2019-05-30 16:42:55 +00:00
|
|
|
blockNumber: t.currentBlockNumber - 1,
|
2023-05-22 08:12:50 +00:00
|
|
|
ommersHash : t.parentUncles
|
|
|
|
)
|
|
|
|
|
2024-03-20 07:35:38 +00:00
|
|
|
let timestamp = EthTime(t.currentTimestamp)
|
2019-08-23 15:54:25 +00:00
|
|
|
|
2023-05-22 08:12:50 +00:00
|
|
|
let diff = calculator(revision, timestamp, p)
|
2019-08-23 15:54:25 +00:00
|
|
|
check diff == t.currentDifficulty
|
|
|
|
|
2023-05-22 08:12:50 +00:00
|
|
|
template runTest() =
|
|
|
|
var filenames: seq[string] = @[]
|
|
|
|
for filename in walkDirRec(inputPath):
|
|
|
|
if not filename.endsWith(".json"):
|
|
|
|
continue
|
|
|
|
filenames.add filename
|
2020-04-12 10:33:17 +00:00
|
|
|
|
2023-05-22 08:12:50 +00:00
|
|
|
doAssert(filenames.len > 0)
|
2020-04-12 11:09:18 +00:00
|
|
|
|
2023-05-22 08:12:50 +00:00
|
|
|
for fname in filenames:
|
|
|
|
let filename = fname
|
|
|
|
test fname.subStr(inputPath.len + 1):
|
|
|
|
let fixtures = parseJson(readFile(filename))
|
|
|
|
testFixture(fixtures, testStatusIMPL)
|
|
|
|
|
|
|
|
proc difficultyMain*() =
|
2019-09-21 05:45:23 +00:00
|
|
|
suite "DifficultyTest":
|
2023-05-22 08:12:50 +00:00
|
|
|
runTest()
|
2019-10-26 01:24:05 +00:00
|
|
|
|
|
|
|
when isMainModule:
|
|
|
|
difficultyMain()
|