Skip to content

Commit

Permalink
feat: Capture broadcasted functions in node (#5353)
Browse files Browse the repository at this point in the history
Includes:
- #5351
- #5350
- #5349
- #5318
- And deletes isInternal flag from functions in contract classes since
it's no longer required by kernel.
  • Loading branch information
spalladino authored Mar 22, 2024
1 parent 060fa1e commit bc05db2
Show file tree
Hide file tree
Showing 77 changed files with 1,512 additions and 272 deletions.
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

0 comments on commit bc05db2

Please sign in to comment.