mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-20 02:08:12 +00:00
allow non-power-of-2 limits in hashlist
fixes "make eth2_network_simulation" a bit sad: no test coverage except against our own tests
This commit is contained in:
parent
3cb7896bab
commit
68b5638da4
@ -21,6 +21,9 @@ import
|
|||||||
export
|
export
|
||||||
spec_types, types
|
spec_types, types
|
||||||
|
|
||||||
|
when hasSerializationTracing:
|
||||||
|
import stew/byteutils, typetraits
|
||||||
|
|
||||||
const
|
const
|
||||||
zero64 = default array[64, byte]
|
zero64 = default array[64, byte]
|
||||||
bitsPerChunk = bytesPerChunk * 8
|
bitsPerChunk = bytesPerChunk * 8
|
||||||
@ -375,7 +378,6 @@ func mergedDataHash(x: HashList|HashArray, chunkIdx: int64): Eth2Digest =
|
|||||||
|
|
||||||
template mergedHash(x: HashList|HashArray, vIdxParam: int64): Eth2Digest =
|
template mergedHash(x: HashList|HashArray, vIdxParam: int64): Eth2Digest =
|
||||||
# The merged hash of the data at `vIdx` and `vIdx + 1`
|
# The merged hash of the data at `vIdx` and `vIdx + 1`
|
||||||
|
|
||||||
let vIdx = vIdxParam
|
let vIdx = vIdxParam
|
||||||
if vIdx >= x.maxChunks:
|
if vIdx >= x.maxChunks:
|
||||||
let dataIdx = vIdx - x.maxChunks
|
let dataIdx = vIdx - x.maxChunks
|
||||||
@ -393,8 +395,9 @@ func hashTreeRootCached*(x: HashList, vIdx: int64): Eth2Digest =
|
|||||||
idxInLayer = vIdx - (1'i64 shl layer)
|
idxInLayer = vIdx - (1'i64 shl layer)
|
||||||
layerIdx = idxInlayer + x.indices[layer]
|
layerIdx = idxInlayer + x.indices[layer]
|
||||||
|
|
||||||
doAssert layer < x.maxDepth
|
|
||||||
trs "GETTING ", vIdx, " ", layerIdx, " ", layer, " ", x.indices.len
|
trs "GETTING ", vIdx, " ", layerIdx, " ", layer, " ", x.indices.len
|
||||||
|
|
||||||
|
doAssert layer < x.maxDepth
|
||||||
if layerIdx >= x.indices[layer + 1]:
|
if layerIdx >= x.indices[layer + 1]:
|
||||||
trs "ZERO ", x.indices[layer], " ", x.indices[layer + 1]
|
trs "ZERO ", x.indices[layer], " ", x.indices[layer + 1]
|
||||||
zeroHashes[x.maxDepth - layer]
|
zeroHashes[x.maxDepth - layer]
|
||||||
|
@ -25,6 +25,25 @@ type
|
|||||||
# * vIdx - virtual index in merkle tree - the root is found at index 1, its
|
# * vIdx - virtual index in merkle tree - the root is found at index 1, its
|
||||||
# two children at 2, 3 then 4, 5, 6, 7 etc
|
# two children at 2, 3 then 4, 5, 6, 7 etc
|
||||||
|
|
||||||
|
func nextPow2Int64(x: int64): int64 =
|
||||||
|
# TODO the nextPow2 in bitops2 works with uint64 - there's a bug in the nim
|
||||||
|
# compiler preventing it to be used - it seems that a conversion to
|
||||||
|
# uint64 cannot be done with the static maxLen :(
|
||||||
|
var v = x - 1
|
||||||
|
|
||||||
|
# round down, make sure all bits are 1 below the threshold, then add 1
|
||||||
|
v = v or v shr 1
|
||||||
|
v = v or v shr 2
|
||||||
|
v = v or v shr 4
|
||||||
|
when bitsof(x) > 8:
|
||||||
|
v = v or v shr 8
|
||||||
|
when bitsof(x) > 16:
|
||||||
|
v = v or v shr 16
|
||||||
|
when bitsof(x) > 32:
|
||||||
|
v = v or v shr 32
|
||||||
|
|
||||||
|
v + 1
|
||||||
|
|
||||||
template dataPerChunk(T: type): int =
|
template dataPerChunk(T: type): int =
|
||||||
# How many data items fit in a chunk
|
# How many data items fit in a chunk
|
||||||
when T is BasicType:
|
when T is BasicType:
|
||||||
@ -38,7 +57,10 @@ template chunkIdx*(T: type, dataIdx: int64): int64 =
|
|||||||
|
|
||||||
template maxChunkIdx*(T: type, maxLen: int64): int64 =
|
template maxChunkIdx*(T: type, maxLen: int64): int64 =
|
||||||
# Given a number of data items, how many chunks are needed?
|
# Given a number of data items, how many chunks are needed?
|
||||||
chunkIdx(T, maxLen + dataPerChunk(T) - 1)
|
# TODO compiler bug:
|
||||||
|
# beacon_chain/ssz/types.nim(75, 53) Error: cannot generate code for: maxLen
|
||||||
|
# nextPow2(chunkIdx(T, maxLen + dataPerChunk(T) - 1).uint64).int64
|
||||||
|
nextPow2Int64(chunkIdx(T, maxLen + dataPerChunk(T) - 1))
|
||||||
|
|
||||||
template layer*(vIdx: int64): int =
|
template layer*(vIdx: int64): int =
|
||||||
## Layer 0 = layer at which the root hash is
|
## Layer 0 = layer at which the root hash is
|
||||||
@ -57,7 +79,7 @@ type
|
|||||||
HashList*[T; maxLen: static Limit] = object
|
HashList*[T; maxLen: static Limit] = object
|
||||||
data*: List[T, maxLen]
|
data*: List[T, maxLen]
|
||||||
hashes* {.dontSerialize.}: seq[Eth2Digest]
|
hashes* {.dontSerialize.}: seq[Eth2Digest]
|
||||||
indices* {.dontSerialize.}: array[layer(maxChunkIdx(T, maxLen)) + 1, int64]
|
indices* {.dontSerialize.}: array[int(layer(maxChunkIdx(T, maxLen))) + 1, int64]
|
||||||
|
|
||||||
# Note for readers:
|
# Note for readers:
|
||||||
# We use `array` for `Vector` and
|
# We use `array` for `Vector` and
|
||||||
@ -130,11 +152,11 @@ template clearCache*(v: var Eth2Digest) =
|
|||||||
|
|
||||||
template maxChunks*(a: HashList|HashArray): int64 =
|
template maxChunks*(a: HashList|HashArray): int64 =
|
||||||
## Layer where data is
|
## Layer where data is
|
||||||
chunkIdx(a.T, a.maxLen)
|
maxChunkIdx(a.T, a.maxLen)
|
||||||
|
|
||||||
template maxDepth*(a: HashList|HashArray): int =
|
template maxDepth*(a: HashList|HashArray): int =
|
||||||
## Layer where data is
|
## Layer where data is
|
||||||
layer(a.maxChunks)
|
layer(nextPow2(a.maxChunks.uint64).int64)
|
||||||
|
|
||||||
template chunkIdx(a: HashList|HashArray, dataIdx: int64): int64 =
|
template chunkIdx(a: HashList|HashArray, dataIdx: int64): int64 =
|
||||||
chunkIdx(a.T, dataIdx)
|
chunkIdx(a.T, dataIdx)
|
||||||
|
@ -10,7 +10,7 @@ import
|
|||||||
os, tables, strutils,
|
os, tables, strutils,
|
||||||
|
|
||||||
# Nimble packages
|
# Nimble packages
|
||||||
stew/[objects], stew/shims/macros,
|
stew/[byteutils, objects], stew/shims/macros,
|
||||||
chronos, metrics, json_rpc/[rpcserver, jsonmarshal],
|
chronos, metrics, json_rpc/[rpcserver, jsonmarshal],
|
||||||
chronicles,
|
chronicles,
|
||||||
json_serialization/std/[options, sets, net], serialization/errors,
|
json_serialization/std/[options, sets, net], serialization/errors,
|
||||||
@ -215,8 +215,10 @@ proc proposeBlock(node: BeaconNode,
|
|||||||
cat = "fastforward"
|
cat = "fastforward"
|
||||||
return head
|
return head
|
||||||
|
|
||||||
|
var graffiti: Eth2Digest
|
||||||
|
graffiti.data[0..<5] = toBytes("quack")
|
||||||
let valInfo = ValidatorInfoForMakeBeaconBlock(kind: viValidator, validator: validator)
|
let valInfo = ValidatorInfoForMakeBeaconBlock(kind: viValidator, validator: validator)
|
||||||
let beaconBlockTuple = makeBeaconBlockForHeadAndSlot(node, valInfo, validator_index, Eth2Digest(), head, slot)
|
let beaconBlockTuple = makeBeaconBlockForHeadAndSlot(node, valInfo, validator_index, graffiti, head, slot)
|
||||||
|
|
||||||
if not beaconBlockTuple.message.isSome():
|
if not beaconBlockTuple.message.isSome():
|
||||||
return head # already logged elsewhere!
|
return head # already logged elsewhere!
|
||||||
|
@ -127,6 +127,13 @@ suiteReport "SSZ navigator":
|
|||||||
leaves2.add c
|
leaves2.add c
|
||||||
check hash_tree_root(leaves2) == hash_tree_root(leaves2.data)
|
check hash_tree_root(leaves2) == hash_tree_root(leaves2.data)
|
||||||
|
|
||||||
|
var leaves3 = HashList[Eth2Digest, 7]() # Non-power-of-2
|
||||||
|
check hash_tree_root(leaves3) == hash_tree_root(leaves3.data)
|
||||||
|
leaves3.add a
|
||||||
|
leaves3.add b
|
||||||
|
leaves3.add c
|
||||||
|
check hash_tree_root(leaves3) == hash_tree_root(leaves3.data)
|
||||||
|
|
||||||
timedTest "basictype":
|
timedTest "basictype":
|
||||||
var leaves = HashList[uint64, 1'i64 shl 3]()
|
var leaves = HashList[uint64, 1'i64 shl 3]()
|
||||||
while leaves.len < leaves.maxLen:
|
while leaves.len < leaves.maxLen:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user