Skip to content
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
3 changes: 2 additions & 1 deletion circuits/cpp/src/aztec3/circuits/kernel/private/c_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ WASM_EXPORT size_t private_kernel__sim(uint8_t const* signed_tx_request_buf,
previous_kernel.public_inputs.end.private_call_stack[0] = private_call_data.call_stack_item.hash();
previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root =
private_call_data.call_stack_item.public_inputs.historic_private_data_tree_root;
// previous_kernel.public_inputs.constants.historic_tree_roots.nullifier_tree_root =
previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots.nullifier_tree_root =
private_call_data.call_stack_item.public_inputs.historic_nullifier_tree_root;
previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots.contract_tree_root =
private_call_data.call_stack_item.public_inputs.historic_contract_tree_root;
// previous_kernel.public_inputs.constants.historic_tree_roots.private_kernel_vk_tree_root =
Expand Down
33 changes: 24 additions & 9 deletions yarn-project/aztec-node/src/aztec-node/aztec-node.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { Archiver } from '@aztec/archiver';
import { PrimitivesWasm } from '@aztec/barretenberg.js/wasm';
import { CircuitsWasm } from '@aztec/circuits.js';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { Fr } from '@aztec/foundation/fields';
import { SiblingPath } from '@aztec/merkle-tree';
import { P2P, P2PClient } from '@aztec/p2p';
import { SequencerClient, getCombinedHistoricTreeRoots } from '@aztec/sequencer-client';
import { SequencerClient } from '@aztec/sequencer-client';
import {
ContractData,
ContractDataSource,
ContractPublicData,
L2Block,
L2BlockSource,
MerkleTreeId,
Tx,
TxHash,
UnverifiedData,
UnverifiedDataSource,
} from '@aztec/types';
import {
MerkleTreeId,
MerkleTrees,
ServerWorldStateSynchroniser,
WorldStateSynchroniser,
Expand All @@ -25,8 +27,6 @@ import {
import { default as levelup } from 'levelup';
import { MemDown, default as memdown } from 'memdown';
import { AztecNodeConfig } from './config.js';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { Fr } from '@aztec/foundation/fields';

export const createMemDown = () => (memdown as any)() as MemDown<any, any>;

Expand Down Expand Up @@ -130,11 +130,6 @@ export class AztecNode {
* @param tx - The transaction to be submitted.
*/
public async sendTx(tx: Tx) {
// TODO: Patch tx to inject historic tree roots until the private kernel circuit supplies this value
if (tx.isPrivate() && tx.data.constants.historicTreeRoots.privateHistoricTreeRoots.isEmpty()) {
tx.data.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(this.merkleTreeDB.asLatest());
}

await this.p2pClient!.sendTx(tx);
}

Expand Down Expand Up @@ -189,4 +184,24 @@ export class AztecNode {
const leafIndex = computePublicDataTreeLeafIndex(contract, new Fr(slot), await PrimitivesWasm.get());
return this.merkleTreeDB.getLeafValue(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex, false);
}

/**
* Returns the current committed roots for the data trees.
* @returns the current committed roots for the data trees.
*/
public async getTreeRoots(): Promise<Record<MerkleTreeId, Fr>> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This information is actually already available within the AztecRPCServer as part of the L2Block download. I know we are building the Aztec Sandbox but there will come a point where we want to rely on Aztec Node for data as little as possible, so I wonder if it is worth removing this interaction in favour of taking the locally available version?

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.

Ah, I didn't know that! It makes a lot more sense. I'll add methods to the aztec-rpc Synchroniser to save in memory the latest roots and use those!

const getTreeRoot = async (id: MerkleTreeId) =>
Fr.fromBuffer((await this.merkleTreeDB.getTreeInfo(id, false)).root);

return {
[MerkleTreeId.CONTRACT_TREE]: await getTreeRoot(MerkleTreeId.CONTRACT_TREE),
[MerkleTreeId.PRIVATE_DATA_TREE]: await getTreeRoot(MerkleTreeId.PRIVATE_DATA_TREE),
[MerkleTreeId.NULLIFIER_TREE]: await getTreeRoot(MerkleTreeId.NULLIFIER_TREE),
[MerkleTreeId.PUBLIC_DATA_TREE]: await getTreeRoot(MerkleTreeId.PUBLIC_DATA_TREE),
[MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: await getTreeRoot(MerkleTreeId.L1_TO_L2_MESSAGES_TREE),
[MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]: await getTreeRoot(MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE),
[MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]: await getTreeRoot(MerkleTreeId.CONTRACT_TREE_ROOTS_TREE),
[MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]: await getTreeRoot(MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE),
};
}
}
25 changes: 17 additions & 8 deletions yarn-project/aztec-rpc/src/account_state/account_state.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { AcirSimulator } from '@aztec/acir-simulator';
import { AztecNode } from '@aztec/aztec-node';
import { Grumpkin } from '@aztec/barretenberg.js/crypto';
import { BarretenbergWasm } from '@aztec/barretenberg.js/wasm';
import { EcdsaSignature, KERNEL_NEW_COMMITMENTS_LENGTH, PrivateHistoricTreeRoots, TxRequest } from '@aztec/circuits.js';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { Fr, Point } from '@aztec/foundation/fields';
import { createDebugLogger } from '@aztec/foundation/log';
import { KernelProver, OutputNoteData } from '@aztec/kernel-prover';
import { EncodedContractFunction, INITIAL_L2_BLOCK_NUM, L2BlockContext, Tx, UnverifiedData } from '@aztec/types';
import { INITIAL_L2_BLOCK_NUM } from '@aztec/types';
import { FunctionType } from '@aztec/noir-contracts';
import { EncodedContractFunction, L2BlockContext, Tx, UnverifiedData } from '@aztec/types';
import { MerkleTreeId } from '@aztec/types';
import { NotePreimage, TxAuxData } from '../aztec_rpc_server/tx_aux_data/index.js';
import { ContractDataOracle } from '../contract_data_oracle/index.js';
import { Database, TxAuxDataDao, TxDao } from '../database/index.js';
import { generateFunctionSelector } from '../index.js';
import { ConstantKeyPair, KeyPair } from '../key_store/index.js';
import { SimulatorOracle } from '../simulator_oracle/index.js';
import { BarretenbergWasm } from '@aztec/barretenberg.js/wasm';
import { FunctionType } from '@aztec/noir-contracts';
import { generateFunctionSelector } from '../index.js';
import { Fr, Point } from '@aztec/foundation/fields';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { createDebugLogger } from '@aztec/foundation/log';

export class AccountState {
public syncedToBlock = 0;
Expand Down Expand Up @@ -66,7 +68,14 @@ export class AccountState {
txRequest.functionData.functionSelector,
);
const portalContract = await contractDataOracle.getPortalContractAddress(contractAddress);
const historicRoots = new PrivateHistoricTreeRoots(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); // TODO - get old roots from the database/node

const currentRoots = await this.db.getTreeRoots();
const historicRoots = PrivateHistoricTreeRoots.from({
contractTreeRoot: currentRoots[MerkleTreeId.CONTRACT_TREE],
nullifierTreeRoot: currentRoots[MerkleTreeId.NULLIFIER_TREE],
privateDataTreeRoot: currentRoots[MerkleTreeId.PRIVATE_DATA_TREE],
privateKernelVkTreeRoot: Fr.ZERO,
});

return {
contractAddress,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class AztecRPCServer implements AztecRPCClient {
for (const account of accounts) {
await this.initAccountState(account);
}
this.synchroniser.start();
await this.synchroniser.start();
this.log(`Started. ${accounts.length} initial accounts.`);
}

Expand Down
4 changes: 4 additions & 0 deletions yarn-project/aztec-rpc/src/database/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TxAuxDataDao } from './tx_aux_data_dao.js';
import { TxDao } from './tx_dao.js';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { Fr, Point } from '@aztec/foundation/fields';
import { MerkleTreeId } from '@aztec/types';

export interface Database extends ContractDatabase {
getTx(txHash: TxHash): Promise<TxDao | undefined>;
Expand All @@ -15,4 +16,7 @@ export interface Database extends ContractDatabase {
addTxAuxData(txAuxDataDao: TxAuxDataDao): Promise<void>;
addTxAuxDataBatch(txAuxDataDaos: TxAuxDataDao[]): Promise<void>;
removeNullifiedTxAuxData(nullifiers: Fr[], account: Point): Promise<TxAuxDataDao[]>;

getTreeRoots(): Promise<Record<MerkleTreeId, Fr>>;
setTreeRoots(roots: Record<MerkleTreeId, Fr>): Promise<void>;
}
13 changes: 13 additions & 0 deletions yarn-project/aztec-rpc/src/database/memory_db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { TxAuxDataDao } from './tx_aux_data_dao.js';
import { TxDao } from './tx_dao.js';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { Fr, Point } from '@aztec/foundation/fields';
import { MerkleTreeId } from '@aztec/types';

export class MemoryDB extends MemoryContractDatabase implements Database {
private txTable: TxDao[] = [];
private txAuxDataTable: TxAuxDataDao[] = [];
private treeRoots: Record<MerkleTreeId, Fr> | undefined;

public getTx(txHash: TxHash) {
return Promise.resolve(this.txTable.find(tx => tx.txHash.equals(txHash)));
Expand Down Expand Up @@ -69,4 +71,15 @@ export class MemoryDB extends MemoryContractDatabase implements Database {

return Promise.resolve(removed);
}

public getTreeRoots(): Promise<Record<MerkleTreeId, Fr>> {
const roots = this.treeRoots;
if (!roots) throw new Error(`Tree roots not set in memory database`);
return Promise.resolve(roots);
}

public setTreeRoots(roots: Record<MerkleTreeId, Fr>) {
this.treeRoots = roots;
return Promise.resolve();
}
}
87 changes: 82 additions & 5 deletions yarn-project/aztec-rpc/src/synchroniser/synchroniser.test.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
import { AztecNode } from '@aztec/aztec-node';
import { Grumpkin } from '@aztec/barretenberg.js/crypto';
import { mock } from 'jest-mock-extended';
import { MockProxy, mock } from 'jest-mock-extended';
import { Database, MemoryDB } from '../database/index.js';
import { ConstantKeyPair } from '../key_store/index.js';
import { Synchroniser } from './synchroniser.js';
import { L2Block, UnverifiedData } from '@aztec/types';
import { MerkleTreeId } from '@aztec/types';
import { Fr } from '@aztec/circuits.js';

describe('Synchroniser', () => {
let grumpkin: Grumpkin;
let aztecNode: ReturnType<typeof mock<AztecNode>>;
let aztecNode: MockProxy<AztecNode>;
let database: Database;
let synchroniser: Synchroniser;
let synchroniser: TestSynchroniser;
let roots: Record<MerkleTreeId, Fr>;

beforeAll(async () => {
grumpkin = await Grumpkin.new();
});

beforeEach(() => {
roots = {
[MerkleTreeId.CONTRACT_TREE]: Fr.random(),
[MerkleTreeId.PRIVATE_DATA_TREE]: Fr.random(),
[MerkleTreeId.NULLIFIER_TREE]: Fr.random(),
[MerkleTreeId.PUBLIC_DATA_TREE]: Fr.random(),
[MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: Fr.random(),
[MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]: Fr.random(),
[MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]: Fr.random(),
[MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]: Fr.random(),
};

aztecNode = mock<AztecNode>();
aztecNode.getUnverifiedData.mockResolvedValue([]);

database = new MemoryDB();

synchroniser = new Synchroniser(aztecNode, database);
synchroniser = new TestSynchroniser(aztecNode, database);
});

it('Should create account state', async () => {
it('should create account state', async () => {
const account = ConstantKeyPair.random(grumpkin);
const address = account.getPublicKey().toAddress();

Expand All @@ -32,4 +49,64 @@ describe('Synchroniser', () => {

expect(synchroniser.getAccount(address)!.getPublicKey()).toEqual(account.getPublicKey());
});

it('sets tree roots from aztec node on initial sync', async () => {
aztecNode.getBlockHeight.mockResolvedValue(3);
aztecNode.getTreeRoots.mockResolvedValue(roots);

await synchroniser.initialSync();

expect(await database.getTreeRoots()).toEqual(roots);
});

it('sets tree roots from latest block', async () => {
const block = L2Block.random(1, 4);

aztecNode.getBlocks.mockResolvedValue([block]);
aztecNode.getUnverifiedData.mockResolvedValue([UnverifiedData.random(4)]);

await synchroniser.work();

const roots = await database.getTreeRoots();
expect(roots[MerkleTreeId.CONTRACT_TREE]).toEqual(block.endContractTreeSnapshot.root);
});

it('overrides tree roots from initial sync once block height is larger', async () => {
// Initial sync is done on block with height 3
aztecNode.getBlockHeight.mockResolvedValue(3);
aztecNode.getTreeRoots.mockResolvedValue(roots);

await synchroniser.initialSync();
const roots0 = await database.getTreeRoots();
expect(roots0[MerkleTreeId.CONTRACT_TREE]).toEqual(roots[MerkleTreeId.CONTRACT_TREE]);

// We then process block with height 1, this should not change tree roots
const block1 = L2Block.random(1, 4);
aztecNode.getBlocks.mockResolvedValueOnce([block1]);
aztecNode.getUnverifiedData.mockResolvedValue([UnverifiedData.random(4)]);

await synchroniser.work();
const roots1 = await database.getTreeRoots();
expect(roots1[MerkleTreeId.CONTRACT_TREE]).toEqual(roots[MerkleTreeId.CONTRACT_TREE]);
expect(roots1[MerkleTreeId.CONTRACT_TREE]).not.toEqual(block1.endContractTreeSnapshot.root);

// But they should change when we process block with height 5
const block5 = L2Block.random(5, 4);
aztecNode.getBlocks.mockResolvedValueOnce([block5]);

await synchroniser.work();
const roots5 = await database.getTreeRoots();
expect(roots5[MerkleTreeId.CONTRACT_TREE]).not.toEqual(roots[MerkleTreeId.CONTRACT_TREE]);
expect(roots5[MerkleTreeId.CONTRACT_TREE]).toEqual(block5.endContractTreeSnapshot.root);
});
});

class TestSynchroniser extends Synchroniser {
public work() {
return super.work();
}

public initialSync(): Promise<void> {
return super.initialSync();
}
}
Loading