@aztec/sequencer-client 0.23.0 → 0.24.0

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.
Files changed (65) hide show
  1. package/dest/block_builder/solo_block_builder.d.ts +2 -2
  2. package/dest/block_builder/solo_block_builder.d.ts.map +1 -1
  3. package/dest/block_builder/solo_block_builder.js +3 -3
  4. package/dest/prover/empty.d.ts +2 -2
  5. package/dest/prover/empty.d.ts.map +1 -1
  6. package/dest/prover/empty.js +1 -1
  7. package/dest/prover/index.d.ts +2 -2
  8. package/dest/prover/index.d.ts.map +1 -1
  9. package/dest/sequencer/abstract_phase_manager.d.ts +11 -11
  10. package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
  11. package/dest/sequencer/abstract_phase_manager.js +18 -15
  12. package/dest/sequencer/application_logic_phase_manager.d.ts +3 -3
  13. package/dest/sequencer/application_logic_phase_manager.d.ts.map +1 -1
  14. package/dest/sequencer/application_logic_phase_manager.js +2 -2
  15. package/dest/sequencer/fee_distribution_phase_manager.d.ts +4 -4
  16. package/dest/sequencer/fee_distribution_phase_manager.d.ts.map +1 -1
  17. package/dest/sequencer/fee_distribution_phase_manager.js +2 -2
  18. package/dest/sequencer/fee_preparation_phase_manager.d.ts +3 -3
  19. package/dest/sequencer/fee_preparation_phase_manager.d.ts.map +1 -1
  20. package/dest/sequencer/fee_preparation_phase_manager.js +1 -2
  21. package/dest/sequencer/processed_tx.d.ts +3 -3
  22. package/dest/sequencer/processed_tx.d.ts.map +1 -1
  23. package/dest/sequencer/processed_tx.js +4 -4
  24. package/dest/sequencer/public_processor.d.ts.map +1 -1
  25. package/dest/sequencer/public_processor.js +1 -1
  26. package/dest/simulator/index.d.ts +3 -3
  27. package/dest/simulator/index.d.ts.map +1 -1
  28. package/dest/simulator/public_kernel.d.ts +3 -3
  29. package/dest/simulator/public_kernel.d.ts.map +1 -1
  30. package/dest/simulator/public_kernel.js +4 -4
  31. package/dest/simulator/rollup.js +2 -2
  32. package/package.json +12 -23
  33. package/src/block_builder/index.ts +24 -0
  34. package/src/block_builder/solo_block_builder.ts +715 -0
  35. package/src/block_builder/types.ts +8 -0
  36. package/src/client/index.ts +1 -0
  37. package/src/client/sequencer-client.ts +97 -0
  38. package/src/config.ts +86 -0
  39. package/src/global_variable_builder/config.ts +20 -0
  40. package/src/global_variable_builder/global_builder.ts +95 -0
  41. package/src/global_variable_builder/index.ts +16 -0
  42. package/src/global_variable_builder/viem-reader.ts +61 -0
  43. package/src/index.ts +15 -0
  44. package/src/mocks/verification_keys.ts +36 -0
  45. package/src/prover/empty.ts +74 -0
  46. package/src/prover/index.ts +53 -0
  47. package/src/publisher/config.ts +41 -0
  48. package/src/publisher/index.ts +14 -0
  49. package/src/publisher/l1-publisher.ts +365 -0
  50. package/src/publisher/viem-tx-sender.ts +241 -0
  51. package/src/receiver.ts +13 -0
  52. package/src/sequencer/abstract_phase_manager.ts +427 -0
  53. package/src/sequencer/application_logic_phase_manager.ts +107 -0
  54. package/src/sequencer/config.ts +1 -0
  55. package/src/sequencer/fee_distribution_phase_manager.ts +70 -0
  56. package/src/sequencer/fee_preparation_phase_manager.ts +79 -0
  57. package/src/sequencer/index.ts +2 -0
  58. package/src/sequencer/processed_tx.ts +95 -0
  59. package/src/sequencer/public_processor.ts +136 -0
  60. package/src/sequencer/sequencer.ts +462 -0
  61. package/src/simulator/index.ts +53 -0
  62. package/src/simulator/public_executor.ts +169 -0
  63. package/src/simulator/public_kernel.ts +58 -0
  64. package/src/simulator/rollup.ts +76 -0
  65. package/src/utils.ts +16 -0
@@ -0,0 +1,365 @@
1
+ import { ExtendedContractData, L2Block } from '@aztec/circuit-types';
2
+ import { L1PublishStats } from '@aztec/circuit-types/stats';
3
+ import { createDebugLogger } from '@aztec/foundation/log';
4
+ import { InterruptibleSleep } from '@aztec/foundation/sleep';
5
+
6
+ import pick from 'lodash.pick';
7
+
8
+ import { L2BlockReceiver } from '../receiver.js';
9
+ import { PublisherConfig } from './config.js';
10
+
11
+ /**
12
+ * Stats for a sent transaction.
13
+ */
14
+ export type TransactionStats = {
15
+ /** Hash of the transaction. */
16
+ transactionHash: string;
17
+ /** Size in bytes of the tx calldata */
18
+ calldataSize: number;
19
+ /** Gas required to pay for the calldata inclusion (depends on size and number of zeros) */
20
+ calldataGas: number;
21
+ };
22
+
23
+ /**
24
+ * Minimal information from a tx receipt returned by an L1PublisherTxSender.
25
+ */
26
+ export type MinimalTransactionReceipt = {
27
+ /** True if the tx was successful, false if reverted. */
28
+ status: boolean;
29
+ /** Hash of the transaction. */
30
+ transactionHash: string;
31
+ /** Effective gas used by the tx. */
32
+ gasUsed: bigint;
33
+ /** Effective gas price paid by the tx. */
34
+ gasPrice: bigint;
35
+ /** Logs emitted in this tx. */
36
+ logs: any[];
37
+ };
38
+
39
+ /**
40
+ * Pushes txs to the L1 chain and waits for their completion.
41
+ */
42
+ export interface L1PublisherTxSender {
43
+ /**
44
+ * Publishes tx effects to Availability Oracle.
45
+ * @param encodedBody - Encoded block body.
46
+ * @returns The hash of the mined tx.
47
+ */
48
+ sendPublishTx(encodedBody: Buffer): Promise<string | undefined>;
49
+
50
+ /**
51
+ * Sends a tx to the L1 rollup contract with a new L2 block. Returns once the tx has been mined.
52
+ * @param encodedData - Serialized data for processing the new L2 block.
53
+ * @returns The hash of the mined tx.
54
+ */
55
+ sendProcessTx(encodedData: L1ProcessArgs): Promise<string | undefined>;
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
+ /**
74
+ * Returns a tx receipt if the tx has been mined.
75
+ * @param txHash - Hash of the tx to look for.
76
+ * @returns Undefined if the tx hasn't been mined yet, the receipt otherwise.
77
+ */
78
+ getTransactionReceipt(txHash: string): Promise<MinimalTransactionReceipt | undefined>;
79
+
80
+ /**
81
+ * Returns info on a tx by calling eth_getTransaction.
82
+ * @param txHash - Hash of the tx to look for.
83
+ */
84
+ getTransactionStats(txHash: string): Promise<TransactionStats | undefined>;
85
+
86
+ /**
87
+ * Returns the current archive root.
88
+ * @returns The current archive root of the rollup contract.
89
+ */
90
+ getCurrentArchive(): Promise<Buffer>;
91
+
92
+ /**
93
+ * Checks if the transaction effects of the given block are available.
94
+ * @param block - The block of which to check whether txs are available.
95
+ * @returns True if the txs are available, false otherwise.
96
+ */
97
+ checkIfTxsAreAvailable(block: L2Block): Promise<boolean>;
98
+ }
99
+
100
+ /**
101
+ * Encoded block and proof ready to be pushed to the L1 contract.
102
+ */
103
+ export type L1ProcessArgs = {
104
+ /** The L2 block header. */
105
+ header: Buffer;
106
+ /** A root of the archive tree after the L2 block is applied. */
107
+ archive: Buffer;
108
+ /** Transactions hash. */
109
+ txsHash: Buffer;
110
+ /** L2 block body. */
111
+ body: Buffer;
112
+ /** Root rollup proof of the L2 block. */
113
+ proof: Buffer;
114
+ };
115
+
116
+ /**
117
+ * Helper function to filter out undefined items from an array.
118
+ * Also asserts the resulting array is of type <T>.
119
+ * @param item - An item from an array to check if undefined or not.
120
+ * @returns True if the item is not undefined.
121
+ */
122
+ function isNotUndefined<T>(item: T | undefined): item is T {
123
+ return item !== undefined;
124
+ }
125
+
126
+ /**
127
+ * Publishes L2 blocks to L1. This implementation does *not* retry a transaction in
128
+ * the event of network congestion, but should work for local development.
129
+ * - If sending (not mining) a tx fails, it retries indefinitely at 1-minute intervals.
130
+ * - If the tx is not mined, keeps polling indefinitely at 1-second intervals.
131
+ *
132
+ * Adapted from https://github.com/AztecProtocol/aztec2-internal/blob/master/falafel/src/rollup_publisher.ts.
133
+ */
134
+ export class L1Publisher implements L2BlockReceiver {
135
+ private interruptibleSleep = new InterruptibleSleep();
136
+ private sleepTimeMs: number;
137
+ private interrupted = false;
138
+ private log = createDebugLogger('aztec:sequencer:publisher');
139
+
140
+ constructor(private txSender: L1PublisherTxSender, config?: PublisherConfig) {
141
+ this.sleepTimeMs = config?.l1BlockPublishRetryIntervalMS ?? 60_000;
142
+ }
143
+
144
+ /**
145
+ * Publishes L2 block on L1.
146
+ * @param block - L2 block to publish.
147
+ * @returns True once the tx has been confirmed and is successful, false on revert or interrupt, blocks otherwise.
148
+ */
149
+ public async processL2Block(block: L2Block): Promise<boolean> {
150
+ // TODO(#4148) Remove this block number check, it's here because we don't currently have proper genesis state on the contract
151
+ const lastArchive = block.header.lastArchive.root.toBuffer();
152
+ if (block.number != 1 && !(await this.checkLastArchiveHash(lastArchive))) {
153
+ this.log(`Detected different last archive prior to publishing a block, aborting publish...`);
154
+ return false;
155
+ }
156
+
157
+ const encodedBody = block.bodyToBuffer();
158
+
159
+ // Publish block transaction effects
160
+ while (!this.interrupted) {
161
+ if (await this.txSender.checkIfTxsAreAvailable(block)) {
162
+ this.log(`Transaction effects of a block ${block.number} already published.`);
163
+ break;
164
+ }
165
+
166
+ const txHash = await this.sendPublishTx(encodedBody);
167
+ if (!txHash) {
168
+ return false;
169
+ }
170
+
171
+ const receipt = await this.getTransactionReceipt(txHash);
172
+ if (!receipt) {
173
+ return false;
174
+ }
175
+
176
+ if (receipt.status) {
177
+ let txsHash;
178
+ if (receipt.logs.length === 1) {
179
+ // txsHash from IAvailabilityOracle.TxsPublished event
180
+ txsHash = receipt.logs[0].data;
181
+ } else {
182
+ this.log(`Expected 1 log, got ${receipt.logs.length}`);
183
+ }
184
+
185
+ this.log.info(`Block txs effects published, txsHash: ${txsHash}`);
186
+ break;
187
+ }
188
+
189
+ this.log(`AvailabilityOracle.publish tx status failed: ${receipt.transactionHash}`);
190
+ await this.sleepOrInterrupted();
191
+ }
192
+
193
+ const processTxArgs = {
194
+ header: block.header.toBuffer(),
195
+ archive: block.archive.root.toBuffer(),
196
+ txsHash: block.getCalldataHash(),
197
+ body: encodedBody,
198
+ proof: Buffer.alloc(0),
199
+ };
200
+
201
+ // Process block
202
+ while (!this.interrupted) {
203
+ const txHash = await this.sendProcessTx(processTxArgs);
204
+ if (!txHash) {
205
+ break;
206
+ }
207
+
208
+ const receipt = await this.getTransactionReceipt(txHash);
209
+ if (!receipt) {
210
+ break;
211
+ }
212
+
213
+ // Tx was mined successfully
214
+ if (receipt.status) {
215
+ const tx = await this.txSender.getTransactionStats(txHash);
216
+ const stats: L1PublishStats = {
217
+ ...pick(receipt, 'gasPrice', 'gasUsed', 'transactionHash'),
218
+ ...pick(tx!, 'calldataGas', 'calldataSize'),
219
+ ...block.getStats(),
220
+ eventName: 'rollup-published-to-l1',
221
+ };
222
+ this.log.info(`Published L2 block to L1 rollup contract`, stats);
223
+ return true;
224
+ }
225
+
226
+ // Check if someone else incremented the block number
227
+ if (!(await this.checkLastArchiveHash(lastArchive))) {
228
+ this.log('Publish failed. Detected different last archive hash.');
229
+ break;
230
+ }
231
+
232
+ this.log(`Rollup.process tx status failed: ${receipt.transactionHash}`);
233
+ await this.sleepOrInterrupted();
234
+ }
235
+
236
+ this.log('L2 block data syncing interrupted while processing blocks.');
237
+ return false;
238
+ }
239
+
240
+ /**
241
+ * Publishes new contract data to L1.
242
+ * @param l2BlockNum - The L2 block number that the new contracts were deployed on.
243
+ * @param l2BlockHash - The hash of the block corresponding to this data.
244
+ * @param contractData - The new contract data to publish.
245
+ * @returns True once the tx has been confirmed and is successful, false on revert or interrupt, blocks otherwise.
246
+ */
247
+ public async processNewContractData(l2BlockNum: number, l2BlockHash: Buffer, contractData: ExtendedContractData[]) {
248
+ let _contractData: ExtendedContractData[] = [];
249
+ while (!this.interrupted) {
250
+ const arr = _contractData.length ? _contractData : contractData;
251
+ const txHashes = await this.sendEmitNewContractDataTx(l2BlockNum, l2BlockHash, arr);
252
+ if (!txHashes) {
253
+ break;
254
+ }
255
+ // filter successful txs
256
+ _contractData = arr.filter((_, i) => !!txHashes[i]);
257
+
258
+ const receipts = await Promise.all(
259
+ txHashes.filter(isNotUndefined).map(txHash => this.getTransactionReceipt(txHash)),
260
+ );
261
+ if (!receipts?.length) {
262
+ break;
263
+ }
264
+
265
+ // ALL Txs were mined successfully
266
+ if (receipts.length === contractData.length && receipts.every(r => r?.status)) {
267
+ return true;
268
+ }
269
+
270
+ this.log(
271
+ `Transaction status failed: ${receipts
272
+ .filter(r => !r?.status)
273
+ .map(r => r?.transactionHash)
274
+ .join(',')}`,
275
+ );
276
+ await this.sleepOrInterrupted();
277
+ }
278
+
279
+ this.log('L2 block data syncing interrupted while processing contract data.');
280
+ return false;
281
+ }
282
+
283
+ /**
284
+ * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
285
+ * Be warned, the call may return false even if the tx subsequently gets successfully mined.
286
+ * In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
287
+ * A call to `restart` is required before you can continue publishing.
288
+ */
289
+ public interrupt() {
290
+ this.interrupted = true;
291
+ this.interruptibleSleep.interrupt();
292
+ }
293
+
294
+ /** Restarts the publisher after calling `interrupt`. */
295
+ public restart() {
296
+ this.interrupted = false;
297
+ }
298
+
299
+ /**
300
+ * Verifies that the given value of last archive in a block header equals current archive of the rollup contract
301
+ * @param lastArchive - The last archive of the block we wish to publish.
302
+ * @returns Boolean indicating if the hashes are equal.
303
+ */
304
+ private async checkLastArchiveHash(lastArchive: Buffer): Promise<boolean> {
305
+ const fromChain = await this.txSender.getCurrentArchive();
306
+ const areSame = lastArchive.equals(fromChain);
307
+ if (!areSame) {
308
+ this.log(`CONTRACT ARCHIVE: ${fromChain.toString('hex')}`);
309
+ this.log(`NEW BLOCK LAST ARCHIVE: ${lastArchive.toString('hex')}`);
310
+ }
311
+ return areSame;
312
+ }
313
+
314
+ private async sendPublishTx(encodedBody: Buffer): Promise<string | undefined> {
315
+ while (!this.interrupted) {
316
+ try {
317
+ return await this.txSender.sendPublishTx(encodedBody);
318
+ } catch (err) {
319
+ this.log.error(`TxEffects publish failed`, err);
320
+ return undefined;
321
+ }
322
+ }
323
+ }
324
+
325
+ private async sendProcessTx(encodedData: L1ProcessArgs): Promise<string | undefined> {
326
+ while (!this.interrupted) {
327
+ try {
328
+ return await this.txSender.sendProcessTx(encodedData);
329
+ } catch (err) {
330
+ this.log.error(`Rollup publish failed`, err);
331
+ return undefined;
332
+ }
333
+ }
334
+ }
335
+
336
+ private async sendEmitNewContractDataTx(
337
+ l2BlockNum: number,
338
+ l2BlockHash: Buffer,
339
+ newExtendedContractData: ExtendedContractData[],
340
+ ) {
341
+ while (!this.interrupted) {
342
+ try {
343
+ return await this.txSender.sendEmitContractDeploymentTx(l2BlockNum, l2BlockHash, newExtendedContractData);
344
+ } catch (err) {
345
+ this.log.error(`Error sending contract data to L1`, err);
346
+ await this.sleepOrInterrupted();
347
+ }
348
+ }
349
+ }
350
+
351
+ private async getTransactionReceipt(txHash: string): Promise<MinimalTransactionReceipt | undefined> {
352
+ while (!this.interrupted) {
353
+ try {
354
+ return await this.txSender.getTransactionReceipt(txHash);
355
+ } catch (err) {
356
+ //this.log.error(`Error getting tx receipt`, err);
357
+ await this.sleepOrInterrupted();
358
+ }
359
+ }
360
+ }
361
+
362
+ protected async sleepOrInterrupted() {
363
+ await this.interruptibleSleep.sleep(this.sleepTimeMs);
364
+ }
365
+ }
@@ -0,0 +1,241 @@
1
+ import { BLOB_SIZE_IN_BYTES, ExtendedContractData, L2Block } from '@aztec/circuit-types';
2
+ import { createEthereumChain } from '@aztec/ethereum';
3
+ import { createDebugLogger } from '@aztec/foundation/log';
4
+ import { AvailabilityOracleAbi, ContractDeploymentEmitterAbi, RollupAbi } from '@aztec/l1-artifacts';
5
+
6
+ import {
7
+ GetContractReturnType,
8
+ Hex,
9
+ HttpTransport,
10
+ PublicClient,
11
+ WalletClient,
12
+ createPublicClient,
13
+ createWalletClient,
14
+ getAddress,
15
+ getContract,
16
+ hexToBytes,
17
+ http,
18
+ } from 'viem';
19
+ import { PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts';
20
+ import * as chains from 'viem/chains';
21
+
22
+ import { TxSenderConfig } from './config.js';
23
+ import {
24
+ L1PublisherTxSender,
25
+ MinimalTransactionReceipt,
26
+ L1ProcessArgs as ProcessTxArgs,
27
+ TransactionStats,
28
+ } from './l1-publisher.js';
29
+
30
+ /**
31
+ * Pushes transactions to the L1 rollup contract using viem.
32
+ */
33
+ export class ViemTxSender implements L1PublisherTxSender {
34
+ private availabilityOracleContract: GetContractReturnType<
35
+ typeof AvailabilityOracleAbi,
36
+ PublicClient<HttpTransport, chains.Chain>,
37
+ WalletClient<HttpTransport, chains.Chain, PrivateKeyAccount>
38
+ >;
39
+ private rollupContract: GetContractReturnType<
40
+ typeof RollupAbi,
41
+ PublicClient<HttpTransport, chains.Chain>,
42
+ WalletClient<HttpTransport, chains.Chain, PrivateKeyAccount>
43
+ >;
44
+ private contractDeploymentEmitterContract: GetContractReturnType<
45
+ typeof ContractDeploymentEmitterAbi,
46
+ PublicClient<HttpTransport, chains.Chain>,
47
+ WalletClient<HttpTransport, chains.Chain, PrivateKeyAccount>
48
+ >;
49
+
50
+ private log = createDebugLogger('aztec:sequencer:viem-tx-sender');
51
+ private publicClient: PublicClient<HttpTransport, chains.Chain>;
52
+ private account: PrivateKeyAccount;
53
+
54
+ constructor(config: TxSenderConfig) {
55
+ const { rpcUrl, apiKey, publisherPrivateKey, l1Contracts } = config;
56
+ const chain = createEthereumChain(rpcUrl, apiKey);
57
+ this.account = privateKeyToAccount(publisherPrivateKey);
58
+ const walletClient = createWalletClient({
59
+ account: this.account,
60
+ chain: chain.chainInfo,
61
+ transport: http(chain.rpcUrl),
62
+ });
63
+
64
+ this.publicClient = createPublicClient({
65
+ chain: chain.chainInfo,
66
+ transport: http(chain.rpcUrl),
67
+ });
68
+
69
+ this.availabilityOracleContract = getContract({
70
+ address: getAddress(l1Contracts.availabilityOracleAddress.toString()),
71
+ abi: AvailabilityOracleAbi,
72
+ publicClient: this.publicClient,
73
+ walletClient,
74
+ });
75
+ this.rollupContract = getContract({
76
+ address: getAddress(l1Contracts.rollupAddress.toString()),
77
+ abi: RollupAbi,
78
+ publicClient: this.publicClient,
79
+ walletClient,
80
+ });
81
+ this.contractDeploymentEmitterContract = getContract({
82
+ address: getAddress(l1Contracts.contractDeploymentEmitterAddress.toString()),
83
+ abi: ContractDeploymentEmitterAbi,
84
+ publicClient: this.publicClient,
85
+ walletClient,
86
+ });
87
+ }
88
+
89
+ async getCurrentArchive(): Promise<Buffer> {
90
+ const archive = await this.rollupContract.read.archive();
91
+ return Buffer.from(archive.replace('0x', ''), 'hex');
92
+ }
93
+
94
+ checkIfTxsAreAvailable(block: L2Block): Promise<boolean> {
95
+ const args = [`0x${block.getCalldataHash().toString('hex')}`] as const;
96
+ return this.availabilityOracleContract.read.isAvailable(args);
97
+ }
98
+
99
+ async getTransactionStats(txHash: string): Promise<TransactionStats | undefined> {
100
+ const tx = await this.publicClient.getTransaction({ hash: txHash as Hex });
101
+ if (!tx) {
102
+ return undefined;
103
+ }
104
+ const calldata = hexToBytes(tx.input);
105
+ return {
106
+ transactionHash: tx.hash,
107
+ calldataSize: calldata.length,
108
+ calldataGas: getCalldataGasUsage(calldata),
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Returns a tx receipt if the tx has been mined.
114
+ * @param txHash - Hash of the tx to look for.
115
+ * @returns Undefined if the tx hasn't been mined yet, the receipt otherwise.
116
+ */
117
+ async getTransactionReceipt(txHash: string): Promise<MinimalTransactionReceipt | undefined> {
118
+ const receipt = await this.publicClient.getTransactionReceipt({
119
+ hash: txHash as Hex,
120
+ });
121
+
122
+ if (receipt) {
123
+ return {
124
+ status: receipt.status === 'success',
125
+ transactionHash: txHash,
126
+ gasUsed: receipt.gasUsed,
127
+ gasPrice: receipt.effectiveGasPrice,
128
+ logs: receipt.logs,
129
+ };
130
+ }
131
+
132
+ this.log(`Receipt not found for tx hash ${txHash}`);
133
+ return undefined;
134
+ }
135
+
136
+ /**
137
+ * Publishes tx effects to Availability Oracle.
138
+ * @param encodedBody - Encoded block body.
139
+ * @returns The hash of the mined tx.
140
+ */
141
+ async sendPublishTx(encodedBody: Buffer): Promise<string | undefined> {
142
+ const args = [`0x${encodedBody.toString('hex')}`] as const;
143
+
144
+ const gas = await this.availabilityOracleContract.estimateGas.publish(args, {
145
+ account: this.account,
146
+ });
147
+ const hash = await this.availabilityOracleContract.write.publish(args, {
148
+ gas,
149
+ account: this.account,
150
+ });
151
+ return hash;
152
+ }
153
+
154
+ /**
155
+ * Sends a tx to the L1 rollup contract with a new L2 block. Returns once the tx has been mined.
156
+ * @param encodedData - Serialized data for processing the new L2 block.
157
+ * @returns The hash of the mined tx.
158
+ */
159
+ async sendProcessTx(encodedData: ProcessTxArgs): Promise<string | undefined> {
160
+ const args = [
161
+ `0x${encodedData.header.toString('hex')}`,
162
+ `0x${encodedData.archive.toString('hex')}`,
163
+ `0x${encodedData.txsHash.toString('hex')}`,
164
+ `0x${encodedData.body.toString('hex')}`,
165
+ `0x${encodedData.proof.toString('hex')}`,
166
+ ] as const;
167
+
168
+ const gas = await this.rollupContract.estimateGas.process(args, {
169
+ account: this.account,
170
+ });
171
+ const hash = await this.rollupContract.write.process(args, {
172
+ gas,
173
+ account: this.account,
174
+ });
175
+ return hash;
176
+ }
177
+
178
+ /**
179
+ * Sends a tx to the contract deployment emitter contract with contract deployment data such as bytecode. Returns once the tx has been mined.
180
+ * @param l2BlockNum - Number of the L2 block that owns this encrypted logs.
181
+ * @param l2BlockHash - The hash of the block corresponding to this data.
182
+ * @param newExtendedContractData - Data to publish.
183
+ * @returns The hash of the mined tx.
184
+ */
185
+ async sendEmitContractDeploymentTx(
186
+ l2BlockNum: number,
187
+ l2BlockHash: Buffer,
188
+ newExtendedContractData: ExtendedContractData[],
189
+ ): Promise<(string | undefined)[]> {
190
+ const hashes: string[] = [];
191
+ for (const extendedContractData of newExtendedContractData) {
192
+ const args = [
193
+ BigInt(l2BlockNum),
194
+ extendedContractData.contractData.contractAddress.toString() as Hex,
195
+ extendedContractData.contractData.portalContractAddress.toString() as Hex,
196
+ `0x${l2BlockHash.toString('hex')}`,
197
+ extendedContractData.contractClassId.toString(),
198
+ extendedContractData.saltedInitializationHash.toString(),
199
+ extendedContractData.publicKeyHash.toString(),
200
+ `0x${extendedContractData.bytecode.toString('hex')}`,
201
+ ] as const;
202
+
203
+ const codeSize = extendedContractData.bytecode.length;
204
+ this.log(`Bytecode is ${codeSize} bytes and require ${codeSize / BLOB_SIZE_IN_BYTES} blobs`);
205
+
206
+ const gas = await this.contractDeploymentEmitterContract.estimateGas.emitContractDeployment(args, {
207
+ account: this.account,
208
+ });
209
+ const hash = await this.contractDeploymentEmitterContract.write.emitContractDeployment(args, {
210
+ gas,
211
+ account: this.account,
212
+ });
213
+ hashes.push(hash);
214
+ }
215
+ return hashes;
216
+ }
217
+
218
+ /**
219
+ * Gets the chain object for the given chain id.
220
+ * @param chainId - Chain id of the target EVM chain.
221
+ * @returns Viem's chain object.
222
+ */
223
+ private getChain(chainId: number) {
224
+ for (const chain of Object.values(chains)) {
225
+ if ('id' in chain && chain.id === chainId) {
226
+ return chain;
227
+ }
228
+ }
229
+
230
+ throw new Error(`Chain with id ${chainId} not found`);
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Returns cost of calldata usage in Ethereum.
236
+ * @param data - Calldata.
237
+ * @returns 4 for each zero byte, 16 for each nonzero.
238
+ */
239
+ function getCalldataGasUsage(data: Uint8Array) {
240
+ return data.filter(byte => byte === 0).length * 4 + data.filter(byte => byte !== 0).length * 16;
241
+ }
@@ -0,0 +1,13 @@
1
+ import { L2Block } from '@aztec/circuit-types';
2
+
3
+ /**
4
+ * Given the necessary rollup data, verifies it, and updates the underlying state accordingly to advance the state of the system.
5
+ * See https://hackmd.io/ouVCnacHQRq2o1oRc5ksNA#RollupReceiver.
6
+ */
7
+ export interface L2BlockReceiver {
8
+ /**
9
+ * Receive and L2 block and process it, returns true if successful.
10
+ * @param l2BlockData - L2 block to process.
11
+ */
12
+ processL2Block(l2BlockData: L2Block): Promise<boolean>;
13
+ }