@xyo-network/chain-sdk 5.4.0 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/modules/services/simple/block/runner/SimpleBlockRunner.d.ts +19 -0
- package/dist/browser/modules/services/simple/block/runner/SimpleBlockRunner.d.ts.map +1 -1
- package/dist/browser/modules/services/simple/block/runner/SimpleBlockRunnerInstrumentation.d.ts +1 -1
- package/dist/browser/modules/services/simple/block/runner/SimpleBlockRunnerInstrumentation.d.ts.map +1 -1
- package/dist/browser/modules/slashing/index/foldSlashIndex.d.ts +24 -8
- package/dist/browser/modules/slashing/index/foldSlashIndex.d.ts.map +1 -1
- package/dist/browser/modules/slashing/verify/verifyInvalidBlock.d.ts.map +1 -1
- package/dist/browser/modules/validation/hydratedBlockState/validators/RequiredBalance.d.ts.map +1 -1
- package/dist/neutral/modules/services/simple/block/runner/SimpleBlockRunner.d.ts +19 -0
- package/dist/neutral/modules/services/simple/block/runner/SimpleBlockRunner.d.ts.map +1 -1
- package/dist/neutral/modules/services/simple/block/runner/SimpleBlockRunnerInstrumentation.d.ts +1 -1
- package/dist/neutral/modules/services/simple/block/runner/SimpleBlockRunnerInstrumentation.d.ts.map +1 -1
- package/dist/neutral/modules/slashing/index/foldSlashIndex.d.ts +24 -8
- package/dist/neutral/modules/slashing/index/foldSlashIndex.d.ts.map +1 -1
- package/dist/neutral/modules/slashing/verify/verifyInvalidBlock.d.ts.map +1 -1
- package/dist/neutral/modules/validation/hydratedBlockState/validators/RequiredBalance.d.ts.map +1 -1
- package/dist/neutral/services.mjs +38 -12
- package/dist/neutral/services.mjs.map +2 -2
- package/dist/neutral/slashing.mjs +52 -20
- package/dist/neutral/slashing.mjs.map +3 -3
- package/dist/neutral/validation.mjs +6 -4
- package/dist/neutral/validation.mjs.map +2 -2
- package/dist/node/modules/services/simple/block/runner/SimpleBlockRunner.d.ts +19 -0
- package/dist/node/modules/services/simple/block/runner/SimpleBlockRunner.d.ts.map +1 -1
- package/dist/node/modules/services/simple/block/runner/SimpleBlockRunnerInstrumentation.d.ts +1 -1
- package/dist/node/modules/services/simple/block/runner/SimpleBlockRunnerInstrumentation.d.ts.map +1 -1
- package/dist/node/modules/slashing/index/foldSlashIndex.d.ts +24 -8
- package/dist/node/modules/slashing/index/foldSlashIndex.d.ts.map +1 -1
- package/dist/node/modules/slashing/verify/verifyInvalidBlock.d.ts.map +1 -1
- package/dist/node/modules/validation/hydratedBlockState/validators/RequiredBalance.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/modules/slashing/detect/candidatePairs.ts", "../../src/modules/slashing/detect/offenseGate.ts", "../../src/modules/slashing/detect/suppression.ts", "../../src/modules/slashing/eligibility/evaluateProducerEligibility.ts", "../../src/modules/slashing/index/foldSlashIndex.ts", "../../src/modules/slashing/model/offenseKey.ts", "../../src/modules/slashing/index/SlashIndexStore.ts", "../../src/modules/slashing/model/VerificationOutcome.ts", "../../src/modules/slashing/verify/preamble.ts", "../../src/modules/slashing/verify/verifyEquivocation.ts", "../../src/modules/slashing/verify/verifyFalseAnchor.ts", "../../src/modules/slashing/verify/verifyFalseAttestation.ts", "../../src/modules/slashing/verify/verifyIneligibleProduction.ts", "../../src/modules/slashing/verify/verifyInvalidBlock.ts", "../../src/modules/slashing/verify/verifyInvalidSlashRequest.ts", "../../src/modules/slashing/verify/verifyRewardOvermint.ts", "../../src/modules/slashing/verify/verifyOffense.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Hash } from '@ariestools/sdk'\nimport type { XyoAddress } from '@xyo-network/sdk'\n\n/** One candidate a watcher saw a producer sign, reduced to what deciding equivocation needs. */\nexport interface CandidateSighting {\n /** Height the candidate claims. */\n block: number\n /** Recomputed signed identity \u2014 never the storage hash, which client meta can move. */\n dataHash: Hash\n /** Parent the candidate builds on. */\n previous: Hash | null\n /** Address that signed it. */\n producer: XyoAddress\n /** The candidate this one declares it replaces, when it declares one. */\n supersedes?: Hash\n}\n\n/** Two candidates from one producer that compete for the same slot. */\nexport interface CandidatePair {\n /** Height they compete at. */\n block: number\n /** The earlier sighting. */\n first: CandidateSighting\n /** Who signed both. */\n producer: XyoAddress\n /** The later sighting. */\n second: CandidateSighting\n}\n\n/** Whether two candidates from one producer compete rather than simply differ. */\nfunction competes(first: CandidateSighting, second: CandidateSighting): boolean {\n if (first.dataHash === second.dataHash) return false\n return first.block === second.block || first.previous === second.previous\n}\n\n/** Whether either candidate declares the other as the one it replaces. */\nfunction linked(first: CandidateSighting, second: CandidateSighting): boolean {\n return first.supersedes === second.dataHash || second.supersedes === first.dataHash\n}\n\n/**\n * Finds candidate pairs that look like equivocation among what a watcher has seen.\n *\n * This is detection, not judgment. It answers which pairs are worth verifying, and a pair reaching\n * this list is not yet an accusation \u2014 the verification procedure decides that, and it re-derives\n * everything from the artifacts rather than trusting anything here.\n *\n * A declared link clears the pair immediately, so an honest producer's re-proposal never enters\n * the pipeline at all. Doing that here rather than later matters: a watcher that queued every\n * re-proposal for verification would spend its budget on producers doing exactly what they should.\n *\n * Sightings are compared by recomputed identity, so a candidate seen twice through different paths\n * collapses to one rather than becoming a pair with itself.\n * @param sightings Candidates the watcher has observed\n * @returns Pairs worth verifying, one per competing combination\n */\nexport function findCandidatePairs(sightings: readonly CandidateSighting[]): CandidatePair[] {\n const byProducer = new Map<XyoAddress, CandidateSighting[]>()\n for (const sighting of sightings) {\n const seen = byProducer.get(sighting.producer) ?? []\n // a candidate observed through two paths is one candidate, not a pair\n if (!seen.some(candidate => candidate.dataHash === sighting.dataHash)) seen.push(sighting)\n byProducer.set(sighting.producer, seen)\n }\n\n const pairs: CandidatePair[] = []\n for (const [producer, candidates] of byProducer) {\n for (const [index, first] of candidates.entries()) {\n for (const second of candidates.slice(index + 1)) {\n if (!competes(first, second) || linked(first, second)) continue\n pairs.push({\n block: Math.max(first.block, second.block), first, producer, second,\n })\n }\n }\n }\n return pairs\n}\n", "import type { ChainParams, OffenseCode } from '@xyo-network/xl1-sdk'\nimport { isOffenseReportableAt, isRuleObservedAt } from '@xyo-network/xl1-sdk'\n\n/**\n * Whether a watcher may treat conduct at a height as a reportable offense.\n *\n * Two gates, and the second one only applies to equivocation. A producer cannot declare that one\n * candidate replaces another until the field that says so is active, so before that activation\n * every honest re-proposal is indistinguishable from equivocation. Reporting the class then would\n * accuse operators of an offense the protocol gave them no way to avoid.\n *\n * That conjunction is fixed here rather than left to configuration. An operator who could switch\n * it off would be arming their node to file accusations the chain cannot sustain.\n * @param params The register version covering the offense height\n * @param offense The offense class being considered\n * @param height The XL1 height the conduct occurred at\n * @returns True when reports naming this class at this height may be recorded\n */\nexport function isOffenseWatchable(params: ChainParams, offense: OffenseCode, height: number): boolean {\n if (!isOffenseReportableAt(params, offense, height)) return false\n return offense === 'equivocation' ? isRuleObservedAt(params, 'supersedes-field', height) : true\n}\n", "import type { OffenseKey } from '../model/offenseKey.ts'\nimport type { SlashHistoryReader } from '../model/SlashHistoryReader.ts'\n\n/** Why a watcher should not file a report it would otherwise have filed. */\nexport type SuppressionReason = 'adjudicated' | 'already-reported'\n\n/**\n * Whether an offense a watcher has detected is already spoken for.\n *\n * Duplicate detection is normal \u2014 every validator watching the same chain sees the same\n * misconduct \u2014 so the interesting question is not whether to detect it but whether to add another\n * report of it.\n *\n * A settled offense is the stronger case. Filing against something already adjudicated is not\n * merely redundant: an adjudicated offense cannot be re-litigated, so the new report is itself\n * invalid and exposes its filer to a counter-slash. A watcher must never walk into that.\n *\n * An existing unsettled report is only redundant. Nothing is lost by staying quiet \u2014 the offense\n * is already on the record and the bounty already claimed by whoever got there first.\n * @param history Finalized slash traffic as this watcher can see it\n * @param key The offense being considered\n * @returns Why to stay quiet, or undefined when the report is worth filing\n */\nexport async function suppressionFor(\n history: SlashHistoryReader,\n key: OffenseKey,\n): Promise<SuppressionReason | undefined> {\n if (await history.adjudicationByKey(key) !== undefined) return 'adjudicated'\n return (await history.requestsByKey(key)).length > 0 ? 'already-reported' : undefined\n}\n", "import type { Promisable } from '@ariestools/sdk'\nimport type { XyoAddress } from '@xyo-network/sdk'\nimport type { ChainParams, StakeSnapshotViewerMethods } from '@xyo-network/xl1-sdk'\nimport { evaluationPoint, producerIneligibility } from '@xyo-network/xl1-sdk'\n\n/**\n * Whether an address has a current declaration to produce, as of a height.\n *\n * `undefined` means the question could not be answered \u2014 no intent reader is wired \u2014 which is\n * different from `false` (the reader looked and found nothing current). Collapsing the two would\n * turn a missing reader into either a free pass or an accusation, depending on the direction.\n */\nexport type HasValidIntent = (address: XyoAddress, height: number) => Promisable<boolean | undefined>\n\n/** What the participation predicate needs about a candidate block. */\nexport interface EligibilityInput {\n /** The producer being evaluated. */\n accused: XyoAddress\n /** EVM anchor carried by the candidate itself. */\n blockAnchor?: number\n /** The candidate's XL1 height, where intent windows are judged. */\n height: number\n /** Whether the address has a current production declaration. */\n intent: HasValidIntent\n /** The register version in force. */\n params: ChainParams\n /** EVM anchor carried by the candidate's parent. */\n parentAnchor?: number\n /** Stake as it stood at an EVM height. */\n snapshot?: StakeSnapshotViewerMethods\n}\n\n/** What evaluating participation concluded, including the numbers it concluded it from. */\nexport interface EligibilityEvaluation {\n /** Seasoned active stake measured at the evaluation point. */\n activeStake?: bigint\n /** The EVM height stake was measured at. */\n eStar?: number\n /** Whether the address may produce, when that could be established. */\n eligible?: boolean\n /** Whether the address has a current declaration. */\n intentValid?: boolean\n /** Why not, when it is not. */\n reason?: string\n /** False when the inputs to the predicate could not be resolved at all. */\n resolvable: boolean\n /** The seasoned portion staked on itself. */\n selfBond?: bigint\n}\n\n/**\n * The one place participation is decided.\n *\n * Admission and after-the-fact verification call this same function, and that is the point. If\n * the finalizer's idea of who may produce and the offense procedure's idea ever diverged, a block\n * could be admitted by the network and simultaneously constitute an offense by its producer \u2014 so\n * there is exactly one implementation and both callers take it.\n *\n * The measurement point comes from the two blocks' own signed anchors rather than any live view,\n * so the answer does not depend on when it is asked. A block admissible when it was produced must\n * still evaluate as admissible a week later.\n *\n * Stake is counted seasoned: a position participates only once it has sat at risk for the\n * register's minimum age, so production rights cannot be flash-acquired the block before the\n * measurement point. The unaged total is measured beside it purely so the report can tell an\n * entrant waiting out seasoning apart from an operator short of capital.\n *\n * The tri-state matters as much as the verdict. `resolvable: false` means the question could not\n * be put \u2014 no snapshot, no anchors, no intent reader \u2014 which admission treats as \"do not gate\"\n * and verification treats as inconclusive. Collapsing it into ineligible would turn a missing\n * reader into an accusation.\n * @param input The candidate, the register, and the readers to consult\n * @returns The verdict with the measurements behind it\n */\nexport async function evaluateProducerEligibility(input: EligibilityInput): Promise<EligibilityEvaluation> {\n const {\n accused, blockAnchor, height, intent, params, parentAnchor, snapshot,\n } = input\n if (blockAnchor === undefined || parentAnchor === undefined) {\n return { resolvable: false }\n }\n if (snapshot === undefined) {\n return { eStar: evaluationPoint(parentAnchor, blockAnchor, params.freshnessBandEvmBlocks), resolvable: false }\n }\n\n const eStar = evaluationPoint(parentAnchor, blockAnchor, params.freshnessBandEvmBlocks)\n const minAge = params.minStakeAgeEvmBlocks\n const [seasonedActive, seasonedSelfBond, active, intentValid] = await Promise.all([\n snapshot.seasonedActiveByStakedAt(accused, eStar, minAge),\n snapshot.seasonedSelfBondAt(accused, eStar, minAge),\n snapshot.activeByStakedAt(accused, eStar),\n intent(accused, height),\n ])\n if (intentValid === undefined) {\n // the stake numbers stood; the intent question could not be put\n return {\n activeStake: seasonedActive, eStar, resolvable: false, selfBond: seasonedSelfBond,\n }\n }\n const standing = {\n active, seasonedActive, seasonedSelfBond,\n }\n const reason = producerIneligibility(\n standing,\n {\n minSelfBond: hexAtto(params.minProducerSelfBondAtto),\n minStake: hexAtto(params.minProducerStakeAtto),\n },\n intentValid,\n )\n return {\n activeStake: seasonedActive,\n eStar,\n eligible: reason === null,\n intentValid,\n reason: reason ?? undefined,\n resolvable: true,\n selfBond: seasonedSelfBond,\n }\n}\n\n/** Register amounts are bare hex; a decimal parse would misread every non-trivial value. */\nfunction hexAtto(value: string): bigint {\n if (value === '') return 0n\n return BigInt(value.startsWith('0x') ? value : `0x${value}`)\n}\n", "import type { Hash, JsonObject } from '@ariestools/sdk'\nimport type { Payload, WithHashMeta } from '@xyo-network/sdk'\nimport type { SignedHydratedBlockWithHashMeta, SlashIndexKeyRecord } from '@xyo-network/xl1-sdk'\nimport {\n isSlashAdjudication, isSlashChallenge, isSlashCommit, isSlashRequest,\n slashIndexAccusedPath, slashIndexAdjudicationPath, slashIndexChallengePath, slashIndexCommitPath,\n slashIndexKeyPath, SlashIndexKeyRecordSchema, slashIndexRequestPath,\n} from '@xyo-network/xl1-sdk'\n\nimport { offenseKeyOf, offenseKeyString } from '../model/offenseKey.ts'\n\n/** One object to write, and whether it may ever be rewritten. */\nexport interface SlashIndexWrite {\n /** True when the object is content-addressed and must never change once written. */\n immutable: boolean\n /** Where it goes. */\n path: string\n /** What goes there. */\n value: JsonObject\n}\n\n/** Everything one batch of finalized blocks contributes to the index. */\nexport interface SlashIndexDelta {\n /** Producer aggregates: path to the offense keys seen for that producer. */\n accused: Map<string, string[]>\n /** Per-offense aggregates, keyed by their path. */\n keys: Map<string, SlashIndexKeyRecord>\n /**\n * Adjudications and challenges whose report was not in this batch.\n *\n * Their offense cannot be resolved from the blocks alone \u2014 the report that names it is further\n * back \u2014 so the writing pass resolves them against the published request records.\n */\n pending: { hash: Hash; kind: 'adjudication' | 'challenge'; request: Hash }[]\n /** Content-addressed records, safe to skip when already present. */\n records: SlashIndexWrite[]\n}\n\nconst emptyDelta = (): SlashIndexDelta => ({\n accused: new Map(), keys: new Map(), pending: [], records: [],\n})\n\nconst recordAt = (path: string, payload: WithHashMeta<Payload>): SlashIndexWrite =>\n ({\n immutable: true, path, value: payload as unknown as JsonObject,\n })\n\n/**\n * Folds finalized blocks into everything the index should gain from them.\n *\n * Pure, and deliberately so: the pass that writes has to be safe to re-run after a crash, and the\n * cheapest way to be sure of that is for the decision of *what* to write to depend on nothing but\n * the blocks. Run it twice over the same range and it produces the same delta.\n *\n * Aggregates are keyed by canonical offense identity, so several validators reporting the same\n * misconduct converge on one record instead of accumulating as separate accusations.\n * @param blocks Finalized blocks to fold, in ascending height order\n * @returns The records and aggregate contributions from those blocks\n */\nexport function foldSlashIndex(blocks: SignedHydratedBlockWithHashMeta[]): SlashIndexDelta {\n const delta = emptyDelta()\n const keyPathByRequest = new Map<Hash, string>()\n for (const [, payloads] of blocks) {\n for (const payload of payloads) foldPayload(delta, keyPathByRequest, payload)\n }\n return delta\n}\n\n/** Ensures an aggregate exists for an offense, and returns its path. */\nfunction keyPathFor(delta: SlashIndexDelta, request: Parameters<typeof offenseKeyOf>[0]): string {\n const key = offenseKeyOf(request)\n const path = slashIndexKeyPath(key.accused, key.offense, key.block)\n if (!delta.keys.has(path)) {\n delta.keys.set(path, {\n accused: key.accused,\n block: key.block,\n challenges: [],\n chain: key.chain,\n offense: key.offense,\n requests: [],\n schema: SlashIndexKeyRecordSchema,\n })\n const accusedPath = slashIndexAccusedPath(key.accused)\n delta.accused.set(accusedPath, [...(delta.accused.get(accusedPath) ?? []), offenseKeyString(key)])\n }\n return path\n}\n\nfunction foldPayload(\n delta: SlashIndexDelta,\n keyPathByRequest: Map<Hash, string>,\n payload: WithHashMeta<Payload>,\n): void {\n if (isSlashRequest(payload)) {\n delta.records.push(recordAt(slashIndexRequestPath(payload._dataHash), payload))\n const path = keyPathFor(delta, payload)\n keyPathByRequest.set(payload._dataHash, path)\n const record = delta.keys.get(path)\n if (record !== undefined && !record.requests.includes(payload._dataHash)) {\n record.requests.push(payload._dataHash)\n }\n return\n }\n if (isSlashCommit(payload)) {\n delta.records.push(recordAt(slashIndexCommitPath(payload._dataHash), payload))\n return\n }\n if (isSlashChallenge(payload)) {\n delta.records.push(recordAt(slashIndexChallengePath(payload._dataHash), payload))\n linkToRequest(delta, keyPathByRequest, payload._dataHash, payload.request, 'challenge')\n return\n }\n if (isSlashAdjudication(payload)) {\n delta.records.push(recordAt(slashIndexAdjudicationPath(payload._dataHash), payload))\n const path = linkToRequest(delta, keyPathByRequest, payload._dataHash, payload.request, 'adjudication')\n const record = path === undefined ? undefined : delta.keys.get(path)\n if (record !== undefined) {\n record.adjudication = payload._dataHash\n record.outcome = payload.outcome\n }\n }\n}\n\n/** Attaches a challenge or adjudication to its offense, deferring when the report is not here. */\nfunction linkToRequest(\n delta: SlashIndexDelta,\n keyPathByRequest: Map<Hash, string>,\n hash: Hash,\n request: Hash,\n kind: 'adjudication' | 'challenge',\n): string | undefined {\n const path = keyPathByRequest.get(request)\n if (path === undefined) {\n delta.pending.push({\n hash, kind, request,\n })\n return undefined\n }\n if (kind === 'challenge') {\n const record = delta.keys.get(path)\n if (record !== undefined && !record.challenges.includes(hash)) record.challenges.push(hash)\n }\n return path\n}\n\n/**\n * Merges an aggregate contribution into whatever is already published.\n *\n * Every field either appends or is set once. That is what lets a crashed pass simply rescan: a\n * second fold over the same blocks adds nothing it did not already add, and a fold over new blocks\n * never erases what an earlier one recorded.\n * @param existing The published aggregate, when there is one\n * @param next The contribution from this pass\n * @returns The aggregate to publish\n */\nexport function mergeKeyRecord(\n existing: SlashIndexKeyRecord | undefined,\n next: SlashIndexKeyRecord,\n): SlashIndexKeyRecord {\n if (existing === undefined) return next\n const union = (left: readonly string[], right: readonly string[]) => [...new Set([...left, ...right])]\n return {\n ...existing,\n ...next,\n // set-once: a verdict already recorded is never replaced by a later pass\n adjudication: existing.adjudication ?? next.adjudication,\n challenges: union(existing.challenges, next.challenges),\n outcome: existing.outcome ?? next.outcome,\n requests: union(existing.requests, next.requests),\n }\n}\n", "import type { XyoAddress } from '@xyo-network/sdk'\nimport type {\n ChainId, OffenseCode, SlashRequest, XL1BlockNumber,\n} from '@xyo-network/xl1-sdk'\n\n/**\n * What makes two reports be about the same offense.\n *\n * Duplicate reports are expected \u2014 several validators watching the same chain will see the same\n * misconduct \u2014 so the system has to recognise them as one thing. Without a canonical key, the same\n * offense could be adjudicated twice and slashed twice.\n */\nexport interface OffenseKey {\n /** Who is accused. */\n accused: XyoAddress\n /** The canonical height the offense is located at. */\n block: XL1BlockNumber\n /** The chain it happened on. */\n chain: ChainId\n /** Which offense class. */\n offense: OffenseCode\n}\n\n/** The key a request is filed under. */\nexport function offenseKeyOf(request: SlashRequest): OffenseKey {\n return {\n accused: request.accused,\n block: request.block,\n chain: request.chain,\n offense: request.offense,\n }\n}\n\n/**\n * A stable string for the key, for use as a map key.\n *\n * Field order is fixed rather than derived from object iteration, so the same offense produces the\n * same string on every node regardless of how the object was built.\n */\nexport function offenseKeyString(key: OffenseKey): string {\n return `${key.chain}|${key.accused}|${key.offense}|${key.block}`\n}\n\n/**\n * Where an offense is located on the chain, which is not always where it was reported.\n *\n * Each class has one canonical height, and it is the height the report's `block` field must carry.\n * Fixing it per class is what stops the same misconduct being filed under several different\n * heights and slashed once for each.\n *\n * - equivocation \u2014 the height the two candidates compete at\n * - invalid-block, reward-overmint, false-anchor, ineligible-production \u2014 the offending block\n * - invalid-slash-request \u2014 the height carrying the request being complained about\n * - false-attestation \u2014 the height carrying the attestation\n */\nexport function canonicalOffenseHeight(request: SlashRequest): XL1BlockNumber {\n return request.block\n}\n", "import type { JsonObject, Promisable } from '@ariestools/sdk'\n\n/** Moniker the slash index's store resolves under. */\nexport const SlashIndexStoreMoniker = 'SlashIndexStore'\n\n/**\n * The object store the slash index is written to.\n *\n * Named apart from any S3 base class on purpose: the pass that decides *what* to write is pure\n * and tested on its own, and this is the whole of what it needs from the world. Keeping the two\n * separate is what makes the crash-safety argument checkable \u2014 the part with the reasoning has no\n * I/O, and the part with I/O has no reasoning.\n */\nexport interface SlashIndexStore {\n /** Whether an object already exists, so immutable writes can be skipped. */\n hasObject(path: string): Promisable<boolean>\n /** Reads a published object, or undefined when it is not there. */\n readObject(path: string): Promisable<unknown>\n /** Writes an object. */\n writeObject(path: string, value: JsonObject, immutable: boolean): Promisable<void>\n}\n\n/** Whether a resolved provider can actually serve as the index store. */\nexport function isSlashIndexStore(value: unknown): value is SlashIndexStore {\n const candidate = value as Partial<SlashIndexStore> | undefined\n return typeof candidate?.readObject === 'function'\n && typeof candidate.hasObject === 'function'\n && typeof candidate.writeObject === 'function'\n}\n", "import type { JsonObject } from '@ariestools/sdk'\n\n/**\n * What verifying a report concluded.\n *\n * Three outcomes rather than two, and the middle one carries the design. `indeterminate` means the\n * check could not be completed from what was available \u2014 a reader was unreachable, history had\n * aged out, an anchor had not matured. Collapsing it into `provably-invalid` would punish an\n * honest reporter for a gap in someone else's data, which is the fastest way to make reporting\n * something nobody sane volunteers for.\n */\nexport const VerificationOutcomes = ['verified', 'indeterminate', 'provably-invalid'] as const\n\n/** The conclusion of a verification procedure. */\nexport type VerificationOutcome = typeof VerificationOutcomes[number]\n\n/**\n * The result of verifying one report.\n *\n * The transcript is not decoration. Every procedure is required to be reproducible by anyone\n * holding the same inputs, so it records what was consulted and what was recomputed \u2014 that record\n * is what an arbiter publishes, and what lets two nodes that disagree find out which of them is\n * reading different data rather than arguing about conclusions.\n */\nexport interface OffenseVerdict {\n /** The conclusion. */\n outcome: VerificationOutcome\n /**\n * Set when the verdict rests on absence rather than evidence.\n *\n * A conclusion drawn from not finding something can be overturned by someone who has it, so the\n * adjudication side has to know the difference before it acts.\n */\n provisional?: boolean\n /** Why the procedure concluded what it did. */\n reason: string\n /** Step-by-step record of inputs consulted and values recomputed. */\n transcript: JsonObject\n}\n\n/** Builds a verdict, keeping the transcript shape uniform across procedures. */\nexport function verdict(\n outcome: VerificationOutcome,\n reason: string,\n transcript: JsonObject = {},\n provisional?: boolean,\n): OffenseVerdict {\n return provisional === undefined\n ? {\n outcome, reason, transcript,\n }\n : {\n outcome, provisional, reason, transcript,\n }\n}\n", "import type { Hash, JsonObject } from '@ariestools/sdk'\nimport type { Payload } from '@xyo-network/sdk'\nimport { isBoundWitness, PayloadBuilder } from '@xyo-network/sdk'\nimport type { SlashRequest } from '@xyo-network/xl1-sdk'\nimport { BoundWitnessSignaturesValidator } from '@xyo-network/xl1-sdk'\n\nimport type { VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerificationContext } from '../model/OffenseVerificationContext.ts'\nimport type { OffenseVerdict } from '../model/VerificationOutcome.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\n\n/** What re-checking a report's cited artifacts concluded. */\nexport type ArtifactCheck\n = | { byHash: Map<Hash, VerifiedArtifact>; ok: true }\n | { missing?: boolean; ok: false; reason: string }\n\n/**\n * Re-derives every cited artifact's identity and checks its signatures.\n *\n * Identity is recomputed, never taken from the report. A reporter naming a hash it did not supply\n * is asserting something no one can check, and accepting that claim is how a fabricated report\n * would pass \u2014 the artifact has to hash to the thing it was cited as.\n *\n * Signature failures are provably invalid rather than indeterminate: nothing about a bad signature\n * depends on what this verifier can see, so every honest verifier reaches the same conclusion. An\n * artifact this verifier simply cannot see is the opposite case \u2014 `missing` marks it, and callers\n * map it to indeterminate, because what a verifier failed to retain says nothing about a reporter.\n * @param artifacts The artifacts supplied with the report, keyed by claimed hash\n * @param referenced The hashes the report cited\n * @returns The artifacts by recomputed hash, or why the citation failed\n */\nexport async function verifyArtifacts(\n artifacts: ReadonlyMap<Hash, JsonObject>,\n referenced: readonly Hash[],\n): Promise<ArtifactCheck> {\n const byHash = new Map<Hash, VerifiedArtifact>()\n for (const claimed of referenced) {\n const candidate = artifacts.get(claimed)\n if (candidate === undefined) {\n return {\n missing: true, ok: false, reason: `cited artifact ${claimed} is not available to this verifier`,\n }\n }\n const payload = candidate as unknown as Payload\n\n const dataHash = await PayloadBuilder.dataHash(payload)\n if (dataHash !== claimed) {\n return { ok: false, reason: `artifact cited as ${claimed} hashes to ${dataHash}` }\n }\n if (isBoundWitness(payload)) {\n const signatureErrors = await BoundWitnessSignaturesValidator(payload)\n if (signatureErrors.length > 0) {\n return { ok: false, reason: `artifact ${dataHash} carries an invalid signature` }\n }\n }\n byHash.set(dataHash, {\n dataHash, payload, storageHash: await PayloadBuilder.hash(payload),\n })\n }\n return { byHash, ok: true }\n}\n\n/**\n * Whether a signed reference points at this artifact.\n *\n * Signed documents reference each other by hash, but which form \u2014 data or meta-inclusive \u2014\n * depends on who wrote the reference. Both are recomputed from the artifact itself, so a match\n * never rests on a hash the supplier merely claimed.\n */\nexport async function referencesArtifact(reference: Hash | null | undefined, artifact: VerifiedArtifact): Promise<boolean> {\n if (reference === null || reference === undefined) return false\n if (reference === artifact.dataHash) return true\n const storageHash = artifact.storageHash ?? await PayloadBuilder.hash(artifact.payload)\n return reference === storageHash\n}\n\n/** How the freshness gate resolved, and the anchors it measured between. */\nexport interface FreshnessResult {\n /** EVM anchor at the offense. */\n eOff?: number\n /** EVM anchor at submission. */\n eSub?: number\n /** Why it concluded what it did. */\n reason: string\n /** Set when the report cannot proceed. */\n verdict?: OffenseVerdict\n}\n\n/**\n * Whether a report was filed while its offense was still fresh.\n *\n * Both ends are measured on the EVM clock rather than the chain's own, because the chain's clock\n * is exactly what a misbehaving producer controls. Anchors are what a reporter cannot forge.\n *\n * An unresolvable anchor is indeterminate, not stale: a verifier that has pruned the history is\n * making a statement about itself, not about the reporter.\n * @param ctx What the verifier may consult\n * @param request The report being checked\n * @returns The measured anchors, and a verdict when the report cannot proceed\n */\nexport async function freshnessGate(\n ctx: OffenseVerificationContext,\n request: SlashRequest,\n): Promise<FreshnessResult> {\n const eOff = await ctx.chain.validatedAnchorAt(request.block)\n if (eOff === undefined) {\n return {\n reason: 'no anchor resolvable at the offense height',\n verdict: verdict('indeterminate', 'no anchor resolvable at the offense height'),\n }\n }\n const submissionHeight = ctx.submission.commitCarryingHeight ?? ctx.submission.requestCarryingHeight\n const eSub = await ctx.chain.validatedAnchorAt(submissionHeight)\n if (eSub === undefined) {\n return {\n eOff,\n reason: 'no anchor resolvable at the submission height',\n verdict: verdict('indeterminate', 'no anchor resolvable at the submission height'),\n }\n }\n const age = eSub - eOff\n if (age > ctx.params.evidenceFreshnessEvmBlocks) {\n const reason = `offense is ${age} EVM blocks old, past the ${ctx.params.evidenceFreshnessEvmBlocks} limit`\n return {\n eOff,\n eSub,\n reason,\n verdict: verdict('provably-invalid', reason, {\n age, eOff, eSub,\n }),\n }\n }\n return {\n eOff, eSub, reason: `offense is ${age} EVM blocks old`,\n }\n}\n", "import type { Hash } from '@ariestools/sdk'\nimport type { BlockBoundWitness } from '@xyo-network/xl1-sdk'\nimport { asBlockBoundWitness } from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\n\n/** A cited artifact that turned out to be a block, paired with the identity it hashes to. */\ninterface CitedBlock {\n block: BlockBoundWitness\n dataHash: Hash\n}\n\nconst asCitedBlock = (artifact: VerifiedArtifact): CitedBlock | undefined => {\n const block = asBlockBoundWitness(artifact.payload)\n return block === undefined ? undefined : { block, dataHash: artifact.dataHash }\n}\n\n/**\n * O1 \u2014 equivocation: signing two competing candidates for the same slot.\n *\n * Producing two blocks is not by itself misconduct. A producer whose candidate goes stale is\n * expected to re-propose, and the honest way to do that is to say which candidate the new one\n * replaces. What this procedure looks for is two candidates that compete without any such\n * statement.\n *\n * It is deliberately self-contained: everything it needs is in the two artifacts, so it never\n * returns indeterminate. Two verifiers holding the same pair always agree, which matters because\n * this is the offense most likely to be reported by someone with a partial view of the chain.\n *\n * The accused's own defense \u2014 producing the missing link later \u2014 is not evaluated here. That\n * arrives during the challenge window and is an adjudication-level `refuted`, not a reason for\n * this procedure to withhold a verdict.\n */\nexport const verifyEquivocation: OffenseProcedure = async (_ctx, request, artifacts) => {\n const cited = [...artifacts.values()]\n // the artifact map is keyed by recomputed hash, so one entry means the reporter cited the same\n // block twice under two names \u2014 no pair, no offense\n if (cited.length !== 2) {\n return verdict('provably-invalid', `equivocation needs two distinct blocks, got ${cited.length}`)\n }\n\n const blocks = cited.map(artifact => asCitedBlock(artifact))\n const [first, second] = blocks\n if (first === undefined || second === undefined) {\n return verdict('provably-invalid', 'cited artifacts are not both blocks')\n }\n\n const transcript = {\n accused: request.accused,\n first: {\n block: first.block.block, dataHash: first.dataHash, previous: first.block.previous, supersedes: first.block.supersedes ?? null,\n },\n second: {\n block: second.block.block, dataHash: second.dataHash, previous: second.block.previous, supersedes: second.block.supersedes ?? null,\n },\n }\n\n if (!blocks.every(cite => cite?.block.addresses.includes(request.accused))) {\n // the accused has to have signed both; a block it never signed says nothing about it\n return verdict('provably-invalid', 'the accused did not sign both blocks', transcript)\n }\n if (first.block.chain !== second.block.chain) {\n return verdict('provably-invalid', 'the blocks are on different chains', transcript)\n }\n if (first.block.chain !== request.chain) {\n return verdict('provably-invalid', 'the blocks are not on the chain the report names', transcript)\n }\n if (first.block.block !== request.block && second.block.block !== request.block) {\n // the report's height is the freshness clock and the dedup key; a pair located elsewhere\n // would let an old offense wear a fresh height\n return verdict('provably-invalid', 'the report does not locate the offense at either cited block', transcript)\n }\n if (first.block.block !== second.block.block && first.block.previous !== second.block.previous) {\n // competing means same slot or same parent; anything else is two ordinary blocks\n return verdict('provably-invalid', 'the blocks neither share a height nor a parent', transcript)\n }\n\n const superseded = new Set([first.block.supersedes, second.block.supersedes])\n if (superseded.has(first.dataHash) || superseded.has(second.dataHash)) {\n // the reporter supplied the producer's own exculpation: this is a declared re-proposal\n return verdict('provably-invalid', 'one block supersedes the other, so this is a re-proposal', transcript)\n }\n\n return verdict('verified', 'two competing candidates with no supersedes link between them', transcript)\n}\n", "import type { Hash, JsonObject } from '@ariestools/sdk'\nimport { isDefined } from '@ariestools/sdk'\nimport { PayloadBuilder } from '@xyo-network/sdk'\nimport type { BlockBoundWitness } from '@xyo-network/xl1-sdk'\nimport { asBlockBoundWitness, isTimePayload } from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { referencesArtifact } from './preamble.ts'\n\n/** A block and the EVM anchor its own signed time payload claims. */\ninterface AnchoredBlock {\n artifact: VerifiedArtifact\n block: BlockBoundWitness\n evm?: number\n evmHash?: Hash\n}\n\n/**\n * Reads a block's claimed anchor from the time payload it actually carried.\n *\n * The anchor has to come from a payload the block committed to, not from anything the reporter\n * supplied alongside it. A reporter that could hand over the anchor could accuse any producer of\n * claiming any height. A block commits to hashes whose form depends on who wrote them, so both\n * forms are recomputed from the payload itself \u2014 never read from a claim about it.\n */\nasync function anchoredBlocks(artifacts: ReadonlyMap<Hash, VerifiedArtifact>): Promise<AnchoredBlock[]> {\n const cited = [...artifacts.values()]\n const times = await Promise.all(cited\n .filter(artifact => isTimePayload(artifact.payload))\n .map(async artifact => ({\n hashes: [artifact.dataHash, artifact.storageHash ?? await PayloadBuilder.hash(artifact.payload)].filter(hash => isDefined(hash)),\n time: artifact.payload,\n })))\n return cited\n .flatMap((artifact) => {\n const block = asBlockBoundWitness(artifact.payload)\n return block === undefined ? [] : [{ artifact, block }]\n })\n .map(({ artifact, block }) => {\n const carried = new Set(block.payload_hashes)\n const time = times.find(candidate => candidate.hashes.some(hash => carried.has(hash)))\n return {\n artifact, block, evm: (time?.time as { ethereum?: number } | undefined)?.ethereum, evmHash: (time?.time as { ethereumHash?: Hash } | undefined)?.ethereumHash,\n }\n })\n}\n\n/** The cited block the accused block's own signed previous-hash names, when it was supplied. */\nasync function parentOf(accused: AnchoredBlock, blocks: AnchoredBlock[]): Promise<AnchoredBlock | undefined> {\n for (const candidate of blocks) {\n if (candidate === accused) continue\n if (await referencesArtifact(accused.block.previous, candidate.artifact)) return candidate\n }\n return undefined\n}\n\n/**\n * O4 \u2014 false anchor: pointing a block at an EVM block that is not where it says it is.\n *\n * Two shapes, and they differ in what they cost to prove. An anchor that moves backwards is\n * settled by the two blocks alone: the chain's anchor is required to be monotonic, so a child\n * claiming an earlier height than its parent contradicts itself, and no external view is needed.\n *\n * The other shape \u2014 an anchor naming a hash the EVM never had at that height \u2014 needs the EVM\n * itself, and it needs to have settled. Judging before the maturity depth has passed would let a\n * reorg convict an honest producer for a block that was canonical when it anchored. Until then the\n * answer is that it is too early to say, which is not the same as saying nothing happened.\n */\nexport const verifyFalseAnchor: OffenseProcedure = async (ctx, request, artifacts) => {\n const blocks = await anchoredBlocks(artifacts)\n const accused = blocks.find(candidate => candidate.block.block === request.block)\n if (accused === undefined) return verdict('provably-invalid', 'the accused block was not among the cited artifacts')\n // the parent is whatever the accused block's own signed previous-hash names \u2014 a block that\n // merely sits at the right height could be any signed orphan, fabricated to manufacture a\n // regression the real lineage never had\n const parent = await parentOf(accused, blocks)\n if (accused.evm === undefined || accused.evmHash === undefined) {\n return verdict('provably-invalid', 'the accused block carries no EVM anchor to be false about')\n }\n if (!accused.block.addresses.includes(request.accused)) {\n // an anchor in a block the accused never signed is not the accused's claim\n return verdict('provably-invalid', 'the accused did not sign the cited block')\n }\n\n const transcript: JsonObject = {\n accused: request.accused,\n block: accused.block.block,\n claimedEvm: accused.evm,\n claimedEvmHash: accused.evmHash,\n parentEvm: parent?.evm ?? null,\n }\n\n if (parent?.evm !== undefined && accused.evm < parent.evm) {\n // self-contained: the pair contradicts itself, whatever the EVM says\n return verdict('verified', `the anchor went backwards, from ${parent.evm} to ${accused.evm}`, transcript)\n }\n\n if (request.evm !== accused.evm) {\n // the report has to name the height it is disputing, or there is nothing specific to check\n return verdict('provably-invalid', 'the report does not name the anchor the block claims', transcript)\n }\n if (ctx.evm === undefined) {\n return verdict('indeterminate', 'no EVM view, so the claimed anchor cannot be checked', transcript)\n }\n const head = await ctx.evm.head()\n if (head === undefined) {\n return verdict('indeterminate', 'the EVM head is not resolvable', transcript)\n }\n if (head - accused.evm < ctx.params.maturityEvmBlocks) {\n // judging now would let a reorg convict a producer whose anchor was canonical when it signed\n return verdict('indeterminate', `the anchor is only ${head - accused.evm} EVM blocks deep and has not matured`, { ...transcript, head })\n }\n const canonical = await ctx.evm.canonicalHashAt(accused.evm)\n if (canonical === undefined) {\n return verdict('indeterminate', 'the canonical hash at that EVM height is not resolvable', transcript)\n }\n return canonical === accused.evmHash\n ? verdict('provably-invalid', 'the block anchored to the canonical hash at that height', { ...transcript, canonical })\n : verdict('verified', 'the block anchored to a hash the EVM never had at that height', { ...transcript, canonical })\n}\n", "import type { JsonObject } from '@ariestools/sdk'\nimport { isBoundWitness } from '@xyo-network/sdk'\nimport type { StepWitness } from '@xyo-network/xl1-sdk'\nimport {\n asBlockBoundWitness, isStepWitness, StepSizes,\n} from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { referencesArtifact } from './preamble.ts'\n\n/** The cited attestation, with the artifact it travels as. */\ninterface CitedAttestation {\n artifact: VerifiedArtifact\n attestation: StepWitness\n}\n\nconst citedAttestation = (cited: VerifiedArtifact[]): CitedAttestation | undefined => {\n const entry = cited.find(artifact => isStepWitness(artifact.payload))\n return entry === undefined\n ? undefined\n : { artifact: entry, attestation: entry.payload as StepWitness }\n}\n\n/**\n * Whether a cited carrier signed by the accused actually carries the attestation.\n *\n * The attestation payload alone binds nobody \u2014 anyone can copy a payload. What makes it the\n * accused's statement is a signed envelope: a bound witness the accused signed whose payload set\n * includes this attestation. The reporter has to cite that envelope, because signatures were\n * already verified in the preamble and this is the only step that connects them to the claim.\n */\nasync function boundToAccused(cited: VerifiedArtifact[], attestation: CitedAttestation, accused: string): Promise<boolean> {\n for (const artifact of cited) {\n const payload = artifact.payload as unknown as { addresses?: string[]; payload_hashes?: string[] }\n if (!isBoundWitness(artifact.payload as never)) continue\n if (!(payload.addresses?.includes(accused) ?? false)) continue\n for (const carried of payload.payload_hashes ?? []) {\n if (await referencesArtifact(carried as never, attestation.artifact)) return true\n }\n }\n return false\n}\n\n/**\n * O7 \u2014 false attestation: signing an attestation for a step that says something else.\n *\n * Two branches, and the second one is weaker than the first on purpose.\n *\n * When the attested block is supplied, the question is closed: the block states its own step\n * hashes, so an attestation naming a different one at the attested level contradicts a signed\n * document and nothing external is needed. Self-contained claims are judged before any retention\n * arithmetic \u2014 a contradiction between two supplied documents does not age out.\n *\n * When no block is supplied, the claim is that the attested block never existed. That is a claim\n * about absence, and absence is exactly what a verifier with an incomplete view would also see.\n * A verdict here is therefore marked provisional: it is enough to open the question, not to close\n * it, and whoever adjudicates has to let the accused produce the block before acting.\n *\n * Past the retention window the absence claim is indeterminate rather than provisional. Once the\n * chain no longer requires anyone to hold the block, absence stops being evidence of anything at\n * all \u2014 treating it as proof would turn the retention policy into a conviction engine.\n */\nexport const verifyFalseAttestation: OffenseProcedure = async (ctx, request, artifacts) => {\n const cited = [...artifacts.values()]\n const found = citedAttestation(cited)\n if (found === undefined) {\n return verdict('provably-invalid', 'no attestation among the cited artifacts')\n }\n const { attestation } = found\n\n const transcript: JsonObject = {\n accused: request.accused,\n attestedBlock: attestation.blockNumber,\n attestedBlockHash: attestation.blockHash,\n attestedStepHash: attestation.stepHash,\n stepSize: attestation.stepSize,\n }\n\n if (attestation.witness !== request.accused || !await boundToAccused(cited, found, request.accused)) {\n // an attestation nobody signed over is a copyable payload, not the accused's statement\n return verdict('provably-invalid', 'the attestation is not bound to the accused by any cited signed carrier', transcript)\n }\n\n const level = (StepSizes as readonly number[]).indexOf(attestation.stepSize)\n if (level === -1) {\n // a step size the chain does not have is the in-block rules' rejection, not this procedure's\n return verdict('provably-invalid', `the attestation names an unknown step size ${attestation.stepSize}`, transcript)\n }\n\n const attested = cited\n .map(artifact => ({ block: asBlockBoundWitness(artifact.payload), dataHash: artifact.dataHash }))\n .find(candidate => candidate.block !== undefined && candidate.dataHash === attestation.blockHash)\n\n if (attested?.block !== undefined) {\n // self-contained: two signed documents either agree at the attested level or they do not\n const carried = attested.block.step_hashes?.[level]\n return carried === attestation.stepHash\n ? verdict('provably-invalid', 'the block carries the step hash the attestation names at that level', transcript)\n : verdict('verified', 'the attested block says something else at that level', {\n ...transcript, blockStepHashes: attested.block.step_hashes ?? [], carried: carried ?? null,\n })\n }\n\n const age = ctx.submission.requestCarryingHeight - attestation.blockNumber\n if (age > ctx.params.evidenceRetentionXl1Blocks) {\n // nobody is required to still hold the block, so its absence proves nothing\n return verdict('indeterminate', `the attested block is ${age} blocks back, past the retention window`, transcript)\n }\n\n const finalized = await ctx.chain.blockAtHeight(attestation.blockNumber)\n if (finalized === undefined) {\n return verdict('indeterminate', 'the attested height is not resolvable on this canonical chain', transcript)\n }\n const finalizedHash = (finalized[0] as unknown as { _dataHash?: string })._dataHash\n return finalizedHash === attestation.blockHash\n ? verdict('provably-invalid', 'the attested block is the one finalized at that height', transcript)\n : verdict(\n 'verified',\n 'no block with the attested hash was finalized at that height',\n { ...transcript, finalizedHash: finalizedHash ?? null },\n true,\n )\n}\n", "import type { Hash, JsonObject } from '@ariestools/sdk'\nimport type { BlockBoundWitness } from '@xyo-network/xl1-sdk'\nimport { asBlockBoundWitness, isTimePayload } from '@xyo-network/xl1-sdk'\n\nimport { evaluateProducerEligibility } from '../eligibility/evaluateProducerEligibility.ts'\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { referencesArtifact } from './preamble.ts'\n\n/**\n * The EVM anchor a block's own signed time payload claims, when it carries one.\n *\n * The carried check recomputes both hash forms from the payload itself rather than reading a\n * claim about it: an artifact that could assert its own storage hash could make an uncarried\n * anchor look carried.\n */\nasync function anchorOf(block: BlockBoundWitness, artifacts: ReadonlyMap<Hash, VerifiedArtifact>): Promise<number | undefined> {\n for (const artifact of artifacts.values()) {\n if (!isTimePayload(artifact.payload)) continue\n for (const carried of block.payload_hashes) {\n if (await referencesArtifact(carried, artifact)) return artifact.payload.ethereum\n }\n }\n return undefined\n}\n\nconst blockAt = (height: number, artifacts: ReadonlyMap<Hash, VerifiedArtifact>): BlockBoundWitness | undefined =>\n [...artifacts.values()]\n .map(artifact => asBlockBoundWitness(artifact.payload))\n .find(block => block?.block === height)\n\n/** The cited block a signed previous-hash names, when it was supplied. */\nasync function blockByReference(\n reference: Hash | null,\n artifacts: ReadonlyMap<Hash, VerifiedArtifact>,\n): Promise<BlockBoundWitness | undefined> {\n if (reference === null) return undefined\n for (const artifact of artifacts.values()) {\n const block = asBlockBoundWitness(artifact.payload)\n if (block === undefined) continue\n if (await referencesArtifact(reference, artifact)) return block\n }\n return undefined\n}\n\n/**\n * O5 \u2014 ineligible production: producing a block without the standing to produce it.\n *\n * The measurement point is recomputed from the two blocks' own signed anchors rather than taken\n * from the report or from a live EVM head. That is what makes admission and after-the-fact\n * verification ask the same question: a block that was admissible when it was produced must not\n * become an offense later because stake moved in the meantime.\n *\n * Both halves of the predicate matter. Stake alone says an address *could* participate; the intent\n * declaration is how it says it *is*. Seasoning is what stops standing being rented for a block.\n *\n * Everything here depends on external state \u2014 stake as it stood at an EVM height \u2014 so an\n * unreadable snapshot is indeterminate. A verifier without that history has no opinion, and\n * pretending otherwise would convict on the basis of not having looked.\n */\nexport const verifyIneligibleProduction: OffenseProcedure = async (ctx, request, artifacts) => {\n const accused = blockAt(request.block, artifacts)\n // the parent is whatever the accused block's own signed previous-hash names; a block that\n // merely sits at the right height could be any signed orphan, chosen to move the measurement\n const parent = accused === undefined ? undefined : await blockByReference(accused.previous, artifacts)\n if (accused === undefined || parent === undefined) {\n return verdict('provably-invalid', 'the accused block and its signed parent were not both cited')\n }\n if (!accused.addresses.includes(request.accused)) {\n return verdict('provably-invalid', 'the accused did not sign the cited block')\n }\n\n const blockAnchor = await anchorOf(accused, artifacts)\n const parentAnchor = await anchorOf(parent, artifacts)\n if (blockAnchor === undefined || parentAnchor === undefined) {\n return verdict('indeterminate', 'the blocks do not both carry an anchor to measure against')\n }\n\n const evaluation = await evaluateProducerEligibility({\n accused: request.accused,\n blockAnchor,\n height: request.block,\n intent: () => accused.addresses.includes(request.accused),\n params: ctx.params,\n parentAnchor,\n snapshot: ctx.snapshot,\n })\n const transcript: JsonObject = {\n accused: request.accused, blockAnchor, eStar: evaluation.eStar ?? null, parentAnchor,\n }\n\n if (request.evm !== evaluation.eStar) {\n // the report has to be measuring the same point the rule measures, or it is judging elsewhere\n return verdict('provably-invalid', `the report measures at ${request.evm}, but the rule measures at ${evaluation.eStar}`, transcript)\n }\n if (!evaluation.resolvable) {\n return verdict('indeterminate', 'no stake snapshot, so standing cannot be measured', transcript)\n }\n\n const measured = {\n ...transcript,\n seasonedActive: evaluation.activeStake?.toString() ?? null,\n seasonedSelfBond: evaluation.selfBond?.toString() ?? null,\n }\n return evaluation.eligible === true\n ? verdict('provably-invalid', 'the accused met every participation requirement at that point', measured)\n : verdict('verified', `the accused was ineligible at that point: ${evaluation.reason}`, { ...measured, reason: evaluation.reason ?? null })\n}\n", "import type { JsonObject } from '@ariestools/sdk'\nimport type { Payload } from '@xyo-network/sdk'\nimport type { BlockBoundWitness } from '@xyo-network/xl1-sdk'\nimport { asBlockBoundWitness, BlockCumulativeBalanceValidatorFactory } from '@xyo-network/xl1-sdk'\n\nimport { validateBlock } from '#validation'\n\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerificationContext } from '../model/OffenseVerificationContext.ts'\nimport type { OffenseVerdict } from '../model/VerificationOutcome.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\n\n/** The cited block, separated from the payloads it carried. */\ninterface CitedHydratedBlock {\n block: BlockBoundWitness\n payloads: Payload[]\n}\n\nfunction citedHydratedBlock(artifacts: ReadonlyMap<string, VerifiedArtifact>): CitedHydratedBlock | undefined {\n const cited = [...artifacts.values()]\n const entry = cited.find(artifact => asBlockBoundWitness(artifact.payload) !== undefined)\n const block = entry === undefined ? undefined : asBlockBoundWitness(entry.payload)\n return block === undefined\n ? undefined\n : { block, payloads: cited.filter(artifact => artifact !== entry).map(artifact => artifact.payload) }\n}\n\n/**\n * Replays the balance rule against canonical history.\n *\n * This calls the same validator the chain runs in production rather than a second implementation\n * of the same idea. Two implementations drift, and the moment they do, a block is an offense\n * according to the verifier and legitimate according to the chain.\n */\nasync function replayStateRules(\n ctx: OffenseVerificationContext,\n cited: CitedHydratedBlock,\n transcript: JsonObject,\n): Promise<OffenseVerdict> {\n if (ctx.balances === undefined) {\n return verdict('indeterminate', 'no balance view, so state rules cannot be replayed', transcript)\n }\n const errors = await BlockCumulativeBalanceValidatorFactory()(\n {\n accountBalance: ctx.balances, chainIdAtBlockNumber: () => cited.block.chain, singletons: {},\n },\n [cited.block, cited.payloads] as never,\n )\n return errors.length > 0\n ? verdict('verified', `the cited block breaks a state rule: ${errors[0]?.message}`, {\n ...transcript, errors: errors.map(error => error.message), rule: 'state',\n })\n : verdict('provably-invalid', 'the cited block satisfies every rule this procedure can replay', transcript)\n}\n\n/**\n * O2 \u2014 invalid block: finalizing a block that breaks the rules in force at its height.\n *\n * Only rules that reproduce identically on every node are replayed. Admission gates are excluded\n * by construction: whether a candidate was admitted depends on what a particular node had in its\n * pool at a particular moment, so re-running one later would convict a producer for someone\n * else's timing.\n *\n * Nothing the reporter supplied is trusted as state. The parent and the balances come from this\n * verifier's own canonical history, because a report that carried its own version of history\n * could prove anything it liked.\n *\n * An unresolvable parent is indeterminate rather than a finding. A verifier that has pruned past\n * the offense knows nothing about the block \u2014 that is a fact about the verifier.\n */\nexport const verifyInvalidBlock: OffenseProcedure = async (ctx, request, artifacts) => {\n const cited = citedHydratedBlock(artifacts)\n if (cited === undefined) return verdict('provably-invalid', 'no block among the cited artifacts')\n\n const transcript: JsonObject = {\n accused: request.accused,\n block: cited.block.block,\n catalogVersion: ctx.catalogVersion,\n payloadCount: cited.payloads.length,\n }\n\n if (cited.block.block !== request.block) {\n // the report's height is the freshness clock and the dedup key; judging a block located\n // elsewhere would let an old offense wear a fresh height\n return verdict('provably-invalid', 'the cited block is not at the height the report names', transcript)\n }\n if (!cited.block.addresses.includes(request.accused)) {\n // a block the accused never signed says nothing about it, whatever rules it breaks\n return verdict('provably-invalid', 'the accused did not sign the cited block', transcript)\n }\n\n const protocolErrors = await validateBlock({ singletons: {} }, cited.block, cited.block.chain)\n if (protocolErrors.length > 0) {\n return verdict('verified', `the cited block breaks a protocol rule: ${protocolErrors[0]?.message}`, {\n ...transcript, errors: protocolErrors.map(error => error.message), rule: 'protocol',\n })\n }\n\n if (cited.block.previous === null) {\n return verdict('provably-invalid', 'the cited block is a genesis block, which has no parent to judge it against', transcript)\n }\n const parent = await ctx.chain.blockByHash(cited.block.previous)\n if (parent === undefined) {\n return verdict('indeterminate', 'the parent is not resolvable on this canonical chain', transcript)\n }\n if (cited.block.block !== parent[0].block + 1) {\n return verdict('verified', 'the cited block does not follow its own parent in height', {\n ...transcript, parentBlock: parent[0].block, rule: 'height',\n })\n }\n\n return await replayStateRules(ctx, cited, transcript)\n}\n", "import type { JsonObject } from '@ariestools/sdk'\nimport type { OffenseCode, SlashRequest } from '@xyo-network/xl1-sdk'\nimport { isSlashRequest } from '@xyo-network/xl1-sdk'\n\nimport { offenseKeyOf } from '../model/offenseKey.ts'\nimport type { OffenseProcedure } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerdict, VerificationOutcome } from '../model/VerificationOutcome.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { freshnessGate, verifyArtifacts } from './preamble.ts'\n\n/** How an inner verdict reads once it is turned around onto the reporter. */\nconst inverted: Record<VerificationOutcome, VerificationOutcome> = {\n 'indeterminate': 'indeterminate',\n 'provably-invalid': 'verified',\n 'verified': 'provably-invalid',\n}\n\n/**\n * Builds the invalid-slash-request procedure over a registry it resolves at call time.\n *\n * The registry is passed as a thunk rather than imported, because this procedure lives inside the\n * same registry it needs. Deferring the lookup keeps that self-reference within one module instead\n * of turning it into an import cycle between two.\n */\nexport function createVerifyInvalidSlashRequest(\n resolve: () => Partial<Record<OffenseCode, OffenseProcedure>>,\n): OffenseProcedure {\n /**\n * O6 \u2014 invalid slash request: accusing someone of something that was never true.\n *\n * The whole procedure is the other six run backwards. A report is bad exactly when the thing it\n * alleged is provably not an offense, so this re-runs the original report and turns the answer\n * around. Writing a separate standard for what makes a report wrong would let the two drift, and\n * a reporter could then be punished for a claim that the offense procedure itself would uphold.\n *\n * The re-run is faithful or it is nothing. It runs on the original report's *own* evidence set \u2014\n * never on whatever the complainant chose to bundle \u2014 and through the same preamble the original\n * was subject to, in *its* context: its catalog version, its submission height. Handing the inner\n * procedure a different artifact set is how an honest reporter gets convicted of a shape error\n * it never made.\n *\n * Inversion is deliberately not total. An inner `indeterminate` stays indeterminate rather than\n * becoming a finding against the reporter: a claim nobody can check is not a false claim, and\n * treating it as one would make honest reporting a gamble on other people's data availability.\n * The same discipline covers the original's evidence itself \u2014 artifacts this verifier cannot see\n * withhold the verdict; only artifacts that are present and provably bad count against anyone.\n */\n return async (ctx, request, artifacts) => {\n const accused = artifacts.values().find(artifact => isSlashRequest(artifact.payload))\n if (accused === undefined) {\n return verdict('provably-invalid', 'no slash request among the cited artifacts')\n }\n const original = accused.payload as SlashRequest\n const key = offenseKeyOf(original)\n\n const finalized = (await ctx.history.requestsByKey(key))\n .find(candidate => candidate.hash === accused.dataHash)\n if (finalized === undefined) {\n // without knowing where it landed there is no way to rebuild the context it was filed in\n return verdict('indeterminate', 'the accused request is not visible in finalized history')\n }\n\n const transcript: JsonObject = {\n accusedRequest: accused.dataHash,\n innerOffense: original.offense,\n originalCarryingHeight: finalized.carryingHeight,\n reporter: request.accused,\n }\n\n const adjudication = await ctx.history.adjudicationByKey(key)\n if (adjudication !== undefined) {\n if (adjudication.carryingHeight >= finalized.carryingHeight) {\n // the verdict landed at or after this report was filed, so its filer could not have known\n return verdict('provably-invalid', 'timing-excused: the offense was not yet adjudicated when the report was filed', { ...transcript, adjudicationHeight: adjudication.carryingHeight })\n }\n // re-litigation is its own offense: the verdict was already public record when this report\n // was filed, and re-running the inner procedure would judge the claim instead of the filing\n return verdict('verified', 're-litigation: the offense was already adjudicated on-chain when the report was filed', { ...transcript, adjudicationHeight: adjudication.carryingHeight })\n }\n\n const procedure = resolve()[original.offense]\n if (procedure === undefined) {\n return verdict('indeterminate', `no verification procedure for the inner offense '${original.offense}'`, transcript)\n }\n\n const innerCtx = {\n ...ctx,\n catalogVersion: original.catalog,\n submission: { requestCarryingHeight: finalized.carryingHeight },\n }\n const innerArtifacts = await verifyArtifacts(ctx.artifacts, original.evidence)\n if (!innerArtifacts.ok) {\n return innerArtifacts.missing === true\n ? verdict('indeterminate', `the original's evidence is not available to re-run: ${innerArtifacts.reason}`, transcript)\n : verdict('verified', `the original's evidence fails the preamble: ${innerArtifacts.reason}`, transcript)\n }\n const innerFreshness = await freshnessGate(innerCtx, original)\n const innerVerdict: OffenseVerdict = innerFreshness.verdict\n ?? await procedure(innerCtx, original, innerArtifacts.byHash)\n\n return verdict(\n inverted[innerVerdict.outcome],\n `the original report verified as '${innerVerdict.outcome}': ${innerVerdict.reason}`,\n {\n ...transcript, inner: innerVerdict.transcript, innerOutcome: innerVerdict.outcome,\n },\n )\n }\n}\n", "import type { JsonObject } from '@ariestools/sdk'\nimport { hexToBigInt } from '@ariestools/sdk'\nimport type { Payload } from '@xyo-network/sdk'\nimport {\n asBlockBoundWitness, isTransferPayload, rewardFromBlockNumber, XYO_ZERO_ADDRESS,\n} from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerificationContext } from '../model/OffenseVerificationContext.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\n\n/**\n * How much a block minted into existence.\n *\n * Only transfers out of the zero address count. Everything else in a block moves value that\n * already existed, and a producer paying itself from its own balance is spending, not minting.\n */\nfunction mintedBy(payloads: Payload[]): bigint {\n return payloads\n .filter(payload => isTransferPayload(payload))\n .filter(transfer => transfer.from === XYO_ZERO_ADDRESS)\n .reduce((total, transfer) =>\n total + Object.values(transfer.transfers).reduce((sum, amount) => sum + hexToBigInt(amount), 0n), 0n)\n}\n\n/** What the register permitted this block to mint, or undefined when it cannot be established. */\nasync function allowedEmission(\n ctx: OffenseVerificationContext,\n blockNumber: number,\n parentAnchor: number | undefined,\n): Promise<bigint | undefined> {\n if (ctx.params.rewardSource === 'schedule') return rewardFromBlockNumber(blockNumber as never)\n if (parentAnchor === undefined || ctx.blockRewardAt === undefined) return undefined\n return await ctx.blockRewardAt(parentAnchor)\n}\n\n/**\n * O3 \u2014 reward overmint: paying yourself more than the rules allowed.\n *\n * The allowance is recomputed from the register rather than read from the block, since a block\n * that could state its own allowance could authorise anything. Where the allowance comes from\n * depends on how the chain is configured \u2014 a fixed schedule, or the staking contract \u2014 and when\n * it comes from the contract it is read at the parent's anchor rather than at a live head, so\n * every verifier asks the contract the same question.\n *\n * Minting is counted only from the zero address. A producer moving its own balance around is\n * spending money that already existed, which is nobody's business but its own.\n *\n * Under-minting is not an offense here. A producer that pays itself less than it could has taken\n * nothing from anyone, and treating generosity as misconduct would be absurd.\n *\n * Only the zero-address mint clause is implemented. The specification's fee-rule and step-transfer\n * clauses wait on the deterministic fee replay and the step-boundary reader; until they land,\n * reports alleging those shapes resolve on the mint clause alone \u2014 never as a conviction the\n * missing clauses would have had to establish.\n */\nexport const verifyRewardOvermint: OffenseProcedure = async (ctx, request, artifacts) => {\n const cited = [...artifacts.values()]\n const entry = cited.find(artifact => asBlockBoundWitness(artifact.payload) !== undefined)\n const block = entry === undefined ? undefined : asBlockBoundWitness(entry.payload)\n if (block === undefined) return verdict('provably-invalid', 'no block among the cited artifacts')\n\n if (block.block !== request.block) {\n // the report's height is the freshness clock and the dedup key; a block located elsewhere\n // would let an old offense wear a fresh height\n return verdict('provably-invalid', 'the cited block is not at the height the report names')\n }\n if (!block.addresses.includes(request.accused)) {\n // a block the accused never signed says nothing about it, whatever it minted\n return verdict('provably-invalid', 'the accused did not sign the cited block')\n }\n\n const payloads = cited.filter(artifact => artifact !== entry).map(artifact => artifact.payload)\n const minted = mintedBy(payloads)\n\n const parentAnchor = block.previous === null\n ? undefined\n : await ctx.chain.validatedAnchorAt((block.block - 1) as never)\n const allowed = await allowedEmission(ctx, block.block, parentAnchor)\n\n const transcript: JsonObject = {\n accused: request.accused,\n allowed: allowed === undefined ? null : allowed.toString(),\n block: block.block,\n minted: minted.toString(),\n parentAnchor: parentAnchor ?? null,\n rewardSource: ctx.params.rewardSource,\n }\n\n if (allowed === undefined) {\n return verdict('indeterminate', 'the allowed emission for this block cannot be established', transcript)\n }\n return minted > allowed\n ? verdict('verified', `the block minted ${minted} against an allowance of ${allowed}`, transcript)\n : verdict('provably-invalid', `the block minted ${minted}, within its allowance of ${allowed}`, transcript)\n}\n", "import type { OffenseCode, SlashRequest } from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerificationContext } from '../model/OffenseVerificationContext.ts'\nimport type { OffenseVerdict } from '../model/VerificationOutcome.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { freshnessGate, verifyArtifacts } from './preamble.ts'\nimport { verifyEquivocation } from './verifyEquivocation.ts'\nimport { verifyFalseAnchor } from './verifyFalseAnchor.ts'\nimport { verifyFalseAttestation } from './verifyFalseAttestation.ts'\nimport { verifyIneligibleProduction } from './verifyIneligibleProduction.ts'\nimport { verifyInvalidBlock } from './verifyInvalidBlock.ts'\nimport { createVerifyInvalidSlashRequest } from './verifyInvalidSlashRequest.ts'\nimport { verifyRewardOvermint } from './verifyRewardOvermint.ts'\n\n/**\n * The procedure for each offense class.\n *\n * Exported as a map so a class can be verified in isolation by conformance tests, and so the\n * invalid-slash-request procedure can recurse back through it to re-run the report it is\n * complaining about.\n */\nexport const offenseProcedures: Partial<Record<OffenseCode, OffenseProcedure>> = {\n 'equivocation': verifyEquivocation,\n 'false-anchor': verifyFalseAnchor,\n 'false-attestation': verifyFalseAttestation,\n 'ineligible-production': verifyIneligibleProduction,\n 'invalid-block': verifyInvalidBlock,\n 'invalid-slash-request': createVerifyInvalidSlashRequest(() => offenseProcedures),\n 'reward-overmint': verifyRewardOvermint,\n}\n\n/**\n * Verifies one report, end to end.\n *\n * The shared preamble runs first for every class: cited artifacts are re-hashed and their\n * signatures checked, then the offense is measured against the freshness window. Both are\n * conditions no class can waive, so running them once here keeps a procedure from quietly\n * skipping one.\n *\n * A class with no registered procedure is indeterminate rather than invalid. The register can\n * activate a class this build does not implement, and refusing to conclude is the honest answer \u2014\n * concluding \"not an offense\" would let the gap read as an acquittal.\n * @param ctx What the verifier may consult\n * @param request The report being verified\n * @returns The verdict, with its transcript\n */\nexport async function verifyOffense(\n ctx: OffenseVerificationContext,\n request: SlashRequest,\n): Promise<OffenseVerdict> {\n const artifacts = await verifyArtifacts(ctx.artifacts, request.evidence)\n if (!artifacts.ok) {\n // an artifact this verifier cannot see is a statement about the verifier, not the reporter\n return verdict(artifacts.missing === true ? 'indeterminate' : 'provably-invalid', artifacts.reason, { stage: 'artifacts' })\n }\n\n const freshness = await freshnessGate(ctx, request)\n if (freshness.verdict !== undefined) return freshness.verdict\n\n const procedure = offenseProcedures[request.offense]\n if (procedure === undefined) {\n return verdict('indeterminate', `no verification procedure for '${request.offense}'`, { catalogVersion: ctx.catalogVersion, offense: request.offense })\n }\n const result = await procedure(ctx, request, artifacts.byHash)\n return {\n ...result,\n transcript: {\n ...result.transcript,\n eOff: freshness.eOff ?? null,\n eSub: freshness.eSub ?? null,\n offense: request.offense,\n },\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["PayloadBuilder", "asBlockBoundWitness", "PayloadBuilder", "asBlockBoundWitness", "isBoundWitness", "asBlockBoundWitness", "isBoundWitness", "asBlockBoundWitness", "asBlockBoundWitness", "isTimePayload", "isTimePayload", "asBlockBoundWitness", "asBlockBoundWitness", "asBlockBoundWitness", "isSlashRequest", "isSlashRequest", "asBlockBoundWitness", "asBlockBoundWitness"]
|
|
4
|
+
"sourcesContent": ["import type { Hash } from '@ariestools/sdk'\nimport type { XyoAddress } from '@xyo-network/sdk'\n\n/** One candidate a watcher saw a producer sign, reduced to what deciding equivocation needs. */\nexport interface CandidateSighting {\n /** Height the candidate claims. */\n block: number\n /** Recomputed signed identity \u2014 never the storage hash, which client meta can move. */\n dataHash: Hash\n /** Parent the candidate builds on. */\n previous: Hash | null\n /** Address that signed it. */\n producer: XyoAddress\n /** The candidate this one declares it replaces, when it declares one. */\n supersedes?: Hash\n}\n\n/** Two candidates from one producer that compete for the same slot. */\nexport interface CandidatePair {\n /** Height they compete at. */\n block: number\n /** The earlier sighting. */\n first: CandidateSighting\n /** Who signed both. */\n producer: XyoAddress\n /** The later sighting. */\n second: CandidateSighting\n}\n\n/** Whether two candidates from one producer compete rather than simply differ. */\nfunction competes(first: CandidateSighting, second: CandidateSighting): boolean {\n if (first.dataHash === second.dataHash) return false\n return first.block === second.block || first.previous === second.previous\n}\n\n/** Whether either candidate declares the other as the one it replaces. */\nfunction linked(first: CandidateSighting, second: CandidateSighting): boolean {\n return first.supersedes === second.dataHash || second.supersedes === first.dataHash\n}\n\n/**\n * Finds candidate pairs that look like equivocation among what a watcher has seen.\n *\n * This is detection, not judgment. It answers which pairs are worth verifying, and a pair reaching\n * this list is not yet an accusation \u2014 the verification procedure decides that, and it re-derives\n * everything from the artifacts rather than trusting anything here.\n *\n * A declared link clears the pair immediately, so an honest producer's re-proposal never enters\n * the pipeline at all. Doing that here rather than later matters: a watcher that queued every\n * re-proposal for verification would spend its budget on producers doing exactly what they should.\n *\n * Sightings are compared by recomputed identity, so a candidate seen twice through different paths\n * collapses to one rather than becoming a pair with itself.\n * @param sightings Candidates the watcher has observed\n * @returns Pairs worth verifying, one per competing combination\n */\nexport function findCandidatePairs(sightings: readonly CandidateSighting[]): CandidatePair[] {\n const byProducer = new Map<XyoAddress, CandidateSighting[]>()\n for (const sighting of sightings) {\n const seen = byProducer.get(sighting.producer) ?? []\n // a candidate observed through two paths is one candidate, not a pair\n if (seen.every(candidate => candidate.dataHash !== sighting.dataHash)) seen.push(sighting)\n byProducer.set(sighting.producer, seen)\n }\n\n const pairs: CandidatePair[] = []\n for (const [producer, candidates] of byProducer) {\n for (const [index, first] of candidates.entries()) {\n for (const second of candidates.slice(index + 1)) {\n if (!competes(first, second) || linked(first, second)) continue\n pairs.push({\n block: Math.max(first.block, second.block), first, producer, second,\n })\n }\n }\n }\n return pairs\n}\n", "import type { ChainParams, OffenseCode } from '@xyo-network/xl1-sdk'\nimport { isOffenseReportableAt, isRuleObservedAt } from '@xyo-network/xl1-sdk'\n\n/**\n * Whether a watcher may treat conduct at a height as a reportable offense.\n *\n * Two gates, and the second one only applies to equivocation. A producer cannot declare that one\n * candidate replaces another until the field that says so is active, so before that activation\n * every honest re-proposal is indistinguishable from equivocation. Reporting the class then would\n * accuse operators of an offense the protocol gave them no way to avoid.\n *\n * That conjunction is fixed here rather than left to configuration. An operator who could switch\n * it off would be arming their node to file accusations the chain cannot sustain.\n * @param params The register version covering the offense height\n * @param offense The offense class being considered\n * @param height The XL1 height the conduct occurred at\n * @returns True when reports naming this class at this height may be recorded\n */\nexport function isOffenseWatchable(params: ChainParams, offense: OffenseCode, height: number): boolean {\n if (!isOffenseReportableAt(params, offense, height)) return false\n return offense === 'equivocation' ? isRuleObservedAt(params, 'supersedes-field', height) : true\n}\n", "import type { OffenseKey } from '../model/offenseKey.ts'\nimport type { SlashHistoryReader } from '../model/SlashHistoryReader.ts'\n\n/** Why a watcher should not file a report it would otherwise have filed. */\nexport type SuppressionReason = 'adjudicated' | 'already-reported'\n\n/**\n * Whether an offense a watcher has detected is already spoken for.\n *\n * Duplicate detection is normal \u2014 every validator watching the same chain sees the same\n * misconduct \u2014 so the interesting question is not whether to detect it but whether to add another\n * report of it.\n *\n * A settled offense is the stronger case. Filing against something already adjudicated is not\n * merely redundant: an adjudicated offense cannot be re-litigated, so the new report is itself\n * invalid and exposes its filer to a counter-slash. A watcher must never walk into that.\n *\n * An existing unsettled report is only redundant. Nothing is lost by staying quiet \u2014 the offense\n * is already on the record and the bounty already claimed by whoever got there first.\n * @param history Finalized slash traffic as this watcher can see it\n * @param key The offense being considered\n * @returns Why to stay quiet, or undefined when the report is worth filing\n */\nexport async function suppressionFor(\n history: SlashHistoryReader,\n key: OffenseKey,\n): Promise<SuppressionReason | undefined> {\n if (await history.adjudicationByKey(key) !== undefined) return 'adjudicated'\n return (await history.requestsByKey(key)).length > 0 ? 'already-reported' : undefined\n}\n", "import type { Promisable } from '@ariestools/sdk'\nimport type { XyoAddress } from '@xyo-network/sdk'\nimport type { ChainParams, StakeSnapshotViewerMethods } from '@xyo-network/xl1-sdk'\nimport { evaluationPoint, producerIneligibility } from '@xyo-network/xl1-sdk'\n\n/**\n * Whether an address has a current declaration to produce, as of a height.\n *\n * `undefined` means the question could not be answered \u2014 no intent reader is wired \u2014 which is\n * different from `false` (the reader looked and found nothing current). Collapsing the two would\n * turn a missing reader into either a free pass or an accusation, depending on the direction.\n */\nexport type HasValidIntent = (address: XyoAddress, height: number) => Promisable<boolean | undefined>\n\n/** What the participation predicate needs about a candidate block. */\nexport interface EligibilityInput {\n /** The producer being evaluated. */\n accused: XyoAddress\n /** EVM anchor carried by the candidate itself. */\n blockAnchor?: number\n /** The candidate's XL1 height, where intent windows are judged. */\n height: number\n /** Whether the address has a current production declaration. */\n intent: HasValidIntent\n /** The register version in force. */\n params: ChainParams\n /** EVM anchor carried by the candidate's parent. */\n parentAnchor?: number\n /** Stake as it stood at an EVM height. */\n snapshot?: StakeSnapshotViewerMethods\n}\n\n/** What evaluating participation concluded, including the numbers it concluded it from. */\nexport interface EligibilityEvaluation {\n /** Seasoned active stake measured at the evaluation point. */\n activeStake?: bigint\n /** The EVM height stake was measured at. */\n eStar?: number\n /** Whether the address may produce, when that could be established. */\n eligible?: boolean\n /** Whether the address has a current declaration. */\n intentValid?: boolean\n /** Why not, when it is not. */\n reason?: string\n /** False when the inputs to the predicate could not be resolved at all. */\n resolvable: boolean\n /** The seasoned portion staked on itself. */\n selfBond?: bigint\n}\n\n/**\n * The one place participation is decided.\n *\n * Admission and after-the-fact verification call this same function, and that is the point. If\n * the finalizer's idea of who may produce and the offense procedure's idea ever diverged, a block\n * could be admitted by the network and simultaneously constitute an offense by its producer \u2014 so\n * there is exactly one implementation and both callers take it.\n *\n * The measurement point comes from the two blocks' own signed anchors rather than any live view,\n * so the answer does not depend on when it is asked. A block admissible when it was produced must\n * still evaluate as admissible a week later.\n *\n * Stake is counted seasoned: a position participates only once it has sat at risk for the\n * register's minimum age, so production rights cannot be flash-acquired the block before the\n * measurement point. The unaged total is measured beside it purely so the report can tell an\n * entrant waiting out seasoning apart from an operator short of capital.\n *\n * The tri-state matters as much as the verdict. `resolvable: false` means the question could not\n * be put \u2014 no snapshot, no anchors, no intent reader \u2014 which admission treats as \"do not gate\"\n * and verification treats as inconclusive. Collapsing it into ineligible would turn a missing\n * reader into an accusation.\n * @param input The candidate, the register, and the readers to consult\n * @returns The verdict with the measurements behind it\n */\nexport async function evaluateProducerEligibility(input: EligibilityInput): Promise<EligibilityEvaluation> {\n const {\n accused, blockAnchor, height, intent, params, parentAnchor, snapshot,\n } = input\n if (blockAnchor === undefined || parentAnchor === undefined) {\n return { resolvable: false }\n }\n if (snapshot === undefined) {\n return { eStar: evaluationPoint(parentAnchor, blockAnchor, params.freshnessBandEvmBlocks), resolvable: false }\n }\n\n const eStar = evaluationPoint(parentAnchor, blockAnchor, params.freshnessBandEvmBlocks)\n const minAge = params.minStakeAgeEvmBlocks\n const [seasonedActive, seasonedSelfBond, active, intentValid] = await Promise.all([\n snapshot.seasonedActiveByStakedAt(accused, eStar, minAge),\n snapshot.seasonedSelfBondAt(accused, eStar, minAge),\n snapshot.activeByStakedAt(accused, eStar),\n intent(accused, height),\n ])\n if (intentValid === undefined) {\n // the stake numbers stood; the intent question could not be put\n return {\n activeStake: seasonedActive, eStar, resolvable: false, selfBond: seasonedSelfBond,\n }\n }\n const standing = {\n active, seasonedActive, seasonedSelfBond,\n }\n const reason = producerIneligibility(\n standing,\n {\n minSelfBond: hexAtto(params.minProducerSelfBondAtto),\n minStake: hexAtto(params.minProducerStakeAtto),\n },\n intentValid,\n )\n return {\n activeStake: seasonedActive,\n eStar,\n eligible: reason === null,\n intentValid,\n reason: reason ?? undefined,\n resolvable: true,\n selfBond: seasonedSelfBond,\n }\n}\n\n/** Register amounts are bare hex; a decimal parse would misread every non-trivial value. */\nfunction hexAtto(value: string): bigint {\n if (value === '') return 0n\n return BigInt(value.startsWith('0x') ? value : `0x${value}`)\n}\n", "import type { Hash, JsonObject } from '@ariestools/sdk'\nimport type { Payload, WithHashMeta } from '@xyo-network/sdk'\nimport type {\n SignedHydratedBlockWithHashMeta, SlashIndexKeyRecord, SlashOutcome,\n} from '@xyo-network/xl1-sdk'\nimport {\n isSlashAdjudication, isSlashChallenge, isSlashCommit, isSlashRequest,\n slashIndexAccusedPath, slashIndexAdjudicationPath, slashIndexChallengePath, slashIndexCommitPath,\n slashIndexKeyPath, SlashIndexKeyRecordSchema, slashIndexRequestPath,\n} from '@xyo-network/xl1-sdk'\n\nimport { offenseKeyOf, offenseKeyString } from '../model/offenseKey.ts'\n\n/** One object to write, and whether it may ever be rewritten. */\nexport interface SlashIndexWrite {\n /** True when the object is content-addressed and must never change once written. */\n immutable: boolean\n /** Where it goes. */\n path: string\n /** What goes there. */\n value: JsonObject\n}\n\n/**\n * A challenge or adjudication, and the report it answers.\n *\n * An adjudication carries its outcome. When the report is in an earlier batch, the writing pass\n * files the verdict and its outcome together, and no later pass reads that verdict again, so an\n * outcome left behind here could never be recovered.\n */\nexport type SlashIndexPendingLink\n = | { hash: Hash; kind: 'adjudication'; outcome: SlashOutcome; request: Hash }\n | { hash: Hash; kind: 'challenge'; request: Hash }\n\n/** Everything one batch of finalized blocks contributes to the index. */\nexport interface SlashIndexDelta {\n /** Producer aggregates: path to the offense keys seen for that producer. */\n accused: Map<string, string[]>\n /** Per-offense aggregates, keyed by their path. */\n keys: Map<string, SlashIndexKeyRecord>\n /**\n * What the writing pass has to attach, in the order it was finalized: adjudications and\n * challenges whose report was not in this batch, and every adjudication after the first such\n * adjudication.\n *\n * Their offense cannot be resolved from the blocks alone \u2014 the report that names it is further\n * back \u2014 so the writing pass resolves them against the published request records. Later\n * adjudications wait behind the first so that every verdict is settled in finalized order.\n */\n pending: SlashIndexPendingLink[]\n /** Content-addressed records, safe to skip when already present. */\n records: SlashIndexWrite[]\n}\n\nconst emptyDelta = (): SlashIndexDelta => ({\n accused: new Map(), keys: new Map(), pending: [], records: [],\n})\n\nconst recordAt = (path: string, payload: WithHashMeta<Payload>): SlashIndexWrite =>\n ({\n immutable: true, path, value: payload as unknown as JsonObject,\n })\n\n/**\n * Folds finalized blocks into everything the index should gain from them.\n *\n * Pure, and deliberately so: the pass that writes has to be safe to re-run after a crash, and the\n * cheapest way to be sure of that is for the decision of *what* to write to depend on nothing but\n * the blocks. Run it twice over the same range and it produces the same delta.\n *\n * Aggregates are keyed by canonical offense identity, so several validators reporting the same\n * misconduct converge on one record instead of accumulating as separate accusations.\n * @param blocks Finalized blocks to fold, in ascending height order\n * @returns The records and aggregate contributions from those blocks\n */\nexport function foldSlashIndex(blocks: SignedHydratedBlockWithHashMeta[]): SlashIndexDelta {\n const delta = emptyDelta()\n const keyPathByRequest = new Map<Hash, string>()\n for (const [, payloads] of blocks) {\n for (const payload of payloads) foldPayload(delta, keyPathByRequest, payload)\n }\n return delta\n}\n\n/** Ensures an aggregate exists for an offense, and returns its path. */\nfunction keyPathFor(delta: SlashIndexDelta, request: Parameters<typeof offenseKeyOf>[0]): string {\n const key = offenseKeyOf(request)\n const path = slashIndexKeyPath(key.accused, key.offense, key.block)\n if (!delta.keys.has(path)) {\n delta.keys.set(path, {\n accused: key.accused,\n block: key.block,\n challenges: [],\n chain: key.chain,\n offense: key.offense,\n requests: [],\n schema: SlashIndexKeyRecordSchema,\n })\n const accusedPath = slashIndexAccusedPath(key.accused)\n delta.accused.set(accusedPath, [...(delta.accused.get(accusedPath) ?? []), offenseKeyString(key)])\n }\n return path\n}\n\nfunction foldPayload(\n delta: SlashIndexDelta,\n keyPathByRequest: Map<Hash, string>,\n payload: WithHashMeta<Payload>,\n): void {\n if (isSlashRequest(payload)) {\n delta.records.push(recordAt(slashIndexRequestPath(payload._dataHash), payload))\n const path = keyPathFor(delta, payload)\n keyPathByRequest.set(payload._dataHash, path)\n const record = delta.keys.get(path)\n if (record !== undefined && !record.requests.includes(payload._dataHash)) {\n record.requests.push(payload._dataHash)\n }\n return\n }\n if (isSlashCommit(payload)) {\n delta.records.push(recordAt(slashIndexCommitPath(payload._dataHash), payload))\n return\n }\n if (isSlashChallenge(payload)) {\n delta.records.push(recordAt(slashIndexChallengePath(payload._dataHash), payload))\n linkToRequest(delta, keyPathByRequest, {\n hash: payload._dataHash, kind: 'challenge', request: payload.request,\n })\n return\n }\n if (isSlashAdjudication(payload)) {\n delta.records.push(recordAt(slashIndexAdjudicationPath(payload._dataHash), payload))\n const path = linkToRequest(delta, keyPathByRequest, {\n hash: payload._dataHash, kind: 'adjudication', outcome: payload.outcome, request: payload.request,\n })\n const record = path === undefined ? undefined : delta.keys.get(path)\n // set once, and as a pair: an offense is closed by the first verdict finalized on any of its\n // reports, and an outcome is only ever recorded with the verdict that reached it\n if (record !== undefined && record.adjudication === undefined) {\n record.adjudication = payload._dataHash\n record.outcome = payload.outcome\n }\n }\n}\n\n/**\n * Attaches a challenge or adjudication to its offense, deferring when the report is not here.\n *\n * Once one verdict is deferred, every later one is deferred behind it, even when its report is\n * here. The writing pass settles deferred verdicts after this batch's aggregates, in the order\n * they were finalized; filed here instead, a verdict on a duplicate report would be recorded ahead\n * of an earlier verdict on the same offense that is still waiting.\n */\nfunction linkToRequest(\n delta: SlashIndexDelta,\n keyPathByRequest: Map<Hash, string>,\n link: SlashIndexPendingLink,\n): string | undefined {\n const path = keyPathByRequest.get(link.request)\n const isVerdictWaiting = delta.pending.some(waiting => waiting.kind === 'adjudication')\n if (path === undefined || (link.kind === 'adjudication' && isVerdictWaiting)) {\n delta.pending.push(link)\n return undefined\n }\n if (link.kind === 'challenge') {\n const record = delta.keys.get(path)\n if (record !== undefined && !record.challenges.includes(link.hash)) record.challenges.push(link.hash)\n }\n return path\n}\n\n/**\n * Merges an aggregate contribution into whatever is already published.\n *\n * Every field either appends or is set once. That is what lets a crashed pass simply rescan: a\n * second fold over the same blocks adds nothing it did not already add, and a fold over new blocks\n * never erases what an earlier one recorded.\n * @param existing The published aggregate, when there is one\n * @param next The contribution from this pass\n * @returns The aggregate to publish\n */\nexport function mergeKeyRecord(\n existing: SlashIndexKeyRecord | undefined,\n next: SlashIndexKeyRecord,\n): SlashIndexKeyRecord {\n if (existing === undefined) return next\n const union = (left: readonly string[], right: readonly string[]) => [...new Set([...left, ...right])]\n // set once, and as a pair: a published verdict was finalized ahead of anything `next` was folded\n // from, and an outcome is only ever published with the verdict that reached it\n const verdict = existing.adjudication === undefined ? next : existing\n return {\n ...existing,\n ...next,\n adjudication: verdict.adjudication,\n challenges: union(existing.challenges, next.challenges),\n outcome: verdict.outcome,\n requests: union(existing.requests, next.requests),\n }\n}\n", "import type { XyoAddress } from '@xyo-network/sdk'\nimport type {\n ChainId, OffenseCode, SlashRequest, XL1BlockNumber,\n} from '@xyo-network/xl1-sdk'\n\n/**\n * What makes two reports be about the same offense.\n *\n * Duplicate reports are expected \u2014 several validators watching the same chain will see the same\n * misconduct \u2014 so the system has to recognise them as one thing. Without a canonical key, the same\n * offense could be adjudicated twice and slashed twice.\n */\nexport interface OffenseKey {\n /** Who is accused. */\n accused: XyoAddress\n /** The canonical height the offense is located at. */\n block: XL1BlockNumber\n /** The chain it happened on. */\n chain: ChainId\n /** Which offense class. */\n offense: OffenseCode\n}\n\n/** The key a request is filed under. */\nexport function offenseKeyOf(request: SlashRequest): OffenseKey {\n return {\n accused: request.accused,\n block: request.block,\n chain: request.chain,\n offense: request.offense,\n }\n}\n\n/**\n * A stable string for the key, for use as a map key.\n *\n * Field order is fixed rather than derived from object iteration, so the same offense produces the\n * same string on every node regardless of how the object was built.\n */\nexport function offenseKeyString(key: OffenseKey): string {\n return `${key.chain}|${key.accused}|${key.offense}|${key.block}`\n}\n\n/**\n * Where an offense is located on the chain, which is not always where it was reported.\n *\n * Each class has one canonical height, and it is the height the report's `block` field must carry.\n * Fixing it per class is what stops the same misconduct being filed under several different\n * heights and slashed once for each.\n *\n * - equivocation \u2014 the height the two candidates compete at\n * - invalid-block, reward-overmint, false-anchor, ineligible-production \u2014 the offending block\n * - invalid-slash-request \u2014 the height carrying the request being complained about\n * - false-attestation \u2014 the height carrying the attestation\n */\nexport function canonicalOffenseHeight(request: SlashRequest): XL1BlockNumber {\n return request.block\n}\n", "import type { JsonObject, Promisable } from '@ariestools/sdk'\n\n/** Moniker the slash index's store resolves under. */\nexport const SlashIndexStoreMoniker = 'SlashIndexStore'\n\n/**\n * The object store the slash index is written to.\n *\n * Named apart from any S3 base class on purpose: the pass that decides *what* to write is pure\n * and tested on its own, and this is the whole of what it needs from the world. Keeping the two\n * separate is what makes the crash-safety argument checkable \u2014 the part with the reasoning has no\n * I/O, and the part with I/O has no reasoning.\n */\nexport interface SlashIndexStore {\n /** Whether an object already exists, so immutable writes can be skipped. */\n hasObject(path: string): Promisable<boolean>\n /** Reads a published object, or undefined when it is not there. */\n readObject(path: string): Promisable<unknown>\n /** Writes an object. */\n writeObject(path: string, value: JsonObject, immutable: boolean): Promisable<void>\n}\n\n/** Whether a resolved provider can actually serve as the index store. */\nexport function isSlashIndexStore(value: unknown): value is SlashIndexStore {\n const candidate = value as Partial<SlashIndexStore> | undefined\n return typeof candidate?.readObject === 'function'\n && typeof candidate.hasObject === 'function'\n && typeof candidate.writeObject === 'function'\n}\n", "import type { JsonObject } from '@ariestools/sdk'\n\n/**\n * What verifying a report concluded.\n *\n * Three outcomes rather than two, and the middle one carries the design. `indeterminate` means the\n * check could not be completed from what was available \u2014 a reader was unreachable, history had\n * aged out, an anchor had not matured. Collapsing it into `provably-invalid` would punish an\n * honest reporter for a gap in someone else's data, which is the fastest way to make reporting\n * something nobody sane volunteers for.\n */\nexport const VerificationOutcomes = ['verified', 'indeterminate', 'provably-invalid'] as const\n\n/** The conclusion of a verification procedure. */\nexport type VerificationOutcome = typeof VerificationOutcomes[number]\n\n/**\n * The result of verifying one report.\n *\n * The transcript is not decoration. Every procedure is required to be reproducible by anyone\n * holding the same inputs, so it records what was consulted and what was recomputed \u2014 that record\n * is what an arbiter publishes, and what lets two nodes that disagree find out which of them is\n * reading different data rather than arguing about conclusions.\n */\nexport interface OffenseVerdict {\n /** The conclusion. */\n outcome: VerificationOutcome\n /**\n * Set when the verdict rests on absence rather than evidence.\n *\n * A conclusion drawn from not finding something can be overturned by someone who has it, so the\n * adjudication side has to know the difference before it acts.\n */\n provisional?: boolean\n /** Why the procedure concluded what it did. */\n reason: string\n /** Step-by-step record of inputs consulted and values recomputed. */\n transcript: JsonObject\n}\n\n/** Builds a verdict, keeping the transcript shape uniform across procedures. */\nexport function verdict(\n outcome: VerificationOutcome,\n reason: string,\n transcript: JsonObject = {},\n provisional?: boolean,\n): OffenseVerdict {\n return provisional === undefined\n ? {\n outcome, reason, transcript,\n }\n : {\n outcome, provisional, reason, transcript,\n }\n}\n", "import type { Hash, JsonObject } from '@ariestools/sdk'\nimport type { Payload } from '@xyo-network/sdk'\nimport { isBoundWitness, PayloadBuilder } from '@xyo-network/sdk'\nimport type { SlashRequest } from '@xyo-network/xl1-sdk'\nimport { BoundWitnessSignaturesValidator } from '@xyo-network/xl1-sdk'\n\nimport type { VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerificationContext } from '../model/OffenseVerificationContext.ts'\nimport type { OffenseVerdict } from '../model/VerificationOutcome.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\n\n/** What re-checking a report's cited artifacts concluded. */\nexport type ArtifactCheck\n = | { byHash: Map<Hash, VerifiedArtifact>; ok: true }\n | { missing?: boolean; ok: false; reason: string }\n\n/**\n * Re-derives every cited artifact's identity and checks its signatures.\n *\n * Identity is recomputed, never taken from the report. A reporter naming a hash it did not supply\n * is asserting something no one can check, and accepting that claim is how a fabricated report\n * would pass \u2014 the artifact has to hash to the thing it was cited as.\n *\n * Signature failures are provably invalid rather than indeterminate: nothing about a bad signature\n * depends on what this verifier can see, so every honest verifier reaches the same conclusion. An\n * artifact this verifier simply cannot see is the opposite case \u2014 `missing` marks it, and callers\n * map it to indeterminate, because what a verifier failed to retain says nothing about a reporter.\n * @param artifacts The artifacts supplied with the report, keyed by claimed hash\n * @param referenced The hashes the report cited\n * @returns The artifacts by recomputed hash, or why the citation failed\n */\nexport async function verifyArtifacts(\n artifacts: ReadonlyMap<Hash, JsonObject>,\n referenced: readonly Hash[],\n): Promise<ArtifactCheck> {\n const byHash = new Map<Hash, VerifiedArtifact>()\n for (const claimed of referenced) {\n const candidate = artifacts.get(claimed)\n if (candidate === undefined) {\n return {\n missing: true, ok: false, reason: `cited artifact ${claimed} is not available to this verifier`,\n }\n }\n const payload = candidate as unknown as Payload\n\n const dataHash = await PayloadBuilder.dataHash(payload)\n if (dataHash !== claimed) {\n return { ok: false, reason: `artifact cited as ${claimed} hashes to ${dataHash}` }\n }\n if (isBoundWitness(payload)) {\n const signatureErrors = await BoundWitnessSignaturesValidator(payload)\n if (signatureErrors.length > 0) {\n return { ok: false, reason: `artifact ${dataHash} carries an invalid signature` }\n }\n }\n byHash.set(dataHash, {\n dataHash, payload, storageHash: await PayloadBuilder.hash(payload),\n })\n }\n return { byHash, ok: true }\n}\n\n/**\n * Whether a signed reference points at this artifact.\n *\n * Signed documents reference each other by hash, but which form \u2014 data or meta-inclusive \u2014\n * depends on who wrote the reference. Both are recomputed from the artifact itself, so a match\n * never rests on a hash the supplier merely claimed.\n */\nexport async function referencesArtifact(reference: Hash | null | undefined, artifact: VerifiedArtifact): Promise<boolean> {\n if (reference === null || reference === undefined) return false\n if (reference === artifact.dataHash) return true\n const storageHash = artifact.storageHash ?? await PayloadBuilder.hash(artifact.payload)\n return reference === storageHash\n}\n\n/** How the freshness gate resolved, and the anchors it measured between. */\nexport interface FreshnessResult {\n /** EVM anchor at the offense. */\n eOff?: number\n /** EVM anchor at submission. */\n eSub?: number\n /** Why it concluded what it did. */\n reason: string\n /** Set when the report cannot proceed. */\n verdict?: OffenseVerdict\n}\n\n/**\n * Whether a report was filed while its offense was still fresh.\n *\n * Both ends are measured on the EVM clock rather than the chain's own, because the chain's clock\n * is exactly what a misbehaving producer controls. Anchors are what a reporter cannot forge.\n *\n * An unresolvable anchor is indeterminate, not stale: a verifier that has pruned the history is\n * making a statement about itself, not about the reporter.\n * @param ctx What the verifier may consult\n * @param request The report being checked\n * @returns The measured anchors, and a verdict when the report cannot proceed\n */\nexport async function freshnessGate(\n ctx: OffenseVerificationContext,\n request: SlashRequest,\n): Promise<FreshnessResult> {\n const eOff = await ctx.chain.validatedAnchorAt(request.block)\n if (eOff === undefined) {\n return {\n reason: 'no anchor resolvable at the offense height',\n verdict: verdict('indeterminate', 'no anchor resolvable at the offense height'),\n }\n }\n const submissionHeight = ctx.submission.commitCarryingHeight ?? ctx.submission.requestCarryingHeight\n const eSub = await ctx.chain.validatedAnchorAt(submissionHeight)\n if (eSub === undefined) {\n return {\n eOff,\n reason: 'no anchor resolvable at the submission height',\n verdict: verdict('indeterminate', 'no anchor resolvable at the submission height'),\n }\n }\n const age = eSub - eOff\n if (age > ctx.params.evidenceFreshnessEvmBlocks) {\n const reason = `offense is ${age} EVM blocks old, past the ${ctx.params.evidenceFreshnessEvmBlocks} limit`\n return {\n eOff,\n eSub,\n reason,\n verdict: verdict('provably-invalid', reason, {\n age, eOff, eSub,\n }),\n }\n }\n return {\n eOff, eSub, reason: `offense is ${age} EVM blocks old`,\n }\n}\n", "import type { Hash } from '@ariestools/sdk'\nimport type { BlockBoundWitness } from '@xyo-network/xl1-sdk'\nimport { asBlockBoundWitness } from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\n\n/** A cited artifact that turned out to be a block, paired with the identity it hashes to. */\ninterface CitedBlock {\n block: BlockBoundWitness\n dataHash: Hash\n}\n\nconst asCitedBlock = (artifact: VerifiedArtifact): CitedBlock | undefined => {\n const block = asBlockBoundWitness(artifact.payload)\n return block === undefined ? undefined : { block, dataHash: artifact.dataHash }\n}\n\n/**\n * O1 \u2014 equivocation: signing two competing candidates for the same slot.\n *\n * Producing two blocks is not by itself misconduct. A producer whose candidate goes stale is\n * expected to re-propose, and the honest way to do that is to say which candidate the new one\n * replaces. What this procedure looks for is two candidates that compete without any such\n * statement.\n *\n * It is deliberately self-contained: everything it needs is in the two artifacts, so it never\n * returns indeterminate. Two verifiers holding the same pair always agree, which matters because\n * this is the offense most likely to be reported by someone with a partial view of the chain.\n *\n * The accused's own defense \u2014 producing the missing link later \u2014 is not evaluated here. That\n * arrives during the challenge window and is an adjudication-level `refuted`, not a reason for\n * this procedure to withhold a verdict.\n */\nexport const verifyEquivocation: OffenseProcedure = async (_ctx, request, artifacts) => {\n const cited = [...artifacts.values()]\n // the artifact map is keyed by recomputed hash, so one entry means the reporter cited the same\n // block twice under two names \u2014 no pair, no offense\n if (cited.length !== 2) {\n return verdict('provably-invalid', `equivocation needs two distinct blocks, got ${cited.length}`)\n }\n\n const blocks = cited.map(artifact => asCitedBlock(artifact))\n const [first, second] = blocks\n if (first === undefined || second === undefined) {\n return verdict('provably-invalid', 'cited artifacts are not both blocks')\n }\n\n const transcript = {\n accused: request.accused,\n first: {\n block: first.block.block, dataHash: first.dataHash, previous: first.block.previous, supersedes: first.block.supersedes ?? null,\n },\n second: {\n block: second.block.block, dataHash: second.dataHash, previous: second.block.previous, supersedes: second.block.supersedes ?? null,\n },\n }\n\n if (blocks.some(cite => !cite?.block.addresses.includes(request.accused))) {\n // the accused has to have signed both; a block it never signed says nothing about it\n return verdict('provably-invalid', 'the accused did not sign both blocks', transcript)\n }\n if (first.block.chain !== second.block.chain) {\n return verdict('provably-invalid', 'the blocks are on different chains', transcript)\n }\n if (first.block.chain !== request.chain) {\n return verdict('provably-invalid', 'the blocks are not on the chain the report names', transcript)\n }\n if (first.block.block !== request.block && second.block.block !== request.block) {\n // the report's height is the freshness clock and the dedup key; a pair located elsewhere\n // would let an old offense wear a fresh height\n return verdict('provably-invalid', 'the report does not locate the offense at either cited block', transcript)\n }\n if (first.block.block !== second.block.block && first.block.previous !== second.block.previous) {\n // competing means same slot or same parent; anything else is two ordinary blocks\n return verdict('provably-invalid', 'the blocks neither share a height nor a parent', transcript)\n }\n\n const superseded = new Set([first.block.supersedes, second.block.supersedes])\n if (superseded.has(first.dataHash) || superseded.has(second.dataHash)) {\n // the reporter supplied the producer's own exculpation: this is a declared re-proposal\n return verdict('provably-invalid', 'one block supersedes the other, so this is a re-proposal', transcript)\n }\n\n return verdict('verified', 'two competing candidates with no supersedes link between them', transcript)\n}\n", "import type { Hash, JsonObject } from '@ariestools/sdk'\nimport { isDefined } from '@ariestools/sdk'\nimport { PayloadBuilder } from '@xyo-network/sdk'\nimport type { BlockBoundWitness } from '@xyo-network/xl1-sdk'\nimport { asBlockBoundWitness, isTimePayload } from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { referencesArtifact } from './preamble.ts'\n\n/** A block and the EVM anchor its own signed time payload claims. */\ninterface AnchoredBlock {\n artifact: VerifiedArtifact\n block: BlockBoundWitness\n evm?: number\n evmHash?: Hash\n}\n\n/**\n * Reads a block's claimed anchor from the time payload it actually carried.\n *\n * The anchor has to come from a payload the block committed to, not from anything the reporter\n * supplied alongside it. A reporter that could hand over the anchor could accuse any producer of\n * claiming any height. A block commits to hashes whose form depends on who wrote them, so both\n * forms are recomputed from the payload itself \u2014 never read from a claim about it.\n */\nasync function anchoredBlocks(artifacts: ReadonlyMap<Hash, VerifiedArtifact>): Promise<AnchoredBlock[]> {\n const cited = [...artifacts.values()]\n const times = await Promise.all(cited\n .filter(artifact => isTimePayload(artifact.payload))\n .map(async artifact => ({\n hashes: [artifact.dataHash, artifact.storageHash ?? await PayloadBuilder.hash(artifact.payload)].filter(hash => isDefined(hash)),\n time: artifact.payload,\n })))\n return cited\n .flatMap((artifact) => {\n const block = asBlockBoundWitness(artifact.payload)\n return block === undefined ? [] : [{ artifact, block }]\n })\n .map(({ artifact, block }) => {\n const carried = new Set(block.payload_hashes)\n const time = times.find(candidate => candidate.hashes.some(hash => carried.has(hash)))\n return {\n artifact, block, evm: (time?.time as { ethereum?: number } | undefined)?.ethereum, evmHash: (time?.time as { ethereumHash?: Hash } | undefined)?.ethereumHash,\n }\n })\n}\n\n/** The cited block the accused block's own signed previous-hash names, when it was supplied. */\nasync function parentOf(accused: AnchoredBlock, blocks: AnchoredBlock[]): Promise<AnchoredBlock | undefined> {\n for (const candidate of blocks) {\n if (candidate === accused) continue\n if (await referencesArtifact(accused.block.previous, candidate.artifact)) return candidate\n }\n return undefined\n}\n\n/**\n * O4 \u2014 false anchor: pointing a block at an EVM block that is not where it says it is.\n *\n * Two shapes, and they differ in what they cost to prove. An anchor that moves backwards is\n * settled by the two blocks alone: the chain's anchor is required to be monotonic, so a child\n * claiming an earlier height than its parent contradicts itself, and no external view is needed.\n *\n * The other shape \u2014 an anchor naming a hash the EVM never had at that height \u2014 needs the EVM\n * itself, and it needs to have settled. Judging before the maturity depth has passed would let a\n * reorg convict an honest producer for a block that was canonical when it anchored. Until then the\n * answer is that it is too early to say, which is not the same as saying nothing happened.\n */\nexport const verifyFalseAnchor: OffenseProcedure = async (ctx, request, artifacts) => {\n const blocks = await anchoredBlocks(artifacts)\n const accused = blocks.find(candidate => candidate.block.block === request.block)\n if (accused === undefined) return verdict('provably-invalid', 'the accused block was not among the cited artifacts')\n // the parent is whatever the accused block's own signed previous-hash names \u2014 a block that\n // merely sits at the right height could be any signed orphan, fabricated to manufacture a\n // regression the real lineage never had\n const parent = await parentOf(accused, blocks)\n if (accused.evm === undefined || accused.evmHash === undefined) {\n return verdict('provably-invalid', 'the accused block carries no EVM anchor to be false about')\n }\n if (!accused.block.addresses.includes(request.accused)) {\n // an anchor in a block the accused never signed is not the accused's claim\n return verdict('provably-invalid', 'the accused did not sign the cited block')\n }\n\n const transcript: JsonObject = {\n accused: request.accused,\n block: accused.block.block,\n claimedEvm: accused.evm,\n claimedEvmHash: accused.evmHash,\n parentEvm: parent?.evm ?? null,\n }\n\n if (parent?.evm !== undefined && accused.evm < parent.evm) {\n // self-contained: the pair contradicts itself, whatever the EVM says\n return verdict('verified', `the anchor went backwards, from ${parent.evm} to ${accused.evm}`, transcript)\n }\n\n if (request.evm !== accused.evm) {\n // the report has to name the height it is disputing, or there is nothing specific to check\n return verdict('provably-invalid', 'the report does not name the anchor the block claims', transcript)\n }\n if (ctx.evm === undefined) {\n return verdict('indeterminate', 'no EVM view, so the claimed anchor cannot be checked', transcript)\n }\n const head = await ctx.evm.head()\n if (head === undefined) {\n return verdict('indeterminate', 'the EVM head is not resolvable', transcript)\n }\n if (head - accused.evm < ctx.params.maturityEvmBlocks) {\n // judging now would let a reorg convict a producer whose anchor was canonical when it signed\n return verdict('indeterminate', `the anchor is only ${head - accused.evm} EVM blocks deep and has not matured`, { ...transcript, head })\n }\n const canonical = await ctx.evm.canonicalHashAt(accused.evm)\n if (canonical === undefined) {\n return verdict('indeterminate', 'the canonical hash at that EVM height is not resolvable', transcript)\n }\n return canonical === accused.evmHash\n ? verdict('provably-invalid', 'the block anchored to the canonical hash at that height', { ...transcript, canonical })\n : verdict('verified', 'the block anchored to a hash the EVM never had at that height', { ...transcript, canonical })\n}\n", "import type { JsonObject } from '@ariestools/sdk'\nimport { isBoundWitness } from '@xyo-network/sdk'\nimport type { StepWitness } from '@xyo-network/xl1-sdk'\nimport {\n asBlockBoundWitness, isStepWitness, StepSizes,\n} from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { referencesArtifact } from './preamble.ts'\n\n/** The cited attestation, with the artifact it travels as. */\ninterface CitedAttestation {\n artifact: VerifiedArtifact\n attestation: StepWitness\n}\n\nconst citedAttestation = (cited: VerifiedArtifact[]): CitedAttestation | undefined => {\n const entry = cited.find(artifact => isStepWitness(artifact.payload))\n return entry === undefined\n ? undefined\n : { artifact: entry, attestation: entry.payload as StepWitness }\n}\n\n/**\n * Whether a cited carrier signed by the accused actually carries the attestation.\n *\n * The attestation payload alone binds nobody \u2014 anyone can copy a payload. What makes it the\n * accused's statement is a signed envelope: a bound witness the accused signed whose payload set\n * includes this attestation. The reporter has to cite that envelope, because signatures were\n * already verified in the preamble and this is the only step that connects them to the claim.\n */\nasync function boundToAccused(cited: VerifiedArtifact[], attestation: CitedAttestation, accused: string): Promise<boolean> {\n for (const artifact of cited) {\n const payload = artifact.payload as unknown as { addresses?: string[]; payload_hashes?: string[] }\n if (!isBoundWitness(artifact.payload as never)) continue\n if (!(payload.addresses?.includes(accused) ?? false)) continue\n for (const carried of payload.payload_hashes ?? []) {\n if (await referencesArtifact(carried as never, attestation.artifact)) return true\n }\n }\n return false\n}\n\n/**\n * O7 \u2014 false attestation: signing an attestation for a step that says something else.\n *\n * Two branches, and the second one is weaker than the first on purpose.\n *\n * When the attested block is supplied, the question is closed: the block states its own step\n * hashes, so an attestation naming a different one at the attested level contradicts a signed\n * document and nothing external is needed. Self-contained claims are judged before any retention\n * arithmetic \u2014 a contradiction between two supplied documents does not age out.\n *\n * When no block is supplied, the claim is that the attested block never existed. That is a claim\n * about absence, and absence is exactly what a verifier with an incomplete view would also see.\n * A verdict here is therefore marked provisional: it is enough to open the question, not to close\n * it, and whoever adjudicates has to let the accused produce the block before acting.\n *\n * Past the retention window the absence claim is indeterminate rather than provisional. Once the\n * chain no longer requires anyone to hold the block, absence stops being evidence of anything at\n * all \u2014 treating it as proof would turn the retention policy into a conviction engine.\n */\nexport const verifyFalseAttestation: OffenseProcedure = async (ctx, request, artifacts) => {\n const cited = [...artifacts.values()]\n const found = citedAttestation(cited)\n if (found === undefined) {\n return verdict('provably-invalid', 'no attestation among the cited artifacts')\n }\n const { attestation } = found\n\n const transcript: JsonObject = {\n accused: request.accused,\n attestedBlock: attestation.blockNumber,\n attestedBlockHash: attestation.blockHash,\n attestedStepHash: attestation.stepHash,\n stepSize: attestation.stepSize,\n }\n\n if (attestation.witness !== request.accused || !await boundToAccused(cited, found, request.accused)) {\n // an attestation nobody signed over is a copyable payload, not the accused's statement\n return verdict('provably-invalid', 'the attestation is not bound to the accused by any cited signed carrier', transcript)\n }\n\n const level = (StepSizes as readonly number[]).indexOf(attestation.stepSize)\n if (level === -1) {\n // a step size the chain does not have is the in-block rules' rejection, not this procedure's\n return verdict('provably-invalid', `the attestation names an unknown step size ${attestation.stepSize}`, transcript)\n }\n\n const attested = cited\n .map(artifact => ({ block: asBlockBoundWitness(artifact.payload), dataHash: artifact.dataHash }))\n .find(candidate => candidate.block !== undefined && candidate.dataHash === attestation.blockHash)\n\n if (attested?.block !== undefined) {\n // self-contained: two signed documents either agree at the attested level or they do not\n const carried = attested.block.step_hashes?.[level]\n return carried === attestation.stepHash\n ? verdict('provably-invalid', 'the block carries the step hash the attestation names at that level', transcript)\n : verdict('verified', 'the attested block says something else at that level', {\n ...transcript, blockStepHashes: attested.block.step_hashes ?? [], carried: carried ?? null,\n })\n }\n\n const age = ctx.submission.requestCarryingHeight - attestation.blockNumber\n if (age > ctx.params.evidenceRetentionXl1Blocks) {\n // nobody is required to still hold the block, so its absence proves nothing\n return verdict('indeterminate', `the attested block is ${age} blocks back, past the retention window`, transcript)\n }\n\n const finalized = await ctx.chain.blockAtHeight(attestation.blockNumber)\n if (finalized === undefined) {\n return verdict('indeterminate', 'the attested height is not resolvable on this canonical chain', transcript)\n }\n const finalizedHash = (finalized[0] as unknown as { _dataHash?: string })._dataHash\n return finalizedHash === attestation.blockHash\n ? verdict('provably-invalid', 'the attested block is the one finalized at that height', transcript)\n : verdict(\n 'verified',\n 'no block with the attested hash was finalized at that height',\n { ...transcript, finalizedHash: finalizedHash ?? null },\n true,\n )\n}\n", "import type { Hash, JsonObject } from '@ariestools/sdk'\nimport type { BlockBoundWitness } from '@xyo-network/xl1-sdk'\nimport { asBlockBoundWitness, isTimePayload } from '@xyo-network/xl1-sdk'\n\nimport { evaluateProducerEligibility } from '../eligibility/evaluateProducerEligibility.ts'\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { referencesArtifact } from './preamble.ts'\n\n/**\n * The EVM anchor a block's own signed time payload claims, when it carries one.\n *\n * The carried check recomputes both hash forms from the payload itself rather than reading a\n * claim about it: an artifact that could assert its own storage hash could make an uncarried\n * anchor look carried.\n */\nasync function anchorOf(block: BlockBoundWitness, artifacts: ReadonlyMap<Hash, VerifiedArtifact>): Promise<number | undefined> {\n for (const artifact of artifacts.values()) {\n if (!isTimePayload(artifact.payload)) continue\n for (const carried of block.payload_hashes) {\n if (await referencesArtifact(carried, artifact)) return artifact.payload.ethereum\n }\n }\n return undefined\n}\n\nconst blockAt = (height: number, artifacts: ReadonlyMap<Hash, VerifiedArtifact>): BlockBoundWitness | undefined =>\n [...artifacts.values()]\n .map(artifact => asBlockBoundWitness(artifact.payload))\n .find(block => block?.block === height)\n\n/** The cited block a signed previous-hash names, when it was supplied. */\nasync function blockByReference(\n reference: Hash | null,\n artifacts: ReadonlyMap<Hash, VerifiedArtifact>,\n): Promise<BlockBoundWitness | undefined> {\n if (reference === null) return undefined\n for (const artifact of artifacts.values()) {\n const block = asBlockBoundWitness(artifact.payload)\n if (block === undefined) continue\n if (await referencesArtifact(reference, artifact)) return block\n }\n return undefined\n}\n\n/**\n * O5 \u2014 ineligible production: producing a block without the standing to produce it.\n *\n * The measurement point is recomputed from the two blocks' own signed anchors rather than taken\n * from the report or from a live EVM head. That is what makes admission and after-the-fact\n * verification ask the same question: a block that was admissible when it was produced must not\n * become an offense later because stake moved in the meantime.\n *\n * Both halves of the predicate matter. Stake alone says an address *could* participate; the intent\n * declaration is how it says it *is*. Seasoning is what stops standing being rented for a block.\n *\n * Everything here depends on external state \u2014 stake as it stood at an EVM height \u2014 so an\n * unreadable snapshot is indeterminate. A verifier without that history has no opinion, and\n * pretending otherwise would convict on the basis of not having looked.\n */\nexport const verifyIneligibleProduction: OffenseProcedure = async (ctx, request, artifacts) => {\n const accused = blockAt(request.block, artifacts)\n // the parent is whatever the accused block's own signed previous-hash names; a block that\n // merely sits at the right height could be any signed orphan, chosen to move the measurement\n const parent = accused === undefined ? undefined : await blockByReference(accused.previous, artifacts)\n if (accused === undefined || parent === undefined) {\n return verdict('provably-invalid', 'the accused block and its signed parent were not both cited')\n }\n if (!accused.addresses.includes(request.accused)) {\n return verdict('provably-invalid', 'the accused did not sign the cited block')\n }\n\n const blockAnchor = await anchorOf(accused, artifacts)\n const parentAnchor = await anchorOf(parent, artifacts)\n if (blockAnchor === undefined || parentAnchor === undefined) {\n return verdict('indeterminate', 'the blocks do not both carry an anchor to measure against')\n }\n\n const evaluation = await evaluateProducerEligibility({\n accused: request.accused,\n blockAnchor,\n height: request.block,\n intent: () => accused.addresses.includes(request.accused),\n params: ctx.params,\n parentAnchor,\n snapshot: ctx.snapshot,\n })\n const transcript: JsonObject = {\n accused: request.accused, blockAnchor, eStar: evaluation.eStar ?? null, parentAnchor,\n }\n\n if (request.evm !== evaluation.eStar) {\n // the report has to be measuring the same point the rule measures, or it is judging elsewhere\n return verdict('provably-invalid', `the report measures at ${request.evm}, but the rule measures at ${evaluation.eStar}`, transcript)\n }\n if (!evaluation.resolvable) {\n return verdict('indeterminate', 'no stake snapshot, so standing cannot be measured', transcript)\n }\n\n const measured = {\n ...transcript,\n seasonedActive: evaluation.activeStake?.toString() ?? null,\n seasonedSelfBond: evaluation.selfBond?.toString() ?? null,\n }\n return evaluation.eligible === true\n ? verdict('provably-invalid', 'the accused met every participation requirement at that point', measured)\n : verdict('verified', `the accused was ineligible at that point: ${evaluation.reason}`, { ...measured, reason: evaluation.reason ?? null })\n}\n", "import type { JsonObject } from '@ariestools/sdk'\nimport type { Payload } from '@xyo-network/sdk'\nimport type { BlockBoundWitness } from '@xyo-network/xl1-sdk'\nimport {\n asBlockBoundWitness, BlockCumulativeBalanceValidatorFactory, BlockTransactionUniquenessValidatorFactory,\n} from '@xyo-network/xl1-sdk'\n\nimport { validateBlock } from '#validation'\n\nimport type { OffenseProcedure, VerifiedArtifact } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerificationContext } from '../model/OffenseVerificationContext.ts'\nimport type { OffenseVerdict } from '../model/VerificationOutcome.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\n\n/** The cited block, separated from the payloads it carried. */\ninterface CitedHydratedBlock {\n block: BlockBoundWitness\n payloads: Payload[]\n}\n\nfunction citedHydratedBlock(artifacts: ReadonlyMap<string, VerifiedArtifact>): CitedHydratedBlock | undefined {\n const cited = [...artifacts.values()]\n const entry = cited.find(artifact => asBlockBoundWitness(artifact.payload) !== undefined)\n const block = entry === undefined ? undefined : asBlockBoundWitness(entry.payload)\n if (block === undefined) return undefined\n // Only payloads the block itself references are admitted. The reporter chooses what to attach,\n // so an unreferenced payload is its claim, not the block's content -- and a rule replayed over\n // it would convict a producer for something it never finalized.\n const referenced = new Set<string>(block.payload_hashes.map(String))\n return {\n block,\n payloads: cited\n .filter(artifact => artifact !== entry)\n .map(artifact => artifact.payload)\n .filter((payload) => {\n const { _hash, _dataHash } = payload as Partial<Record<'_dataHash' | '_hash', string>>\n return (_hash !== undefined && referenced.has(_hash)) || (_dataHash !== undefined && referenced.has(_dataHash))\n }),\n }\n}\n\nconst transactionUniquenessValidator = BlockTransactionUniquenessValidatorFactory()\n\n/**\n * Replays the replay rule against the cited block alone.\n *\n * A transaction's `_hash` covers its `$signatures` while its `_dataHash` does not, so one signed\n * authorization can reach a block under more than one id. Finalizing a block that carries the\n * same authorization twice, or a malleated (high-S) signature, is an offense.\n *\n * Kept apart from the balance replay because it needs no balance view and no parent: both faults\n * are intrinsic to the block, reproduce identically on every node, and are therefore judgeable by\n * a verifier that cannot resolve either. Returns `undefined` when the block is clean, so the\n * caller continues to the rules that do need history.\n */\nasync function replayReplayRule(\n cited: CitedHydratedBlock,\n transcript: JsonObject,\n): Promise<OffenseVerdict | undefined> {\n const errors = await transactionUniquenessValidator(\n { chainIdAtBlockNumber: () => cited.block.chain, singletons: {} } as never,\n [cited.block, cited.payloads] as never,\n )\n return errors.length > 0\n ? verdict('verified', `the cited block breaks a replay rule: ${errors[0]?.message}`, {\n ...transcript, errors: errors.map(error => error.message), rule: 'replay',\n })\n : undefined\n}\n\n/**\n * Replays the balance rule against canonical history.\n *\n * This calls the same validator the chain runs in production rather than a second implementation\n * of the same idea. Two implementations drift, and the moment they do, a block is an offense\n * according to the verifier and legitimate according to the chain.\n */\nasync function replayStateRules(\n ctx: OffenseVerificationContext,\n cited: CitedHydratedBlock,\n transcript: JsonObject,\n): Promise<OffenseVerdict> {\n if (ctx.balances === undefined) {\n return verdict('indeterminate', 'no balance view, so state rules cannot be replayed', transcript)\n }\n const errors = await BlockCumulativeBalanceValidatorFactory()(\n {\n accountBalance: ctx.balances, chainIdAtBlockNumber: () => cited.block.chain, singletons: {},\n },\n [cited.block, cited.payloads] as never,\n )\n return errors.length > 0\n ? verdict('verified', `the cited block breaks a state rule: ${errors[0]?.message}`, {\n ...transcript, errors: errors.map(error => error.message), rule: 'state',\n })\n : verdict('provably-invalid', 'the cited block satisfies every rule this procedure can replay', transcript)\n}\n\n/**\n * O2 \u2014 invalid block: finalizing a block that breaks the rules in force at its height.\n *\n * Only rules that reproduce identically on every node are replayed. Admission gates are excluded\n * by construction: whether a candidate was admitted depends on what a particular node had in its\n * pool at a particular moment, so re-running one later would convict a producer for someone\n * else's timing.\n *\n * Nothing the reporter supplied is trusted as state. The parent and the balances come from this\n * verifier's own canonical history, because a report that carried its own version of history\n * could prove anything it liked.\n *\n * An unresolvable parent is indeterminate rather than a finding. A verifier that has pruned past\n * the offense knows nothing about the block \u2014 that is a fact about the verifier.\n */\nexport const verifyInvalidBlock: OffenseProcedure = async (ctx, request, artifacts) => {\n const cited = citedHydratedBlock(artifacts)\n if (cited === undefined) return verdict('provably-invalid', 'no block among the cited artifacts')\n\n const transcript: JsonObject = {\n accused: request.accused,\n block: cited.block.block,\n catalogVersion: ctx.catalogVersion,\n payloadCount: cited.payloads.length,\n }\n\n if (cited.block.block !== request.block) {\n // the report's height is the freshness clock and the dedup key; judging a block located\n // elsewhere would let an old offense wear a fresh height\n return verdict('provably-invalid', 'the cited block is not at the height the report names', transcript)\n }\n if (!cited.block.addresses.includes(request.accused)) {\n // a block the accused never signed says nothing about it, whatever rules it breaks\n return verdict('provably-invalid', 'the accused did not sign the cited block', transcript)\n }\n\n const protocolErrors = await validateBlock({ singletons: {} }, cited.block, cited.block.chain)\n if (protocolErrors.length > 0) {\n return verdict('verified', `the cited block breaks a protocol rule: ${protocolErrors[0]?.message}`, {\n ...transcript, errors: protocolErrors.map(error => error.message), rule: 'protocol',\n })\n }\n\n // judged before the parent is resolved: a duplicated authorization or a malleated signature is\n // visible in the block itself, so a verifier that has pruned the parent can still convict\n const replayVerdict = await replayReplayRule(cited, transcript)\n if (replayVerdict !== undefined) return replayVerdict\n\n if (cited.block.previous === null) {\n return verdict('provably-invalid', 'the cited block is a genesis block, which has no parent to judge it against', transcript)\n }\n const parent = await ctx.chain.blockByHash(cited.block.previous)\n if (parent === undefined) {\n return verdict('indeterminate', 'the parent is not resolvable on this canonical chain', transcript)\n }\n if (cited.block.block !== parent[0].block + 1) {\n return verdict('verified', 'the cited block does not follow its own parent in height', {\n ...transcript, parentBlock: parent[0].block, rule: 'height',\n })\n }\n\n return await replayStateRules(ctx, cited, transcript)\n}\n", "import type { JsonObject } from '@ariestools/sdk'\nimport type { OffenseCode, SlashRequest } from '@xyo-network/xl1-sdk'\nimport { isSlashRequest } from '@xyo-network/xl1-sdk'\n\nimport { offenseKeyOf } from '../model/offenseKey.ts'\nimport type { OffenseProcedure } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerdict, VerificationOutcome } from '../model/VerificationOutcome.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { freshnessGate, verifyArtifacts } from './preamble.ts'\n\n/** How an inner verdict reads once it is turned around onto the reporter. */\nconst inverted: Record<VerificationOutcome, VerificationOutcome> = {\n 'indeterminate': 'indeterminate',\n 'provably-invalid': 'verified',\n 'verified': 'provably-invalid',\n}\n\n/**\n * Builds the invalid-slash-request procedure over a registry it resolves at call time.\n *\n * The registry is passed as a thunk rather than imported, because this procedure lives inside the\n * same registry it needs. Deferring the lookup keeps that self-reference within one module instead\n * of turning it into an import cycle between two.\n */\nexport function createVerifyInvalidSlashRequest(\n resolve: () => Partial<Record<OffenseCode, OffenseProcedure>>,\n): OffenseProcedure {\n /**\n * O6 \u2014 invalid slash request: accusing someone of something that was never true.\n *\n * The whole procedure is the other six run backwards. A report is bad exactly when the thing it\n * alleged is provably not an offense, so this re-runs the original report and turns the answer\n * around. Writing a separate standard for what makes a report wrong would let the two drift, and\n * a reporter could then be punished for a claim that the offense procedure itself would uphold.\n *\n * The re-run is faithful or it is nothing. It runs on the original report's *own* evidence set \u2014\n * never on whatever the complainant chose to bundle \u2014 and through the same preamble the original\n * was subject to, in *its* context: its catalog version, its submission height. Handing the inner\n * procedure a different artifact set is how an honest reporter gets convicted of a shape error\n * it never made.\n *\n * Inversion is deliberately not total. An inner `indeterminate` stays indeterminate rather than\n * becoming a finding against the reporter: a claim nobody can check is not a false claim, and\n * treating it as one would make honest reporting a gamble on other people's data availability.\n * The same discipline covers the original's evidence itself \u2014 artifacts this verifier cannot see\n * withhold the verdict; only artifacts that are present and provably bad count against anyone.\n */\n return async (ctx, request, artifacts) => {\n const accused = artifacts.values().find(artifact => isSlashRequest(artifact.payload))\n if (accused === undefined) {\n return verdict('provably-invalid', 'no slash request among the cited artifacts')\n }\n const original = accused.payload as SlashRequest\n const key = offenseKeyOf(original)\n\n const finalized = (await ctx.history.requestsByKey(key))\n .find(candidate => candidate.hash === accused.dataHash)\n if (finalized === undefined) {\n // without knowing where it landed there is no way to rebuild the context it was filed in\n return verdict('indeterminate', 'the accused request is not visible in finalized history')\n }\n\n const transcript: JsonObject = {\n accusedRequest: accused.dataHash,\n innerOffense: original.offense,\n originalCarryingHeight: finalized.carryingHeight,\n reporter: request.accused,\n }\n\n const adjudication = await ctx.history.adjudicationByKey(key)\n if (adjudication !== undefined) {\n if (adjudication.carryingHeight >= finalized.carryingHeight) {\n // the verdict landed at or after this report was filed, so its filer could not have known\n return verdict('provably-invalid', 'timing-excused: the offense was not yet adjudicated when the report was filed', { ...transcript, adjudicationHeight: adjudication.carryingHeight })\n }\n // re-litigation is its own offense: the verdict was already public record when this report\n // was filed, and re-running the inner procedure would judge the claim instead of the filing\n return verdict('verified', 're-litigation: the offense was already adjudicated on-chain when the report was filed', { ...transcript, adjudicationHeight: adjudication.carryingHeight })\n }\n\n const procedure = resolve()[original.offense]\n if (procedure === undefined) {\n return verdict('indeterminate', `no verification procedure for the inner offense '${original.offense}'`, transcript)\n }\n\n const innerCtx = {\n ...ctx,\n catalogVersion: original.catalog,\n submission: { requestCarryingHeight: finalized.carryingHeight },\n }\n const innerArtifacts = await verifyArtifacts(ctx.artifacts, original.evidence)\n if (!innerArtifacts.ok) {\n return innerArtifacts.missing === true\n ? verdict('indeterminate', `the original's evidence is not available to re-run: ${innerArtifacts.reason}`, transcript)\n : verdict('verified', `the original's evidence fails the preamble: ${innerArtifacts.reason}`, transcript)\n }\n const innerFreshness = await freshnessGate(innerCtx, original)\n const innerVerdict: OffenseVerdict = innerFreshness.verdict\n ?? await procedure(innerCtx, original, innerArtifacts.byHash)\n\n return verdict(\n inverted[innerVerdict.outcome],\n `the original report verified as '${innerVerdict.outcome}': ${innerVerdict.reason}`,\n {\n ...transcript, inner: innerVerdict.transcript, innerOutcome: innerVerdict.outcome,\n },\n )\n }\n}\n", "import type { JsonObject } from '@ariestools/sdk'\nimport { hexToBigInt } from '@ariestools/sdk'\nimport type { Payload } from '@xyo-network/sdk'\nimport {\n asBlockBoundWitness, isTransferPayload, rewardFromBlockNumber, XYO_ZERO_ADDRESS,\n} from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerificationContext } from '../model/OffenseVerificationContext.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\n\n/**\n * How much a block minted into existence.\n *\n * Only transfers out of the zero address count. Everything else in a block moves value that\n * already existed, and a producer paying itself from its own balance is spending, not minting.\n */\nfunction mintedBy(payloads: Payload[]): bigint {\n return payloads\n .filter(payload => isTransferPayload(payload))\n .filter(transfer => transfer.from === XYO_ZERO_ADDRESS)\n .reduce((total, transfer) =>\n total + Object.values(transfer.transfers).reduce((sum, amount) => sum + hexToBigInt(amount), 0n), 0n)\n}\n\n/** What the register permitted this block to mint, or undefined when it cannot be established. */\nasync function allowedEmission(\n ctx: OffenseVerificationContext,\n blockNumber: number,\n parentAnchor: number | undefined,\n): Promise<bigint | undefined> {\n if (ctx.params.rewardSource === 'schedule') return rewardFromBlockNumber(blockNumber as never)\n if (parentAnchor === undefined || ctx.blockRewardAt === undefined) return undefined\n return await ctx.blockRewardAt(parentAnchor)\n}\n\n/**\n * O3 \u2014 reward overmint: paying yourself more than the rules allowed.\n *\n * The allowance is recomputed from the register rather than read from the block, since a block\n * that could state its own allowance could authorise anything. Where the allowance comes from\n * depends on how the chain is configured \u2014 a fixed schedule, or the staking contract \u2014 and when\n * it comes from the contract it is read at the parent's anchor rather than at a live head, so\n * every verifier asks the contract the same question.\n *\n * Minting is counted only from the zero address. A producer moving its own balance around is\n * spending money that already existed, which is nobody's business but its own.\n *\n * Under-minting is not an offense here. A producer that pays itself less than it could has taken\n * nothing from anyone, and treating generosity as misconduct would be absurd.\n *\n * Only the zero-address mint clause is implemented. The specification's fee-rule and step-transfer\n * clauses wait on the deterministic fee replay and the step-boundary reader; until they land,\n * reports alleging those shapes resolve on the mint clause alone \u2014 never as a conviction the\n * missing clauses would have had to establish.\n */\nexport const verifyRewardOvermint: OffenseProcedure = async (ctx, request, artifacts) => {\n const cited = [...artifacts.values()]\n const entry = cited.find(artifact => asBlockBoundWitness(artifact.payload) !== undefined)\n const block = entry === undefined ? undefined : asBlockBoundWitness(entry.payload)\n if (block === undefined) return verdict('provably-invalid', 'no block among the cited artifacts')\n\n if (block.block !== request.block) {\n // the report's height is the freshness clock and the dedup key; a block located elsewhere\n // would let an old offense wear a fresh height\n return verdict('provably-invalid', 'the cited block is not at the height the report names')\n }\n if (!block.addresses.includes(request.accused)) {\n // a block the accused never signed says nothing about it, whatever it minted\n return verdict('provably-invalid', 'the accused did not sign the cited block')\n }\n\n const payloads = cited.filter(artifact => artifact !== entry).map(artifact => artifact.payload)\n const minted = mintedBy(payloads)\n\n const parentAnchor = block.previous === null\n ? undefined\n : await ctx.chain.validatedAnchorAt((block.block - 1) as never)\n const allowed = await allowedEmission(ctx, block.block, parentAnchor)\n\n const transcript: JsonObject = {\n accused: request.accused,\n allowed: allowed === undefined ? null : allowed.toString(),\n block: block.block,\n minted: minted.toString(),\n parentAnchor: parentAnchor ?? null,\n rewardSource: ctx.params.rewardSource,\n }\n\n if (allowed === undefined) {\n return verdict('indeterminate', 'the allowed emission for this block cannot be established', transcript)\n }\n return minted > allowed\n ? verdict('verified', `the block minted ${minted} against an allowance of ${allowed}`, transcript)\n : verdict('provably-invalid', `the block minted ${minted}, within its allowance of ${allowed}`, transcript)\n}\n", "import type { OffenseCode, SlashRequest } from '@xyo-network/xl1-sdk'\n\nimport type { OffenseProcedure } from '../model/OffenseProcedure.ts'\nimport type { OffenseVerificationContext } from '../model/OffenseVerificationContext.ts'\nimport type { OffenseVerdict } from '../model/VerificationOutcome.ts'\nimport { verdict } from '../model/VerificationOutcome.ts'\nimport { freshnessGate, verifyArtifacts } from './preamble.ts'\nimport { verifyEquivocation } from './verifyEquivocation.ts'\nimport { verifyFalseAnchor } from './verifyFalseAnchor.ts'\nimport { verifyFalseAttestation } from './verifyFalseAttestation.ts'\nimport { verifyIneligibleProduction } from './verifyIneligibleProduction.ts'\nimport { verifyInvalidBlock } from './verifyInvalidBlock.ts'\nimport { createVerifyInvalidSlashRequest } from './verifyInvalidSlashRequest.ts'\nimport { verifyRewardOvermint } from './verifyRewardOvermint.ts'\n\n/**\n * The procedure for each offense class.\n *\n * Exported as a map so a class can be verified in isolation by conformance tests, and so the\n * invalid-slash-request procedure can recurse back through it to re-run the report it is\n * complaining about.\n */\nexport const offenseProcedures: Partial<Record<OffenseCode, OffenseProcedure>> = {\n 'equivocation': verifyEquivocation,\n 'false-anchor': verifyFalseAnchor,\n 'false-attestation': verifyFalseAttestation,\n 'ineligible-production': verifyIneligibleProduction,\n 'invalid-block': verifyInvalidBlock,\n 'invalid-slash-request': createVerifyInvalidSlashRequest(() => offenseProcedures),\n 'reward-overmint': verifyRewardOvermint,\n}\n\n/**\n * Verifies one report, end to end.\n *\n * The shared preamble runs first for every class: cited artifacts are re-hashed and their\n * signatures checked, then the offense is measured against the freshness window. Both are\n * conditions no class can waive, so running them once here keeps a procedure from quietly\n * skipping one.\n *\n * A class with no registered procedure is indeterminate rather than invalid. The register can\n * activate a class this build does not implement, and refusing to conclude is the honest answer \u2014\n * concluding \"not an offense\" would let the gap read as an acquittal.\n * @param ctx What the verifier may consult\n * @param request The report being verified\n * @returns The verdict, with its transcript\n */\nexport async function verifyOffense(\n ctx: OffenseVerificationContext,\n request: SlashRequest,\n): Promise<OffenseVerdict> {\n const artifacts = await verifyArtifacts(ctx.artifacts, request.evidence)\n if (!artifacts.ok) {\n // an artifact this verifier cannot see is a statement about the verifier, not the reporter\n return verdict(artifacts.missing === true ? 'indeterminate' : 'provably-invalid', artifacts.reason, { stage: 'artifacts' })\n }\n\n const freshness = await freshnessGate(ctx, request)\n if (freshness.verdict !== undefined) return freshness.verdict\n\n const procedure = offenseProcedures[request.offense]\n if (procedure === undefined) {\n return verdict('indeterminate', `no verification procedure for '${request.offense}'`, { catalogVersion: ctx.catalogVersion, offense: request.offense })\n }\n const result = await procedure(ctx, request, artifacts.byHash)\n return {\n ...result,\n transcript: {\n ...result.transcript,\n eOff: freshness.eOff ?? null,\n eSub: freshness.eSub ?? null,\n offense: request.offense,\n },\n }\n}\n"],
|
|
5
|
+
"mappings": ";AA8BA,SAAS,SAAS,OAA0B,QAAoC;AAC9E,MAAI,MAAM,aAAa,OAAO,SAAU,QAAO;AAC/C,SAAO,MAAM,UAAU,OAAO,SAAS,MAAM,aAAa,OAAO;AACnE;AAGA,SAAS,OAAO,OAA0B,QAAoC;AAC5E,SAAO,MAAM,eAAe,OAAO,YAAY,OAAO,eAAe,MAAM;AAC7E;AAkBO,SAAS,mBAAmB,WAA0D;AAC3F,QAAM,aAAa,oBAAI,IAAqC;AAC5D,aAAW,YAAY,WAAW;AAChC,UAAM,OAAO,WAAW,IAAI,SAAS,QAAQ,KAAK,CAAC;AAEnD,QAAI,KAAK,MAAM,eAAa,UAAU,aAAa,SAAS,QAAQ,EAAG,MAAK,KAAK,QAAQ;AACzF,eAAW,IAAI,SAAS,UAAU,IAAI;AAAA,EACxC;AAEA,QAAM,QAAyB,CAAC;AAChC,aAAW,CAAC,UAAU,UAAU,KAAK,YAAY;AAC/C,eAAW,CAAC,OAAO,KAAK,KAAK,WAAW,QAAQ,GAAG;AACjD,iBAAW,UAAU,WAAW,MAAM,QAAQ,CAAC,GAAG;AAChD,YAAI,CAAC,SAAS,OAAO,MAAM,KAAK,OAAO,OAAO,MAAM,EAAG;AACvD,cAAM,KAAK;AAAA,UACT,OAAO,KAAK,IAAI,MAAM,OAAO,OAAO,KAAK;AAAA,UAAG;AAAA,UAAO;AAAA,UAAU;AAAA,QAC/D,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AC5EA,SAAS,uBAAuB,wBAAwB;AAiBjD,SAAS,mBAAmB,QAAqB,SAAsB,QAAyB;AACrG,MAAI,CAAC,sBAAsB,QAAQ,SAAS,MAAM,EAAG,QAAO;AAC5D,SAAO,YAAY,iBAAiB,iBAAiB,QAAQ,oBAAoB,MAAM,IAAI;AAC7F;;;ACEA,eAAsB,eACpB,SACA,KACwC;AACxC,MAAI,MAAM,QAAQ,kBAAkB,GAAG,MAAM,OAAW,QAAO;AAC/D,UAAQ,MAAM,QAAQ,cAAc,GAAG,GAAG,SAAS,IAAI,qBAAqB;AAC9E;;;AC1BA,SAAS,iBAAiB,6BAA6B;AAuEvD,eAAsB,4BAA4B,OAAyD;AACzG,QAAM;AAAA,IACJ;AAAA,IAAS;AAAA,IAAa;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAc;AAAA,EAC9D,IAAI;AACJ,MAAI,gBAAgB,UAAa,iBAAiB,QAAW;AAC3D,WAAO,EAAE,YAAY,MAAM;AAAA,EAC7B;AACA,MAAI,aAAa,QAAW;AAC1B,WAAO,EAAE,OAAO,gBAAgB,cAAc,aAAa,OAAO,sBAAsB,GAAG,YAAY,MAAM;AAAA,EAC/G;AAEA,QAAM,QAAQ,gBAAgB,cAAc,aAAa,OAAO,sBAAsB;AACtF,QAAM,SAAS,OAAO;AACtB,QAAM,CAAC,gBAAgB,kBAAkB,QAAQ,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,IAChF,SAAS,yBAAyB,SAAS,OAAO,MAAM;AAAA,IACxD,SAAS,mBAAmB,SAAS,OAAO,MAAM;AAAA,IAClD,SAAS,iBAAiB,SAAS,KAAK;AAAA,IACxC,OAAO,SAAS,MAAM;AAAA,EACxB,CAAC;AACD,MAAI,gBAAgB,QAAW;AAE7B,WAAO;AAAA,MACL,aAAa;AAAA,MAAgB;AAAA,MAAO,YAAY;AAAA,MAAO,UAAU;AAAA,IACnE;AAAA,EACF;AACA,QAAM,WAAW;AAAA,IACf;AAAA,IAAQ;AAAA,IAAgB;AAAA,EAC1B;AACA,QAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,MACE,aAAa,QAAQ,OAAO,uBAAuB;AAAA,MACnD,UAAU,QAAQ,OAAO,oBAAoB;AAAA,IAC/C;AAAA,IACA;AAAA,EACF;AACA,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IACA,UAAU,WAAW;AAAA,IACrB;AAAA,IACA,QAAQ,UAAU;AAAA,IAClB,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ;AACF;AAGA,SAAS,QAAQ,OAAuB;AACtC,MAAI,UAAU,GAAI,QAAO;AACzB,SAAO,OAAO,MAAM,WAAW,IAAI,IAAI,QAAQ,KAAK,KAAK,EAAE;AAC7D;;;ACxHA;AAAA,EACE;AAAA,EAAqB;AAAA,EAAkB;AAAA,EAAe;AAAA,EACtD;AAAA,EAAuB;AAAA,EAA4B;AAAA,EAAyB;AAAA,EAC5E;AAAA,EAAmB;AAAA,EAA2B;AAAA,OACzC;;;ACeA,SAAS,aAAa,SAAmC;AAC9D,SAAO;AAAA,IACL,SAAS,QAAQ;AAAA,IACjB,OAAO,QAAQ;AAAA,IACf,OAAO,QAAQ;AAAA,IACf,SAAS,QAAQ;AAAA,EACnB;AACF;AAQO,SAAS,iBAAiB,KAAyB;AACxD,SAAO,GAAG,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,IAAI,OAAO,IAAI,IAAI,KAAK;AAChE;AAcO,SAAS,uBAAuB,SAAuC;AAC5E,SAAO,QAAQ;AACjB;;;ADHA,IAAM,aAAa,OAAwB;AAAA,EACzC,SAAS,oBAAI,IAAI;AAAA,EAAG,MAAM,oBAAI,IAAI;AAAA,EAAG,SAAS,CAAC;AAAA,EAAG,SAAS,CAAC;AAC9D;AAEA,IAAM,WAAW,CAAC,MAAc,aAC7B;AAAA,EACC,WAAW;AAAA,EAAM;AAAA,EAAM,OAAO;AAChC;AAcK,SAAS,eAAe,QAA4D;AACzF,QAAM,QAAQ,WAAW;AACzB,QAAM,mBAAmB,oBAAI,IAAkB;AAC/C,aAAW,CAAC,EAAE,QAAQ,KAAK,QAAQ;AACjC,eAAW,WAAW,SAAU,aAAY,OAAO,kBAAkB,OAAO;AAAA,EAC9E;AACA,SAAO;AACT;AAGA,SAAS,WAAW,OAAwB,SAAqD;AAC/F,QAAM,MAAM,aAAa,OAAO;AAChC,QAAM,OAAO,kBAAkB,IAAI,SAAS,IAAI,SAAS,IAAI,KAAK;AAClE,MAAI,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG;AACzB,UAAM,KAAK,IAAI,MAAM;AAAA,MACnB,SAAS,IAAI;AAAA,MACb,OAAO,IAAI;AAAA,MACX,YAAY,CAAC;AAAA,MACb,OAAO,IAAI;AAAA,MACX,SAAS,IAAI;AAAA,MACb,UAAU,CAAC;AAAA,MACX,QAAQ;AAAA,IACV,CAAC;AACD,UAAM,cAAc,sBAAsB,IAAI,OAAO;AACrD,UAAM,QAAQ,IAAI,aAAa,CAAC,GAAI,MAAM,QAAQ,IAAI,WAAW,KAAK,CAAC,GAAI,iBAAiB,GAAG,CAAC,CAAC;AAAA,EACnG;AACA,SAAO;AACT;AAEA,SAAS,YACP,OACA,kBACA,SACM;AACN,MAAI,eAAe,OAAO,GAAG;AAC3B,UAAM,QAAQ,KAAK,SAAS,sBAAsB,QAAQ,SAAS,GAAG,OAAO,CAAC;AAC9E,UAAM,OAAO,WAAW,OAAO,OAAO;AACtC,qBAAiB,IAAI,QAAQ,WAAW,IAAI;AAC5C,UAAM,SAAS,MAAM,KAAK,IAAI,IAAI;AAClC,QAAI,WAAW,UAAa,CAAC,OAAO,SAAS,SAAS,QAAQ,SAAS,GAAG;AACxE,aAAO,SAAS,KAAK,QAAQ,SAAS;AAAA,IACxC;AACA;AAAA,EACF;AACA,MAAI,cAAc,OAAO,GAAG;AAC1B,UAAM,QAAQ,KAAK,SAAS,qBAAqB,QAAQ,SAAS,GAAG,OAAO,CAAC;AAC7E;AAAA,EACF;AACA,MAAI,iBAAiB,OAAO,GAAG;AAC7B,UAAM,QAAQ,KAAK,SAAS,wBAAwB,QAAQ,SAAS,GAAG,OAAO,CAAC;AAChF,kBAAc,OAAO,kBAAkB;AAAA,MACrC,MAAM,QAAQ;AAAA,MAAW,MAAM;AAAA,MAAa,SAAS,QAAQ;AAAA,IAC/D,CAAC;AACD;AAAA,EACF;AACA,MAAI,oBAAoB,OAAO,GAAG;AAChC,UAAM,QAAQ,KAAK,SAAS,2BAA2B,QAAQ,SAAS,GAAG,OAAO,CAAC;AACnF,UAAM,OAAO,cAAc,OAAO,kBAAkB;AAAA,MAClD,MAAM,QAAQ;AAAA,MAAW,MAAM;AAAA,MAAgB,SAAS,QAAQ;AAAA,MAAS,SAAS,QAAQ;AAAA,IAC5F,CAAC;AACD,UAAM,SAAS,SAAS,SAAY,SAAY,MAAM,KAAK,IAAI,IAAI;AAGnE,QAAI,WAAW,UAAa,OAAO,iBAAiB,QAAW;AAC7D,aAAO,eAAe,QAAQ;AAC9B,aAAO,UAAU,QAAQ;AAAA,IAC3B;AAAA,EACF;AACF;AAUA,SAAS,cACP,OACA,kBACA,MACoB;AACpB,QAAM,OAAO,iBAAiB,IAAI,KAAK,OAAO;AAC9C,QAAM,mBAAmB,MAAM,QAAQ,KAAK,aAAW,QAAQ,SAAS,cAAc;AACtF,MAAI,SAAS,UAAc,KAAK,SAAS,kBAAkB,kBAAmB;AAC5E,UAAM,QAAQ,KAAK,IAAI;AACvB,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,aAAa;AAC7B,UAAM,SAAS,MAAM,KAAK,IAAI,IAAI;AAClC,QAAI,WAAW,UAAa,CAAC,OAAO,WAAW,SAAS,KAAK,IAAI,EAAG,QAAO,WAAW,KAAK,KAAK,IAAI;AAAA,EACtG;AACA,SAAO;AACT;AAYO,SAAS,eACd,UACA,MACqB;AACrB,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,QAAQ,CAAC,MAAyB,UAA6B,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC;AAGrG,QAAMA,WAAU,SAAS,iBAAiB,SAAY,OAAO;AAC7D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,IACH,cAAcA,SAAQ;AAAA,IACtB,YAAY,MAAM,SAAS,YAAY,KAAK,UAAU;AAAA,IACtD,SAASA,SAAQ;AAAA,IACjB,UAAU,MAAM,SAAS,UAAU,KAAK,QAAQ;AAAA,EAClD;AACF;;;AEnMO,IAAM,yBAAyB;AAoB/B,SAAS,kBAAkB,OAA0C;AAC1E,QAAM,YAAY;AAClB,SAAO,OAAO,WAAW,eAAe,cACnC,OAAO,UAAU,cAAc,cAC/B,OAAO,UAAU,gBAAgB;AACxC;;;ACjBO,IAAM,uBAAuB,CAAC,YAAY,iBAAiB,kBAAkB;AA8B7E,SAAS,QACd,SACA,QACA,aAAyB,CAAC,GAC1B,aACgB;AAChB,SAAO,gBAAgB,SACnB;AAAA,IACE;AAAA,IAAS;AAAA,IAAQ;AAAA,EACnB,IACA;AAAA,IACE;AAAA,IAAS;AAAA,IAAa;AAAA,IAAQ;AAAA,EAChC;AACN;;;ACpDA,SAAS,gBAAgB,sBAAsB;AAE/C,SAAS,uCAAuC;AA2BhD,eAAsB,gBACpB,WACA,YACwB;AACxB,QAAM,SAAS,oBAAI,IAA4B;AAC/C,aAAW,WAAW,YAAY;AAChC,UAAM,YAAY,UAAU,IAAI,OAAO;AACvC,QAAI,cAAc,QAAW;AAC3B,aAAO;AAAA,QACL,SAAS;AAAA,QAAM,IAAI;AAAA,QAAO,QAAQ,kBAAkB,OAAO;AAAA,MAC7D;AAAA,IACF;AACA,UAAM,UAAU;AAEhB,UAAM,WAAW,MAAM,eAAe,SAAS,OAAO;AACtD,QAAI,aAAa,SAAS;AACxB,aAAO,EAAE,IAAI,OAAO,QAAQ,qBAAqB,OAAO,cAAc,QAAQ,GAAG;AAAA,IACnF;AACA,QAAI,eAAe,OAAO,GAAG;AAC3B,YAAM,kBAAkB,MAAM,gCAAgC,OAAO;AACrE,UAAI,gBAAgB,SAAS,GAAG;AAC9B,eAAO,EAAE,IAAI,OAAO,QAAQ,YAAY,QAAQ,gCAAgC;AAAA,MAClF;AAAA,IACF;AACA,WAAO,IAAI,UAAU;AAAA,MACnB;AAAA,MAAU;AAAA,MAAS,aAAa,MAAM,eAAe,KAAK,OAAO;AAAA,IACnE,CAAC;AAAA,EACH;AACA,SAAO,EAAE,QAAQ,IAAI,KAAK;AAC5B;AASA,eAAsB,mBAAmB,WAAoC,UAA8C;AACzH,MAAI,cAAc,QAAQ,cAAc,OAAW,QAAO;AAC1D,MAAI,cAAc,SAAS,SAAU,QAAO;AAC5C,QAAM,cAAc,SAAS,eAAe,MAAM,eAAe,KAAK,SAAS,OAAO;AACtF,SAAO,cAAc;AACvB;AA0BA,eAAsB,cACpB,KACA,SAC0B;AAC1B,QAAM,OAAO,MAAM,IAAI,MAAM,kBAAkB,QAAQ,KAAK;AAC5D,MAAI,SAAS,QAAW;AACtB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS,QAAQ,iBAAiB,4CAA4C;AAAA,IAChF;AAAA,EACF;AACA,QAAM,mBAAmB,IAAI,WAAW,wBAAwB,IAAI,WAAW;AAC/E,QAAM,OAAO,MAAM,IAAI,MAAM,kBAAkB,gBAAgB;AAC/D,MAAI,SAAS,QAAW;AACtB,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR,SAAS,QAAQ,iBAAiB,+CAA+C;AAAA,IACnF;AAAA,EACF;AACA,QAAM,MAAM,OAAO;AACnB,MAAI,MAAM,IAAI,OAAO,4BAA4B;AAC/C,UAAM,SAAS,cAAc,GAAG,6BAA6B,IAAI,OAAO,0BAA0B;AAClG,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,QAAQ,oBAAoB,QAAQ;AAAA,QAC3C;AAAA,QAAK;AAAA,QAAM;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IAAM;AAAA,IAAM,QAAQ,cAAc,GAAG;AAAA,EACvC;AACF;;;ACrIA,SAAS,2BAA2B;AAWpC,IAAM,eAAe,CAAC,aAAuD;AAC3E,QAAM,QAAQ,oBAAoB,SAAS,OAAO;AAClD,SAAO,UAAU,SAAY,SAAY,EAAE,OAAO,UAAU,SAAS,SAAS;AAChF;AAkBO,IAAM,qBAAuC,OAAO,MAAM,SAAS,cAAc;AACtF,QAAM,QAAQ,CAAC,GAAG,UAAU,OAAO,CAAC;AAGpC,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,QAAQ,oBAAoB,+CAA+C,MAAM,MAAM,EAAE;AAAA,EAClG;AAEA,QAAM,SAAS,MAAM,IAAI,cAAY,aAAa,QAAQ,CAAC;AAC3D,QAAM,CAAC,OAAO,MAAM,IAAI;AACxB,MAAI,UAAU,UAAa,WAAW,QAAW;AAC/C,WAAO,QAAQ,oBAAoB,qCAAqC;AAAA,EAC1E;AAEA,QAAM,aAAa;AAAA,IACjB,SAAS,QAAQ;AAAA,IACjB,OAAO;AAAA,MACL,OAAO,MAAM,MAAM;AAAA,MAAO,UAAU,MAAM;AAAA,MAAU,UAAU,MAAM,MAAM;AAAA,MAAU,YAAY,MAAM,MAAM,cAAc;AAAA,IAC5H;AAAA,IACA,QAAQ;AAAA,MACN,OAAO,OAAO,MAAM;AAAA,MAAO,UAAU,OAAO;AAAA,MAAU,UAAU,OAAO,MAAM;AAAA,MAAU,YAAY,OAAO,MAAM,cAAc;AAAA,IAChI;AAAA,EACF;AAEA,MAAI,OAAO,KAAK,UAAQ,CAAC,MAAM,MAAM,UAAU,SAAS,QAAQ,OAAO,CAAC,GAAG;AAEzE,WAAO,QAAQ,oBAAoB,wCAAwC,UAAU;AAAA,EACvF;AACA,MAAI,MAAM,MAAM,UAAU,OAAO,MAAM,OAAO;AAC5C,WAAO,QAAQ,oBAAoB,sCAAsC,UAAU;AAAA,EACrF;AACA,MAAI,MAAM,MAAM,UAAU,QAAQ,OAAO;AACvC,WAAO,QAAQ,oBAAoB,oDAAoD,UAAU;AAAA,EACnG;AACA,MAAI,MAAM,MAAM,UAAU,QAAQ,SAAS,OAAO,MAAM,UAAU,QAAQ,OAAO;AAG/E,WAAO,QAAQ,oBAAoB,gEAAgE,UAAU;AAAA,EAC/G;AACA,MAAI,MAAM,MAAM,UAAU,OAAO,MAAM,SAAS,MAAM,MAAM,aAAa,OAAO,MAAM,UAAU;AAE9F,WAAO,QAAQ,oBAAoB,kDAAkD,UAAU;AAAA,EACjG;AAEA,QAAM,aAAa,oBAAI,IAAI,CAAC,MAAM,MAAM,YAAY,OAAO,MAAM,UAAU,CAAC;AAC5E,MAAI,WAAW,IAAI,MAAM,QAAQ,KAAK,WAAW,IAAI,OAAO,QAAQ,GAAG;AAErE,WAAO,QAAQ,oBAAoB,4DAA4D,UAAU;AAAA,EAC3G;AAEA,SAAO,QAAQ,YAAY,iEAAiE,UAAU;AACxG;;;ACpFA,SAAS,iBAAiB;AAC1B,SAAS,kBAAAC,uBAAsB;AAE/B,SAAS,uBAAAC,sBAAqB,qBAAqB;AAsBnD,eAAe,eAAe,WAA0E;AACtG,QAAM,QAAQ,CAAC,GAAG,UAAU,OAAO,CAAC;AACpC,QAAM,QAAQ,MAAM,QAAQ,IAAI,MAC7B,OAAO,cAAY,cAAc,SAAS,OAAO,CAAC,EAClD,IAAI,OAAM,cAAa;AAAA,IACtB,QAAQ,CAAC,SAAS,UAAU,SAAS,eAAe,MAAMC,gBAAe,KAAK,SAAS,OAAO,CAAC,EAAE,OAAO,UAAQ,UAAU,IAAI,CAAC;AAAA,IAC/H,MAAM,SAAS;AAAA,EACjB,EAAE,CAAC;AACL,SAAO,MACJ,QAAQ,CAAC,aAAa;AACrB,UAAM,QAAQC,qBAAoB,SAAS,OAAO;AAClD,WAAO,UAAU,SAAY,CAAC,IAAI,CAAC,EAAE,UAAU,MAAM,CAAC;AAAA,EACxD,CAAC,EACA,IAAI,CAAC,EAAE,UAAU,MAAM,MAAM;AAC5B,UAAM,UAAU,IAAI,IAAI,MAAM,cAAc;AAC5C,UAAM,OAAO,MAAM,KAAK,eAAa,UAAU,OAAO,KAAK,UAAQ,QAAQ,IAAI,IAAI,CAAC,CAAC;AACrF,WAAO;AAAA,MACL;AAAA,MAAU;AAAA,MAAO,KAAM,MAAM,MAA4C;AAAA,MAAU,SAAU,MAAM,MAA8C;AAAA,IACnJ;AAAA,EACF,CAAC;AACL;AAGA,eAAe,SAAS,SAAwB,QAA6D;AAC3G,aAAW,aAAa,QAAQ;AAC9B,QAAI,cAAc,QAAS;AAC3B,QAAI,MAAM,mBAAmB,QAAQ,MAAM,UAAU,UAAU,QAAQ,EAAG,QAAO;AAAA,EACnF;AACA,SAAO;AACT;AAcO,IAAM,oBAAsC,OAAO,KAAK,SAAS,cAAc;AACpF,QAAM,SAAS,MAAM,eAAe,SAAS;AAC7C,QAAM,UAAU,OAAO,KAAK,eAAa,UAAU,MAAM,UAAU,QAAQ,KAAK;AAChF,MAAI,YAAY,OAAW,QAAO,QAAQ,oBAAoB,qDAAqD;AAInH,QAAM,SAAS,MAAM,SAAS,SAAS,MAAM;AAC7C,MAAI,QAAQ,QAAQ,UAAa,QAAQ,YAAY,QAAW;AAC9D,WAAO,QAAQ,oBAAoB,2DAA2D;AAAA,EAChG;AACA,MAAI,CAAC,QAAQ,MAAM,UAAU,SAAS,QAAQ,OAAO,GAAG;AAEtD,WAAO,QAAQ,oBAAoB,0CAA0C;AAAA,EAC/E;AAEA,QAAM,aAAyB;AAAA,IAC7B,SAAS,QAAQ;AAAA,IACjB,OAAO,QAAQ,MAAM;AAAA,IACrB,YAAY,QAAQ;AAAA,IACpB,gBAAgB,QAAQ;AAAA,IACxB,WAAW,QAAQ,OAAO;AAAA,EAC5B;AAEA,MAAI,QAAQ,QAAQ,UAAa,QAAQ,MAAM,OAAO,KAAK;AAEzD,WAAO,QAAQ,YAAY,mCAAmC,OAAO,GAAG,OAAO,QAAQ,GAAG,IAAI,UAAU;AAAA,EAC1G;AAEA,MAAI,QAAQ,QAAQ,QAAQ,KAAK;AAE/B,WAAO,QAAQ,oBAAoB,wDAAwD,UAAU;AAAA,EACvG;AACA,MAAI,IAAI,QAAQ,QAAW;AACzB,WAAO,QAAQ,iBAAiB,wDAAwD,UAAU;AAAA,EACpG;AACA,QAAM,OAAO,MAAM,IAAI,IAAI,KAAK;AAChC,MAAI,SAAS,QAAW;AACtB,WAAO,QAAQ,iBAAiB,kCAAkC,UAAU;AAAA,EAC9E;AACA,MAAI,OAAO,QAAQ,MAAM,IAAI,OAAO,mBAAmB;AAErD,WAAO,QAAQ,iBAAiB,sBAAsB,OAAO,QAAQ,GAAG,wCAAwC,EAAE,GAAG,YAAY,KAAK,CAAC;AAAA,EACzI;AACA,QAAM,YAAY,MAAM,IAAI,IAAI,gBAAgB,QAAQ,GAAG;AAC3D,MAAI,cAAc,QAAW;AAC3B,WAAO,QAAQ,iBAAiB,2DAA2D,UAAU;AAAA,EACvG;AACA,SAAO,cAAc,QAAQ,UACzB,QAAQ,oBAAoB,2DAA2D,EAAE,GAAG,YAAY,UAAU,CAAC,IACnH,QAAQ,YAAY,iEAAiE,EAAE,GAAG,YAAY,UAAU,CAAC;AACvH;;;ACvHA,SAAS,kBAAAC,uBAAsB;AAE/B;AAAA,EACE,uBAAAC;AAAA,EAAqB;AAAA,EAAe;AAAA,OAC/B;AAYP,IAAM,mBAAmB,CAAC,UAA4D;AACpF,QAAM,QAAQ,MAAM,KAAK,cAAY,cAAc,SAAS,OAAO,CAAC;AACpE,SAAO,UAAU,SACb,SACA,EAAE,UAAU,OAAO,aAAa,MAAM,QAAuB;AACnE;AAUA,eAAe,eAAe,OAA2B,aAA+B,SAAmC;AACzH,aAAW,YAAY,OAAO;AAC5B,UAAM,UAAU,SAAS;AACzB,QAAI,CAACC,gBAAe,SAAS,OAAgB,EAAG;AAChD,QAAI,EAAE,QAAQ,WAAW,SAAS,OAAO,KAAK,OAAQ;AACtD,eAAW,WAAW,QAAQ,kBAAkB,CAAC,GAAG;AAClD,UAAI,MAAM,mBAAmB,SAAkB,YAAY,QAAQ,EAAG,QAAO;AAAA,IAC/E;AAAA,EACF;AACA,SAAO;AACT;AAqBO,IAAM,yBAA2C,OAAO,KAAK,SAAS,cAAc;AACzF,QAAM,QAAQ,CAAC,GAAG,UAAU,OAAO,CAAC;AACpC,QAAM,QAAQ,iBAAiB,KAAK;AACpC,MAAI,UAAU,QAAW;AACvB,WAAO,QAAQ,oBAAoB,0CAA0C;AAAA,EAC/E;AACA,QAAM,EAAE,YAAY,IAAI;AAExB,QAAM,aAAyB;AAAA,IAC7B,SAAS,QAAQ;AAAA,IACjB,eAAe,YAAY;AAAA,IAC3B,mBAAmB,YAAY;AAAA,IAC/B,kBAAkB,YAAY;AAAA,IAC9B,UAAU,YAAY;AAAA,EACxB;AAEA,MAAI,YAAY,YAAY,QAAQ,WAAW,CAAC,MAAM,eAAe,OAAO,OAAO,QAAQ,OAAO,GAAG;AAEnG,WAAO,QAAQ,oBAAoB,2EAA2E,UAAU;AAAA,EAC1H;AAEA,QAAM,QAAS,UAAgC,QAAQ,YAAY,QAAQ;AAC3E,MAAI,UAAU,IAAI;AAEhB,WAAO,QAAQ,oBAAoB,8CAA8C,YAAY,QAAQ,IAAI,UAAU;AAAA,EACrH;AAEA,QAAM,WAAW,MACd,IAAI,eAAa,EAAE,OAAOC,qBAAoB,SAAS,OAAO,GAAG,UAAU,SAAS,SAAS,EAAE,EAC/F,KAAK,eAAa,UAAU,UAAU,UAAa,UAAU,aAAa,YAAY,SAAS;AAElG,MAAI,UAAU,UAAU,QAAW;AAEjC,UAAM,UAAU,SAAS,MAAM,cAAc,KAAK;AAClD,WAAO,YAAY,YAAY,WAC3B,QAAQ,oBAAoB,uEAAuE,UAAU,IAC7G,QAAQ,YAAY,wDAAwD;AAAA,MAC1E,GAAG;AAAA,MAAY,iBAAiB,SAAS,MAAM,eAAe,CAAC;AAAA,MAAG,SAAS,WAAW;AAAA,IACxF,CAAC;AAAA,EACP;AAEA,QAAM,MAAM,IAAI,WAAW,wBAAwB,YAAY;AAC/D,MAAI,MAAM,IAAI,OAAO,4BAA4B;AAE/C,WAAO,QAAQ,iBAAiB,yBAAyB,GAAG,2CAA2C,UAAU;AAAA,EACnH;AAEA,QAAM,YAAY,MAAM,IAAI,MAAM,cAAc,YAAY,WAAW;AACvE,MAAI,cAAc,QAAW;AAC3B,WAAO,QAAQ,iBAAiB,iEAAiE,UAAU;AAAA,EAC7G;AACA,QAAM,gBAAiB,UAAU,CAAC,EAAwC;AAC1E,SAAO,kBAAkB,YAAY,YACjC,QAAQ,oBAAoB,0DAA0D,UAAU,IAChG;AAAA,IACE;AAAA,IACA;AAAA,IACA,EAAE,GAAG,YAAY,eAAe,iBAAiB,KAAK;AAAA,IACtD;AAAA,EACF;AACN;;;ACzHA,SAAS,uBAAAC,sBAAqB,iBAAAC,sBAAqB;AAcnD,eAAe,SAAS,OAA0B,WAA6E;AAC7H,aAAW,YAAY,UAAU,OAAO,GAAG;AACzC,QAAI,CAACC,eAAc,SAAS,OAAO,EAAG;AACtC,eAAW,WAAW,MAAM,gBAAgB;AAC1C,UAAI,MAAM,mBAAmB,SAAS,QAAQ,EAAG,QAAO,SAAS,QAAQ;AAAA,IAC3E;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,UAAU,CAAC,QAAgB,cAC/B,CAAC,GAAG,UAAU,OAAO,CAAC,EACnB,IAAI,cAAYC,qBAAoB,SAAS,OAAO,CAAC,EACrD,KAAK,WAAS,OAAO,UAAU,MAAM;AAG1C,eAAe,iBACb,WACA,WACwC;AACxC,MAAI,cAAc,KAAM,QAAO;AAC/B,aAAW,YAAY,UAAU,OAAO,GAAG;AACzC,UAAM,QAAQA,qBAAoB,SAAS,OAAO;AAClD,QAAI,UAAU,OAAW;AACzB,QAAI,MAAM,mBAAmB,WAAW,QAAQ,EAAG,QAAO;AAAA,EAC5D;AACA,SAAO;AACT;AAiBO,IAAM,6BAA+C,OAAO,KAAK,SAAS,cAAc;AAC7F,QAAM,UAAU,QAAQ,QAAQ,OAAO,SAAS;AAGhD,QAAM,SAAS,YAAY,SAAY,SAAY,MAAM,iBAAiB,QAAQ,UAAU,SAAS;AACrG,MAAI,YAAY,UAAa,WAAW,QAAW;AACjD,WAAO,QAAQ,oBAAoB,6DAA6D;AAAA,EAClG;AACA,MAAI,CAAC,QAAQ,UAAU,SAAS,QAAQ,OAAO,GAAG;AAChD,WAAO,QAAQ,oBAAoB,0CAA0C;AAAA,EAC/E;AAEA,QAAM,cAAc,MAAM,SAAS,SAAS,SAAS;AACrD,QAAM,eAAe,MAAM,SAAS,QAAQ,SAAS;AACrD,MAAI,gBAAgB,UAAa,iBAAiB,QAAW;AAC3D,WAAO,QAAQ,iBAAiB,2DAA2D;AAAA,EAC7F;AAEA,QAAM,aAAa,MAAM,4BAA4B;AAAA,IACnD,SAAS,QAAQ;AAAA,IACjB;AAAA,IACA,QAAQ,QAAQ;AAAA,IAChB,QAAQ,MAAM,QAAQ,UAAU,SAAS,QAAQ,OAAO;AAAA,IACxD,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA,UAAU,IAAI;AAAA,EAChB,CAAC;AACD,QAAM,aAAyB;AAAA,IAC7B,SAAS,QAAQ;AAAA,IAAS;AAAA,IAAa,OAAO,WAAW,SAAS;AAAA,IAAM;AAAA,EAC1E;AAEA,MAAI,QAAQ,QAAQ,WAAW,OAAO;AAEpC,WAAO,QAAQ,oBAAoB,0BAA0B,QAAQ,GAAG,8BAA8B,WAAW,KAAK,IAAI,UAAU;AAAA,EACtI;AACA,MAAI,CAAC,WAAW,YAAY;AAC1B,WAAO,QAAQ,iBAAiB,qDAAqD,UAAU;AAAA,EACjG;AAEA,QAAM,WAAW;AAAA,IACf,GAAG;AAAA,IACH,gBAAgB,WAAW,aAAa,SAAS,KAAK;AAAA,IACtD,kBAAkB,WAAW,UAAU,SAAS,KAAK;AAAA,EACvD;AACA,SAAO,WAAW,aAAa,OAC3B,QAAQ,oBAAoB,iEAAiE,QAAQ,IACrG,QAAQ,YAAY,6CAA6C,WAAW,MAAM,IAAI,EAAE,GAAG,UAAU,QAAQ,WAAW,UAAU,KAAK,CAAC;AAC9I;;;ACxGA;AAAA,EACE,uBAAAC;AAAA,EAAqB;AAAA,EAAwC;AAAA,OACxD;AAEP,SAAS,qBAAqB;AAa9B,SAAS,mBAAmB,WAAkF;AAC5G,QAAM,QAAQ,CAAC,GAAG,UAAU,OAAO,CAAC;AACpC,QAAM,QAAQ,MAAM,KAAK,cAAYC,qBAAoB,SAAS,OAAO,MAAM,MAAS;AACxF,QAAM,QAAQ,UAAU,SAAY,SAAYA,qBAAoB,MAAM,OAAO;AACjF,MAAI,UAAU,OAAW,QAAO;AAIhC,QAAM,aAAa,IAAI,IAAY,MAAM,eAAe,IAAI,MAAM,CAAC;AACnE,SAAO;AAAA,IACL;AAAA,IACA,UAAU,MACP,OAAO,cAAY,aAAa,KAAK,EACrC,IAAI,cAAY,SAAS,OAAO,EAChC,OAAO,CAAC,YAAY;AACnB,YAAM,EAAE,OAAO,UAAU,IAAI;AAC7B,aAAQ,UAAU,UAAa,WAAW,IAAI,KAAK,KAAO,cAAc,UAAa,WAAW,IAAI,SAAS;AAAA,IAC/G,CAAC;AAAA,EACL;AACF;AAEA,IAAM,iCAAiC,2CAA2C;AAclF,eAAe,iBACb,OACA,YACqC;AACrC,QAAM,SAAS,MAAM;AAAA,IACnB,EAAE,sBAAsB,MAAM,MAAM,MAAM,OAAO,YAAY,CAAC,EAAE;AAAA,IAChE,CAAC,MAAM,OAAO,MAAM,QAAQ;AAAA,EAC9B;AACA,SAAO,OAAO,SAAS,IACnB,QAAQ,YAAY,yCAAyC,OAAO,CAAC,GAAG,OAAO,IAAI;AAAA,IACjF,GAAG;AAAA,IAAY,QAAQ,OAAO,IAAI,WAAS,MAAM,OAAO;AAAA,IAAG,MAAM;AAAA,EACnE,CAAC,IACD;AACN;AASA,eAAe,iBACb,KACA,OACA,YACyB;AACzB,MAAI,IAAI,aAAa,QAAW;AAC9B,WAAO,QAAQ,iBAAiB,sDAAsD,UAAU;AAAA,EAClG;AACA,QAAM,SAAS,MAAM,uCAAuC;AAAA,IAC1D;AAAA,MACE,gBAAgB,IAAI;AAAA,MAAU,sBAAsB,MAAM,MAAM,MAAM;AAAA,MAAO,YAAY,CAAC;AAAA,IAC5F;AAAA,IACA,CAAC,MAAM,OAAO,MAAM,QAAQ;AAAA,EAC9B;AACA,SAAO,OAAO,SAAS,IACnB,QAAQ,YAAY,wCAAwC,OAAO,CAAC,GAAG,OAAO,IAAI;AAAA,IAChF,GAAG;AAAA,IAAY,QAAQ,OAAO,IAAI,WAAS,MAAM,OAAO;AAAA,IAAG,MAAM;AAAA,EACnE,CAAC,IACD,QAAQ,oBAAoB,kEAAkE,UAAU;AAC9G;AAiBO,IAAM,qBAAuC,OAAO,KAAK,SAAS,cAAc;AACrF,QAAM,QAAQ,mBAAmB,SAAS;AAC1C,MAAI,UAAU,OAAW,QAAO,QAAQ,oBAAoB,oCAAoC;AAEhG,QAAM,aAAyB;AAAA,IAC7B,SAAS,QAAQ;AAAA,IACjB,OAAO,MAAM,MAAM;AAAA,IACnB,gBAAgB,IAAI;AAAA,IACpB,cAAc,MAAM,SAAS;AAAA,EAC/B;AAEA,MAAI,MAAM,MAAM,UAAU,QAAQ,OAAO;AAGvC,WAAO,QAAQ,oBAAoB,yDAAyD,UAAU;AAAA,EACxG;AACA,MAAI,CAAC,MAAM,MAAM,UAAU,SAAS,QAAQ,OAAO,GAAG;AAEpD,WAAO,QAAQ,oBAAoB,4CAA4C,UAAU;AAAA,EAC3F;AAEA,QAAM,iBAAiB,MAAM,cAAc,EAAE,YAAY,CAAC,EAAE,GAAG,MAAM,OAAO,MAAM,MAAM,KAAK;AAC7F,MAAI,eAAe,SAAS,GAAG;AAC7B,WAAO,QAAQ,YAAY,2CAA2C,eAAe,CAAC,GAAG,OAAO,IAAI;AAAA,MAClG,GAAG;AAAA,MAAY,QAAQ,eAAe,IAAI,WAAS,MAAM,OAAO;AAAA,MAAG,MAAM;AAAA,IAC3E,CAAC;AAAA,EACH;AAIA,QAAM,gBAAgB,MAAM,iBAAiB,OAAO,UAAU;AAC9D,MAAI,kBAAkB,OAAW,QAAO;AAExC,MAAI,MAAM,MAAM,aAAa,MAAM;AACjC,WAAO,QAAQ,oBAAoB,+EAA+E,UAAU;AAAA,EAC9H;AACA,QAAM,SAAS,MAAM,IAAI,MAAM,YAAY,MAAM,MAAM,QAAQ;AAC/D,MAAI,WAAW,QAAW;AACxB,WAAO,QAAQ,iBAAiB,wDAAwD,UAAU;AAAA,EACpG;AACA,MAAI,MAAM,MAAM,UAAU,OAAO,CAAC,EAAE,QAAQ,GAAG;AAC7C,WAAO,QAAQ,YAAY,4DAA4D;AAAA,MACrF,GAAG;AAAA,MAAY,aAAa,OAAO,CAAC,EAAE;AAAA,MAAO,MAAM;AAAA,IACrD,CAAC;AAAA,EACH;AAEA,SAAO,MAAM,iBAAiB,KAAK,OAAO,UAAU;AACtD;;;AC9JA,SAAS,kBAAAC,uBAAsB;AAS/B,IAAM,WAA6D;AAAA,EACjE,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,YAAY;AACd;AASO,SAAS,gCACd,SACkB;AAqBlB,SAAO,OAAO,KAAK,SAAS,cAAc;AACxC,UAAM,UAAU,UAAU,OAAO,EAAE,KAAK,cAAYC,gBAAe,SAAS,OAAO,CAAC;AACpF,QAAI,YAAY,QAAW;AACzB,aAAO,QAAQ,oBAAoB,4CAA4C;AAAA,IACjF;AACA,UAAM,WAAW,QAAQ;AACzB,UAAM,MAAM,aAAa,QAAQ;AAEjC,UAAM,aAAa,MAAM,IAAI,QAAQ,cAAc,GAAG,GACnD,KAAK,eAAa,UAAU,SAAS,QAAQ,QAAQ;AACxD,QAAI,cAAc,QAAW;AAE3B,aAAO,QAAQ,iBAAiB,yDAAyD;AAAA,IAC3F;AAEA,UAAM,aAAyB;AAAA,MAC7B,gBAAgB,QAAQ;AAAA,MACxB,cAAc,SAAS;AAAA,MACvB,wBAAwB,UAAU;AAAA,MAClC,UAAU,QAAQ;AAAA,IACpB;AAEA,UAAM,eAAe,MAAM,IAAI,QAAQ,kBAAkB,GAAG;AAC5D,QAAI,iBAAiB,QAAW;AAC9B,UAAI,aAAa,kBAAkB,UAAU,gBAAgB;AAE3D,eAAO,QAAQ,oBAAoB,iFAAiF,EAAE,GAAG,YAAY,oBAAoB,aAAa,eAAe,CAAC;AAAA,MACxL;AAGA,aAAO,QAAQ,YAAY,yFAAyF,EAAE,GAAG,YAAY,oBAAoB,aAAa,eAAe,CAAC;AAAA,IACxL;AAEA,UAAM,YAAY,QAAQ,EAAE,SAAS,OAAO;AAC5C,QAAI,cAAc,QAAW;AAC3B,aAAO,QAAQ,iBAAiB,oDAAoD,SAAS,OAAO,KAAK,UAAU;AAAA,IACrH;AAEA,UAAM,WAAW;AAAA,MACf,GAAG;AAAA,MACH,gBAAgB,SAAS;AAAA,MACzB,YAAY,EAAE,uBAAuB,UAAU,eAAe;AAAA,IAChE;AACA,UAAM,iBAAiB,MAAM,gBAAgB,IAAI,WAAW,SAAS,QAAQ;AAC7E,QAAI,CAAC,eAAe,IAAI;AACtB,aAAO,eAAe,YAAY,OAC9B,QAAQ,iBAAiB,uDAAuD,eAAe,MAAM,IAAI,UAAU,IACnH,QAAQ,YAAY,+CAA+C,eAAe,MAAM,IAAI,UAAU;AAAA,IAC5G;AACA,UAAM,iBAAiB,MAAM,cAAc,UAAU,QAAQ;AAC7D,UAAM,eAA+B,eAAe,WAC/C,MAAM,UAAU,UAAU,UAAU,eAAe,MAAM;AAE9D,WAAO;AAAA,MACL,SAAS,aAAa,OAAO;AAAA,MAC7B,oCAAoC,aAAa,OAAO,MAAM,aAAa,MAAM;AAAA,MACjF;AAAA,QACE,GAAG;AAAA,QAAY,OAAO,aAAa;AAAA,QAAY,cAAc,aAAa;AAAA,MAC5E;AAAA,IACF;AAAA,EACF;AACF;;;AC3GA,SAAS,mBAAmB;AAE5B;AAAA,EACE,uBAAAC;AAAA,EAAqB;AAAA,EAAmB;AAAA,EAAuB;AAAA,OAC1D;AAYP,SAAS,SAAS,UAA6B;AAC7C,SAAO,SACJ,OAAO,aAAW,kBAAkB,OAAO,CAAC,EAC5C,OAAO,cAAY,SAAS,SAAS,gBAAgB,EACrD,OAAO,CAAC,OAAO,aACd,QAAQ,OAAO,OAAO,SAAS,SAAS,EAAE,OAAO,CAAC,KAAK,WAAW,MAAM,YAAY,MAAM,GAAG,EAAE,GAAG,EAAE;AAC1G;AAGA,eAAe,gBACb,KACA,aACA,cAC6B;AAC7B,MAAI,IAAI,OAAO,iBAAiB,WAAY,QAAO,sBAAsB,WAAoB;AAC7F,MAAI,iBAAiB,UAAa,IAAI,kBAAkB,OAAW,QAAO;AAC1E,SAAO,MAAM,IAAI,cAAc,YAAY;AAC7C;AAsBO,IAAM,uBAAyC,OAAO,KAAK,SAAS,cAAc;AACvF,QAAM,QAAQ,CAAC,GAAG,UAAU,OAAO,CAAC;AACpC,QAAM,QAAQ,MAAM,KAAK,cAAYC,qBAAoB,SAAS,OAAO,MAAM,MAAS;AACxF,QAAM,QAAQ,UAAU,SAAY,SAAYA,qBAAoB,MAAM,OAAO;AACjF,MAAI,UAAU,OAAW,QAAO,QAAQ,oBAAoB,oCAAoC;AAEhG,MAAI,MAAM,UAAU,QAAQ,OAAO;AAGjC,WAAO,QAAQ,oBAAoB,uDAAuD;AAAA,EAC5F;AACA,MAAI,CAAC,MAAM,UAAU,SAAS,QAAQ,OAAO,GAAG;AAE9C,WAAO,QAAQ,oBAAoB,0CAA0C;AAAA,EAC/E;AAEA,QAAM,WAAW,MAAM,OAAO,cAAY,aAAa,KAAK,EAAE,IAAI,cAAY,SAAS,OAAO;AAC9F,QAAM,SAAS,SAAS,QAAQ;AAEhC,QAAM,eAAe,MAAM,aAAa,OACpC,SACA,MAAM,IAAI,MAAM,kBAAmB,MAAM,QAAQ,CAAW;AAChE,QAAM,UAAU,MAAM,gBAAgB,KAAK,MAAM,OAAO,YAAY;AAEpE,QAAM,aAAyB;AAAA,IAC7B,SAAS,QAAQ;AAAA,IACjB,SAAS,YAAY,SAAY,OAAO,QAAQ,SAAS;AAAA,IACzD,OAAO,MAAM;AAAA,IACb,QAAQ,OAAO,SAAS;AAAA,IACxB,cAAc,gBAAgB;AAAA,IAC9B,cAAc,IAAI,OAAO;AAAA,EAC3B;AAEA,MAAI,YAAY,QAAW;AACzB,WAAO,QAAQ,iBAAiB,6DAA6D,UAAU;AAAA,EACzG;AACA,SAAO,SAAS,UACZ,QAAQ,YAAY,oBAAoB,MAAM,4BAA4B,OAAO,IAAI,UAAU,IAC/F,QAAQ,oBAAoB,oBAAoB,MAAM,6BAA6B,OAAO,IAAI,UAAU;AAC9G;;;ACzEO,IAAM,oBAAoE;AAAA,EAC/E,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,iBAAiB;AAAA,EACjB,yBAAyB,gCAAgC,MAAM,iBAAiB;AAAA,EAChF,mBAAmB;AACrB;AAiBA,eAAsB,cACpB,KACA,SACyB;AACzB,QAAM,YAAY,MAAM,gBAAgB,IAAI,WAAW,QAAQ,QAAQ;AACvE,MAAI,CAAC,UAAU,IAAI;AAEjB,WAAO,QAAQ,UAAU,YAAY,OAAO,kBAAkB,oBAAoB,UAAU,QAAQ,EAAE,OAAO,YAAY,CAAC;AAAA,EAC5H;AAEA,QAAM,YAAY,MAAM,cAAc,KAAK,OAAO;AAClD,MAAI,UAAU,YAAY,OAAW,QAAO,UAAU;AAEtD,QAAM,YAAY,kBAAkB,QAAQ,OAAO;AACnD,MAAI,cAAc,QAAW;AAC3B,WAAO,QAAQ,iBAAiB,kCAAkC,QAAQ,OAAO,KAAK,EAAE,gBAAgB,IAAI,gBAAgB,SAAS,QAAQ,QAAQ,CAAC;AAAA,EACxJ;AACA,QAAM,SAAS,MAAM,UAAU,KAAK,SAAS,UAAU,MAAM;AAC7D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY;AAAA,MACV,GAAG,OAAO;AAAA,MACV,MAAM,UAAU,QAAQ;AAAA,MACxB,MAAM,UAAU,QAAQ;AAAA,MACxB,SAAS,QAAQ;AAAA,IACnB;AAAA,EACF;AACF;",
|
|
6
|
+
"names": ["verdict", "PayloadBuilder", "asBlockBoundWitness", "PayloadBuilder", "asBlockBoundWitness", "isBoundWitness", "asBlockBoundWitness", "isBoundWitness", "asBlockBoundWitness", "asBlockBoundWitness", "isTimePayload", "isTimePayload", "asBlockBoundWitness", "asBlockBoundWitness", "asBlockBoundWitness", "isSlashRequest", "isSlashRequest", "asBlockBoundWitness", "asBlockBoundWitness"]
|
|
7
7
|
}
|
|
@@ -1017,10 +1017,12 @@ var RequiredBalanceBlockStateValidator = async (context, block) => {
|
|
|
1017
1017
|
)];
|
|
1018
1018
|
chainId = await context.chainIdAtBlockNumber(block[0].block);
|
|
1019
1019
|
await spanRootAsync("RequiredBalanceBlockStateValidator|balancesLoop", async () => {
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1020
|
+
const requiredAddresses = Object.keys(requiredBalances);
|
|
1021
|
+
if (requiredAddresses.length === 0) return;
|
|
1022
|
+
const balances = await context.accountBalance.accountBalances(requiredAddresses, { head: previous });
|
|
1023
|
+
for (const address of requiredAddresses) {
|
|
1024
|
+
const reqBalance = requiredBalances[address];
|
|
1025
|
+
const balance = balances[address] ?? AttoXL1(0n);
|
|
1024
1026
|
if (address !== XYO_ZERO_ADDRESS && reqBalance > balance) {
|
|
1025
1027
|
const offendingTransactionHashes = offendingTransactionHashesForAddress(block, address);
|
|
1026
1028
|
errors.push(new HydratedBlockStateValidationError(
|