@aztec/prover-client 0.67.1 → 0.68.1
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/block_builder/light.d.ts +4 -3
- package/dest/block_builder/light.d.ts.map +1 -1
- package/dest/block_builder/light.js +23 -16
- package/dest/index.d.ts +0 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/mocks/fixtures.d.ts.map +1 -1
- package/dest/mocks/fixtures.js +3 -3
- package/dest/mocks/test_context.d.ts +3 -2
- package/dest/mocks/test_context.d.ts.map +1 -1
- package/dest/mocks/test_context.js +24 -12
- package/dest/orchestrator/block-building-helpers.d.ts +8 -2
- package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
- package/dest/orchestrator/block-building-helpers.js +20 -7
- package/dest/orchestrator/block-proving-state.d.ts +8 -5
- package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/block-proving-state.js +16 -7
- package/dest/orchestrator/epoch-proving-state.d.ts +3 -2
- package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/epoch-proving-state.js +3 -3
- package/dest/orchestrator/orchestrator.d.ts +10 -7
- package/dest/orchestrator/orchestrator.d.ts.map +1 -1
- package/dest/orchestrator/orchestrator.js +94 -56
- package/dest/orchestrator/tx-proving-state.d.ts +2 -1
- package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/tx-proving-state.js +3 -2
- package/dest/prover-agent/memory-proving-queue.d.ts +4 -2
- package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
- package/dest/prover-agent/memory-proving-queue.js +240 -224
- package/dest/prover-agent/prover-agent.d.ts +11 -2
- package/dest/prover-agent/prover-agent.d.ts.map +1 -1
- package/dest/prover-agent/prover-agent.js +186 -159
- package/dest/prover-client/prover-client.d.ts +2 -3
- package/dest/prover-client/prover-client.d.ts.map +1 -1
- package/dest/prover-client/prover-client.js +4 -7
- package/dest/proving_broker/{caching_broker_facade.d.ts → broker_prover_facade.d.ts} +6 -9
- package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -0
- package/dest/proving_broker/broker_prover_facade.js +107 -0
- package/dest/proving_broker/proving_agent.d.ts +4 -3
- package/dest/proving_broker/proving_agent.d.ts.map +1 -1
- package/dest/proving_broker/proving_agent.js +73 -64
- package/dest/proving_broker/proving_broker.d.ts +4 -3
- package/dest/proving_broker/proving_broker.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker.js +403 -324
- package/dest/proving_broker/proving_job_controller.d.ts +2 -1
- package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
- package/dest/proving_broker/proving_job_controller.js +15 -14
- package/dest/proving_broker/rpc.d.ts.map +1 -1
- package/dest/proving_broker/rpc.js +1 -2
- package/dest/test/mock_prover.d.ts +6 -6
- package/dest/test/mock_prover.d.ts.map +1 -1
- package/dest/test/mock_prover.js +3 -6
- package/package.json +16 -15
- package/src/block_builder/light.ts +23 -16
- package/src/index.ts +0 -1
- package/src/mocks/fixtures.ts +2 -2
- package/src/mocks/test_context.ts +33 -16
- package/src/orchestrator/block-building-helpers.ts +34 -18
- package/src/orchestrator/block-proving-state.ts +18 -8
- package/src/orchestrator/epoch-proving-state.ts +1 -4
- package/src/orchestrator/orchestrator.ts +113 -62
- package/src/orchestrator/tx-proving-state.ts +6 -4
- package/src/prover-agent/memory-proving-queue.ts +21 -15
- package/src/prover-agent/prover-agent.ts +65 -46
- package/src/prover-client/prover-client.ts +3 -10
- package/src/proving_broker/{caching_broker_facade.ts → broker_prover_facade.ts} +46 -83
- package/src/proving_broker/proving_agent.ts +72 -76
- package/src/proving_broker/proving_broker.ts +114 -36
- package/src/proving_broker/proving_job_controller.ts +13 -12
- package/src/proving_broker/rpc.ts +0 -1
- package/src/test/mock_prover.ts +17 -14
- package/dest/proving_broker/caching_broker_facade.d.ts.map +0 -1
- package/dest/proving_broker/caching_broker_facade.js +0 -153
- package/dest/proving_broker/prover_cache/memory.d.ts +0 -9
- package/dest/proving_broker/prover_cache/memory.d.ts.map +0 -1
- package/dest/proving_broker/prover_cache/memory.js +0 -16
- package/src/proving_broker/prover_cache/memory.ts +0 -20
|
@@ -11,26 +11,29 @@ import {
|
|
|
11
11
|
import { createLogger } from '@aztec/foundation/log';
|
|
12
12
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
13
13
|
import { elapsed } from '@aztec/foundation/timer';
|
|
14
|
+
import { Attributes, type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
15
|
+
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
14
16
|
|
|
15
17
|
import { InlineProofStore } from '../proving_broker/proof_store.js';
|
|
16
18
|
|
|
17
19
|
const PRINT_THRESHOLD_NS = 6e10; // 60 seconds
|
|
18
20
|
|
|
21
|
+
type InFlightPromise = {
|
|
22
|
+
id: string;
|
|
23
|
+
type: ProvingRequestType;
|
|
24
|
+
promise: Promise<any>;
|
|
25
|
+
};
|
|
26
|
+
|
|
19
27
|
/**
|
|
20
28
|
* A helper class that encapsulates a circuit prover and connects it to a job source.
|
|
21
29
|
*/
|
|
22
|
-
export class ProverAgent implements ProverAgentApi {
|
|
23
|
-
private inFlightPromises = new Map<
|
|
24
|
-
string,
|
|
25
|
-
{
|
|
26
|
-
id: string;
|
|
27
|
-
type: ProvingRequestType;
|
|
28
|
-
promise: Promise<any>;
|
|
29
|
-
}
|
|
30
|
-
>();
|
|
30
|
+
export class ProverAgent implements ProverAgentApi, Traceable {
|
|
31
|
+
private inFlightPromises = new Map<string, InFlightPromise>();
|
|
31
32
|
private runningPromise?: RunningPromise;
|
|
32
33
|
private proofInputsDatabase = new InlineProofStore();
|
|
33
34
|
|
|
35
|
+
public readonly tracer: Tracer;
|
|
36
|
+
|
|
34
37
|
constructor(
|
|
35
38
|
/** The prover implementation to defer jobs to */
|
|
36
39
|
private circuitProver: ServerCircuitProver,
|
|
@@ -38,8 +41,13 @@ export class ProverAgent implements ProverAgentApi {
|
|
|
38
41
|
private maxConcurrency = 1,
|
|
39
42
|
/** How long to wait between jobs */
|
|
40
43
|
private pollIntervalMs = 100,
|
|
44
|
+
/** Telemetry client */
|
|
45
|
+
private telemetry: TelemetryClient = new NoopTelemetryClient(),
|
|
46
|
+
/** Logger */
|
|
41
47
|
private log = createLogger('prover-client:prover-agent'),
|
|
42
|
-
) {
|
|
48
|
+
) {
|
|
49
|
+
this.tracer = telemetry.getTracer('ProverAgent');
|
|
50
|
+
}
|
|
43
51
|
|
|
44
52
|
setMaxConcurrency(maxConcurrency: number): Promise<void> {
|
|
45
53
|
if (maxConcurrency < 1) {
|
|
@@ -74,49 +82,53 @@ export class ProverAgent implements ProverAgentApi {
|
|
|
74
82
|
|
|
75
83
|
let lastPrint = process.hrtime.bigint();
|
|
76
84
|
|
|
77
|
-
this.runningPromise = new RunningPromise(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const now = process.hrtime.bigint();
|
|
83
|
-
|
|
84
|
-
if (now - lastPrint >= PRINT_THRESHOLD_NS) {
|
|
85
|
-
// only log if we're actually doing work
|
|
86
|
-
if (this.inFlightPromises.size > 0) {
|
|
87
|
-
const jobs = Array.from(this.inFlightPromises.values())
|
|
88
|
-
.map(job => `id=${job.id},type=${ProvingRequestType[job.type]}`)
|
|
89
|
-
.join(' ');
|
|
90
|
-
this.log.info(`Agent is running with ${this.inFlightPromises.size} in-flight jobs: ${jobs}`);
|
|
85
|
+
this.runningPromise = new RunningPromise(
|
|
86
|
+
async () => {
|
|
87
|
+
for (const jobId of this.inFlightPromises.keys()) {
|
|
88
|
+
await jobSource.heartbeat(jobId);
|
|
91
89
|
}
|
|
92
|
-
lastPrint = now;
|
|
93
|
-
}
|
|
94
90
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if
|
|
99
|
-
|
|
100
|
-
|
|
91
|
+
const now = process.hrtime.bigint();
|
|
92
|
+
|
|
93
|
+
if (now - lastPrint >= PRINT_THRESHOLD_NS) {
|
|
94
|
+
// only log if we're actually doing work
|
|
95
|
+
if (this.inFlightPromises.size > 0) {
|
|
96
|
+
const jobs = Array.from(this.inFlightPromises.values())
|
|
97
|
+
.map(job => `id=${job.id},type=${ProvingRequestType[job.type]}`)
|
|
98
|
+
.join(' ');
|
|
99
|
+
this.log.info(`Agent is running with ${this.inFlightPromises.size} in-flight jobs: ${jobs}`);
|
|
101
100
|
}
|
|
101
|
+
lastPrint = now;
|
|
102
|
+
}
|
|
102
103
|
|
|
104
|
+
while (this.inFlightPromises.size < this.maxConcurrency) {
|
|
103
105
|
try {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
const job = await jobSource.getProvingJob();
|
|
107
|
+
if (!job) {
|
|
108
|
+
// job source is fully drained, sleep for a bit and try again
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const promise = this.work(jobSource, job).finally(() => this.inFlightPromises.delete(job.id));
|
|
114
|
+
this.inFlightPromises.set(job.id, {
|
|
115
|
+
id: job.id,
|
|
116
|
+
type: job.type,
|
|
117
|
+
promise,
|
|
118
|
+
});
|
|
119
|
+
} catch (err) {
|
|
120
|
+
this.log.warn(
|
|
121
|
+
`Error processing job! type=${ProvingRequestType[job.type]}: ${err}. ${(err as Error).stack}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
110
124
|
} catch (err) {
|
|
111
|
-
this.log.
|
|
112
|
-
`Error processing job! type=${ProvingRequestType[job.type]}: ${err}. ${(err as Error).stack}`,
|
|
113
|
-
);
|
|
125
|
+
this.log.error(`Error fetching job`, err);
|
|
114
126
|
}
|
|
115
|
-
} catch (err) {
|
|
116
|
-
this.log.error(`Error fetching job`, err);
|
|
117
127
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
128
|
+
},
|
|
129
|
+
this.log,
|
|
130
|
+
this.pollIntervalMs,
|
|
131
|
+
);
|
|
120
132
|
|
|
121
133
|
this.runningPromise.start();
|
|
122
134
|
this.log.info(`Agent started with concurrency=${this.maxConcurrency}`);
|
|
@@ -133,9 +145,16 @@ export class ProverAgent implements ProverAgentApi {
|
|
|
133
145
|
this.log.info('Agent stopped');
|
|
134
146
|
}
|
|
135
147
|
|
|
148
|
+
@trackSpan('ProverAgent.work', (_jobSoure, job) => ({
|
|
149
|
+
[Attributes.PROVING_JOB_ID]: job.id,
|
|
150
|
+
[Attributes.PROVING_JOB_TYPE]: ProvingRequestType[job.type],
|
|
151
|
+
}))
|
|
136
152
|
private async work(jobSource: ProvingJobSource, job: ProvingJob): Promise<void> {
|
|
137
153
|
try {
|
|
138
|
-
this.log.debug(`Picked up proving job
|
|
154
|
+
this.log.debug(`Picked up proving job ${job.id} ${ProvingRequestType[job.type]}`, {
|
|
155
|
+
jobId: job.id,
|
|
156
|
+
jobType: ProvingRequestType[job.type],
|
|
157
|
+
});
|
|
139
158
|
const type = job.type;
|
|
140
159
|
const inputs = await this.proofInputsDatabase.getProofInput(job.inputsUri);
|
|
141
160
|
const [time, result] = await elapsed(this.getProof(inputs));
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
type EpochProver,
|
|
5
5
|
type EpochProverManager,
|
|
6
6
|
type ForkMerkleTreeOperations,
|
|
7
|
-
type ProverCache,
|
|
8
7
|
type ProvingJobBroker,
|
|
9
8
|
type ProvingJobConsumer,
|
|
10
9
|
type ProvingJobProducer,
|
|
@@ -16,13 +15,10 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
16
15
|
import { NativeACVMSimulator } from '@aztec/simulator';
|
|
17
16
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
18
17
|
|
|
19
|
-
import { join } from 'path';
|
|
20
|
-
|
|
21
18
|
import { type ProverClientConfig } from '../config.js';
|
|
22
19
|
import { ProvingOrchestrator } from '../orchestrator/orchestrator.js';
|
|
23
|
-
import {
|
|
20
|
+
import { BrokerCircuitProverFacade } from '../proving_broker/broker_prover_facade.js';
|
|
24
21
|
import { InlineProofStore } from '../proving_broker/proof_store.js';
|
|
25
|
-
import { InMemoryProverCache } from '../proving_broker/prover_cache/memory.js';
|
|
26
22
|
import { ProvingAgent } from '../proving_broker/proving_agent.js';
|
|
27
23
|
|
|
28
24
|
/** Manages proving of epochs by orchestrating the proving of individual blocks relying on a pool of prover agents. */
|
|
@@ -30,8 +26,6 @@ export class ProverClient implements EpochProverManager {
|
|
|
30
26
|
private running = false;
|
|
31
27
|
private agents: ProvingAgent[] = [];
|
|
32
28
|
|
|
33
|
-
private cacheDir?: string;
|
|
34
|
-
|
|
35
29
|
private constructor(
|
|
36
30
|
private config: ProverClientConfig,
|
|
37
31
|
private worldState: ForkMerkleTreeOperations,
|
|
@@ -42,13 +36,12 @@ export class ProverClient implements EpochProverManager {
|
|
|
42
36
|
) {
|
|
43
37
|
// TODO(palla/prover-node): Cache the paddingTx here, and not in each proving orchestrator,
|
|
44
38
|
// so it can be reused across multiple ones and not recomputed every time.
|
|
45
|
-
this.cacheDir = this.config.cacheDir ? join(this.config.cacheDir, `tx_prover_${this.config.proverId}`) : undefined;
|
|
46
39
|
}
|
|
47
40
|
|
|
48
|
-
public createEpochProver(
|
|
41
|
+
public createEpochProver(): EpochProver {
|
|
49
42
|
return new ProvingOrchestrator(
|
|
50
43
|
this.worldState,
|
|
51
|
-
new
|
|
44
|
+
new BrokerCircuitProverFacade(this.orchestratorClient),
|
|
52
45
|
this.telemetry,
|
|
53
46
|
this.config.proverId,
|
|
54
47
|
);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ProofAndVerificationKey,
|
|
3
|
-
type ProverCache,
|
|
4
3
|
type ProvingJobId,
|
|
5
4
|
type ProvingJobInputsMap,
|
|
6
5
|
type ProvingJobProducer,
|
|
@@ -12,47 +11,45 @@ import {
|
|
|
12
11
|
import {
|
|
13
12
|
type AVM_PROOF_LENGTH_IN_FIELDS,
|
|
14
13
|
type AvmCircuitInputs,
|
|
15
|
-
type BaseOrMergeRollupPublicInputs,
|
|
16
14
|
type BaseParityInputs,
|
|
15
|
+
type KernelCircuitPublicInputs,
|
|
16
|
+
type NESTED_RECURSIVE_PROOF_LENGTH,
|
|
17
|
+
type ParityPublicInputs,
|
|
18
|
+
type PrivateKernelEmptyInputData,
|
|
19
|
+
type RECURSIVE_PROOF_LENGTH,
|
|
20
|
+
type RootParityInputs,
|
|
21
|
+
type TUBE_PROOF_LENGTH,
|
|
22
|
+
} from '@aztec/circuits.js';
|
|
23
|
+
import {
|
|
24
|
+
type BaseOrMergeRollupPublicInputs,
|
|
17
25
|
type BlockMergeRollupInputs,
|
|
18
26
|
type BlockRootOrBlockMergePublicInputs,
|
|
19
27
|
type BlockRootRollupInputs,
|
|
20
28
|
type EmptyBlockRootRollupInputs,
|
|
21
|
-
type KernelCircuitPublicInputs,
|
|
22
29
|
type MergeRollupInputs,
|
|
23
|
-
type NESTED_RECURSIVE_PROOF_LENGTH,
|
|
24
|
-
type ParityPublicInputs,
|
|
25
30
|
type PrivateBaseRollupInputs,
|
|
26
|
-
type PrivateKernelEmptyInputData,
|
|
27
31
|
type PublicBaseRollupInputs,
|
|
28
|
-
type RECURSIVE_PROOF_LENGTH,
|
|
29
|
-
type RootParityInputs,
|
|
30
32
|
type RootRollupInputs,
|
|
31
33
|
type RootRollupPublicInputs,
|
|
32
|
-
type TUBE_PROOF_LENGTH,
|
|
33
34
|
type TubeInputs,
|
|
34
|
-
} from '@aztec/circuits.js';
|
|
35
|
+
} from '@aztec/circuits.js/rollup';
|
|
35
36
|
import { sha256 } from '@aztec/foundation/crypto';
|
|
36
37
|
import { createLogger } from '@aztec/foundation/log';
|
|
37
38
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
39
|
+
import { truncate } from '@aztec/foundation/string';
|
|
38
40
|
|
|
39
41
|
import { InlineProofStore, type ProofStore } from './proof_store.js';
|
|
40
|
-
import { InMemoryProverCache } from './prover_cache/memory.js';
|
|
41
42
|
|
|
42
43
|
// 20 minutes, roughly the length of an Aztec epoch. If a proof isn't ready in this amount of time then we've failed to prove the whole epoch
|
|
43
44
|
const MAX_WAIT_MS = 1_200_000;
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
* A facade around a job broker that generates stable job ids and caches results
|
|
47
|
-
*/
|
|
48
|
-
export class CachingBrokerFacade implements ServerCircuitProver {
|
|
46
|
+
export class BrokerCircuitProverFacade implements ServerCircuitProver {
|
|
49
47
|
constructor(
|
|
50
48
|
private broker: ProvingJobProducer,
|
|
51
|
-
private cache: ProverCache = new InMemoryProverCache(),
|
|
52
49
|
private proofStore: ProofStore = new InlineProofStore(),
|
|
53
50
|
private waitTimeoutMs = MAX_WAIT_MS,
|
|
54
51
|
private pollIntervalMs = 1000,
|
|
55
|
-
private log = createLogger('prover-client:
|
|
52
|
+
private log = createLogger('prover-client:broker-circuit-prover-facade'),
|
|
56
53
|
) {}
|
|
57
54
|
|
|
58
55
|
private async enqueueAndWaitForJob<T extends ProvingRequestType>(
|
|
@@ -62,49 +59,23 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
62
59
|
epochNumber = 0,
|
|
63
60
|
signal?: AbortSignal,
|
|
64
61
|
): Promise<ProvingJobResultsMap[T]> {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (cachedResult.status === 'fulfilled') {
|
|
74
|
-
const output = await this.proofStore.getProofOutput(cachedResult.value);
|
|
75
|
-
if (output.type === type) {
|
|
76
|
-
return output.result as ProvingJobResultsMap[T];
|
|
77
|
-
} else {
|
|
78
|
-
this.log.warn(`Cached result type mismatch for job=${id}. Expected=${type} but got=${output.type}`);
|
|
79
|
-
}
|
|
80
|
-
} else if (cachedResult.status === 'rejected') {
|
|
81
|
-
// prefer returning a rejected promises so that we don't trigger the catch block below
|
|
82
|
-
return Promise.reject(new Error(cachedResult.reason));
|
|
83
|
-
} else if (cachedResult.status === 'in-progress' || cachedResult.status === 'in-queue') {
|
|
84
|
-
jobEnqueued = true;
|
|
85
|
-
} else {
|
|
86
|
-
jobEnqueued = false;
|
|
87
|
-
}
|
|
88
|
-
} catch (err) {
|
|
89
|
-
this.log.warn(`Failed to get cached proving job id=${id}: ${err}. Re-running job`);
|
|
90
|
-
}
|
|
62
|
+
const inputsUri = await this.proofStore.saveProofInput(id, type, inputs);
|
|
63
|
+
await this.broker.enqueueProvingJob({
|
|
64
|
+
id,
|
|
65
|
+
type,
|
|
66
|
+
inputsUri,
|
|
67
|
+
epochNumber,
|
|
68
|
+
});
|
|
91
69
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
await this.cache.setProvingJobStatus(id, { status: 'in-queue' });
|
|
102
|
-
} catch (err) {
|
|
103
|
-
this.log.error(`Failed to enqueue proving job id=${id}: ${err}`);
|
|
104
|
-
await this.cache.setProvingJobStatus(id, { status: 'not-found' });
|
|
105
|
-
throw err;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
70
|
+
this.log.verbose(
|
|
71
|
+
`Sent proving job to broker id=${id} type=${ProvingRequestType[type]} epochNumber=${epochNumber}`,
|
|
72
|
+
{
|
|
73
|
+
provingJobId: id,
|
|
74
|
+
provingJobType: ProvingRequestType[type],
|
|
75
|
+
epochNumber,
|
|
76
|
+
inputsUri: truncate(inputsUri),
|
|
77
|
+
},
|
|
78
|
+
);
|
|
108
79
|
|
|
109
80
|
// notify broker of cancelled job
|
|
110
81
|
const abortFn = async () => {
|
|
@@ -131,26 +102,18 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
131
102
|
this.pollIntervalMs / 1000,
|
|
132
103
|
);
|
|
133
104
|
|
|
134
|
-
try {
|
|
135
|
-
await this.cache.setProvingJobStatus(id, result);
|
|
136
|
-
} catch (err) {
|
|
137
|
-
this.log.warn(`Failed to cache proving job id=${id} resultStatus=${result.status}: ${err}`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
105
|
if (result.status === 'fulfilled') {
|
|
141
106
|
const output = await this.proofStore.getProofOutput(result.value);
|
|
142
107
|
if (output.type === type) {
|
|
143
108
|
return output.result as ProvingJobResultsMap[T];
|
|
144
109
|
} else {
|
|
145
|
-
|
|
110
|
+
throw new Error(`Unexpected proof type: ${output.type}. Expected: ${type}`);
|
|
146
111
|
}
|
|
147
112
|
} else {
|
|
148
|
-
|
|
113
|
+
throw new Error(result.reason);
|
|
149
114
|
}
|
|
150
115
|
} finally {
|
|
151
116
|
signal?.removeEventListener('abort', abortFn);
|
|
152
|
-
// we've saved the result in our cache. We can tell the broker to clear its state
|
|
153
|
-
await this.broker.cleanUpProvingJobState(id);
|
|
154
117
|
}
|
|
155
118
|
}
|
|
156
119
|
|
|
@@ -160,7 +123,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
160
123
|
epochNumber?: number,
|
|
161
124
|
): Promise<ProofAndVerificationKey<typeof AVM_PROOF_LENGTH_IN_FIELDS>> {
|
|
162
125
|
return this.enqueueAndWaitForJob(
|
|
163
|
-
this.generateId(ProvingRequestType.PUBLIC_VM, inputs),
|
|
126
|
+
this.generateId(ProvingRequestType.PUBLIC_VM, inputs, epochNumber),
|
|
164
127
|
ProvingRequestType.PUBLIC_VM,
|
|
165
128
|
inputs,
|
|
166
129
|
epochNumber,
|
|
@@ -174,7 +137,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
174
137
|
epochNumber?: number,
|
|
175
138
|
): Promise<PublicInputsAndRecursiveProof<ParityPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
176
139
|
return this.enqueueAndWaitForJob(
|
|
177
|
-
this.generateId(ProvingRequestType.BASE_PARITY, inputs),
|
|
140
|
+
this.generateId(ProvingRequestType.BASE_PARITY, inputs, epochNumber),
|
|
178
141
|
ProvingRequestType.BASE_PARITY,
|
|
179
142
|
inputs,
|
|
180
143
|
epochNumber,
|
|
@@ -188,7 +151,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
188
151
|
epochNumber?: number,
|
|
189
152
|
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
190
153
|
return this.enqueueAndWaitForJob(
|
|
191
|
-
this.generateId(ProvingRequestType.BLOCK_MERGE_ROLLUP, input),
|
|
154
|
+
this.generateId(ProvingRequestType.BLOCK_MERGE_ROLLUP, input, epochNumber),
|
|
192
155
|
ProvingRequestType.BLOCK_MERGE_ROLLUP,
|
|
193
156
|
input,
|
|
194
157
|
epochNumber,
|
|
@@ -202,7 +165,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
202
165
|
epochNumber?: number,
|
|
203
166
|
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
204
167
|
return this.enqueueAndWaitForJob(
|
|
205
|
-
this.generateId(ProvingRequestType.BLOCK_ROOT_ROLLUP, input),
|
|
168
|
+
this.generateId(ProvingRequestType.BLOCK_ROOT_ROLLUP, input, epochNumber),
|
|
206
169
|
ProvingRequestType.BLOCK_ROOT_ROLLUP,
|
|
207
170
|
input,
|
|
208
171
|
epochNumber,
|
|
@@ -216,7 +179,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
216
179
|
epochNumber?: number,
|
|
217
180
|
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>> {
|
|
218
181
|
return this.enqueueAndWaitForJob(
|
|
219
|
-
this.generateId(ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP, input),
|
|
182
|
+
this.generateId(ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP, input, epochNumber),
|
|
220
183
|
ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP,
|
|
221
184
|
input,
|
|
222
185
|
epochNumber,
|
|
@@ -230,7 +193,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
230
193
|
epochNumber?: number,
|
|
231
194
|
): Promise<PublicInputsAndRecursiveProof<KernelCircuitPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
232
195
|
return this.enqueueAndWaitForJob(
|
|
233
|
-
this.generateId(ProvingRequestType.PRIVATE_KERNEL_EMPTY, inputs),
|
|
196
|
+
this.generateId(ProvingRequestType.PRIVATE_KERNEL_EMPTY, inputs, epochNumber),
|
|
234
197
|
ProvingRequestType.PRIVATE_KERNEL_EMPTY,
|
|
235
198
|
inputs,
|
|
236
199
|
epochNumber,
|
|
@@ -244,7 +207,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
244
207
|
epochNumber?: number,
|
|
245
208
|
): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
246
209
|
return this.enqueueAndWaitForJob(
|
|
247
|
-
this.generateId(ProvingRequestType.MERGE_ROLLUP, input),
|
|
210
|
+
this.generateId(ProvingRequestType.MERGE_ROLLUP, input, epochNumber),
|
|
248
211
|
ProvingRequestType.MERGE_ROLLUP,
|
|
249
212
|
input,
|
|
250
213
|
epochNumber,
|
|
@@ -257,7 +220,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
257
220
|
epochNumber?: number,
|
|
258
221
|
): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
259
222
|
return this.enqueueAndWaitForJob(
|
|
260
|
-
this.generateId(ProvingRequestType.PRIVATE_BASE_ROLLUP, baseRollupInput),
|
|
223
|
+
this.generateId(ProvingRequestType.PRIVATE_BASE_ROLLUP, baseRollupInput, epochNumber),
|
|
261
224
|
ProvingRequestType.PRIVATE_BASE_ROLLUP,
|
|
262
225
|
baseRollupInput,
|
|
263
226
|
epochNumber,
|
|
@@ -271,7 +234,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
271
234
|
epochNumber?: number,
|
|
272
235
|
): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
273
236
|
return this.enqueueAndWaitForJob(
|
|
274
|
-
this.generateId(ProvingRequestType.PUBLIC_BASE_ROLLUP, inputs),
|
|
237
|
+
this.generateId(ProvingRequestType.PUBLIC_BASE_ROLLUP, inputs, epochNumber),
|
|
275
238
|
ProvingRequestType.PUBLIC_BASE_ROLLUP,
|
|
276
239
|
inputs,
|
|
277
240
|
epochNumber,
|
|
@@ -285,7 +248,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
285
248
|
epochNumber?: number,
|
|
286
249
|
): Promise<PublicInputsAndRecursiveProof<ParityPublicInputs, typeof NESTED_RECURSIVE_PROOF_LENGTH>> {
|
|
287
250
|
return this.enqueueAndWaitForJob(
|
|
288
|
-
this.generateId(ProvingRequestType.ROOT_PARITY, inputs),
|
|
251
|
+
this.generateId(ProvingRequestType.ROOT_PARITY, inputs, epochNumber),
|
|
289
252
|
ProvingRequestType.ROOT_PARITY,
|
|
290
253
|
inputs,
|
|
291
254
|
epochNumber,
|
|
@@ -299,7 +262,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
299
262
|
epochNumber?: number,
|
|
300
263
|
): Promise<PublicInputsAndRecursiveProof<RootRollupPublicInputs, typeof RECURSIVE_PROOF_LENGTH>> {
|
|
301
264
|
return this.enqueueAndWaitForJob(
|
|
302
|
-
this.generateId(ProvingRequestType.ROOT_ROLLUP, input),
|
|
265
|
+
this.generateId(ProvingRequestType.ROOT_ROLLUP, input, epochNumber),
|
|
303
266
|
ProvingRequestType.ROOT_ROLLUP,
|
|
304
267
|
input,
|
|
305
268
|
epochNumber,
|
|
@@ -313,7 +276,7 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
313
276
|
epochNumber?: number,
|
|
314
277
|
): Promise<ProofAndVerificationKey<typeof TUBE_PROOF_LENGTH>> {
|
|
315
278
|
return this.enqueueAndWaitForJob(
|
|
316
|
-
this.generateId(ProvingRequestType.TUBE_PROOF, tubeInput),
|
|
279
|
+
this.generateId(ProvingRequestType.TUBE_PROOF, tubeInput, epochNumber),
|
|
317
280
|
ProvingRequestType.TUBE_PROOF,
|
|
318
281
|
tubeInput,
|
|
319
282
|
epochNumber,
|
|
@@ -321,8 +284,8 @@ export class CachingBrokerFacade implements ServerCircuitProver {
|
|
|
321
284
|
);
|
|
322
285
|
}
|
|
323
286
|
|
|
324
|
-
private generateId(type: ProvingRequestType, inputs: { toBuffer(): Buffer }) {
|
|
287
|
+
private generateId(type: ProvingRequestType, inputs: { toBuffer(): Buffer }, epochNumber = 0) {
|
|
325
288
|
const inputsHash = sha256(inputs.toBuffer());
|
|
326
|
-
return `${ProvingRequestType[type]}:${inputsHash.toString('hex')}`;
|
|
289
|
+
return `${epochNumber}:${ProvingRequestType[type]}:${inputsHash.toString('hex')}`;
|
|
327
290
|
}
|
|
328
291
|
}
|
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
} from '@aztec/circuit-types';
|
|
11
11
|
import { createLogger } from '@aztec/foundation/log';
|
|
12
12
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
13
|
+
import { truncate } from '@aztec/foundation/string';
|
|
13
14
|
import { Timer } from '@aztec/foundation/timer';
|
|
14
|
-
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
15
|
+
import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
15
16
|
|
|
16
17
|
import { type ProofStore } from './proof_store.js';
|
|
17
18
|
import { ProvingAgentInstrumentation } from './proving_agent_instrumentation.js';
|
|
@@ -20,12 +21,14 @@ import { ProvingJobController, ProvingJobControllerStatus } from './proving_job_
|
|
|
20
21
|
/**
|
|
21
22
|
* A helper class that encapsulates a circuit prover and connects it to a job source.
|
|
22
23
|
*/
|
|
23
|
-
export class ProvingAgent {
|
|
24
|
+
export class ProvingAgent implements Traceable {
|
|
24
25
|
private currentJobController?: ProvingJobController;
|
|
25
26
|
private runningPromise: RunningPromise;
|
|
26
27
|
private instrumentation: ProvingAgentInstrumentation;
|
|
27
28
|
private idleTimer: Timer | undefined;
|
|
28
29
|
|
|
30
|
+
public readonly tracer: Tracer;
|
|
31
|
+
|
|
29
32
|
constructor(
|
|
30
33
|
/** The source of proving jobs */
|
|
31
34
|
private broker: ProvingJobConsumer,
|
|
@@ -41,8 +44,9 @@ export class ProvingAgent {
|
|
|
41
44
|
private pollIntervalMs = 1000,
|
|
42
45
|
private log = createLogger('prover-client:proving-agent'),
|
|
43
46
|
) {
|
|
47
|
+
this.tracer = client.getTracer('ProvingAgent');
|
|
44
48
|
this.instrumentation = new ProvingAgentInstrumentation(client);
|
|
45
|
-
this.runningPromise = new RunningPromise(this.
|
|
49
|
+
this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.pollIntervalMs);
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
public setCircuitProver(circuitProver: ServerCircuitProver): void {
|
|
@@ -63,76 +67,74 @@ export class ProvingAgent {
|
|
|
63
67
|
await this.runningPromise.stop();
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
79
|
-
} else {
|
|
80
|
-
maybeJob = await this.broker.getProvingJob({ allowList: this.proofAllowList });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (!maybeJob) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let abortedProofJobId: string | undefined;
|
|
88
|
-
let abortedProofName: string | undefined;
|
|
89
|
-
if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.PROVING) {
|
|
90
|
-
abortedProofJobId = this.currentJobController.getJobId();
|
|
91
|
-
abortedProofName = this.currentJobController.getProofTypeName();
|
|
92
|
-
this.currentJobController?.abort();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const { job, time } = maybeJob;
|
|
96
|
-
let inputs: ProvingJobInputs;
|
|
97
|
-
try {
|
|
98
|
-
inputs = await this.proofStore.getProofInput(job.inputsUri);
|
|
99
|
-
} catch (err) {
|
|
100
|
-
await this.broker.reportProvingJobError(job.id, 'Failed to load proof inputs', true);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
this.currentJobController = new ProvingJobController(
|
|
105
|
-
job.id,
|
|
106
|
-
inputs,
|
|
107
|
-
time,
|
|
108
|
-
this.circuitProver,
|
|
109
|
-
this.handleJobResult,
|
|
70
|
+
@trackSpan('ProvingAgent.safeWork')
|
|
71
|
+
private async work() {
|
|
72
|
+
// every tick we need to
|
|
73
|
+
// (1) either do a heartbeat, telling the broker that we're working
|
|
74
|
+
// (2) get a new job
|
|
75
|
+
// If during (1) the broker returns a new job that means we can cancel the current job and start the new one
|
|
76
|
+
let maybeJob: { job: ProvingJob; time: number } | undefined;
|
|
77
|
+
if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.PROVING) {
|
|
78
|
+
maybeJob = await this.broker.reportProvingJobProgress(
|
|
79
|
+
this.currentJobController.getJobId(),
|
|
80
|
+
this.currentJobController.getStartedAt(),
|
|
81
|
+
{ allowList: this.proofAllowList },
|
|
110
82
|
);
|
|
83
|
+
} else {
|
|
84
|
+
maybeJob = await this.broker.getProvingJob({ allowList: this.proofAllowList });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!maybeJob) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let abortedProofJobId: string | undefined;
|
|
92
|
+
let abortedProofName: string | undefined;
|
|
93
|
+
if (this.currentJobController?.getStatus() === ProvingJobControllerStatus.PROVING) {
|
|
94
|
+
abortedProofJobId = this.currentJobController.getJobId();
|
|
95
|
+
abortedProofName = this.currentJobController.getProofTypeName();
|
|
96
|
+
this.currentJobController?.abort();
|
|
97
|
+
}
|
|
111
98
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)}`,
|
|
117
|
-
);
|
|
118
|
-
} else {
|
|
119
|
-
this.log.info(
|
|
120
|
-
`Starting job id=${this.currentJobController.getJobId()} type=${this.currentJobController.getProofTypeName()} inputsUri=${truncateString(
|
|
121
|
-
job.inputsUri,
|
|
122
|
-
)}`,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (this.idleTimer) {
|
|
127
|
-
this.instrumentation.recordIdleTime(this.idleTimer);
|
|
128
|
-
}
|
|
129
|
-
this.idleTimer = undefined;
|
|
130
|
-
|
|
131
|
-
this.currentJobController.start();
|
|
99
|
+
const { job, time } = maybeJob;
|
|
100
|
+
let inputs: ProvingJobInputs;
|
|
101
|
+
try {
|
|
102
|
+
inputs = await this.proofStore.getProofInput(job.inputsUri);
|
|
132
103
|
} catch (err) {
|
|
133
|
-
this.
|
|
104
|
+
await this.broker.reportProvingJobError(job.id, 'Failed to load proof inputs', true);
|
|
105
|
+
return;
|
|
134
106
|
}
|
|
135
|
-
|
|
107
|
+
|
|
108
|
+
this.currentJobController = new ProvingJobController(
|
|
109
|
+
job.id,
|
|
110
|
+
inputs,
|
|
111
|
+
job.epochNumber,
|
|
112
|
+
time,
|
|
113
|
+
this.circuitProver,
|
|
114
|
+
this.handleJobResult,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
if (abortedProofJobId) {
|
|
118
|
+
this.log.info(
|
|
119
|
+
`Aborting job id=${abortedProofJobId} type=${abortedProofName} to start new job id=${this.currentJobController.getJobId()} type=${this.currentJobController.getProofTypeName()} inputsUri=${truncate(
|
|
120
|
+
job.inputsUri,
|
|
121
|
+
)}`,
|
|
122
|
+
);
|
|
123
|
+
} else {
|
|
124
|
+
this.log.info(
|
|
125
|
+
`Starting job id=${this.currentJobController.getJobId()} type=${this.currentJobController.getProofTypeName()} inputsUri=${truncate(
|
|
126
|
+
job.inputsUri,
|
|
127
|
+
)}`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (this.idleTimer) {
|
|
132
|
+
this.instrumentation.recordIdleTime(this.idleTimer);
|
|
133
|
+
}
|
|
134
|
+
this.idleTimer = undefined;
|
|
135
|
+
|
|
136
|
+
this.currentJobController.start();
|
|
137
|
+
}
|
|
136
138
|
|
|
137
139
|
handleJobResult = async <T extends ProvingRequestType>(
|
|
138
140
|
jobId: ProvingJobId,
|
|
@@ -147,14 +149,8 @@ export class ProvingAgent {
|
|
|
147
149
|
return this.broker.reportProvingJobError(jobId, err.message, retry);
|
|
148
150
|
} else if (result) {
|
|
149
151
|
const outputUri = await this.proofStore.saveProofOutput(jobId, type, result);
|
|
150
|
-
this.log.info(
|
|
151
|
-
`Job id=${jobId} type=${ProvingRequestType[type]} completed outputUri=${truncateString(outputUri)}`,
|
|
152
|
-
);
|
|
152
|
+
this.log.info(`Job id=${jobId} type=${ProvingRequestType[type]} completed outputUri=${truncate(outputUri)}`);
|
|
153
153
|
return this.broker.reportProvingJobSuccess(jobId, outputUri);
|
|
154
154
|
}
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
|
-
|
|
158
|
-
function truncateString(str: string, length: number = 64): string {
|
|
159
|
-
return str.length > length ? str.slice(0, length) + '...' : str;
|
|
160
|
-
}
|