preconfirmed

package
v0.16.6 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrBaseTxCountMismatch = errors.New("pre-confirmed base transaction count mismatch")

ErrBaseTxCountMismatch is returned when a Delta update's baseTxCount hint doesn't match the targeted slot's current tx count. Defensive against any non-poller writer (or future race) that could drift the slot between the wire send and the storage apply.

Functions

This section is empty.

Types

type ChainReader

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

ChainReader is an immutable snapshot of a contiguous run of pre-confirmed blocks, ordered newest-first via parent pointers. Iteration must respect Length — head-aligned views (see ChainStorage.SnapshotForBlock) may stop before the underlying linked list's nil terminator.

func NewChain

func NewChain(entries ...*pending.PreConfirmed) (ChainReader, error)

NewChain builds a ChainReader from non-nil pre-confirmed entries given in oldest-first order with contiguous block numbers. No args returns the zero-value ChainReader. If an entry has block number 0 behaviour is undefined.

func (*ChainReader) Head

func (c *ChainReader) Head() *pending.PreConfirmed

Head returns the most recent pre-confirmed in the view, or nil if empty.

func (*ChainReader) Length

func (c *ChainReader) Length() int

Length is the number of entries in this chain view.

func (*ChainReader) NewestFirst

func (c *ChainReader) NewestFirst() iter.Seq[*pending.PreConfirmed]

NewestFirst yields entries from the most recent down to head+1, bounded by Length.

func (*ChainReader) OldestFirst

func (c *ChainReader) OldestFirst() iter.Seq[*pending.PreConfirmed]

OldestFirst yields entries from head+1 up to the most recent, bounded by Length.

func (*ChainReader) PreConfirmedStateAt

func (c *ChainReader) PreConfirmedStateAt(
	blockNumber uint64,
	bcReader blockchain.Reader,
) (core.StateReader, blockchain.StateCloser, error)

PreConfirmedStateAt returns the chain's view of state at blockNumber. The chain owns base resolution: it opens the canonical state immediately below its own oldest slot (derived from tip - length + 1).

Returns [pending.ErrPreConfirmedNotFound] if blockNumber falls outside the chain.

func (*ChainReader) PreConfirmedStateBeforeIndexAt

func (c *ChainReader) PreConfirmedStateBeforeIndexAt(
	blockNumber uint64,
	index uint,
	bcReader blockchain.Reader,
) (core.StateReader, blockchain.StateCloser, error)

PreConfirmedStateBeforeIndexAt returns the chain's view of state immediately before transaction `index` at blockNumber. See PreConfirmedStateAt for the base- resolution contract; here the chain additionally layers the target slot's per-transaction diffs up to (but not including) `index`. Returns pending.ErrPreConfirmedNotFound if blockNumber isn't in the chain, or pending.ErrTransactionIndexOutOfBounds if `index` exceeds the target's transaction count.

func (*ChainReader) ReceiptByHash

func (c *ChainReader) ReceiptByHash(

	hash *felt.Felt,
) (*core.TransactionReceipt, uint64, error)

ReceiptByHash scans every chain entry's Block.Receipts. Returns the receipt and the number of the block it lives in. ErrTransactionReceiptNotFound when missing.

func (*ChainReader) TransactionByHash

func (c *ChainReader) TransactionByHash(hash *felt.Felt) (core.Transaction, error)

TransactionByHash scans every chain entry's Block.Transactions.

Returns pending.ErrTransactionNotFound when missing.

type ChainStorage

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

ChainStorage holds a contiguous run of pre-confirmed blocks above the canonical head. Readers obtain a head-aligned view via [SnapshotForBlock]. Single writer (polling loop) with many concurrent readers; reads are lock-free via atomic.Pointer.

func NewChainStorage

func NewChainStorage() *ChainStorage

func (*ChainStorage) AdvanceTo

func (s *ChainStorage) AdvanceTo(oldestPreConf uint64) bool

AdvanceTo realigns the chain to a new canonical head, given as oldestPreConf — the slot the chain's oldest entry must occupy after the realignment, i.e. the first pre-confirmed slot above that head (head number+1). Three outcomes:

  • oldestPreConf == the chain's current oldest: already aligned, no-op.
  • oldestPreConf > mostRecent (head advanced past everything we stored) OR oldestPreConf < the current oldest (head reverted below us — every entry's parent now references a discarded block): drop the whole chain. The next poll bootstraps fresh against the new head.
  • current oldest < oldestPreConf <= mostRecent: rebuild from the new oldest slot up so the surviving nodes nil-terminate cleanly and the dropped tail is GC-able.

Pre-pop readers retain their *ChainReader and walk the original (still intact) nodes; the new chain references only fresh nodes.

Single-writer: like ApplyUpdate, this assumes the pre-confirmed poller goroutine is the only writer.

func (*ChainStorage) ApplyUpdate

func (s *ChainStorage) ApplyUpdate(
	update starknet.PreConfirmedUpdate,
	blockNumber uint64,
	baseTxCount uint64,
	oldestPreConf uint64,
	newClasses map[felt.Felt]core.ClassDefinition,
) (*pending.PreConfirmed, error)

ApplyUpdate atomically evolves the stored chain from a wire-side update. blockNumber is the height targeted by the update; baseTxCount is the knownTransactionCount the poller sent (consulted only for the Delta case as a defensive race-check against the targeted slot). oldestPreConf is the slot the chain's oldest entry is expected to occupy: the first pre-confirmed slot above the canonical head, head number+1. Returns the affected entry, or nil when the update was a no-op (NoChange, preserved, rejected at cap, etc.).

On CAS failure the chain changed between Load and CompareAndSwap; we return an error instead of retrying.

A NoChange still registers newClasses on the targeted (tip) slot when non-empty: a re-poll that reported no content change may still carry declared classes we only just fetched for that block.

func (*ChainStorage) SnapshotForBlock added in v0.16.6

func (s *ChainStorage) SnapshotForBlock(blockNumber uint64) ChainReader

SnapshotForBlock returns a head-aligned view of the pre-confirmed chain based on the input `blockNumber`. If the `blockNumber` sits outside the pre-confirmed chain range, an empty chain is returned. Otherwise, a new chain is returned in the [blockNumber, chain.tip()] range.

The total size of the pre-confirmed chain is uncapped and it can exceed core.BlockHashLag, causing execution simulations on longer chain to fail due to this.

type DataSource

type DataSource interface {
	PreConfirmedBlockLatest(
		ctx context.Context,
		identifier string,
		txCount uint64,
	) (starknet.PreConfirmedUpdate, uint64, error)
	PreConfirmedBlockByNumber(
		ctx context.Context,
		blockNumber uint64,
		identifier string,
		txCount uint64,
	) (starknet.PreConfirmedUpdate, error)
	Class(ctx context.Context, classHash *felt.Felt) (core.ClassDefinition, error)
}

DataSource is the narrow surface the Poller needs from the wire side. Any type implementing these methods (e.g. sync.DataSource) satisfies it.

type Poller

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

Poller drives the pre-confirmed chain from a single goroutine.

One tick reads as: poll the server's latest pre-confirmed, backfill any gap below it, then apply the latest. backfill runs only when the tip jumped ahead; it re-polls the old mostRecent with delta hints and the intermediate slots up to latest-1 as full blocks (capturing each slot's declared classes) and applies each. Same-height polls (latest matches our mostRecent) skip backfill and land in apply as delta / preserve / replace.

func NewPoller

func NewPoller(
	dataSource DataSource,
	storage *ChainStorage,
	bc *blockchain.Blockchain,
	out *feed.Feed[*pending.PreConfirmed],
	highestBlockHeader *atomic.Pointer[core.Header],
	interval time.Duration,
	logger log.StructuredLogger,
) *Poller

func (*Poller) Run

func (p *Poller) Run(ctx context.Context)

Run polls the sequencer every interval and builds the pre-confirmed chain from it. If the blockchain is empty (pre-genesis) then it will stall until the genesis block is synced. It only stops on context cancellation.

Jump to

Keyboard shortcuts

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