Modular Transaction Pipeline
Replace 40+ hardcoded type switches with a registry of transaction type handlers
Status: Design phase. No implementation dependencies — this is a foundational component. Required by: EIP-8141, Interop Bridge (Phase 3+), Shutter refactor, Lucid integration.
The Modular Transaction Pipeline replaces Erigon's current approach of inserting code at every pipeline stage whenever a new transaction type is added. Today, each new type requires editing 40+ locations across ~15 files — a type switch or if txn.Type == X check at every stage from parsing through serialization. With EIP-8141 frames, Shutter, and Lucid all in scope simultaneously, this model becomes unmanageable.
The pipeline introduces a TypeHandler registry: each transaction type registers its behavior once, and every pipeline stage calls through the registry instead of branching on types. Adding a new transaction type means writing one handler — not touching 40 files.
Key Capabilities
Registry-based dispatch: Each transaction type implements TypeHandler — a set of interfaces covering parsing, validation, pool policy, execution, and serialization. The pipeline calls through the registry; it never checks types directly. Types register via init() and components.cfg, following the same pattern as other Cocoon components.
Incremental migration: Existing transaction types (legacy, EIP-1559, EIP-4844, EIP-7702, RIP-7560) are wrapped as TypeHandler implementations with zero behavior change. The scattered type switches are then removed one pipeline stage at a time — each removal is a small, independently-reviewable PR.
Middleware layer: Encrypted mempool integrations (Shutter, Lucid) wrap the registry without touching type-specific code. Shutter decrypts transactions at the slot boundary before the registry handler runs; Lucid reassembles commitment and payload before the handler processes them. Neither needs to know anything about individual transaction types.
Design: TypeHandler Registry
// txtype/registry.go
type TypeHandler interface {
TypeByte() byte
Name() string
Parser // RLP → TxnSlot (txpool) or Transaction (execution)
Validator // mempool acceptance rules
PoolPolicy // replacement, eviction, pool limits
Executor // how this tx type is processed in a block
Serializer // RPC response fields, receipt format
}Handlers embed DefaultHandler for any interfaces they don't need to override — a new type that is identical to DynamicFee except for one field only needs to implement Parser and Serializer.
Registration follows the components.cfg + init() pattern:
Current touch points per new transaction type
Type system
5 files
RLP decode switch, JSON unmarshal, receipt encode, hash computation
Txpool parsing
3 functions
ParseTransaction, type-specific body parser, hash/sender recovery
Txpool validation
4 functions
validateTx, replacement rules, pool limits
Txpool state
3 functions
Auth tracking, eviction, fee checks
Block builder
2 functions
block_assembler.go, builderstages/exec.go
State processor
2 functions
applyTransaction, dispatch
Parallel execution
3 functions
txtask.go, trace workers
RPC
2 functions
Field extraction, receipt generation
Middleware Layer
The middleware layer wraps the registry without touching type-specific code — encrypted mempool integrations don't need to know anything about individual transaction types.
Shutter (threshold decryption): wraps the validation and execution stages. Encrypted transactions enter the mempool as opaque blobs; the Shutter middleware decrypts them at the appropriate slot boundary before the registry handler processes them normally.
Lucid (distributed payload propagation): wraps the pool policy and serialization stages. The commitment (hash) and payload (data) are propagated separately; the Lucid middleware reassembles them before the registry handler runs.
Migration Strategy
Existing transaction types register themselves using the new interface. No pipeline code changes:
LegacyHandler— wraps existing legacy/access-list type codeDynamicFeeHandler— wraps existing EIP-1559 codeBlobHandler— wraps existing EIP-4844 code (KZG, pool limits, replacement rules)SetCodeHandler— wraps existing EIP-7702 code (authorization tracking)AAHandler— wraps existing RIP-7560 code
Once all types are registered, the type switches are removed one pipeline stage at a time. Each removal is a small, independently-reviewable PR.
Last updated