@aztec/prover-node 5.0.0-private.20260319 → 5.0.0-rc.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/README.md +506 -0
- package/dest/actions/download-epoch-proving-job.js +1 -1
- package/dest/actions/rerun-epoch-proving-job.d.ts +4 -3
- package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
- package/dest/actions/rerun-epoch-proving-job.js +103 -21
- package/dest/bin/run-failed-epoch.js +1 -3
- package/dest/checkpoint-store.d.ts +83 -0
- package/dest/checkpoint-store.d.ts.map +1 -0
- package/dest/checkpoint-store.js +181 -0
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +1 -1
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +22 -8
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/job/checkpoint-prover.d.ts +134 -0
- package/dest/job/checkpoint-prover.d.ts.map +1 -0
- package/dest/job/checkpoint-prover.js +350 -0
- package/dest/job/epoch-session.d.ts +146 -0
- package/dest/job/epoch-session.d.ts.map +1 -0
- package/dest/job/epoch-session.js +709 -0
- package/dest/job/top-tree-job.d.ts +82 -0
- package/dest/job/top-tree-job.d.ts.map +1 -0
- package/dest/job/top-tree-job.js +152 -0
- package/dest/metrics.d.ts +29 -5
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +73 -9
- package/dest/monitors/epoch-monitor.js +6 -2
- package/dest/proof-publishing-service.d.ts +159 -0
- package/dest/proof-publishing-service.d.ts.map +1 -0
- package/dest/proof-publishing-service.js +334 -0
- package/dest/prover-node-publisher.d.ts +18 -11
- package/dest/prover-node-publisher.d.ts.map +1 -1
- package/dest/prover-node-publisher.js +195 -57
- package/dest/prover-node.d.ts +96 -68
- package/dest/prover-node.d.ts.map +1 -1
- package/dest/prover-node.js +382 -227
- package/dest/prover-publisher-factory.d.ts +2 -2
- package/dest/prover-publisher-factory.d.ts.map +1 -1
- package/dest/prover-publisher-factory.js +3 -3
- package/dest/session-manager.d.ts +158 -0
- package/dest/session-manager.d.ts.map +1 -0
- package/dest/session-manager.js +452 -0
- package/dest/test/index.d.ts +7 -6
- package/dest/test/index.d.ts.map +1 -1
- package/package.json +23 -23
- package/src/actions/download-epoch-proving-job.ts +1 -1
- package/src/actions/rerun-epoch-proving-job.ts +114 -28
- package/src/bin/run-failed-epoch.ts +1 -2
- package/src/checkpoint-store.ts +213 -0
- package/src/config.ts +2 -1
- package/src/factory.ts +18 -10
- package/src/index.ts +1 -0
- package/src/job/checkpoint-prover.ts +465 -0
- package/src/job/epoch-session.ts +424 -0
- package/src/job/top-tree-job.ts +227 -0
- package/src/metrics.ts +88 -12
- package/src/monitors/epoch-monitor.ts +2 -2
- package/src/proof-publishing-service.ts +424 -0
- package/src/prover-node-publisher.ts +220 -67
- package/src/prover-node.ts +439 -249
- package/src/prover-publisher-factory.ts +3 -3
- package/src/session-manager.ts +552 -0
- package/src/test/index.ts +6 -6
- package/dest/job/epoch-proving-job.d.ts +0 -63
- package/dest/job/epoch-proving-job.d.ts.map +0 -1
- package/dest/job/epoch-proving-job.js +0 -762
- package/src/job/epoch-proving-job.ts +0 -465
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { BatchedBlob } from '@aztec/blob-lib';
|
|
2
|
+
import type { ViemCommitteeAttestation } from '@aztec/ethereum/contracts';
|
|
3
|
+
import { BlockNumber, type CheckpointNumber, type EpochNumber } from '@aztec/foundation/branded-types';
|
|
4
|
+
import { type LoggerBindings } from '@aztec/foundation/log';
|
|
5
|
+
import { SerialQueue } from '@aztec/foundation/queue';
|
|
6
|
+
import type { DateProvider } from '@aztec/foundation/timer';
|
|
7
|
+
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
8
|
+
import type { Proof } from '@aztec/stdlib/proofs';
|
|
9
|
+
import type { RootRollupPublicInputs } from '@aztec/stdlib/rollup';
|
|
10
|
+
import type { ProverNodePublisher } from './prover-node-publisher.js';
|
|
11
|
+
import type { ProverPublisherFactory } from './prover-publisher-factory.js';
|
|
12
|
+
/** A single proof candidate offered to the publishing service by an `EpochSession`. */
|
|
13
|
+
export type PublishCandidate = {
|
|
14
|
+
/** Stable id; matches the originating session so `withdraw` can target this entry. */
|
|
15
|
+
id: string;
|
|
16
|
+
epoch: EpochNumber;
|
|
17
|
+
/**
|
|
18
|
+
* Full vs partial. A `partial` candidate is an early-finish optimisation: if the chain's
|
|
19
|
+
* proven tip catches up to or past its `endBlock` before it publishes, it's superseded —
|
|
20
|
+
* publishing would be wasted L1 gas. A `full` candidate covers the entire epoch and is
|
|
21
|
+
* useful to publish even after some other prover-node has already submitted (the rollup
|
|
22
|
+
* contract records the submission per prover-id), so it is never auto-superseded by the
|
|
23
|
+
* proven tip alone.
|
|
24
|
+
*/
|
|
25
|
+
kind: 'full' | 'partial';
|
|
26
|
+
/** First L2 block in the candidate's range. */
|
|
27
|
+
startBlock: BlockNumber;
|
|
28
|
+
/** Last L2 block in the candidate's range. */
|
|
29
|
+
endBlock: BlockNumber;
|
|
30
|
+
/**
|
|
31
|
+
* Wall-clock time after which the candidate is no longer worth publishing — typically
|
|
32
|
+
* the L1 proof-submission window deadline. If the candidate is still queued at this
|
|
33
|
+
* time it resolves as `'expired'`. If it's already in flight, the publish runs to
|
|
34
|
+
* completion (the L1 tx may still mine; the deadline only governs whether the service
|
|
35
|
+
* will start a publish). `undefined` disables the per-candidate timer.
|
|
36
|
+
*/
|
|
37
|
+
deadline: Date | undefined;
|
|
38
|
+
/** Everything `ProverNodePublisher.submitEpochProof` needs. */
|
|
39
|
+
fromCheckpoint: CheckpointNumber;
|
|
40
|
+
toCheckpoint: CheckpointNumber;
|
|
41
|
+
publicInputs: RootRollupPublicInputs;
|
|
42
|
+
proof: Proof;
|
|
43
|
+
batchedBlobInputs: BatchedBlob;
|
|
44
|
+
attestations: ViemCommitteeAttestation[];
|
|
45
|
+
};
|
|
46
|
+
/** Terminal outcome for a candidate. The promise from `submit()` resolves with one of these. */
|
|
47
|
+
export type PublishOutcome = 'published' | 'superseded' | 'failed' | 'withdrawn' | 'expired';
|
|
48
|
+
/** Subset of `ProverPublisherFactory` the service uses — single async `create()` call. */
|
|
49
|
+
export type PublisherFactoryLike = Pick<ProverPublisherFactory, 'create'>;
|
|
50
|
+
/** Subset of `ProverNodePublisher` the service drives — one publish per fresh publisher. */
|
|
51
|
+
export type PublisherLike = Pick<ProverNodePublisher, 'submitEpochProof' | 'analyzeEpochProofSubmission'>;
|
|
52
|
+
/** Config for the publishing service. */
|
|
53
|
+
export type ProofPublishingServiceConfig = {
|
|
54
|
+
/** When true, submitting a candidate runs `analyzeEpochProofSubmission` instead of publishing. */
|
|
55
|
+
skipSubmitProof: boolean;
|
|
56
|
+
};
|
|
57
|
+
export type ProofPublishingServiceDeps = {
|
|
58
|
+
publisherFactory: PublisherFactoryLike;
|
|
59
|
+
l2BlockSource: Pick<L2BlockSource, 'getBlockNumber'>;
|
|
60
|
+
dateProvider: DateProvider;
|
|
61
|
+
config: ProofPublishingServiceConfig;
|
|
62
|
+
bindings?: LoggerBindings;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Central owner of L1 proof submission. Sessions offer their proofs here as
|
|
66
|
+
* `PublishCandidate`s; the service serialises one publish at a time, picks the
|
|
67
|
+
* longest candidate per epoch as the winner, and resolves the rest as
|
|
68
|
+
* `'superseded'` without spending L1 gas.
|
|
69
|
+
*
|
|
70
|
+
* Construction-time invariants:
|
|
71
|
+
* - Every publish runs against a freshly-created `ProverNodePublisher` from the factory.
|
|
72
|
+
* - Only one publish is ever in flight (`SerialQueue` drain) — no defensive locks.
|
|
73
|
+
* - Once an L1 publish starts, it runs to completion. `withdraw` is a queue-only
|
|
74
|
+
* operation: it removes a candidate that has not yet started publishing. An in-flight
|
|
75
|
+
* candidate is left alone and its outcome (`'published'` / `'failed'`) is reported as
|
|
76
|
+
* usual — the originating session has already moved to a terminal state via `cancel()`
|
|
77
|
+
* and ignores the late outcome.
|
|
78
|
+
*
|
|
79
|
+
* Eligibility for publication is decided against the proven block number read inside
|
|
80
|
+
* the drain (so the value is consistent with the publish that runs on the same drain
|
|
81
|
+
* pass): a candidate is eligible when its predecessor block is proven and (for partial
|
|
82
|
+
* candidates) the candidate's range extends past the proven tip. `onChainProven` is a
|
|
83
|
+
* wake-up signal; it does not pass state into the drain.
|
|
84
|
+
*/
|
|
85
|
+
export declare class ProofPublishingService {
|
|
86
|
+
private readonly deps;
|
|
87
|
+
private readonly log;
|
|
88
|
+
private readonly epochs;
|
|
89
|
+
/**
|
|
90
|
+
* One drain task at a time. Submits, withdrawals, chain-proven advances, and prunes
|
|
91
|
+
* all schedule a `drain` here, so the eligibility re-check and the L1 publish never
|
|
92
|
+
* interleave.
|
|
93
|
+
*
|
|
94
|
+
* Protected so unit tests can `await drainQueue.syncPoint()` to wait for pending
|
|
95
|
+
* drain work to settle deterministically (no sleeps).
|
|
96
|
+
*/
|
|
97
|
+
protected readonly drainQueue: SerialQueue;
|
|
98
|
+
/** Tracks the candidate currently being published. Set while drain is awaiting the L1 publish. */
|
|
99
|
+
private inFlight;
|
|
100
|
+
private stopped;
|
|
101
|
+
constructor(deps: ProofPublishingServiceDeps);
|
|
102
|
+
/**
|
|
103
|
+
* Offers a proof candidate to the service. The returned promise resolves once the
|
|
104
|
+
* service settles the candidate's fate: `'published'` if it wins and L1 accepts it,
|
|
105
|
+
* `'superseded'` if a longer candidate for the same epoch wins, `'failed'` if the
|
|
106
|
+
* L1 submission errored, `'withdrawn'` if the originating session cancelled,
|
|
107
|
+
* `'expired'` if the candidate's `deadline` elapsed before publishing started.
|
|
108
|
+
*/
|
|
109
|
+
submit(candidate: PublishCandidate): Promise<PublishOutcome>;
|
|
110
|
+
/**
|
|
111
|
+
* Pulls a queued candidate from the bucket and resolves its promise as `'withdrawn'`.
|
|
112
|
+
* If the candidate is already being published, the publish runs to completion and the
|
|
113
|
+
* outcome reports whatever L1 returned — callers that cancelled mid-publish must rely
|
|
114
|
+
* on their own terminal-state check to ignore the late outcome. No-op if the candidate
|
|
115
|
+
* is unknown.
|
|
116
|
+
*/
|
|
117
|
+
withdraw(candidateId: string): void;
|
|
118
|
+
/**
|
|
119
|
+
* Signals that the L1 proven tip has advanced and the queue should be re-evaluated.
|
|
120
|
+
* The drain reads the proven block number from `l2BlockSource` itself rather than
|
|
121
|
+
* relying on the value passed here — that way the eligibility check uses a value read
|
|
122
|
+
* inside the serial drain, not one captured by a concurrent caller of `onChainProven`.
|
|
123
|
+
*/
|
|
124
|
+
onChainProven(_provenBlock: BlockNumber): void;
|
|
125
|
+
/**
|
|
126
|
+
* Stops accepting new submissions, waits for any in-flight publish to settle, and
|
|
127
|
+
* resolves remaining queued candidates as `'withdrawn'`.
|
|
128
|
+
*/
|
|
129
|
+
stop(): Promise<void>;
|
|
130
|
+
private scheduleDrain;
|
|
131
|
+
private drain;
|
|
132
|
+
/**
|
|
133
|
+
* Picks the winning candidate for a given epoch. Partial candidates whose `endBlock` is
|
|
134
|
+
* already proven on-chain resolve `'superseded'`.
|
|
135
|
+
* Full candidates are never auto-superseded by the proven tip — multiple prover-nodes
|
|
136
|
+
* legitimately submit redundant full epoch proofs (one per prover-id) and L1 records each.
|
|
137
|
+
* Among the remaining candidates with their predecessor proven, the one with the highest
|
|
138
|
+
* `endBlock` wins; the others resolve `'superseded'`.
|
|
139
|
+
*/
|
|
140
|
+
private pickEpochWinner;
|
|
141
|
+
private publishWinner;
|
|
142
|
+
private runPublish;
|
|
143
|
+
private resolveCandidate;
|
|
144
|
+
/**
|
|
145
|
+
* Arms a per-candidate expiry timer if the candidate carries a deadline. When the timer
|
|
146
|
+
* fires, the candidate resolves as `'expired'` — unless it is already in flight, in
|
|
147
|
+
* which case the publish runs to completion (the timer becomes a no-op). The timer is
|
|
148
|
+
* cleared by `resolveCandidate` whenever the candidate settles for any other reason.
|
|
149
|
+
*/
|
|
150
|
+
private scheduleExpiry;
|
|
151
|
+
/**
|
|
152
|
+
* Protected so unit tests can drive the deadline path without waiting on the real
|
|
153
|
+
* `setTimeout` to fire. Production code calls this only via the per-candidate timer
|
|
154
|
+
* armed in `scheduleExpiry`.
|
|
155
|
+
*/
|
|
156
|
+
protected handleExpiry(candidateId: string): void;
|
|
157
|
+
private readProvenBlockNumber;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvb2YtcHVibGlzaGluZy1zZXJ2aWNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJvb2YtcHVibGlzaGluZy1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sS0FBSyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDMUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxLQUFLLGdCQUFnQixFQUFFLEtBQUssV0FBVyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDdkcsT0FBTyxFQUFlLEtBQUssY0FBYyxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBRXZGLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN0RCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM1RCxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEtBQUssRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRW5FLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDdEUsT0FBTyxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUU1RSx1RkFBdUY7QUFDdkYsTUFBTSxNQUFNLGdCQUFnQixHQUFHO0lBQzdCLHNGQUFzRjtJQUN0RixFQUFFLEVBQUUsTUFBTSxDQUFDO0lBQ1gsS0FBSyxFQUFFLFdBQVcsQ0FBQztJQUNuQjs7Ozs7OztPQU9HO0lBQ0gsSUFBSSxFQUFFLE1BQU0sR0FBRyxTQUFTLENBQUM7SUFDekIsK0NBQStDO0lBQy9DLFVBQVUsRUFBRSxXQUFXLENBQUM7SUFDeEIs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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proof-publishing-service.d.ts","sourceRoot":"","sources":["../src/proof-publishing-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
4
|
+
import { SerialQueue } from '@aztec/foundation/queue';
|
|
5
|
+
/**
|
|
6
|
+
* Backoff after a transient `publisherFactory.create()` failure. The candidate stays
|
|
7
|
+
* in the queue and the drain is re-scheduled after this delay; if the failure persists
|
|
8
|
+
* the candidate's own `deadline` timer caps the total wait.
|
|
9
|
+
*/ const PUBLISHER_ACQUIRE_RETRY_DELAY_MS = 1_000;
|
|
10
|
+
/**
|
|
11
|
+
* Central owner of L1 proof submission. Sessions offer their proofs here as
|
|
12
|
+
* `PublishCandidate`s; the service serialises one publish at a time, picks the
|
|
13
|
+
* longest candidate per epoch as the winner, and resolves the rest as
|
|
14
|
+
* `'superseded'` without spending L1 gas.
|
|
15
|
+
*
|
|
16
|
+
* Construction-time invariants:
|
|
17
|
+
* - Every publish runs against a freshly-created `ProverNodePublisher` from the factory.
|
|
18
|
+
* - Only one publish is ever in flight (`SerialQueue` drain) — no defensive locks.
|
|
19
|
+
* - Once an L1 publish starts, it runs to completion. `withdraw` is a queue-only
|
|
20
|
+
* operation: it removes a candidate that has not yet started publishing. An in-flight
|
|
21
|
+
* candidate is left alone and its outcome (`'published'` / `'failed'`) is reported as
|
|
22
|
+
* usual — the originating session has already moved to a terminal state via `cancel()`
|
|
23
|
+
* and ignores the late outcome.
|
|
24
|
+
*
|
|
25
|
+
* Eligibility for publication is decided against the proven block number read inside
|
|
26
|
+
* the drain (so the value is consistent with the publish that runs on the same drain
|
|
27
|
+
* pass): a candidate is eligible when its predecessor block is proven and (for partial
|
|
28
|
+
* candidates) the candidate's range extends past the proven tip. `onChainProven` is a
|
|
29
|
+
* wake-up signal; it does not pass state into the drain.
|
|
30
|
+
*/ export class ProofPublishingService {
|
|
31
|
+
deps;
|
|
32
|
+
log;
|
|
33
|
+
epochs;
|
|
34
|
+
/**
|
|
35
|
+
* One drain task at a time. Submits, withdrawals, chain-proven advances, and prunes
|
|
36
|
+
* all schedule a `drain` here, so the eligibility re-check and the L1 publish never
|
|
37
|
+
* interleave.
|
|
38
|
+
*
|
|
39
|
+
* Protected so unit tests can `await drainQueue.syncPoint()` to wait for pending
|
|
40
|
+
* drain work to settle deterministically (no sleeps).
|
|
41
|
+
*/ drainQueue;
|
|
42
|
+
/** Tracks the candidate currently being published. Set while drain is awaiting the L1 publish. */ inFlight;
|
|
43
|
+
stopped;
|
|
44
|
+
constructor(deps){
|
|
45
|
+
this.deps = deps;
|
|
46
|
+
this.epochs = new Map();
|
|
47
|
+
this.drainQueue = new SerialQueue();
|
|
48
|
+
this.stopped = false;
|
|
49
|
+
this.log = createLogger('prover-node:proof-publishing-service', deps.bindings);
|
|
50
|
+
this.drainQueue.start();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Offers a proof candidate to the service. The returned promise resolves once the
|
|
54
|
+
* service settles the candidate's fate: `'published'` if it wins and L1 accepts it,
|
|
55
|
+
* `'superseded'` if a longer candidate for the same epoch wins, `'failed'` if the
|
|
56
|
+
* L1 submission errored, `'withdrawn'` if the originating session cancelled,
|
|
57
|
+
* `'expired'` if the candidate's `deadline` elapsed before publishing started.
|
|
58
|
+
*/ submit(candidate) {
|
|
59
|
+
if (this.stopped) {
|
|
60
|
+
return Promise.resolve('withdrawn');
|
|
61
|
+
}
|
|
62
|
+
const { promise, resolve } = promiseWithResolvers();
|
|
63
|
+
let bucket = this.epochs.get(candidate.epoch);
|
|
64
|
+
if (!bucket) {
|
|
65
|
+
bucket = {
|
|
66
|
+
candidates: new Map(),
|
|
67
|
+
resolvers: new Map(),
|
|
68
|
+
expiryTimers: new Map()
|
|
69
|
+
};
|
|
70
|
+
this.epochs.set(candidate.epoch, bucket);
|
|
71
|
+
}
|
|
72
|
+
bucket.candidates.set(candidate.id, candidate);
|
|
73
|
+
bucket.resolvers.set(candidate.id, resolve);
|
|
74
|
+
this.scheduleExpiry(bucket, candidate);
|
|
75
|
+
this.log.info(`Candidate proof ${candidate.id} submitted for publishing`, {
|
|
76
|
+
candidateId: candidate.id,
|
|
77
|
+
epoch: candidate.epoch,
|
|
78
|
+
startBlock: candidate.startBlock,
|
|
79
|
+
endBlock: candidate.endBlock,
|
|
80
|
+
deadline: candidate.deadline?.toISOString()
|
|
81
|
+
});
|
|
82
|
+
this.scheduleDrain();
|
|
83
|
+
return promise;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Pulls a queued candidate from the bucket and resolves its promise as `'withdrawn'`.
|
|
87
|
+
* If the candidate is already being published, the publish runs to completion and the
|
|
88
|
+
* outcome reports whatever L1 returned — callers that cancelled mid-publish must rely
|
|
89
|
+
* on their own terminal-state check to ignore the late outcome. No-op if the candidate
|
|
90
|
+
* is unknown.
|
|
91
|
+
*/ withdraw(candidateId) {
|
|
92
|
+
if (this.inFlight?.id === candidateId) {
|
|
93
|
+
this.log.debug(`Withdraw for in-flight candidate ${candidateId} ignored; publish will run to completion`, {
|
|
94
|
+
candidateId
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
for (const bucket of this.epochs.values()){
|
|
99
|
+
if (bucket.candidates.has(candidateId)) {
|
|
100
|
+
this.log.info(`Candidate ${candidateId} withdrawn`, {
|
|
101
|
+
candidateId
|
|
102
|
+
});
|
|
103
|
+
this.resolveCandidate(bucket, candidateId, 'withdrawn');
|
|
104
|
+
this.scheduleDrain();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Signals that the L1 proven tip has advanced and the queue should be re-evaluated.
|
|
111
|
+
* The drain reads the proven block number from `l2BlockSource` itself rather than
|
|
112
|
+
* relying on the value passed here — that way the eligibility check uses a value read
|
|
113
|
+
* inside the serial drain, not one captured by a concurrent caller of `onChainProven`.
|
|
114
|
+
*/ onChainProven(_provenBlock) {
|
|
115
|
+
this.scheduleDrain();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Stops accepting new submissions, waits for any in-flight publish to settle, and
|
|
119
|
+
* resolves remaining queued candidates as `'withdrawn'`.
|
|
120
|
+
*/ async stop() {
|
|
121
|
+
this.stopped = true;
|
|
122
|
+
await this.drainQueue.end();
|
|
123
|
+
// Anything still parked in a bucket never ran through drain — resolve it as withdrawn so
|
|
124
|
+
// callers awaiting `submit()` aren't left hanging.
|
|
125
|
+
for (const bucket of Array.from(this.epochs.values())){
|
|
126
|
+
for (const id of Array.from(bucket.candidates.keys())){
|
|
127
|
+
this.resolveCandidate(bucket, id, 'withdrawn');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
this.epochs.clear();
|
|
131
|
+
}
|
|
132
|
+
// ---------------- drain ----------------
|
|
133
|
+
scheduleDrain() {
|
|
134
|
+
if (this.stopped) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
void this.drainQueue.put(()=>this.drain()).catch((err)=>{
|
|
138
|
+
this.log.error(`Drain task threw`, err);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async drain() {
|
|
142
|
+
if (this.stopped) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Read the proven block number afresh inside the serial drain so the eligibility
|
|
146
|
+
// check is consistent with the publish that follows it on the same drain pass.
|
|
147
|
+
const proven = await this.readProvenBlockNumber();
|
|
148
|
+
// Process epochs in ascending order: the proven tip advances monotonically, so the lower
|
|
149
|
+
// epoch is the natural next eligible candidate.
|
|
150
|
+
const orderedEpochs = Array.from(this.epochs.keys()).sort((a, b)=>Number(a) - Number(b));
|
|
151
|
+
for (const epoch of orderedEpochs){
|
|
152
|
+
const bucket = this.epochs.get(epoch);
|
|
153
|
+
const eligible = this.pickEpochWinner(bucket, proven);
|
|
154
|
+
if (!eligible) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
await this.publishWinner(epoch, eligible.winner, bucket);
|
|
158
|
+
}
|
|
159
|
+
// Drop empty buckets
|
|
160
|
+
for (const [key, bucket] of Array.from(this.epochs.entries())){
|
|
161
|
+
if (bucket.candidates.size === 0) {
|
|
162
|
+
this.epochs.delete(key);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Picks the winning candidate for a given epoch. Partial candidates whose `endBlock` is
|
|
168
|
+
* already proven on-chain resolve `'superseded'`.
|
|
169
|
+
* Full candidates are never auto-superseded by the proven tip — multiple prover-nodes
|
|
170
|
+
* legitimately submit redundant full epoch proofs (one per prover-id) and L1 records each.
|
|
171
|
+
* Among the remaining candidates with their predecessor proven, the one with the highest
|
|
172
|
+
* `endBlock` wins; the others resolve `'superseded'`.
|
|
173
|
+
*/ pickEpochWinner(bucket, proven) {
|
|
174
|
+
const now = this.deps.dateProvider.now();
|
|
175
|
+
// Resolve any candidate whose deadline has already passed.
|
|
176
|
+
for (const candidate of Array.from(bucket.candidates.values())){
|
|
177
|
+
if (candidate.deadline && candidate.deadline.getTime() <= now) {
|
|
178
|
+
this.resolveCandidate(bucket, candidate.id, 'expired');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Drop partial candidates the proven chain has already caught up to.
|
|
182
|
+
for (const candidate of Array.from(bucket.candidates.values())){
|
|
183
|
+
if (candidate.kind === 'partial' && candidate.endBlock <= proven) {
|
|
184
|
+
this.resolveCandidate(bucket, candidate.id, 'superseded');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const remaining = Array.from(bucket.candidates.values()).filter((c)=>c.startBlock - 1 <= proven);
|
|
188
|
+
if (remaining.length === 0) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
const winner = remaining.reduce((best, c)=>c.endBlock > best.endBlock ? c : best);
|
|
192
|
+
// Every other same-epoch candidate is superseded by the winner.
|
|
193
|
+
for (const candidate of remaining){
|
|
194
|
+
if (candidate.id !== winner.id) {
|
|
195
|
+
this.resolveCandidate(bucket, candidate.id, 'superseded');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
winner
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
async publishWinner(epoch, winner, bucket) {
|
|
203
|
+
let publisher;
|
|
204
|
+
try {
|
|
205
|
+
publisher = await this.deps.publisherFactory.create();
|
|
206
|
+
} catch (err) {
|
|
207
|
+
// Treat this as transient: the publisher pool may be temporarily exhausted
|
|
208
|
+
// (every signer busy, funding tx in flight, etc.). Leave the candidate queued and
|
|
209
|
+
// schedule another drain after a short backoff. If the failure persists past the
|
|
210
|
+
// candidate's deadline the expiry timer will resolve it as `'expired'`.
|
|
211
|
+
this.log.warn(`Failed to acquire publisher for candidate ${winner.id}; retrying`, {
|
|
212
|
+
candidateId: winner.id,
|
|
213
|
+
epoch: winner.epoch,
|
|
214
|
+
retryDelayMs: PUBLISHER_ACQUIRE_RETRY_DELAY_MS,
|
|
215
|
+
err
|
|
216
|
+
});
|
|
217
|
+
setTimeout(()=>this.scheduleDrain(), PUBLISHER_ACQUIRE_RETRY_DELAY_MS);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
this.inFlight = {
|
|
221
|
+
id: winner.id
|
|
222
|
+
};
|
|
223
|
+
this.log.info(`Publishing candidate ${winner.id}`, {
|
|
224
|
+
candidateId: winner.id,
|
|
225
|
+
epoch: winner.epoch,
|
|
226
|
+
startBlock: winner.startBlock,
|
|
227
|
+
endBlock: winner.endBlock,
|
|
228
|
+
fromCheckpoint: winner.fromCheckpoint,
|
|
229
|
+
toCheckpoint: winner.toCheckpoint
|
|
230
|
+
});
|
|
231
|
+
const outcome = await this.runPublish(winner, publisher);
|
|
232
|
+
this.inFlight = undefined;
|
|
233
|
+
this.resolveCandidate(bucket, winner.id, outcome);
|
|
234
|
+
if (bucket.candidates.size === 0) {
|
|
235
|
+
this.epochs.delete(epoch);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async runPublish(candidate, publisher) {
|
|
239
|
+
const submitArgs = {
|
|
240
|
+
epochNumber: candidate.epoch,
|
|
241
|
+
fromCheckpoint: candidate.fromCheckpoint,
|
|
242
|
+
toCheckpoint: candidate.toCheckpoint,
|
|
243
|
+
publicInputs: candidate.publicInputs,
|
|
244
|
+
proof: candidate.proof,
|
|
245
|
+
batchedBlobInputs: candidate.batchedBlobInputs,
|
|
246
|
+
attestations: candidate.attestations,
|
|
247
|
+
// Stop the L1 tx retrying past the candidate's submission-window deadline.
|
|
248
|
+
deadline: candidate.deadline
|
|
249
|
+
};
|
|
250
|
+
if (this.deps.config.skipSubmitProof) {
|
|
251
|
+
try {
|
|
252
|
+
await publisher.analyzeEpochProofSubmission(submitArgs);
|
|
253
|
+
return 'published';
|
|
254
|
+
} catch (err) {
|
|
255
|
+
this.log.warn(`Failed to analyze estimated L1 fees for candidate ${candidate.id}`, {
|
|
256
|
+
err,
|
|
257
|
+
candidateId: candidate.id,
|
|
258
|
+
epoch: candidate.epoch
|
|
259
|
+
});
|
|
260
|
+
// Analyze-mode failures are recorded but the session shouldn't enter `failed` —
|
|
261
|
+
// the operator opted out of submission. Match the previous EpochSession behaviour.
|
|
262
|
+
return 'published';
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const success = await publisher.submitEpochProof(submitArgs);
|
|
267
|
+
return success ? 'published' : 'failed';
|
|
268
|
+
} catch (err) {
|
|
269
|
+
this.log.error(`Error publishing candidate ${candidate.id}`, err, {
|
|
270
|
+
candidateId: candidate.id,
|
|
271
|
+
epoch: candidate.epoch
|
|
272
|
+
});
|
|
273
|
+
return 'failed';
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
resolveCandidate(bucket, id, outcome) {
|
|
277
|
+
const resolve = bucket.resolvers.get(id);
|
|
278
|
+
const timer = bucket.expiryTimers.get(id);
|
|
279
|
+
if (timer) {
|
|
280
|
+
clearTimeout(timer);
|
|
281
|
+
bucket.expiryTimers.delete(id);
|
|
282
|
+
}
|
|
283
|
+
bucket.candidates.delete(id);
|
|
284
|
+
bucket.resolvers.delete(id);
|
|
285
|
+
if (resolve) {
|
|
286
|
+
this.log.info(`Candidate ${id} resolved as ${outcome}`, {
|
|
287
|
+
candidateId: id,
|
|
288
|
+
outcome
|
|
289
|
+
});
|
|
290
|
+
resolve(outcome);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Arms a per-candidate expiry timer if the candidate carries a deadline. When the timer
|
|
295
|
+
* fires, the candidate resolves as `'expired'` — unless it is already in flight, in
|
|
296
|
+
* which case the publish runs to completion (the timer becomes a no-op). The timer is
|
|
297
|
+
* cleared by `resolveCandidate` whenever the candidate settles for any other reason.
|
|
298
|
+
*/ scheduleExpiry(bucket, candidate) {
|
|
299
|
+
if (!candidate.deadline) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const delay = Math.max(candidate.deadline.getTime() - this.deps.dateProvider.now(), 0);
|
|
303
|
+
const timer = setTimeout(()=>this.handleExpiry(candidate.id), delay);
|
|
304
|
+
bucket.expiryTimers.set(candidate.id, timer);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Protected so unit tests can drive the deadline path without waiting on the real
|
|
308
|
+
* `setTimeout` to fire. Production code calls this only via the per-candidate timer
|
|
309
|
+
* armed in `scheduleExpiry`.
|
|
310
|
+
*/ handleExpiry(candidateId) {
|
|
311
|
+
if (this.inFlight?.id === candidateId) {
|
|
312
|
+
this.log.debug(`Expiry for in-flight candidate ${candidateId} ignored; publish will run to completion`, {
|
|
313
|
+
candidateId
|
|
314
|
+
});
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
for (const bucket of this.epochs.values()){
|
|
318
|
+
if (bucket.candidates.has(candidateId)) {
|
|
319
|
+
this.log.info(`Candidate ${candidateId} expired before publishing`, {
|
|
320
|
+
candidateId
|
|
321
|
+
});
|
|
322
|
+
this.resolveCandidate(bucket, candidateId, 'expired');
|
|
323
|
+
this.scheduleDrain();
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async readProvenBlockNumber() {
|
|
329
|
+
const proven = await this.deps.l2BlockSource.getBlockNumber({
|
|
330
|
+
tag: 'proven'
|
|
331
|
+
});
|
|
332
|
+
return BlockNumber(proven ?? 0);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
@@ -23,7 +23,6 @@ export type L1SubmitEpochProofArgs = {
|
|
|
23
23
|
proof: Proof;
|
|
24
24
|
};
|
|
25
25
|
export declare class ProverNodePublisher {
|
|
26
|
-
private interrupted;
|
|
27
26
|
private metrics;
|
|
28
27
|
protected log: Logger;
|
|
29
28
|
protected rollupContract: RollupContract;
|
|
@@ -34,15 +33,6 @@ export declare class ProverNodePublisher {
|
|
|
34
33
|
telemetry?: TelemetryClient;
|
|
35
34
|
}, bindings?: LoggerBindings);
|
|
36
35
|
getRollupContract(): RollupContract;
|
|
37
|
-
/**
|
|
38
|
-
* Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
|
|
39
|
-
* Be warned, the call may return false even if the tx subsequently gets successfully mined.
|
|
40
|
-
* In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
|
|
41
|
-
* A call to `restart` is required before you can continue publishing.
|
|
42
|
-
*/
|
|
43
|
-
interrupt(): void;
|
|
44
|
-
/** Restarts the publisher after calling `interrupt`. */
|
|
45
|
-
restart(): void;
|
|
46
36
|
getSenderAddress(): EthAddress;
|
|
47
37
|
submitEpochProof(args: {
|
|
48
38
|
epochNumber: EpochNumber;
|
|
@@ -52,10 +42,27 @@ export declare class ProverNodePublisher {
|
|
|
52
42
|
proof: Proof;
|
|
53
43
|
batchedBlobInputs: BatchedBlob;
|
|
54
44
|
attestations: ViemCommitteeAttestation[];
|
|
45
|
+
/** Wall-clock deadline (proof-submission window end) past which the L1 tx should stop retrying. */
|
|
46
|
+
deadline?: Date;
|
|
55
47
|
}): Promise<boolean>;
|
|
56
48
|
private validateEpochProofSubmission;
|
|
49
|
+
/**
|
|
50
|
+
* Estimates what submitting the epoch proof would have cost on L1 without actually sending it.
|
|
51
|
+
* Runs the same validation as `submitEpochProof`, encodes the calldata, estimates gas, and records metrics.
|
|
52
|
+
* Used when proof publishing is disabled (e.g. PROVER_NODE_DISABLE_PROOF_PUBLISH=true on mainnet).
|
|
53
|
+
*/
|
|
54
|
+
analyzeEpochProofSubmission(args: {
|
|
55
|
+
epochNumber: EpochNumber;
|
|
56
|
+
fromCheckpoint: CheckpointNumber;
|
|
57
|
+
toCheckpoint: CheckpointNumber;
|
|
58
|
+
publicInputs: RootRollupPublicInputs;
|
|
59
|
+
proof: Proof;
|
|
60
|
+
batchedBlobInputs: BatchedBlob;
|
|
61
|
+
attestations: ViemCommitteeAttestation[];
|
|
62
|
+
}): Promise<void>;
|
|
63
|
+
private encodeSubmitEpochProofCalldata;
|
|
57
64
|
private sendSubmitEpochProofTx;
|
|
58
65
|
private getEpochProofPublicInputsArgs;
|
|
59
66
|
private getSubmitEpochProofArgs;
|
|
60
67
|
}
|
|
61
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmVyLW5vZGUtcHVibGlzaGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJvdmVyLW5vZGUtcHVibGlzaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQThCLE1BQU0saUJBQWlCLENBQUM7QUFDMUUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDN0QsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDMUYsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFN0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWhGLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLEtBQUssTUFBTSxFQUFFLEtBQUssY0FBYyxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBQ3ZGLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBR3pELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUUvRSxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVqRixPQUFPLEVBQUUsS0FBSyxlQUFlLEVBQXNCLE1BQU0seUJBQXlCLENBQUM7QUFPbkYsc0VBQXNFO0FBQ3RFLE1BQU0sTUFBTSxzQkFBc0IsR0FBRztJQUNuQyxTQUFTLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLGVBQWUsRUFBRSxFQUFFLENBQUM7SUFDcEIsVUFBVSxFQUFFLEVBQUUsQ0FBQztJQUNmLFlBQVksRUFBRSxFQUFFLENBQUM7SUFDakIsT0FBTyxFQUFFLEVBQUUsQ0FBQztJQUNaLFFBQVEsRUFBRSxFQUFFLENBQUM7SUFDYixJQUFJLEVBQUUsS0FBSyxDQUFDLFlBQVksRUFBRSxPQUFPLHlCQUF5QixDQUFDLENBQUM7SUFDNUQsS0FBSyxFQUFFLEtBQUssQ0FBQztDQUNkLENBQUM7QUFFRixxQkFBYSxtQkFBbUI7SUFDOUIsT0FBTyxDQUFDLE9BQU8sQ0FBNkI7SUFFNUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUM7SUFFdEIsU0FBUyxDQUFDLGNBQWMsRUFBRSxjQUFjLENBQUM7SUFFekMsU0FBZ0IsU0FBUyxFQUFFLFNBQVMsQ0FBQztJQUVyQyxZQUNFLE1BQU0sRUFBRSxjQUFjLEdBQUcsZUFBZSxFQUN4QyxJQUFJLEVBQUU7UUFDSixjQUFjLEVBQUUsY0FBYyxDQUFDO1FBQy9CLFNBQVMsRUFBRSxTQUFTLENBQUM7UUFDckIsU0FBUyxDQUFDLEVBQUUsZUFBZSxDQUFDO0tBQzdCLEVBQ0QsUUFBUSxDQUFDLEVBQUUsY0FBYyxFQVMxQjtJQUVNLGlCQUFpQixtQkFFdkI7SUFFTSxnQkFBZ0IsZUFFdEI7SUFFWSxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUU7UUFDbEMsV0FBVyxFQUFFLFdBQVcsQ0FBQztRQUN6QixjQUFjLEVBQUUsZ0JBQWdCLENBQUM7UUFDakMsWUFBWSxFQUFFLGdCQUFnQixDQUFDO1FBQy9CLFlBQVksRUFBRSxzQkFBc0IsQ0FBQztRQUNyQyxLQUFLLEVBQUUsS0FBSyxDQUFDO1FBQ2IsaUJBQWlCLEVBQUUsV0FBVyxDQUFDO1FBQy9CLFlBQVksRUFBRSx3QkFBd0IsRUFBRSxDQUFDO1FBQ3pDLG1HQUFtRztRQUNuRyxRQUFRLENBQUMsRUFBRSxJQUFJLENBQUM7S0FDakIsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBNkNuQjtZQUVhLDRCQUE0QjtJQW1FMUM7Ozs7T0FJRztJQUNVLDJCQUEyQixDQUFDLElBQUksRUFBRTtRQUM3QyxXQUFXLEVBQUUsV0FBVyxDQUFDO1FBQ3pCLGNBQWMsRUFBRSxnQkFBZ0IsQ0FBQztRQUNqQyxZQUFZLEVBQUUsZ0JBQWdCLENBQUM7UUFDL0IsWUFBWSxFQUFFLHNCQUFzQixDQUFDO1FBQ3JDLEtBQUssRUFBRSxLQUFLLENBQUM7UUFDYixpQkFBaUIsRUFBRSxXQUFXLENBQUM7UUFDL0IsWUFBWSxFQUFFLHdCQUF3QixFQUFFLENBQUM7S0FDMUMsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBc0NoQjtJQUVELE9BQU8sQ0FBQyw4QkFBOEI7WUFleEIsc0JBQXNCO0lBZ0RwQyxPQUFPLENBQUMsNkJBQTZCO0lBMEJyQyxPQUFPLENBQUMsdUJBQXVCO0NBdUJoQyJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prover-node-publisher.d.ts","sourceRoot":"","sources":["../src/prover-node-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA8B,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAgB,MAAM,uBAAuB,CAAC;AACvF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAGzD,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE/E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAOnF,sEAAsE;AACtE,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,EAAE,CAAC;IACpB,UAAU,EAAE,EAAE,CAAC;IACf,YAAY,EAAE,EAAE,CAAC;IACjB,OAAO,EAAE,EAAE,CAAC;IACZ,QAAQ,EAAE,EAAE,CAAC;IACb,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,yBAAyB,CAAC,CAAC;IAC5D,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"prover-node-publisher.d.ts","sourceRoot":"","sources":["../src/prover-node-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA8B,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAgB,MAAM,uBAAuB,CAAC;AACvF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAGzD,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE/E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAOnF,sEAAsE;AACtE,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,EAAE,CAAC;IACpB,UAAU,EAAE,EAAE,CAAC;IACf,YAAY,EAAE,EAAE,CAAC;IACjB,OAAO,EAAE,EAAE,CAAC;IACZ,QAAQ,EAAE,EAAE,CAAC;IACb,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,yBAAyB,CAAC,CAAC;IAC5D,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAA6B;IAE5C,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC;IAEtB,SAAS,CAAC,cAAc,EAAE,cAAc,CAAC;IAEzC,SAAgB,SAAS,EAAE,SAAS,CAAC;IAErC,YACE,MAAM,EAAE,cAAc,GAAG,eAAe,EACxC,IAAI,EAAE;QACJ,cAAc,EAAE,cAAc,CAAC;QAC/B,SAAS,EAAE,SAAS,CAAC;QACrB,SAAS,CAAC,EAAE,eAAe,CAAC;KAC7B,EACD,QAAQ,CAAC,EAAE,cAAc,EAS1B;IAEM,iBAAiB,mBAEvB;IAEM,gBAAgB,eAEtB;IAEY,gBAAgB,CAAC,IAAI,EAAE;QAClC,WAAW,EAAE,WAAW,CAAC;QACzB,cAAc,EAAE,gBAAgB,CAAC;QACjC,YAAY,EAAE,gBAAgB,CAAC;QAC/B,YAAY,EAAE,sBAAsB,CAAC;QACrC,KAAK,EAAE,KAAK,CAAC;QACb,iBAAiB,EAAE,WAAW,CAAC;QAC/B,YAAY,EAAE,wBAAwB,EAAE,CAAC;QACzC,mGAAmG;QACnG,QAAQ,CAAC,EAAE,IAAI,CAAC;KACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CA6CnB;YAEa,4BAA4B;IAmE1C;;;;OAIG;IACU,2BAA2B,CAAC,IAAI,EAAE;QAC7C,WAAW,EAAE,WAAW,CAAC;QACzB,cAAc,EAAE,gBAAgB,CAAC;QACjC,YAAY,EAAE,gBAAgB,CAAC;QAC/B,YAAY,EAAE,sBAAsB,CAAC;QACrC,KAAK,EAAE,KAAK,CAAC;QACb,iBAAiB,EAAE,WAAW,CAAC;QAC/B,YAAY,EAAE,wBAAwB,EAAE,CAAC;KAC1C,GAAG,OAAO,CAAC,IAAI,CAAC,CAsChB;IAED,OAAO,CAAC,8BAA8B;YAexB,sBAAsB;IAgDpC,OAAO,CAAC,6BAA6B;IA0BrC,OAAO,CAAC,uBAAuB;CAuBhC"}
|