mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 05:14:14 +00:00
Fix TxPool when handling EIP-4844 blob tx (#1831)
* Fix TxPool when handling EIP-4844 blob tx
This commit is contained in:
parent
14ee5f6820
commit
7169c846a3
@ -31,7 +31,7 @@ func wdRoot(x: Option[seq[WithdrawalV1]]): Option[common.Hash256]
|
|||||||
func txRoot(list: openArray[Web3Tx]): common.Hash256
|
func txRoot(list: openArray[Web3Tx]): common.Hash256
|
||||||
{.gcsafe, raises:[RlpError].} =
|
{.gcsafe, raises:[RlpError].} =
|
||||||
{.nosideEffect.}:
|
{.nosideEffect.}:
|
||||||
calcTxRoot(ethTxs list)
|
calcTxRoot(ethTxs(list, removeBlobs = true))
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Public functions
|
# Public functions
|
||||||
|
@ -127,11 +127,15 @@ func ethWithdrawals*(x: Option[seq[WithdrawalV1]]):
|
|||||||
func ethTx*(x: Web3Tx): common.Transaction {.gcsafe, raises:[RlpError].} =
|
func ethTx*(x: Web3Tx): common.Transaction {.gcsafe, raises:[RlpError].} =
|
||||||
result = rlp.decode(distinctBase x, common.Transaction)
|
result = rlp.decode(distinctBase x, common.Transaction)
|
||||||
|
|
||||||
func ethTxs*(list: openArray[Web3Tx]):
|
func ethTxs*(list: openArray[Web3Tx], removeBlobs = false):
|
||||||
seq[common.Transaction] {.gcsafe, raises:[RlpError].} =
|
seq[common.Transaction] {.gcsafe, raises:[RlpError].} =
|
||||||
result = newSeqOfCap[common.Transaction](list.len)
|
result = newSeqOfCap[common.Transaction](list.len)
|
||||||
for x in list:
|
if removeBlobs:
|
||||||
result.add ethTx(x)
|
for x in list:
|
||||||
|
result.add ethTx(x).removeNetworkPayload
|
||||||
|
else:
|
||||||
|
for x in list:
|
||||||
|
result.add ethTx(x)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Eth types to Web3 types
|
# Eth types to Web3 types
|
||||||
|
@ -169,7 +169,7 @@ func validateEip4844Header*(
|
|||||||
|
|
||||||
proc validateBlobTransactionWrapper*(tx: Transaction):
|
proc validateBlobTransactionWrapper*(tx: Transaction):
|
||||||
Result[void, string] {.raises: [].} =
|
Result[void, string] {.raises: [].} =
|
||||||
if not tx.networkPayload.isNil:
|
if tx.networkPayload.isNil:
|
||||||
return err("tx wrapper is none")
|
return err("tx wrapper is none")
|
||||||
|
|
||||||
# note: assert blobs are not malformatted
|
# note: assert blobs are not malformatted
|
||||||
|
@ -921,6 +921,22 @@ proc inPoolAndOk*(xp: TxPoolRef; txHash: Hash256): bool =
|
|||||||
if res.isErr: return false
|
if res.isErr: return false
|
||||||
res.get().reject == txInfoOk
|
res.get().reject == txInfoOk
|
||||||
|
|
||||||
|
proc inPoolAndReason*(xp: TxPoolRef; txHash: Hash256): Result[void, string] =
|
||||||
|
let res = xp.getItem(txHash)
|
||||||
|
if res.isErr:
|
||||||
|
# try to look in rejecteds
|
||||||
|
let r = xp.txDB.byRejects.eq(txHash)
|
||||||
|
if r.isErr:
|
||||||
|
return err("cannot find tx in txpool")
|
||||||
|
else:
|
||||||
|
return err(r.get().rejectInfo)
|
||||||
|
|
||||||
|
let item = res.get()
|
||||||
|
if item.reject == txInfoOk:
|
||||||
|
return ok()
|
||||||
|
else:
|
||||||
|
return err(item.rejectInfo)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# End
|
# End
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -159,7 +159,7 @@ proc cost*(tx: Transaction): UInt256 =
|
|||||||
proc effectiveGasTip*(tx: Transaction; baseFee: GasPrice): GasPriceEx =
|
proc effectiveGasTip*(tx: Transaction; baseFee: GasPrice): GasPriceEx =
|
||||||
## The effective miner gas tip for the globally argument `baseFee`. The
|
## The effective miner gas tip for the globally argument `baseFee`. The
|
||||||
## result (which is a price per gas) might well be negative.
|
## result (which is a price per gas) might well be negative.
|
||||||
if tx.txType != TxEip1559:
|
if tx.txType < TxEip1559:
|
||||||
(tx.gasPrice - baseFee.int64).GasPriceEx
|
(tx.gasPrice - baseFee.int64).GasPriceEx
|
||||||
else:
|
else:
|
||||||
# London, EIP1559
|
# London, EIP1559
|
||||||
@ -205,6 +205,13 @@ proc tx*(item: TxItemRef): Transaction =
|
|||||||
## Getter
|
## Getter
|
||||||
item.tx
|
item.tx
|
||||||
|
|
||||||
|
func rejectInfo*(item: TxItemRef): string =
|
||||||
|
## Getter
|
||||||
|
result = $item.reject
|
||||||
|
if item.info.len > 0:
|
||||||
|
result.add ": "
|
||||||
|
result.add item.info
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Public functions, setters
|
# Public functions, setters
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@ -217,6 +224,10 @@ proc `reject=`*(item: TxItemRef; val: TxInfo) =
|
|||||||
## Setter
|
## Setter
|
||||||
item.reject = val
|
item.reject = val
|
||||||
|
|
||||||
|
proc `info=`*(item: TxItemRef; val: string) =
|
||||||
|
## Setter
|
||||||
|
item.info = val
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Public functions, pretty printing and debugging
|
# Public functions, pretty printing and debugging
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -45,7 +45,7 @@ type
|
|||||||
## Temporary sorter list
|
## Temporary sorter list
|
||||||
SortedSet[AccountNonce,TxItemRef]
|
SortedSet[AccountNonce,TxItemRef]
|
||||||
|
|
||||||
AccouuntNonceTab = ##\
|
AccountNonceTab = ##\
|
||||||
## Temporary sorter table
|
## Temporary sorter table
|
||||||
Table[EthAddress,NonceList]
|
Table[EthAddress,NonceList]
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ logScope:
|
|||||||
# Private helper
|
# Private helper
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc getItemList(tab: var AccouuntNonceTab; key: EthAddress): var NonceList
|
proc getItemList(tab: var AccountNonceTab; key: EthAddress): var NonceList
|
||||||
{.gcsafe,raises: [KeyError].} =
|
{.gcsafe,raises: [KeyError].} =
|
||||||
if not tab.hasKey(key):
|
if not tab.hasKey(key):
|
||||||
tab[key] = NonceList.init
|
tab[key] = NonceList.init
|
||||||
@ -176,18 +176,19 @@ proc addTxs*(xp: TxPoolRef;
|
|||||||
## basket, this list keeps the items with the highest nonce (handy for
|
## basket, this list keeps the items with the highest nonce (handy for
|
||||||
## chasing nonce gaps after a back-move of the block chain head.)
|
## chasing nonce gaps after a back-move of the block chain head.)
|
||||||
##
|
##
|
||||||
var accTab: AccouuntNonceTab
|
var accTab: AccountNonceTab
|
||||||
|
|
||||||
for tx in txs.items:
|
for tx in txs.items:
|
||||||
var reason: TxInfo
|
var reason: TxInfo
|
||||||
|
|
||||||
if tx.txType == TxEip4844:
|
if tx.txType == TxEip4844:
|
||||||
let res = tx.validateBlobTransactionWrapper()
|
let res = tx.validateBlobTransactionWrapper()
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
# move item to waste basket
|
# move item to waste basket
|
||||||
reason = txInfoErrInvalidBlob
|
reason = txInfoErrInvalidBlob
|
||||||
xp.txDB.reject(tx, reason, txItemPending, res.error)
|
xp.txDB.reject(tx, reason, txItemPending, res.error)
|
||||||
invalidTxMeter(1)
|
invalidTxMeter(1)
|
||||||
|
continue
|
||||||
|
|
||||||
# Create tx item wrapper, preferably recovered from waste basket
|
# Create tx item wrapper, preferably recovered from waste basket
|
||||||
let rcTx = xp.recoverItem(tx, txItemPending, info)
|
let rcTx = xp.recoverItem(tx, txItemPending, info)
|
||||||
|
@ -37,7 +37,11 @@ logScope:
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc checkTxBasic(xp: TxPoolRef; item: TxItemRef): bool =
|
proc checkTxBasic(xp: TxPoolRef; item: TxItemRef): bool =
|
||||||
validateTxBasic(item.tx, xp.chain.nextFork).isOk
|
let res = validateTxBasic(item.tx.removeNetworkPayload, xp.chain.nextFork)
|
||||||
|
if res.isOk:
|
||||||
|
return true
|
||||||
|
item.info = res.error
|
||||||
|
return false
|
||||||
|
|
||||||
proc checkTxNonce(xp: TxPoolRef; item: TxItemRef): bool
|
proc checkTxNonce(xp: TxPoolRef; item: TxItemRef): bool
|
||||||
{.gcsafe,raises: [CatchableError].} =
|
{.gcsafe,raises: [CatchableError].} =
|
||||||
@ -224,7 +228,7 @@ proc classifyValidatePacked*(xp: TxPoolRef;
|
|||||||
tx = item.tx.eip1559TxNormalization(xp.chain.baseFee.GasInt)
|
tx = item.tx.eip1559TxNormalization(xp.chain.baseFee.GasInt)
|
||||||
excessBlobGas = calcExcessBlobGas(vmState.parent)
|
excessBlobGas = calcExcessBlobGas(vmState.parent)
|
||||||
|
|
||||||
roDB.validateTransaction(tx, item.sender, gasLimit, baseFee, excessBlobGas, fork).isOk
|
roDB.validateTransaction(tx.removeNetworkPayload, item.sender, gasLimit, baseFee, excessBlobGas, fork).isOk
|
||||||
|
|
||||||
proc classifyPacked*(xp: TxPoolRef; gasBurned, moreBurned: GasInt): bool =
|
proc classifyPacked*(xp: TxPoolRef; gasBurned, moreBurned: GasInt): bool =
|
||||||
## Classifier for *packing* (i.e. adding up `gasUsed` values after executing
|
## Classifier for *packing* (i.e. adding up `gasUsed` values after executing
|
||||||
|
@ -1418,10 +1418,11 @@ proc sendRawTransaction(ud: RootRef, params: Args, parent: Node): RespResult {.a
|
|||||||
|
|
||||||
ctx.txPool.add(tx)
|
ctx.txPool.add(tx)
|
||||||
|
|
||||||
if ctx.txPool.inPoolAndOk(txHash):
|
let res = ctx.txPool.inPoolAndReason(txHash)
|
||||||
|
if res.isOk:
|
||||||
return resp(txHash)
|
return resp(txHash)
|
||||||
else:
|
else:
|
||||||
return err("transaction rejected by txpool")
|
return err(res.error)
|
||||||
|
|
||||||
except CatchableError as em:
|
except CatchableError as em:
|
||||||
return err("failed to process raw transaction: " & em.msg)
|
return err("failed to process raw transaction: " & em.msg)
|
||||||
|
@ -274,8 +274,9 @@ proc setupEthRpc*(
|
|||||||
txHash = rlpHash(signedTx)
|
txHash = rlpHash(signedTx)
|
||||||
|
|
||||||
txPool.add(signedTx)
|
txPool.add(signedTx)
|
||||||
if not txPool.inPoolAndOk(txHash):
|
let res = txPool.inPoolAndReason(txHash)
|
||||||
raise newException(ValueError, "transaction rejected by txpool")
|
if res.isErr:
|
||||||
|
raise newException(ValueError, res.error)
|
||||||
result = txHash.ethHashStr
|
result = txHash.ethHashStr
|
||||||
|
|
||||||
server.rpc("eth_call") do(call: EthCall, quantityTag: string) -> HexDataStr:
|
server.rpc("eth_call") do(call: EthCall, quantityTag: string) -> HexDataStr:
|
||||||
@ -337,17 +338,19 @@ proc setupEthRpc*(
|
|||||||
##
|
##
|
||||||
## data: hash of a transaction.
|
## data: hash of a transaction.
|
||||||
## Returns requested transaction information.
|
## Returns requested transaction information.
|
||||||
let txDetails = chainDB.getTransactionKey(data.toHash())
|
let txHash = data.toHash()
|
||||||
|
let res = txPool.getItem(txHash)
|
||||||
|
if res.isOk:
|
||||||
|
return some(populateTransactionObject(res.get().tx))
|
||||||
|
|
||||||
|
let txDetails = chainDB.getTransactionKey(txHash)
|
||||||
if txDetails.index < 0:
|
if txDetails.index < 0:
|
||||||
return none(TransactionObject)
|
return none(TransactionObject)
|
||||||
|
|
||||||
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.getTransaction(header.txRoot, txDetails.index, tx):
|
||||||
result = some(populateTransactionObject(tx, header, txDetails.index))
|
result = some(populateTransactionObject(tx, some(header), some(txDetails.index)))
|
||||||
|
|
||||||
# TODO: if the requested transaction not in blockchain
|
|
||||||
# try to look for pending transaction in txpool
|
|
||||||
|
|
||||||
server.rpc("eth_getTransactionByBlockHashAndIndex") do(data: EthHashStr, quantity: HexQuantityStr) -> Option[TransactionObject]:
|
server.rpc("eth_getTransactionByBlockHashAndIndex") do(data: EthHashStr, quantity: HexQuantityStr) -> Option[TransactionObject]:
|
||||||
## Returns information about a transaction by block hash and transaction index position.
|
## Returns information about a transaction by block hash and transaction index position.
|
||||||
@ -362,7 +365,7 @@ proc setupEthRpc*(
|
|||||||
|
|
||||||
var tx: Transaction
|
var tx: Transaction
|
||||||
if chainDB.getTransaction(header.txRoot, index, tx):
|
if chainDB.getTransaction(header.txRoot, index, tx):
|
||||||
result = some(populateTransactionObject(tx, header, index))
|
result = some(populateTransactionObject(tx, some(header), some(index)))
|
||||||
|
|
||||||
server.rpc("eth_getTransactionByBlockNumberAndIndex") do(quantityTag: string, quantity: HexQuantityStr) -> Option[TransactionObject]:
|
server.rpc("eth_getTransactionByBlockNumberAndIndex") do(quantityTag: string, quantity: HexQuantityStr) -> Option[TransactionObject]:
|
||||||
## Returns information about a transaction by block number and transaction index position.
|
## Returns information about a transaction by block number and transaction index position.
|
||||||
@ -375,7 +378,7 @@ proc setupEthRpc*(
|
|||||||
|
|
||||||
var tx: Transaction
|
var tx: Transaction
|
||||||
if chainDB.getTransaction(header.txRoot, index, tx):
|
if chainDB.getTransaction(header.txRoot, index, tx):
|
||||||
result = some(populateTransactionObject(tx, header, index))
|
result = some(populateTransactionObject(tx, some(header), some(index)))
|
||||||
|
|
||||||
server.rpc("eth_getTransactionReceipt") do(data: EthHashStr) -> Option[ReceiptObject]:
|
server.rpc("eth_getTransactionReceipt") do(data: EthHashStr) -> Option[ReceiptObject]:
|
||||||
## Returns the receipt of a transaction by transaction hash.
|
## Returns the receipt of a transaction by transaction hash.
|
||||||
|
@ -164,11 +164,14 @@ proc toAccessTupleList(list: openArray[AccessPair]): seq[AccessTuple] =
|
|||||||
for x in list:
|
for x in list:
|
||||||
result.add toAccessTuple(x)
|
result.add toAccessTuple(x)
|
||||||
|
|
||||||
proc populateTransactionObject*(tx: Transaction, header: BlockHeader, txIndex: int): TransactionObject
|
proc populateTransactionObject*(tx: Transaction,
|
||||||
|
header: Option[BlockHeader] = none(BlockHeader),
|
||||||
|
txIndex: Option[int] = none(int)): TransactionObject
|
||||||
{.gcsafe, raises: [ValidationError].} =
|
{.gcsafe, raises: [ValidationError].} =
|
||||||
result.`type` = encodeQuantity(tx.txType.uint64)
|
result.`type` = encodeQuantity(tx.txType.uint64)
|
||||||
result.blockHash = some(header.hash)
|
if header.isSome:
|
||||||
result.blockNumber = some(encodeQuantity(header.blockNumber))
|
result.blockHash = some(header.get().hash)
|
||||||
|
result.blockNumber = some(encodeQuantity(header.get().blockNumber))
|
||||||
result.`from` = tx.getSender()
|
result.`from` = tx.getSender()
|
||||||
result.gas = encodeQuantity(tx.gasLimit.uint64)
|
result.gas = encodeQuantity(tx.gasLimit.uint64)
|
||||||
result.gasPrice = encodeQuantity(tx.gasPrice.uint64)
|
result.gasPrice = encodeQuantity(tx.gasPrice.uint64)
|
||||||
@ -176,7 +179,8 @@ proc populateTransactionObject*(tx: Transaction, header: BlockHeader, txIndex: i
|
|||||||
result.input = tx.payload
|
result.input = tx.payload
|
||||||
result.nonce = encodeQuantity(tx.nonce.uint64)
|
result.nonce = encodeQuantity(tx.nonce.uint64)
|
||||||
result.to = some(tx.destination)
|
result.to = some(tx.destination)
|
||||||
result.transactionIndex = some(encodeQuantity(txIndex.uint64))
|
if txIndex.isSome:
|
||||||
|
result.transactionIndex = some(encodeQuantity(txIndex.get().uint64))
|
||||||
result.value = encodeQuantity(tx.value)
|
result.value = encodeQuantity(tx.value)
|
||||||
result.v = encodeQuantity(tx.V.uint)
|
result.v = encodeQuantity(tx.V.uint)
|
||||||
result.r = encodeQuantity(tx.R)
|
result.r = encodeQuantity(tx.R)
|
||||||
@ -228,7 +232,7 @@ proc populateBlockObject*(header: BlockHeader, chain: CoreDbRef, fullTx: bool, i
|
|||||||
if fullTx:
|
if fullTx:
|
||||||
var i = 0
|
var i = 0
|
||||||
for tx in chain.getBlockTransactions(header):
|
for tx in chain.getBlockTransactions(header):
|
||||||
result.transactions.add %(populateTransactionObject(tx, header, i))
|
result.transactions.add %(populateTransactionObject(tx, some(header), some(i)))
|
||||||
inc i
|
inc i
|
||||||
else:
|
else:
|
||||||
for x in chain.getBlockTransactionHashes(header):
|
for x in chain.getBlockTransactionHashes(header):
|
||||||
|
@ -472,7 +472,7 @@ mutation {
|
|||||||
sendRawTransaction(data: "0xf86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba077c7cd36820c71821c1aed59de46e70e701c4a8dd89c9ba508ab722210f60da8a03f29825d40c7c3f7bff3ca69267e0f3fb74b2d18b8c2c4e3c135b5d3b06e288d")
|
sendRawTransaction(data: "0xf86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba077c7cd36820c71821c1aed59de46e70e701c4a8dd89c9ba508ab722210f60da8a03f29825d40c7c3f7bff3ca69267e0f3fb74b2d18b8c2c4e3c135b5d3b06e288d")
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
errors = ["[2, 3]: Fatal: Field 'sendRawTransaction' cannot be resolved: \"transaction rejected by txpool\": @[\"sendRawTransaction\"]"]
|
errors = ["[2, 3]: Fatal: Field 'sendRawTransaction' cannot be resolved: \"Tx rejected by basic validator\": @[\"sendRawTransaction\"]"]
|
||||||
result = """null"""
|
result = """null"""
|
||||||
|
|
||||||
[[units]]
|
[[units]]
|
||||||
|
@ -7,7 +7,6 @@ import
|
|||||||
../nimbus/core/clique/[clique_sealer, clique_desc],
|
../nimbus/core/clique/[clique_sealer, clique_desc],
|
||||||
../nimbus/[config, transaction, constants],
|
../nimbus/[config, transaction, constants],
|
||||||
../nimbus/core/tx_pool,
|
../nimbus/core/tx_pool,
|
||||||
../nimbus/core/tx_pool/tx_item,
|
|
||||||
../nimbus/core/casper,
|
../nimbus/core/casper,
|
||||||
../nimbus/core/executor,
|
../nimbus/core/executor,
|
||||||
../nimbus/common/common,
|
../nimbus/common/common,
|
||||||
@ -269,11 +268,6 @@ proc runTxPoolPosTest*() =
|
|||||||
let bal = sdb.getBalance(feeRecipient)
|
let bal = sdb.getBalance(feeRecipient)
|
||||||
check not bal.isZero
|
check not bal.isZero
|
||||||
|
|
||||||
proc inPoolAndOk(txPool: TxPoolRef, txHash: Hash256): bool =
|
|
||||||
let res = txPool.getItem(txHash)
|
|
||||||
if res.isErr: return false
|
|
||||||
res.get().reject == txInfoOk
|
|
||||||
|
|
||||||
proc runTxPoolBlobhashTest*() =
|
proc runTxPoolBlobhashTest*() =
|
||||||
var
|
var
|
||||||
env = initEnv(Cancun)
|
env = initEnv(Cancun)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user