Files
zeekayandHanzo Dev c22f13f63e cert: the weight clause Go runs last, the set admitted whole, and one workspace
THE TOTAL. `Register` in `validator/registration.go` runs seven clauses, and
this port had six. The seventh is `math.Add64` on the running weight: a set
whose weights sum past what a `uint64` holds is refused entire, before any of
it is admitted. Without it `total_stake` folded with `saturating_add` and
`voted_stake` summed with `saturating_add`, so a set of four validators at
2^63 reported `u64::MAX` staked AND `u64::MAX` voted — and
`u64::MAX > floor(2·u64::MAX/3)`. A certificate carrying HALF the stake
cleared the two-thirds export floor, which is the rung a bridge reads.

Clamping is what makes the two sides agree on a number neither can represent,
so neither clamps any more. The set carries its total as a fact established at
admission with `checked_add` — one source of truth, decided at the one place
that still has a registration to refuse — and `voted_stake` is checked too:
the voters are a subset of the members, so against a set this crate admitted
the overflow is unreachable, and reaching it is evidence about the stake
source rather than about the votes. `weighted_quasar` takes the same
treatment: a vector with no representable total leaves by the same door as a
zero total, since a plain sum WRAPS to a small total and sizes the count gate
below the stake quorum it exists to anticipate.

THE SET. `insert` admits one validator and reports on that one, which is a
property no set can be built out of: a caller that inserts in a loop and logs
what failed is left holding a set missing a member, with `n` short by one and
the total short by that member's stake — the two numbers every threshold is
read against, wrong, with nothing to say so. `ValidatorSet::register` is the
port of Go's whole-set door: sorted by node id so which duplicate a set is
refused on cannot depend on the order a caller built its input, and
all-or-nothing because the set under construction is a local. `insert` stays
for a membership change to a set already live, and now says so.

THE BINDING. `pkg/typescript` path-depends on `pkg/rust` and could not
compile: narrowing the node id from 32 bytes to 20 left two `NodeID::from([u8;
32])` calls with no impl. It is a 20-byte API now, and the 20 bytes come from
20-byte input — `arr[..20]` would reintroduce exactly the collision the
narrowing exists to prevent, so a hex string of the wrong length is refused,
never trimmed. The width is `size_of::<cert::NodeId>()`, taken from the core
rather than restated, so it cannot drift again. `addValidator` also stopped
discarding the core's answer, which reported a validator as added when the
set had refused it.

And the two crates are one workspace, because that is what they already were.
Built separately they can disagree and did — nothing built both, so nothing
noticed. `cargo test` at the root now builds both, which turns this class of
break from a review finding into a compile error. It also surfaced two tests
in the binding that had been failing unnoticed: they voted with unregistered
ids, from before only members were counted.

No signed byte moves. `canonical_vote_message` is untouched, the node id
enters no signed message, and the Go corpus and the frozen `pop` vectors pass
unchanged.

Verified: 97 tests green (92 rust, 5 napi), clippy clean at the workspace
root, the binding's 29 JS tests green against a linux build of it. Red's PoC
— four validators of 2^63, two voting, read at QUASAR — returned `Ok(())`
before and now dies at registration with `WeightOverflow`.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-01 11:53:54 -07:00

163 lines
5.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* tslint:disable */
/* eslint-disable */
/* auto-generated by NAPI-RS */
/** Block status */
export const enum BlockStatus {
Unknown = 0,
Processing = 1,
Rejected = 2,
Accepted = 3
}
/** Vote type */
export const enum VoteType {
/** Preference vote during sampling */
Preference = 0,
/** Commit vote for finalization */
Commit = 1,
/** Cancel/reject vote */
Cancel = 2
}
/** Complete Quasar consensus configuration */
export interface QuasarConfig {
/** Sample/committee size (default: 20) */
k: number
/** Fixed threshold ratio 0.5-0.8 (default: 0.69 = 69%) */
alpha: number
/** Consecutive rounds for finality (default: 20) */
beta: number
/** Round timeout in milliseconds (default: 100) */
roundTimeoutMs: number
/** Enable FPC adaptive thresholds (default: true) */
enableFpc: boolean
/** Minimum FPC threshold (default: 0.5) */
thetaMin: number
/** Maximum FPC threshold (default: 0.8) */
thetaMax: number
/** PRF seed for FPC (32-byte hex, optional) */
fpcSeed?: string
/** Base luminance in lux (default: 100.0) */
baseLuminance: number
/** Maximum luminance (default: 1000.0) */
maxLuminance: number
/** Minimum luminance (default: 10.0) */
minLuminance: number
/** Success multiplier (default: 1.1) */
successMultiplier: number
/** Failure multiplier (default: 0.9) */
failureMultiplier: number
/** Network timeout in milliseconds (default: 5000) */
networkTimeoutMs: number
/** Max message size in bytes (default: 2MB) */
maxMessageSize: number
/** Max outstanding polls (default: 10) */
maxOutstanding: number
/** Security level: 2=Low, 3=Medium, 5=High (default: 3) */
securityLevel: number
/** Enable quantum-resistant signatures (default: true) */
quantumResistant: boolean
/** Enable GPU acceleration (default: true) */
gpuAcceleration: boolean
}
/** Block data for consensus */
export interface Block {
/** Block ID (32-byte hex string) */
id: string
/** Parent block ID (32-byte hex string) */
parentId: string
/** Block height */
height: number
/** Block payload (hex-encoded) */
payload: string
/** Block timestamp (Unix milliseconds) */
timestamp: number
}
/** Vote on a block */
export interface Vote {
/** Block ID being voted on (hex string) */
blockId: string
/** Vote type (0=Preference, 1=Commit, 2=Cancel) */
voteType: number
/** Voter node ID (20-byte hex string) */
voter: string
/** Optional signature (hex string) */
signature?: string
}
/** Generate a random 32-byte block ID */
export declare function generateBlockId(): string
/** Create default Quasar configuration (production) */
export declare function defaultConfig(): QuasarConfig
/** Create testnet configuration (lower thresholds for testing) */
export declare function testnetConfig(): QuasarConfig
/** Create mainnet configuration (production settings) */
export declare function mainnetConfig(): QuasarConfig
/** Get SDK version */
export declare function version(): string
/** Compute FPC threshold for given parameters */
export declare function fpcThreshold(phase: number, k: number, thetaMin: number, thetaMax: number): number
/** Block identifier (32-byte hex string) */
export declare class BlockId {
constructor(hexString: string)
/** Create zero ID (genesis parent) */
static zero(): BlockId
toHex(): string
toBytes(): Array<number>
isZero(): boolean
}
/** Node identifier (20-byte hex string) */
export declare class NodeId {
constructor(hexString: string)
toHex(): string
toBytes(): Array<number>
}
/**
* FPC (Fast Probabilistic Consensus) threshold selector
*
* Computes phase-dependent thresholds using PRF-based selection.
* Formula: α(phase, k) = ⌈θ(phase) · k⌉
*/
export declare class FpcSelector {
/** Create a new FPC selector with given theta range */
constructor(thetaMin: number, thetaMax: number, seedHex?: string | undefined | null)
/** Get the threshold for a given phase and k */
threshold(phase: number, k: number): number
/** Get theta value for a phase (between theta_min and theta_max) */
theta(phase: number): number
}
/**
* Lux Quasar Consensus Engine for TypeScript/Node.js
*
* Thread-safe consensus engine with native performance.
* Implements complete Quasar consensus with:
* - Wave: Threshold voting with FPC support
* - FPC: Fast Probabilistic Consensus
* - Photon: Light-based validator sampling
* - Focus: Confidence accumulation
* - Quasar: Post-quantum finality
*/
export declare class ConsensusEngine {
/** Create a new consensus engine with configuration */
constructor(config: QuasarConfig)
/** Start the consensus engine */
start(): void
/** Stop the consensus engine */
stop(): void
/** Add a block to the consensus */
addBlock(block: Block): void
/** Record a vote on a block */
recordVote(vote: Vote): void
/** Check if a block has been accepted */
isAccepted(blockId: string): boolean
/** Get the status of a block */
getStatus(blockId: string): BlockStatus
/** Process multiple votes in batch (optimized) */
recordVotesBatch(votes: Array<Vote>): number
/** Add a validator to the engine, by its 20-byte node id */
addValidator(nodeId: string, weight: number): void
/** Get the current configuration */
getConfig(): QuasarConfig
/** Get current block height */
getHeight(): number
}