@aztec/prover-client 2.1.0-rc.9 → 3.0.0-devnet.2
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-factory/light.d.ts +5 -3
- package/dest/block-factory/light.d.ts.map +1 -1
- package/dest/block-factory/light.js +16 -9
- package/dest/mocks/fixtures.d.ts +4 -1
- package/dest/mocks/fixtures.d.ts.map +1 -1
- package/dest/mocks/fixtures.js +31 -3
- package/dest/mocks/test_context.d.ts +32 -9
- package/dest/mocks/test_context.d.ts.map +1 -1
- package/dest/mocks/test_context.js +78 -22
- package/dest/orchestrator/block-building-helpers.d.ts +33 -31
- package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
- package/dest/orchestrator/block-building-helpers.js +126 -137
- package/dest/orchestrator/block-proving-state.d.ts +60 -53
- package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/block-proving-state.js +214 -187
- package/dest/orchestrator/checkpoint-proving-state.d.ts +63 -0
- package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -0
- package/dest/orchestrator/checkpoint-proving-state.js +211 -0
- package/dest/orchestrator/epoch-proving-state.d.ts +34 -28
- package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/epoch-proving-state.js +125 -81
- package/dest/orchestrator/orchestrator.d.ts +26 -25
- package/dest/orchestrator/orchestrator.d.ts.map +1 -1
- package/dest/orchestrator/orchestrator.js +350 -218
- package/dest/orchestrator/tx-proving-state.d.ts +11 -9
- package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
- package/dest/orchestrator/tx-proving-state.js +26 -23
- package/dest/prover-client/server-epoch-prover.d.ts +8 -7
- package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
- package/dest/prover-client/server-epoch-prover.js +7 -7
- package/dest/proving_broker/broker_prover_facade.d.ts +20 -15
- package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
- package/dest/proving_broker/broker_prover_facade.js +36 -21
- package/dest/proving_broker/config.d.ts +8 -8
- package/dest/proving_broker/config.js +4 -4
- package/dest/proving_broker/factory.js +1 -1
- package/dest/proving_broker/fixtures.js +1 -1
- package/dest/proving_broker/proof_store/index.d.ts +1 -0
- 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/proving_broker.d.ts.map +1 -1
- package/dest/proving_broker/proving_broker.js +29 -18
- package/dest/proving_broker/proving_broker_database/persisted.js +5 -5
- package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
- package/dest/proving_broker/proving_job_controller.js +38 -18
- package/dest/test/mock_prover.d.ts +22 -17
- package/dest/test/mock_prover.d.ts.map +1 -1
- package/dest/test/mock_prover.js +35 -20
- package/package.json +16 -17
- package/src/block-factory/light.ts +35 -9
- package/src/mocks/fixtures.ts +39 -11
- package/src/mocks/test_context.ts +137 -31
- package/src/orchestrator/block-building-helpers.ts +213 -211
- package/src/orchestrator/block-proving-state.ts +235 -245
- package/src/orchestrator/checkpoint-proving-state.ts +299 -0
- package/src/orchestrator/epoch-proving-state.ts +169 -126
- package/src/orchestrator/orchestrator.ts +519 -286
- package/src/orchestrator/tx-proving-state.ts +45 -43
- package/src/prover-client/server-epoch-prover.ts +26 -16
- package/src/proving_broker/broker_prover_facade.ts +157 -88
- package/src/proving_broker/config.ts +6 -6
- package/src/proving_broker/factory.ts +1 -1
- package/src/proving_broker/fixtures.ts +1 -1
- package/src/proving_broker/proof_store/index.ts +1 -0
- package/src/proving_broker/proving_broker.ts +36 -18
- package/src/proving_broker/proving_broker_database/persisted.ts +5 -5
- package/src/proving_broker/proving_job_controller.ts +38 -18
- package/src/test/mock_prover.ts +142 -62
- 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/src/bin/get-proof-inputs.ts +0 -59
|
@@ -1,38 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BatchedBlob,
|
|
3
|
+
BatchedBlobAccumulator,
|
|
4
|
+
SpongeBlob,
|
|
5
|
+
computeBlobsHashFromBlobs,
|
|
6
|
+
getBlobCommitmentsFromBlobs,
|
|
7
|
+
getBlobsPerL1Block,
|
|
8
|
+
} from '@aztec/blob-lib';
|
|
2
9
|
import {
|
|
3
10
|
ARCHIVE_HEIGHT,
|
|
11
|
+
CIVC_PROOF_LENGTH,
|
|
4
12
|
MAX_CONTRACT_CLASS_LOGS_PER_TX,
|
|
5
13
|
MAX_NOTE_HASHES_PER_TX,
|
|
6
14
|
MAX_NULLIFIERS_PER_TX,
|
|
7
15
|
NOTE_HASH_SUBTREE_HEIGHT,
|
|
8
|
-
|
|
16
|
+
NOTE_HASH_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
9
17
|
NULLIFIER_SUBTREE_HEIGHT,
|
|
10
|
-
|
|
18
|
+
NULLIFIER_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
11
19
|
NULLIFIER_TREE_HEIGHT,
|
|
12
20
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
13
21
|
PUBLIC_DATA_TREE_HEIGHT,
|
|
14
22
|
} from '@aztec/constants';
|
|
15
23
|
import { makeTuple } from '@aztec/foundation/array';
|
|
16
24
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { type Tuple, assertLength, toFriendlyJSON } from '@aztec/foundation/serialize';
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
import { sha256Trunc } from '@aztec/foundation/crypto';
|
|
26
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
27
|
+
import { type Bufferable, type Tuple, assertLength, toFriendlyJSON } from '@aztec/foundation/serialize';
|
|
28
|
+
import {
|
|
29
|
+
MembershipWitness,
|
|
30
|
+
MerkleTreeCalculator,
|
|
31
|
+
computeCompressedUnbalancedMerkleTreeRoot,
|
|
32
|
+
} from '@aztec/foundation/trees';
|
|
33
|
+
import { getVkData } from '@aztec/noir-protocol-circuits-types/server/vks';
|
|
34
|
+
import { getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
23
35
|
import { computeFeePayerBalanceLeafSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
|
|
36
|
+
import { Body, L2BlockHeader, getBlockBlobFields } from '@aztec/stdlib/block';
|
|
37
|
+
import { getCheckpointBlobFields } from '@aztec/stdlib/checkpoint';
|
|
38
|
+
import type { MerkleTreeWriteOperations, PublicInputsAndRecursiveProof } from '@aztec/stdlib/interfaces/server';
|
|
27
39
|
import { ContractClassLogFields } from '@aztec/stdlib/logs';
|
|
28
|
-
import
|
|
40
|
+
import { Proof, ProofData, RecursiveProof } from '@aztec/stdlib/proofs';
|
|
29
41
|
import {
|
|
30
|
-
type BaseOrMergeRollupPublicInputs,
|
|
31
42
|
BlockConstantData,
|
|
32
|
-
|
|
43
|
+
BlockRollupPublicInputs,
|
|
33
44
|
PrivateBaseRollupHints,
|
|
34
|
-
PrivateBaseStateDiffHints,
|
|
35
45
|
PublicBaseRollupHints,
|
|
46
|
+
PublicTubePrivateInputs,
|
|
47
|
+
TreeSnapshotDiffHints,
|
|
36
48
|
} from '@aztec/stdlib/rollup';
|
|
37
49
|
import {
|
|
38
50
|
AppendOnlyTreeSnapshot,
|
|
@@ -45,12 +57,13 @@ import {
|
|
|
45
57
|
import {
|
|
46
58
|
BlockHeader,
|
|
47
59
|
ContentCommitment,
|
|
48
|
-
|
|
60
|
+
GlobalVariables,
|
|
49
61
|
PartialStateReference,
|
|
50
62
|
type ProcessedTx,
|
|
51
63
|
StateReference,
|
|
52
|
-
|
|
64
|
+
Tx,
|
|
53
65
|
} from '@aztec/stdlib/tx';
|
|
66
|
+
import { VkData } from '@aztec/stdlib/vks';
|
|
54
67
|
import { Attributes, type Span, runInSpan } from '@aztec/telemetry-client';
|
|
55
68
|
import type { MerkleTreeReadOperations } from '@aztec/world-state';
|
|
56
69
|
|
|
@@ -70,28 +83,24 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
|
|
|
70
83
|
async (
|
|
71
84
|
span: Span,
|
|
72
85
|
tx: ProcessedTx,
|
|
73
|
-
|
|
86
|
+
lastArchive: AppendOnlyTreeSnapshot,
|
|
74
87
|
newL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot,
|
|
75
|
-
db: MerkleTreeWriteOperations,
|
|
76
88
|
startSpongeBlob: SpongeBlob,
|
|
89
|
+
proverId: Fr,
|
|
90
|
+
db: MerkleTreeWriteOperations,
|
|
77
91
|
) => {
|
|
78
92
|
span.setAttribute(Attributes.TX_HASH, tx.hash.toString());
|
|
79
93
|
// Get trees info before any changes hit
|
|
80
|
-
const lastArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
|
|
81
94
|
const start = new PartialStateReference(
|
|
82
95
|
await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db),
|
|
83
96
|
await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db),
|
|
84
97
|
await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db),
|
|
85
98
|
);
|
|
86
|
-
// Get the subtree sibling paths for the circuit
|
|
87
|
-
const noteHashSubtreeSiblingPathArray = await getSubtreeSiblingPath(
|
|
88
|
-
MerkleTreeId.NOTE_HASH_TREE,
|
|
89
|
-
NOTE_HASH_SUBTREE_HEIGHT,
|
|
90
|
-
db,
|
|
91
|
-
);
|
|
92
99
|
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
// Get the note hash subtree root sibling path for insertion.
|
|
101
|
+
const noteHashSubtreeRootSiblingPath = assertLength(
|
|
102
|
+
await getSubtreeSiblingPath(MerkleTreeId.NOTE_HASH_TREE, NOTE_HASH_SUBTREE_HEIGHT, db),
|
|
103
|
+
NOTE_HASH_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
95
104
|
);
|
|
96
105
|
|
|
97
106
|
// Update the note hash trees with the new items being inserted to get the new roots
|
|
@@ -99,10 +108,6 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
|
|
|
99
108
|
const noteHashes = padArrayEnd(tx.txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX);
|
|
100
109
|
await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashes);
|
|
101
110
|
|
|
102
|
-
// Create data hint for reading fee payer initial balance in Fee Juice
|
|
103
|
-
const leafSlot = await computeFeePayerBalanceLeafSlot(tx.data.feePayer);
|
|
104
|
-
const feePayerFeeJuiceBalanceReadHint = await getPublicDataHint(db, leafSlot.toBigInt());
|
|
105
|
-
|
|
106
111
|
// The read witnesses for a given TX should be generated before the writes of the same TX are applied.
|
|
107
112
|
// All reads that refer to writes in the same tx are transient and can be simplified out.
|
|
108
113
|
const txPublicDataUpdateRequestInfo = await processPublicDataUpdateRequests(tx, db);
|
|
@@ -110,8 +115,8 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
|
|
|
110
115
|
// Update the nullifier tree, capturing the low nullifier info for each individual operation
|
|
111
116
|
const {
|
|
112
117
|
lowLeavesWitnessData: nullifierWitnessLeaves,
|
|
113
|
-
newSubtreeSiblingPath:
|
|
114
|
-
sortedNewLeaves:
|
|
118
|
+
newSubtreeSiblingPath: nullifiersSubtreeRootSiblingPath,
|
|
119
|
+
sortedNewLeaves: sortedNullifiers,
|
|
115
120
|
sortedNewLeavesIndexes,
|
|
116
121
|
} = await db.batchInsert(
|
|
117
122
|
MerkleTreeId.NULLIFIER_TREE,
|
|
@@ -123,21 +128,10 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
|
|
|
123
128
|
throw new Error(`Could not craft nullifier batch insertion proofs`);
|
|
124
129
|
}
|
|
125
130
|
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
const nullifierSubtreeSiblingPathArray = nullifiersSubtreeSiblingPath.toFields();
|
|
133
|
-
|
|
134
|
-
const nullifierSubtreeSiblingPath = makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, i =>
|
|
135
|
-
i < nullifierSubtreeSiblingPathArray.length ? nullifierSubtreeSiblingPathArray[i] : Fr.ZERO,
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
// Append new data to startSpongeBlob
|
|
139
|
-
const inputSpongeBlob = startSpongeBlob.clone();
|
|
140
|
-
await startSpongeBlob.absorb(tx.txEffect.toBlobFields());
|
|
131
|
+
const blockHash = await tx.data.constants.anchorBlockHeader.hash();
|
|
132
|
+
const anchorBlockArchiveSiblingPath = (
|
|
133
|
+
await getMembershipWitnessFor(blockHash, MerkleTreeId.ARCHIVE, ARCHIVE_HEIGHT, db)
|
|
134
|
+
).siblingPath;
|
|
141
135
|
|
|
142
136
|
const contractClassLogsFields = makeTuple(
|
|
143
137
|
MAX_CONTRACT_CLASS_LOGS_PER_TX,
|
|
@@ -145,18 +139,10 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
|
|
|
145
139
|
);
|
|
146
140
|
|
|
147
141
|
if (tx.avmProvingRequest) {
|
|
148
|
-
const blockHash = await tx.data.constants.historicalHeader.hash();
|
|
149
|
-
const archiveRootMembershipWitness = await getMembershipWitnessFor(
|
|
150
|
-
blockHash,
|
|
151
|
-
MerkleTreeId.ARCHIVE,
|
|
152
|
-
ARCHIVE_HEIGHT,
|
|
153
|
-
db,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
142
|
return PublicBaseRollupHints.from({
|
|
157
|
-
startSpongeBlob
|
|
143
|
+
startSpongeBlob,
|
|
158
144
|
lastArchive,
|
|
159
|
-
|
|
145
|
+
anchorBlockArchiveSiblingPath,
|
|
160
146
|
contractClassLogsFields,
|
|
161
147
|
});
|
|
162
148
|
} else {
|
|
@@ -168,57 +154,62 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
|
|
|
168
154
|
throw new Error(`More than one public data write in a private only tx`);
|
|
169
155
|
}
|
|
170
156
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
157
|
+
// Get hints for reading fee payer's balance in the public data tree.
|
|
158
|
+
const feePayerBalanceMembershipWitness = txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses[0];
|
|
159
|
+
const feePayerBalanceLeafPreimage = txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages[0];
|
|
160
|
+
const leafSlot = await computeFeePayerBalanceLeafSlot(tx.data.feePayer);
|
|
161
|
+
if (!feePayerBalanceMembershipWitness || !leafSlot.equals(feePayerBalanceLeafPreimage?.leaf.slot)) {
|
|
162
|
+
throw new Error(`Cannot find the public data tree leaf for the fee payer's balance`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Extract witness objects from returned data
|
|
166
|
+
const nullifierPredecessorMembershipWitnessesWithoutPadding: MembershipWitness<typeof NULLIFIER_TREE_HEIGHT>[] =
|
|
167
|
+
nullifierWitnessLeaves.map(l =>
|
|
168
|
+
MembershipWitness.fromBufferArray(
|
|
169
|
+
l.index,
|
|
170
|
+
assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT),
|
|
171
|
+
),
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const treeSnapshotDiffHints = TreeSnapshotDiffHints.from({
|
|
175
|
+
noteHashSubtreeRootSiblingPath,
|
|
176
|
+
nullifierPredecessorPreimages: padArrayEnd(
|
|
177
|
+
nullifierWitnessLeaves.map(l => l.leafPreimage as NullifierLeafPreimage),
|
|
178
|
+
NullifierLeafPreimage.empty(),
|
|
179
|
+
MAX_NULLIFIERS_PER_TX,
|
|
185
180
|
),
|
|
186
181
|
nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NULLIFIERS_PER_TX, i =>
|
|
187
182
|
i < nullifierPredecessorMembershipWitnessesWithoutPadding.length
|
|
188
183
|
? nullifierPredecessorMembershipWitnessesWithoutPadding[i]
|
|
189
184
|
: makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT),
|
|
190
185
|
),
|
|
191
|
-
sortedNullifiers:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
186
|
+
sortedNullifiers: assertLength(
|
|
187
|
+
sortedNullifiers.map(n => Fr.fromBuffer(n)),
|
|
188
|
+
MAX_NULLIFIERS_PER_TX,
|
|
189
|
+
),
|
|
190
|
+
sortedNullifierIndexes: assertLength(sortedNewLeavesIndexes, MAX_NULLIFIERS_PER_TX),
|
|
191
|
+
nullifierSubtreeRootSiblingPath: assertLength(
|
|
192
|
+
nullifiersSubtreeRootSiblingPath.toFields(),
|
|
193
|
+
NULLIFIER_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
|
|
194
|
+
),
|
|
195
|
+
feePayerBalanceMembershipWitness,
|
|
198
196
|
});
|
|
199
197
|
|
|
200
|
-
const blockHash = await tx.data.constants.historicalHeader.hash();
|
|
201
|
-
const archiveRootMembershipWitness = await getMembershipWitnessFor(
|
|
202
|
-
blockHash,
|
|
203
|
-
MerkleTreeId.ARCHIVE,
|
|
204
|
-
ARCHIVE_HEIGHT,
|
|
205
|
-
db,
|
|
206
|
-
);
|
|
207
|
-
|
|
208
198
|
const constants = BlockConstantData.from({
|
|
209
199
|
lastArchive,
|
|
210
|
-
|
|
211
|
-
vkTreeRoot:
|
|
212
|
-
|
|
213
|
-
globalVariables,
|
|
200
|
+
l1ToL2TreeSnapshot: newL1ToL2MessageTreeSnapshot,
|
|
201
|
+
vkTreeRoot: tx.data.constants.vkTreeRoot,
|
|
202
|
+
protocolContractsHash: tx.data.constants.protocolContractsHash,
|
|
203
|
+
globalVariables: tx.globalVariables,
|
|
204
|
+
proverId,
|
|
214
205
|
});
|
|
215
206
|
|
|
216
207
|
return PrivateBaseRollupHints.from({
|
|
217
208
|
start,
|
|
218
|
-
startSpongeBlob
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
209
|
+
startSpongeBlob,
|
|
210
|
+
treeSnapshotDiffHints,
|
|
211
|
+
feePayerBalanceLeafPreimage,
|
|
212
|
+
anchorBlockArchiveSiblingPath,
|
|
222
213
|
contractClassLogsFields,
|
|
223
214
|
constants,
|
|
224
215
|
});
|
|
@@ -226,50 +217,55 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
|
|
|
226
217
|
},
|
|
227
218
|
);
|
|
228
219
|
|
|
229
|
-
export
|
|
230
|
-
const
|
|
231
|
-
if (index === undefined) {
|
|
232
|
-
throw new Error(`Cannot find the previous value index for public data ${leafSlot}.`);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const siblingPath = await db.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, index);
|
|
236
|
-
const membershipWitness = new MembershipWitness(PUBLIC_DATA_TREE_HEIGHT, index, siblingPath.toTuple());
|
|
237
|
-
|
|
238
|
-
const leafPreimage = (await db.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, index)) as PublicDataTreeLeafPreimage;
|
|
239
|
-
if (!leafPreimage) {
|
|
240
|
-
throw new Error(`Cannot find the leaf preimage for public data tree at index ${index}.`);
|
|
241
|
-
}
|
|
220
|
+
export function getCivcProofFromTx(tx: Tx | ProcessedTx) {
|
|
221
|
+
const publicInputs = tx.data.publicInputs().toFields();
|
|
242
222
|
|
|
243
|
-
const
|
|
244
|
-
|
|
223
|
+
const binaryProof = new Proof(
|
|
224
|
+
Buffer.concat(
|
|
225
|
+
tx.clientIvcProof.attachPublicInputs(publicInputs).fieldsWithPublicInputs.map(field => field.toBuffer()),
|
|
226
|
+
),
|
|
227
|
+
publicInputs.length,
|
|
228
|
+
);
|
|
229
|
+
return new RecursiveProof(tx.clientIvcProof.fields, binaryProof, true, CIVC_PROOF_LENGTH);
|
|
230
|
+
}
|
|
245
231
|
|
|
246
|
-
|
|
232
|
+
export function getPublicTubePrivateInputsFromTx(tx: Tx | ProcessedTx, proverId: Fr) {
|
|
233
|
+
const proofData = new ProofData(
|
|
234
|
+
tx.data.toPrivateToPublicKernelCircuitPublicInputs(),
|
|
235
|
+
getCivcProofFromTx(tx),
|
|
236
|
+
getVkData('HidingKernelToPublic'),
|
|
237
|
+
);
|
|
238
|
+
return new PublicTubePrivateInputs(proofData, proverId);
|
|
247
239
|
}
|
|
248
240
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
|
|
241
|
+
// Build "hints" as the private inputs for the checkpoint root rollup circuit.
|
|
242
|
+
// The `blobCommitments` will be accumulated and checked in the root rollup against the `finalBlobChallenges`.
|
|
243
|
+
// The `blobsHash` will be validated on L1 against the submitted blob data.
|
|
244
|
+
export const buildBlobHints = (blobFields: Fr[]) => {
|
|
245
|
+
const blobs = getBlobsPerL1Block(blobFields);
|
|
246
|
+
const blobCommitments = getBlobCommitmentsFromBlobs(blobs);
|
|
247
|
+
const blobsHash = computeBlobsHashFromBlobs(blobs);
|
|
248
|
+
return { blobCommitments, blobs, blobsHash };
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// Build the data required to prove the txs in an epoch. Currently only used in tests. It assumes 1 block per checkpoint.
|
|
252
|
+
export const buildBlobDataFromTxs = async (txsPerCheckpoint: ProcessedTx[][]) => {
|
|
253
|
+
const blobFields = txsPerCheckpoint.map(txs => getCheckpointBlobFields([txs.map(tx => tx.txEffect)]));
|
|
254
|
+
const finalBlobChallenges = await buildFinalBlobChallenges(blobFields);
|
|
255
|
+
return { blobFieldsLengths: blobFields.map(fields => fields.length), finalBlobChallenges };
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export const buildFinalBlobChallenges = async (blobFieldsPerCheckpoint: Fr[][]) => {
|
|
259
|
+
const blobs = blobFieldsPerCheckpoint.map(blobFields => getBlobsPerL1Block(blobFields));
|
|
260
|
+
return await BatchedBlob.precomputeBatchedBlobChallenges(blobs);
|
|
261
|
+
};
|
|
265
262
|
|
|
266
263
|
export const accumulateBlobs = runInSpan(
|
|
267
264
|
'BlockBuilderHelpers',
|
|
268
265
|
'accumulateBlobs',
|
|
269
|
-
async (_span: Span,
|
|
270
|
-
const
|
|
271
|
-
const
|
|
272
|
-
const endBlobAccumulator = startBlobAccumulator.accumulateBlobs(blobs);
|
|
266
|
+
async (_span: Span, blobFields: Fr[], startBlobAccumulator: BatchedBlobAccumulator) => {
|
|
267
|
+
const blobs = getBlobsPerL1Block(blobFields);
|
|
268
|
+
const endBlobAccumulator = await startBlobAccumulator.accumulateBlobs(blobs);
|
|
273
269
|
return endBlobAccumulator;
|
|
274
270
|
},
|
|
275
271
|
);
|
|
@@ -277,36 +273,28 @@ export const accumulateBlobs = runInSpan(
|
|
|
277
273
|
export const buildHeaderFromCircuitOutputs = runInSpan(
|
|
278
274
|
'BlockBuilderHelpers',
|
|
279
275
|
'buildHeaderFromCircuitOutputs',
|
|
280
|
-
(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const outHash =
|
|
293
|
-
previousRollupData.length === 0
|
|
294
|
-
? Fr.ZERO
|
|
295
|
-
: previousRollupData.length === 1
|
|
296
|
-
? previousRollupData[0].outHash
|
|
297
|
-
: sha256ToField([previousRollupData[0].outHash, previousRollupData[1].outHash]);
|
|
298
|
-
const contentCommitment = new ContentCommitment(blobsHash, parityPublicInputs.shaRoot, outHash);
|
|
276
|
+
async (_span, blockRootRollupOutput: BlockRollupPublicInputs) => {
|
|
277
|
+
const constants = blockRootRollupOutput.constants;
|
|
278
|
+
const globalVariables = GlobalVariables.from({
|
|
279
|
+
chainId: constants.chainId,
|
|
280
|
+
version: constants.version,
|
|
281
|
+
blockNumber: blockRootRollupOutput.previousArchive.nextAvailableLeafIndex,
|
|
282
|
+
timestamp: blockRootRollupOutput.endTimestamp,
|
|
283
|
+
slotNumber: constants.slotNumber,
|
|
284
|
+
coinbase: constants.coinbase,
|
|
285
|
+
feeRecipient: constants.feeRecipient,
|
|
286
|
+
gasFees: constants.gasFees,
|
|
287
|
+
});
|
|
299
288
|
|
|
300
|
-
const
|
|
301
|
-
const accumulatedManaUsed = previousRollupData.reduce((sum, d) => sum.add(d.accumulatedManaUsed), Fr.ZERO);
|
|
289
|
+
const spongeBlobHash = await blockRootRollupOutput.endSpongeBlob.clone().squeeze();
|
|
302
290
|
|
|
303
291
|
return new BlockHeader(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
accumulatedFees,
|
|
309
|
-
accumulatedManaUsed,
|
|
292
|
+
blockRootRollupOutput.previousArchive,
|
|
293
|
+
blockRootRollupOutput.endState,
|
|
294
|
+
spongeBlobHash,
|
|
295
|
+
globalVariables,
|
|
296
|
+
blockRootRollupOutput.accumulatedFees,
|
|
297
|
+
blockRootRollupOutput.accumulatedManaUsed,
|
|
310
298
|
);
|
|
311
299
|
},
|
|
312
300
|
);
|
|
@@ -320,6 +308,7 @@ export const buildHeaderAndBodyFromTxs = runInSpan(
|
|
|
320
308
|
globalVariables: GlobalVariables,
|
|
321
309
|
l1ToL2Messages: Fr[],
|
|
322
310
|
db: MerkleTreeReadOperations,
|
|
311
|
+
startSpongeBlob?: SpongeBlob,
|
|
323
312
|
) => {
|
|
324
313
|
span.setAttribute(Attributes.BLOCK_NUMBER, globalVariables.blockNumber);
|
|
325
314
|
const stateReference = new StateReference(
|
|
@@ -337,25 +326,75 @@ export const buildHeaderAndBodyFromTxs = runInSpan(
|
|
|
337
326
|
const body = new Body(txEffects);
|
|
338
327
|
|
|
339
328
|
const txOutHashes = txEffects.map(tx => tx.txOutHash());
|
|
340
|
-
const outHash = txOutHashes.length === 0 ? Fr.ZERO : new Fr(
|
|
329
|
+
const outHash = txOutHashes.length === 0 ? Fr.ZERO : new Fr(computeCompressedUnbalancedMerkleTreeRoot(txOutHashes));
|
|
341
330
|
|
|
342
331
|
const parityShaRoot = await computeInHashFromL1ToL2Messages(l1ToL2Messages);
|
|
343
|
-
const
|
|
332
|
+
const blockBlobFields = body.toBlobFields();
|
|
333
|
+
// TODO(#17027): This only works when there's one block per checkpoint.
|
|
334
|
+
const blobFields = [new Fr(blockBlobFields.length + 1)].concat(blockBlobFields);
|
|
335
|
+
const blobsHash = computeBlobsHashFromBlobs(getBlobsPerL1Block(blobFields));
|
|
344
336
|
|
|
345
337
|
const contentCommitment = new ContentCommitment(blobsHash, parityShaRoot, outHash);
|
|
346
338
|
|
|
347
339
|
const fees = txEffects.reduce((acc, tx) => acc.add(tx.transactionFee), Fr.ZERO);
|
|
348
340
|
const manaUsed = txs.reduce((acc, tx) => acc.add(new Fr(tx.gasUsed.billedGas.l2Gas)), Fr.ZERO);
|
|
349
341
|
|
|
350
|
-
const
|
|
342
|
+
const endSpongeBlob = startSpongeBlob?.clone() ?? (await SpongeBlob.init(blobFields.length));
|
|
343
|
+
await endSpongeBlob.absorb(blockBlobFields);
|
|
344
|
+
const spongeBlobHash = await endSpongeBlob.squeeze();
|
|
345
|
+
|
|
346
|
+
const header = new L2BlockHeader(
|
|
347
|
+
previousArchive,
|
|
348
|
+
contentCommitment,
|
|
349
|
+
stateReference,
|
|
350
|
+
globalVariables,
|
|
351
|
+
fees,
|
|
352
|
+
manaUsed,
|
|
353
|
+
spongeBlobHash,
|
|
354
|
+
);
|
|
351
355
|
|
|
352
356
|
return { header, body };
|
|
353
357
|
},
|
|
354
358
|
);
|
|
355
359
|
|
|
360
|
+
export const buildBlockHeaderFromTxs = runInSpan(
|
|
361
|
+
'BlockBuilderHelpers',
|
|
362
|
+
'buildBlockHeaderFromTxs',
|
|
363
|
+
async (
|
|
364
|
+
span,
|
|
365
|
+
txs: ProcessedTx[],
|
|
366
|
+
globalVariables: GlobalVariables,
|
|
367
|
+
startSpongeBlob: SpongeBlob,
|
|
368
|
+
db: MerkleTreeReadOperations,
|
|
369
|
+
) => {
|
|
370
|
+
span.setAttribute(Attributes.BLOCK_NUMBER, globalVariables.blockNumber);
|
|
371
|
+
const stateReference = new StateReference(
|
|
372
|
+
await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db),
|
|
373
|
+
new PartialStateReference(
|
|
374
|
+
await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db),
|
|
375
|
+
await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db),
|
|
376
|
+
await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db),
|
|
377
|
+
),
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
const previousArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
|
|
381
|
+
|
|
382
|
+
const blobFields = getBlockBlobFields(txs.map(tx => tx.txEffect));
|
|
383
|
+
const endSpongeBlob = startSpongeBlob.clone();
|
|
384
|
+
await endSpongeBlob.absorb(blobFields);
|
|
385
|
+
const spongeBlobHash = await endSpongeBlob.squeeze();
|
|
386
|
+
|
|
387
|
+
const txEffects = txs.map(tx => tx.txEffect);
|
|
388
|
+
const fees = txEffects.reduce((acc, tx) => acc.add(tx.transactionFee), Fr.ZERO);
|
|
389
|
+
const manaUsed = txs.reduce((acc, tx) => acc.add(new Fr(tx.gasUsed.billedGas.l2Gas)), Fr.ZERO);
|
|
390
|
+
|
|
391
|
+
return new BlockHeader(previousArchive, stateReference, spongeBlobHash, globalVariables, fees, manaUsed);
|
|
392
|
+
},
|
|
393
|
+
);
|
|
394
|
+
|
|
356
395
|
/** Computes the inHash for a block's ContentCommitment given its l1 to l2 messages. */
|
|
357
396
|
export async function computeInHashFromL1ToL2Messages(unpaddedL1ToL2Messages: Fr[]): Promise<Fr> {
|
|
358
|
-
const l1ToL2Messages = padArrayEnd(unpaddedL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
397
|
+
const l1ToL2Messages = padArrayEnd<Fr, number>(unpaddedL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
359
398
|
const hasher = (left: Buffer, right: Buffer) =>
|
|
360
399
|
Promise.resolve(sha256Trunc(Buffer.concat([left, right])) as Buffer<ArrayBuffer>);
|
|
361
400
|
const parityHeight = Math.ceil(Math.log2(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP));
|
|
@@ -363,52 +402,6 @@ export async function computeInHashFromL1ToL2Messages(unpaddedL1ToL2Messages: Fr
|
|
|
363
402
|
return new Fr(await parityCalculator.computeTreeRoot(l1ToL2Messages.map(msg => msg.toBuffer())));
|
|
364
403
|
}
|
|
365
404
|
|
|
366
|
-
export function getBlobsHashFromBlobs(inputs: Blob[]): Fr {
|
|
367
|
-
return sha256ToField(inputs.map(b => b.getEthVersionedBlobHash()));
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Note: tested against the constant values in block_root/empty_block_root_rollup_inputs.nr, set by block_building_helpers.test.ts.
|
|
371
|
-
// Having this separate fn hopefully makes it clear how we treat empty blocks and their blobs, and won't break if we decide to change how
|
|
372
|
-
// getBlobsPerBlock() works on empty input.
|
|
373
|
-
export async function getEmptyBlockBlobsHash(): Promise<Fr> {
|
|
374
|
-
const blobHash = (await Blob.getBlobsPerBlock([])).map(b => b.getEthVersionedBlobHash());
|
|
375
|
-
return sha256ToField(blobHash);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Validate that the roots of all local trees match the output of the root circuit simulation
|
|
379
|
-
// TODO: does this get called?
|
|
380
|
-
export async function validateBlockRootOutput(
|
|
381
|
-
blockRootOutput: BlockRootOrBlockMergePublicInputs,
|
|
382
|
-
blockHeader: BlockHeader,
|
|
383
|
-
db: MerkleTreeReadOperations,
|
|
384
|
-
) {
|
|
385
|
-
await Promise.all([
|
|
386
|
-
validateState(blockHeader.state, db),
|
|
387
|
-
validateSimulatedTree(await getTreeSnapshot(MerkleTreeId.ARCHIVE, db), blockRootOutput.newArchive, 'Archive'),
|
|
388
|
-
]);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
export const validateState = runInSpan(
|
|
392
|
-
'BlockBuilderHelpers',
|
|
393
|
-
'validateState',
|
|
394
|
-
async (_span, state: StateReference, db: MerkleTreeReadOperations) => {
|
|
395
|
-
const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map(
|
|
396
|
-
async (id: MerkleTreeId) => {
|
|
397
|
-
return { key: id, value: await getTreeSnapshot(id, db) };
|
|
398
|
-
},
|
|
399
|
-
);
|
|
400
|
-
const snapshots: Map<MerkleTreeId, AppendOnlyTreeSnapshot> = new Map(
|
|
401
|
-
(await Promise.all(promises)).map(obj => [obj.key, obj.value]),
|
|
402
|
-
);
|
|
403
|
-
validatePartialState(state.partial, snapshots);
|
|
404
|
-
validateSimulatedTree(
|
|
405
|
-
await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db),
|
|
406
|
-
state.l1ToL2MessageTree,
|
|
407
|
-
'L1ToL2MessageTree',
|
|
408
|
-
);
|
|
409
|
-
},
|
|
410
|
-
);
|
|
411
|
-
|
|
412
405
|
export async function getLastSiblingPath<TID extends MerkleTreeId>(treeId: TID, db: MerkleTreeReadOperations) {
|
|
413
406
|
const { size } = await db.getTreeInfo(treeId);
|
|
414
407
|
const path = await db.getSiblingPath(treeId, size - 1n);
|
|
@@ -541,7 +534,7 @@ function validateSimulatedTree(
|
|
|
541
534
|
}
|
|
542
535
|
|
|
543
536
|
export function validateTx(tx: ProcessedTx) {
|
|
544
|
-
const txHeader = tx.data.constants.
|
|
537
|
+
const txHeader = tx.data.constants.anchorBlockHeader;
|
|
545
538
|
if (txHeader.state.l1ToL2MessageTree.isEmpty()) {
|
|
546
539
|
throw new Error(`Empty L1 to L2 messages tree in tx: ${toFriendlyJSON(tx)}`);
|
|
547
540
|
}
|
|
@@ -555,3 +548,12 @@ export function validateTx(tx: ProcessedTx) {
|
|
|
555
548
|
throw new Error(`Empty public data tree in tx: ${toFriendlyJSON(tx)}`);
|
|
556
549
|
}
|
|
557
550
|
}
|
|
551
|
+
|
|
552
|
+
export function toProofData<T extends Bufferable, PROOF_LENGTH extends number>(
|
|
553
|
+
{ inputs, proof, verificationKey }: PublicInputsAndRecursiveProof<T, PROOF_LENGTH>,
|
|
554
|
+
vkIndex?: number,
|
|
555
|
+
) {
|
|
556
|
+
const leafIndex = vkIndex || getVKIndex(verificationKey.keyAsFields);
|
|
557
|
+
const vkData = new VkData(verificationKey, leafIndex, getVKSiblingPath(leafIndex));
|
|
558
|
+
return new ProofData(inputs, proof, vkData);
|
|
559
|
+
}
|