Skip to content
Closed
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
21 changes: 16 additions & 5 deletions yarn-project/archiver/src/store/block_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ type BlockStorage = {
indexWithinCheckpoint: number;
};

/**
* The subset of {@link L2Block} needed to check that a block chains onto the one before it, so validation can run
* against either a full block or the lightweight metadata read back from the store.
*/
type PreviousBlockInfo = Pick<L2Block, 'number' | 'checkpointNumber' | 'indexWithinCheckpoint' | 'archive'>;

/** Reason a checkpoint was rejected during sync. */
export type RejectedCheckpointReason = 'invalid-attestations' | 'descends-from-invalid-attestations';

Expand Down Expand Up @@ -443,10 +449,10 @@ export class BlockStore {
}

/**
* Gets the last block of the checkpoint before the given one.
* Gets the chaining info for the last block of the checkpoint before the given one.
* Returns undefined if there is no previous checkpoint (i.e. genesis).
*/
private async getPreviousCheckpointBlock(checkpointNumber: CheckpointNumber): Promise<L2Block | undefined> {
private async getPreviousCheckpointBlock(checkpointNumber: CheckpointNumber): Promise<PreviousBlockInfo | undefined> {
const previousCheckpointNumber = CheckpointNumber(checkpointNumber - 1);
if (previousCheckpointNumber === INITIAL_CHECKPOINT_NUMBER - 1) {
return undefined;
Expand All @@ -462,19 +468,24 @@ export class BlockStore {
}

const previousBlockNumber = BlockNumber(predecessor.startBlock + predecessor.blockCount - 1);
const previousBlock = await this.getBlock({ number: previousBlockNumber });
const previousBlock = await this.getBlockData({ number: previousBlockNumber });
if (previousBlock === undefined) {
throw new BlockNotFoundError(previousBlockNumber);
}
return previousBlock;
return {
number: previousBlock.header.globalVariables.blockNumber,
checkpointNumber: previousBlock.checkpointNumber,
indexWithinCheckpoint: previousBlock.indexWithinCheckpoint,
archive: previousBlock.archive,
};
}

/**
* Validates that blocks are sequential, have correct indexes, and chain via archive roots.
* This is the same validation used for both confirmed checkpoints (addCheckpoints) and
* proposed checkpoints (addProposedCheckpoint).
*/
private validateCheckpointBlocks(blocks: L2Block[], previousBlock: L2Block | undefined): void {
private validateCheckpointBlocks(blocks: L2Block[], previousBlock: PreviousBlockInfo | undefined): void {
for (const block of blocks) {
if (previousBlock) {
if (previousBlock.number !== block.number - 1) {
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/archiver/src/store/log_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class LogStore {
addLogs(blocks: L2Block[]): Promise<boolean> {
return this.db.transactionAsync(async () => {
for (const block of blocks) {
const blockHash = await block.hash();
const blockHash = (await block.hash()).toBuffer();
const blockNumber = block.number;
const blockTimestamp = block.timestamp;

Expand All @@ -94,7 +94,7 @@ export class LogStore {

for (let txIndexWithinBlock = 0; txIndexWithinBlock < block.body.txEffects.length; txIndexWithinBlock++) {
const txEffect = block.body.txEffects[txIndexWithinBlock];
const txHash = txEffect.txHash;
const txHash = txEffect.txHash.toBuffer();

// Private and public log indices are counted independently per tx, each starting at 0.
let privateLogIndexWithinTx = 0;
Expand Down
11 changes: 8 additions & 3 deletions yarn-project/archiver/src/store/log_store_codec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ describe('log_store_codec', () => {
const txHash = TxHash.random();
const blockHash = BlockHash.random();
const blockTimestamp = 1234567890n;
const original = { txHash, blockHash, blockTimestamp, logData: [] };
const original = { txHash: txHash.toBuffer(), blockHash: blockHash.toBuffer(), blockTimestamp, logData: [] };
const buf = encodeValue(original);
const decoded = decodeValue(buf);
expect(decoded.txHash.equals(txHash)).toBe(true);
Expand All @@ -214,7 +214,7 @@ describe('log_store_codec', () => {
const blockHash = BlockHash.random();
const blockTimestamp = 9999999999n;
const logData = [Fr.random(), Fr.random(), Fr.random()];
const original = { txHash, blockHash, blockTimestamp, logData };
const original = { txHash: txHash.toBuffer(), blockHash: blockHash.toBuffer(), blockTimestamp, logData };
const buf = encodeValue(original);
const decoded = decodeValue(buf);
expect(decoded.txHash.equals(txHash)).toBe(true);
Expand All @@ -230,7 +230,12 @@ describe('log_store_codec', () => {
const txHash = TxHash.random();
const blockHash = BlockHash.random();
const blockTimestamp = 0n;
const original = { txHash, blockHash, blockTimestamp, logData: [Fr.random()] };
const original = {
txHash: txHash.toBuffer(),
blockHash: blockHash.toBuffer(),
blockTimestamp,
logData: [Fr.random()],
};
const buf = encodeValue(original);
// Convert to Uint8Array (not a Buffer).
const uint8 = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
Expand Down
19 changes: 16 additions & 3 deletions yarn-project/archiver/src/store/log_store_codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ export type StoredLogValue = {
logData: Fr[];
};

/**
* Input to {@link encodeValue}. The hashes come in already serialized because a whole block's logs
* share one `blockHash` and every log of a tx shares its `txHash`, so callers serialize each once.
*/
export type EncodeLogValueInput = {
/** 32-byte serialized tx hash. */
txHash: Buffer;
/** 32-byte serialized block hash. */
blockHash: Buffer;
blockTimestamp: bigint;
logData: Fr[];
};

/** Returns the 64-char lowercase hex representation of a field, stripping the `0x` prefix. */
export function fieldHex(value: Fr | { toString: () => string }): string {
// Fr.toString() and AztecAddress.toString() both return `0x` + 64 lowercase hex chars.
Expand Down Expand Up @@ -108,10 +121,10 @@ export function incKey(key: string): string {
return key + HEX_SENTINEL;
}

export function encodeValue(value: StoredLogValue): Buffer {
export function encodeValue(value: EncodeLogValueInput): Buffer {
const head = Buffer.allocUnsafe(32 + 32 + 8 + 4);
value.txHash.toBuffer().copy(head, 0);
value.blockHash.toBuffer().copy(head, 32);
value.txHash.copy(head, 0);
value.blockHash.copy(head, 32);
head.writeBigUInt64BE(value.blockTimestamp, 64);
head.writeUInt32BE(value.logData.length, 72);
const fieldBufs = value.logData.map(f => f.toBuffer());
Expand Down
Loading