@aztec/txe 0.80.0 → 0.82.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.
@@ -1,4 +1,4 @@
1
- import { type ContractInstanceWithAddress, Fr } from '@aztec/aztec.js';
1
+ import { type ContractInstanceWithAddress, Fr, Point } from '@aztec/aztec.js';
2
2
  import { DEPLOYER_CONTRACT_ADDRESS } from '@aztec/constants';
3
3
  import type { Logger } from '@aztec/foundation/log';
4
4
  import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
@@ -11,6 +11,7 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address';
11
11
  import { computePartialAddress } from '@aztec/stdlib/contract';
12
12
  import { SimulationError } from '@aztec/stdlib/errors';
13
13
  import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/stdlib/hash';
14
+ import { LogWithTxData } from '@aztec/stdlib/logs';
14
15
  import { MerkleTreeId } from '@aztec/stdlib/trees';
15
16
 
16
17
  import { TXE } from '../oracle/txe_oracle.js';
@@ -23,9 +24,11 @@ import {
23
24
  fromArray,
24
25
  fromSingle,
25
26
  fromUintArray,
27
+ fromUintBoundedVec,
26
28
  toArray,
27
29
  toForeignCallResult,
28
30
  toSingle,
31
+ toSingleOrArray,
29
32
  } from '../util/encoding.js';
30
33
  import { ExpectedFailureError } from '../util/expected_failure_error.js';
31
34
 
@@ -260,15 +263,15 @@ export class TXEService {
260
263
  return toForeignCallResult([toArray(newValues)]);
261
264
  }
262
265
 
263
- async getPublicDataTreeWitness(blockNumber: ForeignCallSingle, leafSlot: ForeignCallSingle) {
266
+ async getPublicDataWitness(blockNumber: ForeignCallSingle, leafSlot: ForeignCallSingle) {
264
267
  const parsedBlockNumber = fromSingle(blockNumber).toNumber();
265
268
  const parsedLeafSlot = fromSingle(leafSlot);
266
269
 
267
- const witness = await this.typedOracle.getPublicDataTreeWitness(parsedBlockNumber, parsedLeafSlot);
270
+ const witness = await this.typedOracle.getPublicDataWitness(parsedBlockNumber, parsedLeafSlot);
268
271
  if (!witness) {
269
272
  throw new Error(`Public data witness not found for slot ${parsedLeafSlot} at block ${parsedBlockNumber}.`);
270
273
  }
271
- return toForeignCallResult([toArray(witness.toFields())]);
274
+ return toForeignCallResult(witness.toNoirRepresentation());
272
275
  }
273
276
 
274
277
  async getNotes(
@@ -346,7 +349,7 @@ export class TXEService {
346
349
  fromSingle(noteHash),
347
350
  fromSingle(counter).toNumber(),
348
351
  );
349
- return toForeignCallResult([toSingle(new Fr(0))]);
352
+ return toForeignCallResult([]);
350
353
  }
351
354
 
352
355
  async notifyNullifiedNote(
@@ -359,12 +362,12 @@ export class TXEService {
359
362
  fromSingle(noteHash),
360
363
  fromSingle(counter).toNumber(),
361
364
  );
362
- return toForeignCallResult([toSingle(new Fr(0))]);
365
+ return toForeignCallResult([]);
363
366
  }
364
367
 
365
368
  async notifyCreatedNullifier(innerNullifier: ForeignCallSingle) {
366
369
  await this.typedOracle.notifyCreatedNullifier(fromSingle(innerNullifier));
367
- return toForeignCallResult([toSingle(new Fr(0))]);
370
+ return toForeignCallResult([]);
368
371
  }
369
372
 
370
373
  async checkNullifierExists(innerNullifier: ForeignCallSingle) {
@@ -374,15 +377,15 @@ export class TXEService {
374
377
 
375
378
  async getContractInstance(address: ForeignCallSingle) {
376
379
  const instance = await this.typedOracle.getContractInstance(addressFromSingle(address));
377
- return toForeignCallResult([
378
- toArray([
380
+ return toForeignCallResult(
381
+ [
379
382
  instance.salt,
380
383
  instance.deployer.toField(),
381
384
  instance.currentContractClassId,
382
385
  instance.initializationHash,
383
386
  ...instance.publicKeys.toFields(),
384
- ]),
385
- ]);
387
+ ].map(toSingle),
388
+ );
386
389
  }
387
390
 
388
391
  async getPublicKeysAndPartialAddress(address: ForeignCallSingle) {
@@ -393,7 +396,7 @@ export class TXEService {
393
396
 
394
397
  async getKeyValidationRequest(pkMHash: ForeignCallSingle) {
395
398
  const keyValidationRequest = await this.typedOracle.getKeyValidationRequest(fromSingle(pkMHash));
396
- return toForeignCallResult([toArray(keyValidationRequest.toFields())]);
399
+ return toForeignCallResult(keyValidationRequest.toFields().map(toSingle));
397
400
  }
398
401
 
399
402
  async callPrivateFunction(
@@ -419,7 +422,7 @@ export class TXEService {
419
422
  if (!witness) {
420
423
  throw new Error(`Nullifier membership witness not found at block ${parsedBlockNumber}.`);
421
424
  }
422
- return toForeignCallResult([toArray(witness.toFields())]);
425
+ return toForeignCallResult(witness.toNoirRepresentation());
423
426
  }
424
427
 
425
428
  async getAuthWitness(messageHash: ForeignCallSingle) {
@@ -482,7 +485,7 @@ export class TXEService {
482
485
  if (!header) {
483
486
  throw new Error(`Block header not found for block ${blockNumber}.`);
484
487
  }
485
- return toForeignCallResult([toArray(header.toFields())]);
488
+ return toForeignCallResult(header.toFields().map(toSingle));
486
489
  }
487
490
 
488
491
  async getMembershipWitness(blockNumber: ForeignCallSingle, treeId: ForeignCallSingle, leafValue: ForeignCallSingle) {
@@ -495,7 +498,7 @@ export class TXEService {
495
498
  `Membership witness in tree ${MerkleTreeId[parsedTreeId]} not found for value ${parsedLeafValue} at block ${parsedBlockNumber}.`,
496
499
  );
497
500
  }
498
- return toForeignCallResult([toArray(witness)]);
501
+ return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
499
502
  }
500
503
 
501
504
  async getLowNullifierMembershipWitness(blockNumber: ForeignCallSingle, nullifier: ForeignCallSingle) {
@@ -505,7 +508,7 @@ export class TXEService {
505
508
  if (!witness) {
506
509
  throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${parsedBlockNumber}.`);
507
510
  }
508
- return toForeignCallResult([toArray(witness.toFields())]);
511
+ return toForeignCallResult(witness.toNoirRepresentation());
509
512
  }
510
513
 
511
514
  async getIndexedTaggingSecretAsSender(sender: ForeignCallSingle, recipient: ForeignCallSingle) {
@@ -521,6 +524,42 @@ export class TXEService {
521
524
  return toForeignCallResult([]);
522
525
  }
523
526
 
527
+ public async deliverNote(
528
+ contractAddress: ForeignCallSingle,
529
+ storageSlot: ForeignCallSingle,
530
+ nonce: ForeignCallSingle,
531
+ content: ForeignCallArray,
532
+ contentLength: ForeignCallSingle,
533
+ noteHash: ForeignCallSingle,
534
+ nullifier: ForeignCallSingle,
535
+ txHash: ForeignCallSingle,
536
+ recipient: ForeignCallSingle,
537
+ ) {
538
+ await this.typedOracle.deliverNote(
539
+ AztecAddress.fromField(fromSingle(contractAddress)),
540
+ fromSingle(storageSlot),
541
+ fromSingle(nonce),
542
+ fromArray(content.slice(0, Number(BigInt(contentLength)))),
543
+ fromSingle(noteHash),
544
+ fromSingle(nullifier),
545
+ fromSingle(txHash),
546
+ AztecAddress.fromField(fromSingle(recipient)),
547
+ );
548
+
549
+ return toForeignCallResult([toSingle(Fr.ONE)]);
550
+ }
551
+
552
+ async getLogByTag(tag: ForeignCallSingle) {
553
+ // TODO(AD): this was warning that getLogByTag did not return a promise.
554
+ const log = await Promise.resolve(this.typedOracle.getLogByTag(fromSingle(tag)));
555
+
556
+ if (log == null) {
557
+ return toForeignCallResult([toSingle(Fr.ZERO), ...LogWithTxData.noirSerializationOfEmpty().map(toSingleOrArray)]);
558
+ } else {
559
+ return toForeignCallResult([toSingle(Fr.ONE), ...log.toNoirSerialization().map(toSingleOrArray)]);
560
+ }
561
+ }
562
+
524
563
  async storeCapsule(contractAddress: ForeignCallSingle, slot: ForeignCallSingle, capsule: ForeignCallArray) {
525
564
  await this.typedOracle.storeCapsule(
526
565
  AztecAddress.fromField(fromSingle(contractAddress)),
@@ -567,15 +606,31 @@ export class TXEService {
567
606
  return toForeignCallResult([]);
568
607
  }
569
608
 
570
- // TODO: I forgot to add a corresponding function here, when I introduced an oracle method to txe_oracle.ts. The compiler didn't throw an error, so it took me a while to learn of the existence of this file, and that I need to implement this function here. Isn't there a way to programmatically identify that this is missing, given the existence of a txe_oracle method?
571
- async aes128Decrypt(ciphertext: ForeignCallArray, iv: ForeignCallArray, symKey: ForeignCallArray) {
572
- const ciphertextBuffer = fromUintArray(ciphertext, 8);
609
+ // TODO: I forgot to add a corresponding function here, when I introduced an oracle method to txe_oracle.ts.
610
+ // The compiler didn't throw an error, so it took me a while to learn of the existence of this file, and that I need
611
+ // to implement this function here. Isn't there a way to programmatically identify that this is missing, given the
612
+ // existence of a txe_oracle method?
613
+ async aes128Decrypt(
614
+ ciphertextBVecStorage: ForeignCallArray,
615
+ ciphertextLength: ForeignCallSingle,
616
+ iv: ForeignCallArray,
617
+ symKey: ForeignCallArray,
618
+ ) {
619
+ const ciphertext = fromUintBoundedVec(ciphertextBVecStorage, ciphertextLength, 8);
573
620
  const ivBuffer = fromUintArray(iv, 8);
574
621
  const symKeyBuffer = fromUintArray(symKey, 8);
575
622
 
576
- const plaintextBuffer = await this.typedOracle.aes128Decrypt(ciphertextBuffer, ivBuffer, symKeyBuffer);
623
+ const plaintextBuffer = await this.typedOracle.aes128Decrypt(ciphertext, ivBuffer, symKeyBuffer);
577
624
 
578
- return toForeignCallResult(arrayToBoundedVec(bufferToU8Array(plaintextBuffer), ciphertextBuffer.length));
625
+ return toForeignCallResult(arrayToBoundedVec(bufferToU8Array(plaintextBuffer), ciphertextBVecStorage.length));
626
+ }
627
+
628
+ async getSharedSecret(address: ForeignCallSingle, ephPk: ForeignCallArray) {
629
+ const secret = await this.typedOracle.getSharedSecret(
630
+ AztecAddress.fromField(fromSingle(address)),
631
+ Point.fromFields(fromArray(ephPk)),
632
+ );
633
+ return toForeignCallResult(secret.toFields().map(toSingle));
579
634
  }
580
635
 
581
636
  // AVM opcodes
@@ -31,7 +31,7 @@ export function fromArray(obj: ForeignCallArray) {
31
31
  /**
32
32
  * Converts an array of Noir unsigned integers to a single tightly-packed buffer.
33
33
  * @param uintBitSize If it's an array of Noir u8's, put `8`, etc.
34
- * @returns
34
+ * @returns A buffer where each byte is correctly represented as a single byte in the buffer.
35
35
  */
36
36
  export function fromUintArray(obj: ForeignCallArray, uintBitSize: number): Buffer {
37
37
  if (uintBitSize % 8 !== 0) {
@@ -41,6 +41,24 @@ export function fromUintArray(obj: ForeignCallArray, uintBitSize: number): Buffe
41
41
  return Buffer.concat(obj.map(str => hexToBuffer(str).slice(-uintByteSize)));
42
42
  }
43
43
 
44
+ /**
45
+ * Converts a Noir BoundedVec of unsigned integers into a Buffer. Note that BoundedVecs are structs, and therefore
46
+ * translated as two separate ForeignCallArray and ForeignCallSingle values (an array and a single field).
47
+ *
48
+ * @param storage The array with the BoundedVec's storage (i.e. BoundedVec::storage())
49
+ * @param length The length of the BoundedVec (i.e. BoundedVec::len())
50
+ * @param uintBitSize If it's an array of Noir u8's, put `8`, etc.
51
+ * @returns A buffer containing the unsigned integers tightly packed
52
+ */
53
+ export function fromUintBoundedVec(storage: ForeignCallArray, length: ForeignCallSingle, uintBitSize: number): Buffer {
54
+ if (uintBitSize % 8 !== 0) {
55
+ throw new Error(`u${uintBitSize} is not a supported type in Noir`);
56
+ }
57
+ const uintByteSize = uintBitSize / 8;
58
+ const boundedStorage = storage.slice(0, fromSingle(length).toNumber());
59
+ return Buffer.concat(boundedStorage.map(str => hexToBuffer(str).slice(-uintByteSize)));
60
+ }
61
+
44
62
  export function toSingle(obj: Fr | AztecAddress): ForeignCallSingle {
45
63
  return obj.toString().slice(2);
46
64
  }
@@ -49,6 +67,10 @@ export function toArray(objs: Fr[]): ForeignCallArray {
49
67
  return objs.map(obj => obj.toString());
50
68
  }
51
69
 
70
+ export function toSingleOrArray(value: Fr | Fr[]) {
71
+ return Array.isArray(value) ? value.map(toSingle) : toSingle(value);
72
+ }
73
+
52
74
  export function bufferToU8Array(buffer: Buffer): ForeignCallArray {
53
75
  return toArray(Array.from(buffer).map(byte => new Fr(byte)));
54
76
  }
@@ -57,21 +79,24 @@ export function bufferToU8Array(buffer: Buffer): ForeignCallArray {
57
79
  * Converts a ForeignCallArray into a tuple which represents a nr BoundedVec.
58
80
  * If the input array is shorter than the maxLen, it pads the result with zeros,
59
81
  * so that nr can correctly coerce this result into a BoundedVec.
60
- * @param array
82
+ * @param bVecStorage - The array underlying the BoundedVec.
61
83
  * @param maxLen - the max length of the BoundedVec.
62
84
  * @returns a tuple representing a BoundedVec.
63
85
  */
64
- export function arrayToBoundedVec(array: ForeignCallArray, maxLen: number): [ForeignCallArray, ForeignCallSingle] {
65
- if (array.length > maxLen) {
66
- throw new Error(`Array of length ${array.length} larger than maxLen ${maxLen}`);
86
+ export function arrayToBoundedVec(
87
+ bVecStorage: ForeignCallArray,
88
+ maxLen: number,
89
+ ): [ForeignCallArray, ForeignCallSingle] {
90
+ if (bVecStorage.length > maxLen) {
91
+ throw new Error(`Array of length ${bVecStorage.length} larger than maxLen ${maxLen}`);
67
92
  }
68
- const lengthDiff = maxLen - array.length;
93
+ const lengthDiff = maxLen - bVecStorage.length;
69
94
  // We pad the array to the maxLen of the BoundedVec.
70
95
  const zeroPaddingArray = toArray(Array(lengthDiff).fill(new Fr(0)));
71
96
 
72
97
  // These variable names match with the BoundedVec members in nr:
73
- const storage = array.concat(zeroPaddingArray);
74
- const len = toSingle(new Fr(array.length));
98
+ const storage = bVecStorage.concat(zeroPaddingArray);
99
+ const len = toSingle(new Fr(bVecStorage.length));
75
100
  return [storage, len];
76
101
  }
77
102
 
@@ -16,14 +16,6 @@ import type { TXE } from '../oracle/txe_oracle.js';
16
16
  export class TXEPublicContractDataSource implements ContractDataSource {
17
17
  constructor(private txeOracle: TXE) {}
18
18
 
19
- async getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise<PublicFunction | undefined> {
20
- const bytecode = await this.txeOracle.getContractDataProvider().getBytecode(address, selector);
21
- if (!bytecode) {
22
- return undefined;
23
- }
24
- return { bytecode, selector };
25
- }
26
-
27
19
  getBlockNumber(): Promise<number> {
28
20
  return this.txeOracle.getBlockNumber();
29
21
  }
@@ -92,10 +84,4 @@ export class TXEPublicContractDataSource implements ContractDataSource {
92
84
  registerContractFunctionSignatures(_address: AztecAddress, _signatures: []): Promise<void> {
93
85
  return Promise.resolve();
94
86
  }
95
-
96
- // TODO(#10007): Remove this method.
97
- addContractClass(_contractClass: ContractClassPublic): Promise<void> {
98
- // We don't really need to do anything for the txe here
99
- return Promise.resolve();
100
- }
101
87
  }
@@ -1,17 +1,16 @@
1
1
  import { Fr } from '@aztec/foundation/fields';
2
- import { WorldStateDB } from '@aztec/simulator/server';
2
+ import { PublicTreesDB } from '@aztec/simulator/server';
3
3
  import { PublicDataWrite } from '@aztec/stdlib/avm';
4
4
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
- import type { ContractDataSource } from '@aztec/stdlib/contract';
6
5
  import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
7
6
  import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
8
7
  import { MerkleTreeId, type PublicDataTreeLeafPreimage } from '@aztec/stdlib/trees';
9
8
 
10
9
  import type { TXE } from '../oracle/txe_oracle.js';
11
10
 
12
- export class TXEWorldStateDB extends WorldStateDB {
13
- constructor(private merkleDb: MerkleTreeWriteOperations, dataSource: ContractDataSource, private txe: TXE) {
14
- super(merkleDb, dataSource);
11
+ export class TXEPublicTreesDB extends PublicTreesDB {
12
+ constructor(private merkleDb: MerkleTreeWriteOperations, private txe: TXE) {
13
+ super(merkleDb);
15
14
  }
16
15
 
17
16
  override async storageRead(contract: AztecAddress, slot: Fr): Promise<Fr> {
@@ -1 +0,0 @@
1
- {"version":3,"file":"txe_world_state_db.d.ts","sourceRoot":"","sources":["../../src/util/txe_world_state_db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAGjF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAEnD,qBAAa,eAAgB,SAAQ,YAAY;IACnC,OAAO,CAAC,QAAQ;IAA6D,OAAO,CAAC,GAAG;gBAAhF,QAAQ,EAAE,yBAAyB,EAAE,UAAU,EAAE,kBAAkB,EAAU,GAAG,EAAE,GAAG;IAI1F,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;IAgB1D,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAK3F"}