154 lines
4.6 KiB
Nim
154 lines
4.6 KiB
Nim
|
# Nimbus - Types, data structures and shared utilities used in network sync
|
||
|
#
|
||
|
# Copyright (c) 2018-2021 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/[math, hashes],
|
||
|
eth/common/eth_types,
|
||
|
nimcrypto/keccak,
|
||
|
stew/[byteutils, interval_set],
|
||
|
stint,
|
||
|
../../constants,
|
||
|
../types
|
||
|
|
||
|
{.push raises: [Defect].}
|
||
|
|
||
|
type
|
||
|
NodeTag* = ##\
|
||
|
## Trie leaf item, account hash etc.
|
||
|
distinct UInt256
|
||
|
|
||
|
LeafRange* = ##\
|
||
|
## Interval `[minPt,maxPt]` of` NodeTag` elements, can be managed in an
|
||
|
## `IntervalSet` data type.
|
||
|
Interval[NodeTag,UInt256]
|
||
|
|
||
|
LeafRangeSet* = ##\
|
||
|
## Managed structure to handle non-adjacent `LeafRange` intervals
|
||
|
IntervalSetRef[NodeTag,UInt256]
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Public helpers
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
proc to*(nid: NodeTag; T: type Hash256): T =
|
||
|
## Convert to serialised equivalent
|
||
|
result.data = nid.UInt256.toBytesBE
|
||
|
|
||
|
proc to*(nid: NodeTag; T: type NodeHash): T =
|
||
|
## Syntactic sugar
|
||
|
nid.to(Hash256).T
|
||
|
|
||
|
proc to*(h: Hash256; T: type NodeTag): T =
|
||
|
## Convert from serialised equivalent
|
||
|
UInt256.fromBytesBE(h.data).T
|
||
|
|
||
|
proc to*(nh: NodeHash; T: type NodeTag): T =
|
||
|
## Syntactic sugar
|
||
|
nh.Hash256.to(T)
|
||
|
|
||
|
proc to*(n: SomeUnsignedInt|UInt256; T: type NodeTag): T =
|
||
|
## Syntactic sugar
|
||
|
n.u256.T
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Public constructors
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
proc init*(nh: var NodeHash; data: openArray[byte]): bool =
|
||
|
## Import argument `data` into `nh` which must have length either `32` or `0`.
|
||
|
## The latter case is equivalent to an all zero byte array of size `32`.
|
||
|
if data.len == 32:
|
||
|
for n in 0 ..< 32:
|
||
|
nh.Hash256.data[n] = data[n]
|
||
|
return true
|
||
|
elif data.len == 0:
|
||
|
nh.reset
|
||
|
return true
|
||
|
|
||
|
proc init*(nt: var NodeTag; data: openArray[byte]): bool =
|
||
|
## Similar to `init(nh: var NodeHash; .)`.
|
||
|
var h: NodeHash
|
||
|
if h.init(data):
|
||
|
nt = h.to(NodeTag)
|
||
|
return true
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Public rlp support
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
proc read*(rlp: var Rlp, T: type NodeTag): T
|
||
|
{.gcsafe, raises: [Defect,RlpError]} =
|
||
|
rlp.read(Hash256).to(T)
|
||
|
|
||
|
proc append*(writer: var RlpWriter, nid: NodeTag) =
|
||
|
writer.append(nid.to(Hash256))
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Public `NodeTag` and `LeafRange` functions
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
proc u256*(lp: NodeTag): UInt256 = lp.UInt256
|
||
|
proc low*(T: type NodeTag): T = low(UInt256).T
|
||
|
proc high*(T: type NodeTag): T = high(UInt256).T
|
||
|
|
||
|
proc `+`*(a: NodeTag; b: UInt256): NodeTag = (a.u256+b).NodeTag
|
||
|
proc `-`*(a: NodeTag; b: UInt256): NodeTag = (a.u256-b).NodeTag
|
||
|
proc `-`*(a, b: NodeTag): UInt256 = (a.u256 - b.u256)
|
||
|
|
||
|
proc `==`*(a, b: NodeTag): bool = a.u256 == b.u256
|
||
|
proc `<=`*(a, b: NodeTag): bool = a.u256 <= b.u256
|
||
|
proc `<`*(a, b: NodeTag): bool = a.u256 < b.u256
|
||
|
|
||
|
proc hash*(a: NodeTag): Hash =
|
||
|
## Mixin for `Table` or `keyedQueue`
|
||
|
a.to(Hash256).data.hash
|
||
|
|
||
|
proc digestTo*(data: Blob; T: type NodeTag): T =
|
||
|
## Hash the `data` argument
|
||
|
keccak256.digest(data).to(T)
|
||
|
|
||
|
proc freeFactor*(lrs: LeafRangeSet): float =
|
||
|
## Free factor, ie. `#items-free / 2^256` to be used in statistics
|
||
|
if 0 < lrs.total:
|
||
|
((high(NodeTag) - lrs.total).u256 + 1).to(float) / (2.0^256)
|
||
|
elif lrs.chunks == 0:
|
||
|
1.0
|
||
|
else:
|
||
|
0.0
|
||
|
|
||
|
# Printing & pretty printing
|
||
|
proc `$`*(nt: NodeTag): string =
|
||
|
if nt == high(NodeTag):
|
||
|
"high(NodeTag)"
|
||
|
elif nt == 0.u256.NodeTag:
|
||
|
"0"
|
||
|
else:
|
||
|
nt.to(Hash256).data.toHex
|
||
|
|
||
|
proc leafRangePp*(a, b: NodeTag): string =
|
||
|
## Needed for macro generated DSL files like `snap.nim` because the
|
||
|
## `distinct` flavour of `NodeTag` is discarded there.
|
||
|
result = "[" & $a
|
||
|
if a != b:
|
||
|
result &= ',' & $b
|
||
|
result &= "]"
|
||
|
|
||
|
proc `$`*(a, b: NodeTag): string =
|
||
|
## Prettyfied prototype
|
||
|
leafRangePp(a,b)
|
||
|
|
||
|
proc `$`*(iv: LeafRange): string =
|
||
|
leafRangePp(iv.minPt, iv.maxPt)
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# End
|
||
|
# ------------------------------------------------------------------------------
|