174 lines
5.8 KiB
Nim
174 lines
5.8 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2018 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.
|
|
|
|
## Transaction Pool Tasklets: Update by Bucket
|
|
## ===========================================
|
|
##
|
|
|
|
import
|
|
std/[tables],
|
|
../../../constants,
|
|
../tx_chain,
|
|
../tx_desc,
|
|
../tx_info,
|
|
../tx_item,
|
|
../tx_tabs,
|
|
../tx_tabs/tx_status,
|
|
./tx_classify,
|
|
./tx_dispose,
|
|
chronicles,
|
|
eth/[common, keys],
|
|
stew/[sorted_set]
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
const
|
|
minNonce = AccountNonce.low
|
|
|
|
logScope:
|
|
topics = "tx-pool buckets"
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc bucketItemsReassignPending*(xp: TxPoolRef; labelFrom: TxItemStatus;
|
|
account: EthAddress; nonceFrom = minNonce)
|
|
{.gcsafe,raises: [Defect,CatchableError].} =
|
|
## Move all items in bucket `lblFrom` with nonces not less than `nonceFrom`
|
|
## to the `pending` bucket
|
|
let rc = xp.txDB.byStatus.eq(labelFrom).eq(account)
|
|
if rc.isOk:
|
|
for item in rc.value.data.incNonce(nonceFrom):
|
|
discard xp.txDB.reassign(item, txItemPending)
|
|
|
|
|
|
proc bucketItemsReassignPending*(xp: TxPoolRef; item: TxItemRef)
|
|
{.gcsafe,raises: [Defect,CatchableError].} =
|
|
## Variant of `bucketItemsReassignPending()`
|
|
xp.bucketItemsReassignPending(item.status, item.sender, item.tx.nonce)
|
|
|
|
|
|
proc bucketUpdateAll*(xp: TxPoolRef): bool
|
|
{.discardable,gcsafe,raises: [Defect,CatchableError].} =
|
|
## Update all buckets. The function returns `true` if some items were added
|
|
## to the `staged` bucket.
|
|
|
|
# Sort order: `EthAddress` > `AccountNonce` > item.
|
|
var
|
|
stagedItemsAdded = false
|
|
stashed: Table[EthAddress,seq[TxItemRef]]
|
|
|
|
# Prepare
|
|
if 0 < xp.pDoubleCheck.len:
|
|
for item in xp.pDoubleCheck:
|
|
if item.reject == txInfoOk:
|
|
# Check whether there was a gap when the head was moved backwards.
|
|
let rc = xp.txDB.bySender.eq(item.sender).any.gt(item.tx.nonce)
|
|
if rc.isOk:
|
|
let nextItem = rc.value.data
|
|
if item.tx.nonce + 1 < nextItem.tx.nonce:
|
|
discard xp.disposeItemAndHigherNonces(
|
|
item, txInfoErrNonceGap, txInfoErrImpliedNonceGap)
|
|
else:
|
|
# For failed txs, make sure that the account state has not
|
|
# changed. Assuming that this list is complete, then there are
|
|
# no other account affected.
|
|
let rc = xp.txDB.bySender.eq(item.sender).any.ge(minNonce)
|
|
if rc.isOk:
|
|
let firstItem = rc.value.data
|
|
if not xp.classifyValid(firstItem):
|
|
discard xp.disposeItemAndHigherNonces(
|
|
firstItem, txInfoErrNonceGap, txInfoErrImpliedNonceGap)
|
|
|
|
# Clean up that queue
|
|
xp.pDoubleCheckFlush
|
|
|
|
|
|
# PENDING
|
|
#
|
|
# Stash the items from the `pending` bucket The nonces in this list are
|
|
# greater than the ones from other lists. When processing the `staged`
|
|
# list, all that can happen is that loer nonces (than the stashed ones)
|
|
# are added.
|
|
for (sender,nonceList) in xp.txDB.incAccount(txItemPending):
|
|
# New per-sender-account sub-sequence
|
|
stashed[sender] = newSeq[TxItemRef]()
|
|
for item in nonceList.incNonce:
|
|
# Add to sub-sequence
|
|
stashed[sender].add item
|
|
|
|
# STAGED
|
|
#
|
|
# Update/edit `staged` bucket.
|
|
for (_,nonceList) in xp.txDB.incAccount(txItemStaged):
|
|
for item in nonceList.incNonce:
|
|
|
|
if not xp.classifyActive(item):
|
|
# Larger nonces cannot be held in the `staged` bucket anymore for this
|
|
# sender account. So they are moved back to the `pending` bucket.
|
|
xp.bucketItemsReassignPending(item)
|
|
|
|
# The nonces in the `staged` bucket are always smaller than the one in
|
|
# the `pending` bucket. So, if the lower nonce items must go to the
|
|
# `pending` bucket, then the stashed `pending` bucket items can only
|
|
# stay there.
|
|
stashed.del(item.sender)
|
|
break # inner `incItemList()` loop
|
|
|
|
# PACKED
|
|
#
|
|
# Update `packed` bucket. The items are a subset of all possibly staged
|
|
# (aka active) items. So they follow a similar logic as for the `staged`
|
|
# items above.
|
|
for (_,nonceList) in xp.txDB.incAccount(txItemPacked):
|
|
for item in nonceList.incNonce:
|
|
|
|
if not xp.classifyActive(item):
|
|
xp.bucketItemsReassignPending(item)
|
|
|
|
# For the `sender` all staged items have smaller nonces, so they have
|
|
# to go to the `pending` bucket, as well.
|
|
xp.bucketItemsReassignPending(txItemStaged, item.sender)
|
|
stagedItemsAdded = true
|
|
|
|
stashed.del(item.sender)
|
|
break # inner `incItemList()` loop
|
|
|
|
# PENDING re-visted
|
|
#
|
|
# Post-process `pending` and `staged` buckets. Re-insert the
|
|
# list of stashed `pending` items.
|
|
for itemList in stashed.values:
|
|
for item in itemList:
|
|
if not xp.classifyActive(item):
|
|
# Ignore higher nonces
|
|
break # inner loop for `itemList` sequence
|
|
# Move to staged bucket
|
|
discard xp.txDB.reassign(item, txItemStaged)
|
|
|
|
stagedItemsAdded
|
|
|
|
# ---------------------------
|
|
|
|
proc bucketFlushPacked*(xp: TxPoolRef)
|
|
{.gcsafe,raises: [Defect,CatchableError].} =
|
|
## Move all items from the `packed` bucket to the `pending` bucket
|
|
for (_,nonceList) in xp.txDB.decAccount(txItemPacked):
|
|
for item in nonceList.incNonce:
|
|
discard xp.txDB.reassign(item,txItemStaged)
|
|
|
|
# Reset bucket status info
|
|
xp.chain.clearAccounts
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|