diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 49f54a2dc30e..20df384448f8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,7 @@ { - ".": "0.76.1" + ".": "0.76.2", + "yarn-project/cli": "0.35.1", + "yarn-project/aztec": "0.76.2", + "barretenberg": "0.76.2", + "barretenberg/ts": "0.76.2" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f79f0ad4e10..4a7c1f53993f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # Changelog +## [0.76.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.76.1...aztec-packages-v0.76.2) (2025-02-11) + + +### Features + +* Batch writes to the proving broker database ([#11900](https://github.com/AztecProtocol/aztec-packages/issues/11900)) ([608f887](https://github.com/AztecProtocol/aztec-packages/commit/608f8876a0f4209970ea27679dff6029aab0600c)) + + +### Bug Fixes + +* Cleanup also post test_kind.sh ([#11886](https://github.com/AztecProtocol/aztec-packages/issues/11886)) ([50cdb15](https://github.com/AztecProtocol/aztec-packages/commit/50cdb15c2664a8786336654be402cf8b7b56117b)) +* Contracts with public keys txe ([#11910](https://github.com/AztecProtocol/aztec-packages/issues/11910)) ([2e84bdb](https://github.com/AztecProtocol/aztec-packages/commit/2e84bdb1bb8bc815dfc5fb65b5a6e68e12b7efa9)) +* Dont skip wasm civc tests ([#11909](https://github.com/AztecProtocol/aztec-packages/issues/11909)) ([0395e0b](https://github.com/AztecProtocol/aztec-packages/commit/0395e0bf0c7a82e4506657f508e8f3324bdc56ab)) +* Note hash collision ([#11869](https://github.com/AztecProtocol/aztec-packages/issues/11869)) ([f289b7c](https://github.com/AztecProtocol/aztec-packages/commit/f289b7c038d399c30e17bc27a620860792416b9f)) +* Orchestrator test ([#11901](https://github.com/AztecProtocol/aztec-packages/issues/11901)) ([f1bb51c](https://github.com/AztecProtocol/aztec-packages/commit/f1bb51c9bb6063d52bfd2dafe5faf9476b4bbff0)) +* Smt_verification: negative bitvecs, changed gates indicies. acir_formal_proofs: noir-style signed division ([#11649](https://github.com/AztecProtocol/aztec-packages/issues/11649)) ([4146496](https://github.com/AztecProtocol/aztec-packages/commit/41464968895be2ae0bfc9a0a554a3b6824252fd4)) +* Update path of stern logs ([#11906](https://github.com/AztecProtocol/aztec-packages/issues/11906)) ([05afb5b](https://github.com/AztecProtocol/aztec-packages/commit/05afb5bc763a26b41ce4e8c6253ffba5d20bc1fa)) + + +### Miscellaneous + +* Arm runner start fix ([#11903](https://github.com/AztecProtocol/aztec-packages/issues/11903)) ([6c83c40](https://github.com/AztecProtocol/aztec-packages/commit/6c83c40f09dd9550af426047c300c9f19469409d)) +* Fixing the sizes of VMs in CIVC ([#11793](https://github.com/AztecProtocol/aztec-packages/issues/11793)) ([1afddbd](https://github.com/AztecProtocol/aztec-packages/commit/1afddbd0712ad268bcc82931cf91bbb067766cbe)) +* **logging:** Support explicit FORCE_COLOR parameter ([#11902](https://github.com/AztecProtocol/aztec-packages/issues/11902)) ([3b3f859](https://github.com/AztecProtocol/aztec-packages/commit/3b3f859f53bba6aa5cabf9f79dd210d326045e70)) +* Misc fixes to devnet deploy flow ([#11738](https://github.com/AztecProtocol/aztec-packages/issues/11738)) ([bc4cca7](https://github.com/AztecProtocol/aztec-packages/commit/bc4cca7fe87afc72c38f6a7bf9af5e11149b6d84)) +* Remove warnings from noir protocol circuits ([#11803](https://github.com/AztecProtocol/aztec-packages/issues/11803)) ([c6cc3d3](https://github.com/AztecProtocol/aztec-packages/commit/c6cc3d381253f79d3532c2940f73a9304665f4d4)) +* Replace relative paths to noir-protocol-circuits ([74d6e6a](https://github.com/AztecProtocol/aztec-packages/commit/74d6e6a14b13dbc3cb9f691c1ec40be5e898a6fb)) +* Replacing use of capsules 1.0 with pxe_db + nuking capsules 1.0 ([#11885](https://github.com/AztecProtocol/aztec-packages/issues/11885)) ([72be678](https://github.com/AztecProtocol/aztec-packages/commit/72be67811ebe3b4db0cc245352e5e8e975828578)) + ## [0.76.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.76.0...aztec-packages-v0.76.1) (2025-02-10) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index f6ba6bab53d0..7db3ab75a791 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [0.76.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.76.1...barretenberg-v0.76.2) (2025-02-11) + + +### Bug Fixes + +* Note hash collision ([#11869](https://github.com/AztecProtocol/aztec-packages/issues/11869)) ([f289b7c](https://github.com/AztecProtocol/aztec-packages/commit/f289b7c038d399c30e17bc27a620860792416b9f)) +* Smt_verification: negative bitvecs, changed gates indicies. acir_formal_proofs: noir-style signed division ([#11649](https://github.com/AztecProtocol/aztec-packages/issues/11649)) ([4146496](https://github.com/AztecProtocol/aztec-packages/commit/41464968895be2ae0bfc9a0a554a3b6824252fd4)) + + +### Miscellaneous + +* Fixing the sizes of VMs in CIVC ([#11793](https://github.com/AztecProtocol/aztec-packages/issues/11793)) ([1afddbd](https://github.com/AztecProtocol/aztec-packages/commit/1afddbd0712ad268bcc82931cf91bbb067766cbe)) + ## [0.76.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.76.0...barretenberg-v0.76.1) (2025-02-10) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 19334c877f81..aa749075bed2 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,6 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - # Placeholder version. VERSION 00000000.00000000.00000000 LANGUAGES CXX C ) diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index 1dcc350d68f7..617879ea04d2 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.76.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.76.1...barretenberg.js-v0.76.2) (2025-02-11) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.76.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.76.0...barretenberg.js-v0.76.1) (2025-02-10) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 864fac6da1ae..a0c9ebf0e2c8 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,7 +1,7 @@ { "name": "@aztec/bb.js", "packageManager": "yarn@4.5.2", - "version": "0.76.1", + "version": "0.76.2", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/barretenberg/ts/src/bigint-array/index.ts b/barretenberg/ts/src/bigint-array/index.ts index c315c0758d5a..58aa9c3668d7 100644 --- a/barretenberg/ts/src/bigint-array/index.ts +++ b/barretenberg/ts/src/bigint-array/index.ts @@ -1,21 +1,43 @@ -export function toBigIntBE(bytes: Uint8Array) { - // A Buffer in node, *is* a Uint8Array. We can't refuse it's type. - // However the algo below only works on an actual Uint8Array, hence we make a new one to be safe. - bytes = new Uint8Array(bytes); - let bigint = BigInt(0); - const view = new DataView(bytes.buffer); - for (let i = 0; i < bytes.byteLength; i++) { - bigint = (bigint << BigInt(8)) + BigInt(view.getUint8(i)); - } - return bigint; +/** + * Convert a 32-byte BE Buffer to a BigInt. + */ +export function buffer32BytesToBigIntBE(buf: Buffer): bigint { + return ( + (buf.readBigUInt64BE(0) << 192n) + + (buf.readBigUInt64BE(8) << 128n) + + (buf.readBigUInt64BE(16) << 64n) + + buf.readBigUInt64BE(24) + ); +} + +/** + * Convert a BE Uint8Array to a BigInt. + */ +export function uint8ArrayToBigIntBE(bytes: Uint8Array): bigint { + const buffer = Buffer.from(bytes); + return buffer32BytesToBigIntBE(buffer); } -export function toBufferBE(value: bigint, byteLength = 32) { - const bytes = new Uint8Array(byteLength); - const view = new DataView(bytes.buffer); - for (let i = 0; i < byteLength; i++) { - view.setUint8(byteLength - i - 1, Number(value & BigInt(0xff))); - value >>= BigInt(8); +/** + * Convert a BigInt to a 32-byte BE Buffer. + */ +export function bigIntToBufferBE(value: bigint, byteLength = 32): Buffer { + if (byteLength != 32) { + throw new Error( + `Only 32 bytes supported for conversion from bigint to buffer, attempted byte length: ${byteLength}`, + ); } - return bytes; + const buf = Buffer.alloc(byteLength); + buf.writeBigUInt64BE(value >> 192n, 0); + buf.writeBigUInt64BE((value >> 128n) & 0xffffffffffffffffn, 8); + buf.writeBigUInt64BE((value >> 64n) & 0xffffffffffffffffn, 16); + buf.writeBigUInt64BE(value & 0xffffffffffffffffn, 24); + return buf; +} + +/** + * Convert a BigInt to a 32-byte BE Uint8Array. + */ +export function bigIntToUint8ArrayBE(value: bigint, byteLength = 32): Uint8Array { + return new Uint8Array(bigIntToBufferBE(value, byteLength)); } diff --git a/barretenberg/ts/src/types/fields.ts b/barretenberg/ts/src/types/fields.ts index ed4eec2ace0f..5b0eba2ff78e 100644 --- a/barretenberg/ts/src/types/fields.ts +++ b/barretenberg/ts/src/types/fields.ts @@ -1,5 +1,10 @@ import { randomBytes } from '../random/index.js'; -import { toBigIntBE, toBufferBE } from '../bigint-array/index.js'; +import { + buffer32BytesToBigIntBE, + uint8ArrayToBigIntBE, + bigIntToBufferBE, + bigIntToUint8ArrayBE, +} from '../bigint-array/index.js'; import { BufferReader, uint8ArrayToHexString } from '../serialize/index.js'; // TODO(#4189): Replace with implementation in yarn-project/foundation/src/fields/fields.ts @@ -15,30 +20,36 @@ export class Fr { static SIZE_IN_BYTES = 32; value: Uint8Array; - constructor(value: Uint8Array | bigint) { + constructor(value: Uint8Array | Buffer | bigint) { // We convert buffer value to bigint to be able to check it fits within modulus - const valueBigInt = typeof value === 'bigint' ? value : toBigIntBE(value); + const valueBigInt = + typeof value === 'bigint' + ? value + : value instanceof Buffer + ? buffer32BytesToBigIntBE(value) + : uint8ArrayToBigIntBE(value); if (valueBigInt > Fr.MAX_VALUE) { throw new Error(`Value 0x${valueBigInt.toString(16)} is greater or equal to field modulus.`); } - this.value = typeof value === 'bigint' ? toBufferBE(value) : value; + this.value = + typeof value === 'bigint' ? bigIntToUint8ArrayBE(value) : value instanceof Buffer ? new Uint8Array(value) : value; } static random() { - const r = toBigIntBE(randomBytes(64)) % Fr.MODULUS; + const r = uint8ArrayToBigIntBE(randomBytes(64)) % Fr.MODULUS; return new this(r); } - static fromBuffer(buffer: Uint8Array | BufferReader) { + static fromBuffer(buffer: Uint8Array | Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new this(reader.readBytes(this.SIZE_IN_BYTES)); } static fromBufferReduce(buffer: Uint8Array | BufferReader) { const reader = BufferReader.asReader(buffer); - return new this(toBigIntBE(reader.readBytes(this.SIZE_IN_BYTES)) % Fr.MODULUS); + return new this(uint8ArrayToBigIntBE(reader.readBytes(this.SIZE_IN_BYTES)) % Fr.MODULUS); } static fromString(str: string) { @@ -79,18 +90,18 @@ export class Fq { } static random() { - const r = toBigIntBE(randomBytes(64)) % Fq.MODULUS; + const r = uint8ArrayToBigIntBE(randomBytes(64)) % Fq.MODULUS; return new this(r); } - static fromBuffer(buffer: Uint8Array | BufferReader) { + static fromBuffer(buffer: Uint8Array | Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new this(toBigIntBE(reader.readBytes(this.SIZE_IN_BYTES))); + return new this(uint8ArrayToBigIntBE(reader.readBytes(this.SIZE_IN_BYTES))); } - static fromBufferReduce(buffer: Uint8Array | BufferReader) { + static fromBufferReduce(buffer: Uint8Array | Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new this(toBigIntBE(reader.readBytes(this.SIZE_IN_BYTES)) % Fr.MODULUS); + return new this(uint8ArrayToBigIntBE(reader.readBytes(this.SIZE_IN_BYTES)) % Fr.MODULUS); } static fromString(str: string) { @@ -98,7 +109,7 @@ export class Fq { } toBuffer() { - return toBufferBE(this.value, Fq.SIZE_IN_BYTES); + return bigIntToBufferBE(this.value, Fq.SIZE_IN_BYTES); } toString() { diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index b6cab7aa13b7..cd6d891ad7e0 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -1,6 +1,8 @@ // Sample escrow contract that stores a balance of a private token on behalf of an owner. use dep::aztec::macros::aztec; +mod test; + #[aztec] pub contract Escrow { use dep::aztec::{ diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/test.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/test.nr new file mode 100644 index 000000000000..ed3337a83caf --- /dev/null +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/test.nr @@ -0,0 +1,120 @@ +// TODO(ek): Clean up this test +use crate::Escrow; +use dep::token::Token; + +use aztec::{ + oracle::{execution::{get_block_number, get_contract_address}, storage::storage_read}, + prelude::AztecAddress, + protocol_types::storage::map::derive_storage_slot_in_map, + test::helpers::{cheatcodes, test_environment::TestEnvironment}, +}; + +pub unconstrained fn get_public_balance( + token_contract_address: AztecAddress, + address: AztecAddress, +) -> U128 { + let current_contract_address = get_contract_address(); + cheatcodes::set_contract_address(token_contract_address); + let block_number = get_block_number(); + + let balances_slot = Token::storage_layout().public_balances.slot; + let address_slot = derive_storage_slot_in_map(balances_slot, address); + let amount: U128 = storage_read(token_contract_address, address_slot, block_number); + cheatcodes::set_contract_address(current_contract_address); + amount +} + +pub unconstrained fn get_private_balance( + token_contract_address: AztecAddress, + address: AztecAddress, +) -> U128 { + let current_contract_address = get_contract_address(); + cheatcodes::set_contract_address(token_contract_address); + // Direct call to unconstrained + let amt = Token::balance_of_private(address); + cheatcodes::set_contract_address(current_contract_address); + amt +} + +global MINT_AMOUNT: U128 = U128::from_integer(200000); + +unconstrained fn deploy_contracts( + env: &mut TestEnvironment, + admin_and_owner: AztecAddress, +) -> (AztecAddress, AztecAddress) { + env.impersonate(admin_and_owner); + + // Deploy token contract + let donation_token_initializer_call_interface = Token::interface().constructor( + admin_and_owner, + "Token00000000000000000000000000", + "TKN0000000000000000000000000000", + 18, + ); + let donation_token_contract = env + .deploy("./@token_contract", "Token") + .with_public_void_initializer(donation_token_initializer_call_interface); + let token_contract_address = donation_token_contract.to_address(); + env.advance_block_by(1); + + // Deploy Escrow contract with public keys + let escrow_contract_initializer_call_interface = + Escrow::interface().constructor(admin_and_owner); + let escrow_contract = env + .deploy_with_public_keys("./@escrow_contract", "Escrow", 6969) + .with_private_initializer(escrow_contract_initializer_call_interface); + let escrow_contract_address = escrow_contract.to_address(); + + env.advance_block_by(1); + + Token::at(token_contract_address) + .mint_to_private(admin_and_owner, admin_and_owner, MINT_AMOUNT) + .call(&mut env.private()); + + env.advance_block_by(1); + + let private_balance_after_mint = get_private_balance(token_contract_address, admin_and_owner); + assert(private_balance_after_mint == MINT_AMOUNT); + + (token_contract_address, escrow_contract_address) +} + +#[test] +unconstrained fn main() { + let mut env = TestEnvironment::new(); + + let (account_1, account_2) = (env.create_account_contract(1), env.create_account_contract(2)); + + let (token_contract_address, escrow_contract_address) = deploy_contracts(&mut env, account_1); + + // We transfer tokens to the escrow contract + let TRANSFER_AMOUNT = U128::from_integer(20000); + Token::at(token_contract_address).transfer(escrow_contract_address, TRANSFER_AMOUNT).call( + &mut env.private(), + ); + env.advance_block_by(1); + + let balance_of_escrow_after_transfer = + get_private_balance(token_contract_address, escrow_contract_address); + + assert_eq(balance_of_escrow_after_transfer, TRANSFER_AMOUNT); + + // We then withdraw some escrowed funds to account_2 + let balance_of_account_2_before_withdrawal = + get_private_balance(token_contract_address, account_2); + assert(balance_of_account_2_before_withdrawal == U128::zero()); + + let WITHDRAWAL_AMOUNT = U128::from_integer(69); + Escrow::at(escrow_contract_address) + .withdraw(token_contract_address, WITHDRAWAL_AMOUNT, account_2) + .call(&mut env.private()); + env.advance_block_by(1); + + let balance_of_account_2_after_withdrawal = + get_private_balance(token_contract_address, account_2); + assert(balance_of_account_2_after_withdrawal == WITHDRAWAL_AMOUNT); + + let balance_of_escrow_after_withdrawal = + get_private_balance(token_contract_address, escrow_contract_address); + assert(balance_of_escrow_after_withdrawal == TRANSFER_AMOUNT - WITHDRAWAL_AMOUNT); +} diff --git a/spartan/bootstrap.sh b/spartan/bootstrap.sh index ed9630246d33..f7f32a11a4e4 100755 --- a/spartan/bootstrap.sh +++ b/spartan/bootstrap.sh @@ -76,7 +76,7 @@ case "$cmd" in # Ensure our context exists in kubectl retry "kind delete cluster || true; timeout -v 2m kind create cluster" fi - kubectl config use-context kind-kind >/dev/null || true + kubectl config use-context kind-kind || true docker update --restart=no kind-control-plane >/dev/null ;; "chaos-mesh") diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 678b75ad5b8e..51e377310378 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.76.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.76.1...aztec-package-v0.76.2) (2025-02-11) + + +### Miscellaneous + +* **logging:** Support explicit FORCE_COLOR parameter ([#11902](https://github.com/AztecProtocol/aztec-packages/issues/11902)) ([3b3f859](https://github.com/AztecProtocol/aztec-packages/commit/3b3f859f53bba6aa5cabf9f79dd210d326045e70)) + ## [0.76.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.76.0...aztec-package-v0.76.1) (2025-02-10) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index 943514deb1c8..14b707669675 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.76.1", + "version": "0.76.2", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts b/yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts index aec6a8b03726..ce175e8d1e24 100644 --- a/yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts +++ b/yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts @@ -38,7 +38,7 @@ describe('Client IVC Integration', () => { // 1. Run a mock app that creates two commitments // 2. Run the init kernel to process the app run // 3. Run the tail kernel to finish the client IVC chain. - it.skip('Should generate a verifiable client IVC proof from a simple mock tx via bb.js', async () => { + it('Should generate a verifiable client IVC proof from a simple mock tx via bb.js', async () => { const tx = { number_of_calls: '0x1', }; @@ -82,7 +82,7 @@ describe('Client IVC Integration', () => { // 4. Run the inner kernel to process the second app run // 5. Run the reset kernel to process the read request emitted by the reader app // 6. Run the tail kernel to finish the client IVC chain - it.skip('Should generate a verifiable client IVC proof from a complex mock tx', async () => { + it('Should generate a verifiable client IVC proof from a complex mock tx', async () => { const tx = { number_of_calls: '0x2', }; diff --git a/yarn-project/simulator/src/avm/avm_simulator.ts b/yarn-project/simulator/src/avm/avm_simulator.ts index f29e62e14f47..686de00cfcb6 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.ts @@ -205,7 +205,7 @@ export class AvmSimulator { const endTotalTime = performance.now(); const totalTime = endTotalTime - startTotalTime; - this.log.debug(`Total execution time: ${totalTime}ms`); + this.log.debug(`Core AVM simulation took ${totalTime}ms`); // Return results for processing by calling context return results; diff --git a/yarn-project/simulator/src/avm/avm_tree.ts b/yarn-project/simulator/src/avm/avm_tree.ts index b971da3ee4ef..9130783a810d 100644 --- a/yarn-project/simulator/src/avm/avm_tree.ts +++ b/yarn-project/simulator/src/avm/avm_tree.ts @@ -7,6 +7,21 @@ import { type IndexedTreeLeafPreimage, type TreeLeafPreimage } from '@aztec/foun import { strict as assert } from 'assert'; import cloneDeep from 'lodash.clonedeep'; +const MAX_TREE_DEPTH = 128; + +/** + * Helper function to precompute zero hashes + */ +async function preComputeZeroHashes(): Promise { + let currentHash = Fr.zero(); + const zeroHashes: Fr[] = []; + for (let i = 0; i < MAX_TREE_DEPTH; i++) { + zeroHashes.push(currentHash); + currentHash = await poseidon2Hash([currentHash, currentHash]); + } + return zeroHashes; +} + /****************************************************/ /****** Structs Used by the AvmEphemeralForest ******/ /****************************************************/ @@ -554,6 +569,8 @@ export class EphemeralAvmTree { private tree: Tree; public frontier: Fr[]; + private static precomputedZeroHashes: Fr[] | undefined; + private constructor(private root: Leaf, public leafCount: bigint, public depth: number, private zeroHashes: Fr[]) { this.tree = root; this.frontier = []; @@ -565,13 +582,12 @@ export class EphemeralAvmTree { treeDb: MerkleTreeReadOperations, merkleId: MerkleTreeId, ): Promise { - let zeroHash = Fr.zero(); - // Can probably cache this elsewhere - const zeroHashes = []; - for (let i = 0; i < depth; i++) { - zeroHashes.push(zeroHash); - zeroHash = await poseidon2Hash([zeroHash, zeroHash]); + let zeroHashes = EphemeralAvmTree.precomputedZeroHashes; + if (zeroHashes === undefined) { + zeroHashes = await preComputeZeroHashes(); + EphemeralAvmTree.precomputedZeroHashes = zeroHashes; } + const zeroHash = zeroHashes[depth]; const tree = new EphemeralAvmTree(Leaf(zeroHash), forkedLeafCount, depth, zeroHashes); await tree.initializeFrontier(treeDb, merkleId); return tree; diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index 3dd20c52eb4b..c7ed7e7b7586 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -144,16 +144,16 @@ export class AvmPersistableStateManager { * @param value - the value being written to the slot */ public async writeStorage(contractAddress: AztecAddress, slot: Fr, value: Fr, protocolWrite = false): Promise { - this.log.debug(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`); + this.log.trace(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`); const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot); - this.log.debug(`leafSlot=${leafSlot}`); + this.log.trace(`leafSlot=${leafSlot}`); // Cache storage writes for later reference/reads this.publicStorage.write(contractAddress, slot, value); if (this.doMerkleOperations) { const result = await this.merkleTrees.writePublicStorage(leafSlot, value); assert(result !== undefined, 'Public data tree insertion error. You might want to disable doMerkleOperations.'); - this.log.debug(`Inserted public data tree leaf at leafSlot ${leafSlot}, value: ${value}`); + this.log.trace(`Inserted public data tree leaf at leafSlot ${leafSlot}, value: ${value}`); const lowLeafInfo = result.lowWitness; const lowLeafPreimage = result.lowWitness.preimage as PublicDataTreeLeafPreimage; @@ -195,9 +195,9 @@ export class AvmPersistableStateManager { */ public async readStorage(contractAddress: AztecAddress, slot: Fr): Promise { const { value, cached } = await this.publicStorage.read(contractAddress, slot); - this.log.debug(`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`); + this.log.trace(`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`); const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot); - this.log.debug(`leafSlot=${leafSlot}`); + this.log.trace(`leafSlot=${leafSlot}`); if (this.doMerkleOperations) { // Get leaf if present, low leaf if absent @@ -212,8 +212,8 @@ export class AvmPersistableStateManager { const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex); const leafPreimage = preimage as PublicDataTreeLeafPreimage; - this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`); - this.log.debug( + this.log.trace(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`); + this.log.trace( `leafPreimage.nextSlot: ${leafPreimage.nextSlot}, leafPreimage.nextIndex: ${Number(leafPreimage.nextIndex)}`, ); @@ -223,7 +223,7 @@ export class AvmPersistableStateManager { `Value mismatch when performing public data read (got value: ${value}, value in ephemeral tree: ${leafPreimage.value})`, ); } else { - this.log.debug(`Slot has never been written before!`); + this.log.trace(`Slot has never been written before!`); // Sanity check that the leaf slot is skipped by low leaf when it doesn't exist assert( leafPreimage.slot.toBigInt() < leafSlot.toBigInt() && @@ -250,7 +250,7 @@ export class AvmPersistableStateManager { */ public async peekStorage(contractAddress: AztecAddress, slot: Fr): Promise { const { value, cached } = await this.publicStorage.read(contractAddress, slot); - this.log.debug(`Storage peek (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`); + this.log.trace(`Storage peek (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`); return Promise.resolve(value); } @@ -266,7 +266,7 @@ export class AvmPersistableStateManager { public async checkNoteHashExists(contractAddress: AztecAddress, noteHash: Fr, leafIndex: Fr): Promise { const gotLeafValue = (await this.worldStateDB.getCommitmentValue(leafIndex.toBigInt())) ?? Fr.ZERO; const exists = gotLeafValue.equals(noteHash); - this.log.debug( + this.log.trace( `noteHashes(${contractAddress})@${noteHash} ?? leafIndex: ${leafIndex} | gotLeafValue: ${gotLeafValue}, exists: ${exists}.`, ); if (this.doMerkleOperations) { @@ -306,7 +306,7 @@ export class AvmPersistableStateManager { * @param noteHash - the siloed unique hash to write */ public async writeUniqueNoteHash(noteHash: Fr): Promise { - this.log.debug(`noteHashes += @${noteHash}.`); + this.log.trace(`noteHashes += @${noteHash}.`); if (this.doMerkleOperations) { // Should write a helper for this @@ -325,7 +325,7 @@ export class AvmPersistableStateManager { * @returns exists - whether the nullifier exists in the nullifier set */ public async checkNullifierExists(contractAddress: AztecAddress, nullifier: Fr): Promise { - this.log.debug(`Checking existence of nullifier (address=${contractAddress}, nullifier=${nullifier})`); + this.log.trace(`Checking existence of nullifier (address=${contractAddress}, nullifier=${nullifier})`); const siloedNullifier = await siloNullifier(contractAddress, nullifier); const [exists, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = await this.getNullifierMembership( siloedNullifier, @@ -367,7 +367,7 @@ export class AvmPersistableStateManager { ] > { const [exists, isPending, _] = await this.nullifiers.checkExists(siloedNullifier); - this.log.debug(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}), pending=${isPending}`); + this.log.trace(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}), pending=${isPending}`); if (this.doMerkleOperations) { // Get leaf if present, low leaf if absent @@ -386,7 +386,7 @@ export class AvmPersistableStateManager { ); if (exists) { - this.log.debug(`Siloed nullifier ${siloedNullifier} exists at leafIndex=${leafIndex}`); + this.log.trace(`Siloed nullifier ${siloedNullifier} exists at leafIndex=${leafIndex}`); } else { // Sanity check that the leaf value is skipped by low leaf when it doesn't exist assert( @@ -407,7 +407,7 @@ export class AvmPersistableStateManager { * @param nullifier - the unsiloed nullifier to write */ public async writeNullifier(contractAddress: AztecAddress, nullifier: Fr) { - this.log.debug(`Inserting new nullifier (address=${nullifier}, nullifier=${contractAddress})`); + this.log.trace(`Inserting new nullifier (address=${nullifier}, nullifier=${contractAddress})`); const siloedNullifier = await siloNullifier(contractAddress, nullifier); await this.writeSiloedNullifier(siloedNullifier); } @@ -417,7 +417,7 @@ export class AvmPersistableStateManager { * @param siloedNullifier - the siloed nullifier to write */ public async writeSiloedNullifier(siloedNullifier: Fr) { - this.log.debug(`Inserting siloed nullifier=${siloedNullifier}`); + this.log.trace(`Inserting siloed nullifier=${siloedNullifier}`); if (this.doMerkleOperations) { // Maybe overkill, but we should check if the nullifier is already present in the tree before attempting to insert @@ -447,13 +447,13 @@ export class AvmPersistableStateManager { // Cache pending nullifiers for later access await this.nullifiers.append(siloedNullifier); // We append the new nullifier - this.log.debug( + this.log.trace( `Nullifier tree root before insertion ${await this.merkleTrees.treeMap .get(MerkleTreeId.NULLIFIER_TREE)! .getRoot()}`, ); const appendResult = await this.merkleTrees.appendNullifier(siloedNullifier); - this.log.debug( + this.log.trace( `Nullifier tree root after insertion ${await this.merkleTrees.treeMap .get(MerkleTreeId.NULLIFIER_TREE)! .getRoot()}`, @@ -496,7 +496,7 @@ export class AvmPersistableStateManager { ): Promise { const valueAtIndex = (await this.worldStateDB.getL1ToL2LeafValue(msgLeafIndex.toBigInt())) ?? Fr.ZERO; const exists = valueAtIndex.equals(msgHash); - this.log.debug( + this.log.trace( `l1ToL2Messages(@${msgLeafIndex}) ?? exists: ${exists}, expected: ${msgHash}, found: ${valueAtIndex}.`, ); @@ -522,7 +522,7 @@ export class AvmPersistableStateManager { * @param content - Message content. */ public writeL2ToL1Message(contractAddress: AztecAddress, recipient: Fr, content: Fr) { - this.log.debug(`L2ToL1Messages(${contractAddress}) += (recipient: ${recipient}, content: ${content}).`); + this.log.trace(`L2ToL1Messages(${contractAddress}) += (recipient: ${recipient}, content: ${content}).`); this.trace.traceNewL2ToL1Message(contractAddress, recipient, content); } @@ -532,7 +532,7 @@ export class AvmPersistableStateManager { * @param log - log contents */ public writePublicLog(contractAddress: AztecAddress, log: Fr[]) { - this.log.debug(`PublicLog(${contractAddress}) += event with ${log.length} fields.`); + this.log.trace(`PublicLog(${contractAddress}) += event with ${log.length} fields.`); this.trace.tracePublicLog(contractAddress, log); } @@ -542,7 +542,7 @@ export class AvmPersistableStateManager { * @returns the contract instance or undefined if it does not exist. */ public async getContractInstance(contractAddress: AztecAddress): Promise { - this.log.debug(`Getting contract instance for address ${contractAddress}`); + this.log.trace(`Getting contract instance for address ${contractAddress}`); const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress); const exists = instanceWithAddress !== undefined; @@ -568,7 +568,7 @@ export class AvmPersistableStateManager { if (exists) { const instance = new SerializableContractInstance(instanceWithAddress); - this.log.debug( + this.log.trace( `Got contract instance (address=${contractAddress}): exists=${exists}, instance=${jsonStringify(instance)}`, ); if (this.doMerkleOperations) { diff --git a/yarn-project/simulator/src/public/public_tx_context.ts b/yarn-project/simulator/src/public/public_tx_context.ts index af2b5c76abdd..a6e01d5115ff 100644 --- a/yarn-project/simulator/src/public/public_tx_context.ts +++ b/yarn-project/simulator/src/public/public_tx_context.ts @@ -162,7 +162,7 @@ export class PublicTxContext { * NOTE: this does not "halt" the entire transaction execution. */ revert(phase: TxExecutionPhase, revertReason: SimulationError | undefined = undefined, culprit = '') { - this.log.debug(`${TxExecutionPhase[phase]} phase reverted! ${culprit} failed with reason: ${revertReason}`); + this.log.warn(`${TxExecutionPhase[phase]} phase reverted! ${culprit} failed with reason: ${revertReason}`); if (revertReason && !this.revertReason) { // don't override revertReason @@ -170,7 +170,7 @@ export class PublicTxContext { this.revertReason = revertReason; } if (phase === TxExecutionPhase.SETUP) { - this.log.debug(`Setup phase reverted! The transaction will be thrown out.`); + this.log.warn(`Setup phase reverted! The transaction will be thrown out.`); if (revertReason) { throw revertReason; } else { diff --git a/yarn-project/simulator/src/public/side_effect_trace.ts b/yarn-project/simulator/src/public/side_effect_trace.ts index 20ef38ec2111..bd067e240b3b 100644 --- a/yarn-project/simulator/src/public/side_effect_trace.ts +++ b/yarn-project/simulator/src/public/side_effect_trace.ts @@ -127,7 +127,6 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { /** We need to track the set of class IDs used for bytecode retrieval to deduplicate and enforce limits. */ private gotBytecodeFromClassIds: UniqueClassIds = new UniqueClassIds(), ) { - this.log.debug(`Creating trace instance with startSideEffectCounter: ${startSideEffectCounter}`); this.sideEffectCounter = startSideEffectCounter; this.avmCircuitHints = AvmExecutionHints.empty(); } @@ -215,7 +214,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { path: Fr[] = emptyPublicDataPath(), ) { this.avmCircuitHints.publicDataReads.items.push(new AvmPublicDataReadTreeHint(leafPreimage, leafIndex, path)); - this.log.debug( + this.log.trace( `Tracing storage read (address=${contractAddress}, slot=${slot}): value=${value} (counter=${this.sideEffectCounter})`, ); this.incrementSideEffectCounter(); @@ -265,7 +264,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { new AvmPublicDataWriteTreeHint(readHint, newLeafPreimage, insertionPath), ); - this.log.debug( + this.log.trace( `Traced public data write (address=${contractAddress}, slot=${slot}): value=${value} (counter=${this.sideEffectCounter}, isProtocol:${protocolWrite})`, ); this.incrementSideEffectCounter(); @@ -282,6 +281,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { // New Hinting this.avmCircuitHints.noteHashReads.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path)); // NOTE: counter does not increment for note hash checks (because it doesn't rely on pending note hashes) + this.log.trace(`Tracing note hash check (counter=${this.sideEffectCounter})`); } public traceNewNoteHash(noteHash: Fr, leafIndex: Fr = Fr.zero(), path: Fr[] = emptyNoteHashPath()) { @@ -290,8 +290,8 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { } this.noteHashes.push(new NoteHash(noteHash, this.sideEffectCounter)); - this.log.debug(`NEW_NOTE_HASH cnt: ${this.sideEffectCounter}`); this.avmCircuitHints.noteHashWrites.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path)); + this.log.trace(`Tracing new note hash (counter=${this.sideEffectCounter})`); this.incrementSideEffectCounter(); } @@ -305,7 +305,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { this.avmCircuitHints.nullifierReads.items.push( new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath), ); - this.log.debug(`NULLIFIER_EXISTS cnt: ${this.sideEffectCounter}`); + this.log.trace(`Tracing nullifier check (counter=${this.sideEffectCounter})`); this.incrementSideEffectCounter(); } @@ -324,7 +324,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { const lowLeafReadHint = new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath); this.avmCircuitHints.nullifierWrites.items.push(new AvmNullifierWriteTreeHint(lowLeafReadHint, insertionPath)); - this.log.debug(`NEW_NULLIFIER cnt: ${this.sideEffectCounter}`); + this.log.trace(`Tracing new nullifier (counter=${this.sideEffectCounter})`); this.incrementSideEffectCounter(); } @@ -337,6 +337,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { path: Fr[] = emptyL1ToL2MessagePath(), ) { this.avmCircuitHints.l1ToL2MessageReads.items.push(new AvmAppendTreeHint(msgLeafIndex, msgHash, path)); + this.log.trace(`Tracing l1 to l2 message check (counter=${this.sideEffectCounter})`); } public traceNewL2ToL1Message(contractAddress: AztecAddress, recipient: Fr, content: Fr) { @@ -348,7 +349,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { this.l2ToL1Messages.push( new L2ToL1Message(recipientAddress, content, this.sideEffectCounter).scope(contractAddress), ); - this.log.debug(`NEW_L2_TO_L1_MSG cnt: ${this.sideEffectCounter}`); + this.log.trace(`Tracing new l2 to l1 message (counter=${this.sideEffectCounter})`); this.incrementSideEffectCounter(); } @@ -362,7 +363,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { } const publicLog = new PublicLog(contractAddress, padArrayEnd(log, Fr.ZERO, PUBLIC_LOG_DATA_SIZE_IN_FIELDS)); this.publicLogs.push(publicLog); - this.log.debug(`NEW_PUBLIC_LOG cnt: ${this.sideEffectCounter}`); + this.log.trace(`Tracing new public log (counter=${this.sideEffectCounter})`); this.incrementSideEffectCounter(); } @@ -387,7 +388,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { membershipHint, ), ); - this.log.debug(`CONTRACT_INSTANCE cnt: ${this.sideEffectCounter}`); + this.log.trace(`Tracing contract instance retrieval (counter=${this.sideEffectCounter})`); this.incrementSideEffectCounter(); } @@ -432,7 +433,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { // Since the bytecode hints are keyed by class ID, we need to hint the instance separately // since there might be multiple instances hinted for the same class ID. this.avmCircuitHints.contractInstances.items.push(instance); - this.log.debug( + this.log.trace( `Tracing contract instance for bytecode retrieval: exists=${exists}, instance=${jsonStringify(contractInstance)}`, ); @@ -447,7 +448,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { // To do so, the circuit needs to know the class ID in the if (this.gotBytecodeFromClassIds.has(contractInstance.contractClassId.toString())) { // this ensures there are no duplicates - this.log.debug( + this.log.trace( `Contract class id ${contractInstance.contractClassId.toString()} already exists in previous hints`, ); return; @@ -470,7 +471,7 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { ); } - this.log.debug(`Tracing bytecode & contract class for bytecode retrieval: class=${jsonStringify(contractClass)}`); + this.log.trace(`Tracing bytecode & contract class for bytecode retrieval: class=${jsonStringify(contractClass)}`); this.avmCircuitHints.contractBytecodeHints.set( contractInstance.contractClassId.toString(), new AvmContractBytecodeHints(bytecode, instance, contractClass), @@ -492,7 +493,6 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface { /** Did the call revert? */ _reverted: boolean, ) { - this.log.debug(`Tracing enqueued call`); // TODO(4805): check if some threshold is reached for max enqueued or nested calls (to unique contracts?) this.enqueuedCalls.push(publicCallRequest); this.avmCircuitHints.enqueuedCalls.items.push(new AvmEnqueuedCallHint(publicCallRequest.contractAddress, calldata)); diff --git a/yarn-project/txe/src/txe_service/txe_service.ts b/yarn-project/txe/src/txe_service/txe_service.ts index 76211e383a44..b9553bb3f385 100644 --- a/yarn-project/txe/src/txe_service/txe_service.ts +++ b/yarn-project/txe/src/txe_service/txe_service.ts @@ -95,12 +95,13 @@ export class TXEService { ]); if (!fromSingle(secret).equals(Fr.ZERO)) { - await this.createAccount(secret); + await this.addAccount(artifact, instance, secret); + } else { + await (this.typedOracle as TXE).addContractInstance(instance); + await (this.typedOracle as TXE).addContractArtifact(instance.contractClassId, artifact); + this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`); } - this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`); - await (this.typedOracle as TXE).addContractInstance(instance); - await (this.typedOracle as TXE).addContractArtifact(instance.contractClassId, artifact); return toForeignCallResult([ toArray([ instance.salt, @@ -137,6 +138,7 @@ export class TXEService { async createAccount(secret: ForeignCallSingle) { const keyStore = (this.typedOracle as TXE).getKeyStore(); const secretFr = fromSingle(secret); + // This is a footgun ! const completeAddress = await keyStore.addAccount(secretFr, secretFr); const accountStore = (this.typedOracle as TXE).getTXEDatabase(); await accountStore.setAccount(completeAddress.address, completeAddress);