Documentation
¶
Overview ¶
Package mempool implements Dingo's transaction pool. It accepts transactions from local clients (N2C) and relayed txsubmission traffic (N2N), validates them against the current ledger state, and holds them until they are included in a block, evicted, or expired.
Service is the backend-neutral node contract. FIFO is the default backend and orders transactions by successful admission: independent submissions retain arrival order, and a duplicate refresh does not move a transaction. DAG is the alternative backend. It indexes pending producers plus parent/child edges, and caches successful-admission order, which is topological because a pending parent must exist before a child can be admitted. DAG never watermark-evicts; network intake waits for admission headroom instead. Mempool remains the shared engine embedded by both backends for source compatibility.
Both backends validate every submitted transaction through the ledger package — UTxO resolution, fees, ExUnit budgets, validity interval, size, and the full UTxO validation rules enforced by the ledger package — before admitting it. Transactions outside their validity interval relative to the current tip are rejected at submission time rather than held until expiry.
Eviction and watermarks ¶
FIFO uses a two-level watermark scheme:
- EvictionWatermark — above this fill level, oldest pending txs are evicted from the front of the queue; a value of 0 disables eviction entirely
- RejectionWatermark — above this fill level, new submissions are rejected outright
Fill level charges each pending transaction its CBOR plus the CBOR of the decoded outputs the UTxO overlay keeps for it, since decoding copies them.
When eviction is enabled, it is FIFO/oldest-first rather than priority- based. With the default configuration, Dingo instead applies backpressure at full mempool capacity and removes transactions only when they are confirmed, invalidated, or expired. DAG ignores EvictionWatermark, preserves admitted transactions, and exposes admission headroom so network intake pauses before the rejection watermark. Direct submissions above that watermark receive MempoolFullError.
Events ¶
- MempoolAddTxEventType — a tx was admitted to the pool
- MempoolRemoveTxEventType — a tx was removed (included, evicted, or expired)
Index ¶
- Constants
- Variables
- func RegisterDAGProvider(host *plugin.Host) error
- func RegisterFIFOProvider(host *plugin.Host) error
- func RegisterProvider(host *plugin.Host) error
- type AddTransactionEvent
- type AdmissionHeadroom
- type CertifiedClosureProvider
- type Consumer
- type DAG
- func (d *DAG) AddConsumer(connId ouroboros.ConnectionId) RelayConsumer
- func (d *DAG) AdmissionHeadroomBytes() int64
- func (d *DAG) Consumer(connId ouroboros.ConnectionId) RelayConsumer
- func (d *DAG) Implementation() Implementation
- func (d *DAG) MaxAdmissionHeadroomBytes() int64
- func (d *DAG) WaitForAdmissionHeadroom(minBytes int64, done <-chan struct{}) bool
- type FIFO
- func (f *FIFO) AddConsumer(connId ouroboros.ConnectionId) RelayConsumer
- func (f *FIFO) AdmissionHeadroomBytes() int64
- func (f *FIFO) Consumer(connId ouroboros.ConnectionId) RelayConsumer
- func (f *FIFO) Implementation() Implementation
- func (f *FIFO) MaxAdmissionHeadroomBytes() int64
- func (f *FIFO) WaitForAdmissionHeadroom(minBytes int64, done <-chan struct{}) bool
- type Implementation
- type Mempool
- func (m *Mempool) AddConsumer(connId ouroboros.ConnectionId) *MempoolConsumer
- func (m *Mempool) AddTransaction(ctx context.Context, txType uint, txBytes []byte) (err error)
- func (m *Mempool) AdmissionHeadroomBytes() int64
- func (m *Mempool) AdmitSubmission(ctx context.Context) (context.Context, func(), error)
- func (m *Mempool) CapacityBytes() int64
- func (m *Mempool) Consumer(connId ouroboros.ConnectionId) *MempoolConsumer
- func (m *Mempool) FindConsumer(connId ouroboros.ConnectionId) Consumer
- func (m *Mempool) GetTransaction(txHash string) (MempoolTransaction, bool)
- func (m *Mempool) MaxAdmissionHeadroomBytes() int64
- func (m *Mempool) NewConsumer(connId ouroboros.ConnectionId) Consumer
- func (m *Mempool) RemoveConsumer(connId ouroboros.ConnectionId)
- func (m *Mempool) RemoveTransaction(txHash string)
- func (m *Mempool) RemoveTxsByHash(hashes []string)
- func (m *Mempool) SizeBytes() int64
- func (m *Mempool) Start(ctx context.Context) error
- func (m *Mempool) Stop(ctx context.Context) error
- func (m *Mempool) TransactionHashes(maxItems int) ([]string, int)
- func (m *Mempool) TransactionHashesByAddress(address string) []string
- func (m *Mempool) Transactions() []MempoolTransaction
- func (m *Mempool) TransactionsBounded(maxItems int, maxBytes int64) ([]MempoolTransaction, int)
- type MempoolConfig
- type MempoolConsumer
- type MempoolFullError
- type MempoolTransaction
- type Pool
- type ProviderConfig
- type ProviderDependencies
- type RelayConsumer
- type RemoveTransactionEvent
- type ResolvingTxValidationSessionProvider
- type Service
- type SubmissionAdmitter
- type TxSizeLimitProvider
- type TxValidationSessionProvider
- type TxValidator
- type UtxoResolver
Constants ¶
const ( AddTransactionEventType event.EventType = "mempool.add_tx" RemoveTransactionEventType event.EventType = "mempool.remove_tx" DefaultEvictionWatermark = 0.0 DefaultRejectionWatermark = 1.0 DefaultTransactionTTL = 5 * time.Minute DefaultCleanupInterval = 1 * time.Minute DefaultRevalidationDeltaCap = 64 DefaultConsumerCacheSize = 1024 // DefaultMaxConcurrentSubmissions leaves one connection in SQLite's // default five-connection read pool available to chain and query work. DefaultMaxConcurrentSubmissions = 4 )
Variables ¶
var ErrInputResolution = errors.New(
"mempool: confirmed input address resolution failed",
)
ErrInputResolution reports that admission could not read the addresses of a transaction's confirmed inputs from storage. No verdict was reached on the transaction.
var ErrMempoolStopped = errors.New("mempool: stopped")
ErrMempoolStopped is returned when admission is attempted after shutdown.
var ErrNilValidator = errors.New("mempool: validator is nil")
ErrNilValidator is returned by runtime mempool operations that require a non-nil validator. The constructor refuses to build a Mempool without one, so seeing this in a running node is a programmer error — but returning it lets the chain-update loop log and continue rather than crash the node.
var ErrPendingStateMoved = errors.New(
"mempool: ledger moved since pending transactions were validated",
)
ErrPendingStateMoved is returned by AddTransaction when the ledger kept publishing new state while the transaction was being admitted, so no verdict was reached. It is not a rejection: the same transaction may be admitted once the ledger settles.
var ErrSubmissionBusy = errors.New("transaction submission capacity exhausted")
ErrSubmissionBusy reports that API submission cannot reserve its bounded share of transaction-validation capacity. AdmitSubmission returns it instead of waiting, so an API request does not hold a handler goroutine while it waits for a metadata read transaction.
Functions ¶
func RegisterDAGProvider ¶ added in v0.69.0
RegisterDAGProvider registers the dependency-indexed mempool/dag provider.
func RegisterFIFOProvider ¶ added in v0.69.0
RegisterFIFOProvider registers the explicit mempool/fifo provider.
func RegisterProvider ¶ added in v0.68.0
RegisterProvider registers the FIFO compatibility alias as mempool/default.
Types ¶
type AddTransactionEvent ¶
type AdmissionHeadroom ¶ added in v0.67.0
type AdmissionHeadroom interface {
AdmissionHeadroomBytes() int64
MaxAdmissionHeadroomBytes() int64
WaitForAdmissionHeadroom(minBytes int64, done <-chan struct{}) bool
}
AdmissionHeadroom is an optional capability used by non-evicting backends to pause network intake before requesting transaction bodies that cannot fit.
type CertifiedClosureProvider ¶ added in v0.89.0
type CertifiedClosureProvider interface {
CertifiedClosureTransactions(
ctx context.Context,
block gledger.Block,
) ([]lcommon.Transaction, error)
}
CertifiedClosureProvider optionally resolves the certified endorser-block closure a Leios certifying ranking block applies. Such a block carries no transactions of its own, but the ledger applies its parent's announced endorser block with it, so those transactions are confirmed (and, on a rollback, unconfirmed) by the block exactly like a block's own. LedgerState implements this interface; a validator without it confirms only the transactions in the block body.
type Consumer ¶ added in v0.68.0
type Consumer interface {
NextTx(bool) *MempoolTransaction
GetTxFromCache(string) *MempoolTransaction
ClearCache()
RemoveTxFromCache(string)
AcknowledgeOffered(count int)
}
Consumer is the neutral per-connection transaction cursor used by TxSubmission.
type DAG ¶ added in v0.69.0
type DAG struct {
*Mempool
}
DAG exposes the dependency-indexed mempool backend.
func NewDAG ¶ added in v0.69.0
func NewDAG(config MempoolConfig) (*DAG, error)
NewDAG constructs the DAG backend.
func (*DAG) AddConsumer ¶ added in v0.69.0
func (d *DAG) AddConsumer(connId ouroboros.ConnectionId) RelayConsumer
func (*DAG) AdmissionHeadroomBytes ¶ added in v0.69.0
AdmissionHeadroomBytes returns the bytes currently available before DAG admission reaches its rejection watermark.
func (*DAG) Consumer ¶ added in v0.69.0
func (d *DAG) Consumer(connId ouroboros.ConnectionId) RelayConsumer
func (*DAG) Implementation ¶ added in v0.69.0
func (d *DAG) Implementation() Implementation
func (*DAG) MaxAdmissionHeadroomBytes ¶ added in v0.69.0
MaxAdmissionHeadroomBytes returns the maximum DAG admission budget.
func (*DAG) WaitForAdmissionHeadroom ¶ added in v0.69.0
WaitForAdmissionHeadroom blocks network intake until the requested admission budget is available or either the connection or mempool stops.
type FIFO ¶ added in v0.67.0
type FIFO struct {
*Mempool
}
FIFO exposes the current ordered mempool explicitly as the FIFO backend. The embedded Mempool preserves source compatibility while production composition depends on Pool.
func NewFIFO ¶ added in v0.67.0
func NewFIFO(config MempoolConfig) (*FIFO, error)
NewFIFO constructs the FIFO backend.
func (*FIFO) AddConsumer ¶ added in v0.67.0
func (f *FIFO) AddConsumer(connId ouroboros.ConnectionId) RelayConsumer
func (*FIFO) AdmissionHeadroomBytes ¶ added in v0.70.0
func (*FIFO) Consumer ¶ added in v0.67.0
func (f *FIFO) Consumer(connId ouroboros.ConnectionId) RelayConsumer
func (*FIFO) Implementation ¶ added in v0.67.0
func (f *FIFO) Implementation() Implementation
func (*FIFO) MaxAdmissionHeadroomBytes ¶ added in v0.70.0
func (*FIFO) WaitForAdmissionHeadroom ¶ added in v0.70.0
type Implementation ¶ added in v0.67.0
type Implementation string
Implementation identifies a mempool storage and ordering backend.
const ( // ImplementationFIFO preserves successful-admission order. ImplementationFIFO Implementation = "fifo" // ImplementationDAG tracks transaction dependencies explicitly and exposes // a deterministic topological order. ImplementationDAG Implementation = "dag" )
func (Implementation) Valid ¶ added in v0.67.0
func (i Implementation) Valid() bool
Valid reports whether the implementation name is part of the stable config surface.
type Mempool ¶
func NewMempool ¶
func NewMempool(config MempoolConfig) (*Mempool, error)
func (*Mempool) AddConsumer ¶
func (m *Mempool) AddConsumer(connId ouroboros.ConnectionId) *MempoolConsumer
func (*Mempool) AddTransaction ¶
func (*Mempool) AdmissionHeadroomBytes ¶ added in v0.70.0
func (*Mempool) AdmitSubmission ¶ added in v0.88.0
AdmitSubmission reserves API and shared validation capacity without waiting and marks the returned context so AddTransaction can reuse the reservation. API handlers call this before decoding request data so a busy node can answer the client at once; it returns ErrSubmissionBusy when either limit is held.
func (*Mempool) CapacityBytes ¶ added in v0.67.0
CapacityBytes returns the configured maximum mempool size in bytes.
func (*Mempool) Consumer ¶
func (m *Mempool) Consumer(connId ouroboros.ConnectionId) *MempoolConsumer
func (*Mempool) FindConsumer ¶ added in v0.68.0
func (m *Mempool) FindConsumer(connId ouroboros.ConnectionId) Consumer
FindConsumer exposes Consumer through the neutral Service contract.
func (*Mempool) GetTransaction ¶
func (m *Mempool) GetTransaction(txHash string) (MempoolTransaction, bool)
func (*Mempool) MaxAdmissionHeadroomBytes ¶ added in v0.70.0
func (*Mempool) NewConsumer ¶ added in v0.68.0
func (m *Mempool) NewConsumer(connId ouroboros.ConnectionId) Consumer
NewConsumer exposes AddConsumer through the neutral Service contract.
func (*Mempool) RemoveConsumer ¶
func (m *Mempool) RemoveConsumer(connId ouroboros.ConnectionId)
func (*Mempool) RemoveTransaction ¶
func (*Mempool) RemoveTxsByHash ¶ added in v0.61.1
RemoveTxsByHash removes a batch of transactions by hash without cascading to descendants. Use after a block is confirmed: the block's outputs are now in the ledger, so chained pending transactions remain valid and must not be evicted.
func (*Mempool) SizeBytes ¶ added in v0.87.0
SizeBytes returns the bytes currently retained by pending transactions.
func (*Mempool) Start ¶ added in v0.68.0
Start begins the mempool background lifecycle. Construction is deliberately side-effect free so the plugin host owns startup and rollback.
func (*Mempool) TransactionHashes ¶ added in v0.87.0
TransactionHashes returns the hashes of at most maxItems transactions, in the same order as Transactions, together with the total number of transactions in the pool. A bound of zero or less is not applied.
It reads only the identifiers, so it never clones transaction CBOR and its cost follows the size of the result rather than the size of the pool.
func (*Mempool) TransactionHashesByAddress ¶ added in v0.88.0
TransactionHashesByAddress returns the hashes of the pool transactions that pay address or spend one of its outputs, in the order Transactions reports them. It reads the address index and decodes nothing.
func (*Mempool) Transactions ¶ added in v0.2.2
func (m *Mempool) Transactions() []MempoolTransaction
func (*Mempool) TransactionsBounded ¶ added in v0.81.1
func (m *Mempool) TransactionsBounded( maxItems int, maxBytes int64, ) ([]MempoolTransaction, int)
TransactionsBounded returns a snapshot of at most maxItems transactions whose combined CBOR size stays within maxBytes, in the same order as Transactions, together with the total number of transactions in the pool. A bound of zero or less is not applied. The first transaction is always returned when the pool is non-empty, so a byte bound smaller than one transaction cannot yield an empty snapshot of a non-empty pool.
A bounded read walks and copies only the prefix it returns, headers and CBOR alike, so its cost follows the size of the result rather than the size of the pool.
type MempoolConfig ¶ added in v0.13.0
type MempoolConfig struct {
PromRegistry prometheus.Registerer
Validator TxValidator
Logger *slog.Logger
EventBus *event.EventBus
MempoolCapacity int64
TransactionTTL time.Duration
CleanupInterval time.Duration
EvictionWatermark float64
RejectionWatermark float64
RevalidationDeltaCap int
// ConsumerCacheSize bounds the number of transaction bodies retained per
// transaction-submission consumer. Zero uses DefaultConsumerCacheSize.
ConsumerCacheSize int
// ConsumerCacheBytes bounds retained transaction body bytes per consumer.
// Zero uses one quarter of MempoolCapacity.
ConsumerCacheBytes int64
CurrentSlotFunc func() uint64 // returns current slot for early TX rejection
}
type MempoolConsumer ¶
type MempoolConsumer struct {
// contains filtered or unexported fields
}
func (*MempoolConsumer) AcknowledgeOffered ¶ added in v0.70.6
func (m *MempoolConsumer) AcknowledgeOffered(count int)
AcknowledgeOffered forgets exactly the oldest count previously offered transaction bodies, in the order they were advertised. TxSubmission acks only the consumed prefix of the offered-id window; bodies for ids offered after that prefix are still eligible for the peer to request and must be preserved, so this must never clear the whole cache.
func (*MempoolConsumer) ClearCache ¶
func (m *MempoolConsumer) ClearCache()
func (*MempoolConsumer) GetTxFromCache ¶
func (m *MempoolConsumer) GetTxFromCache(hash string) *MempoolTransaction
func (*MempoolConsumer) NextTx ¶
func (m *MempoolConsumer) NextTx(blocking bool) *MempoolTransaction
func (*MempoolConsumer) RemoveTxFromCache ¶
func (m *MempoolConsumer) RemoveTxFromCache(hash string)
type MempoolFullError ¶ added in v0.13.0
MempoolFullError reports an admission refused for capacity. CurrentSize and TxSize are in the units capacity is charged in: a transaction's CBOR plus the CBOR of the decoded outputs the pool keeps for it.
func (*MempoolFullError) Error ¶ added in v0.13.0
func (e *MempoolFullError) Error() string
type MempoolTransaction ¶
type Pool ¶ added in v0.67.0
type Pool interface {
Implementation() Implementation
Stop(ctx context.Context) error
AddTransaction(ctx context.Context, txType uint, txBytes []byte) error
GetTransaction(txHash string) (MempoolTransaction, bool)
Transactions() []MempoolTransaction
CapacityBytes() int64
RemoveTransaction(txHash string)
RemoveTxsByHash(hashes []string)
AddConsumer(connId ouroboros.ConnectionId) RelayConsumer
RemoveConsumer(connId ouroboros.ConnectionId)
Consumer(connId ouroboros.ConnectionId) RelayConsumer
}
Pool is the backend-neutral mempool contract used at the node composition boundary. Confirmed removals use RemoveTxsByHash; RemoveTransaction is for manual removal and may also remove invalid descendants.
func New ¶ added in v0.67.0
func New(implementation Implementation, config MempoolConfig) (Pool, error)
New constructs the selected mempool implementation. An empty value selects FIFO for compatibility with callers that predate configurable backends.
type ProviderConfig ¶ added in v0.68.0
type ProviderConfig struct {
Capacity int64 `yaml:"capacity"`
EvictionWatermark float64 `yaml:"evictionWatermark"`
RejectionWatermark float64 `yaml:"rejectionWatermark"`
RevalidationDeltaCap int `yaml:"revalidationDeltaCap"`
// ConsumerCacheBytes bounds retained transaction body bytes per relay
// consumer. Zero uses one quarter of Capacity; see
// MempoolConfig.ConsumerCacheBytes.
ConsumerCacheBytes int64 `yaml:"consumerCacheBytes"`
}
ProviderConfig is the canonical configuration for built-in mempool providers.
type ProviderDependencies ¶ added in v0.68.0
type ProviderDependencies struct {
PromRegistry prometheus.Registerer
Validator TxValidator
Logger *slog.Logger
EventBus *event.EventBus
CurrentSlotFunc func() uint64
}
ProviderDependencies are runtime dependencies assembled after ledger and database startup.
type RelayConsumer ¶ added in v0.67.0
type RelayConsumer interface {
NextTx(blocking bool) *MempoolTransaction
GetTxFromCache(hash string) *MempoolTransaction
ClearCache()
RemoveTxFromCache(hash string)
}
RelayConsumer is the backend-neutral cursor and advertised-transaction cache used by node-to-node TxSubmission.
type RemoveTransactionEvent ¶
type RemoveTransactionEvent struct {
Hash string
}
type ResolvingTxValidationSessionProvider ¶ added in v0.88.0
type ResolvingTxValidationSessionProvider interface {
WithResolvingTxValidationSession(context.Context, func(
validate func(
tx gledger.Transaction,
consumedUtxos map[utxoref.Key]struct{},
createdUtxos map[utxoref.Key]lcommon.Utxo,
accounts *utxoref.StateOverlay,
) error,
stillCurrent func() bool,
commitIfCurrent func(func() error) (bool, error),
resolve func(refs []models.UtxoId) ([]models.Utxo, error),
) error) error
}
ResolvingTxValidationSessionProvider is a validation session that also resolves confirmed outputs, through the same storage snapshot and connection its validations read. The pool resolves a transaction's confirmed inputs there, after validating it, so an input the validation found is found again and one it could not have found does not exist. LedgerState implements it.
type Service ¶ added in v0.68.0
type Service interface {
AddTransaction(context.Context, uint, []byte) error
GetTransaction(string) (MempoolTransaction, bool)
Transactions() []MempoolTransaction
TransactionsBounded(
maxItems int,
maxBytes int64,
) ([]MempoolTransaction, int)
TransactionHashes(maxItems int) ([]string, int)
RemoveTransaction(string)
RemoveTxsByHash([]string)
NewConsumer(ouroboros.ConnectionId) Consumer
RemoveConsumer(ouroboros.ConnectionId)
FindConsumer(ouroboros.ConnectionId) Consumer
CapacityBytes() int64
// SizeBytes returns the bytes currently retained by pending
// transactions, the figure capacity and admission limits are measured
// against. It reads a maintained counter and does not walk the pool.
SizeBytes() int64
}
Service is the domain-owned mempool capability consumed by node wiring, networking, forging, ledger, and APIs.
type SubmissionAdmitter ¶ added in v0.88.0
type SubmissionAdmitter interface {
AdmitSubmission(context.Context) (context.Context, func(), error)
}
SubmissionAdmitter is implemented by a mempool that can reserve validation capacity before an API decodes an untrusted transaction body.
type TxSizeLimitProvider ¶ added in v0.88.0
type TxSizeLimitProvider interface {
// MaxTxSize returns the MaxTxSize the ledger would apply to a transaction
// of era txType, and whether it is known. It must report false rather
// than a smaller limit than the ledger would apply, so the early check
// never refuses what the ledger rule accepts.
MaxTxSize(txType uint) (uint, bool)
}
TxSizeLimitProvider optionally reports the MaxTxSize ledger validation applies to a transaction of a given era, so admission can refuse an oversized submission before constructing the ledger transaction, taking the mutation gate, or running ledger rules. LedgerState implements it; validators that do not simply skip the early check and rely on the ledger's own rule.
type TxValidationSessionProvider ¶ added in v0.69.0
type TxValidationSessionProvider interface {
WithTxValidationSession(context.Context, func(
validate func(
tx gledger.Transaction,
consumedUtxos map[utxoref.Key]struct{},
createdUtxos map[utxoref.Key]lcommon.Utxo,
accounts *utxoref.StateOverlay,
) error,
stillCurrent func() bool,
commitIfCurrent func(func() error) (bool, error),
) error) error
}
TxValidationSessionProvider optionally pins a batch of validations to one coherent ledger snapshot. LedgerState implements this interface; lightweight validators used by tests and alternate embeddings may continue to implement only TxValidator.
type TxValidator ¶ added in v0.14.0
type TxValidator interface {
ValidateTx(tx gledger.Transaction) error
ValidateTxWithOverlay(
tx gledger.Transaction,
consumedUtxos map[utxoref.Key]struct{},
createdUtxos map[utxoref.Key]lcommon.Utxo,
accounts *utxoref.StateOverlay,
) error
}
TxValidator defines the interface for transaction validation needed by mempool.
type UtxoResolver ¶ added in v0.88.0
UtxoResolver is the optional capability of a TxValidator without validation sessions that lets the pool find the address a confirmed input belongs to. Without it, or a ResolvingTxValidationSessionProvider, only output addresses and the addresses of other pool transactions' outputs are indexed.