@aztec/aztec-node 0.0.1-commit.fce3e4f → 0.0.1-commit.fffb133c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
- import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
3
  import { countWhile, filterAsync, fromEntries, getEntries, mapValues } from '@aztec/foundation/collection';
4
4
  import { EthAddress } from '@aztec/foundation/eth-address';
5
5
  import { createLogger } from '@aztec/foundation/log';
@@ -19,7 +19,7 @@ import {
19
19
  L2BlockStream,
20
20
  type L2BlockStreamEvent,
21
21
  type L2BlockStreamEventHandler,
22
- getAttestationInfoFromPublishedL2Block,
22
+ getAttestationInfoFromPublishedCheckpoint,
23
23
  } from '@aztec/stdlib/block';
24
24
  import { getEpochAtSlot, getSlotRangeForEpoch, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
25
25
  import type {
@@ -44,8 +44,10 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
44
44
  protected initialSlot: SlotNumber | undefined;
45
45
  protected lastProcessedSlot: SlotNumber | undefined;
46
46
  // eslint-disable-next-line aztec-custom/no-non-primitive-in-collections
47
- protected slotNumberToBlock: Map<SlotNumber, { blockNumber: number; archive: string; attestors: EthAddress[] }> =
48
- new Map();
47
+ protected slotNumberToCheckpoint: Map<
48
+ SlotNumber,
49
+ { checkpointNumber: CheckpointNumber; archive: string; attestors: EthAddress[] }
50
+ > = new Map();
49
51
 
50
52
  constructor(
51
53
  protected epochCache: EpochCache,
@@ -76,7 +78,7 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
76
78
  /** Loads initial slot and initializes blockstream. We will not process anything at or before the initial slot. */
77
79
  protected async init() {
78
80
  this.initialSlot = this.epochCache.getEpochAndSlotNow().slot;
79
- const startingBlock = await this.archiver.getBlockNumber();
81
+ const startingBlock = BlockNumber(await this.archiver.getBlockNumber());
80
82
  this.logger.info(`Starting validator sentinel with initial slot ${this.initialSlot} and block ${startingBlock}`);
81
83
  this.blockStream = new L2BlockStream(this.archiver, this.l2TipsStore, this, this.logger, { startingBlock });
82
84
  }
@@ -87,39 +89,46 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
87
89
 
88
90
  public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
89
91
  await this.l2TipsStore.handleBlockStreamEvent(event);
90
- if (event.type === 'blocks-added') {
91
- // Store mapping from slot to archive, block number, and attestors
92
- for (const block of event.blocks) {
93
- this.slotNumberToBlock.set(block.block.header.getSlot(), {
94
- blockNumber: block.block.number,
95
- archive: block.block.archive.root.toString(),
96
- attestors: getAttestationInfoFromPublishedL2Block(block)
97
- .filter(a => a.status === 'recovered-from-signature')
98
- .map(a => a.address!),
99
- });
100
- }
101
-
102
- // Prune the archive map to only keep at most N entries
103
- const historyLength = this.store.getHistoryLength();
104
- if (this.slotNumberToBlock.size > historyLength) {
105
- const toDelete = Array.from(this.slotNumberToBlock.keys())
106
- .sort((a, b) => Number(a - b))
107
- .slice(0, this.slotNumberToBlock.size - historyLength);
108
- for (const key of toDelete) {
109
- this.slotNumberToBlock.delete(key);
110
- }
111
- }
92
+ if (event.type === 'chain-checkpointed') {
93
+ this.handleCheckpoint(event);
112
94
  } else if (event.type === 'chain-proven') {
113
95
  await this.handleChainProven(event);
114
96
  }
115
97
  }
116
98
 
99
+ protected handleCheckpoint(event: L2BlockStreamEvent) {
100
+ if (event.type !== 'chain-checkpointed') {
101
+ return;
102
+ }
103
+ const checkpoint = event.checkpoint;
104
+
105
+ // Store mapping from slot to archive, checkpoint number, and attestors
106
+ this.slotNumberToCheckpoint.set(checkpoint.checkpoint.header.slotNumber, {
107
+ checkpointNumber: checkpoint.checkpoint.number,
108
+ archive: checkpoint.checkpoint.archive.root.toString(),
109
+ attestors: getAttestationInfoFromPublishedCheckpoint(checkpoint)
110
+ .filter(a => a.status === 'recovered-from-signature')
111
+ .map(a => a.address!),
112
+ });
113
+
114
+ // Prune the archive map to only keep at most N entries
115
+ const historyLength = this.store.getHistoryLength();
116
+ if (this.slotNumberToCheckpoint.size > historyLength) {
117
+ const toDelete = Array.from(this.slotNumberToCheckpoint.keys())
118
+ .sort((a, b) => Number(a - b))
119
+ .slice(0, this.slotNumberToCheckpoint.size - historyLength);
120
+ for (const key of toDelete) {
121
+ this.slotNumberToCheckpoint.delete(key);
122
+ }
123
+ }
124
+ }
125
+
117
126
  protected async handleChainProven(event: L2BlockStreamEvent) {
118
127
  if (event.type !== 'chain-proven') {
119
128
  return;
120
129
  }
121
130
  const blockNumber = event.block.number;
122
- const block = await this.archiver.getBlock(blockNumber);
131
+ const block = await this.archiver.getL2Block(blockNumber);
123
132
  if (!block) {
124
133
  this.logger.error(`Failed to get block ${blockNumber}`, { block });
125
134
  return;
@@ -291,8 +300,8 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
291
300
  return false;
292
301
  }
293
302
 
294
- const archiverLastBlockHash = await this.l2TipsStore.getL2Tips().then(tip => tip.latest.hash);
295
- const p2pLastBlockHash = await this.p2p.getL2Tips().then(tips => tips.latest.hash);
303
+ const archiverLastBlockHash = await this.l2TipsStore.getL2Tips().then(tip => tip.proposed.hash);
304
+ const p2pLastBlockHash = await this.p2p.getL2Tips().then(tips => tips.proposed.hash);
296
305
  const isP2pSynced = archiverLastBlockHash === p2pLastBlockHash;
297
306
  if (!isP2pSynced) {
298
307
  this.logger.debug(`Waiting for P2P client to sync with archiver`, { archiverLastBlockHash, p2pLastBlockHash });
@@ -331,8 +340,8 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
331
340
  // or all attestations for all proposals in the slot if no block was mined.
332
341
  // We gather from both p2p (contains the ones seen on the p2p layer) and archiver
333
342
  // (contains the ones synced from mined blocks, which we may have missed from p2p).
334
- const block = this.slotNumberToBlock.get(slot);
335
- const p2pAttested = await this.p2p.getAttestationsForSlot(slot, block?.archive);
343
+ const block = this.slotNumberToCheckpoint.get(slot);
344
+ const p2pAttested = await this.p2p.getCheckpointAttestationsForSlot(slot, block?.archive);
336
345
  // Filter out attestations with invalid signatures
337
346
  const p2pAttestors = p2pAttested.map(a => a.getSender()).filter((s): s is EthAddress => s !== undefined);
338
347
  const attestors = new Set(