@xyo-network/xl1-cli 5.0.2 → 5.0.3

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/cli-min.mjs CHANGED
@@ -66288,7 +66288,7 @@ config$1(en_default());
66288
66288
  //#region ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js
66289
66289
  var zod_default = external_exports;
66290
66290
  //#endregion
66291
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._3f4b5b54a1d81152ba0117a0986eb39a/node_modules/@xyo-network/xl1-protocol/dist/neutral/protocol-model.mjs
66291
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._0f96b9080457d2eebc7af32da5f3dc17/node_modules/@xyo-network/xl1-protocol/dist/neutral/protocol-model.mjs
66292
66292
  var ExchangeOutcomeSchema$1 = asSchema$1("network.xyo.exchange.outcome", true);
66293
66293
  var isExchangeOutcome$1 = isPayloadOfZodType$1(/* @__PURE__ */ object$5({
66294
66294
  /** Hash of the ExchangeTerms payload this outcome settles */
@@ -66739,6 +66739,57 @@ var asSignedHydratedBlockWithHashMeta$1 = zodAsFactory(SignedHydratedBlockWithHa
66739
66739
  var asSignedHydratedBlockWithStorageMeta$1 = zodAsFactory(/* @__PURE__ */ tuple$1([WithStorageMetaZod$1(SignedBlockBoundWitnessZod$1), /* @__PURE__ */ array$2(/* @__PURE__ */ looseObject$1(WithStorageMetaZod$1(PayloadZod$1).shape))]), "asSignedHydratedBlockWithStorageMeta");
66740
66740
  WithStorageMetaZod$1(SignedBlockBoundWitnessZod$1), WithStorageMetaZod$1(PayloadZod$1).shape;
66741
66741
  BlockBoundWitnessFieldsZod$1.shape, BlockBoundWitnessMetaZod$1.shape;
66742
+ var CandidatePairSchema$1 = asSchema$1("network.xyo.chain.evidence.candidate.pair", true);
66743
+ var isCandidatePair$1 = isPayloadOfZodType$1(/* @__PURE__ */ object$5({
66744
+ /** Chain both candidates were proposed on */
66745
+ chain: ChainIdZod$1,
66746
+ /** Block number both candidates claim */
66747
+ height: XL1BlockNumberZod$1,
66748
+ /** Address that signed both candidates */
66749
+ producer: XyoAddressZod$1,
66750
+ /** The two candidates' recomputed bound witness data hashes, sorted ascending */
66751
+ subjects: /* @__PURE__ */ tuple$1([HashZod, HashZod])
66752
+ }), CandidatePairSchema$1);
66753
+ AsObjectFactory.create(isCandidatePair$1);
66754
+ var CandidateSeenSchema$1 = asSchema$1("network.xyo.chain.evidence.candidate", true);
66755
+ var isCandidateSeen$1 = isPayloadOfZodType$1(/* @__PURE__ */ object$5({
66756
+ /** Chain the candidate was proposed on */
66757
+ chain: ChainIdZod$1,
66758
+ /** Block number the candidate claims */
66759
+ height: XL1BlockNumberZod$1,
66760
+ /** Parent hash the candidate builds on — absent only for a genesis candidate */
66761
+ previous: /* @__PURE__ */ optional$2(HashZod),
66762
+ /** Address that signed the candidate */
66763
+ producer: XyoAddressZod$1,
66764
+ /** Recomputed data hash of the candidate's bound witness */
66765
+ subject: HashZod
66766
+ }), CandidateSeenSchema$1);
66767
+ AsObjectFactory.create(isCandidateSeen$1);
66768
+ var EvidenceDispositionZod$1 = /* @__PURE__ */ literal$2([
66769
+ "expired",
66770
+ "finalized",
66771
+ "foreign",
66772
+ "invalid",
66773
+ "losing",
66774
+ "malformed",
66775
+ "superseded"
66776
+ ]);
66777
+ var EvidenceNoteSchema$1 = asSchema$1("network.xyo.chain.evidence.note", true);
66778
+ var isEvidenceNote$1 = isPayloadOfZodType$1(/* @__PURE__ */ object$5({
66779
+ /** Hash of the stored bundle payload this note describes */
66780
+ bundle: HashZod,
66781
+ /** Why the candidate left the pending pool */
66782
+ disposition: EvidenceDispositionZod$1,
66783
+ /** Block number of the archived candidate — absent when the bundle was malformed */
66784
+ height: /* @__PURE__ */ optional$2(XL1BlockNumberZod$1),
66785
+ /** Finalized head height when the entry was archived — the retention clock for entries with no height */
66786
+ observed: XL1BlockNumberZod$1,
66787
+ /** Producer of the archived candidate — absent when the bundle was malformed */
66788
+ producer: /* @__PURE__ */ optional$2(XyoAddressZod$1),
66789
+ /** Recomputed data hash of the archived block's bound witness — the artifact identity evidence references use */
66790
+ subject: HashZod
66791
+ }), EvidenceNoteSchema$1);
66792
+ AsObjectFactory.create(isEvidenceNote$1);
66742
66793
  var BlockNumberSchema$1 = asSchema$1("network.xyo.chain.block.number", true);
66743
66794
  var isBlockNumberPayload$1 = isPayloadOfSchemaType$1(BlockNumberSchema$1);
66744
66795
  var asBlockNumberPayload$1 = AsObjectFactory.create(isBlockNumberPayload$1);
@@ -66998,7 +67049,7 @@ var TransactionRejectionSchema$1 = asSchema$1("network.xyo.transaction.rejection
66998
67049
  var isTransactionRejection$1 = isPayloadOfSchemaType$1(TransactionRejectionSchema$1);
66999
67050
  AsObjectFactory.create(isTransactionRejection$1);
67000
67051
  //#endregion
67001
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._3f4b5b54a1d81152ba0117a0986eb39a/node_modules/@xyo-network/xl1-protocol/dist/neutral/protocol-lib.mjs
67052
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._0f96b9080457d2eebc7af32da5f3dc17/node_modules/@xyo-network/xl1-protocol/dist/neutral/protocol-lib.mjs
67002
67053
  function derivedReceiveAddress(address, scope) {
67003
67054
  return toAddress(keccak256(new TextEncoder().encode(isDefined$1(scope) ? `${scope}|${address}` : address)).slice(-40), { prefix: false });
67004
67055
  }
@@ -67024,6 +67075,7 @@ var BlockPublishRunnerMoniker = "BlockPublishRunner";
67024
67075
  var ChainStatePublishRunnerMoniker = "ChainStatePublishRunner";
67025
67076
  var DataLakePublishRunnerMoniker = "DataLakePublishRunner";
67026
67077
  var DeadLetterQueueRunnerMoniker$1 = "DeadLetterQueueRunner";
67078
+ var EvidenceStoreRunnerMoniker$1 = "EvidenceStoreRunner";
67027
67079
  var EvmEventIndexPublishRunnerMoniker = "EvmEventIndexPublishRunner";
67028
67080
  var FinalizationRunnerMoniker$1 = "FinalizationRunner";
67029
67081
  var IndexPublishRunnerMoniker = "IndexPublishRunner";
@@ -67173,6 +67225,11 @@ var ChainStateViewerMoniker = "ChainStateViewer";
67173
67225
  (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
67174
67226
  (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
67175
67227
  var DeadLetterQueueViewerMoniker = "DeadLetterQueueViewer";
67228
+ (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
67229
+ (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
67230
+ (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
67231
+ var EvidenceViewerMoniker$1 = "EvidenceViewer";
67232
+ var EvidenceProtectionViewerMoniker$1 = "EvidenceProtectionViewer";
67176
67233
  var EvmChainViewerMoniker$1 = "EvmChainViewer";
67177
67234
  var FinalizationViewerMoniker$1 = "FinalizationViewer";
67178
67235
  var IndexViewerMoniker$1 = "IndexViewer";
@@ -67197,6 +67254,8 @@ var NetworkStakeStepRewardViewerMoniker = "NetworkStakeStepRewardViewer";
67197
67254
  var StakeViewerMoniker$1 = "StakeViewer";
67198
67255
  var StakeRunnerMoniker = "StakeRunner";
67199
67256
  var StakeEventsViewerMoniker$1 = "StakeEventsViewer";
67257
+ var StakeIntentViewerMoniker$1 = "StakeIntentViewer";
67258
+ var StakeSnapshotViewerMoniker$1 = "StakeSnapshotViewer";
67200
67259
  var StakeTotalsViewerMoniker$1 = "StakeTotalsViewer";
67201
67260
  var StepViewerMoniker$1 = "StepViewer";
67202
67261
  var SyncViewerMoniker$1 = "SyncViewer";
@@ -67226,7 +67285,7 @@ var TransactionValidationViewerMoniker$1 = "TransactionValidationViewer";
67226
67285
  var WindowedBlockViewerMoniker$1 = "WindowedBlockViewer";
67227
67286
  var XyoViewerMoniker$1 = "XyoViewer";
67228
67287
  //#endregion
67229
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._3f4b5b54a1d81152ba0117a0986eb39a/node_modules/@xyo-network/xl1-protocol/dist/neutral/network-model.mjs
67288
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._0f96b9080457d2eebc7af32da5f3dc17/node_modules/@xyo-network/xl1-protocol/dist/neutral/network-model.mjs
67230
67289
  var local_default = "<svg id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\"><g style=\"opacity:.5;\"><path d=\"M154.71,97c.46,2.59,2.5,4.62,5.1,5.05l14.05,2.34,31.71-46.17c4.57-6.65-3.62-14.62-10.14-9.87l-43.68,31.83,2.97,16.82Z\" style=\"fill:#f47f00;\"/><path d=\"M173.86,151.62l-14.05,2.34c-2.6.43-4.64,2.45-5.1,5.05l-2.97,16.82,43.68,31.83c6.52,4.75,14.71-3.21,10.14-9.87l-31.71-46.17Z\" style=\"fill:#f47f00;\"/><path d=\"M82.14,104.38l14.05-2.34c2.6-.43,4.64-2.45,5.1-5.05l2.97-16.82-43.68-31.83c-6.52-4.75-14.71,3.21-10.14,9.87l31.71,46.17Z\" style=\"fill:#f47f00;\"/><path d=\"M101.29,159c-.46-2.59-2.5-4.62-5.1-5.05l-14.05-2.34-31.71,46.17c-4.57,6.65,3.62,14.62,10.14,9.87l43.68-31.83-2.97-16.82Z\" style=\"fill:#f47f00;\"/></g><path d=\"M107.33,104l15.94-90.32c.93-5.3,8.53-5.3,9.47,0l15.94,90.32c.35,2.01,1.94,3.57,3.95,3.91l92.24,15.35c5.36.89,5.36,8.59,0,9.49l-92.24,15.35c-2.01.33-3.59,1.9-3.95,3.91l-15.94,90.32c-.93,5.3-8.53,5.3-9.47,0l-15.94-90.32c-.35-2.01-1.94-3.57-3.95-3.91l-92.24-15.35c-5.36-.89-5.36-8.59,0-9.49l92.24-15.35c2.01-.33,3.59-1.9,3.95-3.91Z\" style=\"fill:#f47f00;\"/></svg>";
67231
67290
  var mainnet_default = "<svg id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\"><path d=\"M154.71,97c.46,2.59,2.5,4.62,5.1,5.05l14.05,2.34,31.71-46.17c4.57-6.65-3.62-14.62-10.14-9.87l-43.68,31.83,2.97,16.82Z\" style=\"fill:#8d8fc6;\"/><path d=\"M173.86,151.62l-14.05,2.34c-2.6.43-4.64,2.45-5.1,5.05l-2.97,16.82,43.68,31.83c6.52,4.75,14.71-3.21,10.14-9.87l-31.71-46.17Z\" style=\"fill:#eb407a;\"/><path d=\"M82.14,104.38l14.05-2.34c2.6-.43,4.64-2.45,5.1-5.05l2.97-16.82-43.68-31.83c-6.52-4.75-14.71,3.21-10.14,9.87l31.71,46.17Z\" style=\"fill:#579fd6;\"/><path d=\"M101.29,159c-.46-2.59-2.5-4.62-5.1-5.05l-14.05-2.34-31.71,46.17c-4.57,6.65,3.62,14.62,10.14,9.87l43.68-31.83-2.97-16.82Z\" style=\"fill:#f27046;\"/><path d=\"M107.33,104l15.94-90.32c.93-5.3,8.53-5.3,9.47,0l15.94,90.32c.35,2.01,1.94,3.57,3.95,3.91l92.24,15.35c5.36.89,5.36,8.59,0,9.49l-92.24,15.35c-2.01.33-3.59,1.9-3.95,3.91l-15.94,90.32c-.93,5.3-8.53,5.3-9.47,0l-15.94-90.32c-.35-2.01-1.94-3.57-3.95-3.91l-92.24-15.35c-5.36-.89-5.36-8.59,0-9.49l92.24-15.35c2.01-.33,3.59-1.9,3.95-3.91Z\" style=\"fill:#572aff;\"/></svg>";
67232
67291
  var testnet_default = "<svg id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\"><g style=\"opacity:.5;\"><path d=\"M154.71,97c.46,2.59,2.5,4.62,5.1,5.05l14.05,2.34,31.71-46.17c4.57-6.65-3.62-14.62-10.14-9.87l-43.68,31.83,2.97,16.82Z\" style=\"fill:#579fd6;\"/><path d=\"M173.86,151.62l-14.05,2.34c-2.6.43-4.64,2.45-5.1,5.05l-2.97,16.82,43.68,31.83c6.52,4.75,14.71-3.21,10.14-9.87l-31.71-46.17Z\" style=\"fill:#579fd6;\"/><path d=\"M82.14,104.38l14.05-2.34c2.6-.43,4.64-2.45,5.1-5.05l2.97-16.82-43.68-31.83c-6.52-4.75-14.71,3.21-10.14,9.87l31.71,46.17Z\" style=\"fill:#579fd6;\"/><path d=\"M101.29,159c-.46-2.59-2.5-4.62-5.1-5.05l-14.05-2.34-31.71,46.17c-4.57,6.65,3.62,14.62,10.14,9.87l43.68-31.83-2.97-16.82Z\" style=\"fill:#579fd6;\"/></g><path d=\"M107.33,104l15.94-90.32c.93-5.3,8.53-5.3,9.47,0l15.94,90.32c.35,2.01,1.94,3.57,3.95,3.91l92.24,15.35c5.36.89,5.36,8.59,0,9.49l-92.24,15.35c-2.01.33-3.59,1.9-3.95,3.91l-15.94,90.32c-.93,5.3-8.53,5.3-9.47,0l-15.94-90.32c-.35-2.01-1.94-3.57-3.95-3.91l-92.24-15.35c-5.36-.89-5.36-8.59,0-9.49l92.24-15.35c2.01-.33,3.59-1.9,3.95-3.91Z\" style=\"fill:#579fd6;\"/></svg>";
@@ -67616,7 +67675,7 @@ function networkStakeRewardsIndexStepPath(policyId, step) {
67616
67675
  return `${root2(policyId)}/steps/${step.step}/${step.block}.json`;
67617
67676
  }
67618
67677
  //#endregion
67619
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._3f4b5b54a1d81152ba0117a0986eb39a/node_modules/@xyo-network/xl1-protocol/dist/neutral/schema.mjs
67678
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._0f96b9080457d2eebc7af32da5f3dc17/node_modules/@xyo-network/xl1-protocol/dist/neutral/schema.mjs
67620
67679
  var asRequiredStrings = (required) => {
67621
67680
  if (typeof required === "string") return [required];
67622
67681
  if (!Array.isArray(required)) return [];
@@ -67852,7 +67911,7 @@ var TransferPayloadJsonSchema = {
67852
67911
  };
67853
67912
  var TransferPayloadJsonSchemaPayload = new PayloadBuilder$1({ schema: SchemaSchema$1 }).fields({ definition: TransferPayloadJsonSchema }).build();
67854
67913
  //#endregion
67855
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._3f4b5b54a1d81152ba0117a0986eb39a/node_modules/@xyo-network/xl1-protocol/dist/neutral/validation.mjs
67914
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._0f96b9080457d2eebc7af32da5f3dc17/node_modules/@xyo-network/xl1-protocol/dist/neutral/validation.mjs
67856
67915
  function maxTransactionFeeCost(tx) {
67857
67916
  const { base, gasLimit, priority } = tx.fees;
67858
67917
  return hexToBigInt(base) + hexToBigInt(priority) + hexToBigInt(gasLimit);
@@ -68098,7 +68157,7 @@ var validateTransaction = async (context, tx, additionalValidators) => {
68098
68157
  }
68099
68158
  };
68100
68159
  //#endregion
68101
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_f7cf1f859b51f67ea8ae31d8e591aa95/node_modules/@xyo-network/xl1-sdk/dist/neutral/driver-memory.mjs
68160
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_3d1fd2739949213d427b87ad651353a9/node_modules/@xyo-network/xl1-sdk/dist/neutral/driver-memory.mjs
68102
68161
  var LruCacheMap$1 = class {
68103
68162
  lruCache;
68104
68163
  /** Creates an instance with the supplied configuration. */
@@ -71282,7 +71341,7 @@ var require_ExplorerSync = /* @__PURE__ */ __commonJSMin(((exports) => {
71282
71341
  exports.ExplorerSync = ExplorerSync;
71283
71342
  }));
71284
71343
  //#endregion
71285
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_f7cf1f859b51f67ea8ae31d8e591aa95/node_modules/@xyo-network/xl1-sdk/dist/node/protocol-sdk.mjs
71344
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_3d1fd2739949213d427b87ad651353a9/node_modules/@xyo-network/xl1-sdk/dist/node/protocol-sdk.mjs
71286
71345
  var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
71287
71346
  Object.defineProperty(exports, "__esModule", { value: true });
71288
71347
  exports.defaultLoadersSync = exports.defaultLoaders = exports.globalConfigSearchPlacesSync = exports.globalConfigSearchPlaces = exports.getDefaultSearchPlacesSync = exports.getDefaultSearchPlaces = exports.cosmiconfigSync = exports.cosmiconfig = void 0;
@@ -71982,57 +72041,57 @@ async function stepRewardTotal(context, blockViewer, { block, step }, multiplier
71982
72041
  });
71983
72042
  }
71984
72043
  var XL1_NETWORK_STAKING_GENESIS_PERIOD_END_XL1_BLOCK$1 = 107496;
71985
- var functionName = "externalBlockNumberFromXL1BlockNumber";
71986
- var SCAN_CHUNK = 50;
71987
- var MIN_SCAN_CHUNK = 10;
71988
- var SCAN_CHUNK_RETRIES = 3;
71989
- var SCAN_CHUNK_RETRY_BASE_DELAY_MS = 100;
71990
- function retryDelayMs(attempt) {
71991
- return SCAN_CHUNK_RETRY_BASE_DELAY_MS * 2 ** attempt * (.5 + Math.random() / 2);
71992
- }
71993
- var EXTERNAL_TIME_CACHE_MAX = 25e4;
71994
- function externalTimeCache(context) {
71995
- return contextCache$1(context, "externalTimeAtBlock", () => new LruCacheMap$1({ max: EXTERNAL_TIME_CACHE_MAX }));
71996
- }
71997
- function externalTimeCacheKey(xl1Block, externalTimeName) {
72044
+ var functionName$1 = "externalBlockNumberFromXL1BlockNumber";
72045
+ var SCAN_CHUNK$1 = 50;
72046
+ var MIN_SCAN_CHUNK$1 = 10;
72047
+ var SCAN_CHUNK_RETRIES$1 = 3;
72048
+ var SCAN_CHUNK_RETRY_BASE_DELAY_MS$1 = 100;
72049
+ function retryDelayMs$1(attempt) {
72050
+ return SCAN_CHUNK_RETRY_BASE_DELAY_MS$1 * 2 ** attempt * (.5 + Math.random() / 2);
72051
+ }
72052
+ var EXTERNAL_TIME_CACHE_MAX$1 = 25e4;
72053
+ function externalTimeCache$1(context) {
72054
+ return contextCache$1(context, "externalTimeAtBlock", () => new LruCacheMap$1({ max: EXTERNAL_TIME_CACHE_MAX$1 }));
72055
+ }
72056
+ function externalTimeCacheKey$1(xl1Block, externalTimeName) {
71998
72057
  return `${xl1Block}-${externalTimeName}`;
71999
72058
  }
72000
- function externalTimeOfBlock(block, externalTimeName) {
72059
+ function externalTimeOfBlock$1(block, externalTimeName) {
72001
72060
  const [, payloads = []] = block;
72002
72061
  const time = (isArray(payloads) ? asTimePayload$1(payloads.find(isTimePayload$1)) : void 0)?.[externalTimeName];
72003
72062
  return time === 0 ? void 0 : time;
72004
72063
  }
72005
- async function externalTimeAtBlock(context, blockViewer, xl1Block, externalTimeName) {
72006
- const cache = externalTimeCache(context);
72007
- const cacheKey = externalTimeCacheKey(xl1Block, externalTimeName);
72064
+ async function externalTimeAtBlock$1(context, blockViewer, xl1Block, externalTimeName) {
72065
+ const cache = externalTimeCache$1(context);
72066
+ const cacheKey = externalTimeCacheKey$1(xl1Block, externalTimeName);
72008
72067
  const cached = await cache.get(cacheKey);
72009
72068
  if (isDefined$1(cached)) return cached;
72010
72069
  const block = await blockViewer.blockByNumber(asXL1BlockNumber$1(xl1Block, true));
72011
72070
  if (isUndefined$1(block) || block === null) return { exists: false };
72012
72071
  const result = {
72013
72072
  exists: true,
72014
- time: externalTimeOfBlock(block, externalTimeName)
72073
+ time: externalTimeOfBlock$1(block, externalTimeName)
72015
72074
  };
72016
72075
  await cache.set(cacheKey, result);
72017
72076
  return result;
72018
72077
  }
72019
- async function cacheChunkExternalTimes(cache, blocks, externalTimeName) {
72020
- const times = blocks.map((block) => [block[0].block, externalTimeOfBlock(block, externalTimeName)]);
72021
- for (const [blockNumber, time] of times) await cache.set(externalTimeCacheKey(blockNumber, externalTimeName), {
72078
+ async function cacheChunkExternalTimes$1(cache, blocks, externalTimeName) {
72079
+ const times = blocks.map((block) => [block[0].block, externalTimeOfBlock$1(block, externalTimeName)]);
72080
+ for (const [blockNumber, time] of times) await cache.set(externalTimeCacheKey$1(blockNumber, externalTimeName), {
72022
72081
  exists: true,
72023
72082
  time
72024
72083
  });
72025
72084
  return times;
72026
72085
  }
72027
- async function scanForAnchor(context, blockViewer, from, direction, maxScanBlocks, externalTimeName) {
72086
+ async function scanForAnchor$1(context, blockViewer, from, direction, maxScanBlocks, externalTimeName) {
72028
72087
  if (maxScanBlocks < 1) return { final: true };
72029
- const cache = externalTimeCache(context);
72030
- const chunker = new AdaptiveChunkFetcher(context, blockViewer, direction);
72031
- return direction === "backward" ? await scanBackward(cache, chunker, from, maxScanBlocks, externalTimeName) : await scanForward(cache, chunker, blockViewer, from, maxScanBlocks, externalTimeName);
72088
+ const cache = externalTimeCache$1(context);
72089
+ const chunker = new AdaptiveChunkFetcher$1(context, blockViewer, direction);
72090
+ return direction === "backward" ? await scanBackward$1(cache, chunker, from, maxScanBlocks, externalTimeName) : await scanForward$1(cache, chunker, blockViewer, from, maxScanBlocks, externalTimeName);
72032
72091
  }
72033
- var AdaptiveChunkFetcher = class {
72092
+ var AdaptiveChunkFetcher$1 = class {
72034
72093
  blockViewer;
72035
- chunk = SCAN_CHUNK;
72094
+ chunk = SCAN_CHUNK$1;
72036
72095
  context;
72037
72096
  direction;
72038
72097
  failedAtFloor = false;
@@ -72061,24 +72120,24 @@ var AdaptiveChunkFetcher = class {
72061
72120
  return await this.blockViewer.blocksByNumber(asXL1BlockNumber$1(endBlock, true), count);
72062
72121
  } catch (ex) {
72063
72122
  const message = ex.message;
72064
- if (attempt < SCAN_CHUNK_RETRIES) {
72065
- const delay2 = retryDelayMs(attempt);
72066
- this.context.logger?.warn(`[${functionName}] blocksByNumber(${endBlock}, ${count}) failed during ${this.direction} scan (attempt ${attempt + 1}/${SCAN_CHUNK_RETRIES + 1}, retrying in ${Math.round(delay2)}ms): ${message}`);
72123
+ if (attempt < SCAN_CHUNK_RETRIES$1) {
72124
+ const delay2 = retryDelayMs$1(attempt);
72125
+ this.context.logger?.warn(`[${functionName$1}] blocksByNumber(${endBlock}, ${count}) failed during ${this.direction} scan (attempt ${attempt + 1}/${SCAN_CHUNK_RETRIES$1 + 1}, retrying in ${Math.round(delay2)}ms): ${message}`);
72067
72126
  await new Promise((resolve) => setTimeout(resolve, delay2));
72068
72127
  continue;
72069
72128
  }
72070
- this.context.logger?.warn(`[${functionName}] blocksByNumber(${endBlock}, ${count}) failed during ${this.direction} scan after ${attempt + 1} attempts: ${message}`);
72071
- if (count <= MIN_SCAN_CHUNK) this.failedAtFloor = true;
72072
- else this.chunk = Math.max(MIN_SCAN_CHUNK, this.chunk >> 1);
72129
+ this.context.logger?.warn(`[${functionName$1}] blocksByNumber(${endBlock}, ${count}) failed during ${this.direction} scan after ${attempt + 1} attempts: ${message}`);
72130
+ if (count <= MIN_SCAN_CHUNK$1) this.failedAtFloor = true;
72131
+ else this.chunk = Math.max(MIN_SCAN_CHUNK$1, this.chunk >> 1);
72073
72132
  return;
72074
72133
  }
72075
72134
  }
72076
72135
  };
72077
- async function scanBackward(cache, chunker, from, maxScanBlocks, externalTimeName) {
72136
+ async function scanBackward$1(cache, chunker, from, maxScanBlocks, externalTimeName) {
72078
72137
  const floor = Math.max(0, from - maxScanBlocks);
72079
72138
  let cursor = from - 1;
72080
72139
  while (cursor >= floor) {
72081
- const cached = await cache.get(externalTimeCacheKey(cursor, externalTimeName));
72140
+ const cached = await cache.get(externalTimeCacheKey$1(cursor, externalTimeName));
72082
72141
  if (isDefined$1(cached)) {
72083
72142
  if (isDefined$1(cached.time)) return {
72084
72143
  anchor: cached.time,
@@ -72093,7 +72152,7 @@ async function scanBackward(cache, chunker, from, maxScanBlocks, externalTimeNam
72093
72152
  if (chunker.exhausted) return { final: false };
72094
72153
  continue;
72095
72154
  }
72096
- const hit = (await cacheChunkExternalTimes(cache, blocks, externalTimeName)).find(([, time]) => isDefined$1(time));
72155
+ const hit = (await cacheChunkExternalTimes$1(cache, blocks, externalTimeName)).find(([, time]) => isDefined$1(time));
72097
72156
  if (hit !== void 0 && isDefined$1(hit[1])) return {
72098
72157
  anchor: hit[1],
72099
72158
  final: true
@@ -72103,12 +72162,12 @@ async function scanBackward(cache, chunker, from, maxScanBlocks, externalTimeNam
72103
72162
  }
72104
72163
  return { final: true };
72105
72164
  }
72106
- async function scanForward(cache, chunker, blockViewer, from, maxScanBlocks, externalTimeName) {
72165
+ async function scanForward$1(cache, chunker, blockViewer, from, maxScanBlocks, externalTimeName) {
72107
72166
  const head = await blockViewer.currentBlockNumber();
72108
72167
  const ceiling = Math.min(from + maxScanBlocks, head);
72109
72168
  let windowStart = from + 1;
72110
72169
  while (windowStart <= ceiling) {
72111
- const cached = await cache.get(externalTimeCacheKey(windowStart, externalTimeName));
72170
+ const cached = await cache.get(externalTimeCacheKey$1(windowStart, externalTimeName));
72112
72171
  if (isDefined$1(cached)) {
72113
72172
  if (isDefined$1(cached.time)) return {
72114
72173
  anchor: cached.time,
@@ -72124,7 +72183,7 @@ async function scanForward(cache, chunker, blockViewer, from, maxScanBlocks, ext
72124
72183
  if (chunker.exhausted) return { final: false };
72125
72184
  continue;
72126
72185
  }
72127
- const hit = (await cacheChunkExternalTimes(cache, blocks, externalTimeName)).findLast(([, time]) => isDefined$1(time));
72186
+ const hit = (await cacheChunkExternalTimes$1(cache, blocks, externalTimeName)).findLast(([, time]) => isDefined$1(time));
72128
72187
  if (hit !== void 0 && isDefined$1(hit[1])) return {
72129
72188
  anchor: hit[1],
72130
72189
  final: true
@@ -72134,12 +72193,12 @@ async function scanForward(cache, chunker, blockViewer, from, maxScanBlocks, ext
72134
72193
  }
72135
72194
  return { final: from + maxScanBlocks <= head };
72136
72195
  }
72137
- async function scanBothDirections(context, blockViewer, xl1BlockNumber, direction, maxScanBlocks, externalTimeName) {
72196
+ async function scanBothDirections$1(context, blockViewer, xl1BlockNumber, direction, maxScanBlocks, externalTimeName) {
72138
72197
  let final = true;
72139
72198
  let backwardExhaustedAtGenesis = false;
72140
72199
  const directions = direction === "backward" ? ["backward", "forward"] : ["forward", "backward"];
72141
72200
  for (const scanDirection of directions) {
72142
- const scan = await scanForAnchor(context, blockViewer, xl1BlockNumber, scanDirection, maxScanBlocks, externalTimeName);
72201
+ const scan = await scanForAnchor$1(context, blockViewer, xl1BlockNumber, scanDirection, maxScanBlocks, externalTimeName);
72143
72202
  final = final && scan.final;
72144
72203
  if (isDefined$1(scan.anchor)) return {
72145
72204
  anchor: scan.anchor,
@@ -72148,7 +72207,7 @@ async function scanBothDirections(context, blockViewer, xl1BlockNumber, directio
72148
72207
  if (scanDirection === "backward" && scan.final && xl1BlockNumber <= maxScanBlocks) backwardExhaustedAtGenesis = true;
72149
72208
  }
72150
72209
  if (backwardExhaustedAtGenesis) {
72151
- const scan = await scanForAnchor(context, blockViewer, xl1BlockNumber, "forward", Number.POSITIVE_INFINITY, externalTimeName);
72210
+ const scan = await scanForAnchor$1(context, blockViewer, xl1BlockNumber, "forward", Number.POSITIVE_INFINITY, externalTimeName);
72152
72211
  return {
72153
72212
  anchor: scan.anchor,
72154
72213
  final: final && scan.final
@@ -72156,33 +72215,33 @@ async function scanBothDirections(context, blockViewer, xl1BlockNumber, directio
72156
72215
  }
72157
72216
  return { final };
72158
72217
  }
72159
- async function externalBlockNumberFromXL1BlockNumber(context, blockViewer, xl1BlockNumber, externalTimeName, direction = "backward", options) {
72218
+ async function externalBlockNumberFromXL1BlockNumber$1(context, blockViewer, xl1BlockNumber, externalTimeName, direction = "backward", options) {
72160
72219
  const externalGenesisTime = options?.externalGenesisTime ?? 23372716;
72161
72220
  const maxScanBlocks = options?.maxScanBlocks ?? 1e5;
72162
- const cache = contextCache$1(context, functionName);
72221
+ const cache = contextCache$1(context, functionName$1);
72163
72222
  const cacheKey = `${xl1BlockNumber}-${externalTimeName}-${direction}-${externalGenesisTime}-${maxScanBlocks}`;
72164
72223
  const cached = await cache.get(cacheKey);
72165
72224
  if (isDefined$1(cached)) return cached;
72166
72225
  let result;
72167
72226
  let final = true;
72168
- const own = await externalTimeAtBlock(context, blockViewer, xl1BlockNumber, externalTimeName);
72227
+ const own = await externalTimeAtBlock$1(context, blockViewer, xl1BlockNumber, externalTimeName);
72169
72228
  if (isDefined$1(own.time)) result = own.time;
72170
72229
  else {
72171
- const scan = await scanBothDirections(context, blockViewer, xl1BlockNumber, direction, maxScanBlocks, externalTimeName);
72230
+ const scan = await scanBothDirections$1(context, blockViewer, xl1BlockNumber, direction, maxScanBlocks, externalTimeName);
72172
72231
  final = own.exists && scan.final;
72173
72232
  result = scan.anchor;
72174
72233
  if (isUndefined$1(result)) {
72175
- context.logger?.warn(`[${functionName}] No ${externalTimeName} time anchor within ${maxScanBlocks} blocks of XL1 block ${xl1BlockNumber}; falling back to genesis time ${externalGenesisTime}`);
72234
+ context.logger?.warn(`[${functionName$1}] No ${externalTimeName} time anchor within ${maxScanBlocks} blocks of XL1 block ${xl1BlockNumber}; falling back to genesis time ${externalGenesisTime}`);
72176
72235
  result = externalGenesisTime;
72177
72236
  }
72178
72237
  }
72179
- const blockNumber = asBlockNumber$1(result, { name: functionName });
72238
+ const blockNumber = asBlockNumber$1(result, { name: functionName$1 });
72180
72239
  if (final) await cache.set(cacheKey, blockNumber);
72181
72240
  return blockNumber;
72182
72241
  }
72183
72242
  async function externalBlockRangeFromXL1BlockRange(context, blockViewer, xl1BlockRange, externalTimeName = "ethereum", options) {
72184
- const start = await externalBlockNumberFromXL1BlockNumber(context, blockViewer, xl1BlockRange[0], externalTimeName, "backward", options);
72185
- const end = await externalBlockNumberFromXL1BlockNumber(context, blockViewer, xl1BlockRange[1], externalTimeName, "forward", options);
72243
+ const start = await externalBlockNumberFromXL1BlockNumber$1(context, blockViewer, xl1BlockRange[0], externalTimeName, "backward", options);
72244
+ const end = await externalBlockNumberFromXL1BlockNumber$1(context, blockViewer, xl1BlockRange[1], externalTimeName, "forward", options);
72186
72245
  return end < start ? [start, start] : [start, end];
72187
72246
  }
72188
72247
  async function externalBlockRangeFromStep(context, blockViewer, stepIdentity, options) {
@@ -72400,6 +72459,21 @@ async function allStakersForRange(chain, externalRange, staked) {
72400
72459
  async function allStakersForStep(context, blockViewer, stakeEventsViewer, stepContext, staked, timeAnchor) {
72401
72460
  return await allStakersForRange(stakeEventsViewer, await externalBlockRangeFromXL1BlockRange(context, blockViewer, stepBlockRange(stepContext), "ethereum", timeAnchor), staked);
72402
72461
  }
72462
+ function isPositionActiveAt$1(position, at) {
72463
+ return position.addBlock <= at && (position.removeBlock === 0 || position.removeBlock > at);
72464
+ }
72465
+ function isPositionAtRiskAt$1(position, at) {
72466
+ return position.addBlock <= at && (position.withdrawBlock === 0 || position.withdrawBlock > at);
72467
+ }
72468
+ function isPositionSeasonedAt$1(position, at, minAge) {
72469
+ return isPositionActiveAt$1(position, at) && position.addBlock <= at - minAge;
72470
+ }
72471
+ function isSelfBond$1(position, address) {
72472
+ return position.staker === address && position.staked === address;
72473
+ }
72474
+ function sumPositions$1(positions, predicate) {
72475
+ return positions.reduce((total, position) => predicate(position) ? total + position.amount : total, 0n);
72476
+ }
72403
72477
  function weightedStakeForRangeFromEvents(events, externalRange, staked) {
72404
72478
  if (isDefined$1(staked) && events.at(0)?.args.staked !== staked) return 0n;
72405
72479
  let currentTime = externalRange[0];
@@ -72786,11 +72860,33 @@ var PENDING_TRANSACTIONS_ARCHIVIST_ROLE$1 = "pending-transactions";
72786
72860
  var PENDING_BLOCKS_ARCHIVIST_ROLE$1 = "pending-blocks";
72787
72861
  var REJECTED_BLOCKS_ARCHIVIST_ROLE = "rejected-blocks";
72788
72862
  var REJECTED_TRANSACTIONS_ARCHIVIST_ROLE = "rejected-transactions";
72863
+ var EVIDENCE_ARCHIVIST_ROLE$1 = "evidence";
72789
72864
  async function connectArchivist$1(binding, options) {
72790
72865
  const factory = getArchivistFactory$1(binding.config.type);
72791
72866
  if (factory === void 0) throw new Error(`connectArchivist: no archivist factory registered for connection type '${binding.config.type}'`);
72792
72867
  return await factory.connect(binding.name, binding.config, options);
72793
72868
  }
72869
+ async function signBoundWitness(bw, account) {
72870
+ const unsigned = structuredClone(bw);
72871
+ unsigned.addresses = [account.address];
72872
+ unsigned.previous_hashes = [account.previousHash ?? null];
72873
+ const hash = await PayloadBuilder$1.dataHash(unsigned);
72874
+ const [signature] = await account.sign(toArrayBuffer(hash));
72875
+ return {
72876
+ ...unsigned,
72877
+ $signatures: [hexFromArrayBuffer(signature)]
72878
+ };
72879
+ }
72880
+ async function buildUnsignedBoundWitness(payloads) {
72881
+ const [boundWitness, builtPayloads] = await new BoundWitnessBuilder$1().meta({ $signatures: [] }).payloads(payloads).build(false);
72882
+ return [boundWitness, builtPayloads];
72883
+ }
72884
+ async function buildSignedBlockRejection(rejection, account) {
72885
+ assertEx$1(rejection.rejector === account.address, () => "Rejector does not match the signing account address");
72886
+ const [unsigned] = await buildUnsignedBoundWitness([rejection]);
72887
+ const signed = await signBoundWitness(unsigned, account);
72888
+ return [await PayloadBuilder$1.addHashMeta(signed), [await PayloadBuilder$1.addHashMeta(rejection)]];
72889
+ }
72794
72890
  var CapabilityRegistry = class {
72795
72891
  _entries = /* @__PURE__ */ new Map();
72796
72892
  get(id) {
@@ -73419,17 +73515,6 @@ function transactionRequiredGas(hydratedTransaction) {
73419
73515
  const signatures = hydratedTransaction[0].addresses.length;
73420
73516
  return AttoXL1$1(transactionBytesRequiredGas(hydratedTransaction) + TransactionGasCosts.hashValidation * BigInt(hashes) + TransactionGasCosts.signatureValidation * BigInt(signatures) + TransactionGasCosts.payloadValidation * BigInt(elevatedPayloads.length));
73421
73517
  }
73422
- async function signBoundWitness(bw, account) {
73423
- const unsigned = structuredClone(bw);
73424
- unsigned.addresses = [account.address];
73425
- unsigned.previous_hashes = [account.previousHash ?? null];
73426
- const hash = await PayloadBuilder$1.dataHash(unsigned);
73427
- const [signature] = await account.sign(toArrayBuffer(hash));
73428
- return {
73429
- ...unsigned,
73430
- $signatures: [hexFromArrayBuffer(signature)]
73431
- };
73432
- }
73433
73518
  async function buildXl1Transaction(viewer, signer, onChain, offChain, options = {}) {
73434
73519
  const [chainId, nbf, signerAddress] = await Promise.all([
73435
73520
  viewer.chainId(),
@@ -73768,8 +73853,8 @@ AsObjectFactory.create(isEIP712SignaturePayload$1);
73768
73853
  var verifyEIP712Message = async (data, sig) => {
73769
73854
  const { address, signature, hash } = sig;
73770
73855
  const { schema, ...fields } = data;
73771
- const signedHash = asHash(hash);
73772
- if (isUndefined$1(signedHash) || signedHash !== await PayloadBuilder$1.hash(data)) return false;
73856
+ const signedHash2 = asHash(hash);
73857
+ if (isUndefined$1(signedHash2) || signedHash2 !== await PayloadBuilder$1.hash(data)) return false;
73773
73858
  return verifyTypedData(fields.domain, fields.types, fields.values, signature).toLowerCase() === address.toLowerCase();
73774
73859
  };
73775
73860
  asAttoXL1$1(1343884111859145740576652n) + asAttoXL1$1(100000000000000000000000000n);
@@ -75039,6 +75124,285 @@ __publicField$25(SimpleDataLakeViewer$1, "monikers", [DataLakeViewerMoniker$1]);
75039
75124
  /** Read, write, or mixed capability surface exposed by the provider. */
75040
75125
  __publicField$25(SimpleDataLakeViewer$1, "surface", "node");
75041
75126
  SimpleDataLakeViewer$1 = __decorateClass$26([creatableProvider$1()], SimpleDataLakeViewer$1);
75127
+ function isRetentionExpired$1(subject, clock, params) {
75128
+ const { observedHeight, subjectAnchor, subjectHeight } = subject;
75129
+ const { headAnchor, headHeight } = clock;
75130
+ const { challengeWindowEvmBlocks, evidenceFreshnessEvmBlocks, evidenceRetentionXl1Blocks } = params;
75131
+ const floorExceeded = headHeight - (subjectHeight ?? observedHeight) > evidenceRetentionXl1Blocks;
75132
+ const anchorExceeded = headAnchor - subjectAnchor > evidenceFreshnessEvmBlocks + challengeWindowEvmBlocks;
75133
+ return floorExceeded && anchorExceeded;
75134
+ }
75135
+ var SimpleEvidenceStoreRunnerOptionsZod$1 = object$3({
75136
+ /** How far back the in-memory candidate index tracks heights, in XL1 blocks. */
75137
+ candidatePairLookbackXl1Blocks: number$1().default(1440),
75138
+ /** Challenge window, in EVM blocks. */
75139
+ challengeWindowEvmBlocks: number$1().default(14400),
75140
+ /** Evidence freshness window, in EVM blocks. */
75141
+ evidenceFreshnessEvmBlocks: number$1().default(21600),
75142
+ /** Operational retention floor, in XL1 blocks. */
75143
+ evidenceRetentionXl1Blocks: number$1().default(6e4)
75144
+ });
75145
+ var SimpleEvidenceStoreRunner$1 = class extends AbstractCreatableProvider$1 {
75146
+ /** Moniker implemented by this provider instance. */
75147
+ moniker = SimpleEvidenceStoreRunner$1.defaultMoniker;
75148
+ _blockViewer;
75149
+ _finalizationViewer;
75150
+ _protectionViewer;
75151
+ _archivist;
75152
+ _options;
75153
+ /**
75154
+ * Signed-hash sets keyed by `producer|height`. Only the ingest edge feeds this, so it is a
75155
+ * detection aid rather than the authoritative index — the durable candidate records in the
75156
+ * store are what a full scan reads.
75157
+ */
75158
+ _seen = /* @__PURE__ */ new Map();
75159
+ get archivist() {
75160
+ return assertEx$1(this._archivist, () => "evidence archivist not initialized — bind a connection");
75161
+ }
75162
+ get blockViewer() {
75163
+ return this._blockViewer;
75164
+ }
75165
+ get finalizationViewer() {
75166
+ return this._finalizationViewer;
75167
+ }
75168
+ get options() {
75169
+ this._options ??= SimpleEvidenceStoreRunnerOptionsZod$1.parse(this.config.options);
75170
+ return this._options;
75171
+ }
75172
+ /** Archives pruned candidates with their dispositions, returning the stored hashes. */
75173
+ async archiveCandidates(entries) {
75174
+ if (entries.length === 0) return [];
75175
+ const observed = await this.finalizationViewer.headNumber();
75176
+ const payloads = [];
75177
+ for (const entry of entries) {
75178
+ const boundWitness = entry.block?.[0];
75179
+ payloads.push(entry.bundle, await PayloadBuilder$1.addHashMeta({
75180
+ bundle: entry.bundle._hash,
75181
+ disposition: entry.disposition,
75182
+ height: boundWitness?.block,
75183
+ observed,
75184
+ producer: boundWitness?.addresses[0],
75185
+ schema: EvidenceNoteSchema$1,
75186
+ subject: boundWitness === void 0 ? entry.bundle._hash : await signedHash$1(boundWitness)
75187
+ }));
75188
+ }
75189
+ return (await this.archivist.insert(payloads)).filter(isHashMeta$1).map((payload) => payload._hash);
75190
+ }
75191
+ /** Creates the provider instance after its dependencies and configuration have resolved. */
75192
+ async createHandler() {
75193
+ await super.createHandler();
75194
+ const connection = SimpleEvidenceStoreRunner$1.requireBoundConnection(this.config);
75195
+ this._archivist = await connectArchivist$1(connection, { name: EVIDENCE_ARCHIVIST_ROLE$1 });
75196
+ this._blockViewer = await this.locator.getInstance(BlockViewerMoniker$1);
75197
+ this._finalizationViewer = await this.locator.getInstance(FinalizationViewerMoniker$1);
75198
+ this._protectionViewer = await this.locator.tryGetInstance(EvidenceProtectionViewerMoniker$1);
75199
+ }
75200
+ /**
75201
+ * Records observed candidates in the signed-hash index, returning any same-height pairs newly
75202
+ * detected by this call.
75203
+ *
75204
+ * Identity is the signed data hash, never the stored hash: client metadata such as the block
75205
+ * timestamp sits outside the signature, so two artifacts differing only there are one
75206
+ * candidate and must collapse to a single entry.
75207
+ */
75208
+ async noteCandidates(blocks) {
75209
+ if (blocks.length === 0) return [];
75210
+ const detected = [];
75211
+ const payloads = [];
75212
+ for (const block of blocks) {
75213
+ const boundWitness = block[0];
75214
+ const producer = boundWitness.addresses[0];
75215
+ if (producer === void 0) continue;
75216
+ const height = boundWitness.block;
75217
+ const subject = await signedHash$1(boundWitness);
75218
+ payloads.push(await PayloadBuilder$1.addHashMeta({
75219
+ chain: boundWitness.chain,
75220
+ height,
75221
+ previous: boundWitness.previous ?? void 0,
75222
+ producer,
75223
+ schema: CandidateSeenSchema$1,
75224
+ subject
75225
+ }));
75226
+ const key = `${producer}|${height}`;
75227
+ const known = this._seen.get(key) ?? /* @__PURE__ */ new Set();
75228
+ if (!known.has(subject)) {
75229
+ for (const other of known) {
75230
+ const subjects = other < subject ? [other, subject] : [subject, other];
75231
+ detected.push({
75232
+ chain: boundWitness.chain,
75233
+ height,
75234
+ producer,
75235
+ subjects
75236
+ });
75237
+ payloads.push(await PayloadBuilder$1.addHashMeta({
75238
+ chain: boundWitness.chain,
75239
+ height,
75240
+ producer,
75241
+ schema: CandidatePairSchema$1,
75242
+ subjects
75243
+ }));
75244
+ }
75245
+ known.add(subject);
75246
+ this._seen.set(key, known);
75247
+ }
75248
+ }
75249
+ if (payloads.length > 0) await this.archivist.insert(payloads);
75250
+ await this.evictStaleKeys();
75251
+ return detected;
75252
+ }
75253
+ /**
75254
+ * Removes evidence whose retention has expired on both clocks, skipping anything a pending
75255
+ * report still references. Returns `[pruned, checked]`.
75256
+ *
75257
+ * Notes drive the sweep: each one names the bundle it describes, so an expired note takes its
75258
+ * bundle with it. Anything a protection viewer still claims is left alone regardless of age —
75259
+ * retention deliberately loses to reference protection, since pruning evidence out from under
75260
+ * an open report would destroy the case it rests on.
75261
+ */
75262
+ async pruneEvidence({ batchSize = 100, maxPrune = 5e3, maxCheck = 1e4 } = {}) {
75263
+ const headNumber = await this.finalizationViewer.headNumber();
75264
+ const headAnchor = await this.anchorFor(headNumber);
75265
+ const protectedSubjects = new Set(await this._protectionViewer?.protectedSubjectHashes());
75266
+ const { challengeWindowEvmBlocks, evidenceFreshnessEvmBlocks, evidenceRetentionXl1Blocks } = this.options;
75267
+ const params = {
75268
+ challengeWindowEvmBlocks,
75269
+ evidenceFreshnessEvmBlocks,
75270
+ evidenceRetentionXl1Blocks
75271
+ };
75272
+ let checked = 0;
75273
+ let pruned = 0;
75274
+ let cursor;
75275
+ let batch = await this.archivist.next({
75276
+ limit: batchSize,
75277
+ cursor,
75278
+ order: "asc"
75279
+ });
75280
+ while (batch.length > 0 && pruned < maxPrune && checked < maxCheck) {
75281
+ const expired = [];
75282
+ for (const payload of batch) {
75283
+ if (!isEvidenceNote$1(payload) || !isHashMeta$1(payload)) continue;
75284
+ checked++;
75285
+ if (protectedSubjects.has(payload.subject)) continue;
75286
+ const subjectHeight = payload.height;
75287
+ const subjectAnchor = await this.anchorFor(asXL1BlockNumber$1(subjectHeight ?? payload.observed, true));
75288
+ if (isRetentionExpired$1({
75289
+ observedHeight: payload.observed,
75290
+ subjectAnchor,
75291
+ subjectHeight
75292
+ }, {
75293
+ headAnchor,
75294
+ headHeight: headNumber
75295
+ }, params)) expired.push(payload._hash, payload.bundle);
75296
+ }
75297
+ if (expired.length > 0) {
75298
+ await this.archivist.delete(expired);
75299
+ pruned += expired.length;
75300
+ }
75301
+ const last = batch.at(-1);
75302
+ cursor = isHashMeta$1(last) ? last._sequence : cursor;
75303
+ if (cursor === void 0) break;
75304
+ batch = await this.archivist.next({
75305
+ limit: batchSize,
75306
+ cursor,
75307
+ order: "asc"
75308
+ });
75309
+ }
75310
+ return [pruned, checked];
75311
+ }
75312
+ /** Stores an observer-signed rejection record. */
75313
+ async recordRejection(record) {
75314
+ const [boundWitness, payloads] = record;
75315
+ return (await this.archivist.insert([boundWitness, ...payloads])).length > 0;
75316
+ }
75317
+ /** Resolves the EVM anchor for an XL1 height, tolerating gaps in the anchor history. */
75318
+ async anchorFor(height) {
75319
+ return await externalBlockNumberFromXL1BlockNumber$1(this.context, this.blockViewer, height, "ethereum", "backward");
75320
+ }
75321
+ /** Drops index keys for heights the lookback window no longer covers. */
75322
+ async evictStaleKeys() {
75323
+ const floor = await this.finalizationViewer.headNumber() - this.options.candidatePairLookbackXl1Blocks;
75324
+ if (floor <= 0) return;
75325
+ for (const key of this._seen.keys()) {
75326
+ const height = Number(key.split("|", 2)[1]);
75327
+ if (Number.isFinite(height) && height <= floor) this._seen.delete(key);
75328
+ }
75329
+ }
75330
+ };
75331
+ /** Connection kinds supported by this provider. */
75332
+ __publicField$25(SimpleEvidenceStoreRunner$1, "connectionTypes", [
75333
+ "lmdb",
75334
+ "mongo",
75335
+ "memory"
75336
+ ]);
75337
+ /** Primary moniker used to resolve this provider. */
75338
+ __publicField$25(SimpleEvidenceStoreRunner$1, "defaultMoniker", EvidenceStoreRunnerMoniker$1);
75339
+ /** Provider monikers that must resolve before this provider can be created. */
75340
+ __publicField$25(SimpleEvidenceStoreRunner$1, "dependencies", [FinalizationViewerMoniker$1, BlockViewerMoniker$1]);
75341
+ /** Provider monikers implemented by this provider class. */
75342
+ __publicField$25(SimpleEvidenceStoreRunner$1, "monikers", [EvidenceStoreRunnerMoniker$1]);
75343
+ /** Read, write, or mixed capability surface exposed by the provider. */
75344
+ __publicField$25(SimpleEvidenceStoreRunner$1, "surface", "node");
75345
+ SimpleEvidenceStoreRunner$1 = __decorateClass$26([creatableProvider$1()], SimpleEvidenceStoreRunner$1);
75346
+ async function signedHash$1(boundWitness) {
75347
+ return boundWitness._dataHash ?? await PayloadBuilder$1.dataHash(boundWitness);
75348
+ }
75349
+ var SimpleEvidenceViewer$1 = class extends AbstractCreatableProvider$1 {
75350
+ /** Moniker implemented by this provider instance. */
75351
+ moniker = SimpleEvidenceViewer$1.defaultMoniker;
75352
+ _archivist;
75353
+ get archivist() {
75354
+ return assertEx$1(this._archivist, () => "evidence archivist not initialized — bind a connection");
75355
+ }
75356
+ /** Reads recorded same-height candidate pairs — the equivocation detection feed. */
75357
+ async candidatePairs({ cursor, limit = 100, producer } = {}) {
75358
+ const pairs = (await this.page(cursor, limit)).filter((payload) => isCandidatePair$1(payload));
75359
+ return producer === void 0 ? pairs : pairs.filter((pair) => pair.producer === producer);
75360
+ }
75361
+ /** Creates the provider instance after its dependencies and configuration have resolved. */
75362
+ async createHandler() {
75363
+ await super.createHandler();
75364
+ const connection = SimpleEvidenceViewer$1.requireBoundConnection(this.config);
75365
+ this._archivist = await connectArchivist$1(connection, { name: EVIDENCE_ARCHIVIST_ROLE$1 });
75366
+ }
75367
+ /** Reads raw evidence entries, optionally filtered by schema. */
75368
+ async entries({ cursor, limit = 100, schema } = {}) {
75369
+ const payloads = await this.page(cursor, limit);
75370
+ return schema === void 0 ? payloads : payloads.filter((payload) => payload.schema === schema);
75371
+ }
75372
+ /** Reads observer-signed rejection records. */
75373
+ async rejections({ cursor, limit = 100, rejector } = {}) {
75374
+ const rejections = (await this.page(cursor, limit)).filter((payload) => isBlockRejection$1(payload));
75375
+ return rejector === void 0 ? rejections : rejections.filter((rejection) => rejection.rejector === rejector);
75376
+ }
75377
+ /** Reads one page of the store, newest first, resolving a hash cursor to its sequence. */
75378
+ async page(cursorHash, limit) {
75379
+ let cursor;
75380
+ if (isHash(cursorHash)) {
75381
+ const [payload] = await this.archivist.get([cursorHash]);
75382
+ if (isDefined$1(payload)) cursor = payload._sequence;
75383
+ }
75384
+ return (await this.archivist.next({
75385
+ order: "desc",
75386
+ limit,
75387
+ cursor
75388
+ })).filter(isHashMeta$1);
75389
+ }
75390
+ };
75391
+ /** Connection kinds supported by this provider. */
75392
+ __publicField$25(SimpleEvidenceViewer$1, "connectionTypes", [
75393
+ "lmdb",
75394
+ "mongo",
75395
+ "memory"
75396
+ ]);
75397
+ /** Primary moniker used to resolve this provider. */
75398
+ __publicField$25(SimpleEvidenceViewer$1, "defaultMoniker", EvidenceViewerMoniker$1);
75399
+ /** Provider monikers that must resolve before this provider can be created. */
75400
+ __publicField$25(SimpleEvidenceViewer$1, "dependencies", []);
75401
+ /** Provider monikers implemented by this provider class. */
75402
+ __publicField$25(SimpleEvidenceViewer$1, "monikers", [EvidenceViewerMoniker$1]);
75403
+ /** Read, write, or mixed capability surface exposed by the provider. */
75404
+ __publicField$25(SimpleEvidenceViewer$1, "surface", "node");
75405
+ SimpleEvidenceViewer$1 = __decorateClass$26([creatableProvider$1()], SimpleEvidenceViewer$1);
75042
75406
  function ethProviderFromEvmRpcConnection$1(connection) {
75043
75407
  const provider = isDefined$1(connection.chainId) ? new JsonRpcProvider(connection.url, Number(connection.chainId), {
75044
75408
  polling: true,
@@ -75375,6 +75739,44 @@ __publicField$25(SimpleIndexViewer$1, "dependencies", [BlockViewerMoniker$1]);
75375
75739
  /** Provider monikers implemented by this provider class. */
75376
75740
  __publicField$25(SimpleIndexViewer$1, "monikers", [IndexViewerMoniker$1]);
75377
75741
  SimpleIndexViewer$1 = __decorateClass$26([creatableProvider$1()], SimpleIndexViewer$1);
75742
+ async function classifyPrunedCandidate$1(bundle3, context) {
75743
+ const block = isPayloadBundle$1(bundle3) ? await bundledPayloadToHydratedBlock$1(bundle3) : void 0;
75744
+ if (block === void 0 || !isSignedHydratedBlockWithHashMeta$1(block)) return {
75745
+ bundle: bundle3,
75746
+ disposition: "malformed"
75747
+ };
75748
+ if (block[0].chain !== context.chainId) return {
75749
+ block,
75750
+ bundle: bundle3,
75751
+ disposition: "foreign"
75752
+ };
75753
+ if (block[0].block > context.headNumber) return {
75754
+ block,
75755
+ bundle: bundle3,
75756
+ disposition: "invalid"
75757
+ };
75758
+ const [canonical] = await context.blockViewer?.blocksByNumber(block[0].block, 1) ?? [];
75759
+ return {
75760
+ block,
75761
+ bundle: bundle3,
75762
+ disposition: canonical !== void 0 && canonical[0]._dataHash === block[0]._dataHash ? "finalized" : "losing"
75763
+ };
75764
+ }
75765
+ async function noteSubmittedCandidates$1(blocks, evidence) {
75766
+ if (evidence === void 0) return;
75767
+ const hydrated = await Promise.all(blocks.map(async ([boundWitness, payloads]) => [await PayloadBuilder$1.addHashMeta(boundWitness), await PayloadBuilder$1.addHashMeta(payloads)]));
75768
+ await evidence.noteCandidates(hydrated);
75769
+ }
75770
+ async function archivePrunedCandidates$1(bundles, context, logger) {
75771
+ try {
75772
+ const entries = await Promise.all(bundles.map(async (bundle3) => await classifyPrunedCandidate$1(bundle3, context)));
75773
+ await context.evidence.archiveCandidates(entries);
75774
+ return true;
75775
+ } catch (error) {
75776
+ logger?.error(`[SimpleMempoolRunner] evidence archive failed: ${String(error)}`);
75777
+ return false;
75778
+ }
75779
+ }
75378
75780
  async function resolvePendingStores$1(connection) {
75379
75781
  return {
75380
75782
  pendingBlocksArchivist: await connectArchivist$1(connection, { name: PENDING_BLOCKS_ARCHIVIST_ROLE$1 }),
@@ -75436,6 +75838,13 @@ var SimpleMempoolRunnerOptionsZod$1 = object$3({
75436
75838
  maxPendingTransactions: number$1().default(0),
75437
75839
  /** Interval between synchronization passes, in milliseconds. */
75438
75840
  syncInterval: number$1().default(DEFAULT_SYNC_INTERVAL$1),
75841
+ /**
75842
+ * When true (default), a pruned candidate block is archived to the evidence store before it is
75843
+ * deleted, and the delete is skipped when that write cannot happen. Deleting a candidate
75844
+ * without recording it destroys the only copy of a producer-signed artifact, so the pool is
75845
+ * allowed to grow rather than lose evidence. Set false to restore delete-only behavior.
75846
+ */
75847
+ retainPrunedBlocks: boolean$1().default(true),
75439
75848
  /** Maximum number of remote transactions imported by one synchronization pass. */
75440
75849
  syncLimit: number$1().default(DEFAULT_SYNC_LIMIT$1),
75441
75850
  /**
@@ -75454,8 +75863,10 @@ var SimpleMempoolRunner$1 = class extends AbstractCreatableProvider$1 {
75454
75863
  /** Moniker implemented by this provider instance. */
75455
75864
  moniker = SimpleMempoolRunner$1.defaultMoniker;
75456
75865
  _blockValidationViewer;
75866
+ _blockViewer;
75457
75867
  _chainContractViewer;
75458
75868
  _deadLetterQueueRunner;
75869
+ _evidenceStoreRunner;
75459
75870
  _finalizationViewer;
75460
75871
  _mempoolViewer;
75461
75872
  _transactionValidationViewer;
@@ -75517,6 +75928,8 @@ var SimpleMempoolRunner$1 = class extends AbstractCreatableProvider$1 {
75517
75928
  this._transactionValidationViewer = await this.locator.getInstance(TransactionValidationViewerMoniker$1);
75518
75929
  this._deadLetterQueueRunner = await this.locator.tryGetInstance(DeadLetterQueueRunnerMoniker$1);
75519
75930
  this._mempoolViewer = await this.locator.tryGetInstance(MempoolViewerMoniker$1);
75931
+ this._evidenceStoreRunner = await this.locator.tryGetInstance(EvidenceStoreRunnerMoniker$1);
75932
+ this._blockViewer = await this.locator.tryGetInstance(BlockViewerMoniker$1);
75520
75933
  }
75521
75934
  /** Removes pending blocks that are finalized, expired, or otherwise no longer eligible. */
75522
75935
  async prunePendingBlocks({ batchSize = 10, maxPrune = 1e3, maxCheck = 1e3 } = {}) {
@@ -75557,12 +75970,8 @@ var SimpleMempoolRunner$1 = class extends AbstractCreatableProvider$1 {
75557
75970
  }
75558
75971
  });
75559
75972
  const pruneHashes = invalidBundleHashes$1(bundles, valid);
75560
- pruned += pruneHashes.length;
75561
75973
  total += batch.length;
75562
- if (pruneHashes.length > 0) {
75563
- await this.pendingBlocksArchivist.delete(pruneHashes);
75564
- this.logger?.info(`[SimpleMempoolRunner] prunePendingBlocks batch deleted ${pruneHashes.length} (batchSize=${batch.length} runningPruned=${pruned} checked=${total})`);
75565
- }
75974
+ if (pruneHashes.length > 0) pruned += await this.deletePrunedBatch(bundles, pruneHashes);
75566
75975
  cursor = nextPruneCursor$1(batch, pruneHashes, cursor);
75567
75976
  batch = await this.pendingBlocksArchivist.next({
75568
75977
  limit: batchSize,
@@ -75637,7 +76046,9 @@ var SimpleMempoolRunner$1 = class extends AbstractCreatableProvider$1 {
75637
76046
  const bundles = await Promise.all(blocks.map(async ([bw, payloads]) => {
75638
76047
  return hydratedBlockToPayloadBundle$1([await PayloadBuilder$1.addHashMeta(bw), await PayloadBuilder$1.addHashMeta(payloads)]);
75639
76048
  }));
75640
- return (await this.pendingBlocksArchivist.insert(bundles)).map((p) => p._hash);
76049
+ const inserted = await this.pendingBlocksArchivist.insert(bundles);
76050
+ await noteSubmittedCandidates$1(blocks, this._evidenceStoreRunner);
76051
+ return inserted.map((p) => p._hash);
75641
76052
  }
75642
76053
  /** Submits transactions to the backing provider. */
75643
76054
  async submitTransactions(transactions) {
@@ -75703,6 +76114,30 @@ var SimpleMempoolRunner$1 = class extends AbstractCreatableProvider$1 {
75703
76114
  }
75704
76115
  return all;
75705
76116
  }
76117
+ /**
76118
+ * Deletes a batch of pruned candidates once they are archived, returning how many went.
76119
+ *
76120
+ * Returns zero when the evidence write could not happen: the candidates stay in the pool rather
76121
+ * than being deleted unrecorded. An unbound evidence store means the subsystem is not deployed,
76122
+ * not that a write failed, so those nodes keep pruning as they always have.
76123
+ */
76124
+ async deletePrunedBatch(bundles, pruneHashes) {
76125
+ const evidence = this._evidenceStoreRunner;
76126
+ if (this.options.retainPrunedBlocks && evidence !== void 0) {
76127
+ const pruneSet = new Set(pruneHashes);
76128
+ if (!await archivePrunedCandidates$1(bundles.filter((bundle3) => pruneSet.has(bundle3._hash)), {
76129
+ blockViewer: this._blockViewer,
76130
+ chainId: await this.chainContractViewer.chainId(),
76131
+ evidence,
76132
+ headNumber: await this.finalizationViewer.headNumber()
76133
+ }, this.logger)) {
76134
+ this.logger?.error(`[SimpleMempoolRunner] prunePendingBlocks retained ${pruneHashes.length} (evidence write unavailable \u2014 candidates kept rather than deleted unrecorded)`);
76135
+ return 0;
76136
+ }
76137
+ }
76138
+ await this.pendingBlocksArchivist.delete(pruneHashes);
76139
+ return pruneHashes.length;
76140
+ }
75706
76141
  async enforceCap() {
75707
76142
  const cap = this.maxPendingTransactions;
75708
76143
  if (cap <= 0) return;
@@ -76237,6 +76672,131 @@ __publicField$25(SimpleStakeEventsViewer$1, "monikers", [StakeEventsViewerMonike
76237
76672
  /** Read, write, or mixed capability surface exposed by the provider. */
76238
76673
  __publicField$25(SimpleStakeEventsViewer$1, "surface", "node");
76239
76674
  SimpleStakeEventsViewer$1 = __decorateClass$26([creatableProvider$1()], SimpleStakeEventsViewer$1);
76675
+ var DEFAULT_INTENT_LOOKBACK_BLOCKS$1 = 1e4;
76676
+ var SCAN_PAGE_SIZE$1 = 100;
76677
+ var SimpleStakeIntentViewerOptionsZod$1 = object$3({
76678
+ /**
76679
+ * How far back from the head an intent search walks when no range is given. Intents are
76680
+ * re-declared on a short cadence, so a window well past that cadence finds the current one
76681
+ * without walking the whole chain.
76682
+ */
76683
+ intentLookbackBlocks: number$1().default(DEFAULT_INTENT_LOOKBACK_BLOCKS$1) });
76684
+ var SimpleStakeIntentViewer$1 = class extends AbstractCreatableProvider$1 {
76685
+ /** Moniker implemented by this provider instance. */
76686
+ moniker = SimpleStakeIntentViewer$1.defaultMoniker;
76687
+ _blockViewer;
76688
+ _options;
76689
+ get blockViewer() {
76690
+ return this._blockViewer;
76691
+ }
76692
+ get options() {
76693
+ this._options ??= SimpleStakeIntentViewerOptionsZod$1.parse(this.config.options);
76694
+ return this._options;
76695
+ }
76696
+ /** Creates the provider instance after its dependencies and configuration have resolved. */
76697
+ async createHandler() {
76698
+ await super.createHandler();
76699
+ this._blockViewer = await this.locator.getInstance(BlockViewerMoniker$1);
76700
+ }
76701
+ /** The most recent declared intent for an address, or null when none is found in range. */
76702
+ async intentByAddress(address, headOrRange) {
76703
+ const [intent] = await this.qualifiedIntentByAddress(address, headOrRange);
76704
+ return intent;
76705
+ }
76706
+ /** The most recent declared intent for an address, with the chain position it was read at. */
76707
+ async qualifiedIntentByAddress(address, headOrRange) {
76708
+ const [headHash, range] = await this.resolveScanRange(headOrRange);
76709
+ const [low, high] = range;
76710
+ let intent = null;
76711
+ for (let hi = high; hi >= low && intent === null; hi -= SCAN_PAGE_SIZE$1) {
76712
+ const limit = Math.min(SCAN_PAGE_SIZE$1, hi - low + 1);
76713
+ const blocks = await this.blockViewer.blocksByNumber(asXL1BlockNumber$1(hi, true), limit);
76714
+ for (const block of blocks.toSorted((a, b) => b[0].block - a[0].block)) {
76715
+ const found = block[1].find((payload) => isChainStakeIntent$1(payload) && payload.from === address);
76716
+ if (isChainStakeIntent$1(found)) {
76717
+ intent = found;
76718
+ break;
76719
+ }
76720
+ }
76721
+ }
76722
+ return [intent, {
76723
+ head: headHash,
76724
+ range
76725
+ }];
76726
+ }
76727
+ /** Turns an optional head or range into the concrete window this scan walks. */
76728
+ async resolveScanRange(headOrRange) {
76729
+ const currentBlock = await this.blockViewer.currentBlock();
76730
+ if (Array.isArray(headOrRange)) return [currentBlock[0]._hash, headOrRange];
76731
+ const head = headOrRange === void 0 ? currentBlock[0] : assertEx$1((await this.blockViewer.blockByHash(headOrRange))?.[0], () => `Specified a head that is not in the chain [${headOrRange}]`);
76732
+ const high = head.block;
76733
+ const low = Math.max(0, high - this.options.intentLookbackBlocks);
76734
+ return [head._hash, asXL1BlockRange$1([asXL1BlockNumber$1(low, true), high], true)];
76735
+ }
76736
+ };
76737
+ /** Connection kinds supported by this provider. */
76738
+ __publicField$25(SimpleStakeIntentViewer$1, "connectionTypes", [
76739
+ "lmdb",
76740
+ "mongo",
76741
+ "memory"
76742
+ ]);
76743
+ /** Primary moniker used to resolve this provider. */
76744
+ __publicField$25(SimpleStakeIntentViewer$1, "defaultMoniker", StakeIntentViewerMoniker$1);
76745
+ /** Provider monikers that must resolve before this provider can be created. */
76746
+ __publicField$25(SimpleStakeIntentViewer$1, "dependencies", [BlockViewerMoniker$1]);
76747
+ /** Provider monikers implemented by this provider class. */
76748
+ __publicField$25(SimpleStakeIntentViewer$1, "monikers", [StakeIntentViewerMoniker$1]);
76749
+ /** Read, write, or mixed capability surface exposed by the provider. */
76750
+ __publicField$25(SimpleStakeIntentViewer$1, "surface", "node");
76751
+ SimpleStakeIntentViewer$1 = __decorateClass$26([creatableProvider$1()], SimpleStakeIntentViewer$1);
76752
+ var SimpleStakeSnapshotViewer$1 = class extends AbstractCreatableProvider$1 {
76753
+ /** Moniker implemented by this provider instance. */
76754
+ moniker = SimpleStakeSnapshotViewer$1.defaultMoniker;
76755
+ _stakeViewer;
76756
+ get stakeViewer() {
76757
+ return this._stakeViewer;
76758
+ }
76759
+ /** Stake on an address that was active at an EVM height. */
76760
+ async activeByStakedAt(staked, evmBlock) {
76761
+ return sumPositions$1(await this.positionsByStakedAt(staked, evmBlock), (position) => isPositionActiveAt$1(position, evmBlock));
76762
+ }
76763
+ /** Stake on an address that was still at risk at an EVM height. */
76764
+ async atRiskByStakedAt(staked, evmBlock) {
76765
+ return sumPositions$1(await this.positionsByStakedAt(staked, evmBlock), (position) => isPositionAtRiskAt$1(position, evmBlock));
76766
+ }
76767
+ /** Creates the provider instance after its dependencies and configuration have resolved. */
76768
+ async createHandler() {
76769
+ await super.createHandler();
76770
+ this._stakeViewer = await this.locator.getInstance(StakeViewerMoniker$1);
76771
+ }
76772
+ /** Every position on an address that existed as of an EVM height. */
76773
+ async positionsByStakedAt(staked, evmBlock) {
76774
+ return (await this.stakeViewer.stakesByStaked(staked)).filter((position) => position.addBlock <= evmBlock);
76775
+ }
76776
+ /** Active stake at an EVM height that has also been in place for at least `minAgeBlocks`. */
76777
+ async seasonedActiveByStakedAt(staked, evmBlock, minAgeBlocks) {
76778
+ return sumPositions$1(await this.positionsByStakedAt(staked, evmBlock), (position) => isPositionSeasonedAt$1(position, evmBlock, minAgeBlocks));
76779
+ }
76780
+ /** The seasoned portion of an address's stake that the address placed on itself. */
76781
+ async seasonedSelfBondAt(address, evmBlock, minAgeBlocks) {
76782
+ return sumPositions$1(await this.positionsByStakedAt(address, evmBlock), (position) => isSelfBond$1(position, address) && isPositionSeasonedAt$1(position, evmBlock, minAgeBlocks));
76783
+ }
76784
+ /** Stake an address placed on itself, active at an EVM height. */
76785
+ async selfBondAt(address, evmBlock) {
76786
+ return sumPositions$1(await this.positionsByStakedAt(address, evmBlock), (position) => isSelfBond$1(position, address) && isPositionActiveAt$1(position, evmBlock));
76787
+ }
76788
+ };
76789
+ /** Connection kinds supported by this provider. */
76790
+ __publicField$25(SimpleStakeSnapshotViewer$1, "connectionTypes", ["evm-rpc", "memory"]);
76791
+ /** Primary moniker used to resolve this provider. */
76792
+ __publicField$25(SimpleStakeSnapshotViewer$1, "defaultMoniker", StakeSnapshotViewerMoniker$1);
76793
+ /** Provider monikers that must resolve before this provider can be created. */
76794
+ __publicField$25(SimpleStakeSnapshotViewer$1, "dependencies", [StakeViewerMoniker$1]);
76795
+ /** Provider monikers implemented by this provider class. */
76796
+ __publicField$25(SimpleStakeSnapshotViewer$1, "monikers", [StakeSnapshotViewerMoniker$1]);
76797
+ /** Read, write, or mixed capability surface exposed by the provider. */
76798
+ __publicField$25(SimpleStakeSnapshotViewer$1, "surface", "node");
76799
+ SimpleStakeSnapshotViewer$1 = __decorateClass$26([creatableProvider$1()], SimpleStakeSnapshotViewer$1);
76240
76800
  var SimpleStakeTotalsViewer$1 = class extends AbstractCreatableProvider$1 {
76241
76801
  /** Moniker implemented by this provider instance. */
76242
76802
  moniker = SimpleStakeTotalsViewer$1.defaultMoniker;
@@ -80610,7 +81170,7 @@ function getOriginalId$1(rawRequest) {
80610
81170
  return [void 0, false];
80611
81171
  }
80612
81172
  //#endregion
80613
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_f7cf1f859b51f67ea8ae31d8e591aa95/node_modules/@xyo-network/xl1-sdk/dist/neutral/rpc.mjs
81173
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_3d1fd2739949213d427b87ad651353a9/node_modules/@xyo-network/xl1-sdk/dist/neutral/rpc.mjs
80614
81174
  var __defProp$26 = Object.defineProperty;
80615
81175
  var __getOwnPropDesc$25 = Object.getOwnPropertyDescriptor;
80616
81176
  var __defNormalProp$24 = (obj, key, value) => key in obj ? __defProp$26(obj, key, {
@@ -83152,7 +83712,7 @@ var createRpcDispatchMiddleware = (schemas, handlers, options) => async ({ reque
83152
83712
  }
83153
83713
  };
83154
83714
  //#endregion
83155
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_f7cf1f859b51f67ea8ae31d8e591aa95/node_modules/@xyo-network/xl1-sdk/dist/neutral/rest-block-viewer.mjs
83715
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_3d1fd2739949213d427b87ad651353a9/node_modules/@xyo-network/xl1-sdk/dist/neutral/rest-block-viewer.mjs
83156
83716
  var __defProp$25 = Object.defineProperty;
83157
83717
  var __getOwnPropDesc$24 = Object.getOwnPropertyDescriptor;
83158
83718
  var __defNormalProp$23 = (obj, key, value) => key in obj ? __defProp$25(obj, key, {
@@ -103451,7 +104011,7 @@ var StakedXyoChainV2__factory = class extends ContractFactory {
103451
104011
  }
103452
104012
  };
103453
104013
  //#endregion
103454
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_f7cf1f859b51f67ea8ae31d8e591aa95/node_modules/@xyo-network/xl1-sdk/dist/neutral/providers.mjs
104014
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_3d1fd2739949213d427b87ad651353a9/node_modules/@xyo-network/xl1-sdk/dist/neutral/providers.mjs
103455
104015
  var __defProp$23 = Object.defineProperty;
103456
104016
  var __getOwnPropDesc$23 = Object.getOwnPropertyDescriptor;
103457
104017
  var __defNormalProp$22 = (obj, key, value) => key in obj ? __defProp$23(obj, key, {
@@ -104408,6 +104968,7 @@ EvmStakeViewer$1 = __decorateClass$23([creatableProvider$1()], EvmStakeViewer$1)
104408
104968
  var SimpleDeadLetterQueueRunner$1 = class extends AbstractCreatableProvider$1 {
104409
104969
  /** Moniker implemented by this provider instance. */
104410
104970
  moniker = SimpleDeadLetterQueueRunner$1.defaultMoniker;
104971
+ _evidenceArchivist;
104411
104972
  _rejectedBlocksArchivist;
104412
104973
  _rejectedTransactionsArchivist;
104413
104974
  get rejectedBlocksArchivist() {
@@ -104422,6 +104983,7 @@ var SimpleDeadLetterQueueRunner$1 = class extends AbstractCreatableProvider$1 {
104422
104983
  const connection = SimpleDeadLetterQueueRunner$1.requireBoundConnection(this.config);
104423
104984
  this._rejectedBlocksArchivist = await connectArchivist$1(connection, { name: REJECTED_BLOCKS_ARCHIVIST_ROLE });
104424
104985
  this._rejectedTransactionsArchivist = await connectArchivist$1(connection, { name: REJECTED_TRANSACTIONS_ARCHIVIST_ROLE });
104986
+ this._evidenceArchivist = await connectArchivist$1(connection, { name: EVIDENCE_ARCHIVIST_ROLE$1 });
104425
104987
  }
104426
104988
  /** Removes data through the prune rejected blocks operation. */
104427
104989
  async pruneRejectedBlocks({ batchSize = 10, maxPrune = 1e3, maxCheck = 1e3 } = {}) {
@@ -104474,9 +105036,14 @@ var SimpleDeadLetterQueueRunner$1 = class extends AbstractCreatableProvider$1 {
104474
105036
  return [pruned, total];
104475
105037
  }
104476
105038
  /** Rejects data through the reject block operation. */
104477
- async rejectBlock(rejection) {
105039
+ async rejectBlock(rejection, signed) {
104478
105040
  const withMeta = await PayloadBuilder$1.addHashMeta(rejection);
104479
- return (await this.rejectedBlocksArchivist.insert([withMeta])).length > 0;
105041
+ const inserted = await this.rejectedBlocksArchivist.insert([withMeta]);
105042
+ if (signed !== void 0 && this._evidenceArchivist !== void 0) {
105043
+ const [boundWitness, payloads] = signed;
105044
+ await this._evidenceArchivist.insert([boundWitness, ...payloads]);
105045
+ }
105046
+ return inserted.length > 0;
104480
105047
  }
104481
105048
  /** Rejects data through the reject transaction operation. */
104482
105049
  async rejectTransaction(rejection) {
@@ -105836,7 +106403,7 @@ __publicField$22(RestNetworkStakeStepRewardsByPositionViewer$1, "monikers", [Net
105836
106403
  __publicField$22(RestNetworkStakeStepRewardsByPositionViewer$1, "surface", "node");
105837
106404
  RestNetworkStakeStepRewardsByPositionViewer$1 = __decorateClass$23([creatableProvider$1()], RestNetworkStakeStepRewardsByPositionViewer$1);
105838
106405
  //#endregion
105839
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_f7cf1f859b51f67ea8ae31d8e591aa95/node_modules/@xyo-network/xl1-sdk/dist/neutral/gateway.mjs
106406
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_3d1fd2739949213d427b87ad651353a9/node_modules/@xyo-network/xl1-sdk/dist/neutral/gateway.mjs
105840
106407
  async function witnessPreviousStep(gateway, options) {
105841
106408
  const { addToChain = false, step = 2, transactionOptions, witness: witnessOption } = options ?? {};
105842
106409
  const size = stepSize$1(step);
@@ -105863,7 +106430,7 @@ async function witnessPreviousStep(gateway, options) {
105863
106430
  return { witness };
105864
106431
  }
105865
106432
  //#endregion
105866
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_f7cf1f859b51f67ea8ae31d8e591aa95/node_modules/@xyo-network/xl1-sdk/dist/neutral/wrappers.mjs
106433
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_3d1fd2739949213d427b87ad651353a9/node_modules/@xyo-network/xl1-sdk/dist/neutral/wrappers.mjs
105867
106434
  function parseHexOrBigInt(value) {
105868
106435
  return AttoXL1$1(typeof value === "bigint" ? value : hexToBigInt(value));
105869
106436
  }
@@ -114227,7 +114794,7 @@ __publicField$19(MemoryArchivist, "labels", {
114227
114794
  });
114228
114795
  MemoryArchivist = __decorateClass$19([creatableModule()], MemoryArchivist);
114229
114796
  //#endregion
114230
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._d3b75348f92b7f51ab40e374e53b3e57/node_modules/@xyo-network/xl1-protocol/dist/neutral/protocol-model.mjs
114797
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-protocol@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4._b0999fe1509625eb086040f423d71d2c/node_modules/@xyo-network/xl1-protocol/dist/neutral/protocol-model.mjs
114231
114798
  var ExchangeOutcomeSchema = asSchema("network.xyo.exchange.outcome", true);
114232
114799
  var isExchangeOutcome = isPayloadOfZodType(/* @__PURE__ */ object$5({
114233
114800
  /** Hash of the ExchangeTerms payload this outcome settles */
@@ -114243,7 +114810,8 @@ var NumberishZod = union$1([
114243
114810
  ]).transform((v) => typeof v === "bigint" || typeof v === "string" ? Number(v) : v).pipe(number$2());
114244
114811
  var BlockNumberZod = int().nonnegative().transform((v) => v);
114245
114812
  var BlockNumberishZod = NumberishZod.transform((v) => v);
114246
- zodAsFactory(BlockNumberZod, "asBlockNumber")(0);
114813
+ var asBlockNumber = zodAsFactory(BlockNumberZod, "asBlockNumber");
114814
+ asBlockNumber(0);
114247
114815
  var EthBlockNumberZod = int().nonnegative().transform((v) => v);
114248
114816
  var EthBlockNumberishZod = BlockNumberishZod.transform((v) => v);
114249
114817
  zodAsFactory(EthBlockNumberZod, "asEthBlockNumber")(0);
@@ -114252,6 +114820,7 @@ var XL1BlockNumberishZod = BlockNumberishZod.transform((v) => v);
114252
114820
  var asXL1BlockNumber = zodAsFactory(XL1BlockNumberZod, "asXL1BlockNumber");
114253
114821
  asXL1BlockNumber(0);
114254
114822
  var ChainZod = string$2().toLowerCase().regex(AddressRegEx).transform((v) => toAddress(v));
114823
+ var ChainIdZod = HexZod;
114255
114824
  var xl1MaxValue = (places) => 10n ** (32n - places) - 1n;
114256
114825
  var isXL1Factory = (places) => (val) => {
114257
114826
  if (typeof val !== "bigint") return false;
@@ -114642,6 +115211,57 @@ var asSignedHydratedBlockWithHashMeta = zodAsFactory(SignedHydratedBlockWithHash
114642
115211
  var asSignedHydratedBlockWithStorageMeta = zodAsFactory(/* @__PURE__ */ tuple$1([WithStorageMetaZod(SignedBlockBoundWitnessZod), /* @__PURE__ */ array$2(/* @__PURE__ */ looseObject$1(WithStorageMetaZod(PayloadZod).shape))]), "asSignedHydratedBlockWithStorageMeta");
114643
115212
  WithStorageMetaZod(SignedBlockBoundWitnessZod), WithStorageMetaZod(PayloadZod).shape;
114644
115213
  BlockBoundWitnessFieldsZod.shape, BlockBoundWitnessMetaZod.shape;
115214
+ var CandidatePairSchema = asSchema("network.xyo.chain.evidence.candidate.pair", true);
115215
+ var isCandidatePair = isPayloadOfZodType(/* @__PURE__ */ object$5({
115216
+ /** Chain both candidates were proposed on */
115217
+ chain: ChainIdZod,
115218
+ /** Block number both candidates claim */
115219
+ height: XL1BlockNumberZod,
115220
+ /** Address that signed both candidates */
115221
+ producer: XyoAddressZod,
115222
+ /** The two candidates' recomputed bound witness data hashes, sorted ascending */
115223
+ subjects: /* @__PURE__ */ tuple$1([HashZod, HashZod])
115224
+ }), CandidatePairSchema);
115225
+ AsObjectFactory.create(isCandidatePair);
115226
+ var CandidateSeenSchema = asSchema("network.xyo.chain.evidence.candidate", true);
115227
+ var isCandidateSeen = isPayloadOfZodType(/* @__PURE__ */ object$5({
115228
+ /** Chain the candidate was proposed on */
115229
+ chain: ChainIdZod,
115230
+ /** Block number the candidate claims */
115231
+ height: XL1BlockNumberZod,
115232
+ /** Parent hash the candidate builds on — absent only for a genesis candidate */
115233
+ previous: /* @__PURE__ */ optional$2(HashZod),
115234
+ /** Address that signed the candidate */
115235
+ producer: XyoAddressZod,
115236
+ /** Recomputed data hash of the candidate's bound witness */
115237
+ subject: HashZod
115238
+ }), CandidateSeenSchema);
115239
+ AsObjectFactory.create(isCandidateSeen);
115240
+ var EvidenceDispositionZod = /* @__PURE__ */ literal$2([
115241
+ "expired",
115242
+ "finalized",
115243
+ "foreign",
115244
+ "invalid",
115245
+ "losing",
115246
+ "malformed",
115247
+ "superseded"
115248
+ ]);
115249
+ var EvidenceNoteSchema = asSchema("network.xyo.chain.evidence.note", true);
115250
+ var isEvidenceNote = isPayloadOfZodType(/* @__PURE__ */ object$5({
115251
+ /** Hash of the stored bundle payload this note describes */
115252
+ bundle: HashZod,
115253
+ /** Why the candidate left the pending pool */
115254
+ disposition: EvidenceDispositionZod,
115255
+ /** Block number of the archived candidate — absent when the bundle was malformed */
115256
+ height: /* @__PURE__ */ optional$2(XL1BlockNumberZod),
115257
+ /** Finalized head height when the entry was archived — the retention clock for entries with no height */
115258
+ observed: XL1BlockNumberZod,
115259
+ /** Producer of the archived candidate — absent when the bundle was malformed */
115260
+ producer: /* @__PURE__ */ optional$2(XyoAddressZod),
115261
+ /** Recomputed data hash of the archived block's bound witness — the artifact identity evidence references use */
115262
+ subject: HashZod
115263
+ }), EvidenceNoteSchema);
115264
+ AsObjectFactory.create(isEvidenceNote);
114645
115265
  var BlockNumberSchema = asSchema("network.xyo.chain.block.number", true);
114646
115266
  var isBlockNumberPayload = isPayloadOfSchemaType(BlockNumberSchema);
114647
115267
  AsObjectFactory.create(isBlockNumberPayload);
@@ -114901,6 +115521,7 @@ var DataLakeViewerMoniker = "DataLakeViewer";
114901
115521
  var XyoConnectionMoniker = "XyoConnection";
114902
115522
  var XyoRunnerMoniker = "XyoRunner";
114903
115523
  var DeadLetterQueueRunnerMoniker = "DeadLetterQueueRunner";
115524
+ var EvidenceStoreRunnerMoniker = "EvidenceStoreRunner";
114904
115525
  var FinalizationRunnerMoniker = "FinalizationRunner";
114905
115526
  var MempoolRunnerMoniker = "MempoolRunner";
114906
115527
  var DEFAULT_MAX_EXP_AHEAD = 1e3;
@@ -114996,6 +115617,11 @@ var BlockValidationViewerMoniker = "BlockValidationViewer";
114996
115617
  var ChainContractViewerMoniker = "ChainContractViewer";
114997
115618
  (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
114998
115619
  (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
115620
+ (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
115621
+ (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
115622
+ (/* @__PURE__ */ int$1()).check(/* @__PURE__ */ _positive());
115623
+ var EvidenceViewerMoniker = "EvidenceViewer";
115624
+ var EvidenceProtectionViewerMoniker = "EvidenceProtectionViewer";
114999
115625
  var EvmChainViewerMoniker = "EvmChainViewer";
115000
115626
  var FinalizationViewerMoniker = "FinalizationViewer";
115001
115627
  var IndexViewerMoniker = "IndexViewer";
@@ -115018,6 +115644,8 @@ var NetworkStakeStepRewardsTotalViewerMoniker = "NetworkStakeStepRewardsTotalVie
115018
115644
  var NetworkStakeStepRewardsViewerMoniker = "NetworkStakeStepRewardsViewer";
115019
115645
  var StakeViewerMoniker = "StakeViewer";
115020
115646
  var StakeEventsViewerMoniker = "StakeEventsViewer";
115647
+ var StakeIntentViewerMoniker = "StakeIntentViewer";
115648
+ var StakeSnapshotViewerMoniker = "StakeSnapshotViewer";
115021
115649
  var StakeTotalsViewerMoniker = "StakeTotalsViewer";
115022
115650
  var StepViewerMoniker = "StepViewer";
115023
115651
  var SyncViewerMoniker = "SyncViewer";
@@ -115059,7 +115687,7 @@ new import_ajv.Ajv({
115059
115687
  strict: true
115060
115688
  });
115061
115689
  //#endregion
115062
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_0413c4361bf30f6daaff87ca8a579dc5/node_modules/@xyo-network/xl1-sdk/dist/neutral/driver-memory.mjs
115690
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_203014cdf26a7fb134df680684c24d7b/node_modules/@xyo-network/xl1-sdk/dist/neutral/driver-memory.mjs
115063
115691
  var LruCacheMap = class {
115064
115692
  lruCache;
115065
115693
  /** Creates an instance with the supplied configuration. */
@@ -115141,7 +115769,7 @@ var MemoryMap = class {
115141
115769
  }
115142
115770
  };
115143
115771
  //#endregion
115144
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_0413c4361bf30f6daaff87ca8a579dc5/node_modules/@xyo-network/xl1-sdk/dist/node/protocol-sdk.mjs
115772
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_203014cdf26a7fb134df680684c24d7b/node_modules/@xyo-network/xl1-sdk/dist/node/protocol-sdk.mjs
115145
115773
  var __defProp$18 = Object.defineProperty;
115146
115774
  var __getOwnPropDesc$18 = Object.getOwnPropertyDescriptor;
115147
115775
  var __defNormalProp$18 = (obj, key, value) => key in obj ? __defProp$18(obj, key, {
@@ -115600,6 +116228,204 @@ function netTransfersForPayloads(context, payloads) {
115600
116228
  }, context.traceProvider);
115601
116229
  }
115602
116230
  var XL1_NETWORK_STAKING_GENESIS_PERIOD_END_XL1_BLOCK = 107496;
116231
+ var functionName = "externalBlockNumberFromXL1BlockNumber";
116232
+ var SCAN_CHUNK = 50;
116233
+ var MIN_SCAN_CHUNK = 10;
116234
+ var SCAN_CHUNK_RETRIES = 3;
116235
+ var SCAN_CHUNK_RETRY_BASE_DELAY_MS = 100;
116236
+ function retryDelayMs(attempt) {
116237
+ return SCAN_CHUNK_RETRY_BASE_DELAY_MS * 2 ** attempt * (.5 + Math.random() / 2);
116238
+ }
116239
+ var EXTERNAL_TIME_CACHE_MAX = 25e4;
116240
+ function externalTimeCache(context) {
116241
+ return contextCache(context, "externalTimeAtBlock", () => new LruCacheMap({ max: EXTERNAL_TIME_CACHE_MAX }));
116242
+ }
116243
+ function externalTimeCacheKey(xl1Block, externalTimeName) {
116244
+ return `${xl1Block}-${externalTimeName}`;
116245
+ }
116246
+ function externalTimeOfBlock(block, externalTimeName) {
116247
+ const [, payloads = []] = block;
116248
+ const time = (isArray(payloads) ? asTimePayload(payloads.find(isTimePayload)) : void 0)?.[externalTimeName];
116249
+ return time === 0 ? void 0 : time;
116250
+ }
116251
+ async function externalTimeAtBlock(context, blockViewer, xl1Block, externalTimeName) {
116252
+ const cache = externalTimeCache(context);
116253
+ const cacheKey = externalTimeCacheKey(xl1Block, externalTimeName);
116254
+ const cached = await cache.get(cacheKey);
116255
+ if (isDefined$1(cached)) return cached;
116256
+ const block = await blockViewer.blockByNumber(asXL1BlockNumber(xl1Block, true));
116257
+ if (isUndefined$1(block) || block === null) return { exists: false };
116258
+ const result = {
116259
+ exists: true,
116260
+ time: externalTimeOfBlock(block, externalTimeName)
116261
+ };
116262
+ await cache.set(cacheKey, result);
116263
+ return result;
116264
+ }
116265
+ async function cacheChunkExternalTimes(cache, blocks, externalTimeName) {
116266
+ const times = blocks.map((block) => [block[0].block, externalTimeOfBlock(block, externalTimeName)]);
116267
+ for (const [blockNumber, time] of times) await cache.set(externalTimeCacheKey(blockNumber, externalTimeName), {
116268
+ exists: true,
116269
+ time
116270
+ });
116271
+ return times;
116272
+ }
116273
+ async function scanForAnchor(context, blockViewer, from, direction, maxScanBlocks, externalTimeName) {
116274
+ if (maxScanBlocks < 1) return { final: true };
116275
+ const cache = externalTimeCache(context);
116276
+ const chunker = new AdaptiveChunkFetcher(context, blockViewer, direction);
116277
+ return direction === "backward" ? await scanBackward(cache, chunker, from, maxScanBlocks, externalTimeName) : await scanForward(cache, chunker, blockViewer, from, maxScanBlocks, externalTimeName);
116278
+ }
116279
+ var AdaptiveChunkFetcher = class {
116280
+ blockViewer;
116281
+ chunk = SCAN_CHUNK;
116282
+ context;
116283
+ direction;
116284
+ failedAtFloor = false;
116285
+ constructor(context, blockViewer, direction) {
116286
+ this.context = context;
116287
+ this.blockViewer = blockViewer;
116288
+ this.direction = direction;
116289
+ }
116290
+ /** True once a fetch failed at the minimum chunk size — the scan should give up */
116291
+ get exhausted() {
116292
+ return this.failedAtFloor;
116293
+ }
116294
+ get size() {
116295
+ return this.chunk;
116296
+ }
116297
+ /**
116298
+ * Returns the chunk ending at endBlock (descending), or undefined when
116299
+ * every attempt failed. A failed attempt is retried with jittered
116300
+ * exponential backoff up to SCAN_CHUNK_RETRIES times; only after the
116301
+ * retries exhaust is the chunk size halved so the caller can recompute its
116302
+ * window and retry smaller. Once retries exhaust at the floor size,
116303
+ * `exhausted` is set and the caller should bail non-final.
116304
+ */
116305
+ async fetch(endBlock, count) {
116306
+ for (let attempt = 0;; attempt++) try {
116307
+ return await this.blockViewer.blocksByNumber(asXL1BlockNumber(endBlock, true), count);
116308
+ } catch (ex) {
116309
+ const message = ex.message;
116310
+ if (attempt < SCAN_CHUNK_RETRIES) {
116311
+ const delay2 = retryDelayMs(attempt);
116312
+ this.context.logger?.warn(`[${functionName}] blocksByNumber(${endBlock}, ${count}) failed during ${this.direction} scan (attempt ${attempt + 1}/${SCAN_CHUNK_RETRIES + 1}, retrying in ${Math.round(delay2)}ms): ${message}`);
116313
+ await new Promise((resolve) => setTimeout(resolve, delay2));
116314
+ continue;
116315
+ }
116316
+ this.context.logger?.warn(`[${functionName}] blocksByNumber(${endBlock}, ${count}) failed during ${this.direction} scan after ${attempt + 1} attempts: ${message}`);
116317
+ if (count <= MIN_SCAN_CHUNK) this.failedAtFloor = true;
116318
+ else this.chunk = Math.max(MIN_SCAN_CHUNK, this.chunk >> 1);
116319
+ return;
116320
+ }
116321
+ }
116322
+ };
116323
+ async function scanBackward(cache, chunker, from, maxScanBlocks, externalTimeName) {
116324
+ const floor = Math.max(0, from - maxScanBlocks);
116325
+ let cursor = from - 1;
116326
+ while (cursor >= floor) {
116327
+ const cached = await cache.get(externalTimeCacheKey(cursor, externalTimeName));
116328
+ if (isDefined$1(cached)) {
116329
+ if (isDefined$1(cached.time)) return {
116330
+ anchor: cached.time,
116331
+ final: true
116332
+ };
116333
+ cursor -= 1;
116334
+ continue;
116335
+ }
116336
+ const count = Math.min(chunker.size, cursor - floor + 1);
116337
+ const blocks = await chunker.fetch(cursor, count);
116338
+ if (blocks === void 0) {
116339
+ if (chunker.exhausted) return { final: false };
116340
+ continue;
116341
+ }
116342
+ const hit = (await cacheChunkExternalTimes(cache, blocks, externalTimeName)).find(([, time]) => isDefined$1(time));
116343
+ if (hit !== void 0 && isDefined$1(hit[1])) return {
116344
+ anchor: hit[1],
116345
+ final: true
116346
+ };
116347
+ if (blocks.length < count) return { final: false };
116348
+ cursor -= count;
116349
+ }
116350
+ return { final: true };
116351
+ }
116352
+ async function scanForward(cache, chunker, blockViewer, from, maxScanBlocks, externalTimeName) {
116353
+ const head = await blockViewer.currentBlockNumber();
116354
+ const ceiling = Math.min(from + maxScanBlocks, head);
116355
+ let windowStart = from + 1;
116356
+ while (windowStart <= ceiling) {
116357
+ const cached = await cache.get(externalTimeCacheKey(windowStart, externalTimeName));
116358
+ if (isDefined$1(cached)) {
116359
+ if (isDefined$1(cached.time)) return {
116360
+ anchor: cached.time,
116361
+ final: true
116362
+ };
116363
+ windowStart += 1;
116364
+ continue;
116365
+ }
116366
+ const windowEnd = Math.min(windowStart + chunker.size - 1, ceiling);
116367
+ const count = windowEnd - windowStart + 1;
116368
+ const blocks = await chunker.fetch(windowEnd, count);
116369
+ if (blocks === void 0) {
116370
+ if (chunker.exhausted) return { final: false };
116371
+ continue;
116372
+ }
116373
+ const hit = (await cacheChunkExternalTimes(cache, blocks, externalTimeName)).findLast(([, time]) => isDefined$1(time));
116374
+ if (hit !== void 0 && isDefined$1(hit[1])) return {
116375
+ anchor: hit[1],
116376
+ final: true
116377
+ };
116378
+ if (blocks.length < count) return { final: false };
116379
+ windowStart = windowEnd + 1;
116380
+ }
116381
+ return { final: from + maxScanBlocks <= head };
116382
+ }
116383
+ async function scanBothDirections(context, blockViewer, xl1BlockNumber, direction, maxScanBlocks, externalTimeName) {
116384
+ let final = true;
116385
+ let backwardExhaustedAtGenesis = false;
116386
+ const directions = direction === "backward" ? ["backward", "forward"] : ["forward", "backward"];
116387
+ for (const scanDirection of directions) {
116388
+ const scan = await scanForAnchor(context, blockViewer, xl1BlockNumber, scanDirection, maxScanBlocks, externalTimeName);
116389
+ final = final && scan.final;
116390
+ if (isDefined$1(scan.anchor)) return {
116391
+ anchor: scan.anchor,
116392
+ final
116393
+ };
116394
+ if (scanDirection === "backward" && scan.final && xl1BlockNumber <= maxScanBlocks) backwardExhaustedAtGenesis = true;
116395
+ }
116396
+ if (backwardExhaustedAtGenesis) {
116397
+ const scan = await scanForAnchor(context, blockViewer, xl1BlockNumber, "forward", Number.POSITIVE_INFINITY, externalTimeName);
116398
+ return {
116399
+ anchor: scan.anchor,
116400
+ final: final && scan.final
116401
+ };
116402
+ }
116403
+ return { final };
116404
+ }
116405
+ async function externalBlockNumberFromXL1BlockNumber(context, blockViewer, xl1BlockNumber, externalTimeName, direction = "backward", options) {
116406
+ const externalGenesisTime = options?.externalGenesisTime ?? 23372716;
116407
+ const maxScanBlocks = options?.maxScanBlocks ?? 1e5;
116408
+ const cache = contextCache(context, functionName);
116409
+ const cacheKey = `${xl1BlockNumber}-${externalTimeName}-${direction}-${externalGenesisTime}-${maxScanBlocks}`;
116410
+ const cached = await cache.get(cacheKey);
116411
+ if (isDefined$1(cached)) return cached;
116412
+ let result;
116413
+ let final = true;
116414
+ const own = await externalTimeAtBlock(context, blockViewer, xl1BlockNumber, externalTimeName);
116415
+ if (isDefined$1(own.time)) result = own.time;
116416
+ else {
116417
+ const scan = await scanBothDirections(context, blockViewer, xl1BlockNumber, direction, maxScanBlocks, externalTimeName);
116418
+ final = own.exists && scan.final;
116419
+ result = scan.anchor;
116420
+ if (isUndefined$1(result)) {
116421
+ context.logger?.warn(`[${functionName}] No ${externalTimeName} time anchor within ${maxScanBlocks} blocks of XL1 block ${xl1BlockNumber}; falling back to genesis time ${externalGenesisTime}`);
116422
+ result = externalGenesisTime;
116423
+ }
116424
+ }
116425
+ const blockNumber = asBlockNumber(result, { name: functionName });
116426
+ if (final) await cache.set(cacheKey, blockNumber);
116427
+ return blockNumber;
116428
+ }
115603
116429
  function allHashesPresent(hashes, payloads) {
115604
116430
  const payloadHashes = new Set(payloads.map((p) => p._hash));
115605
116431
  return hashes.every((hash) => payloadHashes.has(hash));
@@ -115741,6 +116567,21 @@ function rewardFromBlockNumber(blockNumber) {
115741
116567
  const reward = XL1_REWARDS_STARTING_REWARD * poweredNumerator / poweredDenominator;
115742
116568
  return asAttoXL1(reward < XL1_REWARDS_MIN_BLOCK_REWARD ? XL1_REWARDS_MIN_BLOCK_REWARD : reward);
115743
116569
  }
116570
+ function isPositionActiveAt(position, at) {
116571
+ return position.addBlock <= at && (position.removeBlock === 0 || position.removeBlock > at);
116572
+ }
116573
+ function isPositionAtRiskAt(position, at) {
116574
+ return position.addBlock <= at && (position.withdrawBlock === 0 || position.withdrawBlock > at);
116575
+ }
116576
+ function isPositionSeasonedAt(position, at, minAge) {
116577
+ return isPositionActiveAt(position, at) && position.addBlock <= at - minAge;
116578
+ }
116579
+ function isSelfBond(position, address) {
116580
+ return position.staker === address && position.staked === address;
116581
+ }
116582
+ function sumPositions(positions, predicate) {
116583
+ return positions.reduce((total, position) => predicate(position) ? total + position.amount : total, 0n);
116584
+ }
115744
116585
  var DEFAULT_NEXT_OPTIONS = { limit: 50 };
115745
116586
  var findMostRecentBlock = async (chainArchivist, nextOptions = DEFAULT_NEXT_OPTIONS, maxIterations = Infinity) => {
115746
116587
  let mostRecentBlock;
@@ -115998,6 +116839,7 @@ registerArchivistFactory("memory", MemoryArchivistFactory$1);
115998
116839
  var CHAIN_ARCHIVIST_ROLE = "chain";
115999
116840
  var PENDING_TRANSACTIONS_ARCHIVIST_ROLE = "pending-transactions";
116000
116841
  var PENDING_BLOCKS_ARCHIVIST_ROLE = "pending-blocks";
116842
+ var EVIDENCE_ARCHIVIST_ROLE = "evidence";
116001
116843
  async function connectArchivist(binding, options) {
116002
116844
  const factory = getArchivistFactory(binding.config.type);
116003
116845
  if (factory === void 0) throw new Error(`connectArchivist: no archivist factory registered for connection type '${binding.config.type}'`);
@@ -117707,6 +118549,285 @@ __publicField$18(SimpleDataLakeViewer, "monikers", [DataLakeViewerMoniker]);
117707
118549
  /** Read, write, or mixed capability surface exposed by the provider. */
117708
118550
  __publicField$18(SimpleDataLakeViewer, "surface", "node");
117709
118551
  SimpleDataLakeViewer = __decorateClass$18([creatableProvider()], SimpleDataLakeViewer);
118552
+ function isRetentionExpired(subject, clock, params) {
118553
+ const { observedHeight, subjectAnchor, subjectHeight } = subject;
118554
+ const { headAnchor, headHeight } = clock;
118555
+ const { challengeWindowEvmBlocks, evidenceFreshnessEvmBlocks, evidenceRetentionXl1Blocks } = params;
118556
+ const floorExceeded = headHeight - (subjectHeight ?? observedHeight) > evidenceRetentionXl1Blocks;
118557
+ const anchorExceeded = headAnchor - subjectAnchor > evidenceFreshnessEvmBlocks + challengeWindowEvmBlocks;
118558
+ return floorExceeded && anchorExceeded;
118559
+ }
118560
+ var SimpleEvidenceStoreRunnerOptionsZod = object$3({
118561
+ /** How far back the in-memory candidate index tracks heights, in XL1 blocks. */
118562
+ candidatePairLookbackXl1Blocks: number$1().default(1440),
118563
+ /** Challenge window, in EVM blocks. */
118564
+ challengeWindowEvmBlocks: number$1().default(14400),
118565
+ /** Evidence freshness window, in EVM blocks. */
118566
+ evidenceFreshnessEvmBlocks: number$1().default(21600),
118567
+ /** Operational retention floor, in XL1 blocks. */
118568
+ evidenceRetentionXl1Blocks: number$1().default(6e4)
118569
+ });
118570
+ var SimpleEvidenceStoreRunner = class extends AbstractCreatableProvider {
118571
+ /** Moniker implemented by this provider instance. */
118572
+ moniker = SimpleEvidenceStoreRunner.defaultMoniker;
118573
+ _blockViewer;
118574
+ _finalizationViewer;
118575
+ _protectionViewer;
118576
+ _archivist;
118577
+ _options;
118578
+ /**
118579
+ * Signed-hash sets keyed by `producer|height`. Only the ingest edge feeds this, so it is a
118580
+ * detection aid rather than the authoritative index — the durable candidate records in the
118581
+ * store are what a full scan reads.
118582
+ */
118583
+ _seen = /* @__PURE__ */ new Map();
118584
+ get archivist() {
118585
+ return assertEx$1(this._archivist, () => "evidence archivist not initialized — bind a connection");
118586
+ }
118587
+ get blockViewer() {
118588
+ return this._blockViewer;
118589
+ }
118590
+ get finalizationViewer() {
118591
+ return this._finalizationViewer;
118592
+ }
118593
+ get options() {
118594
+ this._options ??= SimpleEvidenceStoreRunnerOptionsZod.parse(this.config.options);
118595
+ return this._options;
118596
+ }
118597
+ /** Archives pruned candidates with their dispositions, returning the stored hashes. */
118598
+ async archiveCandidates(entries) {
118599
+ if (entries.length === 0) return [];
118600
+ const observed = await this.finalizationViewer.headNumber();
118601
+ const payloads = [];
118602
+ for (const entry of entries) {
118603
+ const boundWitness = entry.block?.[0];
118604
+ payloads.push(entry.bundle, await PayloadBuilder.addHashMeta({
118605
+ bundle: entry.bundle._hash,
118606
+ disposition: entry.disposition,
118607
+ height: boundWitness?.block,
118608
+ observed,
118609
+ producer: boundWitness?.addresses[0],
118610
+ schema: EvidenceNoteSchema,
118611
+ subject: boundWitness === void 0 ? entry.bundle._hash : await signedHash(boundWitness)
118612
+ }));
118613
+ }
118614
+ return (await this.archivist.insert(payloads)).filter(isHashMeta).map((payload) => payload._hash);
118615
+ }
118616
+ /** Creates the provider instance after its dependencies and configuration have resolved. */
118617
+ async createHandler() {
118618
+ await super.createHandler();
118619
+ const connection = SimpleEvidenceStoreRunner.requireBoundConnection(this.config);
118620
+ this._archivist = await connectArchivist(connection, { name: EVIDENCE_ARCHIVIST_ROLE });
118621
+ this._blockViewer = await this.locator.getInstance(BlockViewerMoniker);
118622
+ this._finalizationViewer = await this.locator.getInstance(FinalizationViewerMoniker);
118623
+ this._protectionViewer = await this.locator.tryGetInstance(EvidenceProtectionViewerMoniker);
118624
+ }
118625
+ /**
118626
+ * Records observed candidates in the signed-hash index, returning any same-height pairs newly
118627
+ * detected by this call.
118628
+ *
118629
+ * Identity is the signed data hash, never the stored hash: client metadata such as the block
118630
+ * timestamp sits outside the signature, so two artifacts differing only there are one
118631
+ * candidate and must collapse to a single entry.
118632
+ */
118633
+ async noteCandidates(blocks) {
118634
+ if (blocks.length === 0) return [];
118635
+ const detected = [];
118636
+ const payloads = [];
118637
+ for (const block of blocks) {
118638
+ const boundWitness = block[0];
118639
+ const producer = boundWitness.addresses[0];
118640
+ if (producer === void 0) continue;
118641
+ const height = boundWitness.block;
118642
+ const subject = await signedHash(boundWitness);
118643
+ payloads.push(await PayloadBuilder.addHashMeta({
118644
+ chain: boundWitness.chain,
118645
+ height,
118646
+ previous: boundWitness.previous ?? void 0,
118647
+ producer,
118648
+ schema: CandidateSeenSchema,
118649
+ subject
118650
+ }));
118651
+ const key = `${producer}|${height}`;
118652
+ const known = this._seen.get(key) ?? /* @__PURE__ */ new Set();
118653
+ if (!known.has(subject)) {
118654
+ for (const other of known) {
118655
+ const subjects = other < subject ? [other, subject] : [subject, other];
118656
+ detected.push({
118657
+ chain: boundWitness.chain,
118658
+ height,
118659
+ producer,
118660
+ subjects
118661
+ });
118662
+ payloads.push(await PayloadBuilder.addHashMeta({
118663
+ chain: boundWitness.chain,
118664
+ height,
118665
+ producer,
118666
+ schema: CandidatePairSchema,
118667
+ subjects
118668
+ }));
118669
+ }
118670
+ known.add(subject);
118671
+ this._seen.set(key, known);
118672
+ }
118673
+ }
118674
+ if (payloads.length > 0) await this.archivist.insert(payloads);
118675
+ await this.evictStaleKeys();
118676
+ return detected;
118677
+ }
118678
+ /**
118679
+ * Removes evidence whose retention has expired on both clocks, skipping anything a pending
118680
+ * report still references. Returns `[pruned, checked]`.
118681
+ *
118682
+ * Notes drive the sweep: each one names the bundle it describes, so an expired note takes its
118683
+ * bundle with it. Anything a protection viewer still claims is left alone regardless of age —
118684
+ * retention deliberately loses to reference protection, since pruning evidence out from under
118685
+ * an open report would destroy the case it rests on.
118686
+ */
118687
+ async pruneEvidence({ batchSize = 100, maxPrune = 5e3, maxCheck = 1e4 } = {}) {
118688
+ const headNumber = await this.finalizationViewer.headNumber();
118689
+ const headAnchor = await this.anchorFor(headNumber);
118690
+ const protectedSubjects = new Set(await this._protectionViewer?.protectedSubjectHashes());
118691
+ const { challengeWindowEvmBlocks, evidenceFreshnessEvmBlocks, evidenceRetentionXl1Blocks } = this.options;
118692
+ const params = {
118693
+ challengeWindowEvmBlocks,
118694
+ evidenceFreshnessEvmBlocks,
118695
+ evidenceRetentionXl1Blocks
118696
+ };
118697
+ let checked = 0;
118698
+ let pruned = 0;
118699
+ let cursor;
118700
+ let batch = await this.archivist.next({
118701
+ limit: batchSize,
118702
+ cursor,
118703
+ order: "asc"
118704
+ });
118705
+ while (batch.length > 0 && pruned < maxPrune && checked < maxCheck) {
118706
+ const expired = [];
118707
+ for (const payload of batch) {
118708
+ if (!isEvidenceNote(payload) || !isHashMeta(payload)) continue;
118709
+ checked++;
118710
+ if (protectedSubjects.has(payload.subject)) continue;
118711
+ const subjectHeight = payload.height;
118712
+ const subjectAnchor = await this.anchorFor(asXL1BlockNumber(subjectHeight ?? payload.observed, true));
118713
+ if (isRetentionExpired({
118714
+ observedHeight: payload.observed,
118715
+ subjectAnchor,
118716
+ subjectHeight
118717
+ }, {
118718
+ headAnchor,
118719
+ headHeight: headNumber
118720
+ }, params)) expired.push(payload._hash, payload.bundle);
118721
+ }
118722
+ if (expired.length > 0) {
118723
+ await this.archivist.delete(expired);
118724
+ pruned += expired.length;
118725
+ }
118726
+ const last = batch.at(-1);
118727
+ cursor = isHashMeta(last) ? last._sequence : cursor;
118728
+ if (cursor === void 0) break;
118729
+ batch = await this.archivist.next({
118730
+ limit: batchSize,
118731
+ cursor,
118732
+ order: "asc"
118733
+ });
118734
+ }
118735
+ return [pruned, checked];
118736
+ }
118737
+ /** Stores an observer-signed rejection record. */
118738
+ async recordRejection(record) {
118739
+ const [boundWitness, payloads] = record;
118740
+ return (await this.archivist.insert([boundWitness, ...payloads])).length > 0;
118741
+ }
118742
+ /** Resolves the EVM anchor for an XL1 height, tolerating gaps in the anchor history. */
118743
+ async anchorFor(height) {
118744
+ return await externalBlockNumberFromXL1BlockNumber(this.context, this.blockViewer, height, "ethereum", "backward");
118745
+ }
118746
+ /** Drops index keys for heights the lookback window no longer covers. */
118747
+ async evictStaleKeys() {
118748
+ const floor = await this.finalizationViewer.headNumber() - this.options.candidatePairLookbackXl1Blocks;
118749
+ if (floor <= 0) return;
118750
+ for (const key of this._seen.keys()) {
118751
+ const height = Number(key.split("|", 2)[1]);
118752
+ if (Number.isFinite(height) && height <= floor) this._seen.delete(key);
118753
+ }
118754
+ }
118755
+ };
118756
+ /** Connection kinds supported by this provider. */
118757
+ __publicField$18(SimpleEvidenceStoreRunner, "connectionTypes", [
118758
+ "lmdb",
118759
+ "mongo",
118760
+ "memory"
118761
+ ]);
118762
+ /** Primary moniker used to resolve this provider. */
118763
+ __publicField$18(SimpleEvidenceStoreRunner, "defaultMoniker", EvidenceStoreRunnerMoniker);
118764
+ /** Provider monikers that must resolve before this provider can be created. */
118765
+ __publicField$18(SimpleEvidenceStoreRunner, "dependencies", [FinalizationViewerMoniker, BlockViewerMoniker]);
118766
+ /** Provider monikers implemented by this provider class. */
118767
+ __publicField$18(SimpleEvidenceStoreRunner, "monikers", [EvidenceStoreRunnerMoniker]);
118768
+ /** Read, write, or mixed capability surface exposed by the provider. */
118769
+ __publicField$18(SimpleEvidenceStoreRunner, "surface", "node");
118770
+ SimpleEvidenceStoreRunner = __decorateClass$18([creatableProvider()], SimpleEvidenceStoreRunner);
118771
+ async function signedHash(boundWitness) {
118772
+ return boundWitness._dataHash ?? await PayloadBuilder.dataHash(boundWitness);
118773
+ }
118774
+ var SimpleEvidenceViewer = class extends AbstractCreatableProvider {
118775
+ /** Moniker implemented by this provider instance. */
118776
+ moniker = SimpleEvidenceViewer.defaultMoniker;
118777
+ _archivist;
118778
+ get archivist() {
118779
+ return assertEx$1(this._archivist, () => "evidence archivist not initialized — bind a connection");
118780
+ }
118781
+ /** Reads recorded same-height candidate pairs — the equivocation detection feed. */
118782
+ async candidatePairs({ cursor, limit = 100, producer } = {}) {
118783
+ const pairs = (await this.page(cursor, limit)).filter((payload) => isCandidatePair(payload));
118784
+ return producer === void 0 ? pairs : pairs.filter((pair) => pair.producer === producer);
118785
+ }
118786
+ /** Creates the provider instance after its dependencies and configuration have resolved. */
118787
+ async createHandler() {
118788
+ await super.createHandler();
118789
+ const connection = SimpleEvidenceViewer.requireBoundConnection(this.config);
118790
+ this._archivist = await connectArchivist(connection, { name: EVIDENCE_ARCHIVIST_ROLE });
118791
+ }
118792
+ /** Reads raw evidence entries, optionally filtered by schema. */
118793
+ async entries({ cursor, limit = 100, schema } = {}) {
118794
+ const payloads = await this.page(cursor, limit);
118795
+ return schema === void 0 ? payloads : payloads.filter((payload) => payload.schema === schema);
118796
+ }
118797
+ /** Reads observer-signed rejection records. */
118798
+ async rejections({ cursor, limit = 100, rejector } = {}) {
118799
+ const rejections = (await this.page(cursor, limit)).filter((payload) => isBlockRejection(payload));
118800
+ return rejector === void 0 ? rejections : rejections.filter((rejection) => rejection.rejector === rejector);
118801
+ }
118802
+ /** Reads one page of the store, newest first, resolving a hash cursor to its sequence. */
118803
+ async page(cursorHash, limit) {
118804
+ let cursor;
118805
+ if (isHash(cursorHash)) {
118806
+ const [payload] = await this.archivist.get([cursorHash]);
118807
+ if (isDefined$1(payload)) cursor = payload._sequence;
118808
+ }
118809
+ return (await this.archivist.next({
118810
+ order: "desc",
118811
+ limit,
118812
+ cursor
118813
+ })).filter(isHashMeta);
118814
+ }
118815
+ };
118816
+ /** Connection kinds supported by this provider. */
118817
+ __publicField$18(SimpleEvidenceViewer, "connectionTypes", [
118818
+ "lmdb",
118819
+ "mongo",
118820
+ "memory"
118821
+ ]);
118822
+ /** Primary moniker used to resolve this provider. */
118823
+ __publicField$18(SimpleEvidenceViewer, "defaultMoniker", EvidenceViewerMoniker);
118824
+ /** Provider monikers that must resolve before this provider can be created. */
118825
+ __publicField$18(SimpleEvidenceViewer, "dependencies", []);
118826
+ /** Provider monikers implemented by this provider class. */
118827
+ __publicField$18(SimpleEvidenceViewer, "monikers", [EvidenceViewerMoniker]);
118828
+ /** Read, write, or mixed capability surface exposed by the provider. */
118829
+ __publicField$18(SimpleEvidenceViewer, "surface", "node");
118830
+ SimpleEvidenceViewer = __decorateClass$18([creatableProvider()], SimpleEvidenceViewer);
117710
118831
  function ethProviderFromEvmRpcConnection(connection) {
117711
118832
  const provider = isDefined$1(connection.chainId) ? new JsonRpcProvider(connection.url, Number(connection.chainId), {
117712
118833
  polling: true,
@@ -117973,6 +119094,44 @@ __publicField$18(SimpleIndexViewer, "dependencies", [BlockViewerMoniker]);
117973
119094
  /** Provider monikers implemented by this provider class. */
117974
119095
  __publicField$18(SimpleIndexViewer, "monikers", [IndexViewerMoniker]);
117975
119096
  SimpleIndexViewer = __decorateClass$18([creatableProvider()], SimpleIndexViewer);
119097
+ async function classifyPrunedCandidate(bundle3, context) {
119098
+ const block = isPayloadBundle(bundle3) ? await bundledPayloadToHydratedBlock(bundle3) : void 0;
119099
+ if (block === void 0 || !isSignedHydratedBlockWithHashMeta(block)) return {
119100
+ bundle: bundle3,
119101
+ disposition: "malformed"
119102
+ };
119103
+ if (block[0].chain !== context.chainId) return {
119104
+ block,
119105
+ bundle: bundle3,
119106
+ disposition: "foreign"
119107
+ };
119108
+ if (block[0].block > context.headNumber) return {
119109
+ block,
119110
+ bundle: bundle3,
119111
+ disposition: "invalid"
119112
+ };
119113
+ const [canonical] = await context.blockViewer?.blocksByNumber(block[0].block, 1) ?? [];
119114
+ return {
119115
+ block,
119116
+ bundle: bundle3,
119117
+ disposition: canonical !== void 0 && canonical[0]._dataHash === block[0]._dataHash ? "finalized" : "losing"
119118
+ };
119119
+ }
119120
+ async function noteSubmittedCandidates(blocks, evidence) {
119121
+ if (evidence === void 0) return;
119122
+ const hydrated = await Promise.all(blocks.map(async ([boundWitness, payloads]) => [await PayloadBuilder.addHashMeta(boundWitness), await PayloadBuilder.addHashMeta(payloads)]));
119123
+ await evidence.noteCandidates(hydrated);
119124
+ }
119125
+ async function archivePrunedCandidates(bundles, context, logger) {
119126
+ try {
119127
+ const entries = await Promise.all(bundles.map(async (bundle3) => await classifyPrunedCandidate(bundle3, context)));
119128
+ await context.evidence.archiveCandidates(entries);
119129
+ return true;
119130
+ } catch (error) {
119131
+ logger?.error(`[SimpleMempoolRunner] evidence archive failed: ${String(error)}`);
119132
+ return false;
119133
+ }
119134
+ }
117976
119135
  async function resolvePendingStores(connection) {
117977
119136
  return {
117978
119137
  pendingBlocksArchivist: await connectArchivist(connection, { name: PENDING_BLOCKS_ARCHIVIST_ROLE }),
@@ -118034,6 +119193,13 @@ var SimpleMempoolRunnerOptionsZod = object$3({
118034
119193
  maxPendingTransactions: number$1().default(0),
118035
119194
  /** Interval between synchronization passes, in milliseconds. */
118036
119195
  syncInterval: number$1().default(DEFAULT_SYNC_INTERVAL),
119196
+ /**
119197
+ * When true (default), a pruned candidate block is archived to the evidence store before it is
119198
+ * deleted, and the delete is skipped when that write cannot happen. Deleting a candidate
119199
+ * without recording it destroys the only copy of a producer-signed artifact, so the pool is
119200
+ * allowed to grow rather than lose evidence. Set false to restore delete-only behavior.
119201
+ */
119202
+ retainPrunedBlocks: boolean$1().default(true),
118037
119203
  /** Maximum number of remote transactions imported by one synchronization pass. */
118038
119204
  syncLimit: number$1().default(DEFAULT_SYNC_LIMIT),
118039
119205
  /**
@@ -118052,8 +119218,10 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
118052
119218
  /** Moniker implemented by this provider instance. */
118053
119219
  moniker = SimpleMempoolRunner.defaultMoniker;
118054
119220
  _blockValidationViewer;
119221
+ _blockViewer;
118055
119222
  _chainContractViewer;
118056
119223
  _deadLetterQueueRunner;
119224
+ _evidenceStoreRunner;
118057
119225
  _finalizationViewer;
118058
119226
  _mempoolViewer;
118059
119227
  _transactionValidationViewer;
@@ -118115,6 +119283,8 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
118115
119283
  this._transactionValidationViewer = await this.locator.getInstance(TransactionValidationViewerMoniker);
118116
119284
  this._deadLetterQueueRunner = await this.locator.tryGetInstance(DeadLetterQueueRunnerMoniker);
118117
119285
  this._mempoolViewer = await this.locator.tryGetInstance(MempoolViewerMoniker);
119286
+ this._evidenceStoreRunner = await this.locator.tryGetInstance(EvidenceStoreRunnerMoniker);
119287
+ this._blockViewer = await this.locator.tryGetInstance(BlockViewerMoniker);
118118
119288
  }
118119
119289
  /** Removes pending blocks that are finalized, expired, or otherwise no longer eligible. */
118120
119290
  async prunePendingBlocks({ batchSize = 10, maxPrune = 1e3, maxCheck = 1e3 } = {}) {
@@ -118155,12 +119325,8 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
118155
119325
  }
118156
119326
  });
118157
119327
  const pruneHashes = invalidBundleHashes(bundles, valid);
118158
- pruned += pruneHashes.length;
118159
119328
  total += batch.length;
118160
- if (pruneHashes.length > 0) {
118161
- await this.pendingBlocksArchivist.delete(pruneHashes);
118162
- this.logger?.info(`[SimpleMempoolRunner] prunePendingBlocks batch deleted ${pruneHashes.length} (batchSize=${batch.length} runningPruned=${pruned} checked=${total})`);
118163
- }
119329
+ if (pruneHashes.length > 0) pruned += await this.deletePrunedBatch(bundles, pruneHashes);
118164
119330
  cursor = nextPruneCursor(batch, pruneHashes, cursor);
118165
119331
  batch = await this.pendingBlocksArchivist.next({
118166
119332
  limit: batchSize,
@@ -118235,7 +119401,9 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
118235
119401
  const bundles = await Promise.all(blocks.map(async ([bw, payloads]) => {
118236
119402
  return hydratedBlockToPayloadBundle([await PayloadBuilder.addHashMeta(bw), await PayloadBuilder.addHashMeta(payloads)]);
118237
119403
  }));
118238
- return (await this.pendingBlocksArchivist.insert(bundles)).map((p) => p._hash);
119404
+ const inserted = await this.pendingBlocksArchivist.insert(bundles);
119405
+ await noteSubmittedCandidates(blocks, this._evidenceStoreRunner);
119406
+ return inserted.map((p) => p._hash);
118239
119407
  }
118240
119408
  /** Submits transactions to the backing provider. */
118241
119409
  async submitTransactions(transactions) {
@@ -118301,6 +119469,30 @@ var SimpleMempoolRunner = class extends AbstractCreatableProvider {
118301
119469
  }
118302
119470
  return all;
118303
119471
  }
119472
+ /**
119473
+ * Deletes a batch of pruned candidates once they are archived, returning how many went.
119474
+ *
119475
+ * Returns zero when the evidence write could not happen: the candidates stay in the pool rather
119476
+ * than being deleted unrecorded. An unbound evidence store means the subsystem is not deployed,
119477
+ * not that a write failed, so those nodes keep pruning as they always have.
119478
+ */
119479
+ async deletePrunedBatch(bundles, pruneHashes) {
119480
+ const evidence = this._evidenceStoreRunner;
119481
+ if (this.options.retainPrunedBlocks && evidence !== void 0) {
119482
+ const pruneSet = new Set(pruneHashes);
119483
+ if (!await archivePrunedCandidates(bundles.filter((bundle3) => pruneSet.has(bundle3._hash)), {
119484
+ blockViewer: this._blockViewer,
119485
+ chainId: await this.chainContractViewer.chainId(),
119486
+ evidence,
119487
+ headNumber: await this.finalizationViewer.headNumber()
119488
+ }, this.logger)) {
119489
+ this.logger?.error(`[SimpleMempoolRunner] prunePendingBlocks retained ${pruneHashes.length} (evidence write unavailable \u2014 candidates kept rather than deleted unrecorded)`);
119490
+ return 0;
119491
+ }
119492
+ }
119493
+ await this.pendingBlocksArchivist.delete(pruneHashes);
119494
+ return pruneHashes.length;
119495
+ }
118304
119496
  async enforceCap() {
118305
119497
  const cap = this.maxPendingTransactions;
118306
119498
  if (cap <= 0) return;
@@ -118794,6 +119986,131 @@ __publicField$18(SimpleStakeEventsViewer, "monikers", [StakeEventsViewerMoniker]
118794
119986
  /** Read, write, or mixed capability surface exposed by the provider. */
118795
119987
  __publicField$18(SimpleStakeEventsViewer, "surface", "node");
118796
119988
  SimpleStakeEventsViewer = __decorateClass$18([creatableProvider()], SimpleStakeEventsViewer);
119989
+ var DEFAULT_INTENT_LOOKBACK_BLOCKS = 1e4;
119990
+ var SCAN_PAGE_SIZE = 100;
119991
+ var SimpleStakeIntentViewerOptionsZod = object$3({
119992
+ /**
119993
+ * How far back from the head an intent search walks when no range is given. Intents are
119994
+ * re-declared on a short cadence, so a window well past that cadence finds the current one
119995
+ * without walking the whole chain.
119996
+ */
119997
+ intentLookbackBlocks: number$1().default(DEFAULT_INTENT_LOOKBACK_BLOCKS) });
119998
+ var SimpleStakeIntentViewer = class extends AbstractCreatableProvider {
119999
+ /** Moniker implemented by this provider instance. */
120000
+ moniker = SimpleStakeIntentViewer.defaultMoniker;
120001
+ _blockViewer;
120002
+ _options;
120003
+ get blockViewer() {
120004
+ return this._blockViewer;
120005
+ }
120006
+ get options() {
120007
+ this._options ??= SimpleStakeIntentViewerOptionsZod.parse(this.config.options);
120008
+ return this._options;
120009
+ }
120010
+ /** Creates the provider instance after its dependencies and configuration have resolved. */
120011
+ async createHandler() {
120012
+ await super.createHandler();
120013
+ this._blockViewer = await this.locator.getInstance(BlockViewerMoniker);
120014
+ }
120015
+ /** The most recent declared intent for an address, or null when none is found in range. */
120016
+ async intentByAddress(address, headOrRange) {
120017
+ const [intent] = await this.qualifiedIntentByAddress(address, headOrRange);
120018
+ return intent;
120019
+ }
120020
+ /** The most recent declared intent for an address, with the chain position it was read at. */
120021
+ async qualifiedIntentByAddress(address, headOrRange) {
120022
+ const [headHash, range] = await this.resolveScanRange(headOrRange);
120023
+ const [low, high] = range;
120024
+ let intent = null;
120025
+ for (let hi = high; hi >= low && intent === null; hi -= SCAN_PAGE_SIZE) {
120026
+ const limit = Math.min(SCAN_PAGE_SIZE, hi - low + 1);
120027
+ const blocks = await this.blockViewer.blocksByNumber(asXL1BlockNumber(hi, true), limit);
120028
+ for (const block of blocks.toSorted((a, b) => b[0].block - a[0].block)) {
120029
+ const found = block[1].find((payload) => isChainStakeIntent(payload) && payload.from === address);
120030
+ if (isChainStakeIntent(found)) {
120031
+ intent = found;
120032
+ break;
120033
+ }
120034
+ }
120035
+ }
120036
+ return [intent, {
120037
+ head: headHash,
120038
+ range
120039
+ }];
120040
+ }
120041
+ /** Turns an optional head or range into the concrete window this scan walks. */
120042
+ async resolveScanRange(headOrRange) {
120043
+ const currentBlock = await this.blockViewer.currentBlock();
120044
+ if (Array.isArray(headOrRange)) return [currentBlock[0]._hash, headOrRange];
120045
+ const head = headOrRange === void 0 ? currentBlock[0] : assertEx$1((await this.blockViewer.blockByHash(headOrRange))?.[0], () => `Specified a head that is not in the chain [${headOrRange}]`);
120046
+ const high = head.block;
120047
+ const low = Math.max(0, high - this.options.intentLookbackBlocks);
120048
+ return [head._hash, asXL1BlockRange([asXL1BlockNumber(low, true), high], true)];
120049
+ }
120050
+ };
120051
+ /** Connection kinds supported by this provider. */
120052
+ __publicField$18(SimpleStakeIntentViewer, "connectionTypes", [
120053
+ "lmdb",
120054
+ "mongo",
120055
+ "memory"
120056
+ ]);
120057
+ /** Primary moniker used to resolve this provider. */
120058
+ __publicField$18(SimpleStakeIntentViewer, "defaultMoniker", StakeIntentViewerMoniker);
120059
+ /** Provider monikers that must resolve before this provider can be created. */
120060
+ __publicField$18(SimpleStakeIntentViewer, "dependencies", [BlockViewerMoniker]);
120061
+ /** Provider monikers implemented by this provider class. */
120062
+ __publicField$18(SimpleStakeIntentViewer, "monikers", [StakeIntentViewerMoniker]);
120063
+ /** Read, write, or mixed capability surface exposed by the provider. */
120064
+ __publicField$18(SimpleStakeIntentViewer, "surface", "node");
120065
+ SimpleStakeIntentViewer = __decorateClass$18([creatableProvider()], SimpleStakeIntentViewer);
120066
+ var SimpleStakeSnapshotViewer = class extends AbstractCreatableProvider {
120067
+ /** Moniker implemented by this provider instance. */
120068
+ moniker = SimpleStakeSnapshotViewer.defaultMoniker;
120069
+ _stakeViewer;
120070
+ get stakeViewer() {
120071
+ return this._stakeViewer;
120072
+ }
120073
+ /** Stake on an address that was active at an EVM height. */
120074
+ async activeByStakedAt(staked, evmBlock) {
120075
+ return sumPositions(await this.positionsByStakedAt(staked, evmBlock), (position) => isPositionActiveAt(position, evmBlock));
120076
+ }
120077
+ /** Stake on an address that was still at risk at an EVM height. */
120078
+ async atRiskByStakedAt(staked, evmBlock) {
120079
+ return sumPositions(await this.positionsByStakedAt(staked, evmBlock), (position) => isPositionAtRiskAt(position, evmBlock));
120080
+ }
120081
+ /** Creates the provider instance after its dependencies and configuration have resolved. */
120082
+ async createHandler() {
120083
+ await super.createHandler();
120084
+ this._stakeViewer = await this.locator.getInstance(StakeViewerMoniker);
120085
+ }
120086
+ /** Every position on an address that existed as of an EVM height. */
120087
+ async positionsByStakedAt(staked, evmBlock) {
120088
+ return (await this.stakeViewer.stakesByStaked(staked)).filter((position) => position.addBlock <= evmBlock);
120089
+ }
120090
+ /** Active stake at an EVM height that has also been in place for at least `minAgeBlocks`. */
120091
+ async seasonedActiveByStakedAt(staked, evmBlock, minAgeBlocks) {
120092
+ return sumPositions(await this.positionsByStakedAt(staked, evmBlock), (position) => isPositionSeasonedAt(position, evmBlock, minAgeBlocks));
120093
+ }
120094
+ /** The seasoned portion of an address's stake that the address placed on itself. */
120095
+ async seasonedSelfBondAt(address, evmBlock, minAgeBlocks) {
120096
+ return sumPositions(await this.positionsByStakedAt(address, evmBlock), (position) => isSelfBond(position, address) && isPositionSeasonedAt(position, evmBlock, minAgeBlocks));
120097
+ }
120098
+ /** Stake an address placed on itself, active at an EVM height. */
120099
+ async selfBondAt(address, evmBlock) {
120100
+ return sumPositions(await this.positionsByStakedAt(address, evmBlock), (position) => isSelfBond(position, address) && isPositionActiveAt(position, evmBlock));
120101
+ }
120102
+ };
120103
+ /** Connection kinds supported by this provider. */
120104
+ __publicField$18(SimpleStakeSnapshotViewer, "connectionTypes", ["evm-rpc", "memory"]);
120105
+ /** Primary moniker used to resolve this provider. */
120106
+ __publicField$18(SimpleStakeSnapshotViewer, "defaultMoniker", StakeSnapshotViewerMoniker);
120107
+ /** Provider monikers that must resolve before this provider can be created. */
120108
+ __publicField$18(SimpleStakeSnapshotViewer, "dependencies", [StakeViewerMoniker]);
120109
+ /** Provider monikers implemented by this provider class. */
120110
+ __publicField$18(SimpleStakeSnapshotViewer, "monikers", [StakeSnapshotViewerMoniker]);
120111
+ /** Read, write, or mixed capability surface exposed by the provider. */
120112
+ __publicField$18(SimpleStakeSnapshotViewer, "surface", "node");
120113
+ SimpleStakeSnapshotViewer = __decorateClass$18([creatableProvider()], SimpleStakeSnapshotViewer);
118797
120114
  var SimpleStakeTotalsViewer = class extends AbstractCreatableProvider {
118798
120115
  /** Moniker implemented by this provider instance. */
118799
120116
  moniker = SimpleStakeTotalsViewer.defaultMoniker;
@@ -120589,7 +121906,7 @@ function getOriginalId(rawRequest) {
120589
121906
  return [void 0, false];
120590
121907
  }
120591
121908
  //#endregion
120592
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_0413c4361bf30f6daaff87ca8a579dc5/node_modules/@xyo-network/xl1-sdk/dist/neutral/rpc.mjs
121909
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_203014cdf26a7fb134df680684c24d7b/node_modules/@xyo-network/xl1-sdk/dist/neutral/rpc.mjs
120593
121910
  var __defProp$17 = Object.defineProperty;
120594
121911
  var __getOwnPropDesc$17 = Object.getOwnPropertyDescriptor;
120595
121912
  var __defNormalProp$17 = (obj, key, value) => key in obj ? __defProp$17(obj, key, {
@@ -221896,7 +223213,7 @@ var BaseMongoSdk = class {
221896
223213
  }
221897
223214
  };
221898
223215
  //#endregion
221899
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-driver-mongodb@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zo_7ea08ed350395a1352e8a87e4b6fb312/node_modules/@xyo-network/xl1-driver-mongodb/dist/neutral/index.mjs
223216
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-driver-mongodb@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zo_76a0ac5a14e58016ccb3a46059c3fe3b/node_modules/@xyo-network/xl1-driver-mongodb/dist/neutral/index.mjs
221900
223217
  var __defProp$15 = Object.defineProperty;
221901
223218
  var __getOwnPropDesc$15 = Object.getOwnPropertyDescriptor;
221902
223219
  var __defNormalProp$15 = (obj, key, value) => key in obj ? __defProp$15(obj, key, {
@@ -226947,7 +228264,27 @@ var createBootstrapHead = async (account, chainId, genesisBlockRewardAmount, gen
226947
228264
  chain.push(producerDeclarationBlock);
226948
228265
  return chain;
226949
228266
  };
226950
- async function processPendingBlocks({ blockValidationViewer, blockViewer, context, logger, mempoolViewer, finalizationRunner, allowedProducers, backoffMs, minCandidates, deadLetterQueueRunner }) {
228267
+ function hasMessage(value) {
228268
+ return typeof value === "object" && value !== null && "message" in value;
228269
+ }
228270
+ async function reportRejectedBlock(deadLetterQueueRunner, block, result, observer) {
228271
+ const rejection = {
228272
+ schema: BlockRejectionSchema$1,
228273
+ block,
228274
+ errors: Array.isArray(result) ? result.map((error) => ({
228275
+ hash: block[0]._hash,
228276
+ name: "BlockValidationError",
228277
+ message: String(hasMessage(error) ? error.message : error)
228278
+ })) : [{
228279
+ hash: block[0]._hash,
228280
+ name: "BlockValidationError"
228281
+ }],
228282
+ rejector: observer?.address ?? "validator"
228283
+ };
228284
+ const signed = observer === void 0 ? void 0 : await buildSignedBlockRejection(rejection, observer);
228285
+ await deadLetterQueueRunner.rejectBlock(rejection, signed);
228286
+ }
228287
+ async function processPendingBlocks({ blockValidationViewer, blockViewer, context, logger, mempoolViewer, finalizationRunner, allowedProducers, backoffMs, minCandidates, deadLetterQueueRunner, observer }) {
226951
228288
  const start = Date.now();
226952
228289
  const currentBlock = await blockViewer.currentBlock();
226953
228290
  const headSelector = new ChainHeadSelector({
@@ -226983,22 +228320,7 @@ async function processPendingBlocks({ blockValidationViewer, blockViewer, contex
226983
228320
  if (isSignedHydratedBlockWithHashMeta$1(result)) blocksToFinalize.push(block);
226984
228321
  else {
226985
228322
  logger?.error("Block validation failed", block[0].block, block[0]._hash, JSON.stringify(result, null, 2));
226986
- if (deadLetterQueueRunner) {
226987
- const errors = Array.isArray(result) ? result.map((e) => ({
226988
- hash: block[0]._hash,
226989
- name: "BlockValidationError",
226990
- message: String(e.message ?? e)
226991
- })) : [{
226992
- hash: block[0]._hash,
226993
- name: "BlockValidationError"
226994
- }];
226995
- await deadLetterQueueRunner.rejectBlock({
226996
- schema: BlockRejectionSchema$1,
226997
- block,
226998
- errors,
226999
- rejector: "validator"
227000
- });
227001
- }
228323
+ if (deadLetterQueueRunner) await reportRejectedBlock(deadLetterQueueRunner, block, result, observer);
227002
228324
  }
227003
228325
  }
227004
228326
  logger?.info("Validated new HeadBlock head from (block) in", `${Date.now() - start}ms`, newHeadBlock.block, "to", oldHeadBlock?.block);
@@ -227796,7 +229118,8 @@ var FinalizerActor = class extends ChainActor {
227796
229118
  allowedProducers: this.allowedProducers,
227797
229119
  backoffMs: this.backoffMs,
227798
229120
  minCandidates: this.minCandidates,
227799
- deadLetterQueueRunner: this._deadLetterQueueRunner
229121
+ deadLetterQueueRunner: this._deadLetterQueueRunner,
229122
+ observer: this.account
227800
229123
  });
227801
229124
  }, {
227802
229125
  ...this.context,
@@ -227987,6 +229310,7 @@ var __decorateClass$8 = (decorators, target, key, kind) => {
227987
229310
  };
227988
229311
  var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
227989
229312
  var DEFAULT_MEMPOOL_BLOCK_PRUNE_INTERVAL = 1e3;
229313
+ var DEFAULT_MEMPOOL_EVIDENCE_PRUNE_INTERVAL = 6e4;
227990
229314
  var DEFAULT_MEMPOOL_TRANSACTION_PRUNE_INTERVAL = 1e3;
227991
229315
  var toBooleanDefaultFalse = (v) => v === true || v === "true" || v === "1" || v === 1;
227992
229316
  var MempoolConfigZod = /* @__PURE__ */ extend(HostActorIdentityZod, {
@@ -228000,6 +229324,11 @@ var MempoolConfigZod = /* @__PURE__ */ extend(HostActorIdentityZod, {
228000
229324
  title: "mempool.demotionThreshold",
228001
229325
  type: "number"
228002
229326
  }),
229327
+ evidencePruneInterval: (/* @__PURE__ */ _default$1(/* @__PURE__ */ number$4(), DEFAULT_MEMPOOL_EVIDENCE_PRUNE_INTERVAL)).register(globalRegistry, {
229328
+ description: "The interval time (in milliseconds) between evidence retention sweeps. Evidence is retained for windows measured in days, so this sweeps far less often than the pending pools.",
229329
+ title: "mempool.evidencePruneInterval",
229330
+ type: "number"
229331
+ }),
228003
229332
  maxPendingTransactions: (/* @__PURE__ */ _default$1((/* @__PURE__ */ number$4()).check(/* @__PURE__ */ _multipleOf(1), /* @__PURE__ */ _nonnegative()), 0)).register(globalRegistry, {
228004
229333
  description: "Maximum number of pending transactions in the pool. When exceeded, demoted transactions are evicted first, then oldest by sequence. 0 disables the cap.",
228005
229334
  title: "mempool.maxPendingTransactions",
@@ -228107,12 +229436,16 @@ async function getServer$1(context) {
228107
229436
  return server;
228108
229437
  }
228109
229438
  var MempoolActor = class extends ChainActor {
229439
+ _evidenceStoreRunner;
228110
229440
  _mempoolRunner;
228111
229441
  _mempoolViewer;
228112
229442
  server;
228113
229443
  get blockPruneInterval() {
228114
229444
  return this.params.config.blockPruneInterval;
228115
229445
  }
229446
+ get evidencePruneInterval() {
229447
+ return this.params.config.evidencePruneInterval;
229448
+ }
228116
229449
  get mempoolRunner() {
228117
229450
  return this._mempoolRunner;
228118
229451
  }
@@ -228125,6 +229458,7 @@ var MempoolActor = class extends ChainActor {
228125
229458
  async createHandler() {
228126
229459
  await super.createHandler();
228127
229460
  this._mempoolRunner = await this.locator.getInstance(MempoolRunnerMoniker$1);
229461
+ this._evidenceStoreRunner = await this.locator.tryGetInstance(EvidenceStoreRunnerMoniker$1);
228128
229462
  if (this.serveRpc) this._mempoolViewer = assertEx$1(await this.locator.tryGetInstance(MempoolViewerMoniker$1), () => "[MempoolActor] serveRpc requires a MempoolViewer provider — bind MempoolViewer to the mempool store connection");
228129
229463
  }
228130
229464
  async startHandler() {
@@ -228139,6 +229473,9 @@ var MempoolActor = class extends ChainActor {
228139
229473
  this.registerTimer("mempoolTransactionPrune", async () => {
228140
229474
  await this.prunePendingTransactions();
228141
229475
  }, 2e3, this.transactionPruneInterval);
229476
+ this.registerTimer("mempoolEvidencePrune", async () => {
229477
+ await this.pruneEvidence();
229478
+ }, 2e3, this.evidencePruneInterval);
228142
229479
  }
228143
229480
  async stopHandler() {
228144
229481
  await super.stopHandler();
@@ -228148,6 +229485,31 @@ var MempoolActor = class extends ChainActor {
228148
229485
  await this.prunePendingBlocks();
228149
229486
  await this.prunePendingTransactions();
228150
229487
  }
229488
+ /**
229489
+ * Sweeps evidence whose retention has expired.
229490
+ *
229491
+ * This lives with the pool sweeps rather than in the finalizer: the finalizer tick is
229492
+ * consensus-critical and time-budgeted, while store maintenance is exactly this actor's job.
229493
+ * Failures are logged and swallowed — over-retained evidence is harmless, but a throwing timer
229494
+ * would take the pool sweeps down with it.
229495
+ */
229496
+ async pruneEvidence() {
229497
+ if (this._evidenceStoreRunner === void 0) return;
229498
+ await this.spanAsync("mempool:pruneEvidence", async () => {
229499
+ try {
229500
+ await this._evidenceStoreRunner?.pruneEvidence({
229501
+ batchSize: 100,
229502
+ maxCheck: 1e4,
229503
+ maxPrune: 5e3
229504
+ });
229505
+ } catch (error) {
229506
+ this.logger?.error(`[MempoolActor] Error pruning evidence: ${error.message}`);
229507
+ }
229508
+ }, {
229509
+ ...this.context,
229510
+ timeBudgetLimit: 5e3
229511
+ });
229512
+ }
228151
229513
  async prunePendingBlocks() {
228152
229514
  await this.spanAsync("mempool:prunePendingBlocks", async () => {
228153
229515
  try {
@@ -228197,7 +229559,7 @@ var MempoolActor = class extends ChainActor {
228197
229559
  }
228198
229560
  };
228199
229561
  __publicField$8(MempoolActor, "dependencies", [MempoolRunnerMoniker$1]);
228200
- __publicField$8(MempoolActor, "optionalDependencies", [MempoolViewerMoniker$1]);
229562
+ __publicField$8(MempoolActor, "optionalDependencies", [MempoolViewerMoniker$1, EvidenceStoreRunnerMoniker$1]);
228201
229563
  MempoolActor = __decorateClass$8([creatable()], MempoolActor);
228202
229564
  var mempoolActorDescriptor = {
228203
229565
  configParser: MempoolConfigZod,
@@ -236185,7 +237547,7 @@ function withDeprecationWarning$1(module, host, options = {}) {
236185
237547
  return module;
236186
237548
  }
236187
237549
  //#endregion
236188
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_f7cf1f859b51f67ea8ae31d8e591aa95/node_modules/@xyo-network/xl1-sdk/dist/node/providers.mjs
237550
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-sdk@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@4.4.3__@o_3d1fd2739949213d427b87ad651353a9/node_modules/@xyo-network/xl1-sdk/dist/node/providers.mjs
236189
237551
  var __defProp$3 = Object.defineProperty;
236190
237552
  var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
236191
237553
  var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, {
@@ -237142,6 +238504,7 @@ EvmStakeViewer = __decorateClass$3([creatableProvider$1()], EvmStakeViewer);
237142
238504
  var SimpleDeadLetterQueueRunner = class extends AbstractCreatableProvider$1 {
237143
238505
  /** Moniker implemented by this provider instance. */
237144
238506
  moniker = SimpleDeadLetterQueueRunner.defaultMoniker;
238507
+ _evidenceArchivist;
237145
238508
  _rejectedBlocksArchivist;
237146
238509
  _rejectedTransactionsArchivist;
237147
238510
  get rejectedBlocksArchivist() {
@@ -237156,6 +238519,7 @@ var SimpleDeadLetterQueueRunner = class extends AbstractCreatableProvider$1 {
237156
238519
  const connection = SimpleDeadLetterQueueRunner.requireBoundConnection(this.config);
237157
238520
  this._rejectedBlocksArchivist = await connectArchivist$1(connection, { name: REJECTED_BLOCKS_ARCHIVIST_ROLE });
237158
238521
  this._rejectedTransactionsArchivist = await connectArchivist$1(connection, { name: REJECTED_TRANSACTIONS_ARCHIVIST_ROLE });
238522
+ this._evidenceArchivist = await connectArchivist$1(connection, { name: EVIDENCE_ARCHIVIST_ROLE$1 });
237159
238523
  }
237160
238524
  /** Removes data through the prune rejected blocks operation. */
237161
238525
  async pruneRejectedBlocks({ batchSize = 10, maxPrune = 1e3, maxCheck = 1e3 } = {}) {
@@ -237208,9 +238572,14 @@ var SimpleDeadLetterQueueRunner = class extends AbstractCreatableProvider$1 {
237208
238572
  return [pruned, total];
237209
238573
  }
237210
238574
  /** Rejects data through the reject block operation. */
237211
- async rejectBlock(rejection) {
238575
+ async rejectBlock(rejection, signed) {
237212
238576
  const withMeta = await PayloadBuilder$1.addHashMeta(rejection);
237213
- return (await this.rejectedBlocksArchivist.insert([withMeta])).length > 0;
238577
+ const inserted = await this.rejectedBlocksArchivist.insert([withMeta]);
238578
+ if (signed !== void 0 && this._evidenceArchivist !== void 0) {
238579
+ const [boundWitness, payloads] = signed;
238580
+ await this._evidenceArchivist.insert([boundWitness, ...payloads]);
238581
+ }
238582
+ return inserted.length > 0;
237214
238583
  }
237215
238584
  /** Rejects data through the reject transaction operation. */
237216
238585
  async rejectTransaction(rejection) {
@@ -238570,7 +239939,7 @@ __publicField$3(RestNetworkStakeStepRewardsByPositionViewer, "monikers", [Networ
238570
239939
  __publicField$3(RestNetworkStakeStepRewardsByPositionViewer, "surface", "node");
238571
239940
  RestNetworkStakeStepRewardsByPositionViewer = __decorateClass$3([creatableProvider$1()], RestNetworkStakeStepRewardsByPositionViewer);
238572
239941
  //#endregion
238573
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-s3-providers@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@_b6b591cbefe2e1c1df4fc70aefe9ca33/node_modules/@xyo-network/xl1-s3-providers/dist/node/index.mjs
239942
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-s3-providers@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod@_d1587aaa1f949f5fa8d7aff6c657231b/node_modules/@xyo-network/xl1-s3-providers/dist/node/index.mjs
238574
239943
  var __defProp$2 = Object.defineProperty;
238575
239944
  var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
238576
239945
  var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, {
@@ -239870,6 +241239,11 @@ var STORE_SPECS = {
239870
241239
  deletable: true,
239871
241240
  maxEntries: 5e3,
239872
241241
  storeName: "rejected_transactions"
241242
+ },
241243
+ [EVIDENCE_ARCHIVIST_ROLE$1]: {
241244
+ deletable: true,
241245
+ maxEntries: 5e4,
241246
+ storeName: "chain_evidence"
239873
241247
  }
239874
241248
  };
239875
241249
  function archivistStoreSpec(role) {
@@ -240300,6 +241674,8 @@ function devStoreProviderBindings(connection) {
240300
241674
  BlockViewer: { connection },
240301
241675
  DeadLetterQueueRunner: { connection },
240302
241676
  DeadLetterQueueViewer: { connection },
241677
+ EvidenceStoreRunner: { connection },
241678
+ EvidenceViewer: { connection },
240303
241679
  FinalizationRunner: { connection },
240304
241680
  FinalizationViewer: { connection },
240305
241681
  MempoolRunner: { connection },
@@ -240487,7 +241863,9 @@ var storeProviders = [
240487
241863
  SimpleBlockValidationViewer$1,
240488
241864
  SimpleTransactionValidationViewer$1,
240489
241865
  SimpleDeadLetterQueueRunner$1,
240490
- SimpleDeadLetterQueueViewer$1
241866
+ SimpleDeadLetterQueueViewer$1,
241867
+ SimpleEvidenceStoreRunner$1,
241868
+ SimpleEvidenceViewer$1
240491
241869
  ];
240492
241870
  var jsonRpcProviders = [
240493
241871
  JsonRpcAccountBalanceViewer$1,
@@ -241164,7 +242542,11 @@ var SELECTED_STORE_ARCHIVIST_REQUIREMENTS = [
241164
242542
  {
241165
242543
  moniker: "MempoolRunner",
241166
242544
  provider: "SimpleMempoolRunner",
241167
- roles: [PENDING_BLOCKS_ARCHIVIST_ROLE$1, PENDING_TRANSACTIONS_ARCHIVIST_ROLE$1]
242545
+ roles: [
242546
+ PENDING_BLOCKS_ARCHIVIST_ROLE$1,
242547
+ PENDING_TRANSACTIONS_ARCHIVIST_ROLE$1,
242548
+ EVIDENCE_ARCHIVIST_ROLE$1
242549
+ ]
241168
242550
  },
241169
242551
  {
241170
242552
  moniker: "MempoolViewer",
@@ -241185,6 +242567,16 @@ var SELECTED_STORE_ARCHIVIST_REQUIREMENTS = [
241185
242567
  moniker: "BlockRunner",
241186
242568
  provider: "SimpleBlockRunner",
241187
242569
  roles: [REJECTED_TRANSACTIONS_ARCHIVIST_ROLE]
242570
+ },
242571
+ {
242572
+ moniker: "EvidenceStoreRunner",
242573
+ provider: "SimpleEvidenceStoreRunner",
242574
+ roles: [EVIDENCE_ARCHIVIST_ROLE$1]
242575
+ },
242576
+ {
242577
+ moniker: "EvidenceViewer",
242578
+ provider: "SimpleEvidenceViewer",
242579
+ roles: [EVIDENCE_ARCHIVIST_ROLE$1]
241188
242580
  }
241189
242581
  ];
241190
242582
  async function ownSelectedStoreArchivists(context, plan) {
@@ -241409,7 +242801,7 @@ async function provisionStoreResourcesIfNeeded(ctx, normalizedConfig, plan, opti
241409
242801
  return await provisionStoreResources(ctx.actorContext, wallet, { onInsecureGenesisConfirm: options.onInsecureGenesisConfirm });
241410
242802
  }
241411
242803
  function planUsesLocalStoreResources(plan) {
241412
- return plan.selected.some((descriptor) => descriptor.id.includes("BlockValidation") || descriptor.id.includes("TransactionValidation") || descriptor.id.includes("DeadLetterQueue") || descriptor.id.includes("RejectedTransactionsArchivist"));
242804
+ return plan.selected.some((descriptor) => descriptor.id.includes("BlockValidation") || descriptor.id.includes("TransactionValidation") || descriptor.id.includes("DeadLetterQueue") || descriptor.id.includes("Evidence") || descriptor.id.includes("RejectedTransactionsArchivist"));
241413
242805
  }
241414
242806
  function definedEntries(source) {
241415
242807
  return Object.fromEntries(Object.entries(source).filter(([, value]) => value !== void 0));
@@ -241631,7 +243023,7 @@ async function tryParseConfig(options) {
241631
243023
  return finalize ? finalizeConfig(section) : section;
241632
243024
  }
241633
243025
  //#endregion
241634
- //#region ../../node_modules/.pnpm/@xyo-network+xl1-system-status@5.1.2_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod_ac032ba6516cd0b2c3030806867e5738/node_modules/@xyo-network/xl1-system-status/dist/node/index.mjs
243026
+ //#region ../../node_modules/.pnpm/@xyo-network+xl1-system-status@5.1.4_@ariestools+sdk@8.1.8_@opentelemetry+api@1.9.1_zod_25b23af0b6ca14cc816b75ee0e1d9eeb/node_modules/@xyo-network/xl1-system-status/dist/node/index.mjs
241635
243027
  function resolveStatusProbe(status, url) {
241636
243028
  switch (url) {
241637
243029
  case "/healthz": {
@@ -242815,8 +244207,8 @@ $0 <command> [options]`).parserConfiguration({
242815
244207
  }
242816
244208
  }).help().alias("help", "h").version(fullVersion2);
242817
244209
  }
242818
- var version = isDefined$1("5.0.2") ? "5.0.2" : "unknown";
242819
- var gitHash = isDefined$1("300c06769") ? "300c06769" : "";
244210
+ var version = isDefined$1("5.0.3") ? "5.0.3" : "unknown";
244211
+ var gitHash = isDefined$1("44a934257") ? "44a934257" : "";
242820
244212
  var fullVersion = gitHash.length > 0 ? `${version} (${gitHash})` : version;
242821
244213
  var mapXl1CliFailure = createSysExitFailureMapper();
242822
244214
  var defaultDependencies2 = {