Help us shape the future of Go! Take the 2026 Go Developer Survey

node

package
v0.0.0-...-39c171a Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultMempoolMaxTransactions = 300
	DefaultMempoolMaxBytes        = consensus.MAX_RELAY_MSG_BYTES
	DefaultMempoolMinFeeRate      = uint64(1)

	// DefaultMinDaFeeRate is the spec-side per-byte DA fee floor from
	// POLICY_MEMPOOL_ADMISSION_GENESIS.md Stage C (`min_da_fee_rate`).
	DefaultMinDaFeeRate = uint64(1)
)

Variables

View Source
var (
	ErrDARelayChunkHashMismatch = errors.New("da chunk hash mismatch")

	ErrDARelayPayloadCommitmentMismatch = errors.New("da payload commitment mismatch")
)
View Source
var (
	ErrParentNotFound = errors.New("parent block not found")
)
View Source
var ErrStoreIntegrity = errors.New("STORE_INTEGRITY")

ErrStoreIntegrity is the stable identity behind every envelope, version, base64, checksum and genesis-anchor rejection class in the RUB-1134 error_contract: errors.Is(err, ErrStoreIntegrity) holds for all of them, and the pinned messages are the exact cross-client strings Rust returns verbatim. None of these is, wraps, or satisfies fs.ErrNotExist: absent-file fallbacks must never trigger on a corrupt file. The inner payload-decode class is deliberately OUTSIDE this identity: a file that clears the checksum is intact on disk, so a failure past it is a schema fault.

View Source
var ErrUndoIntegrity = errors.New("UNDO_INTEGRITY")

ErrUndoIntegrity is the stable identity behind the envelope, version, hash, base64 and checksum rejection classes named in the issue's error_contract: errors.Is(err, ErrUndoIntegrity) holds for all of them, and err.Error() is the exact cross-client message the Rust client returns verbatim from get_undo.

The payload-conversion class is deliberately OUTSIDE this identity. A record that clears the checksum is intact on disk; a failure past that point is a schema fault, not a storage-integrity fault, and the contract does not put it under the prefix.

Functions

func BlockStorePath

func BlockStorePath(dataDir string) string

func CanonicalNetworkName

func CanonicalNetworkName(network string) (string, bool)

CanonicalNetworkName returns the canonical network token for normalized devnet/testnet/mainnet inputs. Callers that care about distinguishing an explicitly blank raw config value must reject that before canonicalization.

func ChainStatePath

func ChainStatePath(dataDir string) string

func CompleteDASetIDsFromParsedBlock

func CompleteDASetIDsFromParsedBlock(pb *consensus.ParsedBlock) ([][32]byte, error)

CompleteDASetIDsFromParsedBlock returns the da_id of every COMPLETE DA set carried by an already-parsed block, in ascending byte order.

This is the single implementation of block-level complete-DA-set extraction in the Go tree; node/p2p parses untrusted bytes and delegates here so the bytes-entry and parsed-entry paths cannot diverge.

A set counts as complete exactly when the block carries one tx_kind=0x01 commit for that da_id (a second commit disqualifies it), the commit's chunk_count is in 1..=consensus.MAX_DA_CHUNK_COUNT, and the block carries a tx_kind=0x02 chunk for every index 0..chunk_count-1. This mirrors the completeness rule consensus.ConnectBlock* already enforces; it is repeated here because the caller may hand over a block that has NOT been validated.

Contract:

  • Output is sorted by raw ID bytes, never by map iteration order, so it is deterministic for a given block.
  • At most consensus.MAX_DA_BATCHES_PER_BLOCK IDs are returned; a block that would yield more is reported as an error rather than truncated. A block that passed consensus validation cannot reach that branch.
  • pb is read-only; no field of pb or of its transactions is mutated.
  • A nil pb, a nil transaction, or a DA transaction missing its DA core is an error or is skipped — never a panic, since callers may pass a block that was assembled rather than parsed.

func DefaultDataDir

func DefaultDataDir() string

func DevnetGenesisBlockBytes

func DevnetGenesisBlockBytes() []byte

func DevnetGenesisBlockHash

func DevnetGenesisBlockHash() [32]byte

func DevnetGenesisChainID

func DevnetGenesisChainID() [32]byte

func NormalizeDataDir

func NormalizeDataDir(path string) string

NormalizeDataDir returns filepath.Clean(path) without filesystem resolution.

func NormalizePeers

func NormalizePeers(raw ...string) []string

func ParseMineAddress

func ParseMineAddress(value string) ([]byte, error)

func ReadConfigFile

func ReadConfigFile(path string) ([]byte, error)

ReadConfigFile reads an operator config file under configFileMaxBytes with the typed pre-allocation refusal from RUB-1057 (errStoreFileTooLarge).

func ReclaimAtomicWriteScratch

func ReclaimAtomicWriteScratch(dataDir string) error

ReclaimAtomicWriteScratch visits the five production parents in frozen order.

func ReclaimAtomicWriteScratchInParent

func ReclaimAtomicWriteScratchInParent(parent string) error

ReclaimAtomicWriteScratchInParent reclaims only the named parent's scratch.

func ReconcileChainStateWithBlockStore

func ReconcileChainStateWithBlockStore(state *ChainState, store *BlockStore, cfg SyncConfig) (bool, error)

ReconcileChainStateWithBlockStore replays any canonical blocks that are present in the blockstore but missing from the persisted chainstate snapshot. When the loaded snapshot disagrees with the canonical chain at its claimed height, the canonical blockstore view wins and replay restarts from an empty state.

It fails closed on canonical corruption before anything else: an incomplete committed canonical prefix returns an error rather than being truncated or repaired, so this function performs no durable write of its own on any path.

func RejectDaAnchorTxPolicy

func RejectDaAnchorTxPolicy(
	tx *consensus.Tx,
	utxos map[consensus.Outpoint]consensus.UtxoEntry,
	currentMempoolMinFeeRate uint64,
	minDaFeeRate uint64,
	daSurchargePerByte uint64,
) (reject bool, daBytes uint64, reason string, err error)

RejectDaAnchorTxPolicy implements policy-only DA/anchor anti-abuse checks aligned with POLICY_MEMPOOL_ADMISSION_GENESIS.md Stage C:

fee(tx)             = sum_inputs - sum_outputs
relay_fee_floor(tx) = weight(tx) * currentMempoolMinFeeRate
da_fee_floor(tx)    = da_payload_len(tx) * minDaFeeRate
da_surcharge(tx)    = da_payload_len(tx) * daSurchargePerByte
da_required_fee(tx) = da_fee_floor(tx) + da_surcharge(tx)
required_fee(tx)    = max(relay_fee_floor(tx), da_required_fee(tx))
reject if fee(tx) < required_fee(tx)

TODO(rust-parity,#1352): Go implements Stage C required_fee = max(relay_fee_floor, da_fee_floor + da_surcharge). Rust is still tracked as surcharge-only per #1352; do not roll this policy out in any multi-client relay/miner deployment until Rust matches this behavior or a release gate explicitly prevents mixed-client divergence.

Arithmetic is checked widening; any overflow rejects fail-closed as a policy error. The helper does not change consensus validity. For non-DA transactions (da_payload_len == 0), this helper applies no DA-specific fee policy; relay-fee-floor enforcement remains the caller/mempool's responsibility (for example via validateFeeFloorLocked).

Inputs:

  • currentMempoolMinFeeRate: rolling local mempool floor exposed by #1336 (e.g. Mempool.currentMinFeeRateLocked()). Callers without a live mempool may use DefaultMempoolMinFeeRate as the documented default for that rolling state — not a parallel floor invention.
  • minDaFeeRate: the spec-side DA per-byte floor (POLICY_MEMPOOL_ADMISSION_GENESIS.md Stage C `min_da_fee_rate`, default 1).
  • daSurchargePerByte: operator-tunable DA per-byte surcharge added on top of the spec-side floor; default 0 disables only the surcharge, not the DA floor.

Miner template budget capping is enforced by the caller (needs running sum).

The helper recomputes both `weight` and `daBytes` from `tx` via consensus.TxWeightAndStats. This avoids trusting any caller-supplied weight value (a stale or zero weight would otherwise silently under-enforce the relay-fee half of the Stage C predicate).

func RejectNonCoinbaseAnchorOutputs

func RejectNonCoinbaseAnchorOutputs(tx *consensus.Tx) (reject bool, reason string, err error)

RejectNonCoinbaseAnchorOutputs implements policy-only "CORE_ANCHOR is non-standard outside coinbase".

It returns reject=true if the transaction creates a CORE_ANCHOR output (COV_TYPE_ANCHOR). This check is independent from consensus validity and is intended for wallet/mempool/miner policy.

func StockDevnetTargetSchedule

func StockDevnetTargetSchedule(network string, chainID [32]byte) bool

StockDevnetTargetSchedule reports whether the exact stock Phase-0 devnet predicate holds: a candidate's expected target MUST then come from the derived schedule, not from the static SyncConfig.ExpectedTarget.

This is the SINGLE formula for that rule in the Go tree, and every layer — including node/p2p — MUST call it rather than replicate it, so no layer can select a different rule than the one the apply path enforces. It normalizes the network itself (blank and any case/whitespace variant of "devnet" count as devnet) because callers may hold the operator's RAW SyncConfig: NewSyncEngine normalizes only its own copy.

Stateless by contract: it takes startup identity only, reads no chain state, performs no derivation, and cannot fail. It confers no derivation capability — the schedule helper, its ancestry walk and the retarget entry stay unexported.

Exactly TWO immutable startup terms, and deliberately no chain-state term. A genesis-hash term would add no guarantee: the chain id IS the SHA3-256 commitment over the published genesis bytes (deriveGenesisChainID, re-derived and panic-checked at init in chainstate.go), so chain-id equality already implies the published genesis identity. What such a term did add was rule selection that depends on chain state — an empty or recovering store flipped it — a canonical-index read per untrusted peer message, and no single realizable form across layers. The genesis hash is still verified at startup by ValidateDevnetGenesisIdentity; that is where it belongs.

Being a pure function of startup identity, this cannot fail, so it returns no error and reads nothing.

func ValidateConfig

func ValidateConfig(cfg Config) error

func ValidateDARelayChunk

func ValidateDARelayChunk(chunk DARelayChunk) error

ValidateDARelayChunk validates one unretained chunk before relay admission.

func ValidateDevnetGenesisIdentity

func ValidateDevnetGenesisIdentity(chainID, genesisHash [32]byte) error

ValidateDevnetGenesisIdentity reports whether a parsed genesis-pack identity (chain_id, genesis_hash) matches the published canonical devnet pack. It is intended to run at startup AFTER the genesis file is parsed and BEFORE any filesystem mutation (datadir create, chainstate load, blockstore open, reconcile, save, sync engine construction). On mismatch returns *consensus.TxError with BLOCK_ERR_LINKAGE_INVALID and the same Msg strings as the runtime height-0 guards in applyCanonicalParsedBlock so log / ban-score / debugging correlate boot-time and runtime rejects under the same class. Callers MUST only invoke this for cfg.Network == "devnet"; for other networks the canonical pack identity is undefined here.

This helper is intentionally NOT integrated into NewSyncEngine: SyncConfig does not carry the parsed genesis_hash, so a guard there would observe only ChainID and could not actually detect a mismatched hash in an embedded caller. The boot-time call site in cmd/rubin-node/main.go is the only place that has both inputs.

func ValidateMainnetGenesisGuard

func ValidateMainnetGenesisGuard(cfg SyncConfig) error

ValidateMainnetGenesisGuard exposes the mainnet genesis / target guard so cmd/rubin-node/main.go can run it BEFORE reconcile (mirror of Rust main.rs validate_mainnet_genesis_guard call). Devnet / test networks no-op. Defense-in-depth: NewSyncEngine still runs the same guard internally for callers that construct an engine directly (tests, embedded uses).

func ValidateParallelValidationMode

func ValidateParallelValidationMode(s string) error

ValidateParallelValidationMode reports whether s names a valid parallel-validation mode. It accepts exactly the values the canonical parser used by NewSyncEngine accepts: "off", "shadow", "on" (case-insensitive, surrounding whitespace ignored) plus "" (the documented default, resolving to "off"). Validation-only: it performs no filesystem, chainstate, blockstore, or service side effect, and a nil return guarantees NewSyncEngine cannot later reject the same value on mode parsing. rubin-node startup calls it so an invalid operator mode exits before datadir creation, chainstate load/save, blockstore open, reconcile, the legacy-exposure-scan chainstate read, or any service start (RUB-665). NewSyncEngine keeps its own internal parse as defense in depth for embedded callers.

Types

type BlockApplyCounts

type BlockApplyCounts struct {
	Accepted uint64
	Rejected uint64
}

BlockApplyCounts is the bounded canonical block-apply outcome metric state.

type BlockArtifactLeaves

type BlockArtifactLeaves struct {
	Block  BlockArtifactState
	Header BlockArtifactState
	Undo   BlockArtifactState
}

BlockArtifactLeaves is the per-artifact evidence behind one BlockPresence.

type BlockArtifactState

type BlockArtifactState string

BlockArtifactState is one stored artifact's state. Valid means the artifact was read AND is bound to the requested hash: the block's own header re-hashes to it, the header hashes to it, the undo envelope carries it. Everything that is neither absent nor bound — corrupt, mismatched, over-bound, unreadable — is invalid, and none of it is ever repaired, truncated or rewritten here.

const (
	BlockArtifactAbsent  BlockArtifactState = "absent"
	BlockArtifactValid   BlockArtifactState = "valid"
	BlockArtifactInvalid BlockArtifactState = "invalid"
)

type BlockPresence

type BlockPresence struct {
	Class  BlockPresenceClass
	Scope  BlockPresenceScope
	Leaves BlockArtifactLeaves
}

BlockPresence is one snapshot classification of a block hash: the class, the scope that qualifies a store error, and the leaf evidence behind both.

func (BlockPresence) String

func (p BlockPresence) String() string

String renders the identity. Only the noncanonical store error is scoped — LOCAL_STORE_ERROR(noncanonical) is the frozen corpus row; a canonical-scoped store error renders the bare contract class and carries its scope and leaves in the struct instead. Nothing else renders a scope, so no class can ever print an empty parenthesis. It is a RENDERING, not a classification: the zero value renders "" (no class was assigned), and the bare LOCAL_STORE_ERROR token is the class name of BOTH scopes, so the consumer that must tell the latching canonical case (TERMINAL_STORE_INTEGRITY(canonical)) from the non-latching noncanonical corpus row reads Scope, never the rendered string.

type BlockPresenceClass

type BlockPresenceClass string

BlockPresenceClass is the closed set of presence classifications for a block hash in this store. All four CLASS strings are the contract's closed return set; ABSENT, STORED_NONCANONICAL, CANONICAL and LOCAL_STORE_ERROR(noncanonical) are frozen RUB-922 identities; fully reclaimed damaged side rows are ABSENT.

const (
	BlockPresenceAbsent             BlockPresenceClass = "ABSENT"
	BlockPresenceStoredNoncanonical BlockPresenceClass = "STORED_NONCANONICAL"
	BlockPresenceCanonical          BlockPresenceClass = "CANONICAL"
	BlockPresenceLocalStoreError    BlockPresenceClass = "LOCAL_STORE_ERROR"
)

type BlockPresenceScope

type BlockPresenceScope string

BlockPresenceScope qualifies LOCAL_STORE_ERROR and is empty for every other class. Only the noncanonical spelling is a frozen corpus identity (LOCAL_STORE_ERROR(noncanonical)); it leaves every canonical image untouched. Canonical scope is LOCAL evidence: the scope and the leaves stay in the struct as what the owning canonical transition latches as TERMINAL_STORE_INTEGRITY(canonical), and the rendered identity stays the bare contract class.

const (
	BlockPresenceScopeCanonical    BlockPresenceScope = "canonical"
	BlockPresenceScopeNoncanonical BlockPresenceScope = "noncanonical"
)

type BlockStore

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

func CreateBlockStore

func CreateBlockStore(rootPath string) (*BlockStore, error)

CreateBlockStore initializes a fresh blockstore with the default 8 GiB limit.

func CreateBlockStoreWithNoncanonicalLimit

func CreateBlockStoreWithNoncanonicalLimit(rootPath string, limit uint64) (*BlockStore, error)

CreateBlockStoreWithNoncanonicalLimit validates the limit before creating the root.

func OpenBlockStore

func OpenBlockStore(rootPath string) (*BlockStore, error)

OpenBlockStore opens an initialized blockstore with the default 8 GiB limit.

func OpenBlockStoreWithNoncanonicalLimit

func OpenBlockStoreWithNoncanonicalLimit(rootPath string, limit uint64) (*BlockStore, error)

OpenBlockStoreWithNoncanonicalLimit strictly reconstructs bounded accounting and publishes no store on error.

func (*BlockStore) CanonicalHash

func (bs *BlockStore) CanonicalHash(height uint64) ([32]byte, bool, error)

func (*BlockStore) CanonicalIndexSnapshot

func (bs *BlockStore) CanonicalIndexSnapshot() ([]string, error)

func (*BlockStore) ChainWork

func (bs *BlockStore) ChainWork(tipHash [32]byte) (*big.Int, error)

func (*BlockStore) CommitCanonicalBlock

func (bs *BlockStore) CommitCanonicalBlock(height uint64, blockHash [32]byte, headerBytes []byte, blockBytes []byte, undo *BlockUndo) error

func (*BlockStore) FindCanonicalHeight

func (bs *BlockStore) FindCanonicalHeight(blockHash [32]byte) (uint64, bool, error)

func (*BlockStore) GetBlockByHash

func (bs *BlockStore) GetBlockByHash(blockHash [32]byte) ([]byte, error)

func (*BlockStore) GetHeaderByHash

func (bs *BlockStore) GetHeaderByHash(blockHash [32]byte) ([]byte, error)

func (*BlockStore) GetUndo

func (bs *BlockStore) GetUndo(blockHash [32]byte) (*BlockUndo, error)

func (*BlockStore) HashesAfterLocators

func (bs *BlockStore) HashesAfterLocators(locatorHashes [][32]byte, stopHash [32]byte, limit uint64) ([][32]byte, error)

func (*BlockStore) InspectBlockPresence

func (bs *BlockStore) InspectBlockPresence(blockHash [32]byte) BlockPresence

InspectBlockPresence classifies blockHash against this store's canonical membership and its three stored artifacts. A nil receiver is a PROGRAMMING ERROR (consumers must not call with a nil store): it proves nothing about any artifact, so it fails closed with every leaf invalid on the CANONICAL scope the owner latches, never on the frozen non-latching corpus row LOCAL_STORE_ERROR(noncanonical); that value coincides with the all-invalid canonical observation by design, and the class set stays closed.

A reader pin precedes the ONE stateMu.RLock spanning membership and artifact reads. Reclaim selects only an unpinned hash and rejects later pins once marked; reverse persistence-order reads therefore still observe one real tuple while damaged rows may move present->absent.

The cost is real and accepted, and all of it runs under the read lock: the block leaf READS, fully PARSES and hashes up to consensus.MAX_BLOCK_BYTES and the undo leaf READS and JSON-decodes up to undoFileMaxBytes (2 GB), so a publication waits behind an inspection and a pending writer blocks every arriving reader. It takes no second lock, repairs nothing, and never treats a present header ALONE as presence.

func (*BlockStore) LocatorHashes

func (bs *BlockStore) LocatorHashes(limit int) ([][32]byte, error)

func (*BlockStore) PutBlock

func (bs *BlockStore) PutBlock(height uint64, blockHash [32]byte, headerBytes []byte, blockBytes []byte) error

PutBlock appends a canonical tip while persisting NO undo record, so a store written only through it is refused by the strict startup scan. Test/legacy convenience with no production caller — the production commit path is preparedCanonicalIndex.commit, which the owning SyncEngine transition invokes exactly once after staging every artifact through StoreBlock and PutUndo.

func (*BlockStore) PutUndo

func (bs *BlockStore) PutUndo(blockHash [32]byte, undo *BlockUndo) error

func (*BlockStore) RestoreCanonicalIndex

func (bs *BlockStore) RestoreCanonicalIndex(canonical []string) error

func (*BlockStore) RewindToHeight

func (bs *BlockStore) RewindToHeight(height uint64) error

func (*BlockStore) SetCanonicalTip

func (bs *BlockStore) SetCanonicalTip(height uint64, blockHash [32]byte) error

func (*BlockStore) StoreBlock

func (bs *BlockStore) StoreBlock(blockHash [32]byte, headerBytes []byte, blockBytes []byte) error

func (*BlockStore) Tip

func (bs *BlockStore) Tip() (uint64, [32]byte, bool, error)

func (*BlockStore) TruncateCanonical

func (bs *BlockStore) TruncateCanonical(count uint64) error

func (*BlockStore) VerifyGenesisAnchor

func (bs *BlockStore) VerifyGenesisAnchor(genesisHash [32]byte) error

VerifyGenesisAnchor enforces the RUB-1134 genesis anchor: a non-empty canonical index must carry the configured genesis hash at row 0, while an empty index skips the anchor. Failure is the distinct fail-closed foreign-datadir class, not an envelope-integrity failure, and satisfies errors.Is(err, ErrStoreIntegrity). Startup wiring (cmd/rubin-node/main.go) calls this BEFORE ReconcileChainStateWithBlockStore, so no replay or reconcile adoption ever consumes a foreign index.

type BlockUndo

type BlockUndo struct {
	BlockHeight              uint64
	PreviousAlreadyGenerated consensus.Uint128
	Txs                      []TxUndo
}

type CanonicalAppliedBlock

type CanonicalAppliedBlock struct {
	Hash          [32]byte
	CompleteDAIDs [][32]byte
}

CanonicalAppliedBlock identifies one block a canonical apply committed, plus the complete DA-set IDs that block carries. It deliberately holds NO raw block bytes: a reorg summary accumulates one record per newly-canonical block, and a block is up to consensus.MAX_BLOCK_BYTES, so retaining bytes made summary size grow with reorg depth times block size. CompleteDAIDs is bounded by consensus.MAX_DA_BATCHES_PER_BLOCK fixed-width IDs and is the block's public DA-set IDENTITY, not consumer input: the retained-DA cleanup that once read it after the apply returned is performed inside the canonical transition's own admission fence, and no post-return consumer of these IDs survives.

type CanonicalCommitState

type CanonicalCommitState string

CanonicalCommitState is the RUBIN_MEMPOOL_POLICY.md Section 6.4.1 commit truth of the canonical apply that selects one mining result, in the exact wire form RUBIN_NODE_RPC_DEVNET.md Section 3.4 requires of its mandatory commit_state field. The three constants below are the CLOSED set; no other value is ever produced, and "unknown" MUST NOT be flattened onto "not_committed".

const (
	// CanonicalCommitStateNotCommitted is truth OLD, NOT_APPLICABLE, or any
	// outcome reached before a commit could cross: the exact old image stands.
	CanonicalCommitStateNotCommitted CanonicalCommitState = "not_committed"
	// CanonicalCommitStateCommitted is truth NEW: the complete planned new
	// image was published, whether or not the transition then latched.
	CanonicalCommitStateCommitted CanonicalCommitState = "committed"
	// CanonicalCommitStateUnknown is TERMINAL_PERSISTENCE(neither_or_unreadable):
	// neither image may be guessed and no identity may be exposed.
	CanonicalCommitStateUnknown CanonicalCommitState = "unknown"
)

type ChainState

type ChainState struct {
	Utxos            map[consensus.Outpoint]consensus.UtxoEntry
	Height           uint64
	AlreadyGenerated consensus.Uint128
	TipHash          [32]byte
	HasTip           bool
	Rotation         consensus.RotationProvider
	Registry         *consensus.SuiteRegistry
	// contains filtered or unexported fields
}

func LoadChainState

func LoadChainState(path string) (*ChainState, error)

LoadChainState reads the store_envelope_v1-wrapped snapshot. An ABSENT file keeps the NewChainState-plus-full-replay repair path; every present file must clear the strict envelope BEFORE the inner chainStateDisk decode runs. Envelope failures carry the ErrStoreIntegrity identity and never satisfy fs.ErrNotExist, so a corrupt file can never ride the absent-file fallback.

func NewChainState

func NewChainState() *ChainState

func (*ChainState) ConnectBlock

func (s *ChainState) ConnectBlock(
	blockBytes []byte,
	expectedTarget *[32]byte,
	prevTimestamps []uint64,
	chainID [32]byte,
) (*ChainStateConnectSummary, error)

func (*ChainState) ConnectBlockParallelSigs

func (s *ChainState) ConnectBlockParallelSigs(
	blockBytes []byte,
	expectedTarget *[32]byte,
	prevTimestamps []uint64,
	chainID [32]byte,
	workers int,
) (*ChainStateConnectSummary, error)

ConnectBlockParallelSigs connects a block using parallel signature verification. This is an IBD optimization: pre-checks are sequential, ML-DSA-87 signature verifications are batched and executed across a goroutine pool. See consensus.ConnectBlockParallelSigVerify for details.

workers controls the goroutine pool size. If <= 0, defaults to GOMAXPROCS.

func (*ChainState) ConnectBlockParallelSigsWithSuiteContext

func (s *ChainState) ConnectBlockParallelSigsWithSuiteContext(
	blockBytes []byte,
	expectedTarget *[32]byte,
	prevTimestamps []uint64,
	chainID [32]byte,
	rotation consensus.RotationProvider,
	registry *consensus.SuiteRegistry,
	workers int,
) (*ChainStateConnectSummary, error)

func (*ChainState) ConnectBlockWithSuiteContext

func (s *ChainState) ConnectBlockWithSuiteContext(
	blockBytes []byte,
	expectedTarget *[32]byte,
	prevTimestamps []uint64,
	chainID [32]byte,
	rotation consensus.RotationProvider,
	registry *consensus.SuiteRegistry,
) (*ChainStateConnectSummary, error)

func (*ChainState) DisconnectBlock

func (s *ChainState) DisconnectBlock(blockBytes []byte, undo *BlockUndo) (*ChainStateDisconnectSummary, error)

func (*ChainState) IndexedSuiteIDs

func (s *ChainState) IndexedSuiteIDs() []uint8

IndexedSuiteIDs returns the sorted suite IDs that are explicitly bound in UTXO covenant data. Today this covers covenant forms that carry suite_id directly in the output itself, such as CORE_P2PK.

func (*ChainState) Save

func (s *ChainState) Save(path string) error

func (*ChainState) StateDigest

func (s *ChainState) StateDigest() [32]byte

StateDigest is an alias for UtxoSetHash that mirrors the Rust node ChainState::state_digest() surface. Today the chain state digest is exactly the UTXO set hash; the two names are kept in parity with Rust so that inspection callers can reach for either spelling.

func (*ChainState) UtxoExposureCountBySuiteID

func (s *ChainState) UtxoExposureCountBySuiteID(suiteID uint8) uint64

UtxoExposureCountBySuiteID reports how many current UTXOs explicitly bind to suiteID in their covenant data.

func (*ChainState) UtxoOutpointsBySuiteID

func (s *ChainState) UtxoOutpointsBySuiteID(suiteID uint8) []consensus.Outpoint

UtxoOutpointsBySuiteID returns the deterministically sorted outpoints whose covenant data explicitly binds to suiteID.

func (*ChainState) UtxoSetHash

func (s *ChainState) UtxoSetHash() [32]byte

UtxoSetHash returns the deterministic SHA3-256 digest over the current UTXO set. It is bit-identical with the Rust node ChainState::utxo_set_hash() and uses the same canonical encoding as consensus.UtxoSetHash (which produces PostStateDigest in ConnectBlock summaries). On a nil receiver returns the digest of an empty UTXO map for definedness.

Cost: O(n log n) over the entire UTXO set (sort by outpoint canonical key) plus one SHA3-256 hash + per-entry allocations for the canonical encoding. Intended for low-frequency inspection / parity-vector verification — do NOT call from hot paths or polling loops. If a caller needs incremental digest updates, fold the maintenance into ConnectBlock / DisconnectTip instead of calling this.

type ChainStateConnectSummary

type ChainStateConnectSummary struct {
	BlockHeight        uint64
	BlockHash          [32]byte
	SumFees            consensus.Uint128
	AlreadyGenerated   consensus.Uint128
	AlreadyGeneratedN1 consensus.Uint128
	UtxoCount          uint64
	// CanonicalAppliedBlocks is populated ONLY by the SyncEngine canonical-apply
	// path, in canonical order: a direct apply reports the single connected
	// block, a reorg reports every newly-canonical branch block, and a
	// stored-but-not-switched side branch reports none. The ChainState connect
	// entry points leave it nil — connecting to an in-memory state is not by
	// itself a canonical-application event (the reorg preview and startup replay
	// both connect blocks that must never be reported).
	CanonicalAppliedBlocks []CanonicalAppliedBlock
	PostStateDigest        [32]byte
	SigTaskCount           uint64 // parallel path only; 0 for sequential
	WorkerPanics           uint64 // parallel path only; 0 for sequential
}

type ChainStateDisconnectSummary

type ChainStateDisconnectSummary struct {
	DisconnectedHeight uint64
	BlockHash          [32]byte
	NewHeight          uint64
	NewTipHash         [32]byte
	HasTip             bool
	AlreadyGenerated   consensus.Uint128
	UtxoCount          uint64
}

type CompactCandidateDisposition

type CompactCandidateDisposition uint8

CompactCandidateDisposition separates absence, integrity and resource limits.

const (
	CompactCandidatePresent    CompactCandidateDisposition = 1
	CompactCandidateAbsent     CompactCandidateDisposition = 2
	CompactCandidateFault      CompactCandidateDisposition = 3
	CompactCandidateOverBudget CompactCandidateDisposition = 4
)

type CompactCandidateIdentity

type CompactCandidateIdentity struct {
	TxID  [32]byte
	WTxID [32]byte
}

CompactCandidateIdentity is an admitted standard transaction identity.

type CompactCandidateRead

type CompactCandidateRead struct {
	Disposition CompactCandidateDisposition
	Raw         []byte
}

CompactCandidateRead owns Raw exactly when Disposition is PRESENT.

type CompleteDASetCandidate

type CompleteDASetCandidate struct {
	DAID         [32]byte
	PayloadBytes uint64
	CommitTx     []byte
	Chunks       []CompleteDASetChunkCandidate
}

CompleteDASetCandidate is a caller-owned snapshot of one relay-complete DA set.

type CompleteDASetChunkCandidate

type CompleteDASetChunkCandidate struct {
	Index uint16
	Tx    []byte
}

CompleteDASetChunkCandidate is a caller-owned DA chunk transaction snapshot.

type CompleteDASetProvider

type CompleteDASetProvider interface {
	CompleteDASetCandidates(maxPayloadBytes uint64) []CompleteDASetCandidate
}

CompleteDASetProvider exposes caller-owned COMPLETE_SET DA relay snapshots.

type Config

type Config struct {
	Network            string              `json:"network"`
	DataDir            string              `json:"data_dir"`
	BindAddr           string              `json:"bind_addr"`
	RPCBindAddr        string              `json:"rpc_bind_addr,omitempty"`
	LogLevel           string              `json:"log_level"`
	Peers              []string            `json:"peers"`
	MaxPeers           int                 `json:"max_peers"`
	MempoolMaxTxs      int                 `json:"mempool_max_txs"`
	MempoolMaxBytes    int                 `json:"mempool_max_bytes"`
	DAMempoolSize      uint64              `json:"da_mempool_size"`
	ChainID            string              `json:"chain_id_hex,omitempty"`
	MineAddress        string              `json:"mine_address"`
	RotationDescriptor *RotationConfigJSON `json:"rotation_descriptor,omitempty"`
	SuiteRegistry      []SuiteParamsJSON   `json:"suite_registry,omitempty"`
}

func DefaultConfig

func DefaultConfig() Config

func (Config) BuildRotationProvider

func (cfg Config) BuildRotationProvider() (consensus.RotationProvider, *consensus.SuiteRegistry, error)

BuildRotationProvider constructs node startup rotation state. On mainnet/testnet, activation authority comes only from the compiled production schedule artifact; local suite_registry is ignored there and never becomes a live activation or live binding source.

type DAAdmission

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

DAAdmission is a one-shot, chainstate-guarded DA candidate admission.

func (*DAAdmission) BeginCommit

func (a *DAAdmission) BeginCommit(victims []DAAdmissionVictim) (*DACommit, error)

BeginCommit is one-shot; its successful input-bearing candidate has a nonzero token. A refusal returns a nil commit and an error whose relay disposition is selected here from the owner error kind: UNAVAILABLE for an unavailable owner, CONFLICT for an occupied input, INTERNAL otherwise.

func (*DAAdmission) Close

func (a *DAAdmission) Close()

Close releases the admission guard after a failed attempt or terminal commit; a copied, live, or repeated Close fails fast without a second unlock.

func (*DAAdmission) Snapshot

func (a *DAAdmission) Snapshot() DAAdmissionSnapshot

Snapshot returns independent copies while the admission remains open.

type DAAdmissionDisposition

type DAAdmissionDisposition uint8

DAAdmissionDisposition describes a successful DA admission result. Only DAAdmissionRetained and DAAdmissionDuplicate are valid nonzero values.

const (
	DAAdmissionRetained  DAAdmissionDisposition = 1
	DAAdmissionDuplicate DAAdmissionDisposition = 2
)

type DAAdmissionResult

type DAAdmissionResult struct {
	DAID                   [32]byte
	Disposition            DAAdmissionDisposition
	SameDAIDCommitConflict bool
}

DAAdmissionResult reports a successful DA admission. On error, AdmitDA returns its zero value; SameDAIDCommitConflict is true only for a different-txid same-DAID commit duplicate.

type DAAdmissionSnapshot

type DAAdmissionSnapshot struct {
	TxID          [32]byte
	WTxID         [32]byte
	TxBytes       []byte
	Fee           consensus.Uint128
	RetainedBytes uint64
	Inputs        []consensus.Outpoint
}

DAAdmissionSnapshot is a defensive copy of a fully validated DA transaction.

type DAAdmissionVictim

type DAAdmissionVictim struct {
	TxID   [32]byte
	Inputs []consensus.Outpoint
	Token  PendingOutpointToken
}

DAAdmissionVictim identifies one finalized DA claim to remove at commit.

type DACommit

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

DACommit owns a prepared owner lock; copied, foreign, and repeated terminal calls fail fast without a second unlock.

func (*DACommit) Abort

func (g *DACommit) Abort()

Abort releases an unfinalized candidate and preserves prepared victims exactly once.

func (*DACommit) CandidateToken

func (g *DACommit) CandidateToken() PendingOutpointToken

CandidateToken returns the nonzero admission token or the zero removal token while live.

func (*DACommit) Commit

func (g *DACommit) Commit()

Commit finalizes the candidate and removes prepared victims exactly once.

type DAProvenance

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

DAProvenance identifies the source used for DA admission. Its zero value is invalid; peer provenance requires nonempty peer and quota identities.

func DetachedReorgDAProvenance

func DetachedReorgDAProvenance() DAProvenance

DetachedReorgDAProvenance returns detached-reorg provenance without peer or quota identities.

func LocalDAProvenance

func LocalDAProvenance() DAProvenance

LocalDAProvenance returns local provenance without peer or quota identities.

func NewPeerDAProvenance

func NewPeerDAProvenance(peerIdentity, quotaIdentity string) (DAProvenance, error)

NewPeerDAProvenance returns peer provenance when both identities are nonempty. Otherwise it returns zero DAProvenance and an error.

type DARelayChunk

type DARelayChunk struct {
	DAID        [32]byte
	ChunkHash   [32]byte
	ChunkIndex  uint16
	Payload     []byte
	WireBytes   uint64
	HashChecked bool
}

DARelayChunk is the unretained chunk descriptor ValidateDARelayChunk checks before local relay admission; retained members are admitted by AdmitDA from exact bytes.

type DARelayPrefetchPlan

type DARelayPrefetchPlan struct {
	DAID    [32]byte
	PeerKey string
	Indexes []uint16
}

DARelayPrefetchPlan is one caller-owned request reservation.

type DARelayState

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

func (*DARelayState) AdmitDA

func (s *DARelayState) AdmitDA(txBytes []byte, provenance DAProvenance) (result DAAdmissionResult, err error)

AdmitDA admits txBytes using provenance. It returns a zero DAAdmissionResult on error and a retained or duplicate disposition on success. A bound, parsed candidate with tx_nonce 0 returns the stable-terminal TX_ERR_TX_NONCE_INVALID rejection before any guard, retained, cache or owner access (RUBIN_COMPACT_BLOCKS.md Section 5.1 item 3).

func (*DARelayState) AdvanceOrphanTTL

func (s *DARelayState) AdvanceOrphanTTL() error

AdvanceOrphanTTL runs the owner-aware TTL tick once, all-or-nothing: each incomplete owner-ready record with ttl above one decrements once and mints one fresh revision; ttl one expires whole (members, locator rows, accounting, prefetch reservation and, on a bound relay, finalized owner claims) with no revision; valid C is a validated zero-TTL no-op, while zero A/B TTL fails. It returns commitOwnerReadyRemoval's error classes unwrapped; that body owns the fence; a nil receiver is not promised.

func (*DARelayState) CompactDAIdentities

func (s *DARelayState) CompactDAIdentities(expected *Mempool) ([]CompactCandidateIdentity, bool)

CompactDAIdentities captures the actual A/B/C retained members, without raw parsing or copying. The expected pointer proves the immutable canonical binding.

func (*DARelayState) CompleteSetCandidates

func (s *DARelayState) CompleteSetCandidates(maxPayloadBytes uint64) []CompleteDASetCandidate

CompleteSetCandidates returns caller-owned COMPLETE_SET snapshots up to maxPayloadBytes.

func (*DARelayState) LookupRetainedTx

func (s *DARelayState) LookupRetainedTx(txid [32]byte) (DARetainedTxSnapshot, bool, error)

LookupRetainedTx classifies txid from ONE guarded retained observation (RUBIN_COMPACT_BLOCKS.md 17.5): (snapshot, true, nil) for an integrity-valid member, (zero, false, nil) for a nil receiver or an unindexed txid, and (zero, false, errDARelayImageIncompatible) unwrapped for every other observation, located corruption included. It never re-reads, repairs or mutates DA, mempool or owner state.

func (*DARelayState) PlanPrefetch

func (s *DARelayState) PlanPrefetch(daID [32]byte, peerKeys []string, now time.Time) ([]DARelayPrefetchPlan, string)

PlanPrefetch reserves missing chunks for the supplied normalized peer keys. The complete reservation runs under the admission read fence.

func (*DARelayState) ReadCompactDA

func (s *DARelayState) ReadCompactDA(identity CompactCandidateIdentity, maxBytes uint64) CompactCandidateRead

ReadCompactDA copies only a matching target within maxBytes, then canonically parses it once off-lock. It neither clones companions nor validates admission.

func (*DARelayState) ReleasePeerQuotaKey

func (s *DARelayState) ReleasePeerQuotaKey(key string) error

ReleasePeerQuotaKey releases the retained members whose finalized PEER provenance carries key (typed match, never the cached quota key): a matching commit survives iff a LOCAL or DETACHED_REORG chunk is retained, keeping its charge and owner claim; an unblocked whole removal also carries the record's non-matching PEER members; an empty key selects nothing after the same preflight; a nil receiver returns nil. Valid C is validated but never selected. It takes no quota lock and returns commitOwnerReadyRemoval's error classes unwrapped, and that body owns the fence.

func (*DARelayState) ReleasePrefetchPlan

func (s *DARelayState) ReleasePrefetchPlan(plan DARelayPrefetchPlan)

ReleasePrefetchPlan releases one previously reserved prefetch plan under the admission read fence. Terminal refusal leaves the reservation frozen until restart.

type DARemoval

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

DARemoval is a one-shot, chainstate-guarded finalized-DA removal.

func (*DARemoval) BeginCommit

func (r *DARemoval) BeginCommit(victims []DAAdmissionVictim) (*DACommit, error)

BeginCommit is one-shot; a successful removal commit always has a zero token.

func (*DARemoval) Close

func (r *DARemoval) Close()

Close releases the removal guard after a failed attempt or terminal commit; copied, live, and repeated calls fail fast without a second unlock.

type DARetainedTxSnapshot

type DARetainedTxSnapshot struct {
	TxID    [32]byte
	WTxID   [32]byte
	TxBytes []byte
}

DARetainedTxSnapshot is one retained DA member copied out of the relay; it shares no memory with retained state.

type HeaderRequest

type HeaderRequest struct {
	FromHash [32]byte
	HasFrom  bool
	Limit    uint64
}

type Mempool

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

func NewMempool

func NewMempool(chainState *ChainState, blockStore *BlockStore, chainID [32]byte) (*Mempool, error)

func NewMempoolWithConfig

func NewMempoolWithConfig(chainState *ChainState, blockStore *BlockStore, chainID [32]byte, cfg MempoolConfig) (*Mempool, error)

func (*Mempool) AddRemoteTx

func (m *Mempool) AddRemoteTx(txBytes []byte) (retErr error)

AddRemoteTx admits a transaction received from a peer while preserving the same validation and admission policy as AddTx. The source is metadata only.

It is the compatibility wrapper over the SAME implementation AddRemoteTxForRelay drives: a nil relay probe is the only difference, and it changes no validation order, no mutation, no error, and no counter.

func (*Mempool) AddRemoteTxForRelay

func (m *Mempool) AddRemoteTxForRelay(txBytes []byte, expected *PendingOutpointAdmissionContext) RelayAdmissionResult

AddRemoteTxForRelay admits a transaction received from a peer through EXACTLY the AddRemoteTx implementation, and additionally publishes the producer-selected relay disposition, the parsed candidate identity, and — for a proven stable terminal rejection only — the exact stable admission context a relay representation cache needs.

expected is the caller's own observed pending-outpoint admission context. A nil expected context admits exactly as AddRemoteTx does, never sets HasAdmissionContext, and never authorizes caching. A NON-nil expected context is COPIED BY VALUE at this boundary and never dereferenced again: this call compares against, and publishes evidence for, the snapshot taken here, so a caller that mutates the pointee afterwards — from this goroutine or any other — can change neither this call's admission behavior nor its published evidence. The pointer is a presence flag only; the memory stays the caller's.

The snapshot is validated at the existing owner seam (PendingOutpointOwner.Reserve), after the baseline parse, consensus, policy, cheap-floor and duplicate precedence: a stale, superseded or mismatched context is UNAVAILABLE there, before the owner scans for a conflict and before it consumes a sequence.

It classifies without mutating: every classification input is either the producing branch's own decision or a pure read. Public errors, messages, admission counters, validation order and mutation order are untouched.

Nil-safe like every other exported Mempool accessor: a nil receiver returns RelayAdmissionUnavailable carrying the legacy "nil mempool" TxAdmitUnavailable error, publishes no identity and no context, and moves no counter.

func (*Mempool) AddReorgTx

func (m *Mempool) AddReorgTx(txBytes []byte) (retErr error)

AddReorgTx admits a transaction requeued from a disconnected canonical block while preserving the same validation and admission policy as AddTx.

func (*Mempool) AddTx

func (m *Mempool) AddTx(txBytes []byte) (retErr error)

func (*Mempool) AdmissionCounts

func (m *Mempool) AdmissionCounts() MempoolAdmissionCounts

AdmissionCounts returns a snapshot of the per-outcome admission counters bumped at the final return path of AddTx. Values are monotonic counts since process start. Returns a zero-valued struct on a nil receiver so callers (e.g. /metrics rendering) can scrape unconditionally. Field order matches the fixed metric rendering order in renderPrometheusMetrics.

func (*Mempool) AllTxIDs

func (m *Mempool) AllTxIDs() [][32]byte

AllTxIDs returns the txids of every transaction currently in the mempool. The slice ordering is not guaranteed to be stable between calls.

func (*Mempool) BeginDAAdmission

func (m *Mempool) BeginDAAdmission(raw []byte) (*DAAdmission, error)

BeginDAAdmission validates raw DA bytes and retains the admission guard until Close.

func (*Mempool) BeginDARemoval

func (m *Mempool) BeginDARemoval() (*DARemoval, error)

BeginDARemoval starts a candidate-free DA removal guarded until Close.

func (*Mempool) BytesUsed

func (m *Mempool) BytesUsed() int

BytesUsed returns the total raw byte size of transactions currently resident in the mempool. Mirrors the existing usedBytes accounting already maintained on every AddTx / RemoveTx path. Returns 0 on a nil receiver so callers (e.g. /metrics rendering) can scrape unconditionally.

func (*Mempool) CompactStandardIdentities

func (m *Mempool) CompactStandardIdentities() ([]CompactCandidateIdentity, bool)

CompactStandardIdentities captures all coherent admitted metadata, without copying or parsing raw bytes. An unavailable/incoherent image returns nil,false.

func (*Mempool) Contains

func (m *Mempool) Contains(txid [32]byte) bool

Contains reports whether a transaction with the given txid is currently present in the mempool.

func (*Mempool) CurrentMinFeeRateSnapshot

func (m *Mempool) CurrentMinFeeRateSnapshot() uint64

CurrentMinFeeRateSnapshot returns the rolling local floor without requiring the caller to already hold m.mu. It briefly takes a read lock so that race-free Stage C admission helpers (which run under a chainstate-side lock, not m.mu) can read the value safely.

It is exported so that external callers (e.g. the miner template loop in cmd/rubin-node) can wire MinerConfig.CurrentMempoolMinFeeRateFn directly to it and keep the relay-fee half of the Stage C admission contract aligned with the rolling floor.

Nil-safe like the other exported Mempool accessors (BytesUsed, AdmissionCounts, Contains): a nil receiver returns DefaultMempoolMinFeeRate so test-time wiring or fail-closed paths that never construct a Mempool see the documented baseline floor instead of a panic from m.mu.RLock().

func (*Mempool) EvictConfirmed

func (m *Mempool) EvictConfirmed(blockBytes []byte) error

func (*Mempool) EvictConfirmedParsed

func (m *Mempool) EvictConfirmedParsed(block *consensus.ParsedBlock) error

func (*Mempool) Len

func (m *Mempool) Len() int

func (*Mempool) PendingOutpointOwner

func (m *Mempool) PendingOutpointOwner() *PendingOutpointOwner

PendingOutpointOwner returns the single pending-outpoint owner bound to this mempool at construction. The pointer is stable for the mempool's lifetime; a nil receiver returns nil so callers can wire unconditionally.

func (*Mempool) ReadCompactStandard

func (m *Mempool) ReadCompactStandard(identity CompactCandidateIdentity, maxBytes uint64) CompactCandidateRead

ReadCompactStandard validates current selected associations before witness absence and budget decisions. Only its owned bounded target is parsed off-lock.

func (*Mempool) RelayMetadata

func (m *Mempool) RelayMetadata(txBytes []byte) (RelayTxMetadata, error)

RelayMetadata returns the metadata a relay peer needs to forward the transaction (fee + serialized size). It runs full structural + chainstate validation via checkParsedTransactionWithSnapshot and then enforces the rolling-relay-fee floor read-only. Below-floor otherwise-valid txs return the same TxAdmitUnavailable class/message family as admit-path validateFeeFloorLockedWithFloor.

RelayMetadata is not full mempool admission: it does not insert, does not record source/admission_seq, and does not check duplicate, conflict, or capacity state. Those remain owned by addTxWithSource/addEntryLockedProbed.

func (*Mempool) RemoveConflicting

func (m *Mempool) RemoveConflicting(blockBytes []byte) error

func (*Mempool) RemoveConflictingParsed

func (m *Mempool) RemoveConflictingParsed(block *consensus.ParsedBlock) error

func (*Mempool) RetainedTxByID

func (m *Mempool) RetainedTxByID(txid [32]byte) (RetainedTxSnapshot, bool)

RetainedTxByID snapshots the retained row indexed under txid.

The bool reports ONLY whether the primary txid index held that key under the read lock — never validity, availability, standard-domain, or relay authority. The method parses, hashes, validates and repairs nothing, and never consults the separate wtxid index. Raw is a defensive exact-length copy: mutating it cannot alter the retained entry or any later snapshot.

A present nil row is CORRUPTION, not absence, and stays distinguishable from it: it returns (IndexedTxID = the requested key, zero AdmissionWTxID, nil Raw, true), where a nil receiver or a missing key returns (zero snapshot, false). Classifying that corruption belongs to the caller.

func (*Mempool) SelectTransactions

func (m *Mempool) SelectTransactions(maxCount int, maxBytes int) [][]byte

func (*Mempool) SetCurrentMinFeeRateForTest

func (m *Mempool) SetCurrentMinFeeRateForTest(floor uint64)

SetCurrentMinFeeRateForTest overrides the rolling local floor. Test-only: bypasses the admit-path eviction logic that normally raises the floor. cmd/rubin-node tests inject a distinctive sentinel through this setter so the live miner wiring tests bind on the exact value, instead of admitting any closure returning the documented baseline. Nil-safe like the other accessors.

func (*Mempool) Stats

func (m *Mempool) Stats() MempoolStats

Stats returns a current snapshot of standard mempool telemetry state for the /metrics renderer. The snapshot reads live struct fields under the read lock — values are NOT cached duplicates of MempoolConfig defaults — so max_bytes, low_water_bytes, and min_fee_rate reflect the rolling state including the post-eviction adjustments performed by eviction and canonical-transition publication. EvictedResidentTotal is loaded INSIDE the read-lock window. Writers bump that counter under m.mu.Lock in the per-victim counter loop of addEntryLockedProbed — the one implementation of the locked admission path — so the reader's m.mu.RLock pairs with the writer's m.mu.Lock and the atomic.Load observes the same critical section as the gauge fields read on the surrounding lines. Covered by TestMempoolStatsScrapePurity and the TestMempoolStatsResidentEvictionIncrementsExactlyOnce assertion chain in clients/go/node/mempool_test.go.

Nil-safety follows the existing exported-accessor convention used by CurrentMinFeeRateSnapshot, BytesUsed, AdmissionCounts: a nil receiver returns counters/sizes 0, but MinFeeRate defaults to DefaultMempoolMinFeeRate. This keeps /metrics rendering on an uninitialized state agreeing with the rest of the Mempool API instead of advertising rubin_node_mempool_min_fee_rate = 0, which would disagree with CurrentMinFeeRateSnapshot's nil return and the documented baseline floor.

func (*Mempool) TxByID

func (m *Mempool) TxByID(txid [32]byte) ([]byte, bool)

TxByID returns the raw transaction bytes of a mempool entry with the given txid. The returned slice is a defensive copy and safe for the caller to retain or mutate. Returns (nil, false) if no matching entry is present.

func (*Mempool) TxIDsLimit

func (m *Mempool) TxIDsLimit(limit int) [][32]byte

TxIDsLimit returns at most limit txids from the current mempool snapshot. It returns nil when limit <= 0; use AllTxIDs for an unbounded snapshot. The slice ordering is not guaranteed to be stable between calls.

type MempoolAdmissionCounts

type MempoolAdmissionCounts struct {
	Accepted    uint64
	Conflict    uint64
	Rejected    uint64
	Unavailable uint64
}

MempoolAdmissionCounts is the snapshot view of admission outcomes. Field order matches the /metrics rendering order in renderPrometheusMetrics so the textual output is stable across readings. Values are monotonic counts since process start; readers MUST treat them as Prometheus counters.

type MempoolConfig

type MempoolConfig struct {
	MaxTransactions int
	MaxBytes        int
	// PolicyMaxDaBytesPerBlock caps the declared DA bytes of a DA_COMMIT
	// transaction admitted to mempool/relay policy. The value is derived from
	// DaCommitCore.ChunkCount * CHUNK_BYTES, not caller-supplied payload bytes.
	// A zero value is treated as omitted and normalized to the miner policy
	// default so partial configs do not accidentally disable the budget.
	PolicyMaxDaBytesPerBlock uint64
	PolicyDaSurchargePerByte uint64
	// MinDaFeeRate is the spec-side per-byte DA fee floor
	// (POLICY_MEMPOOL_ADMISSION_GENESIS.md Stage C `min_da_fee_rate`,
	// default 1). NewMempoolWithConfig treats 0 as omitted and normalizes
	// it to DefaultMinDaFeeRate; callers cannot disable the spec floor
	// through the public mempool config. Direct policy-helper tests may
	// still pass 0 to isolate surcharge-only helper semantics.
	MinDaFeeRate                         uint64
	PolicyRejectNonCoinbaseAnchorOutputs bool
	PolicyRejectSimplicityPreActivation  bool
	RotationProvider                     consensus.RotationProvider
	SuiteRegistry                        *consensus.SuiteRegistry
}

func DefaultMempoolConfig

func DefaultMempoolConfig() MempoolConfig

type MempoolStats

type MempoolStats struct {
	TxCount              int
	BytesUsed            int
	MaxBytes             int
	LowWaterBytes        int
	MinFeeRate           uint64
	EvictedResidentTotal uint64
}

MempoolStats is the snapshot view of standard mempool telemetry state. Field order matches the /metrics rendering order in renderPrometheusMetrics so the textual output is stable across readings. Reading a snapshot does not mutate any mempool state.

Nil-receiver contract (matches CurrentMinFeeRateSnapshot convention): a nil *Mempool returns counters and sizes set to zero (TxCount, BytesUsed, MaxBytes, LowWaterBytes, EvictedResidentTotal) but MinFeeRate set to DefaultMempoolMinFeeRate. Callers do not need to special-case uninitialized mempool wiring; /metrics on an un-wired state renders the documented baseline floor instead of 0.

type MineOneDisposition

type MineOneDisposition uint8

MineOneDisposition is the closed public-result class of one mining attempt. It is what a transport maps to its own status vocabulary — Section 3.4 maps these three to 200, 422 and 503 — so no transport has to classify an error string, a latch, a tip or a storage reread to answer.

const (
	// MineOneDispositionServiceUnavailable is a LOCAL condition rather than a
	// verdict on the candidate: an unavailable runtime, a latched engine, and
	// every failure at or after the durable commit stage — bounded resource,
	// stale plan, noncanonical store, precommit persistence, and every terminal
	// class including a terminal NEW that did publish.
	//
	// It is deliberately the ZERO value, so a MineOneOutcome whose Disposition
	// some later path leaves unset fails CLOSED on 503 instead of claiming a
	// success. That covers the STATUS only: CommitState has no safe zero — its
	// own zero is the empty string, which is outside the closed set — so every
	// MineOneOutcome built anywhere assigns it a constant or the state
	// canonicalMineOneOutcome selected, never a default.
	MineOneDispositionServiceUnavailable MineOneDisposition = iota
	// MineOneDispositionUnprocessable is the candidate's OWN failure: a
	// consensus or policy rejection, a nonce or build failure, a request
	// cancellation, or any other ordinary candidate outcome.
	MineOneDispositionUnprocessable
	// MineOneDispositionSuccess is a mined candidate that committed.
	MineOneDispositionSuccess
)

type MineOneOutcome

type MineOneOutcome struct {
	Block       *MinedBlock
	CommitState CanonicalCommitState
	Disposition MineOneDisposition
}

MineOneOutcome is the complete typed result of ONE MineOneWithOutcome invocation, and the only thing a caller needs to render Section 3.4's projection.

Block is nonnil exactly when the attempt published a candidate — including a terminal candidate NEW, which returns both the block identity and the terminal error. CommitState and Disposition are independent: a committed attempt can be unavailable (terminal NEW), and a not_committed one can be unprocessable (ordinary rejection) or unavailable (local failure).

type MinedBlock

type MinedBlock struct {
	Height    uint64
	Hash      [32]byte
	Timestamp uint64
	Nonce     uint64
	TxCount   int
}

type Miner

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

func NewMiner

func NewMiner(chainState *ChainState, blockStore *BlockStore, sync *SyncEngine, cfg MinerConfig) (*Miner, error)

func (*Miner) MineN

func (m *Miner) MineN(ctx context.Context, blocks int, txs [][]byte) ([]MinedBlock, error)

MineN mines blocks sequentially via MineOne, inheriting its cancellation postconditions; cancellation between blocks surfaces from the next call.

func (*Miner) MineOne

func (m *Miner) MineOne(ctx context.Context, txs [][]byte) (*MinedBlock, error)

MineOne observes ctx at entry (pre-bootstrap), every nonce attempt, and immediately before canonical apply; observing cancellation returns ctx.Err() with no write past the check. A nil ctx disables observation.

Callee-side ctx contract: every checkpoint is a NON-BLOCKING poll (a select with a default). MineOne never blocks on ctx.Done(), never retains ctx or its Done channel across checkpoints, and never shares ctx with another goroutine — so a caller may pass a single-goroutine context implementation whose Done/Err are only valid on the calling goroutine.

func (*Miner) MineOneWithOutcome

func (m *Miner) MineOneWithOutcome(ctx context.Context, txs [][]byte) (MineOneOutcome, error)

MineOneWithOutcome is MineOne plus the typed per-invocation commit state and public-result class of the attempt. It observes ctx at exactly the same checkpoints, returns exactly the same errors, and mutates exactly as much.

A caller that only needs the block should keep using MineOne; a caller that must PROJECT the attempt — Section 3.4's /mine_next is the one in tree — needs the outcome, because the block alone cannot distinguish a terminal candidate NEW (published, unavailable) from an ordinary success, nor an UNKNOWN truth from an ordinary refusal.

type MinerConfig

type MinerConfig struct {
	TimestampSource func() uint64
	MaxTxPerBlock   int
	Target          [32]byte
	// MineAddress is canonical CORE_P2PK covenant_data (suite_id || key_id)
	// used for the subsidy-bearing coinbase output.
	MineAddress []byte

	// PolicyDaAnchorAntiAbuse is the master switch for the whole DA/anchor
	// anti-abuse miner-template policy package. When false,
	// PolicyRejectNonCoinbaseAnchorOutputs is ignored. This is policy-only
	// and does not change consensus validity.
	PolicyDaAnchorAntiAbuse bool

	// PolicyRejectNonCoinbaseAnchorOutputs rejects transactions that create
	// CORE_ANCHOR outputs when PolicyDaAnchorAntiAbuse is enabled.
	// (Non-coinbase CORE_ANCHOR is treated as non-standard by policy.)
	PolicyRejectNonCoinbaseAnchorOutputs bool

	// PolicyMaxDaBytesPerBlock caps total DA payload bytes included in a block template (policy-only).
	// This is independent from the consensus DA byte cap.
	PolicyMaxDaBytesPerBlock uint64

	// PolicyDaSurchargePerByte is the operator-tunable DA per-byte surcharge
	// added on top of the spec-side DA floor in
	// POLICY_MEMPOOL_ADMISSION_GENESIS.md Stage C:
	//   da_required_fee(tx) = da_payload_len(tx) * (MinDaFeeRate + PolicyDaSurchargePerByte)
	// Setting it to 0 disables only the surcharge term, not the DA floor;
	// the DA floor still uses MinDaFeeRate.
	PolicyDaSurchargePerByte uint64

	// MinDaFeeRate is the spec-side per-byte DA fee floor
	// (POLICY_MEMPOOL_ADMISSION_GENESIS.md Stage C `min_da_fee_rate`,
	// default 1). Together with PolicyDaSurchargePerByte it composes the
	// DA half of the Stage C admission contract:
	//   da_required_fee(tx) = da_payload_len(tx) * (MinDaFeeRate + PolicyDaSurchargePerByte)
	// Setting it to 0 disables only the spec floor; the surcharge term
	// still applies when PolicyDaSurchargePerByte > 0.
	MinDaFeeRate uint64

	// CurrentMempoolMinFeeRate is the static fallback for the rolling
	// local floor when CurrentMempoolMinFeeRateFn is nil. Standalone
	// miner builds with no live mempool keep this at
	// DefaultMempoolMinFeeRate (the #1336 baseline). Live nodes SHOULD
	// set CurrentMempoolMinFeeRateFn instead so the miner template
	// reflects the rolling floor as it rises and decays.
	CurrentMempoolMinFeeRate uint64

	// CurrentMempoolMinFeeRateFn returns the live rolling local floor
	// for the relay-fee half of the Stage C admission contract:
	//   relay_fee_floor(tx) = weight(tx) * <floor returned by Fn>
	// Production wiring sets this to Mempool.CurrentMinFeeRateSnapshot
	// so the miner template stays aligned with the admission predicate
	// as the rolling floor changes. When nil the miner falls back to
	// CurrentMempoolMinFeeRate above.
	CurrentMempoolMinFeeRateFn func() uint64

	// PolicyRejectSimplicityPreActivation controls non-consensus
	// pre-activation guardrails for CORE_SIMPLICITY. When enabled, the
	// miner excludes CORE_SIMPLICITY transactions until the miner rotation
	// provider reports Simplicity active at the candidate height.
	PolicyRejectSimplicityPreActivation bool

	CompleteDASetProvider CompleteDASetProvider
}

func DefaultMinerConfig

func DefaultMinerConfig() MinerConfig

type PVTelemetry

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

PVTelemetry provides bounded-cardinality counters and latency tracking for parallel validation (Q-PV-13). All fields use atomic operations or mutex protection and are safe for concurrent access from multiple goroutines.

Telemetry contract:

  • No sensitive data (tx payloads, signatures, addresses) is recorded.
  • All counters are monotonic uint64 — bounded cardinality.
  • Latency tracking uses nanosecond-precision durations, not wall-clock timestamps.
  • Mismatch diagnostics are bounded by the existing PVShadowMaxSamples limit.

func NewPVTelemetry

func NewPVTelemetry(mode string) *PVTelemetry

NewPVTelemetry creates a new PV telemetry instance with the given mode.

func (*PVTelemetry) Mode

func (t *PVTelemetry) Mode() string

Mode returns the current PV mode.

func (*PVTelemetry) RecordBlockSkipped

func (t *PVTelemetry) RecordBlockSkipped()

RecordBlockSkipped increments the blocks-skipped counter.

func (*PVTelemetry) RecordBlockValidated

func (t *PVTelemetry) RecordBlockValidated()

RecordBlockValidated increments the blocks-validated counter.

func (*PVTelemetry) RecordCommitLatency

func (t *PVTelemetry) RecordCommitLatency(d time.Duration)

RecordCommitLatency records a commit phase latency.

func (*PVTelemetry) RecordMismatchError

func (t *PVTelemetry) RecordMismatchError()

RecordMismatchError increments the error-code mismatch counter.

func (*PVTelemetry) RecordMismatchState

func (t *PVTelemetry) RecordMismatchState()

RecordMismatchState increments the post-state-digest mismatch counter.

func (*PVTelemetry) RecordMismatchVerdict

func (t *PVTelemetry) RecordMismatchVerdict()

RecordMismatchVerdict increments the verdict mismatch counter.

func (*PVTelemetry) RecordMismatchWitness

func (t *PVTelemetry) RecordMismatchWitness()

RecordMismatchWitness increments the witness-digest mismatch counter.

func (*PVTelemetry) RecordSigs

func (t *PVTelemetry) RecordSigs(total, cacheHits uint64)

RecordSigs records a batch of signature verification operations.

func (*PVTelemetry) RecordValidateLatency

func (t *PVTelemetry) RecordValidateLatency(d time.Duration)

RecordValidateLatency records a validation phase latency.

func (*PVTelemetry) RecordWorkerPanic

func (t *PVTelemetry) RecordWorkerPanic()

RecordWorkerPanic increments the worker panic counter.

func (*PVTelemetry) RecordWorkerTasks

func (t *PVTelemetry) RecordWorkerTasks(n uint64)

RecordWorkerTasks records the number of tasks dispatched to the worker pool.

func (*PVTelemetry) SetMode

func (t *PVTelemetry) SetMode(mode string)

SetMode updates the current PV mode label.

func (*PVTelemetry) Snapshot

func (t *PVTelemetry) Snapshot() PVTelemetrySnapshot

Snapshot returns a point-in-time copy of all telemetry counters.

type PVTelemetrySnapshot

type PVTelemetrySnapshot struct {
	Mode string

	BlocksValidated uint64
	BlocksSkipped   uint64

	MismatchVerdict uint64
	MismatchError   uint64
	MismatchState   uint64
	MismatchWitness uint64

	SigTotal     uint64
	SigCacheHits uint64

	WorkerTasksTotal uint64
	WorkerPanics     uint64

	ValidateCount int64
	ValidateAvgNs int64
	CommitCount   int64
	CommitAvgNs   int64
}

PVTelemetrySnapshot is a point-in-time copy of all telemetry counters. All fields are plain values — no sensitive data, no unbounded strings.

func (PVTelemetrySnapshot) PrometheusLines

func (s PVTelemetrySnapshot) PrometheusLines() []string

PrometheusLines returns the telemetry snapshot as Prometheus-compatible text exposition lines. All metric names use the rubin_pv_ prefix.

type PeerManager

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

func NewPeerManager

func NewPeerManager(cfg PeerRuntimeConfig) *PeerManager

func (*PeerManager) AddPeer

func (pm *PeerManager) AddPeer(state *PeerState) error

func (*PeerManager) Count

func (pm *PeerManager) Count() int

func (*PeerManager) RemovePeer

func (pm *PeerManager) RemovePeer(addr string)

func (*PeerManager) Snapshot

func (pm *PeerManager) Snapshot() []PeerState

func (*PeerManager) UpsertPeer

func (pm *PeerManager) UpsertPeer(state *PeerState) error

type PeerRuntimeConfig

type PeerRuntimeConfig struct {
	Network          string
	MaxPeers         int
	ReadDeadline     time.Duration
	WriteDeadline    time.Duration
	HandshakeTimeout time.Duration
	BanThreshold     int
	MaxMessageSize   uint32
}

func DefaultPeerRuntimeConfig

func DefaultPeerRuntimeConfig(network string, maxPeers int) PeerRuntimeConfig

type PeerState

type PeerState struct {
	Addr              string
	LastError         string
	RemoteVersion     VersionPayloadV1
	BanScore          int
	HandshakeComplete bool
}

type PendingOutpointAdmissionContext

type PendingOutpointAdmissionContext struct {
	StableTip  PendingOutpointTip
	Generation uint64
}

PendingOutpointAdmissionContext is one linearizable read of the owner's admission-visible state: the exact stable canonical tip reservations are currently bound to, and the monotonic transition generation that tip belongs to.

Generation is the cache-validity term. The initial stable context and every begun canonical transition have DISTINCT generations, and neither a commit nor an abort ever decreases or reuses the generation high-water, so an A->B->A reorg and a failed transition both produce a generation no earlier context ever carried. A downstream policy cache may therefore treat an unchanged generation, and only that, as "nothing observable moved".

type PendingOutpointDomain

type PendingOutpointDomain uint8

PendingOutpointDomain names the pool that owns a pending-outpoint claim. StandardMempool and DA share one owner through distinct domains.

const (
	// PendingOutpointStandardMempool is the standard Mempool admission domain.
	PendingOutpointStandardMempool PendingOutpointDomain = 1
	// PendingOutpointDA is the data-availability domain.
	PendingOutpointDA PendingOutpointDomain = 2
)

type PendingOutpointError

type PendingOutpointError struct {
	Kind         PendingOutpointErrorKind
	Msg          string
	Outpoint     consensus.Outpoint
	InputIndex   int
	ExistingTxid [32]byte
}

PendingOutpointError is the typed owner error. Conflict evidence fields are meaningful only for PendingOutpointConflict.

func (*PendingOutpointError) Error

func (e *PendingOutpointError) Error() string

type PendingOutpointErrorKind

type PendingOutpointErrorKind uint8

PendingOutpointErrorKind classifies pending-outpoint failures.

const (
	// PendingOutpointConflict reports an outpoint already claimed by another
	// live reservation. Evidence names the first conflicting outpoint in the
	// supplied input order, its index, and the claiming txid.
	PendingOutpointConflict PendingOutpointErrorKind = iota + 1
	// PendingOutpointUnavailable reports a temporarily closed owner: an active
	// canonical transition, an expected-tip mismatch, a stale generation, or an
	// exhausted sequence space.
	PendingOutpointUnavailable
	// PendingOutpointInternal reports a malformed request or an owner-state
	// inconsistency. It never publishes domain state.
	PendingOutpointInternal
)

type PendingOutpointOwner

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

PendingOutpointOwner is the single authority over outpoints claimed by in-flight and resident pool candidates.

Lock contract: standard callers use ChainState.admissionMu -> Mempool.mu -> owner. DA callers hold the continuous ChainState admission guard and a downstream DA state lock before owner; this primitive never takes that lock. Callers materialize buffers and scratch before owner; only bounded owner-map bucket growth may occur while publishing one prepared candidate claim.

func (*PendingOutpointOwner) AdmissionContext

AdmissionContext reports the current stable tip and generation, read under ONE owner-lock acquisition so the pair is always internally consistent. It mutates nothing.

It returns false — never a stale or partial context — when the owner is nil, when a canonical transition is active (including the terminal fail-closed state a latched post-commit persistence fault leaves behind), or when the generation space is exhausted so no further transition could ever be distinguished. A reader racing a transition begin therefore observes either the prior stable context or unavailability, never a stable context paired with an active transition.

This is the ONLY downstream policy-generation seam on the owner: it adds no generic TxPool method, no cache, no callback, no notification hook and no DA behavior.

func (*PendingOutpointOwner) Finalize

func (o *PendingOutpointOwner) Finalize(token PendingOutpointToken) error

Finalize publishes a reserved claim of the current generation. An exact retry of an already-finalized current-generation token succeeds without a second mutation. Finalization during a transition, after a release, or from an older generation is unavailable and publishes nothing; an invalid or foreign token identity is internal.

func (*PendingOutpointOwner) Release

Release drops a claim and every by-outpoint row it installed, or drops none. It is generation-independent and remains valid during a transition. An exact retry after the claim is already gone succeeds and leaves no tombstone. A zero token, a foreign owner, a sequence above the high-water mark, or a partially matching live index is internal and changes nothing.

func (*PendingOutpointOwner) Reserve

func (o *PendingOutpointOwner) Reserve(
	expectedContext PendingOutpointAdmissionContext,
	domain PendingOutpointDomain,
	txid [32]byte,
	orderedInputs []consensus.Outpoint,
) (PendingOutpointToken, error)

Reserve claims every outpoint in orderedInputs for txid in domain, bound to the COMPLETE admission context the caller observed — stable tip AND generation, deliberately not a tip alone, so a caller that decided anything under an older generation loses instead of reserving against state it never saw. It validates the request (owner, domain, txid, input set) before it looks at availability or conflicts, so a malformed request is an internal error that mutates nothing and consumes no sequence. Availability failures — active transition, expected-tip mismatch, expected-generation mismatch, sequence exhaustion — and the first conflict in canonical input order likewise mutate no claim, index or sequence: every check is a pure read that completes before the first such write below; only the reserveCalls observation count moves. On success exactly one sequence is consumed and the complete reserved claim is installed.

type PendingOutpointTip

type PendingOutpointTip struct {
	HasTip bool
	Height uint64
	Hash   [32]byte
}

PendingOutpointTip is the stable canonical tip a reservation is bound to. A reservation whose expected tip differs from the owner's committed stable tip is unavailable, never a conflict.

type PendingOutpointToken

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

PendingOutpointToken identifies exactly one reservation. It is comparable and opaque outside package node: it carries the issuing owner's identity and a nonzero monotonic sequence, has no exported constructor, and is never serialized. A token from a previous process, or from any other owner, is foreign to this owner by construction.

type RelayAdmissionDisposition

type RelayAdmissionDisposition uint8

RelayAdmissionDisposition is the closed classification of ONE remote-mempool admission outcome, published for relay-side download and representation state. The enum is exactly the eleven values below, and every production exit of Mempool.AddRemoteTxForRelay selects one of them AT the branch that decided the outcome, before any compatibility mapping onto TxAdmitErrorKind — except for the fail-closed RelayAdmissionInternal override a failed REQUIRED post-decision cleanup applies over that selection (see RelayAdmissionInternal).

A consumer MUST NOT infer a disposition from TxAdmitError.Kind, from Error(), from message text, from the HTTP status mapping, or from a fallback default: those are lossy compatibility views. TxAdmitConflict alone carries both the DUPLICATE and the CONFLICT branch, and TxAdmitUnavailable carries the floor, capacity, sequence, dependency-free unavailability and internal branches.

The zero value is deliberately NOT a member of the enum, so a value that no branch selected can never be mistaken for a classification.

const (
	// RelayAdmissionRetained means the exact candidate representation is
	// resident in the mempool after the call.
	RelayAdmissionRetained RelayAdmissionDisposition = iota + 1
	// RelayAdmissionStableTerminalReject is an explicit canonical, structural,
	// consensus, or constructor-frozen context-bound static-policy rejection.
	// It is the ONLY disposition that may carry cache-authorizing context
	// evidence, and only when that exact context was proven for this call.
	//
	// A policy lane OUTCOME whose verdict depends on state the published context
	// does NOT pin is therefore not one of these, however static its
	// configuration looks: a CORE_SIMPLICITY pre-activation outcome decided from
	// a deployment provider reads a published deployment set that a
	// {StableTip, Generation} context does not bind, so it is UNAVAILABLE. The
	// classification is per outcome, not per lane — the same lane's
	// well-formedness rejection reads no deployment set and stays here
	// (see relayDispositionForSimplicityPreActivationOutcome).
	RelayAdmissionStableTerminalReject
	// RelayAdmissionDuplicate means a resident txid or wtxid duplicate.
	RelayAdmissionDuplicate
	// RelayAdmissionConflict means an exact existing pending-outpoint owner
	// conflict.
	RelayAdmissionConflict
	// RelayAdmissionMissingDependency means a referenced input is absent or not
	// spendable yet. It is retryable and is never stable-terminal: the same
	// bytes can admit at a later height.
	RelayAdmissionMissingDependency
	// RelayAdmissionRollingFloor is the retryable rolling-relay-fee-floor
	// outcome.
	RelayAdmissionRollingFloor
	// RelayAdmissionCapacity is the retryable capacity outcome.
	RelayAdmissionCapacity
	// RelayAdmissionAdmissionSequence is the admission-sequence outcome.
	RelayAdmissionAdmissionSequence
	// RelayAdmissionUnavailable covers an absent chain, owner or admission
	// context, an active canonical transition, a stale expected context,
	// retryable runtime unavailability, and a CORE_SIMPLICITY deployment state
	// this node could not determine from the admission inputs it has — a
	// consensus error carrying TxErrorCauseSimplicityDeployment{Unavailable,
	// EvidenceInvalid, InactiveProvider}, whose public code and message say only
	// "not active" while the deployment set the answer came from is not pinned
	// by the published context. An uncaused TX_ERR_SIG_ALG_INVALID under an untrusted native-suite policy snapshot is also unavailable.
	// The frozen no-provider state is NOT one of these: it reads no set and stays a stable terminal rejection.
	RelayAdmissionUnavailable
	// RelayAdmissionInternal covers an impossible invariant, a retained
	// identity mismatch, accounting corruption, an adapter contract violation,
	// and a process-local crypto-backend fault — a consensus error carrying
	// consensus.TxErrorCauseLocalCryptoBackendFault, whose public code says
	// nothing about whether this node could decide at all.
	//
	// That last class is INTERNAL rather than UNAVAILABLE because it is THIS
	// process failing closed, not a missing admission input the node is waiting
	// on; either way it is not stable invalidity of these bytes, so neither is
	// cache-authorizing.
	//
	// It is also the ONE disposition a branch does not have to select: a
	// REQUIRED post-decision cleanup step that reports a fault — pending-outpoint
	// owner accounting corruption, a claim inconsistency — publishes INTERNAL and
	// OUTRANKS the disposition the deciding branch already selected, because that
	// branch's verdict is no longer the whole truth about the call. The public
	// error still reports the branch's outcome unchanged, so a consumer that
	// wants the corruption signal MUST read the disposition.
	RelayAdmissionInternal
	// RelayAdmissionCancelled is a closed enum value ONLY. This surface
	// implements no cancellation framework and no production branch selects it.
	RelayAdmissionCancelled
)

func (RelayAdmissionDisposition) String

func (d RelayAdmissionDisposition) String() string

String renders the closed enum name. A value outside the enum — including the zero value that means "no branch selected" — renders as UNSELECTED and is never a classification.

type RelayAdmissionResult

type RelayAdmissionResult struct {
	Disposition         RelayAdmissionDisposition
	TxID                [32]byte
	WTxID               [32]byte
	AdmissionContext    PendingOutpointAdmissionContext
	HasAdmissionContext bool
	Err                 error
}

RelayAdmissionResult is the immutable result of one relay admission. It is returned by value and holds no reference the caller can mutate back into the mempool.

TxID and WTxID are the identities the producer PARSED from the candidate bytes; they are the zero hash when the candidate never parsed canonically.

AdmissionContext is meaningful ONLY when HasAdmissionContext is true, and is the zero context otherwise. HasAdmissionContext is set only for RelayAdmissionStableTerminalReject, and only when the caller-supplied expected context was proven equal to the exact complete stable admission context this call validated against. Nothing else authorizes a relay representation cache.

Disposition is the deciding branch's own selection, EXCEPT when a REQUIRED post-decision cleanup step reported a fault: that publishes RelayAdmissionInternal and outranks the branch's selection, while Err keeps reporting the branch's outcome byte-identically. Disposition is therefore the only field that can report an accounting corruption the cleanup layer found.

Err is the unchanged public admission error the equivalent AddRemoteTx call returns: same type, same TxAdmitErrorKind, same message. It is nil exactly on the success exit, whose disposition is RelayAdmissionRetained — or, if the published record somehow failed to be the exact candidate, the retained-identity-mismatch RelayAdmissionInternal that a nil error can also carry.

type RelayTxMetadata

type RelayTxMetadata struct {
	Fee  consensus.Uint128
	Size int
}

RelayTxMetadata is the relay-visible view of an admitted transaction. Fee is the same exact u128 scalar the mempool entry holds, so relay ordering and pool eviction see the authoritative admitted fee unnarrowed.

type RetainedTxSnapshot

type RetainedTxSnapshot struct {
	IndexedTxID    [32]byte
	AdmissionWTxID [32]byte
	Raw            []byte
}

RetainedTxSnapshot is one indivisible read of a retained mempool row: the txid it is indexed under, the wtxid stored at its admission, and a defensive copy of its exact retained bytes, all read under one continuously held mempool read lock so that they describe one row incarnation and never a mixed tuple.

type RotationConfigJSON

type RotationConfigJSON struct {
	Name         string `json:"name"`
	OldSuiteID   uint8  `json:"old_suite_id"`
	NewSuiteID   uint8  `json:"new_suite_id"`
	CreateHeight uint64 `json:"create_height"`
	SpendHeight  uint64 `json:"spend_height"`
	SunsetHeight uint64 `json:"sunset_height,omitempty"`
}

RotationConfigJSON is the JSON-serializable rotation descriptor for node config. When present on non-production networks, the node constructs a DescriptorRotationProvider from it. Production networks derive activation only from the compiled schedule artifact.

type SelectedSideMutationOutcome

type SelectedSideMutationOutcome struct {
	Result, Decision, CanonicalTruth string
	Truth                            mdbx.CommitTruth
	Stage                            mdbx.UpdateStage
	Err                              error
}

SelectedSideMutationOutcome is one invocation's logical result beside the exact raw Update tuple of the attempt that terminated it. Result, Decision and CanonicalTruth stay empty when no callback of that attempt ran.

func PrepareSelectedSideRollingMDBX

func PrepareSelectedSideRollingMDBX(store *mdbx.Store, reservations *mdbx.OperationReservationOwner, raw []byte, expectedTip *mdbx.AuthorityPointV1) SelectedSideMutationOutcome

PrepareSelectedSideRollingMDBX prepares the rolling of a full 1440-row selected side for one raw exact-tip child under an untrusted expected canonical tip locator. A healthy oldest row leaves into SIDE(g,first,first,first) with count 1439; positive oldest damage is the complete clear instead. It returns the terminating attempt's whole tuple, like RetainSelectedSideMDBX.

func RefillSelectedSideMDBX

func RefillSelectedSideMDBX(store *mdbx.Store, reservations *mdbx.OperationReservationOwner, raw []byte) SelectedSideMutationOutcome

RefillSelectedSideMDBX is RF: a fresh raw candidate at first-1 of a cleaned one-slot selected side (C >= 1440, count 1439, no pending SIDE) whose hash is the first retained header's parent restores that row: count 1440, first-1, bytes+n, exact header/body/SideLink(g,first-1) with work = first-link work minus first-header work; the incumbent tip/hash/work, g, F and next stay and no new-tip comparison is made. It shares Retain's attempts, grant, Update, recheck/retry and raw tuple rules and takes no expected-tip locator.

func ReplaceSelectedSideMDBX

func ReplaceSelectedSideMDBX(store *mdbx.Store, reservations *mdbx.OperationReservationOwner, raw []byte, expectedTip *mdbx.AuthorityPointV1) SelectedSideMutationOutcome

ReplaceSelectedSideMDBX is the separate N3 replacement: a freshly qualified winning canonical-parent child clears the live selected side into its SIDE span without storing the candidate. It shares Retain's attempts and tuple rules.

func RetainSelectedSideMDBX

func RetainSelectedSideMDBX(store *mdbx.Store, reservations *mdbx.OperationReservationOwner, raw []byte, expectedTip *mdbx.AuthorityPointV1) SelectedSideMutationOutcome

RetainSelectedSideMDBX retains one raw candidate under an untrusted expected canonical tip locator. It returns the terminating attempt's whole tuple: the first attempt, a non-healthy recheck of its clean damage locator, or the single fresh attempt a healthy recheck permits.

type SpentUndo

type SpentUndo struct {
	Outpoint consensus.Outpoint
	Entry    consensus.UtxoEntry
}

type SuiteParamsJSON

type SuiteParamsJSON struct {
	SuiteID    uint8   `json:"suite_id"`
	PubkeyLen  uint32  `json:"pubkey_len"`
	SigLen     uint32  `json:"sig_len"`
	VerifyCost uint64  `json:"verify_cost"`
	AlgName    *string `json:"-"`
}

SuiteParamsJSON is the JSON-serializable registry entry used for controlled native-suite bootstrap without editing the built-in default registry.

func (SuiteParamsJSON) MarshalJSON

func (item SuiteParamsJSON) MarshalJSON() ([]byte, error)

func (*SuiteParamsJSON) UnmarshalJSON

func (item *SuiteParamsJSON) UnmarshalJSON(data []byte) error

type SyncConfig

type SyncConfig struct {
	ExpectedTarget   *[32]byte
	ChainStatePath   string
	HeaderBatchLimit uint64
	IBDLagSeconds    uint64
	DAMempoolSize    uint64
	ChainID          [32]byte
	Network          string
	RotationProvider consensus.RotationProvider
	SuiteRegistry    *consensus.SuiteRegistry

	ParallelValidationMode string // off|shadow|on
	PVShadowMaxSamples     uint64 // bounded mismatch diagnostics; 0 => default
}

func DefaultSyncConfig

func DefaultSyncConfig(expectedTarget *[32]byte, chainID [32]byte, chainStatePath string) SyncConfig

type SyncEngine

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

func NewSyncEngine

func NewSyncEngine(chainState *ChainState, blockStore *BlockStore, cfg SyncConfig) (*SyncEngine, error)

func (*SyncEngine) ApplyBlock

func (s *SyncEngine) ApplyBlock(blockBytes []byte, prevTimestamps []uint64) (*ChainStateConnectSummary, error)

ApplyBlock connects one block that must extend the current canonical tip, inside exactly one canonical transition.

Return contract, which every caller may rely on:

  • (summary, nil) — ordinary ACCEPTED/NEW. C1/M1/O1 are published, the accepted counter is advanced and admission is open again.
  • (summary, err) — EXACTLY and ONLY TERMINAL_PERSISTENCE(new): the truth is NEW, so the complete image, the summary and the accepted delta are published, the engine latches and admission stays closed until restart, and zero requeue owners are invoked. A caller that treats a non-nil error as "nothing happened" is wrong for this one case.
  • (nil, err) — every other outcome. An OLD/open refusal (local parent-row mismatch, plan bound, precommit persistence error, resource unavailability, stale plan) PUBLISHES nothing: no canonical index write, no C1/M1/O1, no counter, no latch, live image untouched. A refusal reached after the precommit steps does leave durable residue — this block's staged header/block/undo, and the rewritten checkpoint, here the pre-apply image the refusal preserved anyway — harmless by construction: staged rows stay noncanonical until an index commit names them, and the checkpoint row belongs to old and planned-new alike. A latched outcome likewise publishes nothing and keeps admission closed.

Nil-safe on the receiver, like the other exported SyncEngine methods.

func (*SyncEngine) ApplyBlockWithReorg

func (s *SyncEngine) ApplyBlockWithReorg(blockBytes []byte, prevTimestamps []uint64) (*ChainStateConnectSummary, error)

ApplyBlockWithReorg is the relay entry point: it connects a tip extension, or stores a losing side-branch block, or switches to a winning branch — whichever fork choice selects — and any canonical switch runs inside exactly one canonical transition.

It has the same return contract as ApplyBlock:

  • (summary, nil) — ordinary ACCEPTED/NEW, or the synthetic summary for a stored side-branch block that did not win fork choice.
  • (summary, err) — EXACTLY and ONLY TERMINAL_PERSISTENCE(new): C1/M1/O1 and the accepted delta are published for the whole branch, the engine latches, admission stays closed until restart, and zero requeue owners run.
  • (nil, err) — every other outcome, including a consensus rejection, a side-block LOCAL_STORE_ERROR(noncanonical) that never latches, and every OLD/open canonical refusal. A canonical refusal PUBLISHES nothing — no index write, no C/M/O, no counter, no latch, live image untouched — but one reached after the precommit steps leaves the whole branch's staged artifacts behind and the checkpoint rewritten to the COMMON ANCESTOR image, which lags the preserved live tip. Both harmless: staged rows stay noncanonical, and startup replays the unchanged canonical index forward from that common row.

Nil-safe on the receiver, like the other exported SyncEngine methods.

func (*SyncEngine) ApplyBlockWithReorgDeferred

func (s *SyncEngine) ApplyBlockWithReorgDeferred(blockBytes []byte, prevTimestamps []uint64) (*ChainStateConnectSummary, func(), error)

ApplyBlockWithReorgDeferred keeps admissions serialized and returns a nonnil finish that owns every pending retained-result lease. The caller must invoke it synchronously and immediately after releasing its outer canonical lock, including on returned error. finish is serial and idempotent. A panic before handoff cancels pending leases, including diagnostic panics.

func (*SyncEngine) BestKnownHeight

func (s *SyncEngine) BestKnownHeight() uint64

func (*SyncEngine) BlockApplyCounts

func (s *SyncEngine) BlockApplyCounts() BlockApplyCounts

func (*SyncEngine) BootstrapCanonicalGenesisIfEmpty

func (s *SyncEngine) BootstrapCanonicalGenesisIfEmpty() error

BootstrapCanonicalGenesisIfEmpty applies the published canonical genesis block to an empty chainstate when the configured network has one, so the chain always starts from the published bytes rather than from a miner- synthesized height-0 block. The height-0 genesis-identity guard in applyCanonicalParsedBlock rejects any block at height 0 whose hash differs from devnetGenesisBlockHash under a devnet ChainID; without this bootstrap the miner-driven empty-chain path would always produce a non-canonical height-0 block (current timestamp / freshly mined nonce) and fail under that guard.

Idempotent. No-op when:

  • the chainstate already has a tip (HasTip is true), or
  • the configured SyncConfig.ChainID does not identify a network with a published canonical genesis (currently only devnetGenesisChainID is recognized; the all-zero ChainID used by ephemeral unit tests is skipped on purpose to preserve those tests' synthetic genesis fixtures, mirroring the chain_id guard's zero-ChainID skip clause in applyCanonicalParsedBlock).

On success, the chainstate's tip is the published devnet genesis at height 0 and the canonical genesis bytes are persisted to the block store via the normal ApplyBlock path. Returns the ApplyBlock error directly on failure; callers wrap if they want a function-prefix.

A LATCHED apply is never reported as success. If the apply leaves the engine persistence-faulted or admission latched — including TERMINAL_PERSISTENCE(new), where genesis C1 WAS published — this returns that exact terminal error and never reinterprets the published tip as concurrent success. nil is returned for exactly one failure shape: a nonterminal apply error on an unlatched engine whose recheck finds a tip another writer installed on the shared ChainState.

Defensive nil-receiver guard mirrors the pattern used by other exported SyncEngine methods (HeaderSyncRequest, RecordBestKnownHeight, ...). Other exported methods are nil-safe and there are existing tests that exercise the nil-receiver path; this method joins that contract for consistency.

func (*SyncEngine) ClaimDARelayState

func (s *SyncEngine) ClaimDARelayState(expectedRelay *DARelayState, admitDetachedReorg func([]byte) (func(bool), error)) (*DARelayState, error)

ClaimDARelayState atomically publishes the sole lifetime Service claim and its detached-reorg admission callback.

func (*SyncEngine) DARelayState

func (s *SyncEngine) DARelayState() *DARelayState

DARelayState returns the read-only relay-state pointer bound with the engine's initial mempool. It never consumes the lifetime Service claim.

func (*SyncEngine) DisconnectTip

func (s *SyncEngine) DisconnectTip() (*ChainStateDisconnectSummary, error)

DisconnectTip removes the current canonical tip inside exactly one canonical transition. A1 is EMPTY — no block becomes canonical — so there is no accepted delta and no connected-block fee decay event.

Return contract:

  • (summary, nil) — ordinary NEW: the shortened C1 and the matching M1/O1 are published and admission is open again.
  • (summary, err) — EXACTLY and ONLY TERMINAL_PERSISTENCE(new): the shortened image is published because the truth is NEW, and the engine still latches with admission closed until restart.
  • (nil, err) — every other outcome. An OLD/open refusal PUBLISHES nothing: no index write, no C1/M1/O1, no counter, no latch, live tip preserved. Its new suffix is empty, so it stages no artifacts; one reached after the checkpoint step does leave that file rewritten to the POST-disconnect image — the row both identities share, from which startup replays the still-listed tip row back.

Nil-safe on the receiver, like the other exported SyncEngine methods.

func (*SyncEngine) EffectiveDAMempoolSize

func (s *SyncEngine) EffectiveDAMempoolSize() (uint32, error)

EffectiveDAMempoolSize observes the DA capacity the bound relay enforces so Version.da_mempool_size can advertise it (RUBIN_COMPACT_BLOCKS.md Section 18.3, RUBIN_L1_P2P_AUX.md Section 3.1). Postconditions: the bound relay's staged cap, read on every call, is the only source, so a successful result equals the cap that relay enforces whatever any configuration copy holds; the cap is accepted only inside 536870912..4294967295 before the u32 narrowing; a nil engine, an engine with no bound relay, and a bound cap outside that range (zero, below the minimum, above u32) return 0 and an error; nothing is mutated and the lifetime Service claim is not consumed.

func (*SyncEngine) HeaderSyncRequest

func (s *SyncEngine) HeaderSyncRequest() HeaderRequest

func (*SyncEngine) IsInIBD

func (s *SyncEngine) IsInIBD(nowUnix uint64) bool

func (*SyncEngine) LastReorgDepth

func (s *SyncEngine) LastReorgDepth() uint64

func (*SyncEngine) LocalTipHeight

func (s *SyncEngine) LocalTipHeight() uint64

LocalTipHeight is the published local tip height read through the coherent chainstate view, or 0 for a nil engine/chainstate or no published tip; it is never BestKnownHeight and is the P2P peer-quality policy's only height source.

func (*SyncEngine) PVShadowStats

func (s *SyncEngine) PVShadowStats() (mismatches uint64, samples []string)

func (*SyncEngine) PVTelemetry

func (s *SyncEngine) PVTelemetry() *PVTelemetry

PVTelemetry returns the PV telemetry instance for metrics export.

func (*SyncEngine) RecordBestKnownHeight

func (s *SyncEngine) RecordBestKnownHeight(height uint64)

func (*SyncEngine) ReorgCount

func (s *SyncEngine) ReorgCount() uint64

func (*SyncEngine) SetMempool

func (s *SyncEngine) SetMempool(mempool *Mempool)

SetMempool binds, EXACTLY ONCE, the mempool whose pending-outpoint owner this engine drives, serializing on mutationMu so a canonical transition can never observe the pointer set change under it. Initialization-only is the contract, not a convenience: a pool detached at tip A, held while the engine advances, and handed back at an apparently equal tip carries records and claims bound to a canonical history this engine no longer has, and a pointer comparison cannot see that. So only a NEVER-USED pool at the guarded live tip binds — emptiness is not enough, because a pool admitted at tip A and drained back to zero is index-identical to a fresh one and only its history-bearing state (admission sequence, rolling fee floor, cumulative counters, owner high-waters) still says otherwise — and afterwards only the exact same pointer is accepted. A rejection mutates neither the engine nor the candidate's policy, records, indexes, owner state or high-waters, and is reported only through the existing bounded stderr diagnostic; no new public error kind is introduced.

func (*SyncEngine) SetStderr

func (s *SyncEngine) SetStderr(w io.Writer)

SetStderr sets the writer for non-fatal error diagnostics (e.g. mempool post-acceptance failures). A nil writer maps to io.Discard, which is also the default when SetStderr is never called.

The writer MUST be safe for concurrent use — the conventional io.Writer property that os.Stderr and *os.File already hold. Flushes deliberately run outside mutationMu, so two mutations' flush windows may overlap; serializing them behind a flush lock was rejected because a wedged writer would then stall another mutator's return, which is the very class this design removes.

What the engine ENFORCES rather than assumes: the writer is never invoked while mutationMu, s.mu, or any ChainState / Mempool / PendingOutpointOwner lock is held, so it may block or re-enter a non-diagnostic SyncEngine mutation without stalling or deadlocking a mutator. Write errors are ignored: a diagnostic never changes a consensus, persistence, publication or mempool result.

ONE carve-out: terminal fail-closed publication retains the physical ChainState admission writer until restart while its diagnostic flush runs. Fallible read consumers complete with unavailable; direct exclusive acquisition stays closed. SyncEngine mutations refuse through mutationAllowed before touching that guard.

The replacement is a race-free pointer store under s.mu; a flush already in progress keeps the writer it snapshotted.

func (*SyncEngine) StockDevnetTargetSchedule

func (s *SyncEngine) StockDevnetTargetSchedule() bool

StockDevnetTargetSchedule reports the predicate for THIS engine, from the engine's OWN normalized configuration. Every layer that defers a target decision to an engine MUST ask that engine rather than consult a separate SyncConfig copy: a layer holding its own copy could otherwise select a different rule than the engine it hands the block to, which is a same-process accept/reject divergence. Mirrors Rust's SyncEngine::stock_devnet_target_schedule.

Nil-receiver safe, like the other exported SyncEngine methods: a nil engine reports false, which keeps the caller on its pre-existing static behavior instead of panicking on a validity path.

func (*SyncEngine) TerminalFaulted

func (s *SyncEngine) TerminalFaulted() bool

TerminalFaulted reports whether this engine has latched the terminal storage persistence fault that closes admission until the node is restarted. It is the read-only projection of the EXISTING latch (the same one mutationAllowed fails closed on), for operator surfaces such as GET /health.

It exposes only the boolean: the latched cause is never returned, copied or rendered, and the call neither installs, clears, replaces nor mutates a fault — a latched engine stays latched and an unlatched one stays unlatched however often this is called. Nil-safe like the other exported status readers: a nil engine reports false, never a fabricated fault.

type TxAdmitError

type TxAdmitError struct {
	Kind    TxAdmitErrorKind
	Message string
	// contains filtered or unexported fields
}

TxAdmitError is a typed mempool admission error carrying a classification kind and a human-readable message.

func (*TxAdmitError) Error

func (e *TxAdmitError) Error() string

func (*TxAdmitError) Unwrap

func (e *TxAdmitError) Unwrap() error

Unwrap: the building branch's sentinel or nil (nil receiver included); errors.As still stops at this pointer.

type TxAdmitErrorKind

type TxAdmitErrorKind string

TxAdmitErrorKind classifies mempool admission failures for deterministic HTTP status mapping. Mirrors Rust TxPoolAdmitErrorKind.

const (
	TxAdmitConflict    TxAdmitErrorKind = "conflict"
	TxAdmitRejected    TxAdmitErrorKind = "rejected"
	TxAdmitUnavailable TxAdmitErrorKind = "unavailable"
)

type TxUndo

type TxUndo struct {
	Spent []SpentUndo
}

type VersionPayloadV1

type VersionPayloadV1 struct {
	ProtocolVersion   uint32
	TxRelay           bool
	PrunedBelowHeight uint64
	DaMempoolSize     uint32
	ChainID           [32]byte
	GenesisHash       [32]byte
	BestHeight        uint64
	UserAgent         string
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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