Use simpler schema when writing transactions, receipts, and withdrawals (#2420)

* Use simpler schema when writing transactions, receipts, and withdrawals

Using MPT not only slow but also take up more spaces than needed.
Aristo will remove older tries and only keep the last block tries.
Using simpler schema will avoid those problems.

* Rename getTransaction to getTransactionByIndex
This commit is contained in:
andri lim 2024-06-29 12:43:17 +07:00 committed by GitHub
parent 55ebd70d1e
commit c24affadee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 187 additions and 126 deletions

View File

@ -108,11 +108,11 @@ proc setBlock*(c: ChainRef; blk: EthBlock): Result[void, string] =
return err("Could not persist header") return err("Could not persist header")
try: try:
c.db.persistTransactions(header.number, blk.transactions) c.db.persistTransactions(header.number, header.txRoot, blk.transactions)
c.db.persistReceipts(vmState.receipts) c.db.persistReceipts(header.receiptsRoot, vmState.receipts)
if blk.withdrawals.isSome: if blk.withdrawals.isSome:
c.db.persistWithdrawals(blk.withdrawals.get) c.db.persistWithdrawals(header.withdrawalsRoot, blk.withdrawals.get)
except CatchableError as exc: except CatchableError as exc:
return err(exc.msg) return err(exc.msg)

View File

@ -169,16 +169,21 @@ proc replaySegment(c: ForkedChainRef, target: Hash256) =
proc writeBaggage(c: ForkedChainRef, target: Hash256) = proc writeBaggage(c: ForkedChainRef, target: Hash256) =
# Write baggage from base+1 to target block # Write baggage from base+1 to target block
template header(): BlockHeader =
blk.blk.header
shouldNotKeyError: shouldNotKeyError:
var prevHash = target var prevHash = target
while prevHash != c.baseHash: while prevHash != c.baseHash:
let blk = c.blocks[prevHash] let blk = c.blocks[prevHash]
c.db.persistTransactions(blk.blk.header.number, blk.blk.transactions) c.db.persistTransactions(header.number, header.txRoot, blk.blk.transactions)
c.db.persistReceipts(blk.receipts) c.db.persistReceipts(header.receiptsRoot, blk.receipts)
discard c.db.persistUncles(blk.blk.uncles) discard c.db.persistUncles(blk.blk.uncles)
if blk.blk.withdrawals.isSome: if blk.blk.withdrawals.isSome:
c.db.persistWithdrawals(blk.blk.withdrawals.get) c.db.persistWithdrawals(
prevHash = blk.blk.header.parentHash header.withdrawalsRoot.expect("WithdrawalsRoot should be verified before"),
blk.blk.withdrawals.get)
prevHash = header.parentHash
func updateBase(c: ForkedChainRef, func updateBase(c: ForkedChainRef,
newBaseHash: Hash256, newBaseHash: Hash256,

View File

@ -170,13 +170,15 @@ proc persistBlocksImpl(
return err("Could not persist header") return err("Could not persist header")
if NoPersistTransactions notin flags: if NoPersistTransactions notin flags:
c.db.persistTransactions(header.number, blk.transactions) c.db.persistTransactions(header.number, header.txRoot, blk.transactions)
if NoPersistReceipts notin flags: if NoPersistReceipts notin flags:
c.db.persistReceipts(vmState.receipts) c.db.persistReceipts(header.receiptsRoot, vmState.receipts)
if NoPersistWithdrawals notin flags and blk.withdrawals.isSome: if NoPersistWithdrawals notin flags and blk.withdrawals.isSome:
c.db.persistWithdrawals(blk.withdrawals.get) c.db.persistWithdrawals(
header.withdrawalsRoot.expect("WithdrawalsRoot should be verified before"),
blk.withdrawals.get)
# update currentBlock *after* we persist it # update currentBlock *after* we persist it
# so the rpc return consistent result # so the rpc return consistent result

View File

@ -61,9 +61,6 @@ type
CoreDbColType* = enum CoreDbColType* = enum
CtGeneric = 2 # columns smaller than 2 are not provided CtGeneric = 2 # columns smaller than 2 are not provided
CtReceipts
CtTxs
CtWithdrawals
CoreDbCaptFlags* {.pure.} = enum CoreDbCaptFlags* {.pure.} = enum
PersistPut PersistPut

View File

@ -114,30 +114,23 @@ iterator findNewAncestors(
iterator getBlockTransactionData*( iterator getBlockTransactionData*(
db: CoreDbRef; db: CoreDbRef;
transactionRoot: Hash256; txRoot: Hash256;
): Blob = ): Blob =
const info = "getBlockTransactionData()" const info = "getBlockTransactionData()"
block body: block body:
if transactionRoot == EMPTY_ROOT_HASH: if txRoot == EMPTY_ROOT_HASH:
break body break body
let
transactionDb = db.ctx.getColumn CtTxs
state = transactionDb.state(updateOk=true).valueOr:
raiseAssert info & ": " & $$error
if state != transactionRoot:
warn logTxt info, transactionRoot, state, error="state mismatch"
break body
var transactionIdx = 0'u64
while true:
let transactionKey = rlp.encode(transactionIdx)
let data = transactionDb.fetch(transactionKey).valueOr:
if error.error != MptNotFound:
warn logTxt info, transactionRoot,
transactionKey, action="fetch()", error=($$error)
break body
yield data
inc transactionIdx
let kvt = db.newKvt()
for idx in 0'u16..<uint16.high:
let key = hashIndexKey(txRoot, idx)
let txData = kvt.getOrEmpty(key).valueOr:
warn logTxt "getBlockTransactionData()",
txRoot, key, action="getOrEmpty()", error=($$error)
break body
if txData.len == 0:
break body
yield txData
iterator getBlockTransactions*( iterator getBlockTransactions*(
db: CoreDbRef; db: CoreDbRef;
@ -158,32 +151,24 @@ iterator getBlockTransactionHashes*(
for encodedTx in db.getBlockTransactionData(blockHeader.txRoot): for encodedTx in db.getBlockTransactionData(blockHeader.txRoot):
yield keccakHash(encodedTx) yield keccakHash(encodedTx)
iterator getWithdrawalsData*( iterator getWithdrawals*(
db: CoreDbRef; db: CoreDbRef;
withdrawalsRoot: Hash256; withdrawalsRoot: Hash256;
): Blob = ): Withdrawal {.raises: [RlpError].} =
const info = "getWithdrawalsData()"
block body: block body:
if withdrawalsRoot == EMPTY_ROOT_HASH: if withdrawalsRoot == EMPTY_ROOT_HASH:
break body break body
let
wddb = db.ctx.getColumn CtWithdrawals
state = wddb.state(updateOk=true).valueOr:
raiseAssert info & ": " & $$error
if state != withdrawalsRoot:
warn logTxt info, withdrawalsRoot, state, error="state mismatch"
break body
var idx = 0
while true:
let wdKey = rlp.encode(idx.uint)
let data = wddb.fetch(wdKey).valueOr:
if error.error != MptNotFound:
warn logTxt "getWithdrawalsData()",
withdrawalsRoot, wdKey, action="fetch()", error=($$error)
break body
yield data
inc idx
let kvt = db.newKvt()
for idx in 0'u16..<uint16.high:
let key = hashIndexKey(withdrawalsRoot, idx)
let data = kvt.getOrEmpty(key).valueOr:
warn logTxt "getWithdrawals()",
withdrawalsRoot, key, action="getOrEmpty()", error=($$error)
break body
if data.len == 0:
break body
yield rlp.decode(data, Withdrawal)
iterator getReceipts*( iterator getReceipts*(
db: CoreDbRef; db: CoreDbRef;
@ -194,23 +179,17 @@ iterator getReceipts*(
block body: block body:
if receiptsRoot == EMPTY_ROOT_HASH: if receiptsRoot == EMPTY_ROOT_HASH:
break body break body
let
receiptDb = db.ctx.getColumn CtReceipts let kvt = db.newKvt()
state = receiptDb.state(updateOk=true).valueOr: for idx in 0'u16..<uint16.high:
raiseAssert info & ": " & $$error let key = hashIndexKey(receiptsRoot, idx)
if state != receiptsRoot: let data = kvt.getOrEmpty(key).valueOr:
warn logTxt info, receiptsRoot, state, error="state mismatch" warn logTxt "getReceipts()",
break body receiptsRoot, key, action="getOrEmpty()", error=($$error)
var receiptIdx = 0
while true:
let receiptKey = rlp.encode(receiptIdx.uint)
let receiptData = receiptDb.fetch(receiptKey).valueOr:
if error.error != MptNotFound:
warn logTxt "getWithdrawalsData()",
receiptsRoot, receiptKey, action="hasKey()", error=($$error)
break body break body
yield rlp.decode(receiptData, Receipt) if data.len == 0:
inc receiptIdx break body
yield rlp.decode(data, Receipt)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Private helpers # Private helpers
@ -535,6 +514,7 @@ proc addBlockNumberToHashLookup*(
proc persistTransactions*( proc persistTransactions*(
db: CoreDbRef; db: CoreDbRef;
blockNumber: BlockNumber; blockNumber: BlockNumber;
txRoot: Hash256;
transactions: openArray[Transaction]; transactions: openArray[Transaction];
) = ) =
const const
@ -543,19 +523,16 @@ proc persistTransactions*(
if transactions.len == 0: if transactions.len == 0:
return return
let let kvt = db.newKvt()
mpt = db.ctx.getColumn(CtTxs, clearData=true)
kvt = db.newKvt()
for idx, tx in transactions: for idx, tx in transactions:
let let
encodedKey = rlp.encode(idx.uint)
encodedTx = rlp.encode(tx) encodedTx = rlp.encode(tx)
txHash = keccakHash(encodedTx) txHash = keccakHash(encodedTx)
blockKey = transactionHashToBlockKey(txHash) blockKey = transactionHashToBlockKey(txHash)
txKey: TransactionKey = (blockNumber, idx.uint) txKey: TransactionKey = (blockNumber, idx.uint)
mpt.merge(encodedKey, encodedTx).isOkOr: key = hashIndexKey(txRoot, idx.uint16)
warn logTxt info, idx, action="merge()", error=($$error) kvt.put(key, encodedTx).isOkOr:
warn logTxt info, idx, action="put()", error=($$error)
return return
kvt.put(blockKey.toOpenArray, rlp.encode(txKey)).isOkOr: kvt.put(blockKey.toOpenArray, rlp.encode(txKey)).isOkOr:
trace logTxt info, blockKey, action="put()", error=($$error) trace logTxt info, blockKey, action="put()", error=($$error)
@ -579,32 +556,29 @@ proc forgetHistory*(
# delete blockHash->header, stateRoot->blockNum # delete blockHash->header, stateRoot->blockNum
discard kvt.del(genericHashKey(blockHash).toOpenArray) discard kvt.del(genericHashKey(blockHash).toOpenArray)
proc getTransaction*( proc getTransactionByIndex*(
db: CoreDbRef; db: CoreDbRef;
txRoot: Hash256; txRoot: Hash256;
txIndex: uint64; txIndex: uint16;
res: var Transaction; res: var Transaction;
): bool = ): bool =
const const
info = "getTransaction()" info = "getTransaction()"
let
clearOk = txRoot == EMPTY_ROOT_HASH let kvt = db.newKvt()
mpt = db.ctx.getColumn(CtTxs, clearData=clearOk) let key = hashIndexKey(txRoot, txIndex)
if not clearOk: let txData = kvt.getOrEmpty(key).valueOr:
let state = mpt.state(updateOk=true).valueOr: warn logTxt "getTransaction()",
raiseAssert info & ": " & $$error txRoot, key, action="getOrEmpty()", error=($$error)
if state != txRoot: return false
warn logTxt info, txRoot, state, error="state mismatch" if txData.len == 0:
return false return false
let
txData = mpt.fetch(rlp.encode(txIndex)).valueOr:
if error.error != MptNotFound:
warn logTxt info, txIndex, error=($$error)
return false
try: try:
res = rlp.decode(txData, Transaction) res = rlp.decode(txData, Transaction)
except RlpError as e: except RlpError as exc:
warn logTxt info, txRoot, action="rlp.decode()", name=($e.name), msg=e.msg warn logTxt info,
txRoot, action="rlp.decode()", error=exc.msg
return false return false
true true
@ -614,24 +588,19 @@ proc getTransactionCount*(
): int = ): int =
const const
info = "getTransactionCount()" info = "getTransactionCount()"
let
clearOk = txRoot == EMPTY_ROOT_HASH let kvt = db.newKvt()
mpt = db.ctx.getColumn(CtTxs, clearData=clearOk) var txCount = 0'u16
if not clearOk:
let state = mpt.state(updateOk=true).valueOr:
raiseAssert info & ": " & $$error
if state != txRoot:
warn logTxt info, txRoot, state, error="state mismatch"
return 0
var txCount = 0
while true: while true:
let hasPath = mpt.hasPath(rlp.encode(txCount.uint)).valueOr: let key = hashIndexKey(txRoot, txCount)
warn logTxt info, txCount, action="hasPath()", error=($$error) let yes = kvt.hasKey(key).valueOr:
warn logTxt info,
txRoot, key, action="hasKey()", error=($$error)
return 0 return 0
if hasPath: if yes:
inc txCount inc txCount
else: else:
return txCount return txCount.int
doAssert(false, "unreachable") doAssert(false, "unreachable")
@ -667,15 +636,17 @@ proc getUncles*(
proc persistWithdrawals*( proc persistWithdrawals*(
db: CoreDbRef; db: CoreDbRef;
withdrawalsRoot: Hash256;
withdrawals: openArray[Withdrawal]; withdrawals: openArray[Withdrawal];
) = ) =
const info = "persistWithdrawals()" const info = "persistWithdrawals()"
if withdrawals.len == 0: if withdrawals.len == 0:
return return
let mpt = db.ctx.getColumn(CtWithdrawals, clearData=true) let kvt = db.newKvt()
for idx, wd in withdrawals: for idx, wd in withdrawals:
mpt.merge(rlp.encode(idx.uint), rlp.encode(wd)).isOkOr: let key = hashIndexKey(withdrawalsRoot, idx.uint16)
warn logTxt info, idx, error=($$error) kvt.put(key, rlp.encode(wd)).isOkOr:
warn logTxt info, idx, action="put()", error=($$error)
return return
proc getWithdrawals*( proc getWithdrawals*(
@ -683,8 +654,8 @@ proc getWithdrawals*(
withdrawalsRoot: Hash256; withdrawalsRoot: Hash256;
): seq[Withdrawal] ): seq[Withdrawal]
{.gcsafe, raises: [RlpError].} = {.gcsafe, raises: [RlpError].} =
for encodedWd in db.getWithdrawalsData(withdrawalsRoot): for wd in db.getWithdrawals(withdrawalsRoot):
result.add(rlp.decode(encodedWd, Withdrawal)) result.add(wd)
proc getTransactions*( proc getTransactions*(
db: CoreDbRef; db: CoreDbRef;
@ -837,14 +808,17 @@ proc setHead*(
proc persistReceipts*( proc persistReceipts*(
db: CoreDbRef; db: CoreDbRef;
receiptsRoot: Hash256;
receipts: openArray[Receipt]; receipts: openArray[Receipt];
) = ) =
const info = "persistReceipts()" const info = "persistReceipts()"
if receipts.len == 0: if receipts.len == 0:
return return
let mpt = db.ctx.getColumn(CtReceipts, clearData=true)
let kvt = db.newKvt()
for idx, rec in receipts: for idx, rec in receipts:
mpt.merge(rlp.encode(idx.uint), rlp.encode(rec)).isOkOr: let key = hashIndexKey(receiptsRoot, idx.uint16)
kvt.put(key, rlp.encode(rec)).isOkOr:
warn logTxt info, idx, action="merge()", error=($$error) warn logTxt info, idx, action="merge()", error=($$error)
proc getReceipts*( proc getReceipts*(

View File

@ -33,6 +33,8 @@ type
data*: array[33, byte] data*: array[33, byte]
dataEndPos*: uint8 # the last populated position in the data dataEndPos*: uint8 # the last populated position in the data
HashIndexKey* = array[34, byte]
func genericHashKey*(h: Hash256): DbKey {.inline.} = func genericHashKey*(h: Hash256): DbKey {.inline.} =
result.data[0] = byte ord(genericHash) result.data[0] = byte ord(genericHash)
result.data[1 .. 32] = h.data result.data[1 .. 32] = h.data
@ -102,6 +104,11 @@ func skeletonBodyKey*(h: Hash256): DbKey {.inline.} =
result.data[1 .. 32] = h.data result.data[1 .. 32] = h.data
result.dataEndPos = uint8 32 result.dataEndPos = uint8 32
func hashIndexKey*(hash: Hash256, index: uint16): HashIndexKey =
result[0..31] = hash.data
result[32] = byte(index and 0xFF)
result[33] = byte((index shl 8) and 0xFF)
template toOpenArray*(k: DbKey): openArray[byte] = template toOpenArray*(k: DbKey): openArray[byte] =
k.data.toOpenArray(0, int(k.dataEndPos)) k.data.toOpenArray(0, int(k.dataEndPos))

View File

@ -315,7 +315,7 @@ proc getWithdrawals(ctx: GraphqlContextRef, header: common.BlockHeader): RespRes
proc getTxAt(ctx: GraphqlContextRef, header: common.BlockHeader, index: uint64): RespResult = proc getTxAt(ctx: GraphqlContextRef, header: common.BlockHeader, index: uint64): RespResult =
try: try:
var tx: Transaction var tx: Transaction
if getTransaction(ctx.chainDB, header.txRoot, index, tx): if getTransactionByIndex(ctx.chainDB, header.txRoot, index.uint16, tx):
let txn = txNode(ctx, tx, index, header.number, header.baseFeePerGas) let txn = txNode(ctx, tx, index, header.number, header.baseFeePerGas)
var i = 0'u64 var i = 0'u64

View File

@ -11,8 +11,12 @@
import import
std/[sequtils, times, tables, typetraits], std/[sequtils, times, tables, typetraits],
json_rpc/rpcserver, stint, stew/byteutils, json_rpc/rpcserver,
json_serialization, web3/conversions, json_serialization/stew/results, stint,
stew/byteutils,
json_serialization,
web3/conversions,
json_serialization/stew/results,
eth/common/eth_types_json_serialization, eth/common/eth_types_json_serialization,
eth/[keys, rlp, p2p], eth/[keys, rlp, p2p],
".."/[transaction, evm/state, constants], ".."/[transaction, evm/state, constants],
@ -414,7 +418,7 @@ proc setupEthRpc*(
let header = chainDB.getBlockHeader(txDetails.blockNumber) let header = chainDB.getBlockHeader(txDetails.blockNumber)
var tx: Transaction var tx: Transaction
if chainDB.getTransaction(header.txRoot, txDetails.index, tx): if chainDB.getTransactionByIndex(header.txRoot, uint16(txDetails.index), tx):
result = populateTransactionObject(tx, Opt.some(header), Opt.some(txDetails.index)) result = populateTransactionObject(tx, Opt.some(header), Opt.some(txDetails.index))
server.rpc("eth_getTransactionByBlockHashAndIndex") do(data: Web3Hash, quantity: Web3Quantity) -> TransactionObject: server.rpc("eth_getTransactionByBlockHashAndIndex") do(data: Web3Hash, quantity: Web3Quantity) -> TransactionObject:
@ -429,7 +433,7 @@ proc setupEthRpc*(
return nil return nil
var tx: Transaction var tx: Transaction
if chainDB.getTransaction(header.txRoot, index, tx): if chainDB.getTransactionByIndex(header.txRoot, uint16(index), tx):
result = populateTransactionObject(tx, Opt.some(header), Opt.some(index)) result = populateTransactionObject(tx, Opt.some(header), Opt.some(index))
else: else:
result = nil result = nil
@ -444,7 +448,7 @@ proc setupEthRpc*(
index = uint64(quantity) index = uint64(quantity)
var tx: Transaction var tx: Transaction
if chainDB.getTransaction(header.txRoot, index, tx): if chainDB.getTransactionByIndex(header.txRoot, uint16(index), tx):
result = populateTransactionObject(tx, Opt.some(header), Opt.some(index)) result = populateTransactionObject(tx, Opt.some(header), Opt.some(index))
else: else:
result = nil result = nil
@ -461,7 +465,7 @@ proc setupEthRpc*(
let header = chainDB.getBlockHeader(txDetails.blockNumber) let header = chainDB.getBlockHeader(txDetails.blockNumber)
var tx: Transaction var tx: Transaction
if not chainDB.getTransaction(header.txRoot, txDetails.index, tx): if not chainDB.getTransactionByIndex(header.txRoot, uint16(txDetails.index), tx):
return nil return nil
var var

View File

@ -24,7 +24,7 @@ proc generatePrestate*(nimbus, geth: JsonNode, blockNumber: BlockNumber, parent:
kvt = chainDB.newKvt() kvt = chainDB.newKvt()
discard chainDB.setHead(parent, true) discard chainDB.setHead(parent, true)
chainDB.persistTransactions(blockNumber, blk.transactions) chainDB.persistTransactions(blockNumber, header.txRoot, blk.transactions)
discard chainDB.persistUncles(blk.uncles) discard chainDB.persistUncles(blk.uncles)
kvt.put(genericHashKey(headerHash).toOpenArray, rlp.encode(header)).isOkOr: kvt.put(genericHashKey(headerHash).toOpenArray, rlp.encode(header)).isOkOr:

View File

@ -87,8 +87,8 @@ proc persistFixtureBlock(chainDB: CoreDbRef) =
# Manually inserting header to avoid any parent checks # Manually inserting header to avoid any parent checks
discard chainDB.newKvt.put(genericHashKey(header.blockHash).toOpenArray, rlp.encode(header)) discard chainDB.newKvt.put(genericHashKey(header.blockHash).toOpenArray, rlp.encode(header))
chainDB.addBlockNumberToHashLookup(header) chainDB.addBlockNumberToHashLookup(header)
chainDB.persistTransactions(header.number, getBlockBody4514995().transactions) chainDB.persistTransactions(header.number, header.txRoot, getBlockBody4514995().transactions)
chainDB.persistReceipts(getReceipts4514995()) chainDB.persistReceipts(header.receiptsRoot, getReceipts4514995())
proc setupEnv(com: CommonRef, signer, ks2: EthAddress, ctx: EthContext): TestEnv = proc setupEnv(com: CommonRef, signer, ks2: EthAddress, ctx: EthContext): TestEnv =
var var
@ -153,9 +153,9 @@ proc setupEnv(com: CommonRef, signer, ks2: EthAddress, ctx: EthContext): TestEnv
signedTx1 = signTransaction(unsignedTx1, acc.privateKey, com.chainId, eip155) signedTx1 = signTransaction(unsignedTx1, acc.privateKey, com.chainId, eip155)
signedTx2 = signTransaction(unsignedTx2, acc.privateKey, com.chainId, eip155) signedTx2 = signTransaction(unsignedTx2, acc.privateKey, com.chainId, eip155)
txs = [signedTx1, signedTx2] txs = [signedTx1, signedTx2]
com.db.persistTransactions(blockNumber, txs)
let txRoot = com.db.ctx.getColumn(CtTxs).state(updateOk=true).valueOr(EMPTY_ROOT_HASH) let txRoot = calcTxRoot(txs)
com.db.persistTransactions(blockNumber, txRoot, txs)
vmState.receipts = newSeq[Receipt](txs.len) vmState.receipts = newSeq[Receipt](txs.len)
vmState.cumulativeGasUsed = 0 vmState.cumulativeGasUsed = 0

View File

@ -337,6 +337,77 @@ proc runTxHeadDelta(noisy = true) =
balance = sdb.getBalance(recipient) balance = sdb.getBalance(recipient)
check balance == expected check balance == expected
proc runGetBlockBodyTest() =
var
env = initEnv(Cancun)
blockTime = EthTime.now()
parentHeader: BlockHeader
currentHeader: BlockHeader
suite "Test get parent transactions after persistBlock":
test "TxPool create first block":
let
tx1 = env.makeTx(recipient, 1.u256)
tx2 = env.makeTx(recipient, 2.u256)
check env.xp.addLocal(PooledTransaction(tx: tx1), true).isOk
check env.xp.addLocal(PooledTransaction(tx: tx2), true).isOk
env.com.pos.prevRandao = prevRandao
env.com.pos.feeRecipient = feeRecipient
env.com.pos.timestamp = blockTime
let r = env.xp.assembleBlock()
if r.isErr:
check false
return
let blk = r.get.blk
check env.chain.persistBlocks([blk]).isOk
parentHeader = blk.header
check env.xp.smartHead(parentHeader)
check blk.transactions.len == 2
test "TxPool create second block":
let
tx1 = env.makeTx(recipient, 3.u256)
tx2 = env.makeTx(recipient, 4.u256)
tx3 = env.makeTx(recipient, 5.u256)
check env.xp.addLocal(PooledTransaction(tx: tx1), true).isOk
check env.xp.addLocal(PooledTransaction(tx: tx2), true).isOk
check env.xp.addLocal(PooledTransaction(tx: tx3), true).isOk
env.com.pos.prevRandao = prevRandao
env.com.pos.feeRecipient = feeRecipient
env.com.pos.timestamp = blockTime + 1
let r = env.xp.assembleBlock()
if r.isErr:
check false
return
let blk = r.get.blk
check env.chain.persistBlocks([blk]).isOk
currentHeader = blk.header
check env.xp.smartHead(currentHeader)
check blk.transactions.len == 3
test "Get current block body":
var body: BlockBody
check env.com.db.getBlockBody(currentHeader, body)
check body.transactions.len == 3
check env.com.db.getReceipts(currentHeader.receiptsRoot).len == 3
check env.com.db.getTransactionCount(currentHeader.txRoot) == 3
test "Get parent block body":
# Make sure parent baggage doesn't swept away by aristo
var body: BlockBody
check env.com.db.getBlockBody(parentHeader, body)
check body.transactions.len == 2
check env.com.db.getReceipts(parentHeader.receiptsRoot).len == 2
check env.com.db.getTransactionCount(parentHeader.txRoot) == 2
proc txPool2Main*() = proc txPool2Main*() =
const const
noisy = defined(debug) noisy = defined(debug)
@ -346,6 +417,7 @@ proc txPool2Main*() =
runTxPoolPosTest() runTxPoolPosTest()
runTxPoolBlobhashTest() runTxPoolBlobhashTest()
noisy.runTxHeadDelta noisy.runTxHeadDelta
runGetBlockBodyTest()
when isMainModule: when isMainModule:
txPool2Main() txPool2Main()