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:
parent
55ebd70d1e
commit
c24affadee
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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*(
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue