309 lines
8.6 KiB
Nim
309 lines
8.6 KiB
Nim
# nimbus-eth1
|
|
# Copyright (c) 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.
|
|
|
|
{.push raises: [].}
|
|
|
|
import
|
|
std/[algorithm, sets, sequtils, strutils, tables],
|
|
eth/[common, trie/nibbles],
|
|
stew/byteutils,
|
|
../../sync/snap/range_desc,
|
|
"."/[aristo_constants, aristo_desc, aristo_error, aristo_hike, aristo_vid]
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Ptivate functions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc toPfx(indent: int): string =
|
|
"\n" & " ".repeat(indent)
|
|
|
|
proc keyVidUpdate(db: AristoDbRef, key: NodeKey, vid: VertexID): string =
|
|
if not key.isZero and
|
|
not vid.isZero and
|
|
not db.isNil:
|
|
db.pAmk.withValue(key, vidRef):
|
|
if vidRef[] != vid:
|
|
result = "(!)"
|
|
return
|
|
db.xMap.withValue(key, vidRef):
|
|
if vidRef[] == vid:
|
|
result = "(!)"
|
|
return
|
|
db.xMap[key] = vid
|
|
|
|
proc squeeze(s: string; hex = false; ignLen = false): string =
|
|
## For long strings print `begin..end` only
|
|
if hex:
|
|
let n = (s.len + 1) div 2
|
|
result = if s.len < 20: s else: s[0 .. 5] & ".." & s[s.len-8 .. s.len-1]
|
|
if not ignLen:
|
|
result &= "[" & (if 0 < n: "#" & $n else: "") & "]"
|
|
elif s.len <= 30:
|
|
result = s
|
|
else:
|
|
result = if (s.len and 1) == 0: s[0 ..< 8] else: "0" & s[0 ..< 7]
|
|
if not ignLen:
|
|
result &= "..(" & $s.len & ")"
|
|
result &= ".." & s[s.len-16 ..< s.len]
|
|
|
|
proc stripZeros(a: string): string =
|
|
for n in 0 ..< a.len:
|
|
if a[n] != '0':
|
|
return a[n .. ^1]
|
|
return a
|
|
|
|
proc ppVid(vid: VertexID): string =
|
|
if vid.isZero: "ø" else: "$" & vid.uint64.toHex.stripZeros.toLowerAscii
|
|
|
|
proc ppKey(key: NodeKey, db = AristoDbRef(nil)): string =
|
|
if key.isZero:
|
|
return "ø"
|
|
if key == EMPTY_ROOT_KEY:
|
|
return "£r"
|
|
if key == EMPTY_CODE_KEY:
|
|
return "£c"
|
|
|
|
if not db.isNil:
|
|
db.pAmk.withValue(key, pRef):
|
|
return "£" & pRef[].uint64.toHex.stripZeros.toLowerAscii
|
|
db.xMap.withValue(key, xRef):
|
|
return "£" & xRef[].uint64.toHex.stripZeros.toLowerAscii
|
|
|
|
"%" & key.ByteArray32
|
|
.mapIt(it.toHex(2)).join.tolowerAscii
|
|
.squeeze(hex=true,ignLen=true)
|
|
|
|
proc ppRootKey(a: NodeKey, db = AristoDbRef(nil)): string =
|
|
if a != EMPTY_ROOT_KEY:
|
|
return a.ppKey(db)
|
|
|
|
proc ppCodeKey(a: NodeKey, db = AristoDbRef(nil)): string =
|
|
if a != EMPTY_CODE_KEY:
|
|
return a.ppKey(db)
|
|
|
|
proc ppPathTag(tag: NodeTag, db = AristoDbRef(nil)): string =
|
|
## Raw key, for referenced key dump use `key.pp(db)` below
|
|
if not db.isNil:
|
|
db.lTab.withValue(tag, keyPtr):
|
|
return "@" & keyPtr[].ppVid
|
|
|
|
"@" & tag.to(NodeKey).ByteArray32
|
|
.mapIt(it.toHex(2)).join.toLowerAscii
|
|
.squeeze(hex=true,ignLen=true)
|
|
|
|
proc ppPathPfx(pfx: NibblesSeq): string =
|
|
($(pfx & EmptyNibbleSeq)).squeeze(hex=true)
|
|
|
|
proc ppNibble(n: int8): string =
|
|
if n < 0: "ø" elif n < 10: $n else: n.toHex(1).toLowerAscii
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc keyToVtxID*(db: AristoDbRef, key: NodeKey): VertexID =
|
|
## Associate a vertex ID with the argument `key` for pretty printing.
|
|
if not key.isZero and
|
|
key != EMPTY_ROOT_KEY and
|
|
key != EMPTY_CODE_KEY and
|
|
not db.isNil:
|
|
|
|
db.xMap.withValue(key, vidPtr):
|
|
return vidPtr[]
|
|
|
|
result = db.vidFetch()
|
|
db.xMap[key] = result
|
|
|
|
proc pp*(vid: NodeKey): string =
|
|
vid.ppKey
|
|
|
|
proc pp*(tag: NodeTag, db = AristoDbRef(nil)): string =
|
|
tag.ppPathTag(db)
|
|
|
|
proc pp*(vid: VertexID): string =
|
|
vid.ppVid
|
|
|
|
proc pp*(vid: openArray[VertexID]): string =
|
|
"[" & vid.mapIt(it.ppVid).join(",") & "]"
|
|
|
|
proc pp*(p: PayloadRef, db = AristoDbRef(nil)): string =
|
|
if p.isNil:
|
|
result = "n/a"
|
|
else:
|
|
case p.pType:
|
|
of BlobData:
|
|
result &= p.blob.toHex.squeeze(hex=true)
|
|
of AccountData:
|
|
result = "("
|
|
result &= $p.account.nonce & ","
|
|
result &= $p.account.balance & ","
|
|
result &= p.account.storageRoot.to(NodeKey).ppRootKey(db) & ","
|
|
result &= p.account.codeHash.to(NodeKey).ppCodeKey(db) & ")"
|
|
|
|
proc pp*(nd: VertexRef, db = AristoDbRef(nil)): string =
|
|
if nd.isNil:
|
|
result = "n/a"
|
|
else:
|
|
result = ["l(", "x(", "b("][nd.vType.ord]
|
|
case nd.vType:
|
|
of Leaf:
|
|
result &= nd.lPfx.ppPathPfx & "," & nd.lData.pp(db)
|
|
of Extension:
|
|
result &= nd.ePfx.ppPathPfx & "," & nd.eVid.ppVid
|
|
of Branch:
|
|
result &= "["
|
|
for n in 0..15:
|
|
if not nd.bVid[n].isZero:
|
|
result &= nd.bVid[n].ppVid
|
|
result &= ","
|
|
result[^1] = ']'
|
|
result &= ")"
|
|
|
|
proc pp*(nd: NodeRef, db = AristoDbRef(nil)): string =
|
|
if nd.isNil:
|
|
result = "n/a"
|
|
elif nd.isError:
|
|
result = "(!" & $nd.error
|
|
else:
|
|
result = ["L(", "X(", "B("][nd.vType.ord]
|
|
case nd.vType:
|
|
of Leaf:
|
|
result &= $nd.lPfx.ppPathPfx & "," & nd.lData.pp(db)
|
|
|
|
of Extension:
|
|
result &= $nd.ePfx.ppPathPfx & "," & nd.eVid.ppVid & "," & nd.key[0].ppKey
|
|
|
|
of Branch:
|
|
result &= "["
|
|
for n in 0..15:
|
|
if not nd.bVid[n].isZero or not nd.key[n].isZero:
|
|
result &= nd.bVid[n].ppVid
|
|
result &= db.keyVidUpdate(nd.key[n], nd.bVid[n]) & ","
|
|
result[^1] = ']'
|
|
|
|
result &= ",["
|
|
for n in 0..15:
|
|
if not nd.bVid[n].isZero or not nd.key[n].isZero:
|
|
result &= nd.key[n].ppKey(db)
|
|
result &= ","
|
|
result[^1] = ']'
|
|
result &= ")"
|
|
|
|
proc pp*(
|
|
sTab: var Table[VertexID,VertexRef];
|
|
db = AristoDbRef(nil);
|
|
indent = 4;
|
|
): string =
|
|
let pfx = indent.toPfx
|
|
var first = true
|
|
result = "{"
|
|
for vid in toSeq(sTab.keys).mapIt(it.uint64).sorted.mapIt(it.VertexID):
|
|
sTab.withValue(vid, vtxPtr):
|
|
if first:
|
|
first = false
|
|
else:
|
|
result &= pfx & " "
|
|
result &= "(" & vid.ppVid & "," & vtxPtr[].pp(db) & "),"
|
|
if result[^1] == ',':
|
|
result[^1] = '}'
|
|
else:
|
|
result &= "}"
|
|
|
|
proc pp*(lTab: var Table[NodeTag,VertexID]; indent = 4): string =
|
|
let pfx = indent.toPfx
|
|
var first = true
|
|
result = "{"
|
|
for tag in toSeq(lTab.keys).mapIt(it.UInt256).sorted.mapIt(it.NodeTag):
|
|
lTab.withValue(tag,vidPtr):
|
|
if first:
|
|
first = false
|
|
else:
|
|
result &= pfx & " "
|
|
result &= "(" & tag.ppPathTag & "," & vidPtr[].ppVid & "),"
|
|
if result[^1] == ',':
|
|
result[^1] = '}'
|
|
else:
|
|
result &= "}"
|
|
|
|
proc pp*(sDel: HashSet[VertexID]): string =
|
|
result = "{"
|
|
for vid in toSeq(sDel.items).mapIt(it.uint64).sorted.mapIt(it.VertexID):
|
|
result &= vid.ppVid & ","
|
|
if result[^1] == ',':
|
|
result[^1] = '}'
|
|
else:
|
|
result &= "}"
|
|
|
|
proc pp*(
|
|
hike: Hike;
|
|
db = AristoDbRef(nil);
|
|
indent = 4;
|
|
): string =
|
|
let pfx = indent.toPfx
|
|
var first = true
|
|
result = "[(" & hike.root.ppVid & ")"
|
|
for leg in hike.legs:
|
|
result &= "," & pfx & " (" & leg.wp.vid.ppVid
|
|
if not db.isNil:
|
|
var key = "ø"
|
|
db.kMap.withValue(leg.wp.vid, keyPtr):
|
|
key = keyPtr[].ppKey(db)
|
|
result &= "," & key
|
|
result &= "," & $leg.nibble.ppNibble & "," & leg.wp.vtx.pp(db) & ")"
|
|
result &= "," & pfx & " (" & $hike.tail & ")"
|
|
if hike.error != AristoError(0):
|
|
result &= "," & pfx & " (" & $hike.error & ")"
|
|
result &= "]"
|
|
|
|
proc pp*(
|
|
kMap: var Table[VertexID,NodeKey];
|
|
db = AristoDbRef(nil);
|
|
indent = 4;
|
|
): string =
|
|
let pfx = indent.toPfx
|
|
var first = true
|
|
result = "{"
|
|
for vid in toSeq(kMap.keys).mapIt(it.uint64).sorted.mapIt(it.VertexID):
|
|
kMap.withValue(vid, keyPtr):
|
|
if first:
|
|
first = false
|
|
else:
|
|
result &= pfx & " "
|
|
result &= "(" & vid.ppVid & "," & keyPtr[].ppKey(db) & "),"
|
|
if result[^1] == ',':
|
|
result[^1] = '}'
|
|
else:
|
|
result &= "}"
|
|
|
|
proc pp*(
|
|
pAmk: var Table[NodeKey,VertexID];
|
|
db = AristoDbRef(nil);
|
|
indent = 4;
|
|
): string =
|
|
let pfx = indent.toPfx
|
|
var first = true
|
|
result = "{"
|
|
for key in toSeq(pAmk.keys).mapIt(it.to(NodeTag).UInt256)
|
|
.sorted.mapIt(it.NodeTag.to(NodeKey)):
|
|
pAmk.withValue(key,vidPtr):
|
|
if first:
|
|
first = false
|
|
else:
|
|
result &= pfx & " "
|
|
result &= "(" & key.ppKey(db) & "," & vidPtr[].ppVid & "),"
|
|
if result[^1] == ',':
|
|
result[^1] = '}'
|
|
else:
|
|
result &= "}"
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|