Skip to content

Commit

Permalink
chore: Skip emitting public bytecode
Browse files Browse the repository at this point in the history
Skips emitting the event with the contract public bytecode when registering the contract class. This allows for smaller L1 txs so they fit in Sepolia. This is a temporary hack to be reverted.

To get bytecode into the nodes, we push it forcefully from the PXE whenever we register a new contract. However, this only gets the bytecode into the node that the PXE is connected to. To avoid nodes or prover nodes from missing bytecode that is to be used for known deployments, such as the token or token bridge contracts, we now manually register them on initialization.
  • Loading branch information
spalladino committed Nov 19, 2024
1 parent b660739 commit 46a2c17
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
use dep::aztec::protocol_types::{
constants::{
MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE,
REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE,
},
contract_class_id::ContractClassId,
traits::Serialize,
};

// #[event]
// 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_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],
packed_public_bytecode: [Field; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],
}

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];
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];
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_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS {
for i in 0..MAX_BROADCASTEABLE_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,7 +22,9 @@ contract ContractClassRegisterer {
};

use crate::events::{
class_registered::ContractClassRegistered,
class_registered::{
ContractClassRegistered, MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS,
},
private_function_broadcasted::{
ClassPrivateFunctionBroadcasted, InnerPrivateFunction, PrivateFunction,
},
Expand Down Expand Up @@ -81,13 +83,6 @@ contract ContractClassRegisterer {
);

// Emit the contract class id as a nullifier to be able to prove that this class has been (not) registered
let event = ContractClassRegistered {
contract_class_id,
version: 1,
artifact_hash,
private_functions_root,
packed_public_bytecode,
};
context.push_nullifier(contract_class_id.to_field());

// Broadcast class info including public bytecode
Expand All @@ -100,7 +95,24 @@ contract ContractClassRegisterer {
public_bytecode_commitment,
],
);
emit_contract_class_log(&mut context, event.serialize());

// 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];
}
let event = ContractClassRegistered {
contract_class_id,
version: 1,
artifact_hash,
private_functions_root,
packed_public_bytecode: event_public_bytecode,
};
emit_contract_class_log(&mut context, event.serialize());
}
}

#[private]
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/archiver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"@aztec/foundation": "workspace:^",
"@aztec/kv-store": "workspace:^",
"@aztec/l1-artifacts": "workspace:^",
"@aztec/noir-contracts.js": "workspace:^",
"@aztec/protocol-contracts": "workspace:^",
"@aztec/telemetry-client": "workspace:^",
"@aztec/types": "workspace:^",
Expand All @@ -83,7 +84,6 @@
"ws": "^8.13.0"
},
"devDependencies": {
"@aztec/noir-contracts.js": "workspace:^",
"@jest/globals": "^29.5.0",
"@types/debug": "^4.1.7",
"@types/jest": "^29.5.0",
Expand Down
12 changes: 11 additions & 1 deletion yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,12 @@ export class Archiver implements ArchiveSource {
return this.store.getContractClassIds();
}

// TODO(#10007): Remove this method
async addContractClass(contractClass: ContractClassPublic): Promise<void> {
await this.store.addContractClasses([contractClass], 0);
return;
}

addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise<void> {
return this.store.addContractArtifact(address, artifact);
}
Expand Down Expand Up @@ -764,7 +770,6 @@ class ArchiverStoreHelper
ArchiverDataStore,
| 'addLogs'
| 'deleteLogs'
| 'addContractClasses'
| 'deleteContractClasses'
| 'addContractInstances'
| 'deleteContractInstances'
Expand All @@ -775,6 +780,11 @@ class ArchiverStoreHelper

constructor(private readonly store: ArchiverDataStore) {}

// TODO(#10007): Remove this method
addContractClasses(contractClasses: ContractClassPublic[], blockNum: number): Promise<boolean> {
return this.store.addContractClasses(contractClasses, blockNum);
}

/**
* Extracts and stores contract classes out of ContractClassRegistered events emitted by the class registerer contract.
* @param allLogs - All logs emitted in a bunch of blocks.
Expand Down
24 changes: 21 additions & 3 deletions yarn-project/archiver/src/factory.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { type ArchiverApi, type Service } from '@aztec/circuit-types';
import { type ContractClassPublic } from '@aztec/circuits.js';
import { type ContractClassPublic, getContractClassFromArtifact } from '@aztec/circuits.js';
import { createDebugLogger } from '@aztec/foundation/log';
import { type Maybe } from '@aztec/foundation/types';
import { type DataStoreConfig } from '@aztec/kv-store/config';
import { createStore } from '@aztec/kv-store/utils';
import { TokenBridgeContractArtifact, TokenContractArtifact } from '@aztec/noir-contracts.js';
import { getCanonicalProtocolContract, protocolContractNames } from '@aztec/protocol-contracts';
import { type TelemetryClient } from '@aztec/telemetry-client';
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
Expand All @@ -21,14 +22,15 @@ export async function createArchiver(
if (!config.archiverUrl) {
const store = await createStore('archiver', config, createDebugLogger('aztec:archiver:lmdb'));
const archiverStore = new KVArchiverDataStore(store, config.maxLogs);
await initWithProtocolContracts(archiverStore);
await registerProtocolContracts(archiverStore);
await registerCommonContracts(archiverStore);
return Archiver.createAndSync(config, archiverStore, telemetry, opts.blockUntilSync);
} else {
return createArchiverClient(config.archiverUrl);
}
}

async function initWithProtocolContracts(store: KVArchiverDataStore) {
async function registerProtocolContracts(store: KVArchiverDataStore) {
const blockNumber = 0;
for (const name of protocolContractNames) {
const contract = getCanonicalProtocolContract(name);
Expand All @@ -42,3 +44,19 @@ async function initWithProtocolContracts(store: KVArchiverDataStore) {
await store.addContractInstances([contract.instance], blockNumber);
}
}

// TODO(#10007): Remove this method. We are explicitly registering these contracts
// here to ensure they are available to all nodes and all prover nodes, since the PXE
// was tweaked to automatically push contract classes to the node it is registered,
// but other nodes in the network may require the contract classes to be registered as well.
// TODO(#10007): Remove the dependency on noir-contracts.js from this package once we remove this.
async function registerCommonContracts(store: KVArchiverDataStore) {
const blockNumber = 0;
const artifacts = [TokenBridgeContractArtifact, TokenContractArtifact];
const classes = artifacts.map(artifact => ({
...getContractClassFromArtifact(artifact),
privateFunctions: [],
unconstrainedFunctions: [],
}));
await store.addContractClasses(classes, blockNumber);
}
6 changes: 3 additions & 3 deletions yarn-project/archiver/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
{
"path": "../l1-artifacts"
},
{
"path": "../noir-contracts.js"
},
{
"path": "../protocol-contracts"
},
Expand All @@ -32,9 +35,6 @@
},
{
"path": "../types"
},
{
"path": "../noir-contracts.js"
}
],
"include": ["src"]
Expand Down
6 changes: 6 additions & 0 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,13 @@ export class AztecNodeService implements AztecNode {
});
}

// TODO(#10007): Remove this method
public addContractClass(contractClass: ContractClassPublic): Promise<void> {
return this.contractDataSource.addContractClass(contractClass);
}

public addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise<void> {
// TODO: Node should validate the artifact before accepting it
return this.contractDataSource.addContractArtifact(address, artifact);
}

Expand Down
12 changes: 12 additions & 0 deletions yarn-project/circuit-types/src/interfaces/archiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,15 @@ describe('ArchiverApiSchema', () => {
version: 1,
});
});

it('addContractClass', async () => {
const contractClass = getContractClassFromArtifact(artifact);
await context.client.addContractClass({
...omit(contractClass, 'publicBytecodeCommitment'),
unconstrainedFunctions: [],
privateFunctions: [],
});
});
});

class MockArchiver implements ArchiverApi {
Expand Down Expand Up @@ -362,4 +371,7 @@ class MockArchiver implements ArchiverApi {
expect(l1ToL2Message).toBeInstanceOf(Fr);
return Promise.resolve(1n);
}
addContractClass(_contractClass: ContractClassPublic): Promise<void> {
return Promise.resolve();
}
}
2 changes: 2 additions & 0 deletions yarn-project/circuit-types/src/interfaces/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,6 @@ export const ArchiverApiSchema: ApiSchemaFor<ArchiverApi> = {
addContractArtifact: z.function().args(schemas.AztecAddress, ContractArtifactSchema).returns(z.void()),
getL1ToL2Messages: z.function().args(schemas.BigInt).returns(z.array(schemas.Fr)),
getL1ToL2MessageIndex: z.function().args(schemas.Fr).returns(schemas.BigInt.optional()),
// TODO(#10007): Remove this method
addContractClass: z.function().args(ContractClassPublicSchema).returns(z.void()),
};
8 changes: 8 additions & 0 deletions yarn-project/circuit-types/src/interfaces/aztec-node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ describe('AztecNodeApiSchema', () => {
const response = await context.client.getEpochProofQuotes(1n);
expect(response).toEqual([expect.any(EpochProofQuote)]);
});

it('addContractClass', async () => {
const contractClass = getContractClassFromArtifact(artifact);
await context.client.addContractClass({ ...contractClass, unconstrainedFunctions: [], privateFunctions: [] });
});
});

class MockAztecNode implements AztecNode {
Expand Down Expand Up @@ -538,4 +543,7 @@ class MockAztecNode implements AztecNode {
expect(epoch).toEqual(1n);
return Promise.resolve([EpochProofQuote.random()]);
}
addContractClass(_contractClass: ContractClassPublic): Promise<void> {
return Promise.resolve();
}
}
10 changes: 10 additions & 0 deletions yarn-project/circuit-types/src/interfaces/aztec-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,13 @@ export interface AztecNode extends ProverCoordination {
* @param epoch - The epoch for which to get the quotes
*/
getEpochProofQuotes(epoch: bigint): Promise<EpochProofQuote[]>;

/**
* Adds a contract class bypassing the registerer.
* TODO(#10007): Remove this method.
* @param contractClass - The class to register.
*/
addContractClass(contractClass: ContractClassPublic): Promise<void>;
}

export const AztecNodeApiSchema: ApiSchemaFor<AztecNode> = {
Expand Down Expand Up @@ -514,6 +521,9 @@ export const AztecNodeApiSchema: ApiSchemaFor<AztecNode> = {
addEpochProofQuote: z.function().args(EpochProofQuote.schema).returns(z.void()),

getEpochProofQuotes: z.function().args(schemas.BigInt).returns(z.array(EpochProofQuote.schema)),

// TODO(#10007): Remove this method
addContractClass: z.function().args(ContractClassPublicSchema).returns(z.void()),
};

export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecNode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ export interface ContractDataSource {
*/
getContractClass(id: Fr): Promise<ContractClassPublic | undefined>;

/**
* Adds a contract class to the database.
* TODO(#10007): Remove this method
*/
addContractClass(contractClass: ContractClassPublic): Promise<void>;

/**
* Returns a publicly deployed contract instance given its address.
* @param address - Address of the deployed contract.
Expand Down
Loading

0 comments on commit 46a2c17

Please sign in to comment.