Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Capture broadcasted functions in node #5353

Merged
merged 8 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ 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_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 12;
uint256 internal constant REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE =
0x6999d1e02b08a447a463563453cb36919c9dd7150336fc7c4d2b52f8;
uint256 internal constant REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE =
Expand All @@ -89,7 +91,7 @@ library Constants {
uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE =
0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631;
uint256 internal constant DEPLOYER_CONTRACT_ADDRESS =
0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78;
0x127a8fd1a31888ccd00c88d84b93474449bb6683197083e1727dd02ab6803c6c;
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 @@ -4,9 +4,10 @@ use dep::aztec::protocol_types::{
contract_class_id::ContractClassId,
constants::{
ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS,
REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE
REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE,
REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS
},
traits::{Serialize}
traits::Serialize
};

struct UnconstrainedFunction {
Expand All @@ -33,22 +34,24 @@ struct ClassUnconstrainedFunctionBroadcasted {
artifact_metadata_hash: Field,
private_functions_artifact_tree_root: Field,
artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT],
artifact_function_tree_leaf_index: Field,
function: UnconstrainedFunction
}

impl Serialize<MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 11> for ClassUnconstrainedFunctionBroadcasted {
fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 11] {
let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 11];
impl Serialize<MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS> for ClassUnconstrainedFunctionBroadcasted {
fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS] {
let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS];
packed[0] = REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE;
packed[1] = self.contract_class_id.to_field();
packed[2] = self.artifact_metadata_hash;
packed[3] = self.private_functions_artifact_tree_root;
for i in 0..ARTIFACT_FUNCTION_TREE_MAX_HEIGHT {
packed[i + 4] = self.artifact_function_tree_sibling_path[i];
}
packed[4 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT] = self.artifact_function_tree_leaf_index;
let packed_function = self.function.serialize();
for i in 0..MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 2 {
packed[i + 4 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT] = packed_function[i];
packed[i + 5 + ARTIFACT_FUNCTION_TREE_MAX_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 All @@ -90,13 +94,15 @@ contract ContractClassRegisterer {
artifact_metadata_hash: Field,
private_functions_artifact_tree_root: Field,
artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT],
artifact_function_tree_leaf_index: Field,
function_data: UnconstrainedFunction
) {
let event = ClassUnconstrainedFunctionBroadcasted {
contract_class_id,
artifact_metadata_hash,
private_functions_artifact_tree_root,
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 @@ -111,9 +111,13 @@ 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;
// How many fields are on the serialized ClassUnconstrainedFunctionBroadcasted event in addition to MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS.
global REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS: u64 = 12;
// 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 @@ -126,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 = 0x127a8fd1a31888ccd00c88d84b93474449bb6683197083e1727dd02ab6803c6c;

// 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
1 change: 1 addition & 0 deletions yarn-project/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ scripts/tmp
noir-contracts.js/src
noir-contracts.js/artifacts/
noir-contracts.js/codegenCache.json
types/fixtures/*.json

.yarn/*
!.yarn/patches
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
61 changes: 55 additions & 6 deletions yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ import {
UnencryptedL2Log,
} from '@aztec/circuit-types';
import { ContractClassRegisteredEvent, FunctionSelector } from '@aztec/circuits.js';
import { ContractInstanceDeployedEvent } from '@aztec/circuits.js/contract';
import {
ContractInstanceDeployedEvent,
PrivateFunctionBroadcastedEvent,
UnconstrainedFunctionBroadcastedEvent,
isValidPrivateFunctionMembershipProof,
isValidUnconstrainedFunctionMembershipProof,
} 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 @@ -25,9 +31,12 @@ import {
ContractClassPublic,
ContractDataSource,
ContractInstanceWithAddress,
ExecutablePrivateFunctionWithMembershipProof,
PublicFunction,
UnconstrainedFunctionWithMembershipProof,
} 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 +64,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 @@ -276,6 +280,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 @@ -308,6 +313,50 @@ export class Archiver implements ArchiveSource {
}
}

private async storeBroadcastedIndividualFunctions(allLogs: UnencryptedL2Log[], _blockNum: number) {
// Filter out private and unconstrained function broadcast events
const privateFnEvents = PrivateFunctionBroadcastedEvent.fromLogs(allLogs, getCanonicalClassRegistererAddress());
const unconstrainedFnEvents = UnconstrainedFunctionBroadcastedEvent.fromLogs(
allLogs,
getCanonicalClassRegistererAddress(),
);

// Group all events by contract class id
for (const [classIdString, classEvents] of Object.entries(
groupBy([...privateFnEvents, ...unconstrainedFnEvents], e => e.contractClassId.toString()),
)) {
const contractClassId = Fr.fromString(classIdString);
const contractClass = await this.store.getContractClass(contractClassId);
if (!contractClass) {
this.log.warn(`Skipping broadcasted functions as contract class ${contractClassId.toString()} was not found`);
continue;
}

// Split private and unconstrained functions, and filter out invalid ones
const allFns = classEvents.map(e => e.toFunctionWithMembershipProof());
const privateFns = allFns.filter(
(fn): fn is ExecutablePrivateFunctionWithMembershipProof => 'unconstrainedFunctionsArtifactTreeRoot' in fn,
);
const unconstrainedFns = allFns.filter(
(fn): fn is UnconstrainedFunctionWithMembershipProof => 'privateFunctionsArtifactTreeRoot' in fn,
);
const validPrivateFns = privateFns.filter(fn => isValidPrivateFunctionMembershipProof(fn, contractClass));
const validUnconstrainedFns = unconstrainedFns.filter(fn =>
isValidUnconstrainedFunctionMembershipProof(fn, contractClass),
);
const validFnCount = validPrivateFns.length + validUnconstrainedFns.length;
if (validFnCount !== allFns.length) {
this.log.warn(`Skipping ${allFns.length - validFnCount} invalid functions`);
}

// Store the functions in the contract class in a single operation
if (validFnCount > 0) {
this.log(`Storing ${validFnCount} functions for contract class ${contractClassId.toString()}`);
}
await this.store.addFunctions(contractClassId, validPrivateFns, validUnconstrainedFns);
}
}

/**
* Stops the archiver.
* @returns A promise signalling completion of the stop process.
Expand Down
16 changes: 15 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,12 @@ 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,
UnconstrainedFunctionWithMembershipProof,
} from '@aztec/types/contracts';

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

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

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

/**
* Returns a contract instance given its address, or undefined if not exists.
* @param address - Address of the contract.
Expand Down
37 changes: 36 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,12 @@
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,
makeUnconstrainedFunctionWithMembershipProof,
} 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 +247,36 @@ 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.addFunctions(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.addFunctions(contractClass.id, fns.slice(0, 1), []);
await store.addFunctions(contractClass.id, fns, []);
const stored = await store.getContractClass(contractClass.id);
expect(stored?.privateFunctions).toEqual(fns);
});

it('adds new unconstrained functions', async () => {
const fns = times(3, makeUnconstrainedFunctionWithMembershipProof);
await store.addFunctions(contractClass.id, [], fns);
const stored = await store.getContractClass(contractClass.id);
expect(stored?.unconstrainedFunctions).toEqual(fns);
});

it('does not duplicate unconstrained functions', async () => {
const fns = times(3, makeUnconstrainedFunctionWithMembershipProof);
await store.addFunctions(contractClass.id, [], fns.slice(0, 1));
await store.addFunctions(contractClass.id, [], fns);
const stored = await store.getContractClass(contractClass.id);
expect(stored?.unconstrainedFunctions).toEqual(fns);
});
});

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