@aztec/prover-client 0.0.0-test.1 → 0.0.1-commit.0b941701
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 +8 -8
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +12 -2
- package/dest/index.d.ts +1 -1
- package/dest/light/index.d.ts +2 -0
- package/dest/light/index.d.ts.map +1 -0
- package/dest/light/index.js +1 -0
- package/dest/light/lightweight_checkpoint_builder.d.ts +44 -0
- package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -0
- package/dest/light/lightweight_checkpoint_builder.js +194 -0
- package/dest/mocks/fixtures.d.ts +8 -8
- package/dest/mocks/fixtures.d.ts.map +1 -1
- package/dest/mocks/fixtures.js +34 -16
- package/dest/mocks/test_context.d.ts +43 -32
- package/dest/mocks/test_context.d.ts.map +1 -1
- package/dest/mocks/test_context.js +149 -87
- package/dest/orchestrator/block-building-helpers.d.ts +37 -30
- package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
- package/dest/orchestrator/block-building-helpers.js +170 -189
- package/dest/orchestrator/block-proving-state.d.ts +70 -48
- package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/block-proving-state.js +282 -177
- package/dest/orchestrator/checkpoint-proving-state.d.ts +76 -0
- package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -0
- package/dest/orchestrator/checkpoint-proving-state.js +243 -0
- package/dest/orchestrator/epoch-proving-state.d.ts +43 -28
- package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/epoch-proving-state.js +177 -73
- package/dest/orchestrator/index.d.ts +1 -1
- package/dest/orchestrator/orchestrator.d.ts +51 -35
- package/dest/orchestrator/orchestrator.d.ts.map +1 -1
- package/dest/orchestrator/orchestrator.js +830 -278
- package/dest/orchestrator/orchestrator_metrics.d.ts +1 -1
- package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -1
- package/dest/orchestrator/orchestrator_metrics.js +2 -6
- package/dest/orchestrator/tx-proving-state.d.ts +15 -12
- package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/tx-proving-state.js +27 -44
- package/dest/prover-client/factory.d.ts +3 -3
- package/dest/prover-client/factory.d.ts.map +1 -1
- package/dest/prover-client/index.d.ts +1 -1
- package/dest/prover-client/prover-client.d.ts +5 -5
- package/dest/prover-client/prover-client.d.ts.map +1 -1
- package/dest/prover-client/prover-client.js +7 -6
- package/dest/prover-client/server-epoch-prover.d.ts +16 -12
- package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
- package/dest/prover-client/server-epoch-prover.js +11 -11
- package/dest/proving_broker/broker_prover_facade.d.ts +25 -17
- package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
- package/dest/proving_broker/broker_prover_facade.js +59 -40
- package/dest/proving_broker/config.d.ts +23 -10
- package/dest/proving_broker/config.d.ts.map +1 -1
- package/dest/proving_broker/config.js +29 -6
- package/dest/proving_broker/factory.d.ts +2 -2
- package/dest/proving_broker/factory.d.ts.map +1 -1
- package/dest/proving_broker/factory.js +5 -1
- package/dest/proving_broker/fixtures.d.ts +3 -2
- package/dest/proving_broker/fixtures.d.ts.map +1 -1
- package/dest/proving_broker/fixtures.js +3 -2
- package/dest/proving_broker/index.d.ts +1 -1
- package/dest/proving_broker/proof_store/factory.d.ts +2 -2
- package/dest/proving_broker/proof_store/factory.js +1 -1
- package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +1 -1
- package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +1 -1
- package/dest/proving_broker/proof_store/gcs_proof_store.js +1 -0
- package/dest/proving_broker/proof_store/index.d.ts +2 -1
- package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
- package/dest/proving_broker/proof_store/index.js +1 -0
- package/dest/proving_broker/proof_store/inline_proof_store.d.ts +1 -1
- package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -1
- package/dest/proving_broker/proof_store/proof_store.d.ts +1 -1
- package/dest/proving_broker/proving_agent.d.ts +6 -11
- package/dest/proving_broker/proving_agent.d.ts.map +1 -1
- package/dest/proving_broker/proving_agent.js +84 -63
- package/dest/proving_broker/proving_broker.d.ts +13 -4
- package/dest/proving_broker/proving_broker.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker.js +40 -33
- package/dest/proving_broker/proving_broker_database/memory.d.ts +3 -2
- package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker_database/memory.js +1 -1
- package/dest/proving_broker/proving_broker_database/persisted.d.ts +5 -3
- package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker_database/persisted.js +401 -11
- package/dest/proving_broker/proving_broker_database.d.ts +3 -2
- package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker_instrumentation.d.ts +1 -1
- package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker_instrumentation.js +11 -35
- package/dest/proving_broker/proving_job_controller.d.ts +9 -9
- package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
- package/dest/proving_broker/proving_job_controller.js +87 -60
- package/dest/proving_broker/rpc.d.ts +4 -6
- package/dest/proving_broker/rpc.d.ts.map +1 -1
- package/dest/proving_broker/rpc.js +1 -4
- package/dest/test/mock_proof_store.d.ts +9 -0
- package/dest/test/mock_proof_store.d.ts.map +1 -0
- package/dest/test/mock_proof_store.js +10 -0
- package/dest/test/mock_prover.d.ts +23 -17
- package/dest/test/mock_prover.d.ts.map +1 -1
- package/dest/test/mock_prover.js +38 -20
- package/package.json +33 -31
- package/src/config.ts +25 -9
- package/src/light/index.ts +1 -0
- package/src/light/lightweight_checkpoint_builder.ts +274 -0
- package/src/mocks/fixtures.ts +44 -39
- package/src/mocks/test_context.ts +223 -116
- package/src/orchestrator/block-building-helpers.ts +258 -334
- package/src/orchestrator/block-proving-state.ts +325 -231
- package/src/orchestrator/checkpoint-proving-state.ts +349 -0
- package/src/orchestrator/epoch-proving-state.ts +237 -111
- package/src/orchestrator/orchestrator.ts +627 -318
- package/src/orchestrator/orchestrator_metrics.ts +2 -6
- package/src/orchestrator/tx-proving-state.ts +48 -66
- package/src/prover-client/factory.ts +6 -2
- package/src/prover-client/prover-client.ts +27 -26
- package/src/prover-client/server-epoch-prover.ts +40 -22
- package/src/proving_broker/broker_prover_facade.ts +206 -128
- package/src/proving_broker/config.ts +34 -7
- package/src/proving_broker/factory.ts +2 -1
- package/src/proving_broker/fixtures.ts +8 -3
- package/src/proving_broker/proof_store/factory.ts +1 -1
- package/src/proving_broker/proof_store/gcs_proof_store.ts +5 -1
- package/src/proving_broker/proof_store/index.ts +1 -0
- package/src/proving_broker/proof_store/inline_proof_store.ts +1 -1
- package/src/proving_broker/proving_agent.ts +90 -64
- package/src/proving_broker/proving_broker.ts +57 -41
- package/src/proving_broker/proving_broker_database/memory.ts +3 -2
- package/src/proving_broker/proving_broker_database/persisted.ts +29 -13
- package/src/proving_broker/proving_broker_database.ts +2 -1
- package/src/proving_broker/proving_broker_instrumentation.ts +10 -35
- package/src/proving_broker/proving_job_controller.ts +92 -81
- package/src/proving_broker/rpc.ts +1 -6
- package/src/test/mock_proof_store.ts +14 -0
- package/src/test/mock_prover.ts +156 -64
- package/dest/bin/get-proof-inputs.d.ts +0 -2
- package/dest/bin/get-proof-inputs.d.ts.map +0 -1
- package/dest/bin/get-proof-inputs.js +0 -51
- package/dest/block_builder/index.d.ts +0 -6
- package/dest/block_builder/index.d.ts.map +0 -1
- package/dest/block_builder/index.js +0 -1
- package/dest/block_builder/light.d.ts +0 -33
- package/dest/block_builder/light.d.ts.map +0 -1
- package/dest/block_builder/light.js +0 -82
- package/dest/proving_broker/proving_agent_instrumentation.d.ts +0 -8
- package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +0 -1
- package/dest/proving_broker/proving_agent_instrumentation.js +0 -16
- package/src/bin/get-proof-inputs.ts +0 -59
- package/src/block_builder/index.ts +0 -6
- package/src/block_builder/light.ts +0 -101
- package/src/proving_broker/proving_agent_instrumentation.ts +0 -21
|
@@ -1,43 +1,48 @@
|
|
|
1
|
+
import { BatchedBlob, FinalBlobBatchingChallenges, SpongeBlob } from '@aztec/blob-lib/types';
|
|
1
2
|
import {
|
|
2
|
-
AVM_PROOF_LENGTH_IN_FIELDS,
|
|
3
|
-
AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS,
|
|
4
3
|
L1_TO_L2_MSG_SUBTREE_HEIGHT,
|
|
5
|
-
|
|
4
|
+
L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
5
|
+
NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH,
|
|
6
6
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
7
7
|
NUM_BASE_PARITY_PER_ROOT_PARITY,
|
|
8
|
-
type TUBE_PROOF_LENGTH,
|
|
9
8
|
} from '@aztec/constants';
|
|
10
|
-
import {
|
|
9
|
+
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
10
|
+
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
11
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
11
12
|
import { AbortError } from '@aztec/foundation/error';
|
|
12
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
13
13
|
import { createLogger } from '@aztec/foundation/log';
|
|
14
14
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
15
15
|
import { assertLength } from '@aztec/foundation/serialize';
|
|
16
16
|
import { pushTestData } from '@aztec/foundation/testing';
|
|
17
17
|
import { elapsed } from '@aztec/foundation/timer';
|
|
18
18
|
import type { TreeNodeLocation } from '@aztec/foundation/trees';
|
|
19
|
-
import {
|
|
20
|
-
import { L2Block } from '@aztec/stdlib/block';
|
|
19
|
+
import { EthAddress } from '@aztec/stdlib/block';
|
|
21
20
|
import type {
|
|
22
21
|
EpochProver,
|
|
23
22
|
ForkMerkleTreeOperations,
|
|
24
23
|
MerkleTreeWriteOperations,
|
|
25
|
-
|
|
24
|
+
PublicInputsAndRecursiveProof,
|
|
25
|
+
ReadonlyWorldStateAccess,
|
|
26
26
|
ServerCircuitProver,
|
|
27
27
|
} from '@aztec/stdlib/interfaces/server';
|
|
28
|
-
import {
|
|
29
|
-
import { makeEmptyRecursiveProof } from '@aztec/stdlib/proofs';
|
|
28
|
+
import type { Proof } from '@aztec/stdlib/proofs';
|
|
30
29
|
import {
|
|
31
30
|
type BaseRollupHints,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
BlockRootEmptyTxFirstRollupPrivateInputs,
|
|
32
|
+
BlockRootFirstRollupPrivateInputs,
|
|
33
|
+
BlockRootSingleTxFirstRollupPrivateInputs,
|
|
34
|
+
BlockRootSingleTxRollupPrivateInputs,
|
|
35
|
+
CheckpointConstantData,
|
|
36
|
+
CheckpointRootSingleBlockRollupPrivateInputs,
|
|
37
|
+
PrivateTxBaseRollupPrivateInputs,
|
|
38
|
+
PublicChonkVerifierPrivateInputs,
|
|
39
|
+
PublicChonkVerifierPublicInputs,
|
|
40
|
+
RootRollupPublicInputs,
|
|
36
41
|
} from '@aztec/stdlib/rollup';
|
|
37
42
|
import type { CircuitName } from '@aztec/stdlib/stats';
|
|
38
43
|
import { type AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
44
|
+
import type { BlockHeader, ProcessedTx, Tx } from '@aztec/stdlib/tx';
|
|
45
|
+
import type { UInt64 } from '@aztec/stdlib/types';
|
|
41
46
|
import {
|
|
42
47
|
Attributes,
|
|
43
48
|
type TelemetryClient,
|
|
@@ -50,21 +55,29 @@ import {
|
|
|
50
55
|
import { inspect } from 'util';
|
|
51
56
|
|
|
52
57
|
import {
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
buildHeaderFromCircuitOutputs,
|
|
59
|
+
getLastSiblingPath,
|
|
60
|
+
getPublicChonkVerifierPrivateInputsFromTx,
|
|
55
61
|
getRootTreeSiblingPath,
|
|
56
62
|
getSubtreeSiblingPath,
|
|
57
63
|
getTreeSnapshot,
|
|
64
|
+
insertSideEffectsAndBuildBaseRollupHints,
|
|
58
65
|
validatePartialState,
|
|
59
66
|
validateTx,
|
|
60
67
|
} from './block-building-helpers.js';
|
|
61
68
|
import type { BlockProvingState } from './block-proving-state.js';
|
|
69
|
+
import type { CheckpointProvingState } from './checkpoint-proving-state.js';
|
|
62
70
|
import { EpochProvingState, type ProvingResult, type TreeSnapshots } from './epoch-proving-state.js';
|
|
63
71
|
import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
|
|
64
72
|
import { TxProvingState } from './tx-proving-state.js';
|
|
65
73
|
|
|
66
74
|
const logger = createLogger('prover-client:orchestrator');
|
|
67
75
|
|
|
76
|
+
type WorldStateFork = {
|
|
77
|
+
fork: MerkleTreeWriteOperations;
|
|
78
|
+
cleanupPromise: Promise<void> | undefined;
|
|
79
|
+
};
|
|
80
|
+
|
|
68
81
|
/**
|
|
69
82
|
* Implements an event driven proving scheduler to build the recursive proof tree. The idea being:
|
|
70
83
|
* 1. Transactions are provided to the scheduler post simulation.
|
|
@@ -85,12 +98,14 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
85
98
|
|
|
86
99
|
private provingPromise: Promise<ProvingResult> | undefined = undefined;
|
|
87
100
|
private metrics: ProvingOrchestratorMetrics;
|
|
88
|
-
|
|
101
|
+
// eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
|
|
102
|
+
private dbs: Map<BlockNumber, WorldStateFork> = new Map();
|
|
89
103
|
|
|
90
104
|
constructor(
|
|
91
|
-
private dbProvider: ForkMerkleTreeOperations,
|
|
105
|
+
private dbProvider: ReadonlyWorldStateAccess & ForkMerkleTreeOperations,
|
|
92
106
|
private prover: ServerCircuitProver,
|
|
93
|
-
private readonly proverId:
|
|
107
|
+
private readonly proverId: EthAddress,
|
|
108
|
+
private readonly cancelJobsOnStop: boolean = false,
|
|
94
109
|
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
95
110
|
) {
|
|
96
111
|
this.metrics = new ProvingOrchestratorMetrics(telemetryClient, 'ProvingOrchestrator');
|
|
@@ -100,73 +115,167 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
100
115
|
return this.metrics.tracer;
|
|
101
116
|
}
|
|
102
117
|
|
|
103
|
-
public getProverId():
|
|
118
|
+
public getProverId(): EthAddress {
|
|
104
119
|
return this.proverId;
|
|
105
120
|
}
|
|
106
121
|
|
|
122
|
+
public getNumActiveForks() {
|
|
123
|
+
return this.dbs.size;
|
|
124
|
+
}
|
|
125
|
+
|
|
107
126
|
public stop(): Promise<void> {
|
|
108
127
|
this.cancel();
|
|
109
128
|
return Promise.resolve();
|
|
110
129
|
}
|
|
111
130
|
|
|
112
|
-
public startNewEpoch(
|
|
131
|
+
public startNewEpoch(
|
|
132
|
+
epochNumber: EpochNumber,
|
|
133
|
+
totalNumCheckpoints: number,
|
|
134
|
+
finalBlobBatchingChallenges: FinalBlobBatchingChallenges,
|
|
135
|
+
) {
|
|
136
|
+
if (this.provingState?.verifyState()) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`Cannot start epoch ${epochNumber} when epoch ${this.provingState.epochNumber} is still being processed.`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
113
142
|
const { promise: _promise, resolve, reject } = promiseWithResolvers<ProvingResult>();
|
|
114
143
|
const promise = _promise.catch((reason): ProvingResult => ({ status: 'failure', reason }));
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
144
|
+
logger.info(`Starting epoch ${epochNumber} with ${totalNumCheckpoints} checkpoints.`);
|
|
145
|
+
this.provingState = new EpochProvingState(
|
|
146
|
+
epochNumber,
|
|
147
|
+
totalNumCheckpoints,
|
|
148
|
+
finalBlobBatchingChallenges,
|
|
149
|
+
provingState => this.checkAndEnqueueCheckpointRootRollup(provingState),
|
|
150
|
+
resolve,
|
|
151
|
+
reject,
|
|
152
|
+
);
|
|
120
153
|
this.provingPromise = promise;
|
|
121
154
|
}
|
|
122
155
|
|
|
123
156
|
/**
|
|
124
|
-
* Starts
|
|
125
|
-
* @param
|
|
126
|
-
* @param
|
|
127
|
-
* @
|
|
157
|
+
* Starts a new checkpoint.
|
|
158
|
+
* @param checkpointIndex - The index of the checkpoint in the epoch.
|
|
159
|
+
* @param constants - The constants for this checkpoint.
|
|
160
|
+
* @param l1ToL2Messages - The set of L1 to L2 messages to be inserted at the beginning of this checkpoint.
|
|
161
|
+
* @param totalNumBlocks - The total number of blocks expected in the checkpoint (must be at least one).
|
|
162
|
+
* @param headerOfLastBlockInPreviousCheckpoint - The header of the last block in the previous checkpoint.
|
|
128
163
|
*/
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
164
|
+
public async startNewCheckpoint(
|
|
165
|
+
checkpointIndex: number,
|
|
166
|
+
constants: CheckpointConstantData,
|
|
167
|
+
l1ToL2Messages: Fr[],
|
|
168
|
+
totalNumBlocks: number,
|
|
169
|
+
headerOfLastBlockInPreviousCheckpoint: BlockHeader,
|
|
170
|
+
) {
|
|
133
171
|
if (!this.provingState) {
|
|
134
|
-
throw new Error(
|
|
172
|
+
throw new Error('Empty epoch proving state. Call startNewEpoch before starting a checkpoint.');
|
|
135
173
|
}
|
|
136
174
|
|
|
137
|
-
if (!this.provingState
|
|
138
|
-
throw new Error(`Epoch not accepting further
|
|
175
|
+
if (!this.provingState.isAcceptingCheckpoints()) {
|
|
176
|
+
throw new Error(`Epoch not accepting further checkpoints.`);
|
|
139
177
|
}
|
|
140
178
|
|
|
141
|
-
|
|
142
|
-
|
|
179
|
+
// Fork world state at the end of the immediately previous block.
|
|
180
|
+
const lastBlockNumber = headerOfLastBlockInPreviousCheckpoint.globalVariables.blockNumber;
|
|
181
|
+
const db = await this.dbProvider.fork(lastBlockNumber);
|
|
182
|
+
|
|
183
|
+
const firstBlockNumber = BlockNumber(lastBlockNumber + 1);
|
|
184
|
+
this.dbs.set(firstBlockNumber, { fork: db, cleanupPromise: undefined });
|
|
185
|
+
|
|
186
|
+
// Get archive sibling path before any block in this checkpoint lands.
|
|
187
|
+
const lastArchiveSiblingPath = await getLastSiblingPath(MerkleTreeId.ARCHIVE, db);
|
|
188
|
+
|
|
189
|
+
// Insert all the l1 to l2 messages into the db. And get the states before and after the insertion.
|
|
190
|
+
const {
|
|
191
|
+
lastL1ToL2MessageTreeSnapshot,
|
|
192
|
+
lastL1ToL2MessageSubtreeRootSiblingPath,
|
|
193
|
+
newL1ToL2MessageTreeSnapshot,
|
|
194
|
+
newL1ToL2MessageSubtreeRootSiblingPath,
|
|
195
|
+
} = await this.updateL1ToL2MessageTree(l1ToL2Messages, db);
|
|
196
|
+
|
|
197
|
+
this.provingState.startNewCheckpoint(
|
|
198
|
+
checkpointIndex,
|
|
199
|
+
constants,
|
|
200
|
+
totalNumBlocks,
|
|
201
|
+
headerOfLastBlockInPreviousCheckpoint,
|
|
202
|
+
lastArchiveSiblingPath,
|
|
203
|
+
l1ToL2Messages,
|
|
204
|
+
lastL1ToL2MessageTreeSnapshot,
|
|
205
|
+
lastL1ToL2MessageSubtreeRootSiblingPath,
|
|
206
|
+
newL1ToL2MessageTreeSnapshot,
|
|
207
|
+
newL1ToL2MessageSubtreeRootSiblingPath,
|
|
143
208
|
);
|
|
209
|
+
}
|
|
144
210
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
211
|
+
/**
|
|
212
|
+
* Starts off a new block
|
|
213
|
+
* @param blockNumber - The block number
|
|
214
|
+
* @param timestamp - The timestamp of the block. This is only required for constructing the private inputs for the
|
|
215
|
+
* block that doesn't have any txs.
|
|
216
|
+
* @param totalNumTxs - The total number of txs in the block
|
|
217
|
+
*/
|
|
218
|
+
@trackSpan('ProvingOrchestrator.startNewBlock', blockNumber => ({
|
|
219
|
+
[Attributes.BLOCK_NUMBER]: blockNumber,
|
|
220
|
+
}))
|
|
221
|
+
public async startNewBlock(blockNumber: BlockNumber, timestamp: UInt64, totalNumTxs: number) {
|
|
222
|
+
if (!this.provingState) {
|
|
223
|
+
throw new Error('Empty epoch proving state. Call startNewEpoch before starting a block.');
|
|
224
|
+
}
|
|
148
225
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
226
|
+
const checkpointProvingState = this.provingState.getCheckpointProvingStateByBlockNumber(blockNumber);
|
|
227
|
+
if (!checkpointProvingState) {
|
|
228
|
+
throw new Error(`Checkpoint not started. Call startNewCheckpoint first.`);
|
|
229
|
+
}
|
|
152
230
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
231
|
+
if (!checkpointProvingState.isAcceptingBlocks()) {
|
|
232
|
+
throw new Error(`Checkpoint not accepting further blocks.`);
|
|
233
|
+
}
|
|
156
234
|
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
235
|
+
const constants = checkpointProvingState.constants;
|
|
236
|
+
logger.info(`Starting block ${blockNumber} for slot ${constants.slotNumber}.`);
|
|
237
|
+
|
|
238
|
+
// Fork the db only when it's not already set. The db for the first block is set in `startNewCheckpoint`.
|
|
239
|
+
if (!this.dbs.has(blockNumber)) {
|
|
240
|
+
// Fork world state at the end of the immediately previous block
|
|
241
|
+
const db = await this.dbProvider.fork(BlockNumber(blockNumber - 1));
|
|
242
|
+
this.dbs.set(blockNumber, { fork: db, cleanupPromise: undefined });
|
|
243
|
+
}
|
|
244
|
+
const db = this.dbs.get(blockNumber)!.fork;
|
|
245
|
+
|
|
246
|
+
// Get archive snapshot and sibling path before any txs in this block lands.
|
|
247
|
+
const lastArchiveTreeSnapshot = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
|
|
248
|
+
const lastArchiveSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.ARCHIVE, db);
|
|
249
|
+
|
|
250
|
+
const blockProvingState = checkpointProvingState.startNewBlock(
|
|
251
|
+
blockNumber,
|
|
252
|
+
timestamp,
|
|
253
|
+
totalNumTxs,
|
|
254
|
+
lastArchiveTreeSnapshot,
|
|
255
|
+
lastArchiveSiblingPath,
|
|
165
256
|
);
|
|
166
257
|
|
|
167
|
-
// Enqueue base parity circuits for the block
|
|
168
|
-
|
|
169
|
-
|
|
258
|
+
// Enqueue base parity circuits for the first block in the checkpoint.
|
|
259
|
+
if (blockProvingState.index === 0) {
|
|
260
|
+
for (let i = 0; i < NUM_BASE_PARITY_PER_ROOT_PARITY; i++) {
|
|
261
|
+
this.enqueueBaseParityCircuit(checkpointProvingState, blockProvingState, i);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Because `addTxs` won't be called for a block without txs, and that's where the sponge blob state is computed.
|
|
266
|
+
// We need to set its end sponge blob here, which will become the start sponge blob for the next block.
|
|
267
|
+
if (totalNumTxs === 0) {
|
|
268
|
+
const endState = await db.getStateReference();
|
|
269
|
+
blockProvingState.setEndState(endState);
|
|
270
|
+
|
|
271
|
+
const endSpongeBlob = blockProvingState.getStartSpongeBlob().clone();
|
|
272
|
+
const blockEndBlobFields = blockProvingState.getBlockEndBlobFields();
|
|
273
|
+
await endSpongeBlob.absorb(blockEndBlobFields);
|
|
274
|
+
blockProvingState.setEndSpongeBlob(endSpongeBlob);
|
|
275
|
+
|
|
276
|
+
// Try to accumulate the out hashes and blobs as far as we can:
|
|
277
|
+
await this.provingState.accumulateCheckpointOutHashes();
|
|
278
|
+
await this.provingState.setBlobAccumulators();
|
|
170
279
|
}
|
|
171
280
|
}
|
|
172
281
|
|
|
@@ -178,28 +287,40 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
178
287
|
[Attributes.BLOCK_TXS_COUNT]: txs.length,
|
|
179
288
|
}))
|
|
180
289
|
public async addTxs(txs: ProcessedTx[]): Promise<void> {
|
|
290
|
+
if (!this.provingState) {
|
|
291
|
+
throw new Error(`Empty epoch proving state. Call startNewEpoch before adding txs.`);
|
|
292
|
+
}
|
|
293
|
+
|
|
181
294
|
if (!txs.length) {
|
|
182
295
|
// To avoid an ugly throw below. If we require an empty block, we can just call setBlockCompleted
|
|
183
296
|
// on a block with no txs. We cannot do that here because we cannot find the blockNumber without any txs.
|
|
184
297
|
logger.warn(`Provided no txs to orchestrator addTxs.`);
|
|
185
298
|
return;
|
|
186
299
|
}
|
|
187
|
-
|
|
188
|
-
const
|
|
300
|
+
|
|
301
|
+
const blockNumber = BlockNumber(txs[0].globalVariables.blockNumber);
|
|
302
|
+
const provingState = this.provingState.getBlockProvingStateByBlockNumber(blockNumber!);
|
|
189
303
|
if (!provingState) {
|
|
190
|
-
throw new Error(`
|
|
304
|
+
throw new Error(`Proving state for block ${blockNumber} not found. Call startNewBlock first.`);
|
|
191
305
|
}
|
|
192
306
|
|
|
193
|
-
if (provingState.totalNumTxs) {
|
|
307
|
+
if (provingState.totalNumTxs !== txs.length) {
|
|
308
|
+
throw new Error(
|
|
309
|
+
`Block ${blockNumber} should be filled with ${provingState.totalNumTxs} txs. Received ${txs.length} txs.`,
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (!provingState.isAcceptingTxs()) {
|
|
194
314
|
throw new Error(`Block ${blockNumber} has been initialized with transactions.`);
|
|
195
315
|
}
|
|
196
316
|
|
|
197
|
-
|
|
198
|
-
|
|
317
|
+
logger.info(`Adding ${txs.length} transactions to block ${blockNumber}`);
|
|
318
|
+
|
|
319
|
+
const db = this.dbs.get(blockNumber)!.fork;
|
|
320
|
+
const lastArchive = provingState.lastArchiveTreeSnapshot;
|
|
321
|
+
const newL1ToL2MessageTreeSnapshot = provingState.newL1ToL2MessageTreeSnapshot;
|
|
322
|
+
const spongeBlobState = provingState.getStartSpongeBlob().clone();
|
|
199
323
|
|
|
200
|
-
logger.info(
|
|
201
|
-
`Adding ${txs.length} transactions with ${numBlobFields} blob fields to block ${provingState.blockNumber}`,
|
|
202
|
-
);
|
|
203
324
|
for (const tx of txs) {
|
|
204
325
|
try {
|
|
205
326
|
if (!provingState.verifyState()) {
|
|
@@ -208,15 +329,32 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
208
329
|
|
|
209
330
|
validateTx(tx);
|
|
210
331
|
|
|
211
|
-
logger.
|
|
332
|
+
logger.debug(`Received transaction: ${tx.hash}`);
|
|
333
|
+
|
|
334
|
+
const startSpongeBlob = spongeBlobState.clone();
|
|
335
|
+
const [hints, treeSnapshots] = await this.prepareBaseRollupInputs(
|
|
336
|
+
tx,
|
|
337
|
+
lastArchive,
|
|
338
|
+
newL1ToL2MessageTreeSnapshot,
|
|
339
|
+
startSpongeBlob,
|
|
340
|
+
db,
|
|
341
|
+
);
|
|
212
342
|
|
|
213
|
-
|
|
214
|
-
|
|
343
|
+
if (!provingState.verifyState()) {
|
|
344
|
+
throw new Error(`Unable to add transaction, preparing base inputs failed`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
await spongeBlobState.absorb(tx.txEffect.toBlobFields());
|
|
348
|
+
|
|
349
|
+
const txProvingState = new TxProvingState(tx, hints, treeSnapshots, this.proverId.toField());
|
|
215
350
|
const txIndex = provingState.addNewTx(txProvingState);
|
|
216
|
-
this.getOrEnqueueTube(provingState, txIndex);
|
|
217
351
|
if (txProvingState.requireAvmProof) {
|
|
352
|
+
this.getOrEnqueueChonkVerifier(provingState, txIndex);
|
|
218
353
|
logger.debug(`Enqueueing public VM for tx ${txIndex}`);
|
|
219
354
|
this.enqueueVM(provingState, txIndex);
|
|
355
|
+
} else {
|
|
356
|
+
logger.debug(`Enqueueing base rollup for private-only tx ${txIndex}`);
|
|
357
|
+
this.enqueueBaseRollup(provingState, txIndex);
|
|
220
358
|
}
|
|
221
359
|
} catch (err: any) {
|
|
222
360
|
throw new Error(`Error adding transaction ${tx.hash.toString()} to block ${blockNumber}: ${err.message}`, {
|
|
@@ -224,122 +362,163 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
224
362
|
});
|
|
225
363
|
}
|
|
226
364
|
}
|
|
365
|
+
|
|
366
|
+
const endState = await db.getStateReference();
|
|
367
|
+
provingState.setEndState(endState);
|
|
368
|
+
|
|
369
|
+
const blockEndBlobFields = provingState.getBlockEndBlobFields();
|
|
370
|
+
await spongeBlobState.absorb(blockEndBlobFields);
|
|
371
|
+
|
|
372
|
+
provingState.setEndSpongeBlob(spongeBlobState);
|
|
373
|
+
|
|
374
|
+
// Txs have been added to the block. Now try to accumulate the out hashes and blobs as far as we can:
|
|
375
|
+
await this.provingState.accumulateCheckpointOutHashes();
|
|
376
|
+
await this.provingState.setBlobAccumulators();
|
|
227
377
|
}
|
|
228
378
|
|
|
229
379
|
/**
|
|
230
|
-
* Kickstarts
|
|
231
|
-
* Note that if the
|
|
380
|
+
* Kickstarts chonk verifier circuits for the specified txs. These will be used during epoch proving.
|
|
381
|
+
* Note that if the chonk verifier circuits are not started this way, they will be started nontheless after processing.
|
|
232
382
|
*/
|
|
233
|
-
@trackSpan('ProvingOrchestrator.
|
|
234
|
-
public
|
|
383
|
+
@trackSpan('ProvingOrchestrator.startChonkVerifierCircuits')
|
|
384
|
+
public startChonkVerifierCircuits(txs: Tx[]) {
|
|
235
385
|
if (!this.provingState?.verifyState()) {
|
|
236
|
-
throw new Error(`
|
|
386
|
+
throw new Error(`Empty epoch proving state. call startNewEpoch before starting chonk verifier circuits.`);
|
|
237
387
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
388
|
+
const publicTxs = txs.filter(tx => tx.data.forPublic);
|
|
389
|
+
for (const tx of publicTxs) {
|
|
390
|
+
const txHash = tx.getTxHash().toString();
|
|
391
|
+
const privateInputs = getPublicChonkVerifierPrivateInputsFromTx(tx, this.proverId.toField());
|
|
392
|
+
const tubeProof =
|
|
393
|
+
promiseWithResolvers<
|
|
394
|
+
PublicInputsAndRecursiveProof<
|
|
395
|
+
PublicChonkVerifierPublicInputs,
|
|
396
|
+
typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
|
|
397
|
+
>
|
|
398
|
+
>();
|
|
399
|
+
logger.debug(`Starting chonk verifier circuit for tx ${txHash}`);
|
|
400
|
+
this.doEnqueueChonkVerifier(txHash, privateInputs, proof => {
|
|
401
|
+
tubeProof.resolve(proof);
|
|
402
|
+
});
|
|
403
|
+
this.provingState.cachedChonkVerifierProofs.set(txHash, tubeProof.promise);
|
|
245
404
|
}
|
|
405
|
+
return Promise.resolve();
|
|
246
406
|
}
|
|
247
407
|
|
|
248
408
|
/**
|
|
249
409
|
* Marks the block as completed.
|
|
250
410
|
* Computes the block header and updates the archive tree.
|
|
251
411
|
*/
|
|
252
|
-
@trackSpan('ProvingOrchestrator.setBlockCompleted', (blockNumber:
|
|
412
|
+
@trackSpan('ProvingOrchestrator.setBlockCompleted', (blockNumber: BlockNumber) => ({
|
|
253
413
|
[Attributes.BLOCK_NUMBER]: blockNumber,
|
|
254
414
|
}))
|
|
255
|
-
public async setBlockCompleted(blockNumber:
|
|
415
|
+
public async setBlockCompleted(blockNumber: BlockNumber, expectedHeader?: BlockHeader): Promise<BlockHeader> {
|
|
256
416
|
const provingState = this.provingState?.getBlockProvingStateByBlockNumber(blockNumber);
|
|
257
417
|
if (!provingState) {
|
|
258
418
|
throw new Error(`Block proving state for ${blockNumber} not found`);
|
|
259
419
|
}
|
|
260
420
|
|
|
261
|
-
if
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
421
|
+
// Abort with specific error for the block if there's one.
|
|
422
|
+
const error = provingState.getError();
|
|
423
|
+
if (error) {
|
|
424
|
+
throw new Error(`Block proving failed: ${error}`);
|
|
265
425
|
}
|
|
266
426
|
|
|
427
|
+
// Abort if the proving state is not valid due to errors occurred elsewhere.
|
|
267
428
|
if (!provingState.verifyState()) {
|
|
268
|
-
throw new Error(`
|
|
429
|
+
throw new Error(`Invalid proving state when completing block ${blockNumber}.`);
|
|
269
430
|
}
|
|
270
431
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
// If the proofs were faster than the block building, then we need to try the block root rollup again here
|
|
276
|
-
await this.checkAndEnqueueBlockRootRollup(provingState);
|
|
277
|
-
return provingState.block!;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/** Returns the block as built for a given index. */
|
|
281
|
-
public getBlock(index: number): L2Block {
|
|
282
|
-
const block = this.provingState?.blocks[index]?.block;
|
|
283
|
-
if (!block) {
|
|
284
|
-
throw new Error(`Block at index ${index} not available`);
|
|
432
|
+
if (provingState.isAcceptingTxs()) {
|
|
433
|
+
throw new Error(
|
|
434
|
+
`Block ${blockNumber} is still accepting txs. Call setBlockCompleted after all txs have been added.`,
|
|
435
|
+
);
|
|
285
436
|
}
|
|
286
|
-
return block;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
private async buildBlock(provingState: BlockProvingState, expectedHeader?: BlockHeader) {
|
|
290
|
-
// Collect all new nullifiers, commitments, and contracts from all txs in this block to build body
|
|
291
|
-
const txs = provingState.allTxs.map(a => a.processedTx);
|
|
292
437
|
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
// Given we've applied every change from this block, now assemble the block header
|
|
297
|
-
// and update the archive tree, so we're ready to start processing the next block
|
|
298
|
-
const { header, body } = await buildHeaderAndBodyFromTxs(
|
|
299
|
-
txs,
|
|
300
|
-
provingState.globalVariables,
|
|
301
|
-
provingState.newL1ToL2Messages,
|
|
302
|
-
db,
|
|
303
|
-
);
|
|
438
|
+
// Given we've applied every change from this block, now assemble the block header:
|
|
439
|
+
logger.verbose(`Block ${blockNumber} completed. Assembling header.`);
|
|
440
|
+
const header = await provingState.buildBlockHeader();
|
|
304
441
|
|
|
305
442
|
if (expectedHeader && !header.equals(expectedHeader)) {
|
|
306
443
|
logger.error(`Block header mismatch: header=${header} expectedHeader=${expectedHeader}`);
|
|
307
444
|
throw new Error('Block header mismatch');
|
|
308
445
|
}
|
|
309
446
|
|
|
447
|
+
// Get db for this block
|
|
448
|
+
const db = this.dbs.get(provingState.blockNumber)!.fork;
|
|
449
|
+
|
|
450
|
+
// Update the archive tree, so we're ready to start processing the next block:
|
|
310
451
|
logger.verbose(
|
|
311
452
|
`Updating archive tree with block ${provingState.blockNumber} header ${(await header.hash()).toString()}`,
|
|
312
453
|
);
|
|
313
454
|
await db.updateArchive(header);
|
|
314
455
|
|
|
315
|
-
|
|
316
|
-
const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
|
|
317
|
-
const l2Block = new L2Block(newArchive, header, body);
|
|
318
|
-
|
|
319
|
-
await this.verifyBuiltBlockAgainstSyncedState(l2Block, newArchive);
|
|
456
|
+
await this.verifyBuiltBlockAgainstSyncedState(provingState);
|
|
320
457
|
|
|
321
|
-
|
|
322
|
-
provingState.block = l2Block;
|
|
458
|
+
return header;
|
|
323
459
|
}
|
|
324
460
|
|
|
325
461
|
// Flagged as protected to disable in certain unit tests
|
|
326
|
-
protected async verifyBuiltBlockAgainstSyncedState(
|
|
327
|
-
const
|
|
462
|
+
protected async verifyBuiltBlockAgainstSyncedState(provingState: BlockProvingState) {
|
|
463
|
+
const builtBlockHeader = provingState.getBuiltBlockHeader();
|
|
464
|
+
if (!builtBlockHeader) {
|
|
465
|
+
logger.debug('Block header not built yet, skipping header check.');
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const output = provingState.getBlockRootRollupOutput();
|
|
470
|
+
if (!output) {
|
|
471
|
+
logger.debug('Block root rollup proof not built yet, skipping header check.');
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const header = await buildHeaderFromCircuitOutputs(output);
|
|
475
|
+
|
|
476
|
+
if (!(await header.hash()).equals(await builtBlockHeader.hash())) {
|
|
477
|
+
logger.error(`Block header mismatch.\nCircuit: ${inspect(header)}\nComputed: ${inspect(builtBlockHeader)}`);
|
|
478
|
+
provingState.reject(`Block header hash mismatch.`);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Get db for this block
|
|
483
|
+
const blockNumber = provingState.blockNumber;
|
|
484
|
+
const db = this.dbs.get(blockNumber)!.fork;
|
|
485
|
+
|
|
486
|
+
const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
|
|
487
|
+
const syncedArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.dbProvider.getSnapshot(blockNumber));
|
|
328
488
|
if (!syncedArchive.equals(newArchive)) {
|
|
329
|
-
|
|
330
|
-
`Archive tree mismatch for block ${
|
|
489
|
+
logger.error(
|
|
490
|
+
`Archive tree mismatch for block ${blockNumber}: world state synced to ${inspect(
|
|
331
491
|
syncedArchive,
|
|
332
492
|
)} but built ${inspect(newArchive)}`,
|
|
333
493
|
);
|
|
494
|
+
provingState.reject(`Archive tree mismatch.`);
|
|
495
|
+
return;
|
|
334
496
|
}
|
|
497
|
+
|
|
498
|
+
const circuitArchive = output.newArchive;
|
|
499
|
+
if (!newArchive.equals(circuitArchive)) {
|
|
500
|
+
logger.error(`New archive mismatch.\nCircuit: ${output.newArchive}\nComputed: ${newArchive}`);
|
|
501
|
+
provingState.reject(`New archive mismatch.`);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// TODO(palla/prover): This closes the fork only on the happy path. If this epoch orchestrator
|
|
506
|
+
// is aborted and never reaches this point, it will leak the fork. We need to add a global cleanup,
|
|
507
|
+
// but have to make sure it only runs once all operations are completed, otherwise some function here
|
|
508
|
+
// will attempt to access the fork after it was closed.
|
|
509
|
+
void this.cleanupDBFork(blockNumber);
|
|
335
510
|
}
|
|
336
511
|
|
|
337
512
|
/**
|
|
338
|
-
* Cancel any further proving
|
|
513
|
+
* Cancel any further proving.
|
|
514
|
+
* If cancelJobsOnStop is true, aborts all pending jobs with the broker (which marks them as 'Aborted').
|
|
515
|
+
* If cancelJobsOnStop is false (default), jobs remain in the broker queue and can be reused on restart/reorg.
|
|
339
516
|
*/
|
|
340
517
|
public cancel() {
|
|
341
|
-
|
|
342
|
-
controller.
|
|
518
|
+
if (this.cancelJobsOnStop) {
|
|
519
|
+
for (const controller of this.pendingProvingJobs) {
|
|
520
|
+
controller.abort();
|
|
521
|
+
}
|
|
343
522
|
}
|
|
344
523
|
|
|
345
524
|
this.provingState?.cancel();
|
|
@@ -348,9 +527,13 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
348
527
|
/**
|
|
349
528
|
* Returns the proof for the current epoch.
|
|
350
529
|
*/
|
|
351
|
-
public async
|
|
530
|
+
public async finalizeEpoch(): Promise<{
|
|
531
|
+
publicInputs: RootRollupPublicInputs;
|
|
532
|
+
proof: Proof;
|
|
533
|
+
batchedBlobInputs: BatchedBlob;
|
|
534
|
+
}> {
|
|
352
535
|
if (!this.provingState || !this.provingPromise) {
|
|
353
|
-
throw new Error(`Invalid proving state, an epoch must be proven before it can be
|
|
536
|
+
throw new Error(`Invalid proving state, an epoch must be proven before it can be finalized`);
|
|
354
537
|
}
|
|
355
538
|
|
|
356
539
|
const result = await this.provingPromise!;
|
|
@@ -358,6 +541,8 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
358
541
|
throw new Error(`Epoch proving failed: ${result.reason}`);
|
|
359
542
|
}
|
|
360
543
|
|
|
544
|
+
await this.provingState.finalizeBatchedBlob();
|
|
545
|
+
|
|
361
546
|
const epochProofResult = this.provingState.getEpochProofResult();
|
|
362
547
|
|
|
363
548
|
pushTestData('epochProofResult', {
|
|
@@ -368,18 +553,22 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
368
553
|
return epochProofResult;
|
|
369
554
|
}
|
|
370
555
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
556
|
+
private async cleanupDBFork(blockNumber: BlockNumber): Promise<void> {
|
|
557
|
+
logger.debug(`Cleaning up world state fork for ${blockNumber}`);
|
|
558
|
+
const fork = this.dbs.get(blockNumber);
|
|
559
|
+
if (!fork) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
try {
|
|
564
|
+
if (!fork.cleanupPromise) {
|
|
565
|
+
fork.cleanupPromise = fork.fork.close();
|
|
566
|
+
}
|
|
567
|
+
await fork.cleanupPromise;
|
|
568
|
+
this.dbs.delete(blockNumber);
|
|
569
|
+
} catch (err) {
|
|
570
|
+
logger.error(`Error closing db for block ${blockNumber}`, err);
|
|
381
571
|
}
|
|
382
|
-
return txInputs;
|
|
383
572
|
}
|
|
384
573
|
|
|
385
574
|
/**
|
|
@@ -389,11 +578,11 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
389
578
|
* @param job - The actual job, returns a promise notifying of the job's completion
|
|
390
579
|
*/
|
|
391
580
|
private deferredProving<T>(
|
|
392
|
-
provingState: EpochProvingState |
|
|
581
|
+
provingState: EpochProvingState | CheckpointProvingState | BlockProvingState,
|
|
393
582
|
request: (signal: AbortSignal) => Promise<T>,
|
|
394
583
|
callback: (result: T) => void | Promise<void>,
|
|
395
584
|
) {
|
|
396
|
-
if (!provingState
|
|
585
|
+
if (!provingState.verifyState()) {
|
|
397
586
|
logger.debug(`Not enqueuing job, state no longer valid`);
|
|
398
587
|
return;
|
|
399
588
|
}
|
|
@@ -411,7 +600,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
411
600
|
}
|
|
412
601
|
|
|
413
602
|
const result = await request(controller.signal);
|
|
414
|
-
if (!provingState
|
|
603
|
+
if (!provingState.verifyState()) {
|
|
415
604
|
logger.debug(`State no longer valid, discarding result`);
|
|
416
605
|
return;
|
|
417
606
|
}
|
|
@@ -444,52 +633,59 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
444
633
|
setImmediate(() => void safeJob());
|
|
445
634
|
}
|
|
446
635
|
|
|
447
|
-
private async
|
|
448
|
-
const l1ToL2MessagesPadded = padArrayEnd(
|
|
636
|
+
private async updateL1ToL2MessageTree(l1ToL2Messages: Fr[], db: MerkleTreeWriteOperations) {
|
|
637
|
+
const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
|
|
449
638
|
l1ToL2Messages,
|
|
450
639
|
Fr.ZERO,
|
|
451
640
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
452
641
|
'Too many L1 to L2 messages',
|
|
453
642
|
);
|
|
454
|
-
const baseParityInputs = times(NUM_BASE_PARITY_PER_ROOT_PARITY, i =>
|
|
455
|
-
BaseParityInputs.fromSlice(l1ToL2MessagesPadded, i, getVKTreeRoot()),
|
|
456
|
-
);
|
|
457
643
|
|
|
458
|
-
const
|
|
644
|
+
const lastL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
|
|
645
|
+
const lastL1ToL2MessageSubtreeRootSiblingPath = assertLength(
|
|
459
646
|
await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db),
|
|
460
|
-
|
|
647
|
+
L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
461
648
|
);
|
|
462
649
|
|
|
463
650
|
// Update the local trees to include the new l1 to l2 messages
|
|
464
651
|
await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
|
|
465
|
-
|
|
652
|
+
|
|
653
|
+
const newL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db);
|
|
654
|
+
const newL1ToL2MessageSubtreeRootSiblingPath = assertLength(
|
|
655
|
+
await getSubtreeSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, db),
|
|
656
|
+
L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
657
|
+
);
|
|
466
658
|
|
|
467
659
|
return {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
660
|
+
lastL1ToL2MessageTreeSnapshot,
|
|
661
|
+
lastL1ToL2MessageSubtreeRootSiblingPath,
|
|
662
|
+
newL1ToL2MessageTreeSnapshot,
|
|
663
|
+
newL1ToL2MessageSubtreeRootSiblingPath,
|
|
471
664
|
};
|
|
472
665
|
}
|
|
473
666
|
|
|
474
667
|
// Updates the merkle trees for a transaction. The first enqueued job for a transaction
|
|
475
|
-
@trackSpan('ProvingOrchestrator.prepareBaseRollupInputs',
|
|
668
|
+
@trackSpan('ProvingOrchestrator.prepareBaseRollupInputs', tx => ({
|
|
476
669
|
[Attributes.TX_HASH]: tx.hash.toString(),
|
|
477
670
|
}))
|
|
478
671
|
private async prepareBaseRollupInputs(
|
|
479
|
-
provingState: BlockProvingState,
|
|
480
672
|
tx: ProcessedTx,
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
const db = this.dbs.get(provingState.blockNumber)!;
|
|
488
|
-
|
|
673
|
+
lastArchive: AppendOnlyTreeSnapshot,
|
|
674
|
+
newL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot,
|
|
675
|
+
startSpongeBlob: SpongeBlob,
|
|
676
|
+
db: MerkleTreeWriteOperations,
|
|
677
|
+
): Promise<[BaseRollupHints, TreeSnapshots]> {
|
|
489
678
|
// We build the base rollup inputs using a mock proof and verification key.
|
|
490
|
-
// These will be overwritten later once we have proven the
|
|
679
|
+
// These will be overwritten later once we have proven the chonk verifier circuit and any public kernels
|
|
491
680
|
const [ms, hints] = await elapsed(
|
|
492
|
-
|
|
681
|
+
insertSideEffectsAndBuildBaseRollupHints(
|
|
682
|
+
tx,
|
|
683
|
+
lastArchive,
|
|
684
|
+
newL1ToL2MessageTreeSnapshot,
|
|
685
|
+
startSpongeBlob,
|
|
686
|
+
this.proverId.toField(),
|
|
687
|
+
db,
|
|
688
|
+
),
|
|
493
689
|
);
|
|
494
690
|
|
|
495
691
|
this.metrics.recordBaseRollupInputs(ms);
|
|
@@ -501,10 +697,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
501
697
|
);
|
|
502
698
|
const treeSnapshots: TreeSnapshots = new Map((await Promise.all(promises)).map(obj => [obj.key, obj.value]));
|
|
503
699
|
|
|
504
|
-
if (!provingState.verifyState()) {
|
|
505
|
-
logger.debug(`Discarding proving job, state no longer valid`);
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
700
|
return [hints, treeSnapshots];
|
|
509
701
|
}
|
|
510
702
|
|
|
@@ -516,6 +708,11 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
516
708
|
return;
|
|
517
709
|
}
|
|
518
710
|
|
|
711
|
+
if (!provingState.tryStartProvingBase(txIndex)) {
|
|
712
|
+
logger.debug(`Base rollup for tx ${txIndex} already started.`);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
|
|
519
716
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
520
717
|
const { processedTx } = txProvingState;
|
|
521
718
|
const { rollupType, inputs } = txProvingState.getBaseRollupTypeAndInputs();
|
|
@@ -527,70 +724,81 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
527
724
|
wrapCallbackInSpan(
|
|
528
725
|
this.tracer,
|
|
529
726
|
`ProvingOrchestrator.prover.${
|
|
530
|
-
inputs instanceof
|
|
727
|
+
inputs instanceof PrivateTxBaseRollupPrivateInputs
|
|
728
|
+
? 'getPrivateTxBaseRollupProof'
|
|
729
|
+
: 'getPublicTxBaseRollupProof'
|
|
531
730
|
}`,
|
|
532
731
|
{
|
|
533
732
|
[Attributes.TX_HASH]: processedTx.hash.toString(),
|
|
534
|
-
[Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
|
|
535
733
|
[Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
|
|
536
734
|
},
|
|
537
735
|
signal => {
|
|
538
|
-
if (inputs instanceof
|
|
539
|
-
return this.prover.
|
|
736
|
+
if (inputs instanceof PrivateTxBaseRollupPrivateInputs) {
|
|
737
|
+
return this.prover.getPrivateTxBaseRollupProof(inputs, signal, provingState.epochNumber);
|
|
540
738
|
} else {
|
|
541
|
-
return this.prover.
|
|
739
|
+
return this.prover.getPublicTxBaseRollupProof(inputs, signal, provingState.epochNumber);
|
|
542
740
|
}
|
|
543
741
|
},
|
|
544
742
|
),
|
|
545
|
-
|
|
743
|
+
result => {
|
|
546
744
|
logger.debug(`Completed proof for ${rollupType} for tx ${processedTx.hash.toString()}`);
|
|
547
|
-
validatePartialState(result.inputs.
|
|
745
|
+
validatePartialState(result.inputs.endTreeSnapshots, txProvingState.treeSnapshots);
|
|
548
746
|
const leafLocation = provingState.setBaseRollupProof(txIndex, result);
|
|
549
747
|
if (provingState.totalNumTxs === 1) {
|
|
550
|
-
|
|
748
|
+
this.checkAndEnqueueBlockRootRollup(provingState);
|
|
551
749
|
} else {
|
|
552
|
-
|
|
750
|
+
this.checkAndEnqueueNextMergeRollup(provingState, leafLocation);
|
|
553
751
|
}
|
|
554
752
|
},
|
|
555
753
|
);
|
|
556
754
|
}
|
|
557
755
|
|
|
558
|
-
// Enqueues the
|
|
559
|
-
// Once completed, will enqueue the
|
|
560
|
-
private
|
|
756
|
+
// Enqueues the public chonk verifier circuit for a given transaction index, or reuses the one already enqueued.
|
|
757
|
+
// Once completed, will enqueue the the public tx base rollup.
|
|
758
|
+
private getOrEnqueueChonkVerifier(provingState: BlockProvingState, txIndex: number) {
|
|
561
759
|
if (!provingState.verifyState()) {
|
|
562
|
-
logger.debug('Not running
|
|
760
|
+
logger.debug('Not running chonk verifier circuit, state invalid');
|
|
563
761
|
return;
|
|
564
762
|
}
|
|
565
763
|
|
|
566
764
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
567
765
|
const txHash = txProvingState.processedTx.hash.toString();
|
|
568
|
-
|
|
569
|
-
const handleResult = (
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
766
|
+
NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH;
|
|
767
|
+
const handleResult = (
|
|
768
|
+
result: PublicInputsAndRecursiveProof<
|
|
769
|
+
PublicChonkVerifierPublicInputs,
|
|
770
|
+
typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
|
|
771
|
+
>,
|
|
772
|
+
) => {
|
|
773
|
+
logger.debug(`Got chonk verifier proof for tx index: ${txIndex}`, { txHash });
|
|
774
|
+
txProvingState.setPublicChonkVerifierProof(result);
|
|
775
|
+
this.provingState?.cachedChonkVerifierProofs.delete(txHash);
|
|
776
|
+
this.checkAndEnqueueBaseRollup(provingState, txIndex);
|
|
574
777
|
};
|
|
575
778
|
|
|
576
|
-
if (this.provingState?.
|
|
577
|
-
logger.debug(`
|
|
578
|
-
void this.provingState!.
|
|
779
|
+
if (this.provingState?.cachedChonkVerifierProofs.has(txHash)) {
|
|
780
|
+
logger.debug(`Chonk verifier proof already enqueued for tx index: ${txIndex}`, { txHash });
|
|
781
|
+
void this.provingState!.cachedChonkVerifierProofs.get(txHash)!.then(handleResult);
|
|
579
782
|
return;
|
|
580
783
|
}
|
|
581
784
|
|
|
582
|
-
logger.debug(`Enqueuing
|
|
583
|
-
this.
|
|
785
|
+
logger.debug(`Enqueuing chonk verifier circuit for tx index: ${txIndex}`);
|
|
786
|
+
this.doEnqueueChonkVerifier(txHash, txProvingState.getPublicChonkVerifierPrivateInputs(), handleResult);
|
|
584
787
|
}
|
|
585
788
|
|
|
586
|
-
private
|
|
789
|
+
private doEnqueueChonkVerifier(
|
|
587
790
|
txHash: string,
|
|
588
|
-
inputs:
|
|
589
|
-
handler: (
|
|
791
|
+
inputs: PublicChonkVerifierPrivateInputs,
|
|
792
|
+
handler: (
|
|
793
|
+
result: PublicInputsAndRecursiveProof<
|
|
794
|
+
PublicChonkVerifierPublicInputs,
|
|
795
|
+
typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
|
|
796
|
+
>,
|
|
797
|
+
) => void,
|
|
590
798
|
provingState: EpochProvingState | BlockProvingState = this.provingState!,
|
|
591
799
|
) {
|
|
592
|
-
if (!provingState
|
|
593
|
-
logger.debug('Not running
|
|
800
|
+
if (!provingState.verifyState()) {
|
|
801
|
+
logger.debug('Not running chonk verifier circuit, state invalid');
|
|
594
802
|
return;
|
|
595
803
|
}
|
|
596
804
|
|
|
@@ -598,13 +806,12 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
598
806
|
provingState,
|
|
599
807
|
wrapCallbackInSpan(
|
|
600
808
|
this.tracer,
|
|
601
|
-
'ProvingOrchestrator.prover.
|
|
809
|
+
'ProvingOrchestrator.prover.getPublicChonkVerifierProof',
|
|
602
810
|
{
|
|
603
811
|
[Attributes.TX_HASH]: txHash,
|
|
604
|
-
[Attributes.
|
|
605
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'tube-circuit' satisfies CircuitName,
|
|
812
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'chonk-verifier-public' satisfies CircuitName,
|
|
606
813
|
},
|
|
607
|
-
signal => this.prover.
|
|
814
|
+
signal => this.prover.getPublicChonkVerifierProof(inputs, signal, provingState.epochNumber),
|
|
608
815
|
),
|
|
609
816
|
handler,
|
|
610
817
|
);
|
|
@@ -618,40 +825,45 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
618
825
|
return;
|
|
619
826
|
}
|
|
620
827
|
|
|
828
|
+
if (!provingState.tryStartProvingMerge(location)) {
|
|
829
|
+
logger.debug('Merge rollup already started.');
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
|
|
621
833
|
const inputs = provingState.getMergeRollupInputs(location);
|
|
622
834
|
|
|
623
835
|
this.deferredProving(
|
|
624
836
|
provingState,
|
|
625
837
|
wrapCallbackInSpan(
|
|
626
838
|
this.tracer,
|
|
627
|
-
'ProvingOrchestrator.prover.
|
|
839
|
+
'ProvingOrchestrator.prover.getTxMergeRollupProof',
|
|
628
840
|
{
|
|
629
|
-
[Attributes.
|
|
630
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'merge-rollup' satisfies CircuitName,
|
|
841
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-tx-merge' satisfies CircuitName,
|
|
631
842
|
},
|
|
632
|
-
signal => this.prover.
|
|
843
|
+
signal => this.prover.getTxMergeRollupProof(inputs, signal, provingState.epochNumber),
|
|
633
844
|
),
|
|
634
|
-
|
|
845
|
+
result => {
|
|
635
846
|
provingState.setMergeRollupProof(location, result);
|
|
636
|
-
|
|
847
|
+
this.checkAndEnqueueNextMergeRollup(provingState, location);
|
|
637
848
|
},
|
|
638
849
|
);
|
|
639
850
|
}
|
|
640
851
|
|
|
641
852
|
// Executes the block root rollup circuit
|
|
642
|
-
private
|
|
853
|
+
private enqueueBlockRootRollup(provingState: BlockProvingState) {
|
|
643
854
|
if (!provingState.verifyState()) {
|
|
644
855
|
logger.debug('Not running block root rollup, state no longer valid');
|
|
645
856
|
return;
|
|
646
857
|
}
|
|
647
858
|
|
|
648
|
-
provingState.
|
|
859
|
+
if (!provingState.tryStartProvingBlockRoot()) {
|
|
860
|
+
logger.debug('Block root rollup already started.');
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
649
863
|
|
|
650
|
-
const { rollupType, inputs } =
|
|
864
|
+
const { rollupType, inputs } = provingState.getBlockRootRollupTypeAndInputs();
|
|
651
865
|
|
|
652
|
-
logger.debug(
|
|
653
|
-
`Enqueuing ${rollupType} for block ${provingState.blockNumber} with ${provingState.newL1ToL2Messages.length} l1 to l2 msgs.`,
|
|
654
|
-
);
|
|
866
|
+
logger.debug(`Enqueuing ${rollupType} for block ${provingState.blockNumber}.`);
|
|
655
867
|
|
|
656
868
|
this.deferredProving(
|
|
657
869
|
provingState,
|
|
@@ -659,64 +871,74 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
659
871
|
this.tracer,
|
|
660
872
|
'ProvingOrchestrator.prover.getBlockRootRollupProof',
|
|
661
873
|
{
|
|
662
|
-
[Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
|
|
663
874
|
[Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
|
|
664
875
|
},
|
|
665
876
|
signal => {
|
|
666
|
-
if (inputs instanceof
|
|
667
|
-
return this.prover.
|
|
668
|
-
} else if (inputs instanceof
|
|
669
|
-
return this.prover.
|
|
877
|
+
if (inputs instanceof BlockRootFirstRollupPrivateInputs) {
|
|
878
|
+
return this.prover.getBlockRootFirstRollupProof(inputs, signal, provingState.epochNumber);
|
|
879
|
+
} else if (inputs instanceof BlockRootSingleTxFirstRollupPrivateInputs) {
|
|
880
|
+
return this.prover.getBlockRootSingleTxFirstRollupProof(inputs, signal, provingState.epochNumber);
|
|
881
|
+
} else if (inputs instanceof BlockRootEmptyTxFirstRollupPrivateInputs) {
|
|
882
|
+
return this.prover.getBlockRootEmptyTxFirstRollupProof(inputs, signal, provingState.epochNumber);
|
|
883
|
+
} else if (inputs instanceof BlockRootSingleTxRollupPrivateInputs) {
|
|
884
|
+
return this.prover.getBlockRootSingleTxRollupProof(inputs, signal, provingState.epochNumber);
|
|
670
885
|
} else {
|
|
671
886
|
return this.prover.getBlockRootRollupProof(inputs, signal, provingState.epochNumber);
|
|
672
887
|
}
|
|
673
888
|
},
|
|
674
889
|
),
|
|
675
890
|
async result => {
|
|
676
|
-
provingState.
|
|
677
|
-
const header = await provingState.buildHeaderFromProvingOutputs(logger);
|
|
678
|
-
if (!(await header.hash()).equals(await provingState.block!.header.hash())) {
|
|
679
|
-
logger.error(
|
|
680
|
-
`Block header mismatch\nCircuit:${inspect(header)}\nComputed:${inspect(provingState.block!.header)}`,
|
|
681
|
-
);
|
|
682
|
-
provingState.reject(`Block header hash mismatch`);
|
|
683
|
-
}
|
|
891
|
+
logger.debug(`Completed ${rollupType} proof for block ${provingState.blockNumber}`);
|
|
684
892
|
|
|
685
|
-
|
|
686
|
-
|
|
893
|
+
const leafLocation = provingState.setBlockRootRollupProof(result);
|
|
894
|
+
const checkpointProvingState = provingState.parentCheckpoint;
|
|
687
895
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
896
|
+
// If the proofs were slower than the block header building, then we need to try validating the block header hashes here.
|
|
897
|
+
await this.verifyBuiltBlockAgainstSyncedState(provingState);
|
|
898
|
+
|
|
899
|
+
if (checkpointProvingState.totalNumBlocks === 1) {
|
|
900
|
+
this.checkAndEnqueueCheckpointRootRollup(checkpointProvingState);
|
|
692
901
|
} else {
|
|
693
|
-
this.checkAndEnqueueNextBlockMergeRollup(
|
|
902
|
+
this.checkAndEnqueueNextBlockMergeRollup(checkpointProvingState, leafLocation);
|
|
694
903
|
}
|
|
904
|
+
|
|
905
|
+
// We are finished with the block at this point, ensure the fork is cleaned up
|
|
906
|
+
void this.cleanupDBFork(provingState.blockNumber);
|
|
695
907
|
},
|
|
696
908
|
);
|
|
697
909
|
}
|
|
698
910
|
|
|
699
911
|
// Executes the base parity circuit and stores the intermediate state for the root parity circuit
|
|
700
912
|
// Enqueues the root parity circuit if all inputs are available
|
|
701
|
-
private enqueueBaseParityCircuit(
|
|
913
|
+
private enqueueBaseParityCircuit(
|
|
914
|
+
checkpointProvingState: CheckpointProvingState,
|
|
915
|
+
provingState: BlockProvingState,
|
|
916
|
+
baseParityIndex: number,
|
|
917
|
+
) {
|
|
702
918
|
if (!provingState.verifyState()) {
|
|
703
919
|
logger.debug('Not running base parity. State no longer valid.');
|
|
704
920
|
return;
|
|
705
921
|
}
|
|
706
922
|
|
|
923
|
+
if (!provingState.tryStartProvingBaseParity(baseParityIndex)) {
|
|
924
|
+
logger.warn(`Base parity ${baseParityIndex} already started.`);
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
const inputs = checkpointProvingState.getBaseParityInputs(baseParityIndex);
|
|
929
|
+
|
|
707
930
|
this.deferredProving(
|
|
708
931
|
provingState,
|
|
709
932
|
wrapCallbackInSpan(
|
|
710
933
|
this.tracer,
|
|
711
934
|
'ProvingOrchestrator.prover.getBaseParityProof',
|
|
712
935
|
{
|
|
713
|
-
[Attributes.
|
|
714
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'base-parity' satisfies CircuitName,
|
|
936
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'parity-base' satisfies CircuitName,
|
|
715
937
|
},
|
|
716
938
|
signal => this.prover.getBaseParityProof(inputs, signal, provingState.epochNumber),
|
|
717
939
|
),
|
|
718
940
|
provingOutput => {
|
|
719
|
-
provingState.setBaseParityProof(
|
|
941
|
+
provingState.setBaseParityProof(baseParityIndex, provingOutput);
|
|
720
942
|
this.checkAndEnqueueRootParityCircuit(provingState);
|
|
721
943
|
},
|
|
722
944
|
);
|
|
@@ -738,7 +960,12 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
738
960
|
return;
|
|
739
961
|
}
|
|
740
962
|
|
|
741
|
-
|
|
963
|
+
if (!provingState.tryStartProvingRootParity()) {
|
|
964
|
+
logger.debug('Root parity already started.');
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
const inputs = provingState.getParityRootInputs();
|
|
742
969
|
|
|
743
970
|
this.deferredProving(
|
|
744
971
|
provingState,
|
|
@@ -746,36 +973,38 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
746
973
|
this.tracer,
|
|
747
974
|
'ProvingOrchestrator.prover.getRootParityProof',
|
|
748
975
|
{
|
|
749
|
-
[Attributes.
|
|
750
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-parity' satisfies CircuitName,
|
|
976
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'parity-root' satisfies CircuitName,
|
|
751
977
|
},
|
|
752
978
|
signal => this.prover.getRootParityProof(inputs, signal, provingState.epochNumber),
|
|
753
979
|
),
|
|
754
|
-
|
|
980
|
+
result => {
|
|
755
981
|
provingState.setRootParityProof(result);
|
|
756
|
-
|
|
982
|
+
this.checkAndEnqueueBlockRootRollup(provingState);
|
|
757
983
|
},
|
|
758
984
|
);
|
|
759
985
|
}
|
|
760
986
|
|
|
761
987
|
// Executes the block merge rollup circuit and stored the output as intermediate state for the parent merge/block root circuit
|
|
762
988
|
// Enqueues the next level of merge if all inputs are available
|
|
763
|
-
private enqueueBlockMergeRollup(provingState:
|
|
989
|
+
private enqueueBlockMergeRollup(provingState: CheckpointProvingState, location: TreeNodeLocation) {
|
|
764
990
|
if (!provingState.verifyState()) {
|
|
765
991
|
logger.debug('Not running block merge rollup. State no longer valid.');
|
|
766
992
|
return;
|
|
767
993
|
}
|
|
768
994
|
|
|
769
|
-
|
|
995
|
+
if (!provingState.tryStartProvingBlockMerge(location)) {
|
|
996
|
+
logger.debug('Block merge rollup already started.');
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
770
999
|
|
|
1000
|
+
const inputs = provingState.getBlockMergeRollupInputs(location);
|
|
771
1001
|
this.deferredProving(
|
|
772
1002
|
provingState,
|
|
773
1003
|
wrapCallbackInSpan(
|
|
774
1004
|
this.tracer,
|
|
775
1005
|
'ProvingOrchestrator.prover.getBlockMergeRollupProof',
|
|
776
1006
|
{
|
|
777
|
-
[Attributes.
|
|
778
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'block-merge-rollup' satisfies CircuitName,
|
|
1007
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-block-merge' satisfies CircuitName,
|
|
779
1008
|
},
|
|
780
1009
|
signal => this.prover.getBlockMergeRollupProof(inputs, signal, provingState.epochNumber),
|
|
781
1010
|
),
|
|
@@ -786,30 +1015,125 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
786
1015
|
);
|
|
787
1016
|
}
|
|
788
1017
|
|
|
789
|
-
private
|
|
1018
|
+
private enqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
|
|
1019
|
+
if (!provingState.verifyState()) {
|
|
1020
|
+
logger.debug('Not running checkpoint root rollup. State no longer valid.');
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
if (!provingState.tryStartProvingCheckpointRoot()) {
|
|
1025
|
+
logger.debug('Checkpoint root rollup already started.');
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
const rollupType = provingState.getCheckpointRootRollupType();
|
|
1030
|
+
|
|
1031
|
+
logger.debug(`Enqueuing ${rollupType} for checkpoint ${provingState.index}.`);
|
|
1032
|
+
|
|
1033
|
+
const inputs = provingState.getCheckpointRootRollupInputs();
|
|
1034
|
+
|
|
1035
|
+
this.deferredProving(
|
|
1036
|
+
provingState,
|
|
1037
|
+
wrapCallbackInSpan(
|
|
1038
|
+
this.tracer,
|
|
1039
|
+
'ProvingOrchestrator.prover.getCheckpointRootRollupProof',
|
|
1040
|
+
{
|
|
1041
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: rollupType,
|
|
1042
|
+
},
|
|
1043
|
+
signal => {
|
|
1044
|
+
if (inputs instanceof CheckpointRootSingleBlockRollupPrivateInputs) {
|
|
1045
|
+
return this.prover.getCheckpointRootSingleBlockRollupProof(inputs, signal, provingState.epochNumber);
|
|
1046
|
+
} else {
|
|
1047
|
+
return this.prover.getCheckpointRootRollupProof(inputs, signal, provingState.epochNumber);
|
|
1048
|
+
}
|
|
1049
|
+
},
|
|
1050
|
+
),
|
|
1051
|
+
result => {
|
|
1052
|
+
const computedEndBlobAccumulatorState = provingState.getEndBlobAccumulator()!.toBlobAccumulator();
|
|
1053
|
+
const circuitEndBlobAccumulatorState = result.inputs.endBlobAccumulator;
|
|
1054
|
+
if (!circuitEndBlobAccumulatorState.equals(computedEndBlobAccumulatorState)) {
|
|
1055
|
+
logger.error(
|
|
1056
|
+
`Blob accumulator state mismatch.\nCircuit: ${inspect(circuitEndBlobAccumulatorState)}\nComputed: ${inspect(
|
|
1057
|
+
computedEndBlobAccumulatorState,
|
|
1058
|
+
)}`,
|
|
1059
|
+
);
|
|
1060
|
+
provingState.reject(`Blob accumulator state mismatch.`);
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
logger.debug(`Completed ${rollupType} proof for checkpoint ${provingState.index}.`);
|
|
1065
|
+
|
|
1066
|
+
const leafLocation = provingState.setCheckpointRootRollupProof(result);
|
|
1067
|
+
const epochProvingState = provingState.parentEpoch;
|
|
1068
|
+
|
|
1069
|
+
if (epochProvingState.totalNumCheckpoints === 1) {
|
|
1070
|
+
this.enqueueEpochPadding(epochProvingState);
|
|
1071
|
+
} else {
|
|
1072
|
+
this.checkAndEnqueueNextCheckpointMergeRollup(epochProvingState, leafLocation);
|
|
1073
|
+
}
|
|
1074
|
+
},
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
private enqueueCheckpointMergeRollup(provingState: EpochProvingState, location: TreeNodeLocation) {
|
|
1079
|
+
if (!provingState.verifyState()) {
|
|
1080
|
+
logger.debug('Not running checkpoint merge rollup. State no longer valid.');
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
if (!provingState.tryStartProvingCheckpointMerge(location)) {
|
|
1085
|
+
logger.debug('Checkpoint merge rollup already started.');
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
const inputs = provingState.getCheckpointMergeRollupInputs(location);
|
|
1090
|
+
|
|
1091
|
+
this.deferredProving(
|
|
1092
|
+
provingState,
|
|
1093
|
+
wrapCallbackInSpan(
|
|
1094
|
+
this.tracer,
|
|
1095
|
+
'ProvingOrchestrator.prover.getCheckpointMergeRollupProof',
|
|
1096
|
+
{
|
|
1097
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-merge' satisfies CircuitName,
|
|
1098
|
+
},
|
|
1099
|
+
signal => this.prover.getCheckpointMergeRollupProof(inputs, signal, provingState.epochNumber),
|
|
1100
|
+
),
|
|
1101
|
+
result => {
|
|
1102
|
+
logger.debug('Completed proof for checkpoint merge rollup.');
|
|
1103
|
+
provingState.setCheckpointMergeRollupProof(location, result);
|
|
1104
|
+
this.checkAndEnqueueNextCheckpointMergeRollup(provingState, location);
|
|
1105
|
+
},
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
private enqueueEpochPadding(provingState: EpochProvingState) {
|
|
790
1110
|
if (!provingState.verifyState()) {
|
|
791
1111
|
logger.debug('Not running epoch padding. State no longer valid.');
|
|
792
1112
|
return;
|
|
793
1113
|
}
|
|
794
1114
|
|
|
795
|
-
|
|
1115
|
+
if (!provingState.tryStartProvingPaddingCheckpoint()) {
|
|
1116
|
+
logger.debug('Padding checkpoint already started.');
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
logger.debug('Padding epoch proof with a padding block root proof.');
|
|
796
1121
|
|
|
797
|
-
const inputs =
|
|
1122
|
+
const inputs = provingState.getPaddingCheckpointInputs();
|
|
798
1123
|
|
|
799
1124
|
this.deferredProving(
|
|
800
1125
|
provingState,
|
|
801
1126
|
wrapCallbackInSpan(
|
|
802
1127
|
this.tracer,
|
|
803
|
-
'ProvingOrchestrator.prover.
|
|
1128
|
+
'ProvingOrchestrator.prover.getCheckpointPaddingRollupProof',
|
|
804
1129
|
{
|
|
805
|
-
[Attributes.
|
|
806
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'empty-block-root-rollup' satisfies CircuitName,
|
|
1130
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-checkpoint-padding' satisfies CircuitName,
|
|
807
1131
|
},
|
|
808
|
-
signal => this.prover.
|
|
1132
|
+
signal => this.prover.getCheckpointPaddingRollupProof(inputs, signal, provingState.epochNumber),
|
|
809
1133
|
),
|
|
810
1134
|
result => {
|
|
811
|
-
logger.debug('Completed proof for padding
|
|
812
|
-
provingState.
|
|
1135
|
+
logger.debug('Completed proof for padding checkpoint.');
|
|
1136
|
+
provingState.setCheckpointPaddingProof(result);
|
|
813
1137
|
this.checkAndEnqueueRootRollup(provingState);
|
|
814
1138
|
},
|
|
815
1139
|
);
|
|
@@ -824,7 +1148,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
824
1148
|
|
|
825
1149
|
logger.debug(`Preparing root rollup`);
|
|
826
1150
|
|
|
827
|
-
const inputs = provingState.getRootRollupInputs(
|
|
1151
|
+
const inputs = provingState.getRootRollupInputs();
|
|
828
1152
|
|
|
829
1153
|
this.deferredProving(
|
|
830
1154
|
provingState,
|
|
@@ -832,8 +1156,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
832
1156
|
this.tracer,
|
|
833
1157
|
'ProvingOrchestrator.prover.getRootRollupProof',
|
|
834
1158
|
{
|
|
835
|
-
[Attributes.
|
|
836
|
-
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-rollup' satisfies CircuitName,
|
|
1159
|
+
[Attributes.PROTOCOL_CIRCUIT_NAME]: 'rollup-root' satisfies CircuitName,
|
|
837
1160
|
},
|
|
838
1161
|
signal => this.prover.getRootRollupProof(inputs, signal, provingState.epochNumber),
|
|
839
1162
|
),
|
|
@@ -845,46 +1168,51 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
845
1168
|
);
|
|
846
1169
|
}
|
|
847
1170
|
|
|
848
|
-
private
|
|
1171
|
+
private checkAndEnqueueNextMergeRollup(provingState: BlockProvingState, currentLocation: TreeNodeLocation) {
|
|
849
1172
|
if (!provingState.isReadyForMergeRollup(currentLocation)) {
|
|
850
1173
|
return;
|
|
851
1174
|
}
|
|
852
1175
|
|
|
853
1176
|
const parentLocation = provingState.getParentLocation(currentLocation);
|
|
854
1177
|
if (parentLocation.level === 0) {
|
|
855
|
-
|
|
1178
|
+
this.checkAndEnqueueBlockRootRollup(provingState);
|
|
856
1179
|
} else {
|
|
857
1180
|
this.enqueueMergeRollup(provingState, parentLocation);
|
|
858
1181
|
}
|
|
859
1182
|
}
|
|
860
1183
|
|
|
861
|
-
private
|
|
1184
|
+
private checkAndEnqueueBlockRootRollup(provingState: BlockProvingState) {
|
|
862
1185
|
if (!provingState.isReadyForBlockRootRollup()) {
|
|
863
|
-
logger.debug('Not ready for root rollup');
|
|
1186
|
+
logger.debug('Not ready for block root rollup');
|
|
864
1187
|
return;
|
|
865
1188
|
}
|
|
866
|
-
|
|
867
|
-
|
|
1189
|
+
|
|
1190
|
+
this.enqueueBlockRootRollup(provingState);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
private checkAndEnqueueNextBlockMergeRollup(provingState: CheckpointProvingState, currentLocation: TreeNodeLocation) {
|
|
1194
|
+
if (!provingState.isReadyForBlockMerge(currentLocation)) {
|
|
868
1195
|
return;
|
|
869
1196
|
}
|
|
870
|
-
const blockNumber = provingState.blockNumber;
|
|
871
1197
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1198
|
+
const parentLocation = provingState.getParentLocation(currentLocation);
|
|
1199
|
+
if (parentLocation.level === 0) {
|
|
1200
|
+
this.checkAndEnqueueCheckpointRootRollup(provingState);
|
|
1201
|
+
} else {
|
|
1202
|
+
this.enqueueBlockMergeRollup(provingState, parentLocation);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
private checkAndEnqueueCheckpointRootRollup(provingState: CheckpointProvingState) {
|
|
1207
|
+
if (!provingState.isReadyForCheckpointRoot()) {
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
882
1210
|
|
|
883
|
-
|
|
1211
|
+
this.enqueueCheckpointRootRollup(provingState);
|
|
884
1212
|
}
|
|
885
1213
|
|
|
886
|
-
private
|
|
887
|
-
if (!provingState.
|
|
1214
|
+
private checkAndEnqueueNextCheckpointMergeRollup(provingState: EpochProvingState, currentLocation: TreeNodeLocation) {
|
|
1215
|
+
if (!provingState.isReadyForCheckpointMerge(currentLocation)) {
|
|
888
1216
|
return;
|
|
889
1217
|
}
|
|
890
1218
|
|
|
@@ -892,7 +1220,7 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
892
1220
|
if (parentLocation.level === 0) {
|
|
893
1221
|
this.checkAndEnqueueRootRollup(provingState);
|
|
894
1222
|
} else {
|
|
895
|
-
this.
|
|
1223
|
+
this.enqueueCheckpointMergeRollup(provingState, parentLocation);
|
|
896
1224
|
}
|
|
897
1225
|
}
|
|
898
1226
|
|
|
@@ -919,8 +1247,6 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
919
1247
|
|
|
920
1248
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
921
1249
|
|
|
922
|
-
// This function tries to do AVM proving. If there is a failure, it fakes the proof unless AVM_PROVING_STRICT is defined.
|
|
923
|
-
// Nothing downstream depends on the AVM proof yet. So having this mode lets us incrementally build the AVM circuit.
|
|
924
1250
|
const doAvmProving = wrapCallbackInSpan(
|
|
925
1251
|
this.tracer,
|
|
926
1252
|
'ProvingOrchestrator.prover.getAvmProof',
|
|
@@ -929,41 +1255,24 @@ export class ProvingOrchestrator implements EpochProver {
|
|
|
929
1255
|
},
|
|
930
1256
|
async (signal: AbortSignal) => {
|
|
931
1257
|
const inputs = txProvingState.getAvmInputs();
|
|
932
|
-
|
|
933
|
-
return await this.prover.getAvmProof(inputs, signal, provingState.epochNumber);
|
|
934
|
-
} catch (err) {
|
|
935
|
-
if (process.env.AVM_PROVING_STRICT) {
|
|
936
|
-
logger.error(`Error thrown when proving AVM circuit with AVM_PROVING_STRICT on`, err);
|
|
937
|
-
throw err;
|
|
938
|
-
} else {
|
|
939
|
-
logger.warn(
|
|
940
|
-
`Error thrown when proving AVM circuit but AVM_PROVING_STRICT is off. Faking AVM proof and carrying on. ${inspect(
|
|
941
|
-
err,
|
|
942
|
-
)}.`,
|
|
943
|
-
);
|
|
944
|
-
return {
|
|
945
|
-
proof: makeEmptyRecursiveProof(AVM_PROOF_LENGTH_IN_FIELDS),
|
|
946
|
-
verificationKey: VerificationKeyData.makeFake(AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS),
|
|
947
|
-
};
|
|
948
|
-
}
|
|
949
|
-
}
|
|
1258
|
+
return await this.prover.getAvmProof(inputs, signal, provingState.epochNumber);
|
|
950
1259
|
},
|
|
951
1260
|
);
|
|
952
1261
|
|
|
953
|
-
this.deferredProving(provingState, doAvmProving,
|
|
1262
|
+
this.deferredProving(provingState, doAvmProving, proof => {
|
|
954
1263
|
logger.debug(`Proven VM for tx index: ${txIndex}`);
|
|
955
|
-
txProvingState.setAvmProof(
|
|
956
|
-
this.
|
|
1264
|
+
txProvingState.setAvmProof(proof);
|
|
1265
|
+
this.checkAndEnqueueBaseRollup(provingState, txIndex);
|
|
957
1266
|
});
|
|
958
1267
|
}
|
|
959
1268
|
|
|
960
|
-
private
|
|
1269
|
+
private checkAndEnqueueBaseRollup(provingState: BlockProvingState, txIndex: number) {
|
|
961
1270
|
const txProvingState = provingState.getTxProvingState(txIndex);
|
|
962
1271
|
if (!txProvingState.ready()) {
|
|
963
1272
|
return;
|
|
964
1273
|
}
|
|
965
1274
|
|
|
966
|
-
// We must have completed all proving (
|
|
1275
|
+
// We must have completed all proving (chonk verifier proof and (if required) vm proof are generated), we now move to the base rollup.
|
|
967
1276
|
logger.debug(`Public functions completed for tx ${txIndex} enqueueing base rollup`);
|
|
968
1277
|
|
|
969
1278
|
this.enqueueBaseRollup(provingState, txIndex);
|