Files
chains/aivm/quorum_errors.go
zeekay eb02967a9a aivm: one staging layer, one commit, one chain
A-Chain kept the tip only in memory, staged every pending block's writes
in one shared versiondb, and accepted a block by committing that layer
before storing the block. So a restart came back at genesis, accepting A
published B's intent, rejecting B discarded A's, and a failed store left
the state durable and the block gone.

Verify and BuildBlock now decide against an overlay over committed state
and throw it away, so a block that is proposed or checked moves nothing.
Accept stages the transition, the block, its height entry and the tip
through one view and commits them once. Custody moves into engine state,
so balances commit with the stake records that depend on them instead of
living beside them in memory.

Verify also gains the lineage, time and size checks it never had: the
parent must be the tip or a block in flight above it, the height must
follow, the timestamp must sit between the parent's and the local clock
plus a skew allowance, and the encoding must be one a peer will accept.
Accept re-checks the tip under the lock that commits, because it moves
between the two calls.

A block is now named under its chain id, which never travels, so the same
bytes name different blocks on different chains. Nested payloads must
account for their blob exactly, id lists must be whole ids, and an
element the encoder cannot write is reported rather than dropped. A
merkle proof's index must be spent by the fold, so an out-of-range index
no longer verifies on its low bits.

Also: the running flag is read under the lock that writes it, a vertex no
longer moves the block chain's head, and eligibleSet says what its quorum
is a quorum of.

The ten probe files that proved all this are converted to regression
tests, not deleted.
2026-08-28 15:03:32 -07:00

64 lines
3.8 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package aivm
import "errors"
// Engine errors. Every one is a hard failure that leaves state unchanged
// (fail-closed): a rejected operation makes NO write. Grouped by phase so the
// surface is auditable in one place.
var (
// registry / stake
ErrEmptyModelSpec = errors.New("aivm/quorum: empty model spec hash")
ErrStakeBelowMin = errors.New("aivm/quorum: stake below MinProviderBond")
ErrOperatorExists = errors.New("aivm/quorum: operator already registered")
ErrOperatorUnknown = errors.New("aivm/quorum: operator not registered")
ErrOperatorUnbonding = errors.New("aivm/quorum: operator is unbonding")
// ErrOperatorBonded is the converse: the operator has not deregistered,
// so no cooldown has started and there is no stake to withdraw.
ErrOperatorBonded = errors.New("aivm/quorum: operator is still bonded")
ErrCooldownActive = errors.New("aivm/quorum: unbond cooldown not elapsed")
// custody / conservation
ErrInsufficientFunds = errors.New("aivm/quorum: insufficient balance")
ErrEscrowUnderflow = errors.New("aivm/quorum: escrow underflow (invariant broken)")
ErrStakeOverflow = errors.New("aivm/quorum: stake overflow")
ErrCreditOverflow = errors.New("aivm/quorum: credit overflow")
ErrRewardOverflow = errors.New("aivm/quorum: reward escrow overflow")
ErrFeeOverflow = errors.New("aivm/quorum: request fee overflow")
ErrNoCredit = errors.New("aivm/quorum: no credit to withdraw")
// task params / selection
ErrEmptyPromptHash = errors.New("aivm/quorum: empty prompt hash")
ErrBadN = errors.New("aivm/quorum: N out of range [minN, maxN]")
ErrBadThreshold = errors.New("aivm/quorum: threshold must satisfy floor(N/2)+1 <= threshold <= N")
ErrNotEnoughEligible = errors.New("aivm/quorum: fewer eligible operators than N")
ErrEligibleBelowMargin = errors.New("aivm/quorum: eligible operator set below N + required margin")
// task lifecycle
ErrTaskUnknown = errors.New("aivm/quorum: task not found")
ErrTaskNotCommitting = errors.New("aivm/quorum: task not in committing state")
ErrTaskAlreadySettled = errors.New("aivm/quorum: task already settled")
ErrNotSelected = errors.New("aivm/quorum: operator not selected for task")
ErrCommitClosed = errors.New("aivm/quorum: commit window closed")
ErrAlreadyCommitted = errors.New("aivm/quorum: operator already committed")
ErrNotCommitted = errors.New("aivm/quorum: operator did not commit")
ErrRevealNotOpen = errors.New("aivm/quorum: reveal window not open")
ErrRevealClosed = errors.New("aivm/quorum: reveal window closed")
ErrAlreadyRevealed = errors.New("aivm/quorum: operator already revealed")
ErrCommitMismatch = errors.New("aivm/quorum: reveal does not match commit")
ErrEmptyCommit = errors.New("aivm/quorum: empty commit hash")
ErrEmptyOutputHash = errors.New("aivm/quorum: empty output hash")
ErrSettleTooEarly = errors.New("aivm/quorum: reveal window not closed")
// cross-chain seam
ErrIntentNilAmount = errors.New("aivm/quorum: C-chain intent has a nil fee or reward amount")
ErrIntentIDMismatch = errors.New("aivm/quorum: recomputed intent_id does not match delivered id (forged/tampered intent)")
ErrIntentNotCommitted = errors.New("aivm/quorum: C-chain intent is not committed (proof rejected)")
ErrIntentAlreadyUsed = errors.New("aivm/quorum: C-chain intent already consumed (replay)")
ErrReceiptNotFound = errors.New("aivm/quorum: no settled receipt for intent")
ErrProofOutOfRange = errors.New("aivm/quorum: receipt index out of range")
ErrReceiptRootMismatch = errors.New("aivm/quorum: block receipt_root does not match re-derived engine state")
)