Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bf362b8
First set of stats
PhilWindle Nov 21, 2024
759143b
WIP
PhilWindle Nov 21, 2024
c52e2fd
WIP
PhilWindle Nov 22, 2024
3c8e324
WIP
PhilWindle Nov 22, 2024
7d46400
WIP
PhilWindle Nov 23, 2024
2843505
WIP
PhilWindle Nov 23, 2024
0da28dc
WIP
PhilWindle Nov 24, 2024
b9dc6ac
WIP
PhilWindle Nov 24, 2024
92cdace
Merge remote-tracking branch 'origin/master' into pw/check-times-2
PhilWindle Nov 24, 2024
a0c21fc
WIP
PhilWindle Nov 25, 2024
f932cf3
Formatting
PhilWindle Nov 25, 2024
05159b8
Keep instruction set iniitialisation within AVM simulator
PhilWindle Nov 25, 2024
d01a9e3
Function bind fixes
PhilWindle Nov 25, 2024
95adcfc
Merge remote-tracking branch 'origin/master' into pw/check-times-2
PhilWindle Nov 25, 2024
3b73deb
Merge remote-tracking branch 'origin/master' into pw/check-times-2
PhilWindle Nov 25, 2024
8455cbf
New test
PhilWindle Nov 25, 2024
57f5749
Test fixes
PhilWindle Nov 25, 2024
0cc95a4
Test fixes
PhilWindle Nov 26, 2024
3e5c8c5
Review fixes
PhilWindle Nov 26, 2024
332894f
Review fixes
PhilWindle Nov 26, 2024
41bca92
Merge branch 'master' into pw/check-times-2
PhilWindle Nov 26, 2024
a5e9c16
Also process world state errors on the job queue
PhilWindle Nov 26, 2024
cd6ba1c
Merge branch 'pw/check-times-2' of github.com:AztecProtocol/aztec-pac…
PhilWindle Nov 26, 2024
98b957d
Test fix
PhilWindle Nov 26, 2024
9439407
Updated comment
PhilWindle Nov 26, 2024
ae26b46
Merge branch 'pw/check-times-2' of github.com:AztecProtocol/aztec-pac…
PhilWindle Nov 26, 2024
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
14 changes: 14 additions & 0 deletions barretenberg/cpp/src/barretenberg/crypto/poseidon2/c_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,17 @@ WASM_EXPORT void poseidon2_permutation(fr::vec_in_buf inputs_buffer, fr::vec_out
const std::vector<fr> results(results_array.begin(), results_array.end());
*output = to_heap_buffer(results);
}

WASM_EXPORT void poseidon2_hash_accumulate(fr::vec_in_buf inputs_buffer, fr::out_buf output)
{
std::vector<fr> to_hash;
read(inputs_buffer, to_hash);
const size_t numHashes = to_hash.size();
fr result = 0;
size_t count = 0;
while (count < numHashes) {
result = crypto::Poseidon2<crypto::Poseidon2Bn254ScalarFieldParams>::hash({ to_hash[count], result });
++count;
}
write(output, result);
}
12 changes: 12 additions & 0 deletions barretenberg/ts/src/barretenberg_api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,18 @@ export class BarretenbergApiSync {
return out[0];
}

poseidon2HashAccumulate(inputsBuffer: Fr[]): Fr {
const inArgs = [inputsBuffer].map(serializeBufferable);
const outTypes: OutputType[] = [Fr];
const result = this.wasm.callWasmExport(
'poseidon2_hash_accumulate',
inArgs,
outTypes.map(t => t.SIZE_IN_BYTES),
);
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out[0];
}

poseidon2Hashes(inputsBuffer: Fr[]): Fr {
const inArgs = [inputsBuffer].map(serializeBufferable);
const outTypes: OutputType[] = [Fr];
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@
"rollups",
"rushstack",
"sanitise",
"sanitised",
"schnorr",
"secp",
"SEMRESATTRS",
Expand Down
36 changes: 32 additions & 4 deletions yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
type PublicFunction,
UnconstrainedFunctionBroadcastedEvent,
type UnconstrainedFunctionWithMembershipProof,
computePublicBytecodeCommitment,
isValidPrivateFunctionMembershipProof,
isValidUnconstrainedFunctionMembershipProof,
} from '@aztec/circuits.js';
Expand Down Expand Up @@ -706,6 +707,10 @@ export class Archiver implements ArchiveSource {
return this.store.getContractClass(id);
}

public getBytecodeCommitment(id: Fr): Promise<Fr | undefined> {
return this.store.getBytecodeCommitment(id);
}

public getContract(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
return this.store.getContractInstance(address);
}
Expand Down Expand Up @@ -734,7 +739,11 @@ export class Archiver implements ArchiveSource {

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

Expand All @@ -746,6 +755,10 @@ export class Archiver implements ArchiveSource {
return this.store.getContractArtifact(address);
}

getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
return this.store.getContractFunctionName(address, selector);
}

async getL2Tips(): Promise<L2Tips> {
const [latestBlockNumber, provenBlockNumber] = await Promise.all([
this.getBlockNumber(),
Expand Down Expand Up @@ -804,8 +817,12 @@ 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);
addContractClasses(
contractClasses: ContractClassPublic[],
bytecodeCommitments: Fr[],
blockNum: number,
): Promise<boolean> {
return this.store.addContractClasses(contractClasses, bytecodeCommitments, blockNum);
}

/**
Expand All @@ -820,7 +837,12 @@ class ArchiverStoreHelper
if (contractClasses.length > 0) {
contractClasses.forEach(c => this.#log.verbose(`Registering contract class ${c.id.toString()}`));
if (operation == Operation.Store) {
return await this.store.addContractClasses(contractClasses, blockNum);
// TODO: Will probably want to create some worker threads to compute these bytecode commitments as they are expensive
return await this.store.addContractClasses(
contractClasses,
contractClasses.map(x => computePublicBytecodeCommitment(x.packedBytecode)),
blockNum,
);
} else if (operation == Operation.Delete) {
return await this.store.deleteContractClasses(contractClasses, blockNum);
}
Expand Down Expand Up @@ -1028,6 +1050,9 @@ class ArchiverStoreHelper
getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
return this.store.getContractClass(id);
}
getBytecodeCommitment(contractClassId: Fr): Promise<Fr | undefined> {
return this.store.getBytecodeCommitment(contractClassId);
}
Comment on lines +1053 to +1055

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there are any cases where we want the bytecode commitment but not the bytecode, right? If so, instead of having a separate getter for the bytecode commitment, I'd just store it along with the rest of the contract class in the same store, so we don't have to query for them separately. But this is just a cleanup, no need to do now.

getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
return this.store.getContractInstance(address);
}
Expand All @@ -1040,6 +1065,9 @@ class ArchiverStoreHelper
getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined> {
return this.store.getContractArtifact(address);
}
getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
return this.store.getContractFunctionName(address, selector);
}
getTotalL1ToL2MessageCount(): Promise<bigint> {
return this.store.getTotalL1ToL2MessageCount();
}
Expand Down
11 changes: 9 additions & 2 deletions yarn-project/archiver/src/archiver/archiver_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
type Header,
type UnconstrainedFunctionWithMembershipProof,
} from '@aztec/circuits.js';
import { type ContractArtifact } from '@aztec/foundation/abi';
import { type ContractArtifact, type FunctionSelector } from '@aztec/foundation/abi';
import { type AztecAddress } from '@aztec/foundation/aztec-address';

import { type DataRetrieval } from './structs/data_retrieval.js';
Expand Down Expand Up @@ -229,10 +229,12 @@ export interface ArchiverDataStore {
* @param blockNumber - Number of the L2 block the contracts were registered in.
* @returns True if the operation is successful.
*/
addContractClasses(data: ContractClassPublic[], blockNumber: number): Promise<boolean>;
addContractClasses(data: ContractClassPublic[], bytecodeCommitments: Fr[], blockNumber: number): Promise<boolean>;

deleteContractClasses(data: ContractClassPublic[], blockNumber: number): Promise<boolean>;

getBytecodeCommitment(contractClassId: Fr): Promise<Fr | undefined>;

/**
* Returns a contract class given its id, or undefined if not exists.
* @param id - Id of the contract class.
Expand Down Expand Up @@ -269,6 +271,11 @@ export interface ArchiverDataStore {
addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void>;
getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined>;

// TODO: These function names are in memory only as they are for development/debugging. They require the full contract
// artifact supplied to the node out of band. This should be reviewed and potentially removed as part of
// the node api cleanup process.
getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;

/**
* Estimates the size of the store in bytes.
*/
Expand Down
13 changes: 11 additions & 2 deletions yarn-project/archiver/src/archiver/archiver_store_test_suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
L1_TO_L2_MSG_SUBTREE_HEIGHT,
MAX_NULLIFIERS_PER_TX,
SerializableContractInstance,
computePublicBytecodeCommitment,
} from '@aztec/circuits.js';
import {
makeContractClassPublic,
Expand Down Expand Up @@ -310,7 +311,11 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch

beforeEach(async () => {
contractClass = makeContractClassPublic();
await store.addContractClasses([contractClass], blockNum);
await store.addContractClasses(
[contractClass],
[computePublicBytecodeCommitment(contractClass.packedBytecode)],
blockNum,
);
});

it('returns previously stored contract class', async () => {
Expand All @@ -323,7 +328,11 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
});

it('returns contract class if later "deployment" class was deleted', async () => {
await store.addContractClasses([contractClass], blockNum + 1);
await store.addContractClasses(
[contractClass],
[computePublicBytecodeCommitment(contractClass.packedBytecode)],
blockNum + 1,
);
await store.deleteContractClasses([contractClass], blockNum + 1);
await expect(store.getContractClass(contractClass.id)).resolves.toMatchObject(contractClass);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,30 @@ import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
*/
export class ContractClassStore {
#contractClasses: AztecMap<string, Buffer>;
#bytecodeCommitments: AztecMap<string, Buffer>;

constructor(private db: AztecKVStore) {
this.#contractClasses = db.openMap('archiver_contract_classes');
this.#bytecodeCommitments = db.openMap('archiver_bytecode_commitments');
}

async addContractClass(contractClass: ContractClassPublic, blockNumber: number): Promise<void> {
async addContractClass(
contractClass: ContractClassPublic,
bytecodeCommitment: Fr,
blockNumber: number,
): Promise<void> {
await this.#contractClasses.setIfNotExists(
contractClass.id.toString(),
serializeContractClassPublic({ ...contractClass, l2BlockNumber: blockNumber }),
);
await this.#bytecodeCommitments.setIfNotExists(contractClass.id.toString(), bytecodeCommitment.toBuffer());
}

async deleteContractClasses(contractClass: ContractClassPublic, blockNumber: number): Promise<void> {
const restoredContractClass = this.#contractClasses.get(contractClass.id.toString());
if (restoredContractClass && deserializeContractClassPublic(restoredContractClass).l2BlockNumber >= blockNumber) {
await this.#contractClasses.delete(contractClass.id.toString());
await this.#bytecodeCommitments.delete(contractClass.id.toString());
}
}

Expand All @@ -39,6 +47,11 @@ export class ContractClassStore {
return contractClass && { ...deserializeContractClassPublic(contractClass), id };
}

getBytecodeCommitment(id: Fr): Fr | undefined {
const value = this.#bytecodeCommitments.get(id.toString());
return value === undefined ? undefined : Fr.fromBuffer(value);
}

getContractClassIds(): Fr[] {
return Array.from(this.#contractClasses.keys()).map(key => Fr.fromString(key));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
type Header,
type UnconstrainedFunctionWithMembershipProof,
} from '@aztec/circuits.js';
import { type ContractArtifact } from '@aztec/foundation/abi';
import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi';
import { type AztecAddress } from '@aztec/foundation/aztec-address';
import { createDebugLogger } from '@aztec/foundation/log';
import { type AztecKVStore } from '@aztec/kv-store';
Expand All @@ -46,6 +46,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
#contractClassStore: ContractClassStore;
#contractInstanceStore: ContractInstanceStore;
#contractArtifactStore: ContractArtifactsStore;
private functionNames = new Map<string, string>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be persisted, as opposed to an in-memory Map? If we do it memory-only as a cache, then the getter should recalculate it on a miss.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed. These are currently in memory only as they are a debugging feature that is perhaps not a full feature of the node or it's api. I've commented that this needs to be reviewed along with other similar features.


#log = createDebugLogger('aztec:archiver:data-store');

Expand All @@ -63,8 +64,19 @@ export class KVArchiverDataStore implements ArchiverDataStore {
return Promise.resolve(this.#contractArtifactStore.getContractArtifact(address));
}

addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void> {
return this.#contractArtifactStore.addContractArtifact(address, contract);
// TODO: These function names are in memory only as they are for development/debugging. They require the full contract
// artifact supplied to the node out of band. This should be reviewed and potentially removed as part of
// the node api cleanup process.
getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
return Promise.resolve(this.functionNames.get(selector.toString()));
}

async addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void> {
await this.#contractArtifactStore.addContractArtifact(address, contract);
// Building tup this map of selectors to function names save expensive re-hydration of contract artifacts later
contract.functions.forEach(f => {
this.functionNames.set(FunctionSelector.fromNameAndParameters(f.name, f.parameters).toString(), f.name);
});
Comment on lines +77 to +79

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause issues down the road with selector clashes. A selector is just 4 bytes (we're borrowing this from Ethereum), so it's relatively easy to stumble upon a collision. Indexing the functionNames collection by selector only will mean that the most recently stored selector will overwrite any previous ones.

Unfortunately, I think the only recourse is to store both contract class id and selector as key.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun fact: proxies built using the DELEGATECALL pattern in Ethereum were subject to a vulnerability caused by selector clashing.

https://forum.openzeppelin.com/t/beware-of-the-proxy-learn-how-to-exploit-function-clashing/1070

}

getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
Expand All @@ -76,11 +88,20 @@ export class KVArchiverDataStore implements ArchiverDataStore {
}

getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
return Promise.resolve(this.#contractInstanceStore.getContractInstance(address));
const contract = this.#contractInstanceStore.getContractInstance(address);
return Promise.resolve(contract);
}

async addContractClasses(data: ContractClassPublic[], blockNumber: number): Promise<boolean> {
return (await Promise.all(data.map(c => this.#contractClassStore.addContractClass(c, blockNumber)))).every(Boolean);
async addContractClasses(
data: ContractClassPublic[],
bytecodeCommitments: Fr[],
blockNumber: number,
): Promise<boolean> {
return (
await Promise.all(
data.map((c, i) => this.#contractClassStore.addContractClass(c, bytecodeCommitments[i], blockNumber)),
)
).every(Boolean);
}

async deleteContractClasses(data: ContractClassPublic[], blockNumber: number): Promise<boolean> {
Expand All @@ -89,6 +110,10 @@ export class KVArchiverDataStore implements ArchiverDataStore {
);
}

getBytecodeCommitment(contractClassId: Fr): Promise<Fr | undefined> {
return Promise.resolve(this.#contractClassStore.getBytecodeCommitment(contractClassId));
}

addFunctions(
contractClassId: Fr,
privateFunctions: ExecutablePrivateFunctionWithMembershipProof[],
Expand Down
Loading