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

chore: Check tree roots in world state sync #2543

Merged
merged 1 commit into from
Sep 28, 2023
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
2 changes: 2 additions & 0 deletions yarn-project/sequencer-client/src/sequencer/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ export class Sequencer {
const syncedBlocks = await Promise.all([
this.worldState.status().then((s: WorldStateStatus) => s.syncedToL2Block),
this.p2pClient.getStatus().then(s => s.syncedToL2Block),
this.l2BlockSource.getBlockNumber(),
this.l1ToL2MessageSource.getBlockNumber(),
]);
const min = Math.min(...syncedBlocks);
return min >= this.lastPublishedBlock;
Expand Down
6 changes: 6 additions & 0 deletions yarn-project/types/src/contract_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ export interface ContractDataSource {
* @returns The function's data.
*/
getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise<EncodedContractFunction | undefined>;

/**
* Gets the number of the latest L2 block processed by the implementation.
* @returns The number of the latest L2 block processed by the implementation.
*/
getBlockNumber(): Promise<number>;
}

/**
Expand Down
6 changes: 6 additions & 0 deletions yarn-project/types/src/l1_to_l2_message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export interface L1ToL2MessageSource {
* @returns The confirmed L1 to L2 message (throws if not found)
*/
getConfirmedL1ToL2Message(messageKey: Fr): Promise<L1ToL2Message>;

/**
* Gets the number of the latest L2 block processed by the implementation.
* @returns The number of the latest L2 block processed by the implementation.
*/
getBlockNumber(): Promise<number>;
}

/**
Expand Down
6 changes: 6 additions & 0 deletions yarn-project/types/src/logs/l2_logs_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@ export interface L2LogsSource {
* @returns A promise signalling completion of the stop process.
*/
stop(): Promise<void>;

/**
* Gets the number of the latest L2 block processed by the implementation.
* @returns The number of the latest L2 block processed by the implementation.
*/
getBlockNumber(): Promise<number>;
}
33 changes: 22 additions & 11 deletions yarn-project/world-state/src/world-state-db/merkle_trees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,19 +527,19 @@ export class MerkleTrees implements MerkleTreeDb {
* @param l2Block - The L2 block to handle.
*/
private async _handleL2Block(l2Block: L2Block) {
const treeRootWithIdPairs = [
[l2Block.endContractTreeSnapshot.root, MerkleTreeId.CONTRACT_TREE],
[l2Block.endNullifierTreeSnapshot.root, MerkleTreeId.NULLIFIER_TREE],
[l2Block.endPrivateDataTreeSnapshot.root, MerkleTreeId.PRIVATE_DATA_TREE],
[l2Block.endPublicDataTreeRoot, MerkleTreeId.PUBLIC_DATA_TREE],
[l2Block.endL1ToL2MessagesTreeSnapshot.root, MerkleTreeId.L1_TO_L2_MESSAGES_TREE],
[l2Block.endHistoricBlocksTreeSnapshot.root, MerkleTreeId.BLOCKS_TREE],
] as const;
const compareRoot = (root: Fr, treeId: MerkleTreeId) => {
const treeRoot = this.trees[treeId].getRoot(true);
return treeRoot.equals(root.toBuffer());
};
const rootChecks = [
compareRoot(l2Block.endContractTreeSnapshot.root, MerkleTreeId.CONTRACT_TREE),
compareRoot(l2Block.endNullifierTreeSnapshot.root, MerkleTreeId.NULLIFIER_TREE),
compareRoot(l2Block.endPrivateDataTreeSnapshot.root, MerkleTreeId.PRIVATE_DATA_TREE),
compareRoot(l2Block.endPublicDataTreeRoot, MerkleTreeId.PUBLIC_DATA_TREE),
compareRoot(l2Block.endL1ToL2MessagesTreeSnapshot.root, MerkleTreeId.L1_TO_L2_MESSAGES_TREE),
compareRoot(l2Block.endHistoricBlocksTreeSnapshot.root, MerkleTreeId.BLOCKS_TREE),
];
const ourBlock = rootChecks.every(x => x);
const ourBlock = treeRootWithIdPairs.every(([root, id]) => compareRoot(root, id));
if (ourBlock) {
this.log(`Block ${l2Block.number} is ours, committing world state..`);
await this._commit();
Expand Down Expand Up @@ -582,9 +582,20 @@ export class MerkleTrees implements MerkleTreeDb {

await this._commit();
}
for (const treeId of merkleTreeIds()) {

for (const [root, treeId] of treeRootWithIdPairs) {
const treeName = MerkleTreeId[treeId];
const info = await this._getTreeInfo(treeId, false);
this.log(`Tree ${MerkleTreeId[treeId]} synched with size ${info.size} root ${info.root.toString('hex')}`);
const syncedStr = '0x' + info.root.toString('hex');
const rootStr = root.toString();
// Sanity check that the rebuilt trees match the roots published by the L2 block
if (!info.root.equals(root.toBuffer())) {
throw new Error(
`Synced tree root ${treeName} does not match published L2 block root: ${syncedStr} != ${rootStr}`,
);
} else {
this.log(`Tree ${treeName} synched with size ${info.size} root ${rootStr}`);
}
}
}
}