@aztec/archiver 0.0.1-commit.b655e406 → 0.0.1-commit.fce3e4f

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.
Files changed (61) hide show
  1. package/dest/archiver/archiver.d.ts +30 -20
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +294 -208
  4. package/dest/archiver/archiver_store.d.ts +1 -1
  5. package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
  6. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.js +5 -4
  8. package/dest/archiver/config.d.ts +1 -1
  9. package/dest/archiver/config.d.ts.map +1 -1
  10. package/dest/archiver/config.js +5 -0
  11. package/dest/archiver/data_retrieval.d.ts +17 -17
  12. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  13. package/dest/archiver/data_retrieval.js +110 -86
  14. package/dest/archiver/errors.d.ts +1 -1
  15. package/dest/archiver/errors.d.ts.map +1 -1
  16. package/dest/archiver/index.d.ts +1 -1
  17. package/dest/archiver/instrumentation.d.ts +3 -3
  18. package/dest/archiver/instrumentation.d.ts.map +1 -1
  19. package/dest/archiver/kv_archiver_store/block_store.d.ts +1 -1
  20. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  21. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +1 -1
  22. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  23. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +1 -1
  24. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  25. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +2 -2
  26. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  27. package/dest/archiver/kv_archiver_store/log_store.d.ts +1 -1
  28. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  29. package/dest/archiver/kv_archiver_store/message_store.d.ts +1 -1
  30. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  31. package/dest/archiver/structs/data_retrieval.d.ts +1 -1
  32. package/dest/archiver/structs/inbox_message.d.ts +1 -1
  33. package/dest/archiver/structs/published.d.ts +3 -2
  34. package/dest/archiver/structs/published.d.ts.map +1 -1
  35. package/dest/archiver/validation.d.ts +10 -4
  36. package/dest/archiver/validation.d.ts.map +1 -1
  37. package/dest/archiver/validation.js +29 -21
  38. package/dest/factory.d.ts +1 -1
  39. package/dest/index.d.ts +2 -2
  40. package/dest/index.d.ts.map +1 -1
  41. package/dest/index.js +1 -1
  42. package/dest/rpc/index.d.ts +2 -2
  43. package/dest/test/index.d.ts +1 -1
  44. package/dest/test/mock_archiver.d.ts +1 -1
  45. package/dest/test/mock_archiver.d.ts.map +1 -1
  46. package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
  47. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  48. package/dest/test/mock_l2_block_source.d.ts +7 -6
  49. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  50. package/dest/test/mock_l2_block_source.js +1 -1
  51. package/dest/test/mock_structs.d.ts +1 -1
  52. package/package.json +17 -17
  53. package/src/archiver/archiver.ts +380 -244
  54. package/src/archiver/archiver_store_test_suite.ts +5 -4
  55. package/src/archiver/config.ts +5 -0
  56. package/src/archiver/data_retrieval.ts +156 -125
  57. package/src/archiver/instrumentation.ts +2 -2
  58. package/src/archiver/structs/published.ts +2 -1
  59. package/src/archiver/validation.ts +52 -27
  60. package/src/index.ts +1 -1
  61. package/src/test/mock_l2_block_source.ts +7 -6
@@ -1,60 +1,77 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
+ import { EpochNumber } from '@aztec/foundation/branded-types';
2
3
  import { compactArray } from '@aztec/foundation/collection';
3
4
  import type { Logger } from '@aztec/foundation/log';
4
5
  import {
5
- type PublishedL2Block,
6
+ type AttestationInfo,
6
7
  type ValidateBlockNegativeResult,
7
8
  type ValidateBlockResult,
8
- getAttestationInfoFromPublishedL2Block,
9
+ getAttestationInfoFromPayload,
9
10
  } from '@aztec/stdlib/block';
11
+ import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
10
12
  import { type L1RollupConstants, getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
13
+ import { ConsensusPayload } from '@aztec/stdlib/p2p';
11
14
 
12
15
  export type { ValidateBlockResult };
13
16
 
14
17
  /**
15
- * Validates the attestations submitted for the given block.
18
+ * Extracts attestation information from a published checkpoint.
19
+ * Returns info for each attestation, preserving array indices.
20
+ */
21
+ export function getAttestationInfoFromPublishedCheckpoint({
22
+ checkpoint,
23
+ attestations,
24
+ }: PublishedCheckpoint): AttestationInfo[] {
25
+ const payload = ConsensusPayload.fromCheckpoint(checkpoint);
26
+ return getAttestationInfoFromPayload(payload, attestations);
27
+ }
28
+
29
+ /**
30
+ * Validates the attestations submitted for the given checkpoint.
16
31
  * Returns true if the attestations are valid and sufficient, false otherwise.
17
32
  */
18
- export async function validateBlockAttestations(
19
- publishedBlock: PublishedL2Block,
33
+ export async function validateCheckpointAttestations(
34
+ publishedCheckpoint: PublishedCheckpoint,
20
35
  epochCache: EpochCache,
21
36
  constants: Pick<L1RollupConstants, 'epochDuration'>,
22
37
  logger?: Logger,
23
38
  ): Promise<ValidateBlockResult> {
24
- const attestorInfos = getAttestationInfoFromPublishedL2Block(publishedBlock);
39
+ const attestorInfos = getAttestationInfoFromPublishedCheckpoint(publishedCheckpoint);
25
40
  const attestors = compactArray(attestorInfos.map(info => ('address' in info ? info.address : undefined)));
26
- const { block } = publishedBlock;
27
- const blockHash = await block.hash().then(hash => hash.toString());
28
- const archiveRoot = block.archive.root.toString();
29
- const slot = block.header.getSlot();
30
- const epoch = getEpochAtSlot(slot, constants);
41
+ const { checkpoint, attestations } = publishedCheckpoint;
42
+ const headerHash = checkpoint.header.hash();
43
+ const archiveRoot = checkpoint.archive.root.toString();
44
+ const slot = checkpoint.header.slotNumber;
45
+ const epoch: EpochNumber = getEpochAtSlot(slot, constants);
31
46
  const { committee, seed } = await epochCache.getCommitteeForEpoch(epoch);
32
- const logData = { blockNumber: block.number, slot, epoch, blockHash, archiveRoot };
47
+ const logData = { checkpointNumber: checkpoint.number, slot, epoch, headerHash, archiveRoot };
33
48
 
34
- logger?.debug(`Validating attestations for block ${block.number} at slot ${slot} in epoch ${epoch}`, {
49
+ logger?.debug(`Validating attestations for checkpoint ${checkpoint.number} at slot ${slot} in epoch ${epoch}`, {
35
50
  committee: (committee ?? []).map(member => member.toString()),
36
51
  recoveredAttestors: attestorInfos,
37
- postedAttestations: publishedBlock.attestations.map(a => (a.address.isZero() ? a.signature : a.address).toString()),
52
+ postedAttestations: attestations.map(a => (a.address.isZero() ? a.signature : a.address).toString()),
38
53
  ...logData,
39
54
  });
40
55
 
41
56
  if (!committee || committee.length === 0) {
42
- logger?.warn(`No committee found for epoch ${epoch} at slot ${slot}. Accepting block without validation.`, logData);
57
+ logger?.warn(
58
+ `No committee found for epoch ${epoch} at slot ${slot}. Accepting checkpoint without validation.`,
59
+ logData,
60
+ );
43
61
  return { valid: true };
44
62
  }
45
63
 
46
- const committeeSet = new Set(committee.map(member => member.toString()));
47
64
  const requiredAttestationCount = Math.floor((committee.length * 2) / 3) + 1;
48
65
 
49
66
  const failedValidationResult = <TReason extends ValidateBlockNegativeResult['reason']>(reason: TReason) => ({
50
67
  valid: false as const,
51
68
  reason,
52
- block: publishedBlock.block.toBlockInfo(),
69
+ block: checkpoint.blocks[0].toBlockInfo(),
53
70
  committee,
54
71
  seed,
55
72
  epoch,
56
73
  attestors,
57
- attestations: publishedBlock.attestations,
74
+ attestations,
58
75
  });
59
76
 
60
77
  for (let i = 0; i < attestorInfos.length; i++) {
@@ -70,15 +87,20 @@ export async function validateBlockAttestations(
70
87
  return { ...failedValidationResult('invalid-attestation'), invalidIndex: i };
71
88
  }
72
89
 
73
- // Check if the attestor is in the committee
90
+ // Check if the attestor at this index matches the committee member at the same index
74
91
  if (info.status === 'recovered-from-signature' || info.status === 'provided-as-address') {
75
92
  const signer = info.address.toString();
76
- if (!committeeSet.has(signer)) {
77
- logger?.warn(`Attestation from non-committee member ${signer} at slot ${slot}`, {
78
- committee,
79
- invalidIndex: i,
80
- ...logData,
81
- });
93
+ const expectedCommitteeMember = committee[i]?.toString();
94
+
95
+ if (!expectedCommitteeMember || signer !== expectedCommitteeMember) {
96
+ logger?.warn(
97
+ `Attestation at index ${i} from ${signer} does not match expected committee member ${expectedCommitteeMember} at slot ${slot}`,
98
+ {
99
+ committee,
100
+ invalidIndex: i,
101
+ ...logData,
102
+ },
103
+ );
82
104
  return { ...failedValidationResult('invalid-attestation'), invalidIndex: i };
83
105
  }
84
106
  }
@@ -86,7 +108,7 @@ export async function validateBlockAttestations(
86
108
 
87
109
  const validAttestationCount = attestorInfos.filter(info => info.status === 'recovered-from-signature').length;
88
110
  if (validAttestationCount < requiredAttestationCount) {
89
- logger?.warn(`Insufficient attestations for block at slot ${slot}`, {
111
+ logger?.warn(`Insufficient attestations for checkpoint at slot ${slot}`, {
90
112
  requiredAttestations: requiredAttestationCount,
91
113
  actualAttestations: validAttestationCount,
92
114
  ...logData,
@@ -94,6 +116,9 @@ export async function validateBlockAttestations(
94
116
  return failedValidationResult('insufficient-attestations');
95
117
  }
96
118
 
97
- logger?.debug(`Block attestations validated successfully for block ${block.number} at slot ${slot}`, logData);
119
+ logger?.debug(
120
+ `Checkpoint attestations validated successfully for checkpoint ${checkpoint.number} at slot ${slot}`,
121
+ logData,
122
+ );
98
123
  return { valid: true };
99
124
  }
package/src/index.ts CHANGED
@@ -2,4 +2,4 @@ export * from './archiver/index.js';
2
2
  export * from './factory.js';
3
3
  export * from './rpc/index.js';
4
4
 
5
- export { retrieveBlocksFromRollup, retrieveL2ProofVerifiedEvents } from './archiver/data_retrieval.js';
5
+ export { retrieveL2ProofVerifiedEvents } from './archiver/data_retrieval.js';
@@ -1,5 +1,6 @@
1
1
  import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
2
2
  import { DefaultL1ContractsConfig } from '@aztec/ethereum';
3
+ import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
4
  import { Buffer32 } from '@aztec/foundation/buffer';
4
5
  import { EthAddress } from '@aztec/foundation/eth-address';
5
6
  import { Fr } from '@aztec/foundation/fields';
@@ -182,17 +183,17 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
182
183
  return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.getBlockHeader());
183
184
  }
184
185
 
185
- getBlocksForEpoch(epochNumber: bigint): Promise<L2Block[]> {
186
+ getBlocksForEpoch(epochNumber: EpochNumber): Promise<L2Block[]> {
186
187
  const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
187
188
  const [start, end] = getSlotRangeForEpoch(epochNumber, { epochDuration });
188
189
  const blocks = this.l2Blocks.filter(b => {
189
- const slot = b.header.globalVariables.slotNumber.toBigInt();
190
+ const slot = b.header.globalVariables.slotNumber;
190
191
  return slot >= start && slot <= end;
191
192
  });
192
193
  return Promise.resolve(blocks);
193
194
  }
194
195
 
195
- async getBlockHeadersForEpoch(epochNumber: bigint): Promise<BlockHeader[]> {
196
+ async getBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
196
197
  const blocks = await this.getBlocksForEpoch(epochNumber);
197
198
  return blocks.map(b => b.getBlockHeader());
198
199
  }
@@ -268,15 +269,15 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
268
269
  };
269
270
  }
270
271
 
271
- getL2EpochNumber(): Promise<bigint> {
272
+ getL2EpochNumber(): Promise<EpochNumber> {
272
273
  throw new Error('Method not implemented.');
273
274
  }
274
275
 
275
- getL2SlotNumber(): Promise<bigint> {
276
+ getL2SlotNumber(): Promise<SlotNumber> {
276
277
  throw new Error('Method not implemented.');
277
278
  }
278
279
 
279
- isEpochComplete(_epochNumber: bigint): Promise<boolean> {
280
+ isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
280
281
  throw new Error('Method not implemented.');
281
282
  }
282
283