Skip to content

Commit

Permalink
feat: Capture broadcasted fns in node
Browse files Browse the repository at this point in the history
Captures individual private and unconstrained functions broadcasted from
the class registerer contract in the aztec node archiver and store them
for future use.
  • Loading branch information
spalladino committed Mar 20, 2024
1 parent 31ca344 commit 516576f
Show file tree
Hide file tree
Showing 46 changed files with 889 additions and 144 deletions.
8 changes: 4 additions & 4 deletions l1-contracts/slither_output.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,15 +258,15 @@ solc-0.8.23 is not recommended for deployment
Impact: Informational
Confidence: Medium
- [ ] ID-27
Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L130) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L123)
Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L131) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L124)

src/core/libraries/ConstantsGen.sol#L130
src/core/libraries/ConstantsGen.sol#L131


- [ ] ID-28
Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L110) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L111)
Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L111) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L112)

src/core/libraries/ConstantsGen.sol#L110
src/core/libraries/ConstantsGen.sol#L111


- [ ] ID-29
Expand Down
7 changes: 4 additions & 3 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ library Constants {
uint256 internal constant INITIAL_L2_BLOCK_NUM = 1;
uint256 internal constant BLOB_SIZE_IN_BYTES = 126976;
uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 15000;
uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 500;
uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 500;
uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000;
uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000;
uint256 internal constant REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 19;
uint256 internal constant REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE =
0x6999d1e02b08a447a463563453cb36919c9dd7150336fc7c4d2b52f8;
uint256 internal constant REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE =
Expand All @@ -90,7 +91,7 @@ library Constants {
uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE =
0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631;
uint256 internal constant DEPLOYER_CONTRACT_ADDRESS =
0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78;
0x078147c1cf4a0d256b55f090ccfd831daa056f9c8aee8dbd5f48235720cf3315;
uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17;
uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20;
uint256 internal constant GET_NOTE_ORACLE_RETURN_LENGTH = 23;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use dep::aztec::protocol_types::{
constants::{
FUNCTION_TREE_HEIGHT, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT,
MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS,
REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE
REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE,
REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS
},
traits::{Serialize}
traits::Serialize
};

struct PrivateFunction {
Expand Down Expand Up @@ -36,26 +37,30 @@ struct ClassPrivateFunctionBroadcasted {
artifact_metadata_hash: Field,
unconstrained_functions_artifact_tree_root: Field,
private_function_tree_sibling_path: [Field; FUNCTION_TREE_HEIGHT],
private_function_tree_leaf_index: Field,
artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT],
artifact_function_tree_leaf_index: Field,
function: PrivateFunction
}

impl Serialize<MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 17> for ClassPrivateFunctionBroadcasted {
fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 17] {
let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 17];
impl Serialize<MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS> for ClassPrivateFunctionBroadcasted {
fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS] {
let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS];
packed[0] = REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE;
packed[1] = self.contract_class_id.to_field();
packed[2] = self.artifact_metadata_hash;
packed[3] = self.unconstrained_functions_artifact_tree_root;
for i in 0..FUNCTION_TREE_HEIGHT {
packed[i + 4] = self.private_function_tree_sibling_path[i];
}
packed[4 + FUNCTION_TREE_HEIGHT] = self.private_function_tree_leaf_index;
for i in 0..ARTIFACT_FUNCTION_TREE_MAX_HEIGHT {
packed[i + 4 + FUNCTION_TREE_HEIGHT] = self.private_function_tree_sibling_path[i];
packed[i + 5 + FUNCTION_TREE_HEIGHT] = self.artifact_function_tree_sibling_path[i];
}
packed[5 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT + FUNCTION_TREE_HEIGHT] = self.artifact_function_tree_leaf_index;
let packed_function = self.function.serialize();
for i in 0..MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 3 {
packed[i + 4 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT + FUNCTION_TREE_HEIGHT] = packed_function[i];
packed[i + 6 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT + FUNCTION_TREE_HEIGHT] = packed_function[i];
}
packed
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ contract ContractClassRegisterer {
ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, FUNCTION_TREE_HEIGHT,
MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE
},
traits::{Serialize}
traits::Serialize
};

use dep::aztec::log::{emit_unencrypted_log_from_private};
use dep::aztec::log::emit_unencrypted_log_from_private;

use crate::events::{
class_registered::ContractClassRegistered,
Expand Down Expand Up @@ -59,15 +59,19 @@ contract ContractClassRegisterer {
artifact_metadata_hash: Field,
unconstrained_functions_artifact_tree_root: Field,
private_function_tree_sibling_path: [Field; FUNCTION_TREE_HEIGHT],
private_function_tree_leaf_index: Field,
artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT],
artifact_function_tree_leaf_index: Field,
function_data: PrivateFunction
) {
let event = ClassPrivateFunctionBroadcasted {
contract_class_id,
artifact_metadata_hash,
unconstrained_functions_artifact_tree_root,
private_function_tree_sibling_path,
private_function_tree_leaf_index,
artifact_function_tree_sibling_path,
artifact_function_tree_leaf_index,
function: function_data
};
dep::aztec::oracle::debug_log::debug_log_array_with_prefix(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,11 @@ global BLOB_SIZE_IN_BYTES: Field = 126976;
global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u64 = 15000;
// Bytecode size for private functions is per function, not for the entire contract.
// Note that private functions bytecode includes a mix of acir and brillig.
global MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS: u64 = 500;
global MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS: u64 = 3000;
// Same for unconstrained functions: the size is per function.
global MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS: u64 = 500;
global MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS: u64 = 3000;
// How many fields are on the serialized ClassPrivateFunctionBroadcasted event in addition to MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS.
global REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS: u64 = 19;
// Since we are not yet emitting selectors we'll use this magic value to identify events emitted by the ClassRegisterer.
// This is just a stopgap until we implement proper selectors.
// sha224sum '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] }'
Expand All @@ -128,7 +130,7 @@ global REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af8166354
// CONTRACT INSTANCE CONSTANTS
// sha224sum 'struct ContractInstanceDeployed'
global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631;
global DEPLOYER_CONTRACT_ADDRESS = 0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78;
global DEPLOYER_CONTRACT_ADDRESS = 0x078147c1cf4a0d256b55f090ccfd831daa056f9c8aee8dbd5f48235720cf3315;

// NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts
// Some are defined here because Noir doesn't yet support globals referencing other globals yet.
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/archiver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@aztec/types": "workspace:^",
"debug": "^4.3.4",
"lmdb": "^2.9.2",
"lodash.groupby": "^4.6.0",
"lodash.omit": "^4.5.0",
"tsc-watch": "^6.0.0",
"tslib": "^2.5.0",
Expand All @@ -55,6 +56,7 @@
"@jest/globals": "^29.5.0",
"@types/debug": "^4.1.7",
"@types/jest": "^29.5.0",
"@types/lodash.groupby": "^4.6.9",
"@types/lodash.omit": "^4.5.7",
"@types/node": "^18.15.11",
"@types/ws": "^8.5.4",
Expand Down
47 changes: 35 additions & 12 deletions yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import {
UnencryptedL2Log,
} from '@aztec/circuit-types';
import { ContractClassRegisteredEvent, FunctionSelector } from '@aztec/circuits.js';
import { ContractInstanceDeployedEvent } from '@aztec/circuits.js/contract';
import {
ContractInstanceDeployedEvent,
PrivateFunctionBroadcastedEvent,
isValidPrivateFunctionMembershipProof,
} from '@aztec/circuits.js/contract';
import { createEthereumChain } from '@aztec/ethereum';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { EthAddress } from '@aztec/foundation/eth-address';
Expand All @@ -28,6 +32,7 @@ import {
PublicFunction,
} from '@aztec/types/contracts';

import groupBy from 'lodash.groupby';
import { Chain, HttpTransport, PublicClient, createPublicClient, http } from 'viem';

import { ArchiverDataStore } from './archiver_store.js';
Expand Down Expand Up @@ -55,11 +60,6 @@ export class Archiver implements ArchiveSource {
*/
private runningPromise?: RunningPromise;

/**
* Use this to track logged block in order to avoid repeating the same message.
*/
private lastLoggedL1BlockNumber = 0n;

/**
* Creates a new instance of the Archiver.
* @param publicClient - A client for interacting with the Ethereum node.
Expand Down Expand Up @@ -241,14 +241,14 @@ export class Archiver implements ArchiveSource {

if (blocks.length === 0) {
return;
} else {
this.log(
`Retrieved ${blocks.length} new L2 blocks between L1 blocks ${
lastL1Blocks.blocks + 1n
} and ${currentL1BlockNumber}.`,
);
}

this.log(
`Retrieved ${blocks.length} new L2 blocks between L1 blocks ${
lastL1Blocks.blocks + 1n
} and ${currentL1BlockNumber}.`,
);

retrievedBlocks = {
lastProcessedL1BlockNumber: retrievedBlockMetadata.lastProcessedL1BlockNumber,
retrievedData: blocks,
Expand All @@ -273,6 +273,7 @@ export class Archiver implements ArchiveSource {
.map(log => UnencryptedL2Log.fromBuffer(log));
await this.storeRegisteredContractClasses(blockLogs, block.number);
await this.storeDeployedContractInstances(blockLogs, block.number);
await this.storeBroadcastedIndividualFunctions(blockLogs, block.number);
}),
);

Expand Down Expand Up @@ -305,6 +306,28 @@ export class Archiver implements ArchiveSource {
}
}

private async storeBroadcastedIndividualFunctions(allLogs: UnencryptedL2Log[], _blockNum: number) {
const events = PrivateFunctionBroadcastedEvent.fromLogs(allLogs, ClassRegistererAddress);
for (const [classIdString, classEvents] of Object.entries(groupBy(events, e => e.contractClassId.toString()))) {
const contractClassId = Fr.fromString(classIdString);
const contractClass = await this.store.getContractClass(contractClassId);
if (!contractClass) {
this.log.warn(`Skipping private functions as contract class ${contractClassId.toString()} was not found`);
continue;
}
const validFns = classEvents
.map(e => e.toExecutableFunctionWithMembershipProof())
.filter(fn => isValidPrivateFunctionMembershipProof(fn, contractClass));
if (validFns.length !== classEvents.length) {
this.log.warn(`Skipping ${classEvents.length - validFns.length} invalid private functions`);
}
if (validFns.length > 0) {
this.log(`Storing ${validFns.length} private functions for contract class ${contractClassId.toString()}`);
}
await this.store.addPrivateFunctions(contractClassId, validFns);
}
}

/**
* Stops the archiver.
* @returns A promise signalling completion of the stop process.
Expand Down
14 changes: 13 additions & 1 deletion yarn-project/archiver/src/archiver/archiver_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
} from '@aztec/circuit-types';
import { Fr } from '@aztec/circuits.js';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts';
import {
ContractClassPublic,
ContractInstanceWithAddress,
ExecutablePrivateFunctionWithMembershipProof,
} from '@aztec/types/contracts';

import { DataRetrieval } from './data_retrieval.js';

Expand Down Expand Up @@ -158,6 +162,14 @@ export interface ArchiverDataStore {
*/
addContractInstances(data: ContractInstanceWithAddress[], blockNumber: number): Promise<boolean>;

/**
* Adds private functions to a contract class.
*/
addPrivateFunctions(
contractClassId: Fr,
privateFunctions: ExecutablePrivateFunctionWithMembershipProof[],
): Promise<boolean>;

/**
* Returns a contract instance given its address, or undefined if not exists.
* @param address - Address of the contract.
Expand Down
18 changes: 17 additions & 1 deletion yarn-project/archiver/src/archiver/archiver_store_test_suite.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { InboxLeaf, L2Block, L2BlockContext, LogId, LogType, TxHash, UnencryptedL2Log } from '@aztec/circuit-types';
import '@aztec/circuit-types/jest';
import { AztecAddress, Fr, INITIAL_L2_BLOCK_NUM, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js';
import { makeContractClassPublic } from '@aztec/circuits.js/testing';
import { makeContractClassPublic, makeExecutablePrivateFunctionWithMembershipProof } from '@aztec/circuits.js/testing';
import { times } from '@aztec/foundation/collection';
import { randomBytes, randomInt } from '@aztec/foundation/crypto';
import { ContractClassPublic, ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts';

Expand Down Expand Up @@ -242,6 +243,21 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
it('returns undefined if contract class is not found', async () => {
await expect(store.getContractClass(Fr.random())).resolves.toBeUndefined();
});

it('adds new private functions', async () => {
const fns = times(3, makeExecutablePrivateFunctionWithMembershipProof);
await store.addPrivateFunctions(contractClass.id, fns);
const stored = await store.getContractClass(contractClass.id);
expect(stored?.privateFunctions).toEqual(fns);
});

it('does not duplicate private functions', async () => {
const fns = times(3, makeExecutablePrivateFunctionWithMembershipProof);
await store.addPrivateFunctions(contractClass.id, fns.slice(0, 1));
await store.addPrivateFunctions(contractClass.id, fns);
const stored = await store.getContractClass(contractClass.id);
expect(stored?.privateFunctions).toEqual(fns);
});
});

describe('getUnencryptedLogs', () => {
Expand Down
Loading

0 comments on commit 516576f

Please sign in to comment.