nimbus-eth1/nimbus/utils/tx_pool/tx_desc.nim

280 lines
9.0 KiB
Nim
Raw Normal View History

# 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 Descriptor
## ===========================
##
import
std/[times],
../../db/db_chain,
./tx_chain,
./tx_info,
./tx_item,
./tx_job,
./tx_tabs,
./tx_tabs/tx_sender, # for verify()
eth/[common, keys]
{.push raises: [Defect].}
type
TxPoolCallBackRecursion* = object of Defect
## Attempt to recurse a call back function
TxPoolFlags* = enum ##\
## Processing strategy selector symbols
stageItems1559MinFee ##\
## Stage tx items with `tx.maxFee` at least `minFeePrice`. Other items
## are left or set pending. This symbol affects post-London tx items,
## only.
stageItems1559MinTip ##\
## Stage tx items with `tx.effectiveGasTip(baseFee)` at least
## `minTipPrice`. Other items are considered underpriced and left
## or set pending. This symbol affects post-London tx items, only.
stageItemsPlMinPrice ##\
## Stage tx items with `tx.gasPrice` at least `minPreLondonGasPrice`.
## Other items are considered underpriced and left or set pending.
## This symbol affects pre-London tx items, only.
# -----------
packItemsMaxGasLimit ##\
## It set, the *packer* will execute and collect additional items from
## the `staged` bucket while accumulating `gasUsed` as long as
## `maxGasLimit` is not exceeded. If `packItemsTryHarder` flag is also
## set, the *packer* will not stop until at least `hwmGasLimit` is
## reached.
##
## Otherwise the *packer* will accumulate up until `trgGasLimit` is
## not exceeded, and not stop until at least `lwmGasLimit` is reached
## in case `packItemsTryHarder` is also set,
packItemsTryHarder ##\
## It set, the *packer* will *not* stop accumulaing transactions up until
## the `lwmGasLimit` or `hwmGasLimit` is reached, depending on whether
## the `packItemsMaxGasLimit` is set. Otherwise, accumulating stops
## immediately before the next transaction exceeds `trgGasLimit`, or
## `maxGasLimit` depending on `packItemsMaxGasLimit`.
# -----------
autoUpdateBucketsDB ##\
## Automatically update the state buckets after running batch jobs if
## the `dirtyBuckets` flag is also set.
autoZombifyUnpacked ##\
## Automatically dispose *pending* or *staged* txs that were queued
## at least `lifeTime` ago.
autoZombifyPacked ##\
## Automatically dispose *packed* txs that were queued
## at least `lifeTime` ago.
TxPoolParam* = tuple ## Getter/setter accessible parameters
minFeePrice: GasPrice ## Gas price enforced by the pool, `gasFeeCap`
minTipPrice: GasPrice ## Desired tip-per-tx target, `effectiveGasTip`
minPlGasPrice: GasPrice ## Desired pre-London min `gasPrice`
dirtyBuckets: bool ## Buckets need to be updated
doubleCheck: seq[TxItemRef] ## Check items after moving block chain head
flags: set[TxPoolFlags] ## Processing strategy symbols
TxPoolRef* = ref object of RootObj ##\
## Transaction pool descriptor
startDate: Time ## Start date (read-only)
chain: TxChainRef ## block chain state
byJob: TxJobRef ## Job batch list
txDB: TxTabsRef ## Transaction lists & tables
lifeTime*: times.Duration ## Maximum life time of a tx in the system
priceBump*: uint ## Min precentage price when superseding
param: TxPoolParam ## Getter/Setter parameters
const
txItemLifeTime = ##\
## Maximum amount of time transactions can be held in the database\
## unless they are packed already for a block. This default is chosen\
## as found in core/tx_pool.go(184) of the geth implementation.
initDuration(hours = 3)
txPriceBump = ##\
## Minimum price bump percentage to replace an already existing\
## transaction (nonce). This default is chosen as found in\
## core/tx_pool.go(177) of the geth implementation.
10u
txMinFeePrice = 1.GasPrice
txMinTipPrice = 1.GasPrice
txPoolFlags = {stageItems1559MinTip,
stageItems1559MinFee,
stageItemsPlMinPrice,
packItemsTryHarder,
autoUpdateBucketsDB,
autoZombifyUnpacked}
# ------------------------------------------------------------------------------
# Public functions, constructor
# ------------------------------------------------------------------------------
proc init*(xp: TxPoolRef; db: BaseChainDB; miner: EthAddress)
{.gcsafe,raises: [Defect,CatchableError].} =
## Constructor, returns new tx-pool descriptor. The `miner` argument is
## the fee beneficiary for informational purposes only.
xp.startDate = getTime().utc.toTime
xp.chain = TxChainRef.new(db, miner)
xp.txDB = TxTabsRef.new
xp.byJob = TxJobRef.new
xp.lifeTime = txItemLifeTime
xp.priceBump = txPriceBump
xp.param.reset
xp.param.minFeePrice = txMinFeePrice
xp.param.minTipPrice = txMinTipPrice
xp.param.flags = txPoolFlags
# ------------------------------------------------------------------------------
# Public functions, getters
# ------------------------------------------------------------------------------
proc byJob*(xp: TxPoolRef): TxJobRef =
## Getter, job queue
xp.byJob
proc chain*(xp: TxPoolRef): TxChainRef =
## Getter, block chain DB
xp.chain
proc pFlags*(xp: TxPoolRef): set[TxPoolFlags] =
## Returns the set of algorithm strategy symbols for labelling items
## as`packed`
xp.param.flags
proc pDirtyBuckets*(xp: TxPoolRef): bool =
## Getter, buckets need update
xp.param.dirtyBuckets
proc pDoubleCheck*(xp: TxPoolRef): seq[TxItemRef] =
## Getter, cached block chain head was moved back
xp.param.doubleCheck
proc pMinFeePrice*(xp: TxPoolRef): GasPrice =
## Getter
xp.param.minFeePrice
proc pMinTipPrice*(xp: TxPoolRef): GasPrice =
## Getter
xp.param.minTipPrice
proc pMinPlGasPrice*(xp: TxPoolRef): GasPrice =
## Getter
xp.param.minPlGasPrice
proc startDate*(xp: TxPoolRef): Time =
## Getter
xp.startDate
proc txDB*(xp: TxPoolRef): TxTabsRef =
## Getter, pool database
xp.txDB
# ------------------------------------------------------------------------------
# Public functions, setters
# ------------------------------------------------------------------------------
proc `pDirtyBuckets=`*(xp: TxPoolRef; val: bool) =
## Setter
xp.param.dirtyBuckets = val
proc pDoubleCheckAdd*(xp: TxPoolRef; val: seq[TxItemRef]) =
## Pseudo setter
xp.param.doubleCheck.add val
proc pDoubleCheckFlush*(xp: TxPoolRef) =
## Pseudo setter
xp.param.doubleCheck.setLen(0)
proc `pFlags=`*(xp: TxPoolRef; val: set[TxPoolFlags]) =
## Install a set of algorithm strategy symbols for labelling items as`packed`
xp.param.flags = val
proc `pMinFeePrice=`*(xp: TxPoolRef; val: GasPrice) =
## Setter
xp.param.minFeePrice = val
proc `pMinTipPrice=`*(xp: TxPoolRef; val: GasPrice) =
## Setter
xp.param.minTipPrice = val
proc `pMinPlGasPrice=`*(xp: TxPoolRef; val: GasPrice) =
## Setter
xp.param.minPlGasPrice = val
# ------------------------------------------------------------------------------
# Public functions, heplers (debugging only)
# ------------------------------------------------------------------------------
proc verify*(xp: TxPoolRef): Result[void,TxInfo]
{.gcsafe, raises: [Defect,CatchableError].} =
## Verify descriptor and subsequent data structures.
block:
let rc = xp.byJob.verify
if rc.isErr:
return rc
block:
let rc = xp.txDB.verify
if rc.isErr:
return rc
# verify consecutive nonces per sender
var
initOk = false
lastSender: EthAddress
lastNonce: AccountNonce
lastSublist: TxSenderSchedRef
for (_,nonceList) in xp.txDB.incAccount:
for item in nonceList.incNonce:
if not initOk or lastSender != item.sender:
initOk = true
lastSender = item.sender
lastNonce = item.tx.nonce
lastSublist = xp.txDB.bySender.eq(item.sender).value.data
elif lastNonce + 1 == item.tx.nonce:
lastNonce = item.tx.nonce
else:
return err(txInfoVfyNonceChain)
# verify bucket boundary conditions
case item.status:
of txItemPending:
discard
of txItemStaged:
if lastSublist.eq(txItemPending).eq(item.tx.nonce - 1).isOk:
return err(txInfoVfyNonceChain)
of txItemPacked:
if lastSublist.eq(txItemPending).eq(item.tx.nonce - 1).isOk:
return err(txInfoVfyNonceChain)
if lastSublist.eq(txItemStaged).eq(item.tx.nonce - 1).isOk:
return err(txInfoVfyNonceChain)
ok()
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------