Merge pull request #17 from status-im/Rit
use non-EOL macOS in CI; apply styleCheck:error; prefer func to proc(){.noSideEffect.}; check refc in Nim 2.0+
This commit is contained in:
commit
953b8ed994
|
@ -24,7 +24,7 @@ jobs:
|
||||||
builder: ubuntu-20.04
|
builder: ubuntu-20.04
|
||||||
- target:
|
- target:
|
||||||
os: macos
|
os: macos
|
||||||
builder: macos-11
|
builder: macos-12
|
||||||
- target:
|
- target:
|
||||||
os: windows
|
os: windows
|
||||||
builder: windows-latest
|
builder: windows-latest
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
import math, endians,
|
import math, endians,
|
||||||
|
@ -28,7 +28,7 @@ const
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Parameters
|
# Parameters
|
||||||
|
|
||||||
proc get_cache_size*(block_number: uint): uint {.noSideEffect.}=
|
func get_cache_size*(block_number: uint): uint =
|
||||||
result = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number div EPOCH_LENGTH)
|
result = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number div EPOCH_LENGTH)
|
||||||
result -= HASH_BYTES
|
result -= HASH_BYTES
|
||||||
while (let dm = divmod(result, HASH_BYTES);
|
while (let dm = divmod(result, HASH_BYTES);
|
||||||
|
@ -37,7 +37,7 @@ proc get_cache_size*(block_number: uint): uint {.noSideEffect.}=
|
||||||
# Means checking that reminder == 0 and quotient is prime
|
# Means checking that reminder == 0 and quotient is prime
|
||||||
result -= 2 * HASH_BYTES
|
result -= 2 * HASH_BYTES
|
||||||
|
|
||||||
proc get_data_size*(block_number: uint): uint {.noSideEffect.}=
|
func get_data_size*(block_number: uint): uint =
|
||||||
result = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number div EPOCH_LENGTH)
|
result = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number div EPOCH_LENGTH)
|
||||||
result -= MIX_BYTES
|
result -= MIX_BYTES
|
||||||
while (let dm = divmod(result, MIX_BYTES);
|
while (let dm = divmod(result, MIX_BYTES);
|
||||||
|
@ -47,16 +47,16 @@ proc get_data_size*(block_number: uint): uint {.noSideEffect.}=
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Fetch from lookup tables of 2048 epochs of data sizes and cache sizes
|
# Fetch from lookup tables of 2048 epochs of data sizes and cache sizes
|
||||||
|
|
||||||
proc get_datasize_lut*(block_number: Natural): uint64 {.noSideEffect, inline.} =
|
func get_datasize_lut*(block_number: Natural): uint64 {.inline.} =
|
||||||
data_sizes[block_number div EPOCH_LENGTH]
|
data_sizes[block_number div EPOCH_LENGTH]
|
||||||
|
|
||||||
proc get_cachesize_lut*(block_number: Natural): uint64 {.noSideEffect, inline.} =
|
func get_cachesize_lut*(block_number: Natural): uint64 {.inline.} =
|
||||||
cache_sizes[block_number div EPOCH_LENGTH]
|
cache_sizes[block_number div EPOCH_LENGTH]
|
||||||
|
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Cache generation
|
# Cache generation
|
||||||
|
|
||||||
proc mkcache*(cache_size: uint64, seed: Hash[256]): seq[Hash[512]] {.noSideEffect.}=
|
func mkcache*(cache_size: uint64, seed: Hash[256]): seq[Hash[512]] =
|
||||||
|
|
||||||
# Cache size
|
# Cache size
|
||||||
let n = int(cache_size div HASH_BYTES)
|
let n = int(cache_size div HASH_BYTES)
|
||||||
|
@ -82,7 +82,7 @@ proc mkcache*(cache_size: uint64, seed: Hash[256]): seq[Hash[512]] {.noSideEffec
|
||||||
|
|
||||||
const FNV_PRIME = 0x01000193
|
const FNV_PRIME = 0x01000193
|
||||||
|
|
||||||
proc fnv*[T: SomeUnsignedInt or Natural](v1, v2: T): uint32 {.inline, noSideEffect.}=
|
func fnv*[T: SomeUnsignedInt or Natural](v1, v2: T): uint32 {.inline.}=
|
||||||
|
|
||||||
# Original formula is ((v1 * FNV_PRIME) xor v2) mod 2^32
|
# Original formula is ((v1 * FNV_PRIME) xor v2) mod 2^32
|
||||||
# However contrary to Python and depending on the type T,
|
# However contrary to Python and depending on the type T,
|
||||||
|
@ -103,7 +103,7 @@ proc fnv*[T: SomeUnsignedInt or Natural](v1, v2: T): uint32 {.inline, noSideEffe
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Full dataset calculation
|
# Full dataset calculation
|
||||||
|
|
||||||
proc calc_dataset_item*(cache: seq[Hash[512]], i: Natural): Hash[512] {.noSideEffect, noInit.} =
|
func calc_dataset_item*(cache: seq[Hash[512]], i: Natural): Hash[512] {.noinit.} =
|
||||||
let n = cache.len
|
let n = cache.len
|
||||||
const r: uint32 = HASH_BYTES div WORD_BYTES
|
const r: uint32 = HASH_BYTES div WORD_BYTES
|
||||||
|
|
||||||
|
@ -159,14 +159,14 @@ template hashimoto(header: Hash[256],
|
||||||
assert MIX_BYTES mod HASH_BYTES == 0
|
assert MIX_BYTES mod HASH_BYTES == 0
|
||||||
|
|
||||||
# combine header+nonce into a 64 byte seed
|
# combine header+nonce into a 64 byte seed
|
||||||
var s{.noInit.}: Hash[512]
|
var s{.noinit.}: Hash[512]
|
||||||
let s_bytes = cast[ptr array[64, byte]](addr s) # Alias for to interpret s as a byte array
|
let s_bytes = cast[ptr array[64, byte]](addr s) # Alias for to interpret s as a byte array
|
||||||
let s_words = cast[ptr array[16, uint32]](addr s) # Alias for to interpret s as an uint32 array
|
let s_words = cast[ptr array[16, uint32]](addr s) # Alias for to interpret s as an uint32 array
|
||||||
|
|
||||||
s_bytes[][0..<32] = header.data # We first populate the first 40 bytes of s with the concatenation
|
s_bytes[][0..<32] = header.data # We first populate the first 40 bytes of s with the concatenation
|
||||||
# In template we need to dereference first otherwise it's not considered as var
|
# In template we need to dereference first otherwise it's not considered as var
|
||||||
|
|
||||||
var nonceLE{.noInit.}: array[8, byte] # the nonce should be concatenated with its LITTLE ENDIAN representation
|
var nonceLE{.noinit.}: array[8, byte] # the nonce should be concatenated with its LITTLE ENDIAN representation
|
||||||
littleEndian64(addr nonceLE, unsafeAddr nonce)
|
littleEndian64(addr nonceLE, unsafeAddr nonce)
|
||||||
s_bytes[][32..<40] = cast[array[8,byte]](nonceLE)
|
s_bytes[][32..<40] = cast[array[8,byte]](nonceLE)
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ template hashimoto(header: Hash[256],
|
||||||
|
|
||||||
# start the mix with replicated s
|
# start the mix with replicated s
|
||||||
assert MIX_BYTES div HASH_BYTES == 2
|
assert MIX_BYTES div HASH_BYTES == 2
|
||||||
var mix{.noInit.}: array[32, uint32]
|
var mix{.noinit.}: array[32, uint32]
|
||||||
mix[0..<16] = s_words[]
|
mix[0..<16] = s_words[]
|
||||||
mix[16..<32] = s_words[]
|
mix[16..<32] = s_words[]
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ template hashimoto(header: Hash[256],
|
||||||
let p1{.inject.} = p + 1
|
let p1{.inject.} = p + 1
|
||||||
|
|
||||||
# Unrolled: for j in range(MIX_BYTES / HASH_BYTES): => for j in 0 ..< 2
|
# Unrolled: for j in range(MIX_BYTES / HASH_BYTES): => for j in 0 ..< 2
|
||||||
var newdata{.noInit.}: type mix
|
var newdata{.noinit.}: type mix
|
||||||
newdata[0..<16] = cast[array[16, uint32]](dataset_lookup_p)
|
newdata[0..<16] = cast[array[16, uint32]](dataset_lookup_p)
|
||||||
newdata[16..<32] = cast[array[16, uint32]](dataset_lookup_p1)
|
newdata[16..<32] = cast[array[16, uint32]](dataset_lookup_p1)
|
||||||
|
|
||||||
|
@ -198,13 +198,13 @@ template hashimoto(header: Hash[256],
|
||||||
for i in countup(0, mix.len - 1, 4):
|
for i in countup(0, mix.len - 1, 4):
|
||||||
cmix[i div 4] = mix[i].fnv(mix[i+1]).fnv(mix[i+2]).fnv(mix[i+3])
|
cmix[i div 4] = mix[i].fnv(mix[i+1]).fnv(mix[i+2]).fnv(mix[i+3])
|
||||||
|
|
||||||
var concat{.noInit.}: array[64 + 32, byte]
|
var concat{.noinit.}: array[64 + 32, byte]
|
||||||
concat[0..<64] = s_bytes[]
|
concat[0..<64] = s_bytes[]
|
||||||
concat[64..<96] = cast[array[32, byte]](result.mix_digest)
|
concat[64..<96] = cast[array[32, byte]](result.mix_digest)
|
||||||
result.value = keccak_256(concat)
|
result.value = keccak_256(concat)
|
||||||
|
|
||||||
proc hashimoto_light*(full_size:Natural, cache: seq[Hash[512]],
|
func hashimoto_light*(full_size:Natural, cache: seq[Hash[512]],
|
||||||
header: Hash[256], nonce: uint64): HashimotoHash {.noSideEffect.} =
|
header: Hash[256], nonce: uint64): HashimotoHash =
|
||||||
|
|
||||||
hashimoto(header,
|
hashimoto(header,
|
||||||
nonce,
|
nonce,
|
||||||
|
@ -213,8 +213,8 @@ proc hashimoto_light*(full_size:Natural, cache: seq[Hash[512]],
|
||||||
calc_data_set_item(cache, p1),
|
calc_data_set_item(cache, p1),
|
||||||
result)
|
result)
|
||||||
|
|
||||||
proc hashimoto_full*(full_size:Natural, dataset: seq[Hash[512]],
|
func hashimoto_full*(full_size:Natural, dataset: seq[Hash[512]],
|
||||||
header: Hash[256], nonce: uint64): HashimotoHash {.noSideEffect.} =
|
header: Hash[256], nonce: uint64): HashimotoHash =
|
||||||
# TODO spec mentions full_size but I don't think we need it (retrieve it from dataset.len)
|
# TODO spec mentions full_size but I don't think we need it (retrieve it from dataset.len)
|
||||||
hashimoto(header,
|
hashimoto(header,
|
||||||
nonce,
|
nonce,
|
||||||
|
@ -225,6 +225,6 @@ proc hashimoto_full*(full_size:Natural, dataset: seq[Hash[512]],
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Defining the seed hash
|
# Defining the seed hash
|
||||||
|
|
||||||
proc get_seedhash*(block_number: uint64): Hash[256] {.noSideEffect.} =
|
func get_seedhash*(block_number: uint64): Hash[256] =
|
||||||
for i in 0 ..< int(block_number div EPOCH_LENGTH):
|
for i in 0 ..< int(block_number div EPOCH_LENGTH):
|
||||||
result = keccak256 result.data
|
result = keccak256 result.data
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
mode = ScriptMode.Verbose
|
||||||
|
|
||||||
packageName = "ethash"
|
packageName = "ethash"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
author = "Status Research & Development GmbH"
|
author = "Status Research & Development GmbH"
|
||||||
|
@ -7,25 +9,20 @@ srcDir = "src"
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
requires "nim >= 0.18.0", "nimcrypto >= 0.1.0"
|
requires "nim >= 1.6.0", "nimcrypto >= 0.1.0"
|
||||||
|
|
||||||
proc test(name: string, lang: string = "c") =
|
proc test(name: string, args: string) =
|
||||||
if not dirExists "build":
|
if not dirExists "build":
|
||||||
mkDir "build"
|
mkDir "build"
|
||||||
--run
|
exec "nim c --styleCheck:usages --styleCheck:error --outdir:./build/ " & args & " --run tests/" & name & ".nim"
|
||||||
switch("out", ("./build/" & name))
|
if (NimMajor, NimMinor) > (1, 6):
|
||||||
setCommand lang, "tests/" & name & ".nim"
|
exec "nim c --styleCheck:usages --styleCheck:error --mm:refc --outdir:./build/ " & args & " --run tests/" & name & ".nim"
|
||||||
|
|
||||||
task test, "Run Proof-of-Work tests (without mining)":
|
task test, "Run Proof-of-Work tests (without mining)":
|
||||||
test "all_tests"
|
test "all_tests", ""
|
||||||
|
|
||||||
task testRelease, "test release mode":
|
task testRelease, "test release mode":
|
||||||
switch("define", "release")
|
test "all_tests", "-d:release"
|
||||||
testTask()
|
|
||||||
|
|
||||||
task test_mining, "Run Proof-of-Work and mining tests (test in release mode + OpenMP + march=native)":
|
task test_mining, "Run Proof-of-Work and mining tests (test in release mode + OpenMP + march=native)":
|
||||||
switch("define", "release")
|
test "all_tests", "-d:release -d:openmp -d:march_native -d:ethash_mining"
|
||||||
switch("define", "openmp")
|
|
||||||
switch("define", "march_native")
|
|
||||||
switch("define", "ethash_mining")
|
|
||||||
test "all_tests"
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import ./internal
|
||||||
|
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
proc toHex*[N: static[int]](ba: array[N, byte]): string {.noSideEffect.}=
|
func toHex*[N: static[int]](ba: array[N, byte]): string =
|
||||||
## Convert a big-endian byte array to its hex representation
|
## Convert a big-endian byte array to its hex representation
|
||||||
## Output is in lowercase
|
## Output is in lowercase
|
||||||
##
|
##
|
||||||
|
@ -19,7 +19,7 @@ proc toHex*[N: static[int]](ba: array[N, byte]): string {.noSideEffect.}=
|
||||||
result[2*i+1] = hexChars[int ba[i] and 0xF]
|
result[2*i+1] = hexChars[int ba[i] and 0xF]
|
||||||
|
|
||||||
|
|
||||||
proc readHexChar(c: char): byte {.noSideEffect.}=
|
func readHexChar(c: char): byte =
|
||||||
## Converts an hex char to a byte
|
## Converts an hex char to a byte
|
||||||
case c
|
case c
|
||||||
of '0'..'9': result = byte(ord(c) - ord('0'))
|
of '0'..'9': result = byte(ord(c) - ord('0'))
|
||||||
|
@ -28,7 +28,7 @@ proc readHexChar(c: char): byte {.noSideEffect.}=
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, $c & "is not a hexademical character")
|
raise newException(ValueError, $c & "is not a hexademical character")
|
||||||
|
|
||||||
proc hexToByteArrayBE*[N: static[int]](hexStr: string): array[N, byte] {.noSideEffect, noInit.}=
|
func hexToByteArrayBE*[N: static[int]](hexStr: string): array[N, byte] {.noinit.}=
|
||||||
## Read an hex string and store it in a Byte Array in Big-Endian order
|
## Read an hex string and store it in a Byte Array in Big-Endian order
|
||||||
var i = 0
|
var i = 0
|
||||||
if hexStr[i] == '0' and (hexStr[i+1] == 'x' or hexStr[i+1] == 'X'):
|
if hexStr[i] == '0' and (hexStr[i+1] == 'x' or hexStr[i+1] == 'X'):
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
when defined(openmp):
|
when defined(openmp):
|
||||||
{.passC: "-fopenmp".}
|
{.passc: "-fopenmp".}
|
||||||
{.passL: "-fopenmp".}
|
{.passl: "-fopenmp".}
|
||||||
|
|
||||||
when defined(march_native):
|
when defined(march_native):
|
||||||
{.passC: "-march=native".}
|
{.passc: "-march=native".}
|
||||||
|
|
||||||
import ./proof_of_work
|
import ./proof_of_work
|
||||||
export proof_of_work
|
export proof_of_work
|
||||||
|
|
|
@ -60,11 +60,11 @@ proc mulCarry(a, b: uint64): tuple[carry, unit: uint64] =
|
||||||
result.unit += z0
|
result.unit += z0
|
||||||
result.carry = (result.unit < z0).uint64 + z2 + z1 shr 32
|
result.carry = (result.unit < z0).uint64 + z2 + z1 shr 32
|
||||||
|
|
||||||
proc isValid(nonce: uint64,
|
func isValid(nonce: uint64,
|
||||||
difficulty: uint64,
|
difficulty: uint64,
|
||||||
full_size: Natural,
|
full_size: Natural,
|
||||||
dataset: seq[MDigest[512]],
|
dataset: seq[MDigest[512]],
|
||||||
header: MDigest[256]): bool {.noSideEffect.}=
|
header: MDigest[256]): bool =
|
||||||
# Boundary is 2^256/difficulty
|
# Boundary is 2^256/difficulty
|
||||||
# A valid nonce will have: hashimoto < 2^256/difficulty
|
# A valid nonce will have: hashimoto < 2^256/difficulty
|
||||||
# We can't represent 2^256 as an uint256 so as a workaround we use:
|
# We can't represent 2^256 as an uint256 so as a workaround we use:
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
import nimcrypto
|
import nimcrypto
|
||||||
|
|
||||||
proc as_u32_words*[bits: static[int]](x: MDigest[bits]): array[bits div 32, uint32] {.inline, noSideEffect, noInit.}=
|
func as_u32_words*[bits: static[int]](x: MDigest[bits]): array[bits div 32, uint32] {.inline, noinit.}=
|
||||||
# Convert an hash to its uint32 representation
|
# Convert an hash to its uint32 representation
|
||||||
cast[type result](x)
|
cast[type result](x)
|
||||||
|
|
||||||
proc readHexChar(c: char): byte {.noSideEffect.}=
|
func readHexChar(c: char): byte =
|
||||||
## Converts an hex char to a byte
|
## Converts an hex char to a byte
|
||||||
case c
|
case c
|
||||||
of '0'..'9': result = byte(ord(c) - ord('0'))
|
of '0'..'9': result = byte(ord(c) - ord('0'))
|
||||||
|
@ -16,7 +16,7 @@ proc readHexChar(c: char): byte {.noSideEffect.}=
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, $c & "is not a hexademical character")
|
raise newException(ValueError, $c & "is not a hexademical character")
|
||||||
|
|
||||||
proc hexToByteArrayBE*[N: static[int]](hexStr: string): array[N, byte] {.noSideEffect, noInit.}=
|
func hexToByteArrayBE*[N: static[int]](hexStr: string): array[N, byte] {.noinit.}=
|
||||||
## Read an hex string and store it in a Byte Array in Big-Endian order
|
## Read an hex string and store it in a Byte Array in Big-Endian order
|
||||||
var i = 0
|
var i = 0
|
||||||
if hexStr[i] == '0' and (hexStr[i+1] == 'x' or hexStr[i+1] == 'X'):
|
if hexStr[i] == '0' and (hexStr[i+1] == 'x' or hexStr[i+1] == 'X'):
|
||||||
|
@ -28,7 +28,7 @@ proc hexToByteArrayBE*[N: static[int]](hexStr: string): array[N, byte] {.noSideE
|
||||||
result[i] = hexStr[2*i].readHexChar shl 4 or hexStr[2*i+1].readHexChar
|
result[i] = hexStr[2*i].readHexChar shl 4 or hexStr[2*i+1].readHexChar
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
proc hexToSeqBytesBE*(hexStr: string): seq[byte] {.noSideEffect.}=
|
func hexToSeqBytesBE*(hexStr: string): seq[byte] =
|
||||||
## Read an hex string and store it in a sequence of bytes in Big-Endian order
|
## Read an hex string and store it in a sequence of bytes in Big-Endian order
|
||||||
var i = 0
|
var i = 0
|
||||||
if hexStr[i] == '0' and (hexStr[i+1] == 'x' or hexStr[i+1] == 'X'):
|
if hexStr[i] == '0' and (hexStr[i+1] == 'x' or hexStr[i+1] == 'X'):
|
||||||
|
@ -41,7 +41,7 @@ proc hexToSeqBytesBE*(hexStr: string): seq[byte] {.noSideEffect.}=
|
||||||
result[i] = hexStr[2*i].readHexChar shl 4 or hexStr[2*i+1].readHexChar
|
result[i] = hexStr[2*i].readHexChar shl 4 or hexStr[2*i+1].readHexChar
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
proc toHex*[N: static[int]](ba: array[N, byte]): string {.noSideEffect.}=
|
func toHex*[N: static[int]](ba: array[N, byte]): string =
|
||||||
## Convert a big-endian byte array to its hex representation
|
## Convert a big-endian byte array to its hex representation
|
||||||
## Output is in lowercase
|
## Output is in lowercase
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ proc toHex*[N: static[int]](ba: array[N, byte]): string {.noSideEffect.}=
|
||||||
result[2*i] = hexChars[int ba[i] shr 4 and 0xF]
|
result[2*i] = hexChars[int ba[i] shr 4 and 0xF]
|
||||||
result[2*i+1] = hexChars[int ba[i] and 0xF]
|
result[2*i+1] = hexChars[int ba[i] and 0xF]
|
||||||
|
|
||||||
proc toHex*(ba: seq[byte]): string {.noSideEffect, noInit.}=
|
func toHex*(ba: seq[byte]): string {.noinit.}=
|
||||||
## Convert a big-endian byte sequence to its hex representation
|
## Convert a big-endian byte sequence to its hex representation
|
||||||
## Output is in lowercase
|
## Output is in lowercase
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ proc toHex*(ba: seq[byte]): string {.noSideEffect, noInit.}=
|
||||||
result[2*i] = hexChars[int ba[i] shr 4 and 0xF]
|
result[2*i] = hexChars[int ba[i] shr 4 and 0xF]
|
||||||
result[2*i+1] = hexChars[int ba[i] and 0xF]
|
result[2*i+1] = hexChars[int ba[i] and 0xF]
|
||||||
|
|
||||||
proc toByteArrayBE*[T: SomeInteger](num: T): array[T.sizeof, byte] {.noSideEffect, noInit, inline.}=
|
func toByteArrayBE*[T: SomeInteger](num: T): array[T.sizeof, byte] {.noinit, inline.}=
|
||||||
## Convert an int (in native host endianness) to a big-endian byte array
|
## Convert an int (in native host endianness) to a big-endian byte array
|
||||||
# Note: only works on devel
|
# Note: only works on devel
|
||||||
|
|
||||||
|
@ -78,5 +78,5 @@ proc toByteArrayBE*[T: SomeInteger](num: T): array[T.sizeof, byte] {.noSideEffec
|
||||||
for i in 0 ..< N:
|
for i in 0 ..< N:
|
||||||
result[i] = byte(num shr T((N-1-i) * 8))
|
result[i] = byte(num shr T((N-1-i) * 8))
|
||||||
|
|
||||||
proc toByteArrayBE*[bits: static[int]](x: MDigest[bits]): array[bits div 8, byte] {.inline, noSideEffect, noInit.}=
|
func toByteArrayBE*[bits: static[int]](x: MDigest[bits]): array[bits div 8, byte] {.inline, noinit.}=
|
||||||
cast[type result](x.data)
|
cast[type result](x.data)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ template zipMap*[N: static[int], T, U](
|
||||||
))
|
))
|
||||||
|
|
||||||
{.pragma: align64, codegenDecl: "$# $# __attribute__((aligned(64)))".}
|
{.pragma: align64, codegenDecl: "$# $# __attribute__((aligned(64)))".}
|
||||||
var result{.noInit, align64.}: array[N, outType]
|
var result{.noinit, align64.}: array[N, outType]
|
||||||
|
|
||||||
for i, x {.inject.}, y {.inject.} in enumerateZip(a, b):
|
for i, x {.inject.}, y {.inject.} in enumerateZip(a, b):
|
||||||
{.unroll: 4.} # This is a no-op at the moment
|
{.unroll: 4.} # This is a no-op at the moment
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# From https://github.com/numforge/number-theory/
|
# From https://github.com/numforge/number-theory/
|
||||||
# MIT Licence
|
# MIT Licence
|
||||||
# Copyright (c) 2016 Mamy Ratsimbazafy
|
# Copyright (c) 2016-2024 Mamy Ratsimbazafy
|
||||||
|
|
||||||
# ########### Number of bits to represent a number
|
# ########### Number of bits to represent a number
|
||||||
|
|
||||||
|
@ -59,16 +59,16 @@ type
|
||||||
proc ldiv(a, b: clong): ldiv_t {.importc: "ldiv", header: "<stdlib.h>".}
|
proc ldiv(a, b: clong): ldiv_t {.importc: "ldiv", header: "<stdlib.h>".}
|
||||||
proc lldiv(a, b: clonglong): lldiv_t {.importc: "lldiv", header: "<stdlib.h>".}
|
proc lldiv(a, b: clonglong): lldiv_t {.importc: "lldiv", header: "<stdlib.h>".}
|
||||||
|
|
||||||
proc divmod*(a, b: int32): tuple[quot, rem: clong] {.inline, noSideEffect, noInit.}=
|
func divmod*(a, b: int32): tuple[quot, rem: clong] {.inline, noinit.}=
|
||||||
## Compute quotient and reminder of integer division in a single intrinsics operation
|
## Compute quotient and reminder of integer division in a single intrinsics operation
|
||||||
# TODO: changing clong to int32 poses an issue for some reason
|
# TODO: changing clong to int32 poses an issue for some reason
|
||||||
cast[type result](ldiv(a,b))
|
cast[type result](ldiv(a,b))
|
||||||
|
|
||||||
proc divmod*(a, b: int64): tuple[quot, rem: int64] {.inline, noSideEffect, noInit.}=
|
func divmod*(a, b: int64): tuple[quot, rem: int64] {.inline, noinit.}=
|
||||||
## Compute quotient and reminder of integer division in a single intrinsicsoperation
|
## Compute quotient and reminder of integer division in a single intrinsicsoperation
|
||||||
cast[type result](lldiv(a,b))
|
cast[type result](lldiv(a,b))
|
||||||
|
|
||||||
proc divmod*[T: SomeUnsignedInt](a, b: T): tuple[quot, rem: T] {.inline, noSideEffect, noInit.}=
|
func divmod*[T: SomeUnsignedInt](a, b: T): tuple[quot, rem: T] {.inline, noinit.}=
|
||||||
# There is no single instruction for unsigned ints
|
# There is no single instruction for unsigned ints
|
||||||
# Hopefully the compiler does its work properly
|
# Hopefully the compiler does its work properly
|
||||||
(a div b, a mod b)
|
(a div b, a mod b)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
# Primality testing. TODO: a scalable implementation (i.e. Miller-Rabin)
|
# Primality testing. TODO: a scalable implementation (i.e. Miller-Rabin)
|
||||||
|
@ -6,13 +6,13 @@
|
||||||
|
|
||||||
import ./intmath
|
import ./intmath
|
||||||
|
|
||||||
proc isPrime*[T: SomeUnsignedInt](x: T): bool {.noSideEffect.}=
|
func isPrime*[T: SomeUnsignedInt](x: T): bool =
|
||||||
for i in 2.T .. isqrt x:
|
for i in 2.T .. isqrt x:
|
||||||
if x mod i == 0:
|
if x mod i == 0:
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc isPrime*(x: Natural): bool {.noSideEffect.}=
|
func isPrime*(x: Natural): bool =
|
||||||
for i in 2 .. isqrt x:
|
for i in 2 .. isqrt x:
|
||||||
if x mod i == 0:
|
if x mod i == 0:
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -28,7 +28,7 @@ const
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Parameters
|
# Parameters
|
||||||
|
|
||||||
proc get_cache_size*(block_number: uint64): uint64 {.noSideEffect.}=
|
func get_cache_size*(block_number: uint64): uint64 =
|
||||||
result = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number div EPOCH_LENGTH)
|
result = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number div EPOCH_LENGTH)
|
||||||
result -= HASH_BYTES
|
result -= HASH_BYTES
|
||||||
while (let dm = intmath.divmod(result, HASH_BYTES);
|
while (let dm = intmath.divmod(result, HASH_BYTES);
|
||||||
|
@ -37,7 +37,7 @@ proc get_cache_size*(block_number: uint64): uint64 {.noSideEffect.}=
|
||||||
# means checking that remainder == 0 and quotient is prime
|
# means checking that remainder == 0 and quotient is prime
|
||||||
result -= 2 * HASH_BYTES
|
result -= 2 * HASH_BYTES
|
||||||
|
|
||||||
proc get_data_size*(block_number: uint64): uint64 {.noSideEffect.}=
|
func get_data_size*(block_number: uint64): uint64 =
|
||||||
result = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number div EPOCH_LENGTH)
|
result = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number div EPOCH_LENGTH)
|
||||||
result -= MIX_BYTES
|
result -= MIX_BYTES
|
||||||
while (let dm = intmath.divmod(result, MIX_BYTES);
|
while (let dm = intmath.divmod(result, MIX_BYTES);
|
||||||
|
@ -48,16 +48,16 @@ proc get_data_size*(block_number: uint64): uint64 {.noSideEffect.}=
|
||||||
# Fetch from lookup tables of 2048 epochs of data sizes and cache sizes
|
# Fetch from lookup tables of 2048 epochs of data sizes and cache sizes
|
||||||
import ./data_sizes
|
import ./data_sizes
|
||||||
|
|
||||||
proc get_datasize_lut*(block_number: Natural): uint64 {.noSideEffect, inline.} =
|
func get_datasize_lut*(block_number: Natural): uint64 {.inline.} =
|
||||||
data_sizes[block_number div EPOCH_LENGTH]
|
data_sizes[block_number div EPOCH_LENGTH]
|
||||||
|
|
||||||
proc get_cachesize_lut*(block_number: Natural): uint64 {.noSideEffect, inline.} =
|
func get_cachesize_lut*(block_number: Natural): uint64 {.inline.} =
|
||||||
cache_sizes[block_number div EPOCH_LENGTH]
|
cache_sizes[block_number div EPOCH_LENGTH]
|
||||||
|
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Cache generation
|
# Cache generation
|
||||||
|
|
||||||
proc mkcache*(cache_size: uint64, seed: MDigest[256]): seq[MDigest[512]] {.noSideEffect.}=
|
func mkcache*(cache_size: uint64, seed: MDigest[256]): seq[MDigest[512]] =
|
||||||
|
|
||||||
# Cache size
|
# Cache size
|
||||||
let n = int(cache_size div HASH_BYTES)
|
let n = int(cache_size div HASH_BYTES)
|
||||||
|
@ -83,7 +83,7 @@ proc mkcache*(cache_size: uint64, seed: MDigest[256]): seq[MDigest[512]] {.noSid
|
||||||
|
|
||||||
const FNV_PRIME = 0x01000193
|
const FNV_PRIME = 0x01000193
|
||||||
|
|
||||||
proc fnv*[T: SomeUnsignedInt or Natural](v1, v2: T): uint32 {.inline, noSideEffect.}=
|
func fnv*[T: SomeUnsignedInt or Natural](v1, v2: T): uint32 {.inline.}=
|
||||||
|
|
||||||
# Original formula is ((v1 * FNV_PRIME) xor v2) mod 2^32
|
# Original formula is ((v1 * FNV_PRIME) xor v2) mod 2^32
|
||||||
# However contrary to Python and depending on the type T,
|
# However contrary to Python and depending on the type T,
|
||||||
|
@ -104,7 +104,7 @@ proc fnv*[T: SomeUnsignedInt or Natural](v1, v2: T): uint32 {.inline, noSideEffe
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Full dataset calculation
|
# Full dataset calculation
|
||||||
|
|
||||||
proc calc_dataset_item*(cache: seq[MDigest[512]], i: Natural): MDigest[512] {.noSideEffect, noInit.} =
|
func calc_dataset_item*(cache: seq[MDigest[512]], i: Natural): MDigest[512] {.noinit.} =
|
||||||
let n = cache.len
|
let n = cache.len
|
||||||
const r: uint32 = HASH_BYTES div WORD_BYTES
|
const r: uint32 = HASH_BYTES div WORD_BYTES
|
||||||
|
|
||||||
|
@ -161,14 +161,14 @@ template hashimoto(header: MDigest[256],
|
||||||
|
|
||||||
# combine header+nonce into a 64 byte seed
|
# combine header+nonce into a 64 byte seed
|
||||||
{.pragma: align64, codegenDecl: "$# $# __attribute__((aligned(64)))".}
|
{.pragma: align64, codegenDecl: "$# $# __attribute__((aligned(64)))".}
|
||||||
var s{.align64, noInit.}: MDigest[512]
|
var s{.align64, noinit.}: MDigest[512]
|
||||||
let s_bytes = cast[ptr array[64, byte]](addr s) # Alias to interpret s as a byte array
|
let s_bytes = cast[ptr array[64, byte]](addr s) # Alias to interpret s as a byte array
|
||||||
let s_words = cast[ptr array[16, uint32]](addr s) # Alias to interpret s as an uint32 array
|
let s_words = cast[ptr array[16, uint32]](addr s) # Alias to interpret s as an uint32 array
|
||||||
|
|
||||||
s_bytes[][0..<32] = header.data # We first populate the first 40 bytes of s with the concatenation
|
s_bytes[][0..<32] = header.data # We first populate the first 40 bytes of s with the concatenation
|
||||||
# In template we need to dereference first otherwise it's not considered as var
|
# In template we need to dereference first otherwise it's not considered as var
|
||||||
|
|
||||||
var nonceLE{.noInit.}: array[8, byte] # the nonce should be concatenated with its LITTLE ENDIAN representation
|
var nonceLE{.noinit.}: array[8, byte] # the nonce should be concatenated with its LITTLE ENDIAN representation
|
||||||
littleEndian64(addr nonceLE, unsafeAddr nonce)
|
littleEndian64(addr nonceLE, unsafeAddr nonce)
|
||||||
s_bytes[][32..<40] = nonceLE
|
s_bytes[][32..<40] = nonceLE
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ template hashimoto(header: MDigest[256],
|
||||||
|
|
||||||
# start the mix with replicated s
|
# start the mix with replicated s
|
||||||
assert MIX_BYTES div HASH_BYTES == 2
|
assert MIX_BYTES div HASH_BYTES == 2
|
||||||
var mix{.align64, noInit.}: array[32, uint32]
|
var mix{.align64, noinit.}: array[32, uint32]
|
||||||
mix[0..<16] = s_words[]
|
mix[0..<16] = s_words[]
|
||||||
mix[16..<32] = s_words[]
|
mix[16..<32] = s_words[]
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ template hashimoto(header: MDigest[256],
|
||||||
let p1{.inject.} = p + 1
|
let p1{.inject.} = p + 1
|
||||||
|
|
||||||
# Unrolled: for j in range(MIX_BYTES / HASH_BYTES): => for j in 0 ..< 2
|
# Unrolled: for j in range(MIX_BYTES / HASH_BYTES): => for j in 0 ..< 2
|
||||||
var newdata{.noInit.}: type mix
|
var newdata{.noinit.}: type mix
|
||||||
newdata[0..<16] = cast[array[16, uint32]](dataset_lookup_p)
|
newdata[0..<16] = cast[array[16, uint32]](dataset_lookup_p)
|
||||||
newdata[16..<32] = cast[array[16, uint32]](dataset_lookup_p1)
|
newdata[16..<32] = cast[array[16, uint32]](dataset_lookup_p1)
|
||||||
|
|
||||||
|
@ -200,23 +200,23 @@ template hashimoto(header: MDigest[256],
|
||||||
for i in countup(0, mix.len - 1, 4):
|
for i in countup(0, mix.len - 1, 4):
|
||||||
cmix[i div 4] = mix[i].fnv(mix[i+1]).fnv(mix[i+2]).fnv(mix[i+3])
|
cmix[i div 4] = mix[i].fnv(mix[i+1]).fnv(mix[i+2]).fnv(mix[i+3])
|
||||||
|
|
||||||
var concat{.noInit.}: array[64 + 32, byte]
|
var concat{.noinit.}: array[64 + 32, byte]
|
||||||
concat[0..<64] = s_bytes[]
|
concat[0..<64] = s_bytes[]
|
||||||
concat[64..<96] = cast[array[32, byte]](result.mix_digest)
|
concat[64..<96] = cast[array[32, byte]](result.mix_digest)
|
||||||
result.value = keccak_256.digest concat
|
result.value = keccak_256.digest concat
|
||||||
|
|
||||||
proc hashimoto_light*(full_size:Natural, cache: seq[MDigest[512]],
|
func hashimoto_light*(full_size:Natural, cache: seq[MDigest[512]],
|
||||||
header: MDigest[256], nonce: uint64): HashimotoHash {.noSideEffect.} =
|
header: MDigest[256], nonce: uint64): HashimotoHash =
|
||||||
|
|
||||||
hashimoto(header,
|
hashimoto(header,
|
||||||
nonce,
|
nonce,
|
||||||
full_size,
|
full_size,
|
||||||
calc_data_set_item(cache, p),
|
calc_dataset_item(cache, p),
|
||||||
calc_data_set_item(cache, p1),
|
calc_dataset_item(cache, p1),
|
||||||
result)
|
result)
|
||||||
|
|
||||||
proc hashimoto_full*(full_size:Natural, dataset: seq[MDigest[512]],
|
func hashimoto_full*(full_size:Natural, dataset: seq[MDigest[512]],
|
||||||
header: MDigest[256], nonce: uint64): HashimotoHash {.noSideEffect.} =
|
header: MDigest[256], nonce: uint64): HashimotoHash =
|
||||||
# TODO spec mentions full_size but I don't think we need it (retrieve it from dataset.len)
|
# TODO spec mentions full_size but I don't think we need it (retrieve it from dataset.len)
|
||||||
hashimoto(header,
|
hashimoto(header,
|
||||||
nonce,
|
nonce,
|
||||||
|
@ -227,6 +227,6 @@ proc hashimoto_full*(full_size:Natural, dataset: seq[MDigest[512]],
|
||||||
# ###############################################################################
|
# ###############################################################################
|
||||||
# Defining the seed hash
|
# Defining the seed hash
|
||||||
|
|
||||||
proc get_seedhash*(block_number: uint64): MDigest[256] {.noSideEffect.} =
|
func get_seedhash*(block_number: uint64): MDigest[256] =
|
||||||
for i in 0 ..< int(block_number div EPOCH_LENGTH):
|
for i in 0 ..< int(block_number div EPOCH_LENGTH):
|
||||||
result = keccak256.digest result.data
|
result = keccak256.digest result.data
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
import ../src/ethash, unittest, times, strutils, nimcrypto
|
import ../src/ethash, unittest, times, strutils, nimcrypto
|
||||||
|
@ -11,12 +11,12 @@ suite "Test mining":
|
||||||
# POC-9 testnet, epoch 0
|
# POC-9 testnet, epoch 0
|
||||||
let
|
let
|
||||||
blck = 22'u # block number
|
blck = 22'u # block number
|
||||||
cache = mkcache(get_cachesize(blck), get_seedhash(blck))
|
cache = mkcache(get_cache_size(blck), get_seedhash(blck))
|
||||||
header = cast[MDigest[256]](
|
header = cast[MDigest[256]](
|
||||||
hexToByteArrayBE[32]("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d")
|
hexToByteArrayBE[32]("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d")
|
||||||
)
|
)
|
||||||
difficulty = 132416'u64
|
difficulty = 132416'u64
|
||||||
full_size = get_datasize(blck)
|
full_size = get_data_size(blck)
|
||||||
|
|
||||||
echo "\nGenerating dataset"
|
echo "\nGenerating dataset"
|
||||||
var start = epochTime()
|
var start = epochTime()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
# Distributed under the Apache v2 License (license terms are at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
import ../src/ethash, unittest, strutils, algorithm, random, sequtils, nimcrypto
|
import ../src/ethash, unittest, strutils, algorithm, random, sequtils, nimcrypto
|
||||||
|
@ -43,8 +43,8 @@ suite "Endianness (not implemented)":
|
||||||
suite "Genesis parameters":
|
suite "Genesis parameters":
|
||||||
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/test/c/test.cpp#L155-L180
|
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/test/c/test.cpp#L155-L180
|
||||||
let
|
let
|
||||||
full_size = get_datasize(0)
|
full_size = get_data_size(0)
|
||||||
cache_size = get_cachesize(0)
|
cache_size = get_cache_size(0)
|
||||||
|
|
||||||
test "Full dataset size should be less or equal DATASET_BYTES_INIT":
|
test "Full dataset size should be less or equal DATASET_BYTES_INIT":
|
||||||
check: full_size <= DATASET_BYTES_INIT
|
check: full_size <= DATASET_BYTES_INIT
|
||||||
|
@ -79,19 +79,19 @@ suite "Epoch change":
|
||||||
check: get_cache_size(EPOCH_LENGTH * 2048 - 1) == 285081536'u
|
check: get_cache_size(EPOCH_LENGTH * 2048 - 1) == 285081536'u
|
||||||
|
|
||||||
test "Full dataset size at the change of epochs - Look-up tables":
|
test "Full dataset size at the change of epochs - Look-up tables":
|
||||||
check: get_data_size_lut(EPOCH_LENGTH - 1) == 1073739904'u
|
check: get_datasize_lut(EPOCH_LENGTH - 1) == 1073739904'u
|
||||||
check: get_data_size_lut(EPOCH_LENGTH) == 1082130304'u
|
check: get_datasize_lut(EPOCH_LENGTH) == 1082130304'u
|
||||||
check: get_data_size_lut(EPOCH_LENGTH + 1) == 1082130304'u
|
check: get_datasize_lut(EPOCH_LENGTH + 1) == 1082130304'u
|
||||||
check: get_data_size_lut(EPOCH_LENGTH * 2046) == 18236833408'u
|
check: get_datasize_lut(EPOCH_LENGTH * 2046) == 18236833408'u
|
||||||
check: get_data_size_lut(EPOCH_LENGTH * 2047) == 18245220736'u
|
check: get_datasize_lut(EPOCH_LENGTH * 2047) == 18245220736'u
|
||||||
|
|
||||||
test "Cache size at the change of epochs - Look-up tables":
|
test "Cache size at the change of epochs - Look-up tables":
|
||||||
check: get_cache_size_lut(EPOCH_LENGTH - 1) == 16776896'u
|
check: get_cachesize_lut(EPOCH_LENGTH - 1) == 16776896'u
|
||||||
check: get_cache_size_lut(EPOCH_LENGTH) == 16907456'u
|
check: get_cachesize_lut(EPOCH_LENGTH) == 16907456'u
|
||||||
check: get_cache_size_lut(EPOCH_LENGTH + 1) == 16907456'u
|
check: get_cachesize_lut(EPOCH_LENGTH + 1) == 16907456'u
|
||||||
check: get_cache_size_lut(EPOCH_LENGTH * 2046) == 284950208'u
|
check: get_cachesize_lut(EPOCH_LENGTH * 2046) == 284950208'u
|
||||||
check: get_cache_size_lut(EPOCH_LENGTH * 2047) == 285081536'u
|
check: get_cachesize_lut(EPOCH_LENGTH * 2047) == 285081536'u
|
||||||
check: get_cache_size_lut(EPOCH_LENGTH * 2048 - 1) == 285081536'u
|
check: get_cachesize_lut(EPOCH_LENGTH * 2048 - 1) == 285081536'u
|
||||||
|
|
||||||
test "Random testing of full size":
|
test "Random testing of full size":
|
||||||
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/test/python/test_pyethash.py#L23-L28
|
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/test/python/test_pyethash.py#L23-L28
|
||||||
|
@ -191,13 +191,13 @@ suite "Real blocks test":
|
||||||
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/test/c/test.cpp#L603-L617
|
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/test/c/test.cpp#L603-L617
|
||||||
# POC-9 testnet, epoch 0
|
# POC-9 testnet, epoch 0
|
||||||
let blck = 22'u # block number
|
let blck = 22'u # block number
|
||||||
let cache = mkcache(get_cachesize(blck), get_seedhash(blck))
|
let cache = mkcache(get_cache_size(blck), get_seedhash(blck))
|
||||||
let header = cast[MDigest[256]](
|
let header = cast[MDigest[256]](
|
||||||
hexToByteArrayBE[32]("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d")
|
hexToByteArrayBE[32]("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d")
|
||||||
)
|
)
|
||||||
|
|
||||||
let light = hashimoto_light(
|
let light = hashimoto_light(
|
||||||
get_datasize(blck),
|
get_data_size(blck),
|
||||||
cache,
|
cache,
|
||||||
header,
|
header,
|
||||||
0x495732e0ed7a801c'u
|
0x495732e0ed7a801c'u
|
||||||
|
@ -206,7 +206,7 @@ suite "Real blocks test":
|
||||||
check: light.value == cast[MDigest[256]](
|
check: light.value == cast[MDigest[256]](
|
||||||
hexToByteArrayBE[32]("00000b184f1fdd88bfd94c86c39e65db0c36144d5e43f745f722196e730cb614")
|
hexToByteArrayBE[32]("00000b184f1fdd88bfd94c86c39e65db0c36144d5e43f745f722196e730cb614")
|
||||||
)
|
)
|
||||||
check: light.mixDigest == cast[MDigest[256]](
|
check: light.mix_digest == cast[MDigest[256]](
|
||||||
hexToByteArrayBE[32]("2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5")
|
hexToByteArrayBE[32]("2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -214,19 +214,19 @@ suite "Real blocks test":
|
||||||
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/ethash_test.go#L63-L69
|
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/ethash_test.go#L63-L69
|
||||||
# POC-9 testnet, epoch 1
|
# POC-9 testnet, epoch 1
|
||||||
let blck = 30001'u # block number
|
let blck = 30001'u # block number
|
||||||
let cache = mkcache(get_cachesize(blck), get_seedhash(blck))
|
let cache = mkcache(get_cache_size(blck), get_seedhash(blck))
|
||||||
let header = cast[MDigest[256]](
|
let header = cast[MDigest[256]](
|
||||||
hexToByteArrayBE[32]("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34")
|
hexToByteArrayBE[32]("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34")
|
||||||
)
|
)
|
||||||
|
|
||||||
let light = hashimoto_light(
|
let light = hashimoto_light(
|
||||||
get_datasize(blck),
|
get_data_size(blck),
|
||||||
cache,
|
cache,
|
||||||
header,
|
header,
|
||||||
0x318df1c8adef7e5e'u
|
0x318df1c8adef7e5e'u
|
||||||
)
|
)
|
||||||
|
|
||||||
check: light.mixDigest == cast[MDigest[256]](
|
check: light.mix_digest == cast[MDigest[256]](
|
||||||
hexToByteArrayBE[32]("144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84")
|
hexToByteArrayBE[32]("144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -234,18 +234,18 @@ suite "Real blocks test":
|
||||||
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/ethash_test.go#L70-L78
|
# https://github.com/ethereum/ethash/blob/f5f0a8b1962544d2b6f40df8e4b0d9a32faf8f8e/ethash_test.go#L70-L78
|
||||||
# POC-9 testnet, epoch 2
|
# POC-9 testnet, epoch 2
|
||||||
let blck = 60000'u # block number
|
let blck = 60000'u # block number
|
||||||
let cache = mkcache(get_cachesize(blck), get_seedhash(blck))
|
let cache = mkcache(get_cache_size(blck), get_seedhash(blck))
|
||||||
let header = cast[MDigest[256]](
|
let header = cast[MDigest[256]](
|
||||||
hexToByteArrayBE[32]("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0")
|
hexToByteArrayBE[32]("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0")
|
||||||
)
|
)
|
||||||
|
|
||||||
let light = hashimoto_light(
|
let light = hashimoto_light(
|
||||||
get_datasize(blck),
|
get_data_size(blck),
|
||||||
cache,
|
cache,
|
||||||
header,
|
header,
|
||||||
0x50377003e5d830ca'u
|
0x50377003e5d830ca'u
|
||||||
)
|
)
|
||||||
|
|
||||||
check: light.mixDigest == cast[MDigest[256]](
|
check: light.mix_digest == cast[MDigest[256]](
|
||||||
hexToByteArrayBE[32]("ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063")
|
hexToByteArrayBE[32]("ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063")
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue