mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 21:34:33 +00:00
Ordered trie (#2712)
Speed up trie computations and remove redundant ways of performing this operation. Co-authored-by: jangko <jangko128@gmail.com>
This commit is contained in:
parent
e59d2825f4
commit
11646ad3c4
1
Makefile
1
Makefile
@ -51,6 +51,7 @@ EXCLUDED_NIM_PACKAGES := \
|
|||||||
vendor/nimbus-eth2/vendor/nim-presto \
|
vendor/nimbus-eth2/vendor/nim-presto \
|
||||||
vendor/nimbus-eth2/vendor/nim-zxcvbn \
|
vendor/nimbus-eth2/vendor/nim-zxcvbn \
|
||||||
vendor/nimbus-eth2/vendor/nim-kzg4844 \
|
vendor/nimbus-eth2/vendor/nim-kzg4844 \
|
||||||
|
vendor/nimbus-eth2/vendor/nim-minilru \
|
||||||
vendor/nimbus-eth2/vendor/nimbus-security-resources \
|
vendor/nimbus-eth2/vendor/nimbus-security-resources \
|
||||||
vendor/nimbus-eth2/vendor/NimYAML
|
vendor/nimbus-eth2/vendor/NimYAML
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import
|
|||||||
results,
|
results,
|
||||||
chronos,
|
chronos,
|
||||||
chronicles,
|
chronicles,
|
||||||
eth/[trie, trie/db],
|
eth/trie/ordered_trie,
|
||||||
eth/common/[hashes, headers_rlp, blocks_rlp, receipts_rlp, transactions_rlp],
|
eth/common/[hashes, headers_rlp, blocks_rlp, receipts_rlp, transactions_rlp],
|
||||||
eth/p2p/discoveryv5/[protocol, enr],
|
eth/p2p/discoveryv5/[protocol, enr],
|
||||||
../../common/common_types,
|
../../common/common_types,
|
||||||
@ -163,27 +163,6 @@ func encode*(receipts: seq[Receipt]): seq[byte] =
|
|||||||
# TODO: Failures on validation and perhaps deserialisation should be punished
|
# TODO: Failures on validation and perhaps deserialisation should be punished
|
||||||
# for if/when peer scoring/banning is added.
|
# for if/when peer scoring/banning is added.
|
||||||
|
|
||||||
proc calcRootHash(items: Transactions | PortalReceipts | Withdrawals): Hash32 =
|
|
||||||
var tr = initHexaryTrie(newMemoryDB(), isPruning = false)
|
|
||||||
for i, item in items:
|
|
||||||
try:
|
|
||||||
tr.put(rlp.encode(i.uint), item.asSeq())
|
|
||||||
except RlpError as e:
|
|
||||||
# RlpError should not occur
|
|
||||||
# TODO: trace down why it might raise this
|
|
||||||
raiseAssert(e.msg)
|
|
||||||
|
|
||||||
return tr.rootHash
|
|
||||||
|
|
||||||
template calcTxsRoot*(transactions: Transactions): Hash32 =
|
|
||||||
calcRootHash(transactions)
|
|
||||||
|
|
||||||
template calcReceiptsRoot*(receipts: PortalReceipts): Hash32 =
|
|
||||||
calcRootHash(receipts)
|
|
||||||
|
|
||||||
template calcWithdrawalsRoot*(receipts: Withdrawals): Hash32 =
|
|
||||||
calcRootHash(receipts)
|
|
||||||
|
|
||||||
func validateBlockHeader*(header: Header, blockHash: Hash32): Result[void, string] =
|
func validateBlockHeader*(header: Header, blockHash: Hash32): Result[void, string] =
|
||||||
if not (header.rlpHash() == blockHash):
|
if not (header.rlpHash() == blockHash):
|
||||||
err("Block header hash does not match")
|
err("Block header hash does not match")
|
||||||
@ -217,6 +196,15 @@ func validateBlockHeaderBytes*(
|
|||||||
|
|
||||||
ok(header)
|
ok(header)
|
||||||
|
|
||||||
|
template append*(w: var RlpWriter, v: TransactionByteList) =
|
||||||
|
w.appendRawBytes(v.asSeq)
|
||||||
|
|
||||||
|
template append*(w: var RlpWriter, v: WithdrawalByteList) =
|
||||||
|
w.appendRawBytes(v.asSeq)
|
||||||
|
|
||||||
|
template append*(w: var RlpWriter, v: ReceiptByteList) =
|
||||||
|
w.appendRawBytes(v.asSeq)
|
||||||
|
|
||||||
proc validateBlockBody*(
|
proc validateBlockBody*(
|
||||||
body: PortalBlockBodyLegacy, header: Header
|
body: PortalBlockBodyLegacy, header: Header
|
||||||
): Result[void, string] =
|
): Result[void, string] =
|
||||||
@ -225,7 +213,7 @@ proc validateBlockBody*(
|
|||||||
if calculatedOmmersHash != header.ommersHash:
|
if calculatedOmmersHash != header.ommersHash:
|
||||||
return err("Invalid ommers hash")
|
return err("Invalid ommers hash")
|
||||||
|
|
||||||
let calculatedTxsRoot = calcTxsRoot(body.transactions)
|
let calculatedTxsRoot = orderedTrieRoot(body.transactions.asSeq)
|
||||||
if calculatedTxsRoot != header.txRoot:
|
if calculatedTxsRoot != header.txRoot:
|
||||||
return err(
|
return err(
|
||||||
"Invalid transactions root: expected " & $header.txRoot & " - got " &
|
"Invalid transactions root: expected " & $header.txRoot & " - got " &
|
||||||
@ -244,7 +232,7 @@ proc validateBlockBody*(
|
|||||||
if body.uncles.asSeq() != @[byte 0xc0]:
|
if body.uncles.asSeq() != @[byte 0xc0]:
|
||||||
return err("Invalid ommers hash, uncles list is not empty")
|
return err("Invalid ommers hash, uncles list is not empty")
|
||||||
|
|
||||||
let calculatedTxsRoot = calcTxsRoot(body.transactions)
|
let calculatedTxsRoot = orderedTrieRoot(body.transactions.asSeq)
|
||||||
if calculatedTxsRoot != header.txRoot:
|
if calculatedTxsRoot != header.txRoot:
|
||||||
return err(
|
return err(
|
||||||
"Invalid transactions root: expected " & $header.txRoot & " - got " &
|
"Invalid transactions root: expected " & $header.txRoot & " - got " &
|
||||||
@ -256,7 +244,7 @@ proc validateBlockBody*(
|
|||||||
doAssert(header.withdrawalsRoot.isSome())
|
doAssert(header.withdrawalsRoot.isSome())
|
||||||
|
|
||||||
let
|
let
|
||||||
calculatedWithdrawalsRoot = calcWithdrawalsRoot(body.withdrawals)
|
calculatedWithdrawalsRoot = orderedTrieRoot(body.withdrawals.asSeq)
|
||||||
headerWithdrawalsRoot = header.withdrawalsRoot.get()
|
headerWithdrawalsRoot = header.withdrawalsRoot.get()
|
||||||
if calculatedWithdrawalsRoot != headerWithdrawalsRoot:
|
if calculatedWithdrawalsRoot != headerWithdrawalsRoot:
|
||||||
return err(
|
return err(
|
||||||
@ -314,7 +302,7 @@ proc validateBlockBodyBytes*(
|
|||||||
proc validateReceipts*(
|
proc validateReceipts*(
|
||||||
receipts: PortalReceipts, receiptsRoot: Hash32
|
receipts: PortalReceipts, receiptsRoot: Hash32
|
||||||
): Result[void, string] =
|
): Result[void, string] =
|
||||||
if calcReceiptsRoot(receipts) != receiptsRoot:
|
if orderedTrieRoot(receipts.asSeq) != receiptsRoot:
|
||||||
err("Unexpected receipt root")
|
err("Unexpected receipt root")
|
||||||
else:
|
else:
|
||||||
ok()
|
ok()
|
||||||
|
@ -41,7 +41,7 @@ import
|
|||||||
chronicles,
|
chronicles,
|
||||||
chronos,
|
chronos,
|
||||||
confutils,
|
confutils,
|
||||||
eth/[rlp, trie, trie/db],
|
eth/[rlp, trie/ordered_trie],
|
||||||
eth/common/keys,
|
eth/common/keys,
|
||||||
eth/common/[base, headers_rlp, blocks_rlp],
|
eth/common/[base, headers_rlp, blocks_rlp],
|
||||||
beacon_chain/el/[el_manager, engine_api_conversions],
|
beacon_chain/el/[el_manager, engine_api_conversions],
|
||||||
@ -62,43 +62,24 @@ import
|
|||||||
from beacon_chain/gossip_processing/block_processor import newExecutionPayload
|
from beacon_chain/gossip_processing/block_processor import newExecutionPayload
|
||||||
from beacon_chain/gossip_processing/eth2_processor import toValidationResult
|
from beacon_chain/gossip_processing/eth2_processor import toValidationResult
|
||||||
|
|
||||||
proc calculateTransactionData(
|
template append(w: var RlpWriter, t: TypedTransaction) =
|
||||||
items: openArray[TypedTransaction]
|
w.appendRawBytes(distinctBase t)
|
||||||
): Hash32 {.raises: [].} =
|
|
||||||
var tr = initHexaryTrie(newMemoryDB(), isPruning = false)
|
|
||||||
for i, t in items:
|
|
||||||
try:
|
|
||||||
let tx = distinctBase(t)
|
|
||||||
tr.put(rlp.encode(uint64 i), tx)
|
|
||||||
except CatchableError as e:
|
|
||||||
# tr.put interface can raise exception
|
|
||||||
raiseAssert(e.msg)
|
|
||||||
|
|
||||||
return tr.rootHash()
|
template append(w: var RlpWriter, t: WithdrawalV1) =
|
||||||
|
# TODO: Since Capella we can also access ExecutionPayloadHeader and thus
|
||||||
# TODO: Since Capella we can also access ExecutionPayloadHeader and thus
|
# could get the Roots through there instead.
|
||||||
# could get the Roots through there instead.
|
w.append blocks.Withdrawal(
|
||||||
proc calculateWithdrawalsRoot(items: openArray[WithdrawalV1]): Hash32 {.raises: [].} =
|
index: distinctBase(t.index),
|
||||||
var tr = initHexaryTrie(newMemoryDB(), isPruning = false)
|
validatorIndex: distinctBase(t.validatorIndex),
|
||||||
for i, w in items:
|
address: t.address,
|
||||||
try:
|
amount: distinctBase(t.amount),
|
||||||
let withdrawal = blocks.Withdrawal(
|
|
||||||
index: distinctBase(w.index),
|
|
||||||
validatorIndex: distinctBase(w.validatorIndex),
|
|
||||||
address: w.address,
|
|
||||||
amount: distinctBase(w.amount),
|
|
||||||
)
|
)
|
||||||
tr.put(rlp.encode(uint64 i), rlp.encode(withdrawal))
|
|
||||||
except CatchableError as e:
|
|
||||||
raiseAssert(e.msg)
|
|
||||||
|
|
||||||
return tr.rootHash()
|
|
||||||
|
|
||||||
proc asPortalBlockData*(
|
proc asPortalBlockData*(
|
||||||
payload: ExecutionPayloadV1
|
payload: ExecutionPayloadV1
|
||||||
): (Hash32, BlockHeaderWithProof, PortalBlockBodyLegacy) =
|
): (Hash32, BlockHeaderWithProof, PortalBlockBodyLegacy) =
|
||||||
let
|
let
|
||||||
txRoot = calculateTransactionData(payload.transactions)
|
txRoot = orderedTrieRoot(payload.transactions)
|
||||||
|
|
||||||
header = Header(
|
header = Header(
|
||||||
parentHash: payload.parentHash,
|
parentHash: payload.parentHash,
|
||||||
@ -139,8 +120,8 @@ proc asPortalBlockData*(
|
|||||||
payload: ExecutionPayloadV2 | ExecutionPayloadV3 | ExecutionPayloadV4
|
payload: ExecutionPayloadV2 | ExecutionPayloadV3 | ExecutionPayloadV4
|
||||||
): (Hash32, BlockHeaderWithProof, PortalBlockBodyShanghai) =
|
): (Hash32, BlockHeaderWithProof, PortalBlockBodyShanghai) =
|
||||||
let
|
let
|
||||||
txRoot = calculateTransactionData(payload.transactions)
|
txRoot = orderedTrieRoot(payload.transactions)
|
||||||
withdrawalsRoot = Opt.some(calculateWithdrawalsRoot(payload.withdrawals))
|
withdrawalsRoot = Opt.some(orderedTrieRoot(payload.withdrawals))
|
||||||
|
|
||||||
# TODO: adjust blobGasUsed & excessBlobGas according to deneb fork!
|
# TODO: adjust blobGasUsed & excessBlobGas according to deneb fork!
|
||||||
header = Header(
|
header = Header(
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
aristo/[aristo_api, aristo_constants, aristo_sign]
|
aristo/[aristo_api, aristo_constants]
|
||||||
export
|
export
|
||||||
aristo_api, aristo_constants, aristo_sign
|
aristo_api, aristo_constants
|
||||||
|
|
||||||
import
|
import
|
||||||
aristo/aristo_init
|
aristo/aristo_init
|
||||||
@ -48,7 +48,6 @@ export
|
|||||||
AristoDbRef,
|
AristoDbRef,
|
||||||
AristoError,
|
AristoError,
|
||||||
AristoTxRef,
|
AristoTxRef,
|
||||||
MerkleSignRef,
|
|
||||||
isValid
|
isValid
|
||||||
|
|
||||||
# End
|
# End
|
||||||
|
@ -507,12 +507,6 @@ proc pp*(w: Hash32; codeHashOk: bool): string =
|
|||||||
proc pp*(n: NibblesBuf): string =
|
proc pp*(n: NibblesBuf): string =
|
||||||
n.ppPathPfx()
|
n.ppPathPfx()
|
||||||
|
|
||||||
proc pp*(w: HashKey; sig: MerkleSignRef): string =
|
|
||||||
w.ppKey(sig.db)
|
|
||||||
|
|
||||||
proc pp*(w: Hash32; sig: MerkleSignRef): string =
|
|
||||||
w.to(HashKey).ppKey(sig.db)
|
|
||||||
|
|
||||||
proc pp*(w: HashKey; db = AristoDbRef(nil)): string =
|
proc pp*(w: HashKey; db = AristoDbRef(nil)): string =
|
||||||
w.ppKey(db.orDefault)
|
w.ppKey(db.orDefault)
|
||||||
|
|
||||||
@ -740,14 +734,6 @@ proc pp*(
|
|||||||
elif balancerOk:
|
elif balancerOk:
|
||||||
result &= indent.toPfx & db.balancer.ppBalancer(db, indent+1)
|
result &= indent.toPfx & db.balancer.ppBalancer(db, indent+1)
|
||||||
|
|
||||||
proc pp*(sdb: MerkleSignRef; indent = 4): string =
|
|
||||||
result = "" &
|
|
||||||
"count=" & $sdb.count &
|
|
||||||
" root=" & sdb.root.pp
|
|
||||||
if sdb.error != AristoError(0):
|
|
||||||
result &= " error=" & $sdb.error
|
|
||||||
result &= "\n db\n " & sdb.db.pp(indent=indent+1)
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# End
|
# End
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -46,14 +46,6 @@ type
|
|||||||
txUid*: uint ## Unique ID among transactions
|
txUid*: uint ## Unique ID among transactions
|
||||||
level*: int ## Stack index for this transaction
|
level*: int ## Stack index for this transaction
|
||||||
|
|
||||||
MerkleSignRef* = ref object
|
|
||||||
## Simple Merkle signature calculatior for key-value lists
|
|
||||||
root*: VertexID ## Not accounts tree, e.g. `VertexID(2)`
|
|
||||||
db*: AristoDbRef
|
|
||||||
count*: uint
|
|
||||||
error*: AristoError
|
|
||||||
errKey*: seq[byte]
|
|
||||||
|
|
||||||
DudesRef = ref object
|
DudesRef = ref object
|
||||||
## List of peers accessing the same database. This list is layzily allocated
|
## List of peers accessing the same database. This list is layzily allocated
|
||||||
## and might be kept with a single entry, i.e. so that `{centre} == peers`.
|
## and might be kept with a single entry, i.e. so that `{centre} == peers`.
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
# nimbus-eth1
|
|
||||||
# Copyright (c) 2023-2024 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.
|
|
||||||
|
|
||||||
## Aristo DB -- Sign Helper
|
|
||||||
## ========================
|
|
||||||
##
|
|
||||||
{.push raises: [].}
|
|
||||||
|
|
||||||
import
|
|
||||||
eth/common,
|
|
||||||
results,
|
|
||||||
"."/[aristo_compute, aristo_desc, aristo_get, aristo_init,
|
|
||||||
aristo_delete, aristo_merge]
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# Public functions, signature generator
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
proc merkleSignBegin*(): MerkleSignRef =
|
|
||||||
## Start signature calculator for a list of key-value items.
|
|
||||||
let
|
|
||||||
db = AristoDbRef.init VoidBackendRef
|
|
||||||
vid = VertexID(2)
|
|
||||||
MerkleSignRef(
|
|
||||||
root: vid,
|
|
||||||
db: db)
|
|
||||||
|
|
||||||
proc merkleSignAdd*(
|
|
||||||
sdb: MerkleSignRef;
|
|
||||||
key: openArray[byte];
|
|
||||||
val: openArray[byte];
|
|
||||||
) =
|
|
||||||
## Add key-value item to the signature list. The order of the items to add
|
|
||||||
## is irrelevant.
|
|
||||||
if sdb.error == AristoError(0):
|
|
||||||
sdb.count.inc
|
|
||||||
discard sdb.db.mergeGenericData(sdb.root, key, val).valueOr:
|
|
||||||
sdb.`error` = error
|
|
||||||
sdb.errKey = @key
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
proc merkleSignDelete*(
|
|
||||||
sdb: MerkleSignRef;
|
|
||||||
key: openArray[byte];
|
|
||||||
) =
|
|
||||||
## Add key-value item to the signature list. The order of the items to add
|
|
||||||
## is irrelevant.
|
|
||||||
if sdb.error == AristoError(0):
|
|
||||||
sdb.count.inc
|
|
||||||
discard sdb.db.deleteGenericData(sdb.root, key).valueOr:
|
|
||||||
sdb.`error` = error
|
|
||||||
sdb.errKey = @key
|
|
||||||
return
|
|
||||||
|
|
||||||
proc merkleSignCommit*(
|
|
||||||
sdb: MerkleSignRef;
|
|
||||||
): Result[Hash32,(seq[byte],AristoError)] =
|
|
||||||
## Finish with the list, calculate signature and return it.
|
|
||||||
if sdb.count == 0:
|
|
||||||
return ok EMPTY_ROOTHASH
|
|
||||||
if sdb.error != AristoError(0):
|
|
||||||
return err((sdb.errKey, sdb.error))
|
|
||||||
|
|
||||||
let sign = sdb.db.computeKey((sdb.root, sdb.root)).valueOr:
|
|
||||||
if error == GetVtxNotFound:
|
|
||||||
if not sdb.db.getVtx((sdb.root, sdb.root)).isValid:
|
|
||||||
return ok EMPTY_ROOTHASH
|
|
||||||
raiseAssert "merkleSignCommit(): " & $error
|
|
||||||
|
|
||||||
ok sign.to(Hash32)
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# End
|
|
||||||
# ------------------------------------------------------------------------------
|
|
@ -12,32 +12,24 @@
|
|||||||
|
|
||||||
import
|
import
|
||||||
std/[math, times, strutils],
|
std/[math, times, strutils],
|
||||||
eth/[rlp, common/eth_types_rlp],
|
eth/[common/eth_types_rlp, trie/ordered_trie],
|
||||||
stew/byteutils,
|
stew/byteutils,
|
||||||
nimcrypto,
|
nimcrypto/sha2,
|
||||||
results,
|
|
||||||
../db/aristo/aristo_sign,
|
|
||||||
../constants
|
../constants
|
||||||
|
|
||||||
export eth_types_rlp
|
export eth_types_rlp
|
||||||
|
|
||||||
proc calcRootHash[T](items: openArray[T]): Hash256 {.gcsafe.} =
|
template calcTxRoot*(transactions: openArray[Transaction]): Root =
|
||||||
let sig = merkleSignBegin()
|
orderedTrieRoot(transactions)
|
||||||
for i, t in items:
|
|
||||||
sig.merkleSignAdd(rlp.encode(i.uint), rlp.encode(t))
|
|
||||||
sig.merkleSignCommit.value
|
|
||||||
|
|
||||||
template calcTxRoot*(transactions: openArray[Transaction]): Hash256 =
|
template calcWithdrawalsRoot*(withdrawals: openArray[Withdrawal]): Root =
|
||||||
calcRootHash(transactions)
|
orderedTrieRoot(withdrawals)
|
||||||
|
|
||||||
template calcWithdrawalsRoot*(withdrawals: openArray[Withdrawal]): Hash256 =
|
template calcReceiptsRoot*(receipts: openArray[Receipt]): Root =
|
||||||
calcRootHash(withdrawals)
|
orderedTrieRoot(receipts)
|
||||||
|
|
||||||
template calcReceiptsRoot*(receipts: openArray[Receipt]): Hash256 =
|
template calcRequestsRoot*(requests: openArray[Request]): Root =
|
||||||
calcRootHash(receipts)
|
orderedTrieRoot(requests)
|
||||||
|
|
||||||
template calcRequestsRoot*(requests: openArray[Request]): Hash256 =
|
|
||||||
calcRootHash(requests)
|
|
||||||
|
|
||||||
func sumHash*(hashes: varargs[Hash256]): Hash256 =
|
func sumHash*(hashes: varargs[Hash256]): Hash256 =
|
||||||
var ctx: sha256
|
var ctx: sha256
|
||||||
|
@ -21,7 +21,7 @@ import
|
|||||||
./test_aristo/test_blobify,
|
./test_aristo/test_blobify,
|
||||||
./test_aristo/test_merge_proof,
|
./test_aristo/test_merge_proof,
|
||||||
./test_aristo/test_portal_proof,
|
./test_aristo/test_portal_proof,
|
||||||
./test_aristo/test_short_keys,
|
./test_aristo/test_compute,
|
||||||
./test_aristo/[
|
./test_aristo/[
|
||||||
test_balancer, test_helpers, test_samples_xx, test_tx,
|
test_balancer, test_helpers, test_samples_xx, test_tx,
|
||||||
undump_accounts, undump_storages]
|
undump_accounts, undump_storages]
|
||||||
|
150
tests/test_aristo/test_compute.nim
Normal file
150
tests/test_aristo/test_compute.nim
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
# Nimbus
|
||||||
|
# Copyright (c) 2023-2024 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.
|
||||||
|
|
||||||
|
{.used.}
|
||||||
|
|
||||||
|
import
|
||||||
|
std/[algorithm, sets],
|
||||||
|
stew/byteutils,
|
||||||
|
unittest2,
|
||||||
|
../../nimbus/db/aristo/[
|
||||||
|
aristo_check, aristo_compute, aristo_delete, aristo_get, aristo_merge, aristo_desc,
|
||||||
|
aristo_utils, aristo_serialise, aristo_init,
|
||||||
|
]
|
||||||
|
|
||||||
|
func x(s: string): seq[byte] =
|
||||||
|
s.hexToSeqByte
|
||||||
|
func k(s: string): HashKey =
|
||||||
|
HashKey.fromBytes(s.x).value
|
||||||
|
|
||||||
|
let samples = [
|
||||||
|
# From InvalidBlocks/bc4895-withdrawals/twoIdenticalIndex.json
|
||||||
|
@[
|
||||||
|
(
|
||||||
|
"80".x,
|
||||||
|
"da808094c94f5374fce5edbc8e2a8697c15331677e6ebf0b822710".x,
|
||||||
|
hash32"27f166f1d7c789251299535cb176ba34116e44894476a7886fe5d73d9be5c973",
|
||||||
|
VOID_HASH_KEY,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"01".x,
|
||||||
|
"da028094c94f5374fce5edbc8e2a8697c15331677e6ebf0b822710".x,
|
||||||
|
hash32"81eac5f476f48feb289af40ee764015f6b49036760438ea45df90d5342b6ae61",
|
||||||
|
VOID_HASH_KEY,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"02".x,
|
||||||
|
"da018094c94f5374fce5edbc8e2a8697c15331677e6ebf0b822710".x,
|
||||||
|
hash32"463769ae507fcc6d6231c8888425191c5622f330fdd4b78a7b24c4521137b573",
|
||||||
|
VOID_HASH_KEY,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"03".x,
|
||||||
|
"da028094c94f5374fce5edbc8e2a8697c15331677e6ebf0b822710".x,
|
||||||
|
hash32"a95b9a7b58a6b3cb4001eb0be67951c5517141cb0183a255b5cae027a7b10b36",
|
||||||
|
VOID_HASH_KEY,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
# Somew on-the-fly provided stuff
|
||||||
|
@[
|
||||||
|
(
|
||||||
|
"0000".x,
|
||||||
|
"0000".x,
|
||||||
|
hash32"69a4785bd4f5a1590e329138d4248b6f887fa37e41bfc510a55f21b44f98be61",
|
||||||
|
"c783200000820000".k,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"0000".x,
|
||||||
|
"0001".x,
|
||||||
|
hash32"910fa1155b667666abe7b4b1cb4864c1dc91c57c9528e1c5f5f9f95e003afece",
|
||||||
|
"c783200000820001".k,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"0001".x,
|
||||||
|
"0001".x,
|
||||||
|
hash32"d082d2bfe8586142d6f40df0245e56365043819e51e2c9799c660558eeea0db5",
|
||||||
|
"dd821000d9c420820001c420820001808080808080808080808080808080".k,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"0002".x,
|
||||||
|
"0000".x,
|
||||||
|
hash32"d56ea5154fbad18e0ff1eaeafa2310d0879b59adf189c12ff1b2701e54db07b2",
|
||||||
|
VOID_HASH_KEY,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"0100".x,
|
||||||
|
"0100".x,
|
||||||
|
hash32"d1c0699fe7928a536e0183c6400ae34eb1174ce6b21f9d117b061385034743ad",
|
||||||
|
VOID_HASH_KEY,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"0101".x,
|
||||||
|
"0101".x,
|
||||||
|
hash32"74ddb98cb56e2dd7e8fa090b9ce740c3de589b72403b20136af75fb6168b1d19",
|
||||||
|
VOID_HASH_KEY,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"0200".x,
|
||||||
|
"0200".x,
|
||||||
|
hash32"2e777f06ab2de1a460a8412b8691f10fdcb162077ab5cbb1865636668bcb6471",
|
||||||
|
VOID_HASH_KEY,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
suite "Aristo compute":
|
||||||
|
for n, sample in samples:
|
||||||
|
test "Add and delete entries " & $n:
|
||||||
|
let
|
||||||
|
db = AristoDbRef.init VoidBackendRef
|
||||||
|
root = VertexID(2)
|
||||||
|
|
||||||
|
for inx, (k, v, r, s) in sample:
|
||||||
|
checkpoint("k = " & k.toHex & ", v = " & v.toHex())
|
||||||
|
|
||||||
|
check:
|
||||||
|
db.mergeGenericData(root, k, v) == Result[bool, AristoError].ok(true)
|
||||||
|
|
||||||
|
# Check state against expected value
|
||||||
|
let w = db.computeKey((root, root)).expect("no errors")
|
||||||
|
check r == w.to(Hash32)
|
||||||
|
|
||||||
|
# Check raw node if given, check nor ref against expected value
|
||||||
|
if s.isValid:
|
||||||
|
let z = db.getVtx((root, root)).toNode(root, db).value.digestTo(HashKey)
|
||||||
|
check s == z
|
||||||
|
|
||||||
|
let rc = db.check
|
||||||
|
check rc == typeof(rc).ok()
|
||||||
|
|
||||||
|
# Reverse run deleting entries
|
||||||
|
var deletedKeys: HashSet[seq[byte]]
|
||||||
|
for iny, (k, v, r, s) in sample.reversed:
|
||||||
|
# Check whether key was already deleted
|
||||||
|
if k in deletedKeys:
|
||||||
|
continue
|
||||||
|
deletedKeys.incl k
|
||||||
|
|
||||||
|
# Check state against expected value
|
||||||
|
let w = db.computeKey((root, root)).value.to(Hash32)
|
||||||
|
|
||||||
|
check r == w
|
||||||
|
|
||||||
|
# Check raw node if given, check nor ref against expected value
|
||||||
|
if s.isValid:
|
||||||
|
let z = db.getVtx((root, root)).toNode(root, db).value.digestTo(HashKey)
|
||||||
|
check s == z
|
||||||
|
|
||||||
|
check:
|
||||||
|
db.deleteGenericData(root, k).isOk
|
||||||
|
|
||||||
|
let rc = db.check
|
||||||
|
check rc == typeof(rc).ok()
|
@ -1,172 +0,0 @@
|
|||||||
# Nimbus
|
|
||||||
# Copyright (c) 2023-2024 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.
|
|
||||||
|
|
||||||
{.used.}
|
|
||||||
|
|
||||||
import
|
|
||||||
std/[algorithm, sets],
|
|
||||||
eth/common,
|
|
||||||
results,
|
|
||||||
stew/byteutils,
|
|
||||||
unittest2,
|
|
||||||
../../nimbus/db/aristo,
|
|
||||||
../../nimbus/db/aristo/[
|
|
||||||
aristo_check, aristo_get, aristo_debug, aristo_desc, aristo_serialise,
|
|
||||||
aristo_utils],
|
|
||||||
../replay/xcheck,
|
|
||||||
./test_helpers
|
|
||||||
|
|
||||||
func x(s: string): seq[byte] = s.hexToSeqByte
|
|
||||||
func k(s: string): HashKey = HashKey.fromBytes(s.x).value
|
|
||||||
|
|
||||||
let samples = [
|
|
||||||
|
|
||||||
# From InvalidBlocks/bc4895-withdrawals/twoIdenticalIndex.json
|
|
||||||
@[("80".x,
|
|
||||||
"da808094c94f5374fce5edbc8e2a8697c15331677e6ebf0b822710".x,
|
|
||||||
"27f166f1d7c789251299535cb176ba34116e44894476a7886fe5d73d9be5c973".k,
|
|
||||||
VOID_HASH_KEY),
|
|
||||||
("01".x,
|
|
||||||
"da028094c94f5374fce5edbc8e2a8697c15331677e6ebf0b822710".x,
|
|
||||||
"81eac5f476f48feb289af40ee764015f6b49036760438ea45df90d5342b6ae61".k,
|
|
||||||
VOID_HASH_KEY),
|
|
||||||
("02".x,
|
|
||||||
"da018094c94f5374fce5edbc8e2a8697c15331677e6ebf0b822710".x,
|
|
||||||
"463769ae507fcc6d6231c8888425191c5622f330fdd4b78a7b24c4521137b573".k,
|
|
||||||
VOID_HASH_KEY),
|
|
||||||
("03".x,
|
|
||||||
"da028094c94f5374fce5edbc8e2a8697c15331677e6ebf0b822710".x,
|
|
||||||
"a95b9a7b58a6b3cb4001eb0be67951c5517141cb0183a255b5cae027a7b10b36".k,
|
|
||||||
VOID_HASH_KEY)],
|
|
||||||
|
|
||||||
# Somew on-the-fly provided stuff
|
|
||||||
@[("0000".x, "0000".x,
|
|
||||||
"69a4785bd4f5a1590e329138d4248b6f887fa37e41bfc510a55f21b44f98be61".k,
|
|
||||||
"c783200000820000".k),
|
|
||||||
("0000".x, "0001".x,
|
|
||||||
"910fa1155b667666abe7b4b1cb4864c1dc91c57c9528e1c5f5f9f95e003afece".k,
|
|
||||||
"c783200000820001".k),
|
|
||||||
("0001".x, "0001".x,
|
|
||||||
"d082d2bfe8586142d6f40df0245e56365043819e51e2c9799c660558eeea0db5".k,
|
|
||||||
"dd821000d9c420820001c420820001808080808080808080808080808080".k),
|
|
||||||
("0002".x, "0000".x,
|
|
||||||
"d56ea5154fbad18e0ff1eaeafa2310d0879b59adf189c12ff1b2701e54db07b2".k,
|
|
||||||
VOID_HASH_KEY),
|
|
||||||
("0100".x, "0100".x,
|
|
||||||
"d1c0699fe7928a536e0183c6400ae34eb1174ce6b21f9d117b061385034743ad".k,
|
|
||||||
VOID_HASH_KEY),
|
|
||||||
("0101".x, "0101".x,
|
|
||||||
"74ddb98cb56e2dd7e8fa090b9ce740c3de589b72403b20136af75fb6168b1d19".k,
|
|
||||||
VOID_HASH_KEY),
|
|
||||||
("0200".x, "0200".x,
|
|
||||||
"2e777f06ab2de1a460a8412b8691f10fdcb162077ab5cbb1865636668bcb6471".k,
|
|
||||||
VOID_HASH_KEY)]]
|
|
||||||
|
|
||||||
let
|
|
||||||
noisy = true
|
|
||||||
gossip = false # or noisy
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# Public test function
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
suite "Aristo short keys":
|
|
||||||
test "Add and delete entries":
|
|
||||||
|
|
||||||
# Check for some pathological cases
|
|
||||||
for n,sample in samples:
|
|
||||||
let
|
|
||||||
sig = merkleSignBegin()
|
|
||||||
root = (sig.root,sig.root)
|
|
||||||
db = sig.db
|
|
||||||
|
|
||||||
for inx,(k,v,r,s) in sample:
|
|
||||||
|
|
||||||
sig.merkleSignAdd(k,v)
|
|
||||||
gossip.say "*** testShortkeys (1)", "n=", n, " inx=", inx,
|
|
||||||
"\n k=", k.toHex, " v=", v.toHex,
|
|
||||||
"\n r=", r.pp(sig),
|
|
||||||
"\n ", sig.pp(),
|
|
||||||
"\n"
|
|
||||||
|
|
||||||
# Check state against expected value
|
|
||||||
let w = sig.merkleSignCommit().value
|
|
||||||
gossip.say "*** testShortkeys (2)", "n=", n, " inx=", inx,
|
|
||||||
"\n k=", k.toHex, " v=", v.toHex,
|
|
||||||
"\n r=", r.pp(sig),
|
|
||||||
"\n R=", w.pp(sig),
|
|
||||||
"\n ", sig.pp(),
|
|
||||||
"\n ----------------",
|
|
||||||
"\n"
|
|
||||||
xCheck r == w.to(HashKey):
|
|
||||||
noisy.say "*** testShortkeys (2.1)", "n=", n, " inx=", inx,
|
|
||||||
"\n k=", k.toHex, " v=", v.toHex,
|
|
||||||
"\n r=", r.pp(sig),
|
|
||||||
"\n R=", w.pp(sig),
|
|
||||||
"\n ", sig.pp(),
|
|
||||||
"\n"
|
|
||||||
|
|
||||||
# Check raw node if given, check nor ref against expected value
|
|
||||||
if s.isValid:
|
|
||||||
let z = db.getVtx(root).toNode(root[0],db).value.digestTo(HashKey)
|
|
||||||
xCheck s == z:
|
|
||||||
noisy.say "*** testShortkeys (2.2)", "n=", n, " inx=", inx,
|
|
||||||
"\n k=", k.toHex, " v=", v.toHex,
|
|
||||||
"\n r=", r.pp(sig),
|
|
||||||
"\n R=", w.pp(sig),
|
|
||||||
"\n ", sig.pp(),
|
|
||||||
"\n"
|
|
||||||
|
|
||||||
let rc = sig.db.check
|
|
||||||
xCheckRc rc.error == (0,0):
|
|
||||||
noisy.say "*** testShortkeys (2.3)", "n=", n, " inx=", inx,
|
|
||||||
"\n k=", k.toHex, " v=", v.toHex, " rc=", rc.error,
|
|
||||||
"\n r=", r.pp(sig),
|
|
||||||
"\n R=", w.pp(sig),
|
|
||||||
"\n ", sig.pp(),
|
|
||||||
"\n"
|
|
||||||
|
|
||||||
# Reverse run deleting entries
|
|
||||||
var deletedKeys: HashSet[seq[byte]]
|
|
||||||
for iny,(k,v,r,s) in sample.reversed:
|
|
||||||
let inx = sample.len - 1 - iny
|
|
||||||
|
|
||||||
# Check whether key was already deleted
|
|
||||||
if k in deletedKeys:
|
|
||||||
continue
|
|
||||||
deletedKeys.incl k
|
|
||||||
|
|
||||||
# Check state against expected value
|
|
||||||
let w = sig.merkleSignCommit().value
|
|
||||||
gossip.say "*** testShortkeys, pre-del (5)", "n=", n, " inx=", inx,
|
|
||||||
"\n k", k.toHex, " v=", v.toHex,
|
|
||||||
"\n r=", r.pp(sig),
|
|
||||||
"\n R=", w.pp(sig),
|
|
||||||
"\n ", sig.pp(),
|
|
||||||
"\n"
|
|
||||||
xCheck r == w.to(HashKey)
|
|
||||||
|
|
||||||
# Check raw node if given, check nor ref against expected value
|
|
||||||
if s.isValid:
|
|
||||||
let z = db.getVtx(root).toNode(root[0],db).value.digestTo(HashKey)
|
|
||||||
xCheck s == z
|
|
||||||
|
|
||||||
sig.merkleSignDelete(k)
|
|
||||||
gossip.say "*** testShortkeys, post-del (6)", "n=", n, " inx=", inx,
|
|
||||||
"\n k", k.toHex, " v=", v.toHex,
|
|
||||||
"\n ", sig.pp(),
|
|
||||||
"\n"
|
|
||||||
|
|
||||||
let rc = sig.db.check
|
|
||||||
xCheckRc rc.error == (0,0)
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# End
|
|
||||||
# ------------------------------------------------------------------------------
|
|
2
vendor/nimbus-eth2
vendored
2
vendor/nimbus-eth2
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 8f0d910422b12497852f80c22d1cee48a971d246
|
Subproject commit b8a424991d4f8590f5e5364b18ffeabef72e1ff4
|
Loading…
x
Reference in New Issue
Block a user