Core db and aristo updates for destructor and tx logic (#1894)
* Disable `TransactionID` related functions from `state_db.nim`
why:
Functions `getCommittedStorage()` and `updateOriginalRoot()` from
the `state_db` module are nowhere used. The emulation of a legacy
`TransactionID` type functionality is administratively expensive to
provide by `Aristo` (the legacy DB version is only partially
implemented, anyway).
As there is no other place where `TransactionID`s are used, they will
not be provided by the `Aristo` variant of the `CoreDb`. For the
legacy DB API, nothing will change.
* Fix copyright headers in source code
* Get rid of compiler warning
* Update Aristo code, remove unused `merge()` variant, export `hashify()`
why:
Adapt to upcoming `CoreDb` wrapper
* Remove synced tx feature from `Aristo`
why:
+ This feature allowed to synchronise transaction methods like begin,
commit, and rollback for a group of descriptors.
+ The feature is over engineered and not needed for `CoreDb`, neither
is it complete (some convergence features missing.)
* Add debugging helpers to `Kvt`
also:
Update database iterator, add count variable yield argument similar
to `Aristo`.
* Provide optional destructors for `CoreDb` API
why;
For the upcoming Aristo wrapper, this allows to control when certain
smart destruction and update can take place. The auto destructor works
fine in general when the storage/cache strategy is known and acceptable
when creating descriptors.
* Add update option for `CoreDb` API function `hash()`
why;
The hash function is typically used to get the state root of the MPT.
Due to lazy hashing, this might be not available on the `Aristo` DB.
So the `update` function asks for re-hashing the gurrent state changes
if needed.
* Update API tracking log mode: `info` => `debug
* Use shared `Kvt` descriptor in new Ledger API
why:
No need to create a new descriptor all the time
2023-11-16 19:35:03 +00:00
|
|
|
# Nimbus
|
|
|
|
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
2023-02-02 13:27: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.
|
|
|
|
|
|
|
|
## Snap sync components tester and TDD environment
|
|
|
|
|
|
|
|
import
|
2023-02-15 10:14:40 +00:00
|
|
|
std/[random, sequtils],
|
2023-02-02 13:27:09 +00:00
|
|
|
eth/common,
|
2023-02-15 10:14:40 +00:00
|
|
|
stew/byteutils,
|
2023-02-02 13:27:09 +00:00
|
|
|
unittest2,
|
2023-02-15 10:14:40 +00:00
|
|
|
../../nimbus/sync/[handlers, protocol],
|
|
|
|
../../nimbus/sync/snap/range_desc,
|
|
|
|
../../nimbus/sync/snap/worker/db/[hexary_desc, hexary_range],
|
2023-02-02 13:27:09 +00:00
|
|
|
./test_helpers
|
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
const
|
|
|
|
accObjRlpMin = 70 # min size of an encoded `Account()` obj
|
|
|
|
accObjRlpMax = 110 # max size of an encoded `Account()` obj
|
|
|
|
var
|
|
|
|
accBlobs: array[accObjRlpMax - accObjRlpMin + 1, Blob]
|
|
|
|
brNode = XNodeObj(kind: Branch)
|
|
|
|
nodeBlob: Blob
|
|
|
|
|
2023-02-02 13:27:09 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
2023-02-15 10:14:40 +00:00
|
|
|
# Private helpers for `test_calcAccountsListSizes()`
|
2023-02-02 13:27:09 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2023-04-14 22:28:57 +00:00
|
|
|
proc `==`(a,b: ChainId): bool {.borrow.}
|
|
|
|
## helper for ` test_calcBlockBodyTranscode()`
|
|
|
|
|
|
|
|
# ------------------
|
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
proc randAccSize(r: var Rand): int =
|
|
|
|
## Print random account size
|
|
|
|
accObjRlpMin + r.rand(accBlobs.len - 1)
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
proc accBlob(n: int): Blob =
|
|
|
|
let inx = n - accObjRlpMin
|
|
|
|
if 0 <= inx and inx < accBlobs.len:
|
|
|
|
accBlobs[inx]
|
|
|
|
else:
|
|
|
|
@[]
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
proc initAccBlobs() =
|
|
|
|
if accBlobs[0].len == 0:
|
|
|
|
let ffAccLen = Account(
|
|
|
|
storageRoot: Hash256(data: high(UInt256).toBytesBE),
|
|
|
|
codeHash: Hash256(data: high(UInt256).toBytesBE),
|
|
|
|
nonce: high(uint64),
|
|
|
|
balance: high(UInt256)).encode.len
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
check accObjRlpMin == Account().encode.len
|
|
|
|
check accObjRlpMax == ffAccLen
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
# Initialise
|
|
|
|
for n in 0 ..< accBlobs.len:
|
|
|
|
accBlobs[n] = 5.byte.repeat(accObjRlpMin + n)
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
# Verify
|
|
|
|
for n in 0 .. (accObjRlpMax + 2):
|
|
|
|
if accObjRlpMin <= n and n <= accObjRlpMax:
|
|
|
|
check n == accBlob(n).len
|
|
|
|
else:
|
|
|
|
check 0 == accBlob(n).len
|
|
|
|
|
|
|
|
proc accRndChain(r: var Rand; nItems: int): seq[RangeLeaf] =
|
|
|
|
for n in 0 ..< nItems:
|
|
|
|
result.add RangeLeaf(data: accBlob(r.randAccSize()))
|
|
|
|
discard result[^1].key.init (n mod 256).byte.repeat(32)
|
|
|
|
|
|
|
|
proc accRndChain(seed: int; nItems: int): seq[RangeLeaf] =
|
|
|
|
var prng = initRand(seed)
|
|
|
|
prng.accRndChain(nItems)
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private helpers for `test_calcProofsListSizes()`
|
|
|
|
# ------------------------------------------------------------------------------
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
proc initBranchNodeSample() =
|
|
|
|
if nodeBlob.len == 0:
|
2023-02-02 13:27:09 +00:00
|
|
|
for n in 0 .. 15:
|
2023-02-15 10:14:40 +00:00
|
|
|
brNode.bLink[n] = high(NodeTag).to(Blob)
|
|
|
|
nodeBlob = brNode.convertTo(Blob)
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public test function
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
proc test_calcAccountsListSizes*() =
|
|
|
|
## Verify accounts size calculation for `hexaryRangeLeafsProof()`.
|
|
|
|
initAccBlobs()
|
|
|
|
|
|
|
|
let chain = 42.accRndChain(123)
|
|
|
|
|
|
|
|
# Emulate `hexaryRangeLeafsProof()` size calculations
|
|
|
|
var sizeAccu = 0
|
|
|
|
for n in 0 ..< chain.len:
|
|
|
|
let (pairLen,listLen) =
|
|
|
|
chain[n].data.len.hexaryRangeRlpLeafListSize(sizeAccu)
|
|
|
|
check listLen == chain[0 .. n].encode.len
|
|
|
|
sizeAccu += pairLen
|
|
|
|
|
|
|
|
|
|
|
|
proc test_calcProofsListSizes*() =
|
|
|
|
## RLP does not allow static check ..
|
|
|
|
initBranchNodeSample()
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-02-15 10:14:40 +00:00
|
|
|
for n in [0, 1, 2, 126, 127]:
|
|
|
|
let
|
2023-03-03 20:01:59 +00:00
|
|
|
nodeSample = nodeBlob.to(SnapProof).repeat(n)
|
|
|
|
nodeBlobsEncoded = nodeSample.proofEncode
|
|
|
|
nodeBlobsDecoded = nodeBlobsEncoded.proofDecode
|
2023-02-15 10:14:40 +00:00
|
|
|
nodeBlobsHex = nodeBlobsEncoded.toHex
|
|
|
|
brNodesHex = brNode.repeat(n).convertTo(Blob).toHex
|
2023-03-03 20:01:59 +00:00
|
|
|
#echo "+++ ", n, " ", nodeBlobsEncoded.rlpFromBytes.inspect
|
2023-02-15 10:14:40 +00:00
|
|
|
#echo ">>> ", n, " ", nodeBlobsHex
|
|
|
|
#echo "<<< ", n, " ", brNodesHex
|
2023-03-10 17:10:30 +00:00
|
|
|
check nodeBlobsEncoded.len == n.hexaryRangeRlpNodesListSizeMax
|
2023-03-03 20:01:59 +00:00
|
|
|
check nodeBlobsDecoded == nodeSample
|
2023-02-15 10:14:40 +00:00
|
|
|
check nodeBlobsHex == brNodesHex
|
2023-02-02 13:27:09 +00:00
|
|
|
|
2023-03-22 20:11:49 +00:00
|
|
|
|
2023-04-14 22:28:57 +00:00
|
|
|
proc test_calcTrieNodeTranscode*() =
|
|
|
|
## RLP encode/decode a list of `SnapTriePaths` objects
|
2023-03-22 20:11:49 +00:00
|
|
|
let
|
|
|
|
raw = @[
|
|
|
|
# Accounts
|
|
|
|
SnapTriePaths(accPath: @[1.byte]),
|
|
|
|
SnapTriePaths(accPath: @[2.byte]),
|
|
|
|
SnapTriePaths(accPath: @[3.byte]),
|
|
|
|
|
|
|
|
# Storage slots
|
|
|
|
SnapTriePaths(
|
|
|
|
accPath: 4.u256.NodeTag.to(Blob),
|
|
|
|
slotPaths: @[@[4.byte,1.byte], @[4.byte,2.byte], @[4.byte,3.byte]]),
|
|
|
|
SnapTriePaths(
|
|
|
|
accPath: 5.u256.NodeTag.to(Blob),
|
|
|
|
slotPaths: @[@[5.byte,4.byte], @[5.byte,5.byte], @[5.byte,6.byte]]),
|
|
|
|
SnapTriePaths(
|
|
|
|
accPath: 6.u256.NodeTag.to(Blob),
|
|
|
|
slotPaths: @[@[6.byte,7.byte], @[6.byte,8.byte], @[6.byte,9.byte]]),
|
|
|
|
|
|
|
|
# Accounts contd.
|
|
|
|
SnapTriePaths(accPath: @[7.byte]),
|
|
|
|
SnapTriePaths(accPath: @[8.byte]),
|
|
|
|
SnapTriePaths(accPath: @[9.byte])]
|
|
|
|
|
|
|
|
cured = @[
|
|
|
|
@[@[1.byte]],
|
|
|
|
@[@[2.byte]],
|
|
|
|
@[@[3.byte]],
|
|
|
|
|
|
|
|
@[4.u256.NodeTag.to(Blob),
|
|
|
|
@[4.byte,1.byte], @[4.byte,2.byte], @[4.byte,3.byte]],
|
|
|
|
@[5.u256.NodeTag.to(Blob),
|
|
|
|
@[5.byte,4.byte], @[5.byte,5.byte], @[5.byte,6.byte]],
|
|
|
|
@[6.u256.NodeTag.to(Blob),
|
|
|
|
@[6.byte,7.byte], @[6.byte,8.byte], @[6.byte,9.byte]],
|
|
|
|
|
|
|
|
@[@[7.byte]],
|
|
|
|
@[@[8.byte]],
|
|
|
|
@[@[9.byte]]]
|
|
|
|
|
|
|
|
# cook it
|
|
|
|
proc append(w: var RlpWriter; p: SnapTriePaths) = w.snapAppend p
|
|
|
|
let cooked = rlp.encode raw
|
|
|
|
check cooked == rlp.encode cured
|
|
|
|
|
|
|
|
# reverse
|
|
|
|
proc read(rlp: var Rlp; T: type SnapTriePaths): T = rlp.snapRead T
|
|
|
|
check raw == rlp.decode(cooked, seq[SnapTriePaths])
|
|
|
|
check cured == rlp.decode(cooked, seq[seq[Blob]])
|
|
|
|
|
2023-04-14 22:28:57 +00:00
|
|
|
|
|
|
|
proc test_calcBlockBodyTranscode*() =
|
|
|
|
## RLP encode/decode a list of `BlockBody` objects. Note that tere is/was a
|
|
|
|
## problem in `eth/common/eth_types_rlp.append()` for `BlockBody` encoding.
|
|
|
|
let blkSeq = @[
|
|
|
|
BlockBody(
|
|
|
|
transactions: @[
|
|
|
|
Transaction(nonce: 1)]),
|
|
|
|
BlockBody(
|
|
|
|
uncles: @[
|
|
|
|
BlockHeader(nonce: [0x20u8,0,0,0,0,0,0,0])]),
|
|
|
|
BlockBody(),
|
|
|
|
BlockBody(
|
|
|
|
transactions: @[
|
|
|
|
Transaction(nonce: 3),
|
|
|
|
Transaction(nonce: 4)])]
|
|
|
|
|
|
|
|
let trBlkSeq = blkSeq.encode.decode(typeof blkSeq)
|
|
|
|
|
|
|
|
check trBlkSeq.len == blkSeq.len
|
|
|
|
for n in 0 ..< min(trBlkSeq.len, trBlkSeq.len):
|
|
|
|
check (n, trBlkSeq[n]) == (n, blkSeq[n])
|
|
|
|
|
2023-02-02 13:27:09 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|