sequencer

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 14, 2025 License: GPL-3.0 Imports: 13 Imported by: 0

README

Sequencer SDK (SBCP Integration)

This package provides a sequencer-side SDK that integrates the base 2PC consensus (x/consensus) with the Superblock Construction Protocol (SBCP). It can be used in two modes:

  • Standalone 2PC (no SBCP): use x/consensus directly.
  • With SBCP: wrap the base coordinator via NewSequencerCoordinator and wire it to the Shared Publisher (SP) and peer sequencers.

Quick Start

  1. Create the base 2PC coordinator
cfg := consensus.DefaultConfig("seq-<id>")
cfg.Role = consensus.Follower
base := consensus.New(log, cfg)

  1. Connect to the Shared Publisher (SP)
spClient := tcp.NewClient(tcp.DefaultClientConfig(), log)
spClient.SetHandler(func (ctx context.Context, msg *pb.Message) ([]common.Hash, error) {
return nil, sequencerCoordinator.HandleMessage(ctx, msg.SenderId, msg)
})
_ = spClient.Connect(ctx, "<sp-host>:8080")
  1. Create the Sequencer Coordinator (SBCP)
seqCfg := sequencer.DefaultConfig(chainIDBytes)
sequencerCoordinator := sequencer.NewSequencerCoordinator(base, seqCfg, spClient, log)
_ = sequencerCoordinator.Start(ctx)
  1. P2P for CIRC (sequencer-to-sequencer)
  • Start a TCP server to receive CIRC messages from peers (no SP involvement). Route messages to the coordinator:
p2pServer := tcp.NewServer(tcp.DefaultServerConfig(), log)
p2pServer.SetHandler(func (ctx context.Context, from string, msg *pb.Message) error {
return sequencerCoordinator.HandleMessage(ctx, from, msg)
})
_ = p2pServer.Start(ctx)
  • Maintain TCP clients to other sequencers (by chain ID) and send pb.Message_CircMessage when simulation emits a mailbox.write(...).

Using x/consensus Alone (no SBCP)

The base coordinator exposes a small API:

  • StartTransaction(from, *pb.XTRequest) – initialize local state for an xT.
  • RecordCIRCMessage(*pb.CIRCMessage) – record incoming CIRC from a peer.
  • ConsumeCIRCMessage(xtID, sourceChainKey string) – pop a queued CIRC for a given source chain.
  • RecordVote(xtID, chainKey, vote) and SetDecisionCallback(...) – 2PC integration.

You’re responsible for:

  • Exchanging CIRC directly between sequencers (e.g., using x/transport/tcp).
  • Computing xtID from XTRequest and maintaining a consistent chain ID representation.

Chain Key Normalization (IMPORTANT)

Consensus indexes per-chain structures using a hex-encoded key derived from raw chain ID bytes. Always normalize via:

key := consensus.ChainKeyBytes(chainIDBytes)
// or, when you only have uint64 (minimal big-endian encoding):
key := consensus.ChainKeyUint64(chainID)

Use the same key for:

  • ConsumeCIRCMessage(xtID, key)
  • Internally-created maps keyed by chain ID
  • Any logs/diagnostics comparing chain IDs across components

Tip: Ensure pb.XTRequest.Transactions[i].ChainId and pb.CIRCMessage.{Source,Destination}Chain contain the exact same byte representation that you’ll normalize with ChainKeyBytes.

The SDK wires the 2PC coordinator and provides the SBCP state machine and block builder.

  • SP → Sequencer

    • StartSlot: sequencer transitions to Building-Free and starts a draft block (adds Mailbox.clean() top-of-block tx).
    • StartSC: sequencer locks, initializes local 2PC state (SDK does this), simulates, sends CIRC to peers, and votes to SP.
    • Decided: sequencer updates the block builder (include xT and CIRC mailbox-population txs if decision=true) and unlocks.
    • RequestSeal: sequencer seals block and sends L2Block to SP.
  • Sequencer ↔ Sequencer (P2P CIRC)

    • On mailbox.write(...), build pb.CIRCMessage and send to the peer’s TCP endpoint.
    • On receive, the coordinator records it via RecordCIRCMessage (already handled through HandleMessage).
    • When simulation requires data (mailbox.read(...)), call ConsumeCIRCMessage(xtID, consensus.ChainKeyBytes(sourceChainBytes)).
Bootstrap Helper

To quickly wire a sequencer with SP + P2P using sensible defaults:

rt, err := bootstrap.Setup(ctx, bootstrap.Config{
    ChainID:   chainIDBytes,
    SPAddr:    "sp-host:8080",
    PeerAddrs: map[string]string{
        "11111":  "peer-a:9000",   // decimal or hex keys accepted
        "0x1a2b": "peer-b:9001",
    },
    Log: log,
})
if err != nil { panic(err) }

if err := rt.Start(ctx); err != nil { panic(err) }
defer rt.Stop(ctx)

// CIRC send example
_ = rt.SendCIRC(ctx, &pb.CIRCMessage{DestinationChain: someChainIDBytes /* ... */})

Integration Notes

  • The coordinator now ensures local 2PC state exists when StartSC arrives, so CIRC recording works immediately.
  • Ensure CIRC XtId equals xtReq.XtID() computed by both sequencers.
  • Ensure P2P connections are up before StartSC to avoid delays.

Example Connection Topology (from a Node wrapper)

  • One TCP client to SP for SBCP messages.
  • One TCP server per sequencer to receive CIRC from peers.
  • Clients to other sequencers (by configured chain IDs) for sending CIRC.

See your node wiring for a concrete example of SP and peer setup using x/transport/tcp and ConnectWithRetry.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetMessageTypeString

func GetMessageTypeString(msg *pb.Message) string

GetMessageTypeString returns a formatted string for logging

func IsProtocolMessage

func IsProtocolMessage(msg *pb.Message) bool

IsProtocolMessage returns true if the message belongs to any known protocol

func NewSBCPHandler

func NewSBCPHandler(coordinator *SequencerCoordinator, log zerolog.Logger) protocol.MessageHandler

NewSBCPHandler creates a new SBCP message handler

Types

type BlockBuilder

type BlockBuilder struct {
	// contains filtered or unexported fields
}

func NewBlockBuilder

func NewBlockBuilder(chainID []byte, log zerolog.Logger) *BlockBuilder

func (*BlockBuilder) AddCIRCMessage

func (bb *BlockBuilder) AddCIRCMessage(msg *pb.CIRCMessage) error

func (*BlockBuilder) AddLocalTransaction

func (bb *BlockBuilder) AddLocalTransaction(tx []byte) error

func (*BlockBuilder) AddSCPTransactions

func (bb *BlockBuilder) AddSCPTransactions(xtID string, txs [][]byte, decision bool) error

AddSCPTransactions adds or removes SCP-related transaction(s) for a given xtID If decision is true, provided txs are appended; if false, any existing entries are removed.

func (*BlockBuilder) GetDraftStats

func (bb *BlockBuilder) GetDraftStats() map[string]interface{}

func (*BlockBuilder) Reset

func (bb *BlockBuilder) Reset()

func (*BlockBuilder) SealBlock

func (bb *BlockBuilder) SealBlock(includedXTs [][]byte) (*pb.L2Block, error)

func (*BlockBuilder) StartSlot

func (bb *BlockBuilder) StartSlot(slot uint64, request *pb.L2BlockRequest) error

type BlockBuilderInterface

type BlockBuilderInterface interface {
	StartSlot(slot uint64, request *pb.L2BlockRequest) error
	AddLocalTransaction(tx []byte) error
	AddSCPTransactions(xtID string, txs [][]byte, decision bool) error
	AddCIRCMessage(msg *pb.CIRCMessage) error
	SealBlock(includedXTs [][]byte) (*pb.L2Block, error)
	GetDraftStats() map[string]interface{}
	Reset()
}

BlockBuilderInterface for L2 block construction

type BlockLifecycleManager

type BlockLifecycleManager interface {
	OnBlockBuildingStart(ctx context.Context, slot uint64) error
	OnBlockBuildingComplete(ctx context.Context, block *pb.L2Block, success bool) error
}

BlockLifecycleManager handles block building lifecycle events

type CallbackManager

type CallbackManager interface {
	SetCallbacks(callbacks CoordinatorCallbacks)
	SetMinerNotifier(notifier MinerNotifier)
}

CallbackManager handles callback registration and miner notifications

type Config

type Config struct {
	ChainID []byte      `json:"chain_id"`
	Slot    slot.Config `json:"slot"`

	// Sequencer-specific settings
	BlockTimeout         time.Duration `json:"block_timeout"`
	MaxLocalTxs          int           `json:"max_local_txs"`
	SCPTimeout           time.Duration `json:"scp_timeout"`
	EnableCIRCValidation bool          `json:"enable_circ_validation"`
}

Config holds sequencer coordinator configuration

func DefaultConfig

func DefaultConfig(chainID []byte) Config

DefaultConfig returns sensible defaults for sequencer

type Coordinator

type Coordinator interface {
	// Lifecycle
	Start(ctx context.Context) error
	Stop(ctx context.Context) error

	// Message handling
	HandleMessage(ctx context.Context, from string, msg *pb.Message) error

	// State queries
	GetCurrentSlot() uint64
	GetState() State
	GetStats() map[string]interface{}
	GetActiveSCPInstanceCount() int
	ShouldRejectXt(xtID string) bool

	// Consensus access
	Consensus() consensus.Coordinator

	// SDK access
	BlockLifecycleManager
	TransactionManager
	CallbackManager
}

Coordinator defines the sequencer coordinator interface

func WrapCoordinator

func WrapCoordinator(
	baseConsensus consensus.Coordinator,
	config Config,
	transport transport.Client,
	log zerolog.Logger,
) (Coordinator, error)

WrapCoordinator wraps an existing consensus coordinator with SBCP functionality

type CoordinatorCallbacks

type CoordinatorCallbacks struct {
	SendCIRC func(ctx context.Context, circ *pb.CIRCMessage) error
	// SimulateAndVote runs local-chain simulation for the provided XT request
	// and returns whether the local transactions are ready to commit (vote=true)
	// or not (vote=false). This callback is used by the coordinator during
	// StartSC handling and is implemented by the host SDK (e.g., geth backend).
	SimulateAndVote func(ctx context.Context, xtReq *pb.XTRequest, xtID *pb.XtID) (bool, error)
	// CleanupAbortedTransaction is called when an SCP instance decides to abort,
	// allowing the execution layer to immediately remove staged transactions from
	// its pending pool. This ensures atomic exclude behavior when blocks are built
	// before RequestSeal arrives.
	CleanupAbortedTransaction func(ctx context.Context, xtID *pb.XtID) error
}

CoordinatorCallbacks defines callback functions for cross-component communication

type DecidedXT

type DecidedXT struct {
	XtIDBytes []byte // raw xtID bytes
	Included  bool   // true=included, false=aborted
}

DecidedXT tracks the final decision for an XT in a slot

type DraftBlock

type DraftBlock struct {
	// contains filtered or unexported fields
}

type MessageRouter

type MessageRouter struct {
	// contains filtered or unexported fields
}

func NewMessageRouter

func NewMessageRouter(
	sbcpHandler protocol.Handler,
	scpHandler consensus.ProtocolHandler,
	log zerolog.Logger,
) *MessageRouter

func (*MessageRouter) GetStats

func (mr *MessageRouter) GetStats() map[string]interface{}

GetStats returns routing statistics

func (*MessageRouter) Reset

func (mr *MessageRouter) Reset()

Reset clears routing statistics

func (*MessageRouter) Route

func (mr *MessageRouter) Route(ctx context.Context, from string, msg *pb.Message) error

type MessageRouterInterface

type MessageRouterInterface interface {
	Route(ctx context.Context, from string, msg *pb.Message) error
}

MessageRouterInterface for routing messages

type MinerNotifier

type MinerNotifier interface {
	NotifySlotStart(startSlot *pb.StartSlot) error
	NotifyRequestSeal(ctx context.Context, requestSeal *pb.RequestSeal) error
	NotifyStateChange(from, to State, slot uint64) error
}

MinerNotifier defines the interface for notifying miner about sequencer events

type ProtocolType

type ProtocolType int

ProtocolType represents the high-level protocol classification

const (
	ProtocolUnknown ProtocolType = iota
	ProtocolSBCP                 // Superblock Construction Protocol
	ProtocolSCP                  // Synchronous Composability Protocol
)

func ClassifyProtocol

func ClassifyProtocol(msg *pb.Message) ProtocolType

ClassifyProtocol determines which high-level protocol a message belongs to

func (ProtocolType) IsValid

func (p ProtocolType) IsValid() bool

IsValid returns true if a protocol type is valid

func (ProtocolType) String

func (p ProtocolType) String() string

String returns human-readable protocol name

type SCPContext

type SCPContext struct {
	XtID           *pb.XtID
	Request        *pb.XTRequest
	Slot           uint64
	SequenceNumber uint64
	MyTransactions [][]byte
	Decision       *bool
}

type SCPIntegration

type SCPIntegration struct {
	// contains filtered or unexported fields
}

func NewSCPIntegration

func NewSCPIntegration(
	chainID []byte,
	consensus consensus.Coordinator,
	stateMachine *StateMachine,
	log zerolog.Logger,
	builder *BlockBuilder,
) *SCPIntegration

func (*SCPIntegration) GetActiveContexts

func (si *SCPIntegration) GetActiveContexts() map[string]*SCPContext

func (*SCPIntegration) GetActiveCount

func (si *SCPIntegration) GetActiveCount() int

GetActiveCount returns the number of in-flight SCP instances

func (*SCPIntegration) GetIncludedXTsHex

func (si *SCPIntegration) GetIncludedXTsHex() []string

GetIncludedXTsHex returns hex-encoded xtIDs decided to include in current slot

func (*SCPIntegration) GetLastDecidedSequenceNumber

func (si *SCPIntegration) GetLastDecidedSequenceNumber() (uint64, bool)

GetLastDecidedSequenceNumber returns the last decided sequence and whether it exists

func (*SCPIntegration) HandleDecision

func (si *SCPIntegration) HandleDecision(xtID *pb.XtID, decision bool) error

func (*SCPIntegration) HandleStartSC

func (si *SCPIntegration) HandleStartSC(ctx context.Context, startSC *pb.StartSC) error

func (*SCPIntegration) ResetForSlot

func (si *SCPIntegration) ResetForSlot(slot uint64)

ResetForSlot clears per-slot SCP tracking

func (*SCPIntegration) ShouldRejectXt

func (si *SCPIntegration) ShouldRejectXt(xtID string) bool

ShouldRejectXt returns true if the XT was decided against and should be rejected

type SCPIntegrationInterface

type SCPIntegrationInterface interface {
	HandleStartSC(ctx context.Context, startSC *pb.StartSC) error
	HandleDecision(xtID *pb.XtID, decision bool) error
	GetActiveContexts() map[string]*SCPContext
	ResetForSlot(slot uint64)
	GetIncludedXTsHex() []string
	GetLastDecidedSequenceNumber() (uint64, bool)
	GetActiveCount() int
	ShouldRejectXt(xtID string) bool
}

SCPIntegrationInterface for SCP coordination

type SequencerCoordinator

type SequencerCoordinator struct {
	// contains filtered or unexported fields
}

SequencerCoordinator coordinates sequencer SBCP operations

func NewSequencerCoordinator

func NewSequencerCoordinator(
	baseConsensus consensus.Coordinator,
	config Config,
	transport transport.Client,
	log zerolog.Logger,
) *SequencerCoordinator

NewSequencerCoordinator creates a new sequencer coordinator

func (*SequencerCoordinator) Consensus

func (sc *SequencerCoordinator) Consensus() consensus.Coordinator

Consensus returns the underlying consensus coordinator

func (*SequencerCoordinator) GetActiveSCPInstanceCount

func (sc *SequencerCoordinator) GetActiveSCPInstanceCount() int

GetActiveSCPInstanceCount returns the number of active SCP instances

func (*SequencerCoordinator) GetCurrentSlot

func (sc *SequencerCoordinator) GetCurrentSlot() uint64

func (*SequencerCoordinator) GetOrderedTransactionsForBlock

func (sc *SequencerCoordinator) GetOrderedTransactionsForBlock(ctx context.Context) ([]*pb.TransactionRequest, error)

GetOrderedTransactionsForBlock returns transactions in correct order for block

func (*SequencerCoordinator) GetState

func (sc *SequencerCoordinator) GetState() State

func (*SequencerCoordinator) GetStats

func (sc *SequencerCoordinator) GetStats() map[string]interface{}

func (*SequencerCoordinator) HandleMessage

func (sc *SequencerCoordinator) HandleMessage(ctx context.Context, from string, msg *pb.Message) error

HandleMessage routes messages through the message router

func (*SequencerCoordinator) OnBlockBuildingComplete

func (sc *SequencerCoordinator) OnBlockBuildingComplete(ctx context.Context, block *pb.L2Block, success bool) error

OnBlockBuildingComplete is called when block building completes

func (*SequencerCoordinator) OnBlockBuildingStart

func (sc *SequencerCoordinator) OnBlockBuildingStart(ctx context.Context, slot uint64) error

OnBlockBuildingStart is called when block building starts TODO: rethink lock, it blocks ethapi engine

func (*SequencerCoordinator) PrepareTransactionsForBlock

func (sc *SequencerCoordinator) PrepareTransactionsForBlock(ctx context.Context, slot uint64) error

PrepareTransactionsForBlock prepares transactions for block inclusion

func (*SequencerCoordinator) SetCallbacks

func (sc *SequencerCoordinator) SetCallbacks(callbacks CoordinatorCallbacks)

SetCallbacks sets the coordinator callbacks

func (*SequencerCoordinator) SetMinerNotifier

func (sc *SequencerCoordinator) SetMinerNotifier(notifier MinerNotifier)

SetMinerNotifier sets the miner notifier

func (*SequencerCoordinator) ShouldRejectXt

func (sc *SequencerCoordinator) ShouldRejectXt(xtID string) bool

ShouldRejectXt returns true if the XT was decided against and should be rejected

func (*SequencerCoordinator) Start

func (sc *SequencerCoordinator) Start(ctx context.Context) error

Start starts the sequencer coordinator

func (*SequencerCoordinator) Stop

func (sc *SequencerCoordinator) Stop(ctx context.Context) error

Stop stops the sequencer coordinator

type State

type State int
const (
	StateWaiting State = iota
	StateBuildingFree
	StateBuildingLocked
	StateSubmission
)

func (State) String

func (s State) String() string

type StateChangeCallback

type StateChangeCallback func(from, to State, slot uint64, reason string)

type StateMachine

type StateMachine struct {
	// contains filtered or unexported fields
}

func NewStateMachine

func NewStateMachine(chainID []byte, log zerolog.Logger, callback StateChangeCallback) *StateMachine

func (*StateMachine) GetCurrentSlot

func (sm *StateMachine) GetCurrentSlot() uint64

func (*StateMachine) GetCurrentState

func (sm *StateMachine) GetCurrentState() State

func (*StateMachine) GetTransitions

func (sm *StateMachine) GetTransitions() []StateTransition

func (*StateMachine) Reset

func (sm *StateMachine) Reset()

func (*StateMachine) TransitionTo

func (sm *StateMachine) TransitionTo(newState State, slot uint64, reason string) error

type StateMachineInterface

type StateMachineInterface interface {
	GetCurrentState() State
	GetCurrentSlot() uint64
	TransitionTo(newState State, slot uint64, reason string) error
	GetTransitions() []StateTransition
	Reset()
}

StateMachineInterface for sequencer FSM

type StateTransition

type StateTransition struct {
	From      State
	To        State
	Slot      uint64
	Timestamp time.Time
	Reason    string
}

type TransactionManager

type TransactionManager interface {
	PrepareTransactionsForBlock(ctx context.Context, slot uint64) error
	GetOrderedTransactionsForBlock(ctx context.Context) ([]*pb.TransactionRequest, error)
}

TransactionManager handles transaction preparation and ordering

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL