@aztec/sequencer-client 0.28.1 → 0.30.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 (41) hide show
  1. package/dest/block_builder/index.d.ts +2 -4
  2. package/dest/block_builder/index.d.ts.map +1 -1
  3. package/dest/block_builder/solo_block_builder.d.ts +4 -7
  4. package/dest/block_builder/solo_block_builder.d.ts.map +1 -1
  5. package/dest/block_builder/solo_block_builder.js +18 -20
  6. package/dest/client/sequencer-client.d.ts +4 -3
  7. package/dest/client/sequencer-client.d.ts.map +1 -1
  8. package/dest/client/sequencer-client.js +2 -2
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +6 -2
  11. package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
  12. package/dest/sequencer/abstract_phase_manager.js +10 -11
  13. package/dest/sequencer/hints_builder.d.ts +1 -1
  14. package/dest/sequencer/hints_builder.d.ts.map +1 -1
  15. package/dest/sequencer/hints_builder.js +4 -4
  16. package/dest/sequencer/processed_tx.d.ts.map +1 -1
  17. package/dest/sequencer/processed_tx.js +3 -3
  18. package/dest/sequencer/public_processor.d.ts +2 -1
  19. package/dest/sequencer/public_processor.d.ts.map +1 -1
  20. package/dest/sequencer/public_processor.js +1 -1
  21. package/dest/sequencer/sequencer.d.ts +6 -26
  22. package/dest/sequencer/sequencer.d.ts.map +1 -1
  23. package/dest/sequencer/sequencer.js +26 -101
  24. package/dest/sequencer/tx_validator.d.ts +22 -0
  25. package/dest/sequencer/tx_validator.d.ts.map +1 -0
  26. package/dest/sequencer/tx_validator.js +125 -0
  27. package/dest/simulator/public_executor.d.ts +3 -5
  28. package/dest/simulator/public_executor.d.ts.map +1 -1
  29. package/dest/simulator/public_executor.js +18 -34
  30. package/package.json +13 -13
  31. package/src/block_builder/index.ts +2 -8
  32. package/src/block_builder/solo_block_builder.ts +18 -29
  33. package/src/client/sequencer-client.ts +3 -1
  34. package/src/config.ts +6 -0
  35. package/src/sequencer/abstract_phase_manager.ts +9 -12
  36. package/src/sequencer/hints_builder.ts +2 -8
  37. package/src/sequencer/processed_tx.ts +2 -0
  38. package/src/sequencer/public_processor.ts +2 -1
  39. package/src/sequencer/sequencer.ts +31 -117
  40. package/src/sequencer/tx_validator.ts +189 -0
  41. package/src/simulator/public_executor.ts +15 -42
@@ -11,6 +11,7 @@ import {
11
11
  PublicKernelCircuitPublicInputs,
12
12
  SideEffect,
13
13
  SideEffectLinkedToNoteHash,
14
+ ValidationRequests,
14
15
  makeEmptyProof,
15
16
  } from '@aztec/circuits.js';
16
17
  import { Tuple, fromFieldsTuple } from '@aztec/foundation/serialize';
@@ -109,6 +110,7 @@ export function getPreviousOutputAndProof(
109
110
  } else {
110
111
  const publicKernelPublicInput = new PublicKernelCircuitPublicInputs(
111
112
  tx.data.aggregationObject,
113
+ ValidationRequests.empty(),
112
114
  PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData),
113
115
  PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end),
114
116
  tx.data.constants,
@@ -1,9 +1,10 @@
1
- import { ContractDataSource, L1ToL2MessageSource, SimulationError, Tx } from '@aztec/circuit-types';
1
+ import { L1ToL2MessageSource, SimulationError, Tx } from '@aztec/circuit-types';
2
2
  import { TxSequencerProcessingStats } from '@aztec/circuit-types/stats';
3
3
  import { GlobalVariables, Header } from '@aztec/circuits.js';
4
4
  import { createDebugLogger } from '@aztec/foundation/log';
5
5
  import { Timer } from '@aztec/foundation/timer';
6
6
  import { PublicExecutor, PublicStateDB } from '@aztec/simulator';
7
+ import { ContractDataSource } from '@aztec/types/contracts';
7
8
  import { MerkleTreeOperations } from '@aztec/world-state';
8
9
 
9
10
  import { EmptyPublicProver } from '../prover/empty.js';
@@ -12,10 +12,12 @@ import { WorldStateStatus, WorldStateSynchronizer } from '@aztec/world-state';
12
12
  import { BlockBuilder } from '../block_builder/index.js';
13
13
  import { GlobalVariableBuilder } from '../global_variable_builder/global_builder.js';
14
14
  import { L1Publisher } from '../publisher/l1-publisher.js';
15
+ import { WorldStatePublicDB } from '../simulator/public_executor.js';
15
16
  import { ceilPowerOfTwo } from '../utils.js';
16
17
  import { SequencerConfig } from './config.js';
17
18
  import { ProcessedTx } from './processed_tx.js';
18
19
  import { PublicProcessorFactory } from './public_processor.js';
20
+ import { TxValidator } from './tx_validator.js';
19
21
 
20
22
  /**
21
23
  * Sequencer client
@@ -47,6 +49,7 @@ export class Sequencer {
47
49
  private l1ToL2MessageSource: L1ToL2MessageSource,
48
50
  private publicProcessorFactory: PublicProcessorFactory,
49
51
  config: SequencerConfig = {},
52
+ private gasPortalAddress = EthAddress.ZERO,
50
53
  private log = createDebugLogger('aztec:sequencer'),
51
54
  ) {
52
55
  this.updateConfig(config);
@@ -171,8 +174,20 @@ export class Sequencer {
171
174
  );
172
175
 
173
176
  // Filter out invalid txs
177
+ const trees = this.worldState.getLatest();
178
+ const txValidator = new TxValidator(
179
+ {
180
+ getNullifierIndex(nullifier: Fr): Promise<bigint | undefined> {
181
+ return trees.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
182
+ },
183
+ },
184
+ new WorldStatePublicDB(trees),
185
+ this.gasPortalAddress,
186
+ newGlobalVariables,
187
+ );
188
+
174
189
  // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here
175
- const validTxs = await this.takeValidTxs(pendingTxs, newGlobalVariables);
190
+ const validTxs = await this.takeValidTxs(pendingTxs, txValidator);
176
191
  if (validTxs.length < this.minTxsPerBLock) {
177
192
  return;
178
193
  }
@@ -193,7 +208,7 @@ export class Sequencer {
193
208
  // public functions emitting nullifiers would pass earlier check but fail here.
194
209
  // Note that we're checking all nullifiers generated in the private execution twice,
195
210
  // we could store the ones already checked and skip them here as an optimization.
196
- const processedValidTxs = await this.takeValidTxs(processedTxs, newGlobalVariables);
211
+ const processedValidTxs = await this.takeValidTxs(processedTxs, txValidator);
197
212
 
198
213
  if (processedValidTxs.length === 0) {
199
214
  this.log('No txs processed correctly to build block. Exiting');
@@ -202,12 +217,10 @@ export class Sequencer {
202
217
 
203
218
  await assertBlockHeight();
204
219
 
205
- const newModelL1ToL2Messages = await this.l1ToL2MessageSource.getNewL1ToL2Messages(BigInt(newBlockNumber));
206
-
207
220
  // Get l1 to l2 messages from the contract
208
221
  this.log('Requesting L1 to L2 messages from contract');
209
- const l1ToL2Messages = await this.getPendingL1ToL2EntryKeys();
210
- this.log('Successfully retrieved L1 to L2 messages from contract');
222
+ const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(BigInt(newBlockNumber));
223
+ this.log(`Retrieved ${l1ToL2Messages.length} L1 to L2 messages for block ${newBlockNumber}`);
211
224
 
212
225
  // Build the new block by running the rollup circuits
213
226
  this.log(`Assembling block with txs ${processedValidTxs.map(tx => tx.hash).join(', ')}`);
@@ -216,7 +229,7 @@ export class Sequencer {
216
229
 
217
230
  const emptyTx = processor.makeEmptyProcessedTx();
218
231
  const [rollupCircuitsDuration, block] = await elapsed(() =>
219
- this.buildBlock(processedValidTxs, newModelL1ToL2Messages, l1ToL2Messages, emptyTx, newGlobalVariables),
232
+ this.buildBlock(processedValidTxs, l1ToL2Messages, emptyTx, newGlobalVariables),
220
233
  );
221
234
 
222
235
  this.log(`Assembled block ${block.number}`, {
@@ -253,47 +266,14 @@ export class Sequencer {
253
266
  }
254
267
  }
255
268
 
256
- protected async takeValidTxs<T extends Tx | ProcessedTx>(txs: T[], globalVariables: GlobalVariables): Promise<T[]> {
257
- const validTxs: T[] = [];
258
- const txsToDelete = [];
259
- const thisBlockNullifiers: Set<bigint> = new Set();
260
-
261
- // Process txs until we get to maxTxsPerBlock, rejecting double spends in the process
262
- for (const tx of txs) {
263
- if (tx.data.constants.txContext.chainId.value !== globalVariables.chainId.value) {
264
- this.log(
265
- `Deleting tx for incorrect chain ${tx.data.constants.txContext.chainId.toString()}, tx hash ${Tx.getHash(
266
- tx,
267
- )}`,
268
- );
269
- txsToDelete.push(tx);
270
- continue;
271
- }
272
- if (await this.isTxDoubleSpend(tx)) {
273
- this.log(`Deleting double spend tx ${Tx.getHash(tx)}`);
274
- txsToDelete.push(tx);
275
- continue;
276
- } else if (this.isTxDoubleSpendSameBlock(tx, thisBlockNullifiers)) {
277
- // We don't drop these txs from the p2p pool immediately since they become valid
278
- // again if the current block fails to be published for some reason.
279
- this.log(`Skipping tx with double-spend for this same block ${Tx.getHash(tx)}`);
280
- continue;
281
- }
282
-
283
- tx.data.end.newNullifiers.forEach(n => thisBlockNullifiers.add(n.value.toBigInt()));
284
- tx.data.endNonRevertibleData.newNullifiers.forEach(n => thisBlockNullifiers.add(n.value.toBigInt()));
285
- validTxs.push(tx);
286
- if (validTxs.length >= this.maxTxsPerBlock) {
287
- break;
288
- }
289
- }
290
-
291
- // Make sure we remove these from the tx pool so we do not consider it again
292
- if (txsToDelete.length > 0) {
293
- await this.p2pClient.deleteTxs(Tx.getHashes([...txsToDelete]));
269
+ protected async takeValidTxs<T extends Tx | ProcessedTx>(txs: T[], validator: TxValidator): Promise<T[]> {
270
+ const [valid, invalid] = await validator.validateTxs(txs);
271
+ if (invalid.length > 0) {
272
+ this.log(`Dropping invalid txs from the p2p pool ${Tx.getHashes(invalid).join(', ')}`);
273
+ await this.p2pClient.deleteTxs(Tx.getHashes(invalid));
294
274
  }
295
275
 
296
- return validTxs;
276
+ return valid.slice(0, this.maxTxsPerBlock);
297
277
  }
298
278
 
299
279
  /**
@@ -314,16 +294,14 @@ export class Sequencer {
314
294
  /**
315
295
  * Pads the set of txs to a power of two and assembles a block by calling the block builder.
316
296
  * @param txs - Processed txs to include in the next block.
317
- * @param newModelL1ToL2Messages - L1 to L2 messages emitted by the new inbox.
318
- * @param newL1ToL2Messages - L1 to L2 messages to be part of the block.
297
+ * @param l1ToL2Messages - L1 to L2 messages to be part of the block.
319
298
  * @param emptyTx - Empty tx to repeat at the end of the block to pad to a power of two.
320
299
  * @param globalVariables - Global variables to use in the block.
321
300
  * @returns The new block.
322
301
  */
323
302
  protected async buildBlock(
324
303
  txs: ProcessedTx[],
325
- newModelL1ToL2Messages: Fr[], // TODO(#4492): Rename this when purging the old inbox
326
- newL1ToL2Messages: Fr[], // TODO(#4492): Nuke this when purging the old inbox
304
+ l1ToL2Messages: Fr[],
327
305
  emptyTx: ProcessedTx,
328
306
  globalVariables: GlobalVariables,
329
307
  ) {
@@ -332,74 +310,10 @@ export class Sequencer {
332
310
  const emptyTxCount = txsTargetSize - txs.length;
333
311
 
334
312
  const allTxs = [...txs, ...times(emptyTxCount, () => emptyTx)];
335
- this.log(`Building block ${globalVariables.blockNumber}`);
336
-
337
- const [block] = await this.blockBuilder.buildL2Block(
338
- globalVariables,
339
- allTxs,
340
- newModelL1ToL2Messages,
341
- newL1ToL2Messages,
342
- );
343
- return block;
344
- }
345
-
346
- /**
347
- * Calls the archiver to pull upto `NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP` entry keys
348
- * (archiver returns the top messages sorted by fees)
349
- * @returns An array of L1 to L2 messages' entryKeys
350
- */
351
- protected async getPendingL1ToL2EntryKeys(): Promise<Fr[]> {
352
- return await this.l1ToL2MessageSource.getPendingL1ToL2EntryKeys();
353
- }
354
-
355
- /**
356
- * Returns true if one of the tx nullifiers exist on the block being built.
357
- * @param tx - The tx to test.
358
- * @param thisBlockNullifiers - The nullifiers added so far.
359
- */
360
- protected isTxDoubleSpendSameBlock(tx: Tx | ProcessedTx, thisBlockNullifiers: Set<bigint>): boolean {
361
- // We only consider non-empty nullifiers
362
- const newNullifiers = [
363
- ...tx.data.endNonRevertibleData.newNullifiers.filter(n => !n.isEmpty()),
364
- ...tx.data.end.newNullifiers.filter(n => !n.isEmpty()),
365
- ];
366
-
367
- for (const nullifier of newNullifiers) {
368
- if (thisBlockNullifiers.has(nullifier.value.toBigInt())) {
369
- return true;
370
- }
371
- }
372
- return false;
373
- }
313
+ this.log(`Building block ${globalVariables.blockNumber.toBigInt()}`);
374
314
 
375
- /**
376
- * Returns true if one of the transaction nullifiers exist.
377
- * Nullifiers prevent double spends in a private context.
378
- * @param tx - The transaction.
379
- * @returns Whether this is a problematic double spend that the L1 contract would reject.
380
- */
381
- protected async isTxDoubleSpend(tx: Tx | ProcessedTx): Promise<boolean> {
382
- // We only consider non-empty nullifiers
383
- const newNullifiers = [
384
- ...tx.data.endNonRevertibleData.newNullifiers.filter(n => !n.isEmpty()),
385
- ...tx.data.end.newNullifiers.filter(n => !n.isEmpty()),
386
- ];
387
-
388
- // Ditch this tx if it has a repeated nullifiers
389
- const uniqNullifiers = new Set(newNullifiers.map(n => n.value.toBigInt()));
390
- if (uniqNullifiers.size !== newNullifiers.length) {
391
- return true;
392
- }
393
-
394
- for (const nullifier of newNullifiers) {
395
- // TODO(AD): this is an exhaustive search currently
396
- const db = this.worldState.getLatest();
397
- const indexInDb = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
398
- if (indexInDb !== undefined) {
399
- return true;
400
- }
401
- }
402
- return false;
315
+ const [block] = await this.blockBuilder.buildL2Block(globalVariables, allTxs, l1ToL2Messages);
316
+ return block;
403
317
  }
404
318
 
405
319
  get coinbase(): EthAddress {
@@ -0,0 +1,189 @@
1
+ import { Tx } from '@aztec/circuit-types';
2
+ import { AztecAddress, EthAddress, Fr, GlobalVariables } from '@aztec/circuits.js';
3
+ import { pedersenHash } from '@aztec/foundation/crypto';
4
+ import { Logger, createDebugLogger } from '@aztec/foundation/log';
5
+ import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token';
6
+
7
+ import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
8
+ import { ProcessedTx } from './processed_tx.js';
9
+
10
+ /** A source of what nullifiers have been committed to the state trees */
11
+ export interface NullifierSource {
12
+ getNullifierIndex: (nullifier: Fr) => Promise<bigint | undefined>;
13
+ }
14
+
15
+ /** Provides a view into public contract state */
16
+ export interface PublicStateSource {
17
+ storageRead: (contractAddress: AztecAddress, slot: Fr) => Promise<Fr>;
18
+ }
19
+
20
+ // prefer symbols over booleans so it's clear what the intention is
21
+ // vs returning true/false is tied to the function name
22
+ // eg. isDoubleSpend vs isValidChain assign different meanings to booleans
23
+ const VALID_TX = Symbol('valid_tx');
24
+ const INVALID_TX = Symbol('invalid_tx');
25
+
26
+ type TxValidationStatus = typeof VALID_TX | typeof INVALID_TX;
27
+
28
+ // the storage slot associated with "storage.balances"
29
+ const GAS_TOKEN_BALANCES_SLOT = new Fr(1);
30
+
31
+ export class TxValidator {
32
+ #log: Logger;
33
+ #globalVariables: GlobalVariables;
34
+ #nullifierSource: NullifierSource;
35
+ #publicStateSource: PublicStateSource;
36
+ #gasPortalAddress: EthAddress;
37
+
38
+ constructor(
39
+ nullifierSource: NullifierSource,
40
+ publicStateSource: PublicStateSource,
41
+ gasPortalAddress: EthAddress,
42
+ globalVariables: GlobalVariables,
43
+ log = createDebugLogger('aztec:sequencer:tx_validator'),
44
+ ) {
45
+ this.#nullifierSource = nullifierSource;
46
+ this.#globalVariables = globalVariables;
47
+ this.#publicStateSource = publicStateSource;
48
+ this.#gasPortalAddress = gasPortalAddress;
49
+
50
+ this.#log = log;
51
+ }
52
+
53
+ /**
54
+ * Validates a list of transactions.
55
+ * @param txs - The transactions to validate.
56
+ * @returns A tuple of valid and invalid transactions.
57
+ */
58
+ public async validateTxs<T extends Tx | ProcessedTx>(txs: T[]): Promise<[validTxs: T[], invalidTxs: T[]]> {
59
+ const validTxs: T[] = [];
60
+ const invalidTxs: T[] = [];
61
+ const thisBlockNullifiers = new Set<bigint>();
62
+
63
+ for (const tx of txs) {
64
+ if (this.#validateMetadata(tx) === INVALID_TX) {
65
+ invalidTxs.push(tx);
66
+ continue;
67
+ }
68
+
69
+ if ((await this.#validateNullifiers(tx, thisBlockNullifiers)) === INVALID_TX) {
70
+ invalidTxs.push(tx);
71
+ continue;
72
+ }
73
+
74
+ // skip already processed transactions
75
+ if (tx instanceof Tx && (await this.#validateFee(tx)) === INVALID_TX) {
76
+ invalidTxs.push(tx);
77
+ continue;
78
+ }
79
+
80
+ validTxs.push(tx);
81
+ }
82
+
83
+ return [validTxs, invalidTxs];
84
+ }
85
+
86
+ /**
87
+ * It rejects transactions with the wrong chain id.
88
+ * @param tx - The transaction.
89
+ * @returns Whether the transaction is valid.
90
+ */
91
+ #validateMetadata(tx: Tx | ProcessedTx): TxValidationStatus {
92
+ if (!tx.data.constants.txContext.chainId.equals(this.#globalVariables.chainId)) {
93
+ this.#log.warn(
94
+ `Rejecting tx ${Tx.getHash(
95
+ tx,
96
+ )} because of incorrect chain ${tx.data.constants.txContext.chainId.toString()} != ${this.#globalVariables.chainId.toString()}`,
97
+ );
98
+ return INVALID_TX;
99
+ }
100
+
101
+ return VALID_TX;
102
+ }
103
+
104
+ /**
105
+ * It looks for duplicate nullifiers:
106
+ * - in the same transaction
107
+ * - in the same block
108
+ * - in the nullifier tree
109
+ *
110
+ * Nullifiers prevent double spends in a private context.
111
+ *
112
+ * @param tx - The transaction.
113
+ * @returns Whether this is a problematic double spend that the L1 contract would reject.
114
+ */
115
+ async #validateNullifiers(tx: Tx | ProcessedTx, thisBlockNullifiers: Set<bigint>): Promise<TxValidationStatus> {
116
+ const newNullifiers = [...tx.data.endNonRevertibleData.newNullifiers, ...tx.data.end.newNullifiers]
117
+ .filter(x => !x.isEmpty())
118
+ .map(x => x.value.toBigInt());
119
+
120
+ // Ditch this tx if it has repeated nullifiers
121
+ const uniqueNullifiers = new Set(newNullifiers);
122
+ if (uniqueNullifiers.size !== newNullifiers.length) {
123
+ this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for emitting duplicate nullifiers`);
124
+ return INVALID_TX;
125
+ }
126
+
127
+ for (const nullifier of newNullifiers) {
128
+ if (thisBlockNullifiers.has(nullifier)) {
129
+ this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating a nullifier in the same block`);
130
+ return INVALID_TX;
131
+ }
132
+
133
+ thisBlockNullifiers.add(nullifier);
134
+ }
135
+
136
+ const nullifierIndexes = await Promise.all(
137
+ newNullifiers.map(n => this.#nullifierSource.getNullifierIndex(new Fr(n))),
138
+ );
139
+
140
+ const hasDuplicates = nullifierIndexes.some(index => index !== undefined);
141
+ if (hasDuplicates) {
142
+ this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating nullifiers present in state trees`);
143
+ return INVALID_TX;
144
+ }
145
+
146
+ return VALID_TX;
147
+ }
148
+
149
+ async #validateFee(tx: Tx): Promise<TxValidationStatus> {
150
+ if (!tx.data.needsTeardown) {
151
+ // TODO check if fees are mandatory and reject this tx
152
+ this.#log.debug(`Tx ${Tx.getHash(tx)} doesn't pay for gas`);
153
+ return VALID_TX;
154
+ }
155
+
156
+ const {
157
+ // TODO what if there's more than one function call?
158
+ // if we're to enshrine that teardown = 1 function call, then we should turn this into a single function call
159
+ [PublicKernelPhase.TEARDOWN]: [teardownFn],
160
+ } = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx.data, tx.enqueuedPublicFunctionCalls);
161
+
162
+ if (!teardownFn) {
163
+ this.#log.warn(
164
+ `Rejecting tx ${Tx.getHash(tx)} because it should pay for gas but has no enqueued teardown function call`,
165
+ );
166
+ return INVALID_TX;
167
+ }
168
+
169
+ // TODO(#1204) if a generator index is used for the derived storage slot of a map, update it here as well
170
+ const slot = pedersenHash([GAS_TOKEN_BALANCES_SLOT.toBuffer(), teardownFn.callContext.msgSender.toBuffer()]);
171
+ const gasBalance = await this.#publicStateSource.storageRead(
172
+ getCanonicalGasTokenAddress(this.#gasPortalAddress),
173
+ slot,
174
+ );
175
+
176
+ // TODO(#5004) calculate fee needed based on tx limits and gas prices
177
+ const gasAmountNeeded = new Fr(1);
178
+ if (gasBalance.lt(gasAmountNeeded)) {
179
+ this.#log.warn(
180
+ `Rejecting tx ${Tx.getHash(
181
+ tx,
182
+ )} because it should pay for gas but has insufficient balance ${gasBalance.toShortString()} < ${gasAmountNeeded.toShortString()}`,
183
+ );
184
+ return INVALID_TX;
185
+ }
186
+
187
+ return VALID_TX;
188
+ }
189
+ }
@@ -1,6 +1,4 @@
1
1
  import {
2
- ContractDataSource,
3
- ExtendedContractData,
4
2
  L1ToL2MessageSource,
5
3
  MerkleTreeId,
6
4
  NullifierMembershipWitness,
@@ -22,9 +20,8 @@ import {
22
20
  import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
23
21
  import { createDebugLogger } from '@aztec/foundation/log';
24
22
  import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
25
- import { InstanceDeployerAddress } from '@aztec/protocol-contracts/instance-deployer';
26
23
  import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '@aztec/simulator';
27
- import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts';
24
+ import { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/types/contracts';
28
25
  import { MerkleTreeOperations } from '@aztec/world-state';
29
26
 
30
27
  /**
@@ -32,7 +29,6 @@ import { MerkleTreeOperations } from '@aztec/world-state';
32
29
  * Progressively records contracts in transaction as they are processed in a block.
33
30
  */
34
31
  export class ContractsDataSourcePublicDB implements PublicContractsDB {
35
- private cache = new Map<string, ExtendedContractData>();
36
32
  private instanceCache = new Map<string, ContractInstanceWithAddress>();
37
33
  private classCache = new Map<string, ContractClassPublic>();
38
34
 
@@ -51,7 +47,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
51
47
  this.log(`Adding class ${e.contractClassId.toString()} to public execution contract cache`);
52
48
  this.classCache.set(e.contractClassId.toString(), e.toContractClassPublic());
53
49
  });
54
- ContractInstanceDeployedEvent.fromLogs(logs, InstanceDeployerAddress).forEach(e => {
50
+ ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => {
55
51
  this.log(
56
52
  `Adding instance ${e.address.toString()} with class ${e.contractClassId.toString()} to public execution contract cache`,
57
53
  );
@@ -73,9 +69,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
73
69
  ContractClassRegisteredEvent.fromLogs(logs, ClassRegistererAddress).forEach(e =>
74
70
  this.classCache.delete(e.contractClassId.toString()),
75
71
  );
76
- ContractInstanceDeployedEvent.fromLogs(logs, InstanceDeployerAddress).forEach(e =>
77
- this.instanceCache.delete(e.address.toString()),
78
- );
72
+ ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => this.instanceCache.delete(e.address.toString()));
79
73
  return Promise.resolve();
80
74
  }
81
75
 
@@ -83,46 +77,25 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
83
77
  return this.instanceCache.get(address.toString()) ?? (await this.db.getContract(address));
84
78
  }
85
79
 
86
- async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise<Buffer | undefined> {
87
- const contract = await this.#getContract(address);
88
- return contract?.getPublicFunction(selector)?.bytecode;
80
+ public async getContractClass(contractClassId: Fr): Promise<ContractClassPublic | undefined> {
81
+ return this.classCache.get(contractClassId.toString()) ?? (await this.db.getContractClass(contractClassId));
89
82
  }
90
83
 
91
- async getIsInternal(address: AztecAddress, selector: FunctionSelector): Promise<boolean | undefined> {
92
- const contract = await this.#getContract(address);
93
- return contract?.getPublicFunction(selector)?.isInternal;
94
- }
95
-
96
- async getPortalContractAddress(address: AztecAddress): Promise<EthAddress | undefined> {
97
- const contract = await this.#getContract(address);
98
- return contract?.contractData.portalContractAddress;
99
- }
100
-
101
- async #getContract(address: AztecAddress): Promise<ExtendedContractData | undefined> {
102
- return (
103
- this.cache.get(address.toString()) ??
104
- (await this.#makeExtendedContractDataFor(address)) ??
105
- (await this.db.getExtendedContractData(address))
106
- );
107
- }
108
-
109
- async #makeExtendedContractDataFor(address: AztecAddress): Promise<ExtendedContractData | undefined> {
110
- const instance = this.instanceCache.get(address.toString());
84
+ async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise<Buffer | undefined> {
85
+ const instance = await this.getContractInstance(address);
111
86
  if (!instance) {
112
- return undefined;
87
+ throw new Error(`Contract ${address.toString()} not found`);
113
88
  }
114
-
115
- const contractClass =
116
- this.classCache.get(instance.contractClassId.toString()) ??
117
- (await this.db.getContractClass(instance.contractClassId));
89
+ const contractClass = await this.getContractClass(instance.contractClassId);
118
90
  if (!contractClass) {
119
- this.log.warn(
120
- `Contract class ${instance.contractClassId.toString()} for address ${address.toString()} not found`,
121
- );
122
- return undefined;
91
+ throw new Error(`Contract class ${instance.contractClassId.toString()} for ${address.toString()} not found`);
123
92
  }
93
+ return contractClass.publicFunctions.find(f => f.selector.equals(selector))?.bytecode;
94
+ }
124
95
 
125
- return ExtendedContractData.fromClassAndInstance(contractClass, instance);
96
+ async getPortalContractAddress(address: AztecAddress): Promise<EthAddress | undefined> {
97
+ const contract = await this.getContractInstance(address);
98
+ return contract?.portalContractAddress;
126
99
  }
127
100
  }
128
101