@aztec/prover-client 0.0.1-commit.343b43af6 → 0.0.1-commit.350e0a4d
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/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +16 -2
- package/dest/light/lightweight_checkpoint_builder.d.ts +1 -1
- package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -1
- package/dest/light/lightweight_checkpoint_builder.js +19 -5
- package/dest/mocks/test_context.d.ts +11 -11
- package/dest/mocks/test_context.d.ts.map +1 -1
- package/dest/mocks/test_context.js +26 -28
- package/dest/orchestrator/block-building-helpers.d.ts +1 -1
- package/dest/orchestrator/checkpoint-proving-state.d.ts +20 -36
- package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/checkpoint-proving-state.js +22 -120
- package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts +161 -0
- package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts.map +1 -0
- package/dest/orchestrator/{orchestrator.js → checkpoint-sub-tree-orchestrator.js} +267 -448
- package/dest/orchestrator/chonk-cache.d.ts +39 -0
- package/dest/orchestrator/chonk-cache.d.ts.map +1 -0
- package/dest/orchestrator/chonk-cache.js +80 -0
- package/dest/orchestrator/index.d.ts +4 -2
- package/dest/orchestrator/index.d.ts.map +1 -1
- package/dest/orchestrator/index.js +3 -1
- package/dest/orchestrator/proving-scheduler.d.ts +81 -0
- package/dest/orchestrator/proving-scheduler.d.ts.map +1 -0
- package/dest/orchestrator/proving-scheduler.js +120 -0
- package/dest/orchestrator/top-tree-orchestrator.d.ts +88 -0
- package/dest/orchestrator/top-tree-orchestrator.d.ts.map +1 -0
- package/dest/orchestrator/top-tree-orchestrator.js +232 -0
- package/dest/orchestrator/top-tree-proving-state.d.ts +61 -0
- package/dest/orchestrator/top-tree-proving-state.d.ts.map +1 -0
- package/dest/orchestrator/top-tree-proving-state.js +185 -0
- package/dest/orchestrator/tx-proving-state.d.ts +3 -3
- package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
- package/dest/prover-client/prover-client.d.ts +61 -4
- package/dest/prover-client/prover-client.d.ts.map +1 -1
- package/dest/prover-client/prover-client.js +54 -7
- package/dest/proving_broker/broker_prover_facade.d.ts +3 -3
- package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
- package/dest/proving_broker/broker_prover_facade.js +10 -16
- package/dest/proving_broker/config.d.ts +8 -72
- package/dest/proving_broker/config.d.ts.map +1 -1
- package/dest/proving_broker/config.js +2 -2
- package/dest/proving_broker/index.d.ts +2 -1
- package/dest/proving_broker/index.d.ts.map +1 -1
- package/dest/proving_broker/index.js +1 -0
- package/dest/proving_broker/proving_broker.d.ts +2 -2
- package/dest/proving_broker/proving_broker.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker.js +32 -7
- package/dest/proving_broker/proving_broker_database/persisted.js +2 -2
- package/dest/proving_broker/rpc.d.ts +3 -1
- package/dest/proving_broker/rpc.d.ts.map +1 -1
- package/dest/proving_broker/rpc.js +80 -24
- package/dest/test/epoch_settlement.d.ts +36 -0
- package/dest/test/epoch_settlement.d.ts.map +1 -0
- package/dest/test/epoch_settlement.js +52 -0
- package/dest/test/index.d.ts +2 -0
- package/dest/test/index.d.ts.map +1 -0
- package/dest/test/index.js +1 -0
- package/dest/test/mock_prover.d.ts +4 -4
- package/dest/test/mock_prover.js +2 -2
- package/package.json +19 -18
- package/src/config.ts +18 -2
- package/src/light/lightweight_checkpoint_builder.ts +23 -6
- package/src/mocks/test_context.ts +25 -41
- package/src/orchestrator/checkpoint-proving-state.ts +21 -162
- package/src/orchestrator/{orchestrator.ts → checkpoint-sub-tree-orchestrator.ts} +415 -658
- package/src/orchestrator/chonk-cache.ts +99 -0
- package/src/orchestrator/index.ts +8 -1
- package/src/orchestrator/proving-scheduler.ts +160 -0
- package/src/orchestrator/top-tree-orchestrator.ts +384 -0
- package/src/orchestrator/top-tree-proving-state.ts +219 -0
- package/src/orchestrator/tx-proving-state.ts +3 -3
- package/src/prover-client/prover-client.ts +128 -18
- package/src/proving_broker/broker_prover_facade.ts +10 -18
- package/src/proving_broker/config.ts +2 -1
- package/src/proving_broker/index.ts +1 -0
- package/src/proving_broker/proving_broker.ts +27 -5
- package/src/proving_broker/proving_broker_database/persisted.ts +2 -2
- package/src/proving_broker/rpc.ts +36 -24
- package/src/test/epoch_settlement.ts +82 -0
- package/src/test/index.ts +1 -0
- package/src/test/mock_prover.ts +2 -2
- package/dest/orchestrator/epoch-proving-state.d.ts +0 -75
- package/dest/orchestrator/epoch-proving-state.d.ts.map +0 -1
- package/dest/orchestrator/epoch-proving-state.js +0 -269
- package/dest/orchestrator/orchestrator.d.ts +0 -130
- package/dest/orchestrator/orchestrator.d.ts.map +0 -1
- package/dest/prover-client/server-epoch-prover.d.ts +0 -32
- package/dest/prover-client/server-epoch-prover.d.ts.map +0 -1
- package/dest/prover-client/server-epoch-prover.js +0 -40
- package/src/orchestrator/epoch-proving-state.ts +0 -380
- package/src/prover-client/server-epoch-prover.ts +0 -69
|
@@ -370,52 +370,49 @@ function applyDecs2203RFactory() {
|
|
|
370
370
|
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
371
371
|
return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
|
|
372
372
|
}
|
|
373
|
-
var _dec, _dec1, _dec2, _dec3,
|
|
374
|
-
import { L1_TO_L2_MSG_SUBTREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
373
|
+
var _dec, _dec1, _dec2, _dec3, _initProto;
|
|
374
|
+
import { L1_TO_L2_MSG_SUBTREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH, NUM_BASE_PARITY_PER_ROOT_PARITY } from '@aztec/constants';
|
|
375
375
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
376
|
-
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
377
|
-
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
378
376
|
import { AbortError } from '@aztec/foundation/error';
|
|
379
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
380
377
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
381
|
-
import { SerialQueue } from '@aztec/foundation/queue';
|
|
382
378
|
import { assertLength } from '@aztec/foundation/serialize';
|
|
383
|
-
import {
|
|
384
|
-
import {
|
|
385
|
-
import { BlockRootEmptyTxFirstRollupPrivateInputs, BlockRootFirstRollupPrivateInputs, BlockRootSingleTxFirstRollupPrivateInputs, BlockRootSingleTxRollupPrivateInputs, CheckpointRootSingleBlockRollupPrivateInputs, PrivateTxBaseRollupPrivateInputs } from '@aztec/stdlib/rollup';
|
|
379
|
+
import { appendL1ToL2MessagesToTree } from '@aztec/stdlib/messaging';
|
|
380
|
+
import { BlockRootEmptyTxFirstRollupPrivateInputs, BlockRootFirstRollupPrivateInputs, BlockRootSingleTxFirstRollupPrivateInputs, BlockRootSingleTxRollupPrivateInputs, PrivateTxBaseRollupPrivateInputs } from '@aztec/stdlib/rollup';
|
|
386
381
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
387
382
|
import { Attributes, getTelemetryClient, trackSpan, wrapCallbackInSpan } from '@aztec/telemetry-client';
|
|
388
383
|
import { inspect } from 'util';
|
|
389
384
|
import { buildHeaderFromCircuitOutputs, getLastSiblingPath, getPublicChonkVerifierPrivateInputsFromTx, getRootTreeSiblingPath, getSubtreeSiblingPath, getTreeSnapshot, insertSideEffectsAndBuildBaseRollupHints, validatePartialState, validateTx } from './block-building-helpers.js';
|
|
390
|
-
import {
|
|
385
|
+
import { CheckpointProvingState } from './checkpoint-proving-state.js';
|
|
391
386
|
import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
|
|
387
|
+
import { ProvingScheduler } from './proving-scheduler.js';
|
|
392
388
|
import { TxProvingState } from './tx-proving-state.js';
|
|
393
|
-
_dec = trackSpan('
|
|
389
|
+
_dec = trackSpan('CheckpointSubTreeOrchestrator.startNewBlock', (blockNumber)=>({
|
|
394
390
|
[Attributes.BLOCK_NUMBER]: blockNumber
|
|
395
|
-
})), _dec1 = trackSpan('
|
|
391
|
+
})), _dec1 = trackSpan('CheckpointSubTreeOrchestrator.addTxs', (txs)=>({
|
|
396
392
|
[Attributes.BLOCK_TXS_COUNT]: txs.length
|
|
397
|
-
})), _dec2 = trackSpan('
|
|
393
|
+
})), _dec2 = trackSpan('CheckpointSubTreeOrchestrator.setBlockCompleted', (blockNumber)=>({
|
|
398
394
|
[Attributes.BLOCK_NUMBER]: blockNumber
|
|
399
|
-
})),
|
|
395
|
+
})), _dec3 = trackSpan('CheckpointSubTreeOrchestrator.prepareBaseRollupInputs', (tx)=>({
|
|
400
396
|
[Attributes.TX_HASH]: tx.hash.toString()
|
|
401
397
|
}));
|
|
402
398
|
/**
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
* 4. Once a transaction is proven, it will be incorporated into a merge proof
|
|
408
|
-
* 5. Merge proofs are produced at each level of the tree until the root proof is produced
|
|
399
|
+
* Orchestrates block-level proving for a single checkpoint, stopping at the boundary
|
|
400
|
+
* where checkpoint root rollup would otherwise begin. Used by the per-checkpoint
|
|
401
|
+
* `CheckpointProver` in production; the top-tree orchestrator then composes the
|
|
402
|
+
* sub-tree's block proofs into the epoch proof.
|
|
409
403
|
*
|
|
410
|
-
*
|
|
411
|
-
|
|
412
|
-
*
|
|
413
|
-
|
|
404
|
+
* Wiring: a single-checkpoint mini-proving session is owned by the constructor. The
|
|
405
|
+
* canonical way to obtain a fully-started sub-tree is the `start` static factory,
|
|
406
|
+
* which also drives the single internal `startCheckpoint` call. The sub-tree never
|
|
407
|
+
* escalates past the checkpoint root boundary; `getSubTreeResult()` resolves once
|
|
408
|
+
* every block-level proof in the checkpoint's tree is ready.
|
|
409
|
+
*/ export class CheckpointSubTreeOrchestrator extends ProvingScheduler {
|
|
414
410
|
dbProvider;
|
|
415
411
|
prover;
|
|
416
412
|
proverId;
|
|
413
|
+
chonkCache;
|
|
414
|
+
epochNumber;
|
|
417
415
|
cancelJobsOnStop;
|
|
418
|
-
enqueueConcurrency;
|
|
419
416
|
static{
|
|
420
417
|
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
421
418
|
[
|
|
@@ -431,43 +428,33 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
431
428
|
[
|
|
432
429
|
_dec2,
|
|
433
430
|
2,
|
|
434
|
-
"startChonkVerifierCircuits"
|
|
435
|
-
],
|
|
436
|
-
[
|
|
437
|
-
_dec3,
|
|
438
|
-
2,
|
|
439
431
|
"setBlockCompleted"
|
|
440
432
|
],
|
|
441
433
|
[
|
|
442
|
-
|
|
434
|
+
_dec3,
|
|
443
435
|
2,
|
|
444
436
|
"prepareBaseRollupInputs"
|
|
445
437
|
]
|
|
446
438
|
], []));
|
|
447
439
|
}
|
|
448
|
-
provingState;
|
|
449
|
-
|
|
450
|
-
provingPromise;
|
|
440
|
+
/** The single checkpoint proving state this sub-tree owns. Allocated in the `start` factory. */ provingState;
|
|
441
|
+
subTreeResult;
|
|
451
442
|
metrics;
|
|
452
|
-
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
453
443
|
dbs;
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
this.cancelJobsOnStop = cancelJobsOnStop;
|
|
461
|
-
this.
|
|
462
|
-
this.
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
this.
|
|
466
|
-
this.deferredJobQueue = new SerialQueue();
|
|
467
|
-
this.logger = createLogger('prover-client:orchestrator', bindings);
|
|
468
|
-
this.metrics = new ProvingOrchestratorMetrics(telemetryClient, 'ProvingOrchestrator');
|
|
469
|
-
this.deferredJobQueue.start(this.enqueueConcurrency);
|
|
444
|
+
constructor(dbProvider, prover, proverId, /**
|
|
445
|
+
* Shared chonk-verifier proof cache. Every chonk-verifier proof started by this
|
|
446
|
+
* sub-tree lives on the cache and survives the sub-tree's cancellation, so a tx
|
|
447
|
+
* whose original checkpoint is reorged out and re-appears in a replacement
|
|
448
|
+
* checkpoint reuses the cached proof.
|
|
449
|
+
*/ chonkCache, /** The epoch this sub-tree proves into. */ epochNumber, cancelJobsOnStop = false, deferredJobQueue, telemetryClient = getTelemetryClient(), bindings){
|
|
450
|
+
super(deferredJobQueue, 'prover-client:checkpoint-sub-tree-orchestrator', bindings), this.dbProvider = dbProvider, this.prover = prover, this.proverId = proverId, this.chonkCache = chonkCache, this.epochNumber = epochNumber, this.cancelJobsOnStop = cancelJobsOnStop, this.provingState = (_initProto(this), undefined), this.dbs = new Map(), this.cancelled = false;
|
|
451
|
+
this.metrics = new ProvingOrchestratorMetrics(telemetryClient, 'CheckpointSubTreeOrchestrator');
|
|
452
|
+
this.subTreeResult = promiseWithResolvers();
|
|
453
|
+
// Mark the rejection branch as observed so a `cancel()` or proving failure does not
|
|
454
|
+
// surface an unhandled rejection when no consumer awaits getSubTreeResult().
|
|
455
|
+
this.subTreeResult.promise.catch(()=>{});
|
|
470
456
|
}
|
|
457
|
+
/** Tracks whether `cancel()` has been called; flows into the checkpoint state's isAlive hook. */ cancelled;
|
|
471
458
|
get tracer() {
|
|
472
459
|
return this.metrics.tracer;
|
|
473
460
|
}
|
|
@@ -477,72 +464,74 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
477
464
|
getNumActiveForks() {
|
|
478
465
|
return this.dbs.size;
|
|
479
466
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const oldQueue = this.deferredJobQueue;
|
|
483
|
-
this.cancel();
|
|
484
|
-
await oldQueue.cancel();
|
|
485
|
-
}
|
|
486
|
-
startNewEpoch(epochNumber, totalNumCheckpoints, finalBlobBatchingChallenges) {
|
|
487
|
-
if (this.provingState?.verifyState()) {
|
|
488
|
-
throw new Error(`Cannot start epoch ${epochNumber} when epoch ${this.provingState.epochNumber} is still being processed.`);
|
|
489
|
-
}
|
|
490
|
-
const { promise: _promise, resolve, reject } = promiseWithResolvers();
|
|
491
|
-
const promise = _promise.catch((reason)=>({
|
|
492
|
-
status: 'failure',
|
|
493
|
-
reason
|
|
494
|
-
}));
|
|
495
|
-
this.logger.info(`Starting epoch ${epochNumber} with ${totalNumCheckpoints} checkpoints.`);
|
|
496
|
-
this.provingState = new EpochProvingState(epochNumber, totalNumCheckpoints, finalBlobBatchingChallenges, (provingState)=>this.checkAndEnqueueCheckpointRootRollup(provingState), resolve, reject);
|
|
497
|
-
this.provingPromise = promise;
|
|
467
|
+
/** Returns a promise that resolves when block-level proving completes for the checkpoint. */ getSubTreeResult() {
|
|
468
|
+
return this.subTreeResult.promise;
|
|
498
469
|
}
|
|
499
470
|
/**
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
|
|
505
|
-
* @param headerOfLastBlockInPreviousCheckpoint - The header of the last block in the previous checkpoint.
|
|
506
|
-
*/ async startNewCheckpoint(checkpointIndex, constants, l1ToL2Messages, totalNumBlocks, headerOfLastBlockInPreviousCheckpoint) {
|
|
471
|
+
* Returns the archive sibling path captured at the internal checkpoint start.
|
|
472
|
+
* Available synchronously once `start` has resolved, before block-level proving
|
|
473
|
+
* completes. The top-tree consumer uses this to assemble checkpoint root rollup hints
|
|
474
|
+
* up-front so checkpoint root proofs can pipeline against in-flight sub-tree proving.
|
|
475
|
+
*/ getPreviousArchiveSiblingPath() {
|
|
507
476
|
if (!this.provingState) {
|
|
508
|
-
throw new Error('
|
|
477
|
+
throw new Error('Checkpoint not started; call CheckpointSubTreeOrchestrator.start first.');
|
|
509
478
|
}
|
|
510
|
-
|
|
511
|
-
|
|
479
|
+
return this.provingState.getLastArchiveSiblingPath();
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Constructs and starts a sub-tree for a single checkpoint. The returned sub-tree
|
|
483
|
+
* has had its single internal checkpoint state allocated; callers proceed directly
|
|
484
|
+
* to per-block `startNewBlock` / `addTxs` / `setBlockCompleted`.
|
|
485
|
+
*
|
|
486
|
+
* If the internal start rejects, the partially-constructed sub-tree is stopped
|
|
487
|
+
* before the error propagates, so no broker resources leak.
|
|
488
|
+
*/ static async start(dbProvider, prover, proverId, chonkCache, epochNumber, cancelJobsOnStop, deferredJobQueue, checkpointConstants, l1ToL2Messages, totalNumBlocks, headerOfLastBlockInPreviousCheckpoint, telemetryClient = getTelemetryClient(), bindings) {
|
|
489
|
+
const subTree = new CheckpointSubTreeOrchestrator(dbProvider, prover, proverId, chonkCache, epochNumber, cancelJobsOnStop, deferredJobQueue, telemetryClient, bindings);
|
|
490
|
+
try {
|
|
491
|
+
await subTree.startCheckpoint(checkpointConstants, l1ToL2Messages, totalNumBlocks, headerOfLastBlockInPreviousCheckpoint);
|
|
492
|
+
return subTree;
|
|
493
|
+
} catch (err) {
|
|
494
|
+
await subTree.stop().catch(()=>{});
|
|
495
|
+
throw err;
|
|
512
496
|
}
|
|
513
|
-
// Fork world state at the end of the immediately previous block.
|
|
514
|
-
const lastBlockNumber = headerOfLastBlockInPreviousCheckpoint.globalVariables.blockNumber;
|
|
515
|
-
const db = await this.dbProvider.fork(lastBlockNumber);
|
|
516
|
-
const firstBlockNumber = BlockNumber(lastBlockNumber + 1);
|
|
517
|
-
this.dbs.set(firstBlockNumber, db);
|
|
518
|
-
// Get archive sibling path before any block in this checkpoint lands.
|
|
519
|
-
const lastArchiveSiblingPath = await getLastSiblingPath(MerkleTreeId.ARCHIVE, db);
|
|
520
|
-
// Insert all the l1 to l2 messages into the db. And get the states before and after the insertion.
|
|
521
|
-
const { lastL1ToL2MessageTreeSnapshot, lastL1ToL2MessageSubtreeRootSiblingPath, newL1ToL2MessageTreeSnapshot, newL1ToL2MessageSubtreeRootSiblingPath } = await this.updateL1ToL2MessageTree(l1ToL2Messages, db);
|
|
522
|
-
this.provingState.startNewCheckpoint(checkpointIndex, constants, totalNumBlocks, headerOfLastBlockInPreviousCheckpoint, lastArchiveSiblingPath, l1ToL2Messages, lastL1ToL2MessageTreeSnapshot, lastL1ToL2MessageSubtreeRootSiblingPath, newL1ToL2MessageTreeSnapshot, newL1ToL2MessageSubtreeRootSiblingPath);
|
|
523
497
|
}
|
|
524
498
|
/**
|
|
525
|
-
*
|
|
499
|
+
* Kickstart chonk-verifier circuits via the shared `ChonkCache`. The cache owns the
|
|
500
|
+
* broker job lifecycle, so the proof survives this sub-tree's `cancel()` — a tx that
|
|
501
|
+
* ends up in a replacement checkpoint after a reorg can pick the cached promise up
|
|
502
|
+
* and skip re-proving.
|
|
503
|
+
*/ startChonkVerifierCircuits(txs) {
|
|
504
|
+
if (!this.provingState?.verifyState()) {
|
|
505
|
+
return Promise.reject(new Error('Sub-tree proving state is not active.'));
|
|
506
|
+
}
|
|
507
|
+
const publicTxs = txs.filter((tx)=>tx.data.forPublic);
|
|
508
|
+
for (const tx of publicTxs){
|
|
509
|
+
const txHash = tx.getTxHash().toString();
|
|
510
|
+
const inputs = getPublicChonkVerifierPrivateInputsFromTx(tx, this.getProverId().toField());
|
|
511
|
+
// Fire and forget — getOrEnqueueChonkVerifier later picks up the cached promise
|
|
512
|
+
// when the tx is processed inside its block.
|
|
513
|
+
void this.chonkCache.getOrCompute(txHash, (signal)=>this.prover.getPublicChonkVerifierProof(inputs, signal, this.epochNumber));
|
|
514
|
+
}
|
|
515
|
+
return Promise.resolve();
|
|
516
|
+
}
|
|
517
|
+
// ---------------- per-block driving (called by the per-checkpoint CheckpointProver) ----------------
|
|
518
|
+
/**
|
|
519
|
+
* Starts off a new block.
|
|
526
520
|
* @param blockNumber - The block number
|
|
527
|
-
* @param timestamp - The timestamp of the block.
|
|
528
|
-
*
|
|
529
|
-
* @param totalNumTxs - The total number of txs in the block
|
|
521
|
+
* @param timestamp - The timestamp of the block. Required for empty blocks to construct private inputs.
|
|
522
|
+
* @param totalNumTxs - The total number of txs in the block.
|
|
530
523
|
*/ async startNewBlock(blockNumber, timestamp, totalNumTxs) {
|
|
531
524
|
if (!this.provingState) {
|
|
532
|
-
throw new Error('Empty
|
|
533
|
-
}
|
|
534
|
-
const checkpointProvingState = this.provingState.getCheckpointProvingStateByBlockNumber(blockNumber);
|
|
535
|
-
if (!checkpointProvingState) {
|
|
536
|
-
throw new Error(`Checkpoint not started. Call startNewCheckpoint first.`);
|
|
525
|
+
throw new Error('Empty proving state. The checkpoint sub-tree has not been started.');
|
|
537
526
|
}
|
|
538
|
-
if (!
|
|
527
|
+
if (!this.provingState.isAcceptingBlocks()) {
|
|
539
528
|
throw new Error(`Checkpoint not accepting further blocks.`);
|
|
540
529
|
}
|
|
541
|
-
const constants =
|
|
530
|
+
const constants = this.provingState.constants;
|
|
542
531
|
this.logger.info(`Starting block ${blockNumber} for slot ${constants.slotNumber}.`);
|
|
543
|
-
// Fork the db only when it's not already set. The db for the first block is set in
|
|
532
|
+
// Fork the db only when it's not already set. The db for the first block is set in startCheckpoint.
|
|
544
533
|
if (!this.dbs.has(blockNumber)) {
|
|
545
|
-
// Fork world state at the end of the immediately previous block
|
|
534
|
+
// Fork world state at the end of the immediately previous block.
|
|
546
535
|
const db = await this.dbProvider.fork(BlockNumber(blockNumber - 1));
|
|
547
536
|
this.dbs.set(blockNumber, db);
|
|
548
537
|
}
|
|
@@ -550,15 +539,15 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
550
539
|
// Get archive snapshot and sibling path before any txs in this block lands.
|
|
551
540
|
const lastArchiveTreeSnapshot = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
|
|
552
541
|
const lastArchiveSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.ARCHIVE, db);
|
|
553
|
-
const blockProvingState =
|
|
542
|
+
const blockProvingState = this.provingState.startNewBlock(blockNumber, timestamp, totalNumTxs, lastArchiveTreeSnapshot, lastArchiveSiblingPath);
|
|
554
543
|
// Enqueue base parity circuits for the first block in the checkpoint.
|
|
555
544
|
if (blockProvingState.index === 0) {
|
|
556
545
|
for(let i = 0; i < NUM_BASE_PARITY_PER_ROOT_PARITY; i++){
|
|
557
|
-
this.enqueueBaseParityCircuit(
|
|
546
|
+
this.enqueueBaseParityCircuit(this.provingState, blockProvingState, i);
|
|
558
547
|
}
|
|
559
548
|
}
|
|
560
|
-
// Because `addTxs` won't be called for a block without txs, and that's where the sponge blob state is computed
|
|
561
|
-
//
|
|
549
|
+
// Because `addTxs` won't be called for a block without txs, and that's where the sponge blob state is computed,
|
|
550
|
+
// set its end sponge blob here. This becomes the start sponge blob for the next block.
|
|
562
551
|
if (totalNumTxs === 0) {
|
|
563
552
|
const endState = await db.getStateReference();
|
|
564
553
|
blockProvingState.setEndState(endState);
|
|
@@ -566,22 +555,19 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
566
555
|
const blockEndBlobFields = blockProvingState.getBlockEndBlobFields();
|
|
567
556
|
await endSpongeBlob.absorb(blockEndBlobFields);
|
|
568
557
|
blockProvingState.setEndSpongeBlob(endSpongeBlob);
|
|
569
|
-
// Try to accumulate the out hashes and blobs as far as we can:
|
|
570
|
-
await this.provingState.accumulateCheckpointOutHashes();
|
|
571
|
-
await this.provingState.setBlobAccumulators();
|
|
572
558
|
}
|
|
573
559
|
}
|
|
574
560
|
/**
|
|
575
|
-
* The interface to add simulated transactions to the scheduler.
|
|
561
|
+
* The interface to add simulated transactions to the scheduler. Called at most once per block.
|
|
576
562
|
* @param txs - The transactions to be proven
|
|
577
563
|
*/ async addTxs(txs) {
|
|
578
564
|
if (!this.provingState) {
|
|
579
|
-
throw new Error(`Empty
|
|
565
|
+
throw new Error(`Empty proving state. The checkpoint sub-tree has not been started.`);
|
|
580
566
|
}
|
|
581
567
|
if (!txs.length) {
|
|
582
|
-
//
|
|
583
|
-
//
|
|
584
|
-
this.logger.
|
|
568
|
+
// Empty block: setBlockCompleted handles this without addTxs being called. Bail to
|
|
569
|
+
// avoid the throw below (we cannot find the blockNumber without any txs).
|
|
570
|
+
this.logger.verbose(`Provided no txs to addTxs.`);
|
|
585
571
|
return;
|
|
586
572
|
}
|
|
587
573
|
const blockNumber = BlockNumber(txs[0].globalVariables.blockNumber);
|
|
@@ -634,29 +620,6 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
634
620
|
const blockEndBlobFields = provingState.getBlockEndBlobFields();
|
|
635
621
|
await spongeBlobState.absorb(blockEndBlobFields);
|
|
636
622
|
provingState.setEndSpongeBlob(spongeBlobState);
|
|
637
|
-
// Txs have been added to the block. Now try to accumulate the out hashes and blobs as far as we can:
|
|
638
|
-
await this.provingState.accumulateCheckpointOutHashes();
|
|
639
|
-
await this.provingState.setBlobAccumulators();
|
|
640
|
-
}
|
|
641
|
-
/**
|
|
642
|
-
* Kickstarts chonk verifier circuits for the specified txs. These will be used during epoch proving.
|
|
643
|
-
* Note that if the chonk verifier circuits are not started this way, they will be started nontheless after processing.
|
|
644
|
-
*/ startChonkVerifierCircuits(txs) {
|
|
645
|
-
if (!this.provingState?.verifyState()) {
|
|
646
|
-
throw new Error(`Empty epoch proving state. call startNewEpoch before starting chonk verifier circuits.`);
|
|
647
|
-
}
|
|
648
|
-
const publicTxs = txs.filter((tx)=>tx.data.forPublic);
|
|
649
|
-
for (const tx of publicTxs){
|
|
650
|
-
const txHash = tx.getTxHash().toString();
|
|
651
|
-
const privateInputs = getPublicChonkVerifierPrivateInputsFromTx(tx, this.proverId.toField());
|
|
652
|
-
const tubeProof = promiseWithResolvers();
|
|
653
|
-
this.logger.debug(`Starting chonk verifier circuit for tx ${txHash}`);
|
|
654
|
-
this.doEnqueueChonkVerifier(txHash, privateInputs, (proof)=>{
|
|
655
|
-
tubeProof.resolve(proof);
|
|
656
|
-
});
|
|
657
|
-
this.provingState.cachedChonkVerifierProofs.set(txHash, tubeProof.promise);
|
|
658
|
-
}
|
|
659
|
-
return Promise.resolve();
|
|
660
623
|
}
|
|
661
624
|
/**
|
|
662
625
|
* Marks the block as completed.
|
|
@@ -699,144 +662,50 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
699
662
|
await this.verifyBuiltBlockAgainstSyncedState(provingState);
|
|
700
663
|
return header;
|
|
701
664
|
}
|
|
702
|
-
//
|
|
703
|
-
async verifyBuiltBlockAgainstSyncedState(provingState) {
|
|
704
|
-
const builtBlockHeader = provingState.getBuiltBlockHeader();
|
|
705
|
-
if (!builtBlockHeader) {
|
|
706
|
-
this.logger.debug('Block header not built yet, skipping header check.');
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
const output = provingState.getBlockRootRollupOutput();
|
|
710
|
-
if (!output) {
|
|
711
|
-
this.logger.debug('Block root rollup proof not built yet, skipping header check.');
|
|
712
|
-
return;
|
|
713
|
-
}
|
|
714
|
-
const newArchive = provingState.getBuiltArchive();
|
|
715
|
-
if (!newArchive) {
|
|
716
|
-
this.logger.debug('Archive snapshot not yet captured, skipping header check.');
|
|
717
|
-
return;
|
|
718
|
-
}
|
|
719
|
-
const header = await buildHeaderFromCircuitOutputs(output);
|
|
720
|
-
if (!(await header.hash()).equals(await builtBlockHeader.hash())) {
|
|
721
|
-
this.logger.error(`Block header mismatch.\nCircuit: ${inspect(header)}\nComputed: ${inspect(builtBlockHeader)}`);
|
|
722
|
-
provingState.reject(`Block header hash mismatch.`);
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
const blockNumber = provingState.blockNumber;
|
|
726
|
-
const syncedArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.dbProvider.getSnapshot(blockNumber));
|
|
727
|
-
if (!syncedArchive.equals(newArchive)) {
|
|
728
|
-
this.logger.error(`Archive tree mismatch for block ${blockNumber}: world state synced to ${inspect(syncedArchive)} but built ${inspect(newArchive)}`);
|
|
729
|
-
provingState.reject(`Archive tree mismatch.`);
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
const circuitArchive = output.newArchive;
|
|
733
|
-
if (!newArchive.equals(circuitArchive)) {
|
|
734
|
-
this.logger.error(`New archive mismatch.\nCircuit: ${output.newArchive}\nComputed: ${newArchive}`);
|
|
735
|
-
provingState.reject(`New archive mismatch.`);
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
}
|
|
665
|
+
// ---------------- lifecycle ----------------
|
|
739
666
|
/**
|
|
740
|
-
*
|
|
741
|
-
*
|
|
742
|
-
* If cancelJobsOnStop is false (default), jobs remain in the broker queue and can be reused on restart/reorg.
|
|
667
|
+
* Cancels any further proving. If `cancelJobsOnStop` was set, aborts all pending broker jobs
|
|
668
|
+
* (used on reorg). Otherwise jobs remain in the broker queue and can be reused on restart.
|
|
743
669
|
*/ cancel() {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
if (this.cancelJobsOnStop) {
|
|
749
|
-
for (const controller of this.pendingProvingJobs){
|
|
750
|
-
controller.abort();
|
|
751
|
-
}
|
|
752
|
-
}
|
|
670
|
+
this.cancelled = true;
|
|
671
|
+
this.resetSchedulerState(this.cancelJobsOnStop);
|
|
672
|
+
// Reject the proving state (and hence subTreeResult) so anyone awaiting the sub-tree result
|
|
673
|
+
// is released rather than hanging — matching TopTreeOrchestrator.cancel().
|
|
753
674
|
this.provingState?.cancel();
|
|
754
675
|
for (const [blockNumber, db] of this.dbs.entries()){
|
|
755
676
|
void db.close().catch((err)=>this.logger.error(`Error closing db for block ${blockNumber}`, err));
|
|
756
677
|
}
|
|
757
678
|
this.dbs.clear();
|
|
758
679
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
if (!db) {
|
|
762
|
-
throw new Error(`World state fork for block ${blockNumber} not found.`);
|
|
763
|
-
}
|
|
764
|
-
return db;
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* Returns the proof for the current epoch.
|
|
768
|
-
*/ async finalizeEpoch() {
|
|
769
|
-
if (!this.provingState || !this.provingPromise) {
|
|
770
|
-
throw new Error(`Invalid proving state, an epoch must be proven before it can be finalized`);
|
|
771
|
-
}
|
|
772
|
-
const result = await this.provingPromise;
|
|
773
|
-
if (result.status === 'failure') {
|
|
774
|
-
throw new Error(`Epoch proving failed: ${result.reason}`);
|
|
775
|
-
}
|
|
776
|
-
await this.provingState.finalizeBatchedBlob();
|
|
777
|
-
const epochProofResult = this.provingState.getEpochProofResult();
|
|
778
|
-
pushTestData('epochProofResult', {
|
|
779
|
-
proof: epochProofResult.proof.toString(),
|
|
780
|
-
publicInputs: epochProofResult.publicInputs.toString()
|
|
781
|
-
});
|
|
782
|
-
return epochProofResult;
|
|
680
|
+
cancelInternal() {
|
|
681
|
+
this.cancel();
|
|
783
682
|
}
|
|
683
|
+
// ---------------- private: per-checkpoint init ----------------
|
|
784
684
|
/**
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
*
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
this.logger.debug(`Not enqueuing job, state no longer valid`);
|
|
792
|
-
return;
|
|
685
|
+
* Internal driver for the single-checkpoint init. Allocates the world-state fork,
|
|
686
|
+
* inserts L1-to-L2 messages, and creates the per-checkpoint proving state with this
|
|
687
|
+
* sub-tree as its parent. Only called once, from the `start` factory.
|
|
688
|
+
*/ async startCheckpoint(constants, l1ToL2Messages, totalNumBlocks, headerOfLastBlockInPreviousCheckpoint) {
|
|
689
|
+
if (this.provingState) {
|
|
690
|
+
throw new Error('Checkpoint sub-tree already started.');
|
|
793
691
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
const result = await request(controller.signal);
|
|
805
|
-
if (!provingState.verifyState()) {
|
|
806
|
-
this.logger.debug(`State no longer valid, discarding result`);
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
|
-
// we could have been cancelled whilst waiting for the result
|
|
810
|
-
// and the prover ignored the signal. Drop the result in that case
|
|
811
|
-
if (controller.signal.aborted) {
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
|
-
await callback(result);
|
|
815
|
-
} catch (err) {
|
|
816
|
-
if (err instanceof AbortError) {
|
|
817
|
-
// operation was cancelled, probably because the block was cancelled
|
|
818
|
-
// drop this result
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
this.logger.error(`Error thrown when proving job`, err);
|
|
822
|
-
provingState.reject(`${err}`);
|
|
823
|
-
} finally{
|
|
824
|
-
const index = this.pendingProvingJobs.indexOf(controller);
|
|
825
|
-
if (index > -1) {
|
|
826
|
-
this.pendingProvingJobs.splice(index, 1);
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
};
|
|
830
|
-
// Enqueue onto the serial queue with limited workers to avoid starving the event loop.
|
|
831
|
-
// Workers yield between jobs via await, allowing I/O callbacks to process.
|
|
832
|
-
void this.deferredJobQueue.put(()=>safeJob());
|
|
692
|
+
// Fork world state at the end of the immediately previous block.
|
|
693
|
+
const lastBlockNumber = headerOfLastBlockInPreviousCheckpoint.globalVariables.blockNumber;
|
|
694
|
+
const db = await this.dbProvider.fork(lastBlockNumber);
|
|
695
|
+
const firstBlockNumber = BlockNumber(lastBlockNumber + 1);
|
|
696
|
+
this.dbs.set(firstBlockNumber, db);
|
|
697
|
+
// Get archive sibling path before any block in this checkpoint lands.
|
|
698
|
+
const lastArchiveSiblingPath = await getLastSiblingPath(MerkleTreeId.ARCHIVE, db);
|
|
699
|
+
// Insert all the l1 to l2 messages into the db. Get the states before and after the insertion.
|
|
700
|
+
const { lastL1ToL2MessageTreeSnapshot, lastL1ToL2MessageSubtreeRootSiblingPath, newL1ToL2MessageTreeSnapshot, newL1ToL2MessageSubtreeRootSiblingPath } = await this.updateL1ToL2MessageTree(l1ToL2Messages, db);
|
|
701
|
+
this.provingState = new CheckpointProvingState(/* index */ 0, constants, totalNumBlocks, headerOfLastBlockInPreviousCheckpoint, lastArchiveSiblingPath, l1ToL2Messages, lastL1ToL2MessageTreeSnapshot, lastL1ToL2MessageSubtreeRootSiblingPath, newL1ToL2MessageTreeSnapshot, newL1ToL2MessageSubtreeRootSiblingPath, Number(this.epochNumber), /* isAlive */ ()=>!this.cancelled, /* onReject */ (reason)=>this.subTreeResult.reject(new Error(reason)));
|
|
833
702
|
}
|
|
703
|
+
// ---------------- private: per-block proof orchestration ----------------
|
|
834
704
|
async updateL1ToL2MessageTree(l1ToL2Messages, db) {
|
|
835
|
-
const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 'Too many L1 to L2 messages');
|
|
836
705
|
const lastL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
|
|
837
706
|
const lastL1ToL2MessageSubtreeRootSiblingPath = assertLength(await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db), L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH);
|
|
838
|
-
// Update the local trees to include the new l1 to l2 messages
|
|
839
|
-
await db
|
|
707
|
+
// Update the local trees to include the new l1 to l2 messages.
|
|
708
|
+
await appendL1ToL2MessagesToTree(db, l1ToL2Messages);
|
|
840
709
|
const newL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
|
|
841
710
|
const newL1ToL2MessageSubtreeRootSiblingPath = assertLength(await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db), L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH);
|
|
842
711
|
return {
|
|
@@ -846,12 +715,15 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
846
715
|
newL1ToL2MessageSubtreeRootSiblingPath
|
|
847
716
|
};
|
|
848
717
|
}
|
|
849
|
-
// Updates the merkle trees for a transaction. The first enqueued job for a transaction
|
|
718
|
+
// Updates the merkle trees for a transaction. The first enqueued job for a transaction.
|
|
850
719
|
async prepareBaseRollupInputs(tx, lastArchive, newL1ToL2MessageTreeSnapshot, startSpongeBlob, db) {
|
|
851
|
-
//
|
|
852
|
-
//
|
|
853
|
-
|
|
854
|
-
|
|
720
|
+
// These hints deliberately carry no recursive proof or verification key — see
|
|
721
|
+
// BaseRollupHintsWithoutProofAndVK. The tx's proof + VK are attached later in
|
|
722
|
+
// TxProvingState.getBaseRollupTypeAndInputs from the proven chonk-verifier / kernel / AVM
|
|
723
|
+
// proofs, which are required there and so cannot be silently omitted.
|
|
724
|
+
const start = performance.now();
|
|
725
|
+
const hints = await insertSideEffectsAndBuildBaseRollupHints(tx, lastArchive, newL1ToL2MessageTreeSnapshot, startSpongeBlob, this.proverId.toField(), db);
|
|
726
|
+
this.metrics.recordBaseRollupInputs(performance.now() - start);
|
|
855
727
|
const promises = [
|
|
856
728
|
MerkleTreeId.NOTE_HASH_TREE,
|
|
857
729
|
MerkleTreeId.NULLIFIER_TREE,
|
|
@@ -871,8 +743,8 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
871
743
|
treeSnapshots
|
|
872
744
|
];
|
|
873
745
|
}
|
|
874
|
-
// Executes the base rollup circuit and
|
|
875
|
-
// Executes the next level of merge if all inputs are available
|
|
746
|
+
// Executes the base rollup circuit and stores the output as intermediate state for the parent merge/root circuit.
|
|
747
|
+
// Executes the next level of merge if all inputs are available.
|
|
876
748
|
enqueueBaseRollup(provingState, txIndex) {
|
|
877
749
|
if (!provingState.verifyState()) {
|
|
878
750
|
this.logger.debug('Not running base rollup, state invalid');
|
|
@@ -886,15 +758,15 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
886
758
|
const { processedTx } = txProvingState;
|
|
887
759
|
const { rollupType, inputs } = txProvingState.getBaseRollupTypeAndInputs();
|
|
888
760
|
this.logger.debug(`Enqueuing deferred proving base rollup for ${processedTx.hash.toString()}`);
|
|
889
|
-
this.deferredProving(provingState,
|
|
890
|
-
[Attributes.TX_HASH]: processedTx.hash.toString(),
|
|
891
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType
|
|
892
|
-
}, (signal)=>{
|
|
761
|
+
this.deferredProving(provingState, this.wrapCircuitCall(inputs instanceof PrivateTxBaseRollupPrivateInputs ? 'getPrivateTxBaseRollupProof' : 'getPublicTxBaseRollupProof', (signal)=>{
|
|
893
762
|
if (inputs instanceof PrivateTxBaseRollupPrivateInputs) {
|
|
894
763
|
return this.prover.getPrivateTxBaseRollupProof(inputs, signal, provingState.epochNumber);
|
|
895
764
|
} else {
|
|
896
765
|
return this.prover.getPublicTxBaseRollupProof(inputs, signal, provingState.epochNumber);
|
|
897
766
|
}
|
|
767
|
+
}, {
|
|
768
|
+
[Attributes.TX_HASH]: processedTx.hash.toString(),
|
|
769
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType
|
|
898
770
|
}), (result)=>{
|
|
899
771
|
this.logger.debug(`Completed proof for ${rollupType} for tx ${processedTx.hash.toString()}`);
|
|
900
772
|
validatePartialState(result.inputs.endTreeSnapshots, txProvingState.treeSnapshots);
|
|
@@ -906,46 +778,37 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
906
778
|
}
|
|
907
779
|
});
|
|
908
780
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
781
|
+
/**
|
|
782
|
+
* Route the tx's chonk-verifier dependency through the per-epoch context: read the
|
|
783
|
+
* cached promise (or enqueue if missing), then `.then(handleResult)` to progress to
|
|
784
|
+
* the base rollup once the proof lands.
|
|
785
|
+
*/ getOrEnqueueChonkVerifier(provingState, txIndex) {
|
|
912
786
|
if (!provingState.verifyState()) {
|
|
913
|
-
this.logger.debug('Not running chonk verifier circuit, state invalid');
|
|
914
787
|
return;
|
|
915
788
|
}
|
|
916
789
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
917
790
|
const txHash = txProvingState.processedTx.hash.toString();
|
|
918
|
-
NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH;
|
|
919
791
|
const handleResult = (result)=>{
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
}
|
|
792
|
+
if (!provingState.verifyState()) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
923
795
|
txProvingState.setPublicChonkVerifierProof(result);
|
|
924
|
-
this.provingState?.cachedChonkVerifierProofs.delete(txHash);
|
|
925
796
|
this.checkAndEnqueueBaseRollup(provingState, txIndex);
|
|
926
797
|
};
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
this.logger.debug('Not running chonk verifier circuit, state invalid');
|
|
940
|
-
return;
|
|
941
|
-
}
|
|
942
|
-
this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getPublicChonkVerifierProof', {
|
|
943
|
-
[Attributes.TX_HASH]: txHash,
|
|
944
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'chonk-verifier-public'
|
|
945
|
-
}, (signal)=>this.prover.getPublicChonkVerifierProof(inputs, signal, provingState.epochNumber)), handler);
|
|
798
|
+
const promise = this.chonkCache.getOrCompute(txHash, (signal)=>this.prover.getPublicChonkVerifierProof(txProvingState.getPublicChonkVerifierPrivateInputs(), signal, this.epochNumber));
|
|
799
|
+
void promise.then(handleResult).catch((err)=>{
|
|
800
|
+
// The cache self-cleans on rejection, so a replacement sub-tree for this tx will see the
|
|
801
|
+
// miss and re-enqueue. But if this proving state is still active, the failure must abort
|
|
802
|
+
// it: otherwise the base rollup for this tx is never enqueued and the checkpoint (and
|
|
803
|
+
// epoch) orchestrators hang forever waiting for a proof that will never arrive.
|
|
804
|
+
if (err instanceof AbortError || !provingState.verifyState()) {
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
this.logger.error(`Chonk verifier proof failed for tx ${txHash}`, err);
|
|
808
|
+
provingState.reject(`Chonk verifier proof failed for tx ${txHash}: ${err}`);
|
|
809
|
+
});
|
|
946
810
|
}
|
|
947
|
-
// Executes the merge rollup circuit
|
|
948
|
-
// Enqueues the next level of merge if all inputs are available
|
|
811
|
+
// Executes the merge rollup circuit. Enqueues the next level of merge if all inputs are available.
|
|
949
812
|
enqueueMergeRollup(provingState, location) {
|
|
950
813
|
if (!provingState.verifyState()) {
|
|
951
814
|
this.logger.debug('Not running merge rollup. State no longer valid.');
|
|
@@ -956,14 +819,14 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
956
819
|
return;
|
|
957
820
|
}
|
|
958
821
|
const inputs = provingState.getMergeRollupInputs(location);
|
|
959
|
-
this.deferredProving(provingState,
|
|
822
|
+
this.deferredProving(provingState, this.wrapCircuitCall('getTxMergeRollupProof', (signal)=>this.prover.getTxMergeRollupProof(inputs, signal, provingState.epochNumber), {
|
|
960
823
|
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-tx-merge'
|
|
961
|
-
}
|
|
824
|
+
}), (result)=>{
|
|
962
825
|
provingState.setMergeRollupProof(location, result);
|
|
963
826
|
this.checkAndEnqueueNextMergeRollup(provingState, location);
|
|
964
827
|
});
|
|
965
828
|
}
|
|
966
|
-
// Executes the block root rollup circuit
|
|
829
|
+
// Executes the block root rollup circuit.
|
|
967
830
|
enqueueBlockRootRollup(provingState) {
|
|
968
831
|
if (!provingState.verifyState()) {
|
|
969
832
|
this.logger.debug('Not running block root rollup, state no longer valid');
|
|
@@ -975,9 +838,7 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
975
838
|
}
|
|
976
839
|
const { rollupType, inputs } = provingState.getBlockRootRollupTypeAndInputs();
|
|
977
840
|
this.logger.debug(`Enqueuing ${rollupType} for block ${provingState.blockNumber}.`);
|
|
978
|
-
this.deferredProving(provingState,
|
|
979
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType
|
|
980
|
-
}, (signal)=>{
|
|
841
|
+
this.deferredProving(provingState, this.wrapCircuitCall('getBlockRootRollupProof', (signal)=>{
|
|
981
842
|
if (inputs instanceof BlockRootFirstRollupPrivateInputs) {
|
|
982
843
|
return this.prover.getBlockRootFirstRollupProof(inputs, signal, provingState.epochNumber);
|
|
983
844
|
} else if (inputs instanceof BlockRootSingleTxFirstRollupPrivateInputs) {
|
|
@@ -989,22 +850,27 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
989
850
|
} else {
|
|
990
851
|
return this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber);
|
|
991
852
|
}
|
|
853
|
+
}, {
|
|
854
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType
|
|
992
855
|
}), async (result)=>{
|
|
993
|
-
this.logger.debug(`Completed ${rollupType} proof for block ${provingState.blockNumber}
|
|
856
|
+
this.logger.debug(`Completed ${rollupType} proof for block ${provingState.blockNumber}`, {
|
|
857
|
+
blockNumber: provingState.blockNumber,
|
|
858
|
+
checkpointIndex: provingState.parentCheckpoint.index,
|
|
859
|
+
...result.inputs.toInspect()
|
|
860
|
+
});
|
|
994
861
|
const leafLocation = provingState.setBlockRootRollupProof(result);
|
|
995
862
|
const checkpointProvingState = provingState.parentCheckpoint;
|
|
996
863
|
// Verification is called from both here and setBlockCompleted. Whichever runs last
|
|
997
864
|
// will be the first to see all three pieces (header, proof output, archive) and run the checks.
|
|
998
865
|
await this.verifyBuiltBlockAgainstSyncedState(provingState);
|
|
999
866
|
if (checkpointProvingState.totalNumBlocks === 1) {
|
|
1000
|
-
|
|
867
|
+
this.checkAndEnqueueSubTreeResolution(checkpointProvingState);
|
|
1001
868
|
} else {
|
|
1002
|
-
|
|
869
|
+
this.checkAndEnqueueNextBlockMergeRollup(checkpointProvingState, leafLocation);
|
|
1003
870
|
}
|
|
1004
871
|
});
|
|
1005
872
|
}
|
|
1006
|
-
// Executes the base parity circuit
|
|
1007
|
-
// Enqueues the root parity circuit if all inputs are available
|
|
873
|
+
// Executes the base parity circuit. Enqueues the root parity circuit if all inputs are available.
|
|
1008
874
|
enqueueBaseParityCircuit(checkpointProvingState, provingState, baseParityIndex) {
|
|
1009
875
|
if (!provingState.verifyState()) {
|
|
1010
876
|
this.logger.debug('Not running base parity. State no longer valid.');
|
|
@@ -1015,9 +881,9 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
1015
881
|
return;
|
|
1016
882
|
}
|
|
1017
883
|
const inputs = checkpointProvingState.getBaseParityInputs(baseParityIndex);
|
|
1018
|
-
this.deferredProving(provingState,
|
|
884
|
+
this.deferredProving(provingState, this.wrapCircuitCall('getBaseParityProof', (signal)=>this.prover.getBaseParityProof(inputs, signal, provingState.epochNumber), {
|
|
1019
885
|
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'parity-base'
|
|
1020
|
-
}
|
|
886
|
+
}), (provingOutput)=>{
|
|
1021
887
|
provingState.setBaseParityProof(baseParityIndex, provingOutput);
|
|
1022
888
|
this.checkAndEnqueueRootParityCircuit(provingState);
|
|
1023
889
|
});
|
|
@@ -1028,8 +894,8 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
1028
894
|
}
|
|
1029
895
|
this.enqueueRootParityCircuit(provingState);
|
|
1030
896
|
}
|
|
1031
|
-
// Runs the root parity circuit
|
|
1032
|
-
// Enqueues the root rollup
|
|
897
|
+
// Runs the root parity circuit and stores the outputs.
|
|
898
|
+
// Enqueues the block root rollup if all inputs are available.
|
|
1033
899
|
enqueueRootParityCircuit(provingState) {
|
|
1034
900
|
if (!provingState.verifyState()) {
|
|
1035
901
|
this.logger.debug('Not running root parity. State no longer valid.');
|
|
@@ -1040,15 +906,14 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
1040
906
|
return;
|
|
1041
907
|
}
|
|
1042
908
|
const inputs = provingState.getParityRootInputs();
|
|
1043
|
-
this.deferredProving(provingState,
|
|
909
|
+
this.deferredProving(provingState, this.wrapCircuitCall('getRootParityProof', (signal)=>this.prover.getRootParityProof(inputs, signal, provingState.epochNumber), {
|
|
1044
910
|
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'parity-root'
|
|
1045
|
-
}
|
|
911
|
+
}), (result)=>{
|
|
1046
912
|
provingState.setRootParityProof(result);
|
|
1047
913
|
this.checkAndEnqueueBlockRootRollup(provingState);
|
|
1048
914
|
});
|
|
1049
915
|
}
|
|
1050
|
-
// Executes the block merge rollup circuit
|
|
1051
|
-
// Enqueues the next level of merge if all inputs are available
|
|
916
|
+
// Executes the block merge rollup circuit.
|
|
1052
917
|
enqueueBlockMergeRollup(provingState, location) {
|
|
1053
918
|
if (!provingState.verifyState()) {
|
|
1054
919
|
this.logger.debug('Not running block merge rollup. State no longer valid.');
|
|
@@ -1059,104 +924,16 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
1059
924
|
return;
|
|
1060
925
|
}
|
|
1061
926
|
const inputs = provingState.getBlockMergeRollupInputs(location);
|
|
1062
|
-
this.deferredProving(provingState,
|
|
927
|
+
this.deferredProving(provingState, this.wrapCircuitCall('getBlockMergeRollupProof', (signal)=>this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber), {
|
|
1063
928
|
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-block-merge'
|
|
1064
|
-
}, (signal)=>this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber)), async (result)=>{
|
|
1065
|
-
provingState.setBlockMergeRollupProof(location, result);
|
|
1066
|
-
await this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
|
|
1067
|
-
});
|
|
1068
|
-
}
|
|
1069
|
-
async enqueueCheckpointRootRollup(provingState) {
|
|
1070
|
-
if (!provingState.verifyState()) {
|
|
1071
|
-
this.logger.debug('Not running checkpoint root rollup. State no longer valid.');
|
|
1072
|
-
return;
|
|
1073
|
-
}
|
|
1074
|
-
if (!provingState.tryStartProvingCheckpointRoot()) {
|
|
1075
|
-
this.logger.debug('Checkpoint root rollup already started.');
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
|
-
const rollupType = provingState.getCheckpointRootRollupType();
|
|
1079
|
-
this.logger.debug(`Enqueuing ${rollupType} for checkpoint ${provingState.index}.`);
|
|
1080
|
-
const inputs = await provingState.getCheckpointRootRollupInputs();
|
|
1081
|
-
this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getCheckpointRootRollupProof', {
|
|
1082
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType
|
|
1083
|
-
}, (signal)=>{
|
|
1084
|
-
if (inputs instanceof CheckpointRootSingleBlockRollupPrivateInputs) {
|
|
1085
|
-
return this.prover.getCheckpointRootSingleBlockRollupProof(inputs, signal, provingState.epochNumber);
|
|
1086
|
-
} else {
|
|
1087
|
-
return this.prover.getCheckpointRootRollupProof(inputs, signal, provingState.epochNumber);
|
|
1088
|
-
}
|
|
1089
929
|
}), (result)=>{
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
provingState.reject(`Blob accumulator state mismatch.`);
|
|
1095
|
-
return;
|
|
1096
|
-
}
|
|
1097
|
-
this.logger.debug(`Completed ${rollupType} proof for checkpoint ${provingState.index}.`);
|
|
1098
|
-
const leafLocation = provingState.setCheckpointRootRollupProof(result);
|
|
1099
|
-
const epochProvingState = provingState.parentEpoch;
|
|
1100
|
-
if (epochProvingState.totalNumCheckpoints === 1) {
|
|
1101
|
-
this.enqueueEpochPadding(epochProvingState);
|
|
1102
|
-
} else {
|
|
1103
|
-
this.checkAndEnqueueNextCheckpointMergeRollup(epochProvingState, leafLocation);
|
|
1104
|
-
}
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1107
|
-
enqueueCheckpointMergeRollup(provingState, location) {
|
|
1108
|
-
if (!provingState.verifyState()) {
|
|
1109
|
-
this.logger.debug('Not running checkpoint merge rollup. State no longer valid.');
|
|
1110
|
-
return;
|
|
1111
|
-
}
|
|
1112
|
-
if (!provingState.tryStartProvingCheckpointMerge(location)) {
|
|
1113
|
-
this.logger.debug('Checkpoint merge rollup already started.');
|
|
1114
|
-
return;
|
|
1115
|
-
}
|
|
1116
|
-
const inputs = provingState.getCheckpointMergeRollupInputs(location);
|
|
1117
|
-
this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getCheckpointMergeRollupProof', {
|
|
1118
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-merge'
|
|
1119
|
-
}, (signal)=>this.prover.getCheckpointMergeRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
|
|
1120
|
-
this.logger.debug('Completed proof for checkpoint merge rollup.');
|
|
1121
|
-
provingState.setCheckpointMergeRollupProof(location, result);
|
|
1122
|
-
this.checkAndEnqueueNextCheckpointMergeRollup(provingState, location);
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
|
-
enqueueEpochPadding(provingState) {
|
|
1126
|
-
if (!provingState.verifyState()) {
|
|
1127
|
-
this.logger.debug('Not running epoch padding. State no longer valid.');
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
if (!provingState.tryStartProvingPaddingCheckpoint()) {
|
|
1131
|
-
this.logger.debug('Padding checkpoint already started.');
|
|
1132
|
-
return;
|
|
1133
|
-
}
|
|
1134
|
-
this.logger.debug('Padding epoch proof with a padding block root proof.');
|
|
1135
|
-
const inputs = provingState.getPaddingCheckpointInputs();
|
|
1136
|
-
this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getCheckpointPaddingRollupProof', {
|
|
1137
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-padding'
|
|
1138
|
-
}, (signal)=>this.prover.getCheckpointPaddingRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
|
|
1139
|
-
this.logger.debug('Completed proof for padding checkpoint.');
|
|
1140
|
-
provingState.setCheckpointPaddingProof(result);
|
|
1141
|
-
this.checkAndEnqueueRootRollup(provingState);
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
// Executes the root rollup circuit
|
|
1145
|
-
enqueueRootRollup(provingState) {
|
|
1146
|
-
if (!provingState.verifyState()) {
|
|
1147
|
-
this.logger.debug('Not running root rollup, state no longer valid');
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
this.logger.debug(`Preparing root rollup`);
|
|
1151
|
-
const inputs = provingState.getRootRollupInputs();
|
|
1152
|
-
this.deferredProving(provingState, wrapCallbackInSpan(this.tracer, 'ProvingOrchestrator.prover.getRootRollupProof', {
|
|
1153
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-root'
|
|
1154
|
-
}, (signal)=>this.prover.getRootRollupProof(inputs, signal, provingState.epochNumber)), (result)=>{
|
|
1155
|
-
this.logger.verbose(`Orchestrator completed root rollup for epoch ${provingState.epochNumber}`);
|
|
1156
|
-
provingState.setRootRollupProof(result);
|
|
1157
|
-
provingState.resolve({
|
|
1158
|
-
status: 'success'
|
|
930
|
+
this.logger.debug(`Completed block merge rollup proof for checkpoint ${provingState.index}`, {
|
|
931
|
+
checkpointIndex: provingState.index,
|
|
932
|
+
mergeLocation: location,
|
|
933
|
+
...result.inputs.toInspect()
|
|
1159
934
|
});
|
|
935
|
+
provingState.setBlockMergeRollupProof(location, result);
|
|
936
|
+
this.checkAndEnqueueNextBlockMergeRollup(provingState, location);
|
|
1160
937
|
});
|
|
1161
938
|
}
|
|
1162
939
|
checkAndEnqueueNextMergeRollup(provingState, currentLocation) {
|
|
@@ -1177,59 +954,48 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
1177
954
|
}
|
|
1178
955
|
this.enqueueBlockRootRollup(provingState);
|
|
1179
956
|
}
|
|
1180
|
-
|
|
957
|
+
checkAndEnqueueNextBlockMergeRollup(provingState, currentLocation) {
|
|
1181
958
|
if (!provingState.isReadyForBlockMerge(currentLocation)) {
|
|
1182
959
|
return;
|
|
1183
960
|
}
|
|
1184
961
|
const parentLocation = provingState.getParentLocation(currentLocation);
|
|
1185
962
|
if (parentLocation.level === 0) {
|
|
1186
|
-
|
|
963
|
+
this.checkAndEnqueueSubTreeResolution(provingState);
|
|
1187
964
|
} else {
|
|
1188
965
|
this.enqueueBlockMergeRollup(provingState, parentLocation);
|
|
1189
966
|
}
|
|
1190
967
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
if (
|
|
1199
|
-
|
|
1200
|
-
}
|
|
1201
|
-
const parentLocation = provingState.getParentLocation(currentLocation);
|
|
1202
|
-
if (parentLocation.level === 0) {
|
|
1203
|
-
this.checkAndEnqueueRootRollup(provingState);
|
|
1204
|
-
} else {
|
|
1205
|
-
this.enqueueCheckpointMergeRollup(provingState, parentLocation);
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
checkAndEnqueueRootRollup(provingState) {
|
|
1209
|
-
if (!provingState.isReadyForRootRollup()) {
|
|
1210
|
-
this.logger.debug('Not ready for root rollup');
|
|
968
|
+
/**
|
|
969
|
+
* Sub-tree analogue of the orchestrator's `checkAndEnqueueCheckpointRootRollup`:
|
|
970
|
+
* resolves the sub-tree promise with the block-level proof outputs once they're all ready,
|
|
971
|
+
* instead of escalating to the checkpoint root rollup.
|
|
972
|
+
*/ checkAndEnqueueSubTreeResolution(provingState) {
|
|
973
|
+
const proofs = provingState.getSubTreeOutputProofs();
|
|
974
|
+
const nonEmpty = proofs.filter((p)=>!!p);
|
|
975
|
+
if (proofs.length !== nonEmpty.length) {
|
|
976
|
+
// Block merge tree not fully resolved yet — retried as more block proofs land.
|
|
1211
977
|
return;
|
|
1212
978
|
}
|
|
1213
|
-
this.
|
|
979
|
+
this.subTreeResult.resolve({
|
|
980
|
+
blockProofOutputs: nonEmpty,
|
|
981
|
+
previousArchiveSiblingPath: provingState.getLastArchiveSiblingPath()
|
|
982
|
+
});
|
|
1214
983
|
}
|
|
1215
984
|
/**
|
|
1216
|
-
* Executes the VM circuit for a public function
|
|
1217
|
-
*
|
|
1218
|
-
* @param provingState - The proving state being operated on
|
|
1219
|
-
* @param txIndex - The index of the transaction being proven
|
|
985
|
+
* Executes the VM circuit for a public function. Enqueues the base rollup once the
|
|
986
|
+
* tx's chonk-verifier + VM proofs are both ready.
|
|
1220
987
|
*/ enqueueVM(provingState, txIndex) {
|
|
1221
988
|
if (!provingState.verifyState()) {
|
|
1222
989
|
this.logger.debug(`Not running VM circuit as state is no longer valid`);
|
|
1223
990
|
return;
|
|
1224
991
|
}
|
|
1225
992
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
1226
|
-
|
|
1227
|
-
[Attributes.TX_HASH]: txProvingState.processedTx.hash.toString()
|
|
1228
|
-
}, async (signal)=>{
|
|
993
|
+
this.deferredProving(provingState, this.wrapCircuitCall('getAvmProof', async (signal)=>{
|
|
1229
994
|
const inputs = txProvingState.getAvmInputs();
|
|
1230
995
|
return await this.prover.getAvmProof(inputs, signal, provingState.epochNumber);
|
|
1231
|
-
}
|
|
1232
|
-
|
|
996
|
+
}, {
|
|
997
|
+
[Attributes.TX_HASH]: txProvingState.processedTx.hash.toString()
|
|
998
|
+
}), (proof)=>{
|
|
1233
999
|
this.logger.debug(`Proven VM for tx index: ${txIndex}`);
|
|
1234
1000
|
txProvingState.setAvmProof(proof);
|
|
1235
1001
|
this.checkAndEnqueueBaseRollup(provingState, txIndex);
|
|
@@ -1240,8 +1006,61 @@ _dec = trackSpan('ProvingOrchestrator.startNewBlock', (blockNumber)=>({
|
|
|
1240
1006
|
if (!txProvingState.ready()) {
|
|
1241
1007
|
return;
|
|
1242
1008
|
}
|
|
1243
|
-
//
|
|
1009
|
+
// All upstream proofs (chonk verifier and, if required, vm) are ready — proceed to the base rollup.
|
|
1244
1010
|
this.logger.debug(`Public functions completed for tx ${txIndex} enqueueing base rollup`);
|
|
1245
1011
|
this.enqueueBaseRollup(provingState, txIndex);
|
|
1246
1012
|
}
|
|
1013
|
+
// Flagged as protected so unit tests can override.
|
|
1014
|
+
async verifyBuiltBlockAgainstSyncedState(provingState) {
|
|
1015
|
+
const builtBlockHeader = provingState.getBuiltBlockHeader();
|
|
1016
|
+
if (!builtBlockHeader) {
|
|
1017
|
+
this.logger.debug('Block header not built yet, skipping header check.');
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
const output = provingState.getBlockRootRollupOutput();
|
|
1021
|
+
if (!output) {
|
|
1022
|
+
this.logger.debug('Block root rollup proof not built yet, skipping header check.');
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
const newArchive = provingState.getBuiltArchive();
|
|
1026
|
+
if (!newArchive) {
|
|
1027
|
+
this.logger.debug('Archive snapshot not yet captured, skipping header check.');
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
const header = await buildHeaderFromCircuitOutputs(output);
|
|
1031
|
+
if (!(await header.hash()).equals(await builtBlockHeader.hash())) {
|
|
1032
|
+
this.logger.error(`Block header mismatch.\nCircuit: ${inspect(header)}\nComputed: ${inspect(builtBlockHeader)}`);
|
|
1033
|
+
provingState.reject(`Block header hash mismatch.`);
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
const blockNumber = provingState.blockNumber;
|
|
1037
|
+
const syncedArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.dbProvider.getSnapshot(blockNumber));
|
|
1038
|
+
if (!syncedArchive.equals(newArchive)) {
|
|
1039
|
+
this.logger.error(`Archive tree mismatch for block ${blockNumber}: world state synced to ${inspect(syncedArchive)} but built ${inspect(newArchive)}`);
|
|
1040
|
+
provingState.reject(`Archive tree mismatch.`);
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
const circuitArchive = output.newArchive;
|
|
1044
|
+
if (!newArchive.equals(circuitArchive)) {
|
|
1045
|
+
this.logger.error(`New archive mismatch.\nCircuit: ${output.newArchive}\nComputed: ${newArchive}`);
|
|
1046
|
+
provingState.reject(`New archive mismatch.`);
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
getDbForBlock(blockNumber) {
|
|
1051
|
+
const db = this.dbs.get(blockNumber);
|
|
1052
|
+
if (!db) {
|
|
1053
|
+
throw new Error(`World state fork for block ${blockNumber} not found.`);
|
|
1054
|
+
}
|
|
1055
|
+
return db;
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Wraps a circuit call with a tracer span and circuit attributes. Replaces the
|
|
1059
|
+
* `ProvingScheduler.wrapCircuitCall` indirection that used to live on the abstract base.
|
|
1060
|
+
*/ wrapCircuitCall(circuitName, fn, attributes = {}) {
|
|
1061
|
+
return wrapCallbackInSpan(this.tracer, `CheckpointSubTreeOrchestrator.prover.${circuitName}`, {
|
|
1062
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: circuitName,
|
|
1063
|
+
...attributes
|
|
1064
|
+
}, fn);
|
|
1065
|
+
}
|
|
1247
1066
|
}
|