@aztec/txe 0.71.0 → 0.73.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.
@@ -2,7 +2,8 @@ import { createLogger } from '@aztec/aztec.js';
2
2
  import {
3
3
  type AztecNode,
4
4
  type EpochProofQuote,
5
- type GetUnencryptedLogsResponse,
5
+ type GetContractClassLogsResponse,
6
+ type GetPublicLogsResponse,
6
7
  type InBlock,
7
8
  type L2Block,
8
9
  L2BlockHash,
@@ -10,6 +11,8 @@ import {
10
11
  type L2Tips,
11
12
  type LogFilter,
12
13
  type MerkleTreeId,
14
+ type MerkleTreeReadOperations,
15
+ type MerkleTreeWriteOperations,
13
16
  type NullifierMembershipWitness,
14
17
  type ProverConfig,
15
18
  type PublicDataWitness,
@@ -22,7 +25,6 @@ import {
22
25
  TxReceipt,
23
26
  TxScopedL2Log,
24
27
  type TxValidationResult,
25
- type UnencryptedL2Log,
26
28
  } from '@aztec/circuit-types';
27
29
  import {
28
30
  type ARCHIVE_HEIGHT,
@@ -36,13 +38,15 @@ import {
36
38
  type NULLIFIER_TREE_HEIGHT,
37
39
  type NodeInfo,
38
40
  type PUBLIC_DATA_TREE_HEIGHT,
41
+ PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
39
42
  type PrivateLog,
40
43
  type ProtocolContractAddresses,
44
+ type PublicLog,
41
45
  } from '@aztec/circuits.js';
42
46
  import { type L1ContractAddresses } from '@aztec/ethereum';
43
47
  import { poseidon2Hash } from '@aztec/foundation/crypto';
44
48
  import { Fr } from '@aztec/foundation/fields';
45
- import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state';
49
+ import { type NativeWorldStateService } from '@aztec/world-state';
46
50
 
47
51
  export class TXENode implements AztecNode {
48
52
  #logsByTags = new Map<string, TxScopedL2Log[]>();
@@ -57,7 +61,8 @@ export class TXENode implements AztecNode {
57
61
  private blockNumber: number,
58
62
  private version: number,
59
63
  private chainId: number,
60
- private trees: MerkleTrees,
64
+ private nativeWorldStateService: NativeWorldStateService,
65
+ private baseFork: MerkleTreeWriteOperations,
61
66
  ) {}
62
67
 
63
68
  /**
@@ -93,10 +98,10 @@ export class TXENode implements AztecNode {
93
98
  * @param txHash - The transaction hash of the transaction.
94
99
  * @param effect - The tx effect to set.
95
100
  */
96
- setTxEffect(blockNumber: number, txHash: TxHash, effect: TxEffect) {
101
+ async setTxEffect(blockNumber: number, txHash: TxHash, effect: TxEffect) {
97
102
  // We are not creating real blocks on which membership proofs can be constructed - we instead define its hash as
98
103
  // simply the hash of the block number.
99
- const blockHash = poseidon2Hash([blockNumber]);
104
+ const blockHash = await poseidon2Hash([blockNumber]);
100
105
 
101
106
  this.#txEffectsByTxHash.set(txHash.toString(), {
102
107
  l2BlockHash: blockHash.toString(),
@@ -192,45 +197,46 @@ export class TXENode implements AztecNode {
192
197
  /**
193
198
  * Adds public logs to the txe node, given a block
194
199
  * @param blockNumber - The block number at which to add the public logs.
195
- * @param privateLogs - The unencrypted logs to be added.
196
- */
197
- addPublicLogsByTags(blockNumber: number, unencryptedLogs: UnencryptedL2Log[]) {
198
- unencryptedLogs.forEach(log => {
199
- if (log.data.length < 32 * 33) {
200
- // TODO remove when #9835 and #9836 are fixed
201
- this.#logger.warn(`Skipping unencrypted log with insufficient data length: ${log.data.length}`);
200
+ * @param publicLogs - The public logs to be added.
201
+ */
202
+ addPublicLogsByTags(blockNumber: number, publicLogs: PublicLog[]) {
203
+ publicLogs.forEach(log => {
204
+ // Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
205
+ const firstFieldBuf = log.log[0].toBuffer();
206
+ // See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
207
+ // Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
208
+ if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
209
+ // See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
210
+ // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
211
+ this.#logger.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
202
212
  return;
203
213
  }
204
- try {
205
- // TODO remove when #9835 and #9836 are fixed. The partial note logs are emitted as bytes, but encoded as Fields.
206
- // This means that for every 32 bytes of payload, we only have 1 byte of data.
207
- // Also, the tag is not stored in the first 32 bytes of the log, (that's the length of public fields now) but in the next 32.
208
- const correctedBuffer = Buffer.alloc(32);
209
- const initialOffset = 32;
210
- for (let i = 0; i < 32; i++) {
211
- const byte = Fr.fromBuffer(log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset)).toNumber();
212
- correctedBuffer.writeUInt8(byte, i);
213
- }
214
- const tag = new Fr(correctedBuffer);
215
-
216
- this.#logger.verbose(
217
- `Found tagged unencrypted log with tag ${tag.toString()} in block ${this.getBlockNumber()}`,
218
- );
219
-
220
- const currentLogs = this.#logsByTags.get(tag.toString()) ?? [];
221
- const scopedLog = new TxScopedL2Log(
222
- new TxHash(new Fr(blockNumber)),
223
- this.#noteIndex,
224
- blockNumber,
225
- true,
226
- log.toBuffer(),
227
- );
228
-
229
- currentLogs.push(scopedLog);
230
- this.#logsByTags.set(tag.toString(), currentLogs);
231
- } catch (err) {
232
- this.#logger.warn(`Failed to add tagged log to store: ${err}`);
214
+ // Check that the length values line up with the log contents
215
+ const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
216
+ const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
217
+ // Add 1 for the first field holding lengths
218
+ const totalLogLength = 1 + publicValuesLength + privateValuesLength;
219
+ // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
220
+ if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
221
+ this.#logger.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
222
+ return;
233
223
  }
224
+ // The first elt stores lengths => tag is in fields[1]
225
+ const tag = log.log[1];
226
+
227
+ this.#logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.getBlockNumber()}`);
228
+
229
+ const currentLogs = this.#logsByTags.get(tag.toString()) ?? [];
230
+ const scopedLog = new TxScopedL2Log(
231
+ new TxHash(new Fr(blockNumber)),
232
+ this.#noteIndex,
233
+ blockNumber,
234
+ true,
235
+ log.toBuffer(),
236
+ );
237
+
238
+ currentLogs.push(scopedLog);
239
+ this.#logsByTags.set(tag.toString(), currentLogs);
234
240
  });
235
241
  }
236
242
  /**
@@ -268,14 +274,11 @@ export class TXENode implements AztecNode {
268
274
  // hold a reference to them.
269
275
  // We should likely migrate this so that the trees are owned by the node.
270
276
 
271
- if (blockNumber == 'latest') {
272
- blockNumber = await this.getBlockNumber();
273
- }
274
-
275
- const db =
276
- blockNumber === (await this.getBlockNumber())
277
- ? await this.trees.getLatest()
278
- : new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
277
+ // TODO: blockNumber is being passed as undefined, figure out why
278
+ const db: MerkleTreeReadOperations =
279
+ blockNumber === (await this.getBlockNumber()) || blockNumber === 'latest' || blockNumber === undefined
280
+ ? this.baseFork
281
+ : this.nativeWorldStateService.getSnapshot(blockNumber);
279
282
 
280
283
  return await db.findLeafIndices(
281
284
  treeId,
@@ -497,12 +500,12 @@ export class TXENode implements AztecNode {
497
500
  }
498
501
 
499
502
  /**
500
- * Gets unencrypted logs based on the provided filter.
503
+ * Gets public logs based on the provided filter.
501
504
  * @param filter - The filter to apply to the logs.
502
505
  * @returns The requested logs.
503
506
  */
504
- getUnencryptedLogs(_filter: LogFilter): Promise<GetUnencryptedLogsResponse> {
505
- throw new Error('TXE Node method getUnencryptedLogs not implemented');
507
+ getPublicLogs(_filter: LogFilter): Promise<GetPublicLogsResponse> {
508
+ throw new Error('TXE Node method getPublicLogs not implemented');
506
509
  }
507
510
 
508
511
  /**
@@ -510,7 +513,7 @@ export class TXENode implements AztecNode {
510
513
  * @param filter - The filter to apply to the logs.
511
514
  * @returns The requested logs.
512
515
  */
513
- getContractClassLogs(_filter: LogFilter): Promise<GetUnencryptedLogsResponse> {
516
+ getContractClassLogs(_filter: LogFilter): Promise<GetContractClassLogsResponse> {
514
517
  throw new Error('TXE Node method getContractClassLogs not implemented');
515
518
  }
516
519