From 5da4e0e5944afe6b01be0b34cec066de008bb034 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Tue, 3 Dec 2024 11:52:37 +0000 Subject: [PATCH] feat: optionally emit public bytecode --- .../src/events/class_registered.nr | 20 +++++++++---------- .../src/main.nr | 14 ++++--------- .../aztec.js/src/deployment/register_class.ts | 9 ++++++++- .../contract_class_registration.test.ts | 10 +++++++++- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr index 34949a5b691..8e6edbfdb57 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr @@ -1,30 +1,28 @@ use dep::aztec::protocol_types::{ - constants::REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, contract_class_id::ContractClassId, + constants::{ + MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, + }, + contract_class_id::ContractClassId, traits::Serialize, }; -// TODO(#10007): Use MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS instead -pub global MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u32 = 100; - pub struct ContractClassRegistered { contract_class_id: ContractClassId, version: Field, artifact_hash: Field, private_functions_root: Field, - packed_public_bytecode: [Field; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS], + packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS], } -impl Serialize for ContractClassRegistered { - fn serialize( - self: Self, - ) -> [Field; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5] { - let mut packed = [0; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5]; +impl Serialize for ContractClassRegistered { + fn serialize(self: Self) -> [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5] { + let mut packed = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5]; packed[0] = REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE; packed[1] = self.contract_class_id.to_field(); packed[2] = self.version; packed[3] = self.artifact_hash; packed[4] = self.private_functions_root; - for i in 0..MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS { + for i in 0..MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS { packed[i + 5] = self.packed_public_bytecode[i]; } packed diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 1e8fb176fd1..6c90b6d4cf5 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -22,9 +22,7 @@ contract ContractClassRegisterer { }; use crate::events::{ - class_registered::{ - ContractClassRegistered, MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, - }, + class_registered::ContractClassRegistered, private_function_broadcasted::{ ClassPrivateFunctionBroadcasted, InnerPrivateFunction, PrivateFunction, }, @@ -44,6 +42,7 @@ contract ContractClassRegisterer { artifact_hash: Field, private_functions_root: Field, public_bytecode_commitment: Field, + emit: bool, ) { // TODO: Validate public_bytecode_commitment is the correct commitment of packed_public_bytecode // TODO: We should be able to remove public_bytecode_commitment from the input if it's calculated in this function @@ -98,18 +97,13 @@ contract ContractClassRegisterer { // TODO(#10007): Drop this conditional and always emit the bytecode. We allow skipping the broadcast // as a stopgap solution to allow txs to fit in Sepolia when we broadcast public bytecode. - if bytecode_length_in_fields <= MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS { - let mut event_public_bytecode = - [0; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS]; - for i in 0..MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS { - event_public_bytecode[i] = packed_public_bytecode[i]; - } + if emit { let event = ContractClassRegistered { contract_class_id, version: 1, artifact_hash, private_functions_root, - packed_public_bytecode: event_public_bytecode, + packed_public_bytecode, }; emit_contract_class_log(&mut context, event.serialize()); } diff --git a/yarn-project/aztec.js/src/deployment/register_class.ts b/yarn-project/aztec.js/src/deployment/register_class.ts index 8ba9c99f55a..eaaba5e8b95 100644 --- a/yarn-project/aztec.js/src/deployment/register_class.ts +++ b/yarn-project/aztec.js/src/deployment/register_class.ts @@ -5,15 +5,22 @@ import { type ContractFunctionInteraction } from '../contract/contract_function_ import { type Wallet } from '../wallet/index.js'; import { getRegistererContract } from './protocol_contracts.js'; +const defaultEmitPublicBytecode = + // guard against `process` not being defined (e.g. in the browser) + typeof process === 'object' && typeof process.env === 'object' + ? ['1', 'true', 'yes', ''].includes(process.env.AZTEC_EMIT_PUBLIC_BYTECODE ?? '') + : true; + /** Sets up a call to register a contract class given its artifact. */ export async function registerContractClass( wallet: Wallet, artifact: ContractArtifact, + emitPublicBytecode = defaultEmitPublicBytecode, ): Promise { const { artifactHash, privateFunctionsRoot, publicBytecodeCommitment, packedBytecode } = getContractClassFromArtifact(artifact); const encodedBytecode = bufferAsFields(packedBytecode, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS); const registerer = getRegistererContract(wallet); await wallet.addCapsule(encodedBytecode); - return registerer.methods.register(artifactHash, privateFunctionsRoot, publicBytecodeCommitment); + return registerer.methods.register(artifactHash, privateFunctionsRoot, publicBytecodeCommitment, emitPublicBytecode); } diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts index f74795170f2..d436c38e0ac 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts @@ -49,7 +49,7 @@ describe('e2e_deploy_contract contract class registration', () => { beforeAll(async () => { artifact = StatefulTestContract.artifact; - registrationTxReceipt = await registerContractClass(wallet, artifact).then(c => c.send().wait()); + registrationTxReceipt = await registerContractClass(wallet, artifact, false).then(c => c.send().wait()); contractClass = getContractClassFromArtifact(artifact); // TODO(#10007) Remove this call. Node should get the bytecode from the event broadcast. @@ -58,6 +58,14 @@ describe('e2e_deploy_contract contract class registration', () => { }); describe('registering a contract class', () => { + it('optionally emits public bytecode', async () => { + const registrationTxReceipt = await registerContractClass(wallet, TestContract.artifact, true).then(c => + c.send().wait(), + ); + const logs = await aztecNode.getContractClassLogs({ txHash: registrationTxReceipt.txHash }); + expect(logs.logs.length).toEqual(1); + }); + // TODO(#10007) Remove this test. We should always broadcast public bytecode. it('bypasses broadcast if exceeds bytecode limit for event size', async () => { const logs = await aztecNode.getContractClassLogs({ txHash: registrationTxReceipt.txHash });