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

fix(sync): Sync latest globals within merkle tree ops #1612

Merged
merged 16 commits into from
Aug 18, 2023
Merged
44 changes: 26 additions & 18 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,16 +317,26 @@ export class AztecNodeService implements AztecNode {
* @returns The current committed roots for the data trees.
*/
public async getTreeRoots(): Promise<Record<MerkleTreeId, Fr>> {
const getTreeRoot = async (id: MerkleTreeId) =>
Fr.fromBuffer((await this.merkleTreeDB.getTreeInfo(id, false)).root);
const committedDb = this.worldStateSynchroniser.getCommitted();
const getTreeRoot = async (id: MerkleTreeId) => Fr.fromBuffer((await committedDb.getTreeInfo(id)).root);

const [privateDataTree, nullifierTree, contractTree, l1ToL2MessagesTree, blocksTree, publicDataTree] =
await Promise.all([
getTreeRoot(MerkleTreeId.PRIVATE_DATA_TREE),
getTreeRoot(MerkleTreeId.NULLIFIER_TREE),
getTreeRoot(MerkleTreeId.CONTRACT_TREE),
getTreeRoot(MerkleTreeId.L1_TO_L2_MESSAGES_TREE),
getTreeRoot(MerkleTreeId.BLOCKS_TREE),
getTreeRoot(MerkleTreeId.PUBLIC_DATA_TREE),
]);

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.BLOCKS_TREE]: await getTreeRoot(MerkleTreeId.BLOCKS_TREE),
[MerkleTreeId.CONTRACT_TREE]: contractTree,
[MerkleTreeId.PRIVATE_DATA_TREE]: privateDataTree,
[MerkleTreeId.NULLIFIER_TREE]: nullifierTree,
[MerkleTreeId.PUBLIC_DATA_TREE]: publicDataTree,
[MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: l1ToL2MessagesTree,
[MerkleTreeId.BLOCKS_TREE]: blocksTree,
};
}

Expand All @@ -335,19 +345,17 @@ export class AztecNodeService implements AztecNode {
* @returns The current committed block data.
*/
public async getHistoricBlockData(): Promise<HistoricBlockData> {
const getTreeRoot = async (id: MerkleTreeId) =>
Fr.fromBuffer((await this.merkleTreeDB.getTreeInfo(id, false)).root);

const globalsHash = this.worldStateSynchroniser.latestGlobalVariablesHash;
const committedDb = this.worldStateSynchroniser.getCommitted();
const [roots, globalsHash] = await Promise.all([this.getTreeRoots(), committedDb.getLatestGlobalVariablesHash()]);

return new HistoricBlockData(
await getTreeRoot(MerkleTreeId.PRIVATE_DATA_TREE),
await getTreeRoot(MerkleTreeId.NULLIFIER_TREE),
await getTreeRoot(MerkleTreeId.CONTRACT_TREE),
await getTreeRoot(MerkleTreeId.L1_TO_L2_MESSAGES_TREE),
await getTreeRoot(MerkleTreeId.BLOCKS_TREE),
roots[MerkleTreeId.PRIVATE_DATA_TREE],
roots[MerkleTreeId.NULLIFIER_TREE],
roots[MerkleTreeId.CONTRACT_TREE],
roots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE],
roots[MerkleTreeId.BLOCKS_TREE],
Fr.ZERO,
await getTreeRoot(MerkleTreeId.PUBLIC_DATA_TREE),
roots[MerkleTreeId.PUBLIC_DATA_TREE],
globalsHash,
);
}
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class Synchroniser {
protected async initialSync() {
const [blockNumber, historicBlockData] = await Promise.all([
this.node.getBlockHeight(),
Promise.resolve(this.node.getHistoricBlockData()),
this.node.getHistoricBlockData(),
]);
this.initialSyncBlockHeight = blockNumber;
this.synchedToBlock = this.initialSyncBlockHeight;
Expand Down
3 changes: 1 addition & 2 deletions yarn-project/end-to-end/src/e2e_multi_transfer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { AztecNodeService } from '@aztec/aztec-node';
import { AztecRPCServer } from '@aztec/aztec-rpc';
import { AztecAddress, Contract, Fr, Wallet } from '@aztec/aztec.js';
import { DebugLogger } from '@aztec/foundation/log';
import { PrivateTokenAirdropContract } from '@aztec/noir-contracts/types';
import { MultiTransferContract } from '@aztec/noir-contracts/types';
import { MultiTransferContract, PrivateTokenAirdropContract } from '@aztec/noir-contracts/types';
import { AztecRPC, CompleteAddress } from '@aztec/types';

import { expectsNumOfEncryptedLogsInTheLastBlockToBe, setup } from './fixtures/utils.js';
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/foundation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"./wasm": "./dest/wasm/index.js",
"./worker": "./dest/worker/index.js",
"./bigint-buffer": "./dest/bigint-buffer/index.js",
"./types": "./dest/types/index.js"
"./types": "./dest/types/index.js",
"./committable": "./dest/committable/index.js"
},
"scripts": {
"prepare": "node ../yarn-project-base/scripts/update_build_manifest.mjs package.json",
Expand Down
32 changes: 32 additions & 0 deletions yarn-project/foundation/src/committable/committable.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Committable } from './committable.js';

describe('committable', () => {
it('include uncommitted should work as expected', () => {
const committableNumber: Committable<number> = new Committable(0);

// Check the initial value is 0
expect(committableNumber.get(true)).toBe(0);

// Update the value to 1
committableNumber.set(1);
committableNumber.commit();

// Check the value is 1
expect(committableNumber.get()).toBe(1);

// Test include uncommitted
committableNumber.set(2);
expect(committableNumber.get(true)).toBe(2);
expect(committableNumber.get(false)).toBe(1);

committableNumber.commit();
expect(committableNumber.get()).toBe(2);

// Test rollback
committableNumber.set(3);
expect(committableNumber.get(true)).toBe(3);
expect(committableNumber.get(false)).toBe(2);
committableNumber.rollback();
expect(committableNumber.get()).toBe(2);
});
});
46 changes: 46 additions & 0 deletions yarn-project/foundation/src/committable/committable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* A class that allows for a value to be committed or rolled back.
*/
export class Committable<T> {
private currentValue: T;
private nextValue: T | undefined = undefined;

constructor(initialValue: T) {
this.currentValue = initialValue;
}

/**
* Commits the uncommitted value.
*/
public commit() {
if (this.nextValue === undefined) {
return;
}
this.currentValue = this.nextValue;
this.nextValue = undefined;
}

/**
* Rolls back the uncommitted value.
*/
public rollback() {
this.nextValue === undefined;
}

/**
* Gets the current value.
* @param includeUncommitted - Whether to include the uncommitted value.
* @returns The current value if includeUncommitted is false, otherwise the uncommitted value.
*/
public get(includeUncommitted: boolean = false): T {
return includeUncommitted && this.nextValue ? this.nextValue : this.currentValue;
}

/**
* Sets the next value to be committed to.
* @param value - The new value to be set.
*/
public set(value: T) {
this.nextValue = value;
}
}
1 change: 1 addition & 0 deletions yarn-project/foundation/src/committable/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './committable.js';
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { Fr } from '@aztec/foundation/fields';
import { createDebugLogger } from '@aztec/foundation/log';
import { assertLength } from '@aztec/foundation/serialize';
import { ContractData, L2Block, L2BlockL2Logs, MerkleTreeId, PublicDataWrite, TxL2Logs } from '@aztec/types';
import { MerkleTreeOperations } from '@aztec/world-state';
import { MerkleTreeOperations, computeGlobalVariablesHash } from '@aztec/world-state';

import chunk from 'lodash.chunk';
import flatMap from 'lodash.flatmap';
Expand Down Expand Up @@ -295,7 +295,9 @@ export class SoloBlockBuilder implements BlockBuilder {
// Update the root trees with the latest data and contract tree roots,
// and validate them against the output of the root circuit simulation
this.debug(`Updating and validating root trees`);
await this.db.updateHistoricBlocksTree(left[0].constants.globalVariables);
const globalVariablesHash = await computeGlobalVariablesHash(left[0].constants.globalVariables);
await this.db.updateLatestGlobalVariablesHash(globalVariablesHash);
await this.db.updateHistoricBlocksTree(globalVariablesHash);

await this.validateRootOutput(rootOutput);

Expand Down
2 changes: 1 addition & 1 deletion yarn-project/sequencer-client/src/sequencer/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export async function getHistoricBlockData(
) {
const wasm = await CircuitsWasm.get();
const prevGlobalsHash = computeGlobalsHash(wasm, prevBlockGlobalVariables);
const roots = db.getTreeRoots();
const roots = await db.getTreeRoots();

return new HistoricBlockData(
Fr.fromBuffer(roots.privateDataTreeRoot),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GlobalVariables } from '@aztec/circuits.js';
import { Fr } from '@aztec/foundation/fields';
import { LowLeafWitnessData } from '@aztec/merkle-tree';
import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/types';

Expand All @@ -24,7 +24,7 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
* Get the current roots of the commitment trees.
* @returns The current roots of the trees.
*/
getTreeRoots(): CurrentTreeRoots {
getTreeRoots(): Promise<CurrentTreeRoots> {
return this.trees.getTreeRoots(this.includeUncommitted);
}

Expand Down Expand Up @@ -116,11 +116,26 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations {
/**
* Inserts into the roots trees (CONTRACT_TREE_ROOTS_TREE, PRIVATE_DATA_TREE_ROOTS_TREE)
* the current roots of the corresponding trees (CONTRACT_TREE, PRIVATE_DATA_TREE).
* @param globalVariables - The current global variables to include in the block hash.
* @param globalVariablesHash - The hash of the current global variables to include in the block hash.
* @returns Empty promise.
*/
public updateHistoricBlocksTree(globalVariables: GlobalVariables): Promise<void> {
return this.trees.updateHistoricBlocksTree(globalVariables, this.includeUncommitted);
public updateHistoricBlocksTree(globalVariablesHash: Fr): Promise<void> {
return this.trees.updateHistoricBlocksTree(globalVariablesHash, this.includeUncommitted);
}

/**
* Updates the latest global variables hash
* @param globalVariablesHash - The latest global variables hash
*/
public updateLatestGlobalVariablesHash(globalVariablesHash: Fr): Promise<void> {
return this.trees.updateLatestGlobalVariablesHash(globalVariablesHash, this.includeUncommitted);
}

/**
* Gets the global variables hash from the previous block
*/
public getLatestGlobalVariablesHash(): Promise<Fr> {
return this.trees.getLatestGlobalVariablesHash(this.includeUncommitted);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Fr } from '@aztec/foundation/fields';
import { createDebugLogger } from '@aztec/foundation/log';
import { L2Block, L2BlockDownloader, L2BlockSource } from '@aztec/types';

import { MerkleTreeDb, MerkleTreeOperations, computeGlobalVariablesHash } from '../index.js';
import { MerkleTreeDb, MerkleTreeOperations } from '../index.js';
import { MerkleTreeOperationsFacade } from '../merkle-tree/merkle_tree_operations_facade.js';
import { getConfigEnvVars } from './config.js';
import { WorldStateRunningState, WorldStateStatus, WorldStateSynchroniser } from './world_state_synchroniser.js';
Expand All @@ -23,9 +22,6 @@ export class ServerWorldStateSynchroniser implements WorldStateSynchroniser {
private runningPromise: Promise<void> = Promise.resolve();
private currentState: WorldStateRunningState = WorldStateRunningState.IDLE;

/** The latest Global Variables hash for the HEAD of the chain. */
public latestGlobalVariablesHash: Fr = Fr.ZERO;

constructor(
private merkleTreeDb: MerkleTreeDb,
private l2BlockSource: L2BlockSource,
Expand Down Expand Up @@ -57,7 +53,6 @@ export class ServerWorldStateSynchroniser implements WorldStateSynchroniser {

// get the current latest block number
this.latestBlockNumberAtStart = await this.l2BlockSource.getBlockHeight();
this.latestGlobalVariablesHash = await computeGlobalVariablesHash();

const blockToDownloadFrom = this.currentL2BlockNum + 1;

Expand Down Expand Up @@ -121,8 +116,6 @@ export class ServerWorldStateSynchroniser implements WorldStateSynchroniser {
private async handleL2Block(l2Block: L2Block) {
await this.merkleTreeDb.handleL2Block(l2Block);
this.currentL2BlockNum = l2Block.number;
this.latestGlobalVariablesHash = await computeGlobalVariablesHash(l2Block.globalVariables);
this.log(`Synced global variables with hash ${this.latestGlobalVariablesHash.toString()}`);
if (
this.currentState === WorldStateRunningState.SYNCHING &&
this.currentL2BlockNum >= this.latestBlockNumberAtStart
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Fr } from '@aztec/circuits.js';

import { MerkleTreeOperations } from '../index.js';

/**
Expand Down Expand Up @@ -58,9 +56,4 @@ export interface WorldStateSynchroniser {
* @returns An instance of MerkleTreeOperations that will not include uncommitted data.
*/
getCommitted(): MerkleTreeOperations;

/**
* The latest Global Variables hash for the HEAD of the chain.
*/
latestGlobalVariablesHash: Fr;
}
20 changes: 16 additions & 4 deletions yarn-project/world-state/src/world-state-db/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GlobalVariables, MAX_NEW_NULLIFIERS_PER_TX } from '@aztec/circuits.js';
import { MAX_NEW_NULLIFIERS_PER_TX } from '@aztec/circuits.js';
import { Fr } from '@aztec/foundation/fields';
import { createDebugLogger } from '@aztec/foundation/log';
import { LeafData, LowLeafWitnessData } from '@aztec/merkle-tree';
import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/types';
Expand Down Expand Up @@ -115,7 +116,7 @@ export interface MerkleTreeOperations {
/**
* Gets the current roots of the commitment trees.
*/
getTreeRoots(): CurrentTreeRoots;
getTreeRoots(): Promise<CurrentTreeRoots>;

/**
* Gets sibling path for a leaf.
Expand Down Expand Up @@ -175,9 +176,20 @@ export interface MerkleTreeOperations {
/**
* Inserts the new block hash into the new block hashes tree.
* This includes all of the current roots of all of the data trees and the current blocks global vars.
* @param globalVariables - The global variables to insert into the block hash.
* @param globalVariablesHash - The global variables hash to insert into the block hash.
*/
updateHistoricBlocksTree(globalVariables: GlobalVariables): Promise<void>;
updateHistoricBlocksTree(globalVariablesHash: Fr): Promise<void>;

/**
* Updates the latest global variables hash
* @param globalVariablesHash - The latest global variables hash
*/
updateLatestGlobalVariablesHash(globalVariablesHash: Fr): Promise<void>;

/**
* Gets the global variables hash from the previous block
*/
getLatestGlobalVariablesHash(): Promise<Fr>;

/**
* Batch insert multiple leaves into the tree.
Expand Down
Loading