@aztec/sequencer-client 0.26.6 → 0.27.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/solo_block_builder.d.ts.map +1 -1
- package/dest/block_builder/solo_block_builder.js +6 -25
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +2 -5
- package/dest/publisher/l1-publisher.d.ts +1 -21
- package/dest/publisher/l1-publisher.d.ts.map +1 -1
- package/dest/publisher/l1-publisher.js +1 -55
- package/dest/publisher/viem-tx-sender.d.ts +1 -10
- package/dest/publisher/viem-tx-sender.d.ts.map +1 -1
- package/dest/publisher/viem-tx-sender.js +2 -41
- package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/abstract_phase_manager.js +6 -4
- package/dest/sequencer/hints_builder.d.ts +9 -3
- package/dest/sequencer/hints_builder.d.ts.map +1 -1
- package/dest/sequencer/hints_builder.js +26 -5
- package/dest/sequencer/processed_tx.d.ts +1 -1
- package/dest/sequencer/processed_tx.d.ts.map +1 -1
- package/dest/sequencer/processed_tx.js +3 -5
- package/dest/sequencer/sequencer.d.ts +0 -6
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +1 -26
- package/dest/simulator/public_executor.d.ts.map +1 -1
- package/dest/simulator/public_executor.js +1 -15
- package/package.json +13 -13
- package/src/block_builder/solo_block_builder.ts +11 -45
- package/src/config.ts +0 -4
- package/src/publisher/l1-publisher.ts +1 -85
- package/src/publisher/viem-tx-sender.ts +2 -52
- package/src/sequencer/abstract_phase_manager.ts +17 -2
- package/src/sequencer/hints_builder.ts +42 -6
- package/src/sequencer/processed_tx.ts +2 -18
- package/src/sequencer/sequencer.ts +0 -35
- package/src/simulator/public_executor.ts +0 -20
|
@@ -5,8 +5,6 @@ import {
|
|
|
5
5
|
AppendOnlyTreeSnapshot,
|
|
6
6
|
BaseOrMergeRollupPublicInputs,
|
|
7
7
|
BaseRollupInputs,
|
|
8
|
-
CONTRACT_SUBTREE_HEIGHT,
|
|
9
|
-
CONTRACT_SUBTREE_SIBLING_PATH_LENGTH,
|
|
10
8
|
ConstantRollupData,
|
|
11
9
|
GlobalVariables,
|
|
12
10
|
L1_TO_L2_MSG_SUBTREE_HEIGHT,
|
|
@@ -137,9 +135,6 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
137
135
|
if (txHeader.state.partial.nullifierTree.isZero()) {
|
|
138
136
|
throw new Error(`Empty nullifier tree in tx: ${toFriendlyJSON(tx)}`);
|
|
139
137
|
}
|
|
140
|
-
if (txHeader.state.partial.contractTree.isZero()) {
|
|
141
|
-
throw new Error(`Empty contract tree in tx: ${toFriendlyJSON(tx)}`);
|
|
142
|
-
}
|
|
143
138
|
if (txHeader.state.partial.publicDataTree.isZero()) {
|
|
144
139
|
throw new Error(`Empty public data tree in tx: ${toFriendlyJSON(tx)}`);
|
|
145
140
|
}
|
|
@@ -171,14 +166,11 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
171
166
|
for (const tx of txs) {
|
|
172
167
|
const input = await this.buildBaseRollupInput(tx, globalVariables);
|
|
173
168
|
baseRollupInputs.push(input);
|
|
174
|
-
const promises = [
|
|
175
|
-
MerkleTreeId
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
].map(async (id: MerkleTreeId) => {
|
|
180
|
-
return { key: id, value: await this.getTreeSnapshot(id) };
|
|
181
|
-
});
|
|
169
|
+
const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map(
|
|
170
|
+
async (id: MerkleTreeId) => {
|
|
171
|
+
return { key: id, value: await this.getTreeSnapshot(id) };
|
|
172
|
+
},
|
|
173
|
+
);
|
|
182
174
|
const snapshots: Map<MerkleTreeId, AppendOnlyTreeSnapshot> = new Map(
|
|
183
175
|
(await Promise.all(promises)).map(obj => [obj.key, obj.value]),
|
|
184
176
|
);
|
|
@@ -316,11 +308,6 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
316
308
|
partialState.nullifierTree,
|
|
317
309
|
'NullifierTree',
|
|
318
310
|
);
|
|
319
|
-
this.validateSimulatedTree(
|
|
320
|
-
treeSnapshots.get(MerkleTreeId.CONTRACT_TREE)!,
|
|
321
|
-
partialState.contractTree,
|
|
322
|
-
'ContractTree',
|
|
323
|
-
);
|
|
324
311
|
this.validateSimulatedTree(
|
|
325
312
|
treeSnapshots.get(MerkleTreeId.PUBLIC_DATA_TREE)!,
|
|
326
313
|
partialState.publicDataTree,
|
|
@@ -329,14 +316,11 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
329
316
|
}
|
|
330
317
|
|
|
331
318
|
protected async validateState(state: StateReference) {
|
|
332
|
-
const promises = [
|
|
333
|
-
MerkleTreeId
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
].map(async (id: MerkleTreeId) => {
|
|
338
|
-
return { key: id, value: await this.getTreeSnapshot(id) };
|
|
339
|
-
});
|
|
319
|
+
const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map(
|
|
320
|
+
async (id: MerkleTreeId) => {
|
|
321
|
+
return { key: id, value: await this.getTreeSnapshot(id) };
|
|
322
|
+
},
|
|
323
|
+
);
|
|
340
324
|
const snapshots: Map<MerkleTreeId, AppendOnlyTreeSnapshot> = new Map(
|
|
341
325
|
(await Promise.all(promises)).map(obj => [obj.key, obj.value]),
|
|
342
326
|
);
|
|
@@ -636,7 +620,6 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
636
620
|
const start = new PartialStateReference(
|
|
637
621
|
await this.getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE),
|
|
638
622
|
await this.getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE),
|
|
639
|
-
await this.getTreeSnapshot(MerkleTreeId.CONTRACT_TREE),
|
|
640
623
|
await this.getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE),
|
|
641
624
|
);
|
|
642
625
|
|
|
@@ -650,25 +633,9 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
650
633
|
i < noteHashSubtreeSiblingPathArray.length ? noteHashSubtreeSiblingPathArray[i] : Fr.ZERO,
|
|
651
634
|
);
|
|
652
635
|
|
|
653
|
-
|
|
654
|
-
MerkleTreeId.CONTRACT_TREE,
|
|
655
|
-
CONTRACT_SUBTREE_HEIGHT,
|
|
656
|
-
);
|
|
657
|
-
|
|
658
|
-
const contractSubtreeSiblingPath = makeTuple(CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, i =>
|
|
659
|
-
i < contractSubtreeSiblingPathArray.length ? contractSubtreeSiblingPathArray[i] : Fr.ZERO,
|
|
660
|
-
);
|
|
661
|
-
|
|
662
|
-
// Update the contract and note hash trees with the new items being inserted to get the new roots
|
|
636
|
+
// Update the note hash trees with the new items being inserted to get the new roots
|
|
663
637
|
// that will be used by the next iteration of the base rollup circuit, skipping the empty ones
|
|
664
|
-
const newContracts = tx.data.combinedData.newContracts.map(cd => cd.hash());
|
|
665
638
|
const newNoteHashes = tx.data.combinedData.newNoteHashes.map(x => x.value.toBuffer());
|
|
666
|
-
|
|
667
|
-
await this.db.appendLeaves(
|
|
668
|
-
MerkleTreeId.CONTRACT_TREE,
|
|
669
|
-
newContracts.map(x => x.toBuffer()),
|
|
670
|
-
);
|
|
671
|
-
|
|
672
639
|
await this.db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, newNoteHashes);
|
|
673
640
|
|
|
674
641
|
// The read witnesses for a given TX should be generated before the writes of the same TX are applied.
|
|
@@ -720,7 +687,6 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
720
687
|
sortedNullifierIndexes: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]),
|
|
721
688
|
noteHashSubtreeSiblingPath,
|
|
722
689
|
nullifierSubtreeSiblingPath,
|
|
723
|
-
contractSubtreeSiblingPath,
|
|
724
690
|
publicDataSiblingPath,
|
|
725
691
|
});
|
|
726
692
|
|
package/src/config.ts
CHANGED
|
@@ -44,7 +44,6 @@ export function getConfigEnvVars(): SequencerClientConfig {
|
|
|
44
44
|
ROLLUP_CONTRACT_ADDRESS,
|
|
45
45
|
REGISTRY_CONTRACT_ADDRESS,
|
|
46
46
|
INBOX_CONTRACT_ADDRESS,
|
|
47
|
-
CONTRACT_DEPLOYMENT_EMITTER_ADDRESS,
|
|
48
47
|
OUTBOX_CONTRACT_ADDRESS,
|
|
49
48
|
COINBASE,
|
|
50
49
|
FEE_RECIPIENT,
|
|
@@ -64,9 +63,6 @@ export function getConfigEnvVars(): SequencerClientConfig {
|
|
|
64
63
|
registryAddress: REGISTRY_CONTRACT_ADDRESS ? EthAddress.fromString(REGISTRY_CONTRACT_ADDRESS) : EthAddress.ZERO,
|
|
65
64
|
inboxAddress: INBOX_CONTRACT_ADDRESS ? EthAddress.fromString(INBOX_CONTRACT_ADDRESS) : EthAddress.ZERO,
|
|
66
65
|
outboxAddress: OUTBOX_CONTRACT_ADDRESS ? EthAddress.fromString(OUTBOX_CONTRACT_ADDRESS) : EthAddress.ZERO,
|
|
67
|
-
contractDeploymentEmitterAddress: CONTRACT_DEPLOYMENT_EMITTER_ADDRESS
|
|
68
|
-
? EthAddress.fromString(CONTRACT_DEPLOYMENT_EMITTER_ADDRESS)
|
|
69
|
-
: EthAddress.ZERO,
|
|
70
66
|
};
|
|
71
67
|
|
|
72
68
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { L2Block } from '@aztec/circuit-types';
|
|
2
2
|
import { L1PublishStats } from '@aztec/circuit-types/stats';
|
|
3
3
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { InterruptibleSleep } from '@aztec/foundation/sleep';
|
|
@@ -54,22 +54,6 @@ export interface L1PublisherTxSender {
|
|
|
54
54
|
*/
|
|
55
55
|
sendProcessTx(encodedData: L1ProcessArgs): Promise<string | undefined>;
|
|
56
56
|
|
|
57
|
-
/**
|
|
58
|
-
* Sends a tx to the contract deployment emitter contract with contract deployment data such as bytecode. Returns once the tx has been mined.
|
|
59
|
-
* @param l2BlockNum - Number of the L2 block that owns this encrypted logs.
|
|
60
|
-
* @param l2BlockHash - The hash of the block corresponding to this data.
|
|
61
|
-
* @param partialAddresses - The partial addresses of the deployed contract
|
|
62
|
-
* @param publicKeys - The public keys of the deployed contract
|
|
63
|
-
* @param newExtendedContractData - Data to publish.
|
|
64
|
-
* @returns The hash of the mined tx.
|
|
65
|
-
* @remarks Partial addresses, public keys and contract data has to be in the same order. Read more {@link https://docs.aztec.network/concepts/foundation/accounts/keys#addresses-partial-addresses-and-public-keys | here}.
|
|
66
|
-
*/
|
|
67
|
-
sendEmitContractDeploymentTx(
|
|
68
|
-
l2BlockNum: number,
|
|
69
|
-
l2BlockHash: Buffer,
|
|
70
|
-
newExtendedContractData: ExtendedContractData[],
|
|
71
|
-
): Promise<(string | undefined)[]>;
|
|
72
|
-
|
|
73
57
|
/**
|
|
74
58
|
* Returns a tx receipt if the tx has been mined.
|
|
75
59
|
* @param txHash - Hash of the tx to look for.
|
|
@@ -111,16 +95,6 @@ export type L1ProcessArgs = {
|
|
|
111
95
|
proof: Buffer;
|
|
112
96
|
};
|
|
113
97
|
|
|
114
|
-
/**
|
|
115
|
-
* Helper function to filter out undefined items from an array.
|
|
116
|
-
* Also asserts the resulting array is of type <T>.
|
|
117
|
-
* @param item - An item from an array to check if undefined or not.
|
|
118
|
-
* @returns True if the item is not undefined.
|
|
119
|
-
*/
|
|
120
|
-
function isNotUndefined<T>(item: T | undefined): item is T {
|
|
121
|
-
return item !== undefined;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
98
|
/**
|
|
125
99
|
* Publishes L2 blocks to L1. This implementation does *not* retry a transaction in
|
|
126
100
|
* the event of network congestion, but should work for local development.
|
|
@@ -234,49 +208,6 @@ export class L1Publisher implements L2BlockReceiver {
|
|
|
234
208
|
return false;
|
|
235
209
|
}
|
|
236
210
|
|
|
237
|
-
/**
|
|
238
|
-
* Publishes new contract data to L1.
|
|
239
|
-
* @param l2BlockNum - The L2 block number that the new contracts were deployed on.
|
|
240
|
-
* @param l2BlockHash - The hash of the block corresponding to this data.
|
|
241
|
-
* @param contractData - The new contract data to publish.
|
|
242
|
-
* @returns True once the tx has been confirmed and is successful, false on revert or interrupt, blocks otherwise.
|
|
243
|
-
*/
|
|
244
|
-
public async processNewContractData(l2BlockNum: number, l2BlockHash: Buffer, contractData: ExtendedContractData[]) {
|
|
245
|
-
let _contractData: ExtendedContractData[] = [];
|
|
246
|
-
while (!this.interrupted) {
|
|
247
|
-
const arr = _contractData.length ? _contractData : contractData;
|
|
248
|
-
const txHashes = await this.sendEmitNewContractDataTx(l2BlockNum, l2BlockHash, arr);
|
|
249
|
-
if (!txHashes) {
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
// filter successful txs
|
|
253
|
-
_contractData = arr.filter((_, i) => !!txHashes[i]);
|
|
254
|
-
|
|
255
|
-
const receipts = await Promise.all(
|
|
256
|
-
txHashes.filter(isNotUndefined).map(txHash => this.getTransactionReceipt(txHash)),
|
|
257
|
-
);
|
|
258
|
-
if (!receipts?.length) {
|
|
259
|
-
break;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// ALL Txs were mined successfully
|
|
263
|
-
if (receipts.length === contractData.length && receipts.every(r => r?.status)) {
|
|
264
|
-
return true;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
this.log(
|
|
268
|
-
`Transaction status failed: ${receipts
|
|
269
|
-
.filter(r => !r?.status)
|
|
270
|
-
.map(r => r?.transactionHash)
|
|
271
|
-
.join(',')}`,
|
|
272
|
-
);
|
|
273
|
-
await this.sleepOrInterrupted();
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
this.log('L2 block data syncing interrupted while processing contract data.');
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
211
|
/**
|
|
281
212
|
* Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
|
|
282
213
|
* Be warned, the call may return false even if the tx subsequently gets successfully mined.
|
|
@@ -330,21 +261,6 @@ export class L1Publisher implements L2BlockReceiver {
|
|
|
330
261
|
}
|
|
331
262
|
}
|
|
332
263
|
|
|
333
|
-
private async sendEmitNewContractDataTx(
|
|
334
|
-
l2BlockNum: number,
|
|
335
|
-
l2BlockHash: Buffer,
|
|
336
|
-
newExtendedContractData: ExtendedContractData[],
|
|
337
|
-
) {
|
|
338
|
-
while (!this.interrupted) {
|
|
339
|
-
try {
|
|
340
|
-
return await this.txSender.sendEmitContractDeploymentTx(l2BlockNum, l2BlockHash, newExtendedContractData);
|
|
341
|
-
} catch (err) {
|
|
342
|
-
this.log.error(`Error sending contract data to L1`, err);
|
|
343
|
-
await this.sleepOrInterrupted();
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
264
|
private async getTransactionReceipt(txHash: string): Promise<MinimalTransactionReceipt | undefined> {
|
|
349
265
|
while (!this.interrupted) {
|
|
350
266
|
try {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BLOB_SIZE_IN_BYTES } from '@aztec/circuits.js/constants';
|
|
1
|
+
import { L2Block } from '@aztec/circuit-types';
|
|
3
2
|
import { createEthereumChain } from '@aztec/ethereum';
|
|
4
3
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
5
|
-
import { AvailabilityOracleAbi,
|
|
4
|
+
import { AvailabilityOracleAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
6
5
|
|
|
7
6
|
import {
|
|
8
7
|
GetContractReturnType,
|
|
@@ -40,10 +39,6 @@ export class ViemTxSender implements L1PublisherTxSender {
|
|
|
40
39
|
typeof RollupAbi,
|
|
41
40
|
WalletClient<HttpTransport, chains.Chain, PrivateKeyAccount>
|
|
42
41
|
>;
|
|
43
|
-
private contractDeploymentEmitterContract: GetContractReturnType<
|
|
44
|
-
typeof ContractDeploymentEmitterAbi,
|
|
45
|
-
WalletClient<HttpTransport, chains.Chain, PrivateKeyAccount>
|
|
46
|
-
>;
|
|
47
42
|
|
|
48
43
|
private log = createDebugLogger('aztec:sequencer:viem-tx-sender');
|
|
49
44
|
private publicClient: PublicClient<HttpTransport, chains.Chain>;
|
|
@@ -74,11 +69,6 @@ export class ViemTxSender implements L1PublisherTxSender {
|
|
|
74
69
|
abi: RollupAbi,
|
|
75
70
|
client: walletClient,
|
|
76
71
|
});
|
|
77
|
-
this.contractDeploymentEmitterContract = getContract({
|
|
78
|
-
address: getAddress(l1Contracts.contractDeploymentEmitterAddress.toString()),
|
|
79
|
-
abi: ContractDeploymentEmitterAbi,
|
|
80
|
-
client: walletClient,
|
|
81
|
-
});
|
|
82
72
|
}
|
|
83
73
|
|
|
84
74
|
async getCurrentArchive(): Promise<Buffer> {
|
|
@@ -169,46 +159,6 @@ export class ViemTxSender implements L1PublisherTxSender {
|
|
|
169
159
|
return hash;
|
|
170
160
|
}
|
|
171
161
|
|
|
172
|
-
/**
|
|
173
|
-
* Sends a tx to the contract deployment emitter contract with contract deployment data such as bytecode. Returns once the tx has been mined.
|
|
174
|
-
* @param l2BlockNum - Number of the L2 block that owns this encrypted logs.
|
|
175
|
-
* @param l2BlockHash - The hash of the block corresponding to this data.
|
|
176
|
-
* @param newExtendedContractData - Data to publish.
|
|
177
|
-
* @returns The hash of the mined tx.
|
|
178
|
-
*/
|
|
179
|
-
async sendEmitContractDeploymentTx(
|
|
180
|
-
l2BlockNum: number,
|
|
181
|
-
l2BlockHash: Buffer,
|
|
182
|
-
newExtendedContractData: ExtendedContractData[],
|
|
183
|
-
): Promise<(string | undefined)[]> {
|
|
184
|
-
const hashes: string[] = [];
|
|
185
|
-
for (const extendedContractData of newExtendedContractData) {
|
|
186
|
-
const args = [
|
|
187
|
-
BigInt(l2BlockNum),
|
|
188
|
-
extendedContractData.contractData.contractAddress.toString() as Hex,
|
|
189
|
-
extendedContractData.contractData.portalContractAddress.toString() as Hex,
|
|
190
|
-
`0x${l2BlockHash.toString('hex')}`,
|
|
191
|
-
extendedContractData.contractClassId.toString(),
|
|
192
|
-
extendedContractData.saltedInitializationHash.toString(),
|
|
193
|
-
extendedContractData.publicKeyHash.toString(),
|
|
194
|
-
`0x${extendedContractData.bytecode.toString('hex')}`,
|
|
195
|
-
] as const;
|
|
196
|
-
|
|
197
|
-
const codeSize = extendedContractData.bytecode.length;
|
|
198
|
-
this.log(`Bytecode is ${codeSize} bytes and require ${codeSize / BLOB_SIZE_IN_BYTES} blobs`);
|
|
199
|
-
|
|
200
|
-
const gas = await this.contractDeploymentEmitterContract.estimateGas.emitContractDeployment(args, {
|
|
201
|
-
account: this.account,
|
|
202
|
-
});
|
|
203
|
-
const hash = await this.contractDeploymentEmitterContract.write.emitContractDeployment(args, {
|
|
204
|
-
gas,
|
|
205
|
-
account: this.account,
|
|
206
|
-
});
|
|
207
|
-
hashes.push(hash);
|
|
208
|
-
}
|
|
209
|
-
return hashes;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
162
|
/**
|
|
213
163
|
* Gets the chain object for the given chain id.
|
|
214
164
|
* @param chainId - Chain id of the target EVM chain.
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
MAX_NEW_NULLIFIERS_PER_CALL,
|
|
14
14
|
MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX,
|
|
15
15
|
MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
16
|
+
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL,
|
|
16
17
|
MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
|
|
17
18
|
MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
|
|
18
19
|
MAX_PUBLIC_DATA_READS_PER_CALL,
|
|
@@ -264,13 +265,22 @@ export abstract class AbstractPhaseManager {
|
|
|
264
265
|
|
|
265
266
|
if (this.phase === PublicKernelPhase.TAIL) {
|
|
266
267
|
const { endNonRevertibleData, end } = previousOutput;
|
|
267
|
-
const
|
|
268
|
+
const nullifierReadRequestHints = await this.hintsBuilder.getNullifierReadRequestHints(
|
|
268
269
|
endNonRevertibleData.nullifierReadRequests,
|
|
269
270
|
end.nullifierReadRequests,
|
|
270
271
|
endNonRevertibleData.newNullifiers,
|
|
271
272
|
end.newNullifiers,
|
|
272
273
|
);
|
|
273
|
-
const
|
|
274
|
+
const nullifierNonExistentReadRequestHints = await this.hintsBuilder.getNullifierNonExistentReadRequestHints(
|
|
275
|
+
endNonRevertibleData.nullifierNonExistentReadRequests,
|
|
276
|
+
endNonRevertibleData.newNullifiers,
|
|
277
|
+
end.newNullifiers,
|
|
278
|
+
);
|
|
279
|
+
const inputs = new PublicKernelTailCircuitPrivateInputs(
|
|
280
|
+
previousKernel,
|
|
281
|
+
nullifierReadRequestHints,
|
|
282
|
+
nullifierNonExistentReadRequestHints,
|
|
283
|
+
);
|
|
274
284
|
return this.publicKernel.publicKernelCircuitTail(inputs);
|
|
275
285
|
}
|
|
276
286
|
|
|
@@ -329,6 +339,11 @@ export abstract class AbstractPhaseManager {
|
|
|
329
339
|
ReadRequest.empty(),
|
|
330
340
|
MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
|
|
331
341
|
),
|
|
342
|
+
nullifierNonExistentReadRequests: padArrayEnd(
|
|
343
|
+
result.nullifierNonExistentReadRequests,
|
|
344
|
+
ReadRequest.empty(),
|
|
345
|
+
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL,
|
|
346
|
+
),
|
|
332
347
|
contractStorageReads: padArrayEnd(
|
|
333
348
|
result.contractStorageReads,
|
|
334
349
|
ContractStorageRead.empty(),
|
|
@@ -3,14 +3,15 @@ import {
|
|
|
3
3
|
Fr,
|
|
4
4
|
MAX_NEW_NULLIFIERS_PER_TX,
|
|
5
5
|
MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX,
|
|
6
|
+
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX,
|
|
6
7
|
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
7
8
|
MAX_REVERTIBLE_NULLIFIERS_PER_TX,
|
|
8
9
|
MembershipWitness,
|
|
9
10
|
NULLIFIER_TREE_HEIGHT,
|
|
10
|
-
NullifierLeafPreimage,
|
|
11
11
|
ReadRequestContext,
|
|
12
12
|
SideEffectLinkedToNoteHash,
|
|
13
|
-
|
|
13
|
+
buildNullifierNonExistentReadRequestHints,
|
|
14
|
+
buildNullifierReadRequestHints,
|
|
14
15
|
concatAccumulatedData,
|
|
15
16
|
mergeAccumulatedData,
|
|
16
17
|
} from '@aztec/circuits.js';
|
|
@@ -20,13 +21,13 @@ import { MerkleTreeOperations } from '@aztec/world-state';
|
|
|
20
21
|
export class HintsBuilder {
|
|
21
22
|
constructor(private db: MerkleTreeOperations) {}
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
getNullifierReadRequestHints(
|
|
24
25
|
nullifierReadRequestsNonRevertible: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>,
|
|
25
26
|
nullifierReadRequestsRevertible: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>,
|
|
26
27
|
nullifiersNonRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX>,
|
|
27
28
|
nullifiersRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_REVERTIBLE_NULLIFIERS_PER_TX>,
|
|
28
29
|
) {
|
|
29
|
-
return
|
|
30
|
+
return buildNullifierReadRequestHints(
|
|
30
31
|
this,
|
|
31
32
|
mergeAccumulatedData(
|
|
32
33
|
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
@@ -37,19 +38,54 @@ export class HintsBuilder {
|
|
|
37
38
|
);
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
getNullifierNonExistentReadRequestHints(
|
|
42
|
+
nullifierNonExistentReadRequests: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX>,
|
|
43
|
+
nullifiersNonRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX>,
|
|
44
|
+
nullifiersRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_REVERTIBLE_NULLIFIERS_PER_TX>,
|
|
45
|
+
) {
|
|
46
|
+
const pendingNullifiers = concatAccumulatedData(
|
|
47
|
+
MAX_NEW_NULLIFIERS_PER_TX,
|
|
48
|
+
nullifiersNonRevertible,
|
|
49
|
+
nullifiersRevertible,
|
|
50
|
+
);
|
|
51
|
+
return buildNullifierNonExistentReadRequestHints(this, nullifierNonExistentReadRequests, pendingNullifiers);
|
|
52
|
+
}
|
|
53
|
+
|
|
40
54
|
async getNullifierMembershipWitness(nullifier: Fr) {
|
|
41
55
|
const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
|
|
42
56
|
if (index === undefined) {
|
|
43
57
|
return;
|
|
44
58
|
}
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
return this.getNullifierMembershipWitnessWithPreimage(index);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async getLowNullifierMembershipWitness(nullifier: Fr) {
|
|
64
|
+
const res = await this.db.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
65
|
+
if (res === undefined) {
|
|
66
|
+
throw new Error(`Cannot find the low leaf for nullifier ${nullifier.toBigInt()}.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const { index, alreadyPresent } = res;
|
|
70
|
+
if (alreadyPresent) {
|
|
71
|
+
throw new Error(`Nullifier ${nullifier.toBigInt()} already exists in the tree.`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return this.getNullifierMembershipWitnessWithPreimage(index);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private async getNullifierMembershipWitnessWithPreimage(index: bigint) {
|
|
78
|
+
const siblingPath = await this.db.getSiblingPath<typeof NULLIFIER_TREE_HEIGHT>(MerkleTreeId.NULLIFIER_TREE, index);
|
|
47
79
|
const membershipWitness = new MembershipWitness(
|
|
48
80
|
NULLIFIER_TREE_HEIGHT,
|
|
49
81
|
index,
|
|
50
82
|
siblingPath.toTuple<typeof NULLIFIER_TREE_HEIGHT>(),
|
|
51
83
|
);
|
|
52
|
-
|
|
84
|
+
|
|
85
|
+
const leafPreimage = await this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
|
|
86
|
+
if (!leafPreimage) {
|
|
87
|
+
throw new Error(`Cannot find the leaf preimage at index ${index}.`);
|
|
88
|
+
}
|
|
53
89
|
|
|
54
90
|
return { membershipWitness, leafPreimage };
|
|
55
91
|
}
|
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ContractData,
|
|
3
|
-
ExtendedContractData,
|
|
4
|
-
PublicDataWrite,
|
|
5
|
-
SimulationError,
|
|
6
|
-
Tx,
|
|
7
|
-
TxEffect,
|
|
8
|
-
TxHash,
|
|
9
|
-
TxL2Logs,
|
|
10
|
-
} from '@aztec/circuit-types';
|
|
1
|
+
import { PublicDataWrite, SimulationError, Tx, TxEffect, TxHash, TxL2Logs } from '@aztec/circuit-types';
|
|
11
2
|
import {
|
|
12
3
|
Fr,
|
|
13
4
|
Header,
|
|
14
|
-
MAX_NEW_CONTRACTS_PER_TX,
|
|
15
5
|
MAX_NEW_NOTE_HASHES_PER_TX,
|
|
16
6
|
MAX_NEW_NULLIFIERS_PER_TX,
|
|
17
7
|
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
@@ -29,7 +19,7 @@ import { Tuple, fromFieldsTuple } from '@aztec/foundation/serialize';
|
|
|
29
19
|
* Represents a tx that has been processed by the sequencer public processor,
|
|
30
20
|
* so its kernel circuit public inputs are filled in.
|
|
31
21
|
*/
|
|
32
|
-
export type ProcessedTx = Pick<Tx, 'proof' | 'encryptedLogs' | 'unencryptedLogs'
|
|
22
|
+
export type ProcessedTx = Pick<Tx, 'proof' | 'encryptedLogs' | 'unencryptedLogs'> & {
|
|
33
23
|
/**
|
|
34
24
|
* Output of the public kernel circuit for this tx.
|
|
35
25
|
*/
|
|
@@ -153,7 +143,6 @@ export function makeProcessedTx(
|
|
|
153
143
|
proof: previousProof,
|
|
154
144
|
encryptedLogs: revertReason ? new TxL2Logs([]) : tx.encryptedLogs,
|
|
155
145
|
unencryptedLogs: revertReason ? new TxL2Logs([]) : tx.unencryptedLogs,
|
|
156
|
-
newContracts: revertReason ? [ExtendedContractData.empty()] : tx.newContracts,
|
|
157
146
|
isEmpty: false,
|
|
158
147
|
revertReason,
|
|
159
148
|
};
|
|
@@ -177,7 +166,6 @@ export function makeEmptyProcessedTx(header: Header, chainId: Fr, version: Fr):
|
|
|
177
166
|
unencryptedLogs: new TxL2Logs([]),
|
|
178
167
|
data: emptyKernelOutput,
|
|
179
168
|
proof: emptyProof,
|
|
180
|
-
newContracts: [ExtendedContractData.empty()],
|
|
181
169
|
isEmpty: true,
|
|
182
170
|
revertReason: undefined,
|
|
183
171
|
};
|
|
@@ -195,10 +183,6 @@ export function toTxEffect(tx: ProcessedTx): TxEffect {
|
|
|
195
183
|
PublicDataWrite,
|
|
196
184
|
typeof MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
|
|
197
185
|
>,
|
|
198
|
-
tx.data.combinedData.newContracts.map(cd => cd.hash()) as Tuple<Fr, typeof MAX_NEW_CONTRACTS_PER_TX>,
|
|
199
|
-
tx.data.combinedData.newContracts.map(
|
|
200
|
-
cd => new ContractData(cd.contractAddress, cd.portalContractAddress),
|
|
201
|
-
) as Tuple<ContractData, typeof MAX_NEW_CONTRACTS_PER_TX>,
|
|
202
186
|
tx.encryptedLogs || new TxL2Logs([]),
|
|
203
187
|
tx.unencryptedLogs || new TxL2Logs([]),
|
|
204
188
|
);
|
|
@@ -227,10 +227,6 @@ export class Sequencer {
|
|
|
227
227
|
|
|
228
228
|
await assertBlockHeight();
|
|
229
229
|
|
|
230
|
-
await this.publishExtendedContractData(processedValidTxs, block);
|
|
231
|
-
|
|
232
|
-
await assertBlockHeight();
|
|
233
|
-
|
|
234
230
|
await this.publishL2Block(block);
|
|
235
231
|
this.log.info(`Submitted rollup block ${block.number} with ${processedValidTxs.length} transactions`);
|
|
236
232
|
} catch (err) {
|
|
@@ -239,37 +235,6 @@ export class Sequencer {
|
|
|
239
235
|
}
|
|
240
236
|
}
|
|
241
237
|
|
|
242
|
-
/**
|
|
243
|
-
* Gets new extended contract data from the txs and publishes it on chain.
|
|
244
|
-
* @param validTxs - The set of real transactions being published as part of the block.
|
|
245
|
-
* @param block - The L2Block to be published.
|
|
246
|
-
*/
|
|
247
|
-
protected async publishExtendedContractData(validTxs: ProcessedTx[], block: L2Block) {
|
|
248
|
-
// Publishes contract data for txs to the network and awaits the tx to be mined
|
|
249
|
-
this.state = SequencerState.PUBLISHING_CONTRACT_DATA;
|
|
250
|
-
const newContracts = validTxs.flatMap(tx => tx.newContracts).filter(cd => !cd.isEmpty());
|
|
251
|
-
|
|
252
|
-
if (newContracts.length === 0) {
|
|
253
|
-
this.log.debug(`No new contracts to publish in block ${block.number}`);
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const txsEffectsHash = block.body.getTxsEffectsHash();
|
|
258
|
-
this.log.info(`Publishing ${newContracts.length} contracts in block ${block.number}`);
|
|
259
|
-
|
|
260
|
-
const publishedContractData = await this.publisher.processNewContractData(
|
|
261
|
-
block.number,
|
|
262
|
-
txsEffectsHash,
|
|
263
|
-
newContracts,
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
if (publishedContractData) {
|
|
267
|
-
this.log(`Successfully published new contract data for block ${block.number}`);
|
|
268
|
-
} else if (!publishedContractData && newContracts.length) {
|
|
269
|
-
this.log(`Failed to publish new contract data for block ${block.number}`);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
238
|
/**
|
|
274
239
|
* Publishes the L2Block to the rollup contract.
|
|
275
240
|
* @param block - The L2Block to be published.
|
|
@@ -45,16 +45,6 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
|
|
|
45
45
|
* @param tx - The transaction to add contracts from.
|
|
46
46
|
*/
|
|
47
47
|
public addNewContracts(tx: Tx): Promise<void> {
|
|
48
|
-
for (const contract of tx.newContracts) {
|
|
49
|
-
const contractAddress = contract.contractData.contractAddress;
|
|
50
|
-
|
|
51
|
-
if (contractAddress.isZero()) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this.cache.set(contractAddress.toString(), contract);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
48
|
// Extract contract class and instance data from logs and add to cache for this block
|
|
59
49
|
const logs = tx.unencryptedLogs.unrollLogs().map(UnencryptedL2Log.fromBuffer);
|
|
60
50
|
ContractClassRegisteredEvent.fromLogs(logs, ClassRegistererAddress).forEach(e => {
|
|
@@ -76,16 +66,6 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
|
|
|
76
66
|
* @param tx - The tx's contracts to be removed
|
|
77
67
|
*/
|
|
78
68
|
public removeNewContracts(tx: Tx): Promise<void> {
|
|
79
|
-
for (const contract of tx.newContracts) {
|
|
80
|
-
const contractAddress = contract.contractData.contractAddress;
|
|
81
|
-
|
|
82
|
-
if (contractAddress.isZero()) {
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
this.cache.delete(contractAddress.toString());
|
|
87
|
-
}
|
|
88
|
-
|
|
89
69
|
// TODO(@spalladino): Can this inadvertently delete a valid contract added by another tx?
|
|
90
70
|
// Let's say we have two txs adding the same contract on the same block. If the 2nd one reverts,
|
|
91
71
|
// wouldn't that accidentally remove the contract added on the first one?
|