Skip to content

Commit

Permalink
feat: optionally emit public bytecode (#10365)
Browse files Browse the repository at this point in the history
This PR builds on top of #10009 and makes publishing bytecode
conditionally on a function parameter such that it might be
enabled/disabled on just some networks
  • Loading branch information
alexghr authored Dec 3, 2024
1 parent cc54a1e commit 84ff623
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -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<MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5> 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<MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand All @@ -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
Expand Down Expand Up @@ -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());
}
Expand Down
9 changes: 8 additions & 1 deletion yarn-project/aztec.js/src/deployment/register_class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ContractFunctionInteraction> {
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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 });
Expand Down

0 comments on commit 84ff623

Please sign in to comment.