Skip to content

Commit 280d169

Browse files
authored
chore: Skip emitting public bytecode (#10009)
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. Reverting this is logged as issue #10007 Fixes #10000 Please read [contributing guidelines](CONTRIBUTING.md) and remove this line.
1 parent a2c0701 commit 280d169

File tree

16 files changed

+191
-73
lines changed

16 files changed

+191
-73
lines changed

noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
use dep::aztec::protocol_types::{
2-
constants::{
3-
MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE,
4-
},
5-
contract_class_id::ContractClassId,
2+
constants::REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, contract_class_id::ContractClassId,
63
traits::Serialize,
74
};
85

9-
// #[event]
6+
// TODO(#10007): Use MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS instead
7+
pub global MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u32 = 100;
8+
109
pub struct ContractClassRegistered {
1110
contract_class_id: ContractClassId,
1211
version: Field,
1312
artifact_hash: Field,
1413
private_functions_root: Field,
15-
packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],
14+
packed_public_bytecode: [Field; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],
1615
}
1716

18-
impl Serialize<MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5> for ContractClassRegistered {
19-
fn serialize(self: Self) -> [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5] {
20-
let mut packed = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5];
17+
impl Serialize<MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5> for ContractClassRegistered {
18+
fn serialize(
19+
self: Self,
20+
) -> [Field; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5] {
21+
let mut packed = [0; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5];
2122
packed[0] = REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE;
2223
packed[1] = self.contract_class_id.to_field();
2324
packed[2] = self.version;
2425
packed[3] = self.artifact_hash;
2526
packed[4] = self.private_functions_root;
26-
for i in 0..MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS {
27+
for i in 0..MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS {
2728
packed[i + 5] = self.packed_public_bytecode[i];
2829
}
2930
packed

noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr

+21-9
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ contract ContractClassRegisterer {
2222
};
2323

2424
use crate::events::{
25-
class_registered::ContractClassRegistered,
25+
class_registered::{
26+
ContractClassRegistered, MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS,
27+
},
2628
private_function_broadcasted::{
2729
ClassPrivateFunctionBroadcasted, InnerPrivateFunction, PrivateFunction,
2830
},
@@ -81,13 +83,6 @@ contract ContractClassRegisterer {
8183
);
8284

8385
// Emit the contract class id as a nullifier to be able to prove that this class has been (not) registered
84-
let event = ContractClassRegistered {
85-
contract_class_id,
86-
version: 1,
87-
artifact_hash,
88-
private_functions_root,
89-
packed_public_bytecode,
90-
};
9186
context.push_nullifier(contract_class_id.to_field());
9287

9388
// Broadcast class info including public bytecode
@@ -100,7 +95,24 @@ contract ContractClassRegisterer {
10095
public_bytecode_commitment,
10196
],
10297
);
103-
emit_contract_class_log(&mut context, event.serialize());
98+
99+
// TODO(#10007): Drop this conditional and always emit the bytecode. We allow skipping the broadcast
100+
// as a stopgap solution to allow txs to fit in Sepolia when we broadcast public bytecode.
101+
if bytecode_length_in_fields <= MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS {
102+
let mut event_public_bytecode =
103+
[0; MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS];
104+
for i in 0..MAX_BROADCASTEABLE_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS {
105+
event_public_bytecode[i] = packed_public_bytecode[i];
106+
}
107+
let event = ContractClassRegistered {
108+
contract_class_id,
109+
version: 1,
110+
artifact_hash,
111+
private_functions_root,
112+
packed_public_bytecode: event_public_bytecode,
113+
};
114+
emit_contract_class_log(&mut context, event.serialize());
115+
}
104116
}
105117

106118
#[private]

yarn-project/archiver/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"@aztec/foundation": "workspace:^",
7272
"@aztec/kv-store": "workspace:^",
7373
"@aztec/l1-artifacts": "workspace:^",
74+
"@aztec/noir-contracts.js": "workspace:^",
7475
"@aztec/protocol-contracts": "workspace:^",
7576
"@aztec/telemetry-client": "workspace:^",
7677
"@aztec/types": "workspace:^",
@@ -83,7 +84,6 @@
8384
"ws": "^8.13.0"
8485
},
8586
"devDependencies": {
86-
"@aztec/noir-contracts.js": "workspace:^",
8787
"@jest/globals": "^29.5.0",
8888
"@types/debug": "^4.1.7",
8989
"@types/jest": "^29.5.0",

yarn-project/archiver/src/archiver/archiver.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,12 @@ export class Archiver implements ArchiveSource {
712712
return this.store.getContractClassIds();
713713
}
714714

715+
// TODO(#10007): Remove this method
716+
async addContractClass(contractClass: ContractClassPublic): Promise<void> {
717+
await this.store.addContractClasses([contractClass], 0);
718+
return;
719+
}
720+
715721
addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise<void> {
716722
return this.store.addContractArtifact(address, artifact);
717723
}
@@ -764,7 +770,6 @@ class ArchiverStoreHelper
764770
ArchiverDataStore,
765771
| 'addLogs'
766772
| 'deleteLogs'
767-
| 'addContractClasses'
768773
| 'deleteContractClasses'
769774
| 'addContractInstances'
770775
| 'deleteContractInstances'
@@ -775,6 +780,11 @@ class ArchiverStoreHelper
775780

776781
constructor(private readonly store: ArchiverDataStore) {}
777782

783+
// TODO(#10007): Remove this method
784+
addContractClasses(contractClasses: ContractClassPublic[], blockNum: number): Promise<boolean> {
785+
return this.store.addContractClasses(contractClasses, blockNum);
786+
}
787+
778788
/**
779789
* Extracts and stores contract classes out of ContractClassRegistered events emitted by the class registerer contract.
780790
* @param allLogs - All logs emitted in a bunch of blocks.

yarn-project/archiver/src/factory.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { type ArchiverApi, type Service } from '@aztec/circuit-types';
2-
import { type ContractClassPublic } from '@aztec/circuits.js';
2+
import { type ContractClassPublic, getContractClassFromArtifact } from '@aztec/circuits.js';
33
import { createDebugLogger } from '@aztec/foundation/log';
44
import { type Maybe } from '@aztec/foundation/types';
55
import { type DataStoreConfig } from '@aztec/kv-store/config';
66
import { createStore } from '@aztec/kv-store/utils';
7+
import { TokenBridgeContractArtifact, TokenContractArtifact } from '@aztec/noir-contracts.js';
78
import { getCanonicalProtocolContract, protocolContractNames } from '@aztec/protocol-contracts';
89
import { type TelemetryClient } from '@aztec/telemetry-client';
910
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
@@ -21,14 +22,15 @@ export async function createArchiver(
2122
if (!config.archiverUrl) {
2223
const store = await createStore('archiver', config, createDebugLogger('aztec:archiver:lmdb'));
2324
const archiverStore = new KVArchiverDataStore(store, config.maxLogs);
24-
await initWithProtocolContracts(archiverStore);
25+
await registerProtocolContracts(archiverStore);
26+
await registerCommonContracts(archiverStore);
2527
return Archiver.createAndSync(config, archiverStore, telemetry, opts.blockUntilSync);
2628
} else {
2729
return createArchiverClient(config.archiverUrl);
2830
}
2931
}
3032

31-
async function initWithProtocolContracts(store: KVArchiverDataStore) {
33+
async function registerProtocolContracts(store: KVArchiverDataStore) {
3234
const blockNumber = 0;
3335
for (const name of protocolContractNames) {
3436
const contract = getCanonicalProtocolContract(name);
@@ -42,3 +44,19 @@ async function initWithProtocolContracts(store: KVArchiverDataStore) {
4244
await store.addContractInstances([contract.instance], blockNumber);
4345
}
4446
}
47+
48+
// TODO(#10007): Remove this method. We are explicitly registering these contracts
49+
// here to ensure they are available to all nodes and all prover nodes, since the PXE
50+
// was tweaked to automatically push contract classes to the node it is registered,
51+
// but other nodes in the network may require the contract classes to be registered as well.
52+
// TODO(#10007): Remove the dependency on noir-contracts.js from this package once we remove this.
53+
async function registerCommonContracts(store: KVArchiverDataStore) {
54+
const blockNumber = 0;
55+
const artifacts = [TokenBridgeContractArtifact, TokenContractArtifact];
56+
const classes = artifacts.map(artifact => ({
57+
...getContractClassFromArtifact(artifact),
58+
privateFunctions: [],
59+
unconstrainedFunctions: [],
60+
}));
61+
await store.addContractClasses(classes, blockNumber);
62+
}

yarn-project/archiver/tsconfig.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
{
2525
"path": "../l1-artifacts"
2626
},
27+
{
28+
"path": "../noir-contracts.js"
29+
},
2730
{
2831
"path": "../protocol-contracts"
2932
},
@@ -32,9 +35,6 @@
3235
},
3336
{
3437
"path": "../types"
35-
},
36-
{
37-
"path": "../noir-contracts.js"
3838
}
3939
],
4040
"include": ["src"]

yarn-project/aztec-node/src/aztec-node/server.ts

+6
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,13 @@ export class AztecNodeService implements AztecNode {
812812
});
813813
}
814814

815+
// TODO(#10007): Remove this method
816+
public addContractClass(contractClass: ContractClassPublic): Promise<void> {
817+
return this.contractDataSource.addContractClass(contractClass);
818+
}
819+
815820
public addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise<void> {
821+
// TODO: Node should validate the artifact before accepting it
816822
return this.contractDataSource.addContractArtifact(address, artifact);
817823
}
818824

yarn-project/circuit-types/src/interfaces/archiver.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,15 @@ describe('ArchiverApiSchema', () => {
232232
version: 1,
233233
});
234234
});
235+
236+
it('addContractClass', async () => {
237+
const contractClass = getContractClassFromArtifact(artifact);
238+
await context.client.addContractClass({
239+
...omit(contractClass, 'publicBytecodeCommitment'),
240+
unconstrainedFunctions: [],
241+
privateFunctions: [],
242+
});
243+
});
235244
});
236245

237246
class MockArchiver implements ArchiverApi {
@@ -362,4 +371,7 @@ class MockArchiver implements ArchiverApi {
362371
expect(l1ToL2Message).toBeInstanceOf(Fr);
363372
return Promise.resolve(1n);
364373
}
374+
addContractClass(_contractClass: ContractClassPublic): Promise<void> {
375+
return Promise.resolve();
376+
}
365377
}

yarn-project/circuit-types/src/interfaces/archiver.ts

+2
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,6 @@ export const ArchiverApiSchema: ApiSchemaFor<ArchiverApi> = {
7070
addContractArtifact: z.function().args(schemas.AztecAddress, ContractArtifactSchema).returns(z.void()),
7171
getL1ToL2Messages: z.function().args(schemas.BigInt).returns(z.array(schemas.Fr)),
7272
getL1ToL2MessageIndex: z.function().args(schemas.Fr).returns(schemas.BigInt.optional()),
73+
// TODO(#10007): Remove this method
74+
addContractClass: z.function().args(ContractClassPublicSchema).returns(z.void()),
7375
};

yarn-project/circuit-types/src/interfaces/aztec-node.test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ describe('AztecNodeApiSchema', () => {
313313
const response = await context.client.getEpochProofQuotes(1n);
314314
expect(response).toEqual([expect.any(EpochProofQuote)]);
315315
});
316+
317+
it('addContractClass', async () => {
318+
const contractClass = getContractClassFromArtifact(artifact);
319+
await context.client.addContractClass({ ...contractClass, unconstrainedFunctions: [], privateFunctions: [] });
320+
});
316321
});
317322

318323
class MockAztecNode implements AztecNode {
@@ -538,4 +543,7 @@ class MockAztecNode implements AztecNode {
538543
expect(epoch).toEqual(1n);
539544
return Promise.resolve([EpochProofQuote.random()]);
540545
}
546+
addContractClass(_contractClass: ContractClassPublic): Promise<void> {
547+
return Promise.resolve();
548+
}
541549
}

yarn-project/circuit-types/src/interfaces/aztec-node.ts

+10
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,13 @@ export interface AztecNode extends ProverCoordination {
391391
* @param epoch - The epoch for which to get the quotes
392392
*/
393393
getEpochProofQuotes(epoch: bigint): Promise<EpochProofQuote[]>;
394+
395+
/**
396+
* Adds a contract class bypassing the registerer.
397+
* TODO(#10007): Remove this method.
398+
* @param contractClass - The class to register.
399+
*/
400+
addContractClass(contractClass: ContractClassPublic): Promise<void>;
394401
}
395402

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

516523
getEpochProofQuotes: z.function().args(schemas.BigInt).returns(z.array(EpochProofQuote.schema)),
524+
525+
// TODO(#10007): Remove this method
526+
addContractClass: z.function().args(ContractClassPublicSchema).returns(z.void()),
517527
};
518528

519529
export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecNode {

yarn-project/circuits.js/src/contract/interfaces/contract_data_source.ts

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ export interface ContractDataSource {
2626
*/
2727
getContractClass(id: Fr): Promise<ContractClassPublic | undefined>;
2828

29+
/**
30+
* Adds a contract class to the database.
31+
* TODO(#10007): Remove this method
32+
*/
33+
addContractClass(contractClass: ContractClassPublic): Promise<void>;
34+
2935
/**
3036
* Returns a publicly deployed contract instance given its address.
3137
* @param address - Address of the deployed contract.

0 commit comments

Comments
 (0)