@aztec/archiver 3.0.0-nightly.20251016 → 3.0.0-nightly.20251023

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 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/archiver/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EAEzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,iBAAiB,EAAkB,MAAM,6BAA6B,CAAC;AAErF,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,cAAc,EAAE,gBAAgB,EAChC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,eAAe,CAAC,EACnD,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CAqE9B"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/archiver/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,mBAAmB,EAEzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,iBAAiB,EAAkB,MAAM,6BAA6B,CAAC;AAErF,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,cAAc,EAAE,gBAAgB,EAChC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,eAAe,CAAC,EACnD,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CA4E9B"}
@@ -1,11 +1,12 @@
1
- import { getAttestationsFromPublishedL2Block } from '@aztec/stdlib/block';
1
+ import { compactArray } from '@aztec/foundation/collection';
2
+ import { getAttestationInfoFromPublishedL2Block } from '@aztec/stdlib/block';
2
3
  import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
3
4
  /**
4
5
  * Validates the attestations submitted for the given block.
5
6
  * Returns true if the attestations are valid and sufficient, false otherwise.
6
7
  */ export async function validateBlockAttestations(publishedBlock, epochCache, constants, logger) {
7
- const attestations = getAttestationsFromPublishedL2Block(publishedBlock);
8
- const attestors = attestations.map((a)=>a.getSender());
8
+ const attestorInfos = getAttestationInfoFromPublishedL2Block(publishedBlock);
9
+ const attestors = compactArray(attestorInfos.map((info)=>'address' in info ? info.address : undefined));
9
10
  const { block } = publishedBlock;
10
11
  const blockHash = await block.hash().then((hash)=>hash.toString());
11
12
  const archiveRoot = block.archive.root.toString();
@@ -21,8 +22,8 @@ import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
21
22
  };
22
23
  logger?.debug(`Validating attestations for block ${block.number} at slot ${slot} in epoch ${epoch}`, {
23
24
  committee: (committee ?? []).map((member)=>member.toString()),
24
- recoveredAttestors: attestations.map((a)=>a.getSender().toString()),
25
- postedAttestations: publishedBlock.attestations.map((a)=>a.address.isZero() ? a.signature.toString() : a.address.toString()),
25
+ recoveredAttestors: attestorInfos,
26
+ postedAttestations: publishedBlock.attestations.map((a)=>(a.address.isZero() ? a.signature : a.address).toString()),
26
27
  ...logData
27
28
  });
28
29
  if (!committee || committee.length === 0) {
@@ -33,44 +34,54 @@ import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
33
34
  }
34
35
  const committeeSet = new Set(committee.map((member)=>member.toString()));
35
36
  const requiredAttestationCount = Math.floor(committee.length * 2 / 3) + 1;
36
- for(let i = 0; i < attestations.length; i++){
37
- const attestation = attestations[i];
38
- const signer = attestation.getSender().toString();
39
- if (!committeeSet.has(signer)) {
40
- logger?.warn(`Attestation from non-committee member ${signer} at slot ${slot}`, {
41
- committee
37
+ const failedValidationResult = (reason)=>({
38
+ valid: false,
39
+ reason,
40
+ block: publishedBlock.block.toBlockInfo(),
41
+ committee,
42
+ seed,
43
+ epoch,
44
+ attestors,
45
+ attestations: publishedBlock.attestations
46
+ });
47
+ for(let i = 0; i < attestorInfos.length; i++){
48
+ const info = attestorInfos[i];
49
+ // Fail on invalid signatures (no address recovered)
50
+ if (info.status === 'invalid-signature' || info.status === 'empty') {
51
+ logger?.warn(`Attestation with empty or invalid signature at slot ${slot}`, {
52
+ committee,
53
+ invalidIndex: i,
54
+ ...logData
42
55
  });
43
- const reason = 'invalid-attestation';
44
56
  return {
45
- valid: false,
46
- reason,
47
- invalidIndex: i,
48
- block: publishedBlock.block.toBlockInfo(),
49
- committee,
50
- seed,
51
- epoch,
52
- attestors,
53
- attestations: publishedBlock.attestations
57
+ ...failedValidationResult('invalid-attestation'),
58
+ invalidIndex: i
54
59
  };
55
60
  }
61
+ // Check if the attestor is in the committee
62
+ if (info.status === 'recovered-from-signature' || info.status === 'provided-as-address') {
63
+ const signer = info.address.toString();
64
+ if (!committeeSet.has(signer)) {
65
+ logger?.warn(`Attestation from non-committee member ${signer} at slot ${slot}`, {
66
+ committee,
67
+ invalidIndex: i,
68
+ ...logData
69
+ });
70
+ return {
71
+ ...failedValidationResult('invalid-attestation'),
72
+ invalidIndex: i
73
+ };
74
+ }
75
+ }
56
76
  }
57
- if (attestations.length < requiredAttestationCount) {
77
+ const validAttestationCount = attestorInfos.filter((info)=>info.status === 'recovered-from-signature').length;
78
+ if (validAttestationCount < requiredAttestationCount) {
58
79
  logger?.warn(`Insufficient attestations for block at slot ${slot}`, {
59
80
  requiredAttestations: requiredAttestationCount,
60
- actualAttestations: attestations.length,
81
+ actualAttestations: validAttestationCount,
61
82
  ...logData
62
83
  });
63
- const reason = 'insufficient-attestations';
64
- return {
65
- valid: false,
66
- reason,
67
- block: publishedBlock.block.toBlockInfo(),
68
- committee,
69
- seed,
70
- epoch,
71
- attestors,
72
- attestations: publishedBlock.attestations
73
- };
84
+ return failedValidationResult('insufficient-attestations');
74
85
  }
75
86
  logger?.debug(`Block attestations validated successfully for block ${block.number} at slot ${slot}`, logData);
76
87
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/archiver",
3
- "version": "3.0.0-nightly.20251016",
3
+ "version": "3.0.0-nightly.20251023",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -66,23 +66,23 @@
66
66
  ]
67
67
  },
68
68
  "dependencies": {
69
- "@aztec/blob-lib": "3.0.0-nightly.20251016",
70
- "@aztec/blob-sink": "3.0.0-nightly.20251016",
71
- "@aztec/constants": "3.0.0-nightly.20251016",
72
- "@aztec/epoch-cache": "3.0.0-nightly.20251016",
73
- "@aztec/ethereum": "3.0.0-nightly.20251016",
74
- "@aztec/foundation": "3.0.0-nightly.20251016",
75
- "@aztec/kv-store": "3.0.0-nightly.20251016",
76
- "@aztec/l1-artifacts": "3.0.0-nightly.20251016",
77
- "@aztec/noir-protocol-circuits-types": "3.0.0-nightly.20251016",
78
- "@aztec/protocol-contracts": "3.0.0-nightly.20251016",
79
- "@aztec/stdlib": "3.0.0-nightly.20251016",
80
- "@aztec/telemetry-client": "3.0.0-nightly.20251016",
69
+ "@aztec/blob-lib": "3.0.0-nightly.20251023",
70
+ "@aztec/blob-sink": "3.0.0-nightly.20251023",
71
+ "@aztec/constants": "3.0.0-nightly.20251023",
72
+ "@aztec/epoch-cache": "3.0.0-nightly.20251023",
73
+ "@aztec/ethereum": "3.0.0-nightly.20251023",
74
+ "@aztec/foundation": "3.0.0-nightly.20251023",
75
+ "@aztec/kv-store": "3.0.0-nightly.20251023",
76
+ "@aztec/l1-artifacts": "3.0.0-nightly.20251023",
77
+ "@aztec/noir-protocol-circuits-types": "3.0.0-nightly.20251023",
78
+ "@aztec/protocol-contracts": "3.0.0-nightly.20251023",
79
+ "@aztec/stdlib": "3.0.0-nightly.20251023",
80
+ "@aztec/telemetry-client": "3.0.0-nightly.20251023",
81
81
  "lodash.groupby": "^4.6.0",
82
82
  "lodash.omit": "^4.5.0",
83
83
  "tsc-watch": "^6.0.0",
84
84
  "tslib": "^2.5.0",
85
- "viem": "2.23.7"
85
+ "viem": "npm:@spalladino/viem@2.38.2-eip7594.0"
86
86
  },
87
87
  "devDependencies": {
88
88
  "@jest/globals": "^30.0.0",
@@ -1,9 +1,11 @@
1
1
  import type { EpochCache } from '@aztec/epoch-cache';
2
+ import { compactArray } from '@aztec/foundation/collection';
2
3
  import type { Logger } from '@aztec/foundation/log';
3
4
  import {
4
5
  type PublishedL2Block,
6
+ type ValidateBlockNegativeResult,
5
7
  type ValidateBlockResult,
6
- getAttestationsFromPublishedL2Block,
8
+ getAttestationInfoFromPublishedL2Block,
7
9
  } from '@aztec/stdlib/block';
8
10
  import { type L1RollupConstants, getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
9
11
 
@@ -19,8 +21,8 @@ export async function validateBlockAttestations(
19
21
  constants: Pick<L1RollupConstants, 'epochDuration'>,
20
22
  logger?: Logger,
21
23
  ): Promise<ValidateBlockResult> {
22
- const attestations = getAttestationsFromPublishedL2Block(publishedBlock);
23
- const attestors = attestations.map(a => a.getSender());
24
+ const attestorInfos = getAttestationInfoFromPublishedL2Block(publishedBlock);
25
+ const attestors = compactArray(attestorInfos.map(info => ('address' in info ? info.address : undefined)));
24
26
  const { block } = publishedBlock;
25
27
  const blockHash = await block.hash().then(hash => hash.toString());
26
28
  const archiveRoot = block.archive.root.toString();
@@ -31,10 +33,8 @@ export async function validateBlockAttestations(
31
33
 
32
34
  logger?.debug(`Validating attestations for block ${block.number} at slot ${slot} in epoch ${epoch}`, {
33
35
  committee: (committee ?? []).map(member => member.toString()),
34
- recoveredAttestors: attestations.map(a => a.getSender().toString()),
35
- postedAttestations: publishedBlock.attestations.map(a =>
36
- a.address.isZero() ? a.signature.toString() : a.address.toString(),
37
- ),
36
+ recoveredAttestors: attestorInfos,
37
+ postedAttestations: publishedBlock.attestations.map(a => (a.address.isZero() ? a.signature : a.address).toString()),
38
38
  ...logData,
39
39
  });
40
40
 
@@ -46,43 +46,52 @@ export async function validateBlockAttestations(
46
46
  const committeeSet = new Set(committee.map(member => member.toString()));
47
47
  const requiredAttestationCount = Math.floor((committee.length * 2) / 3) + 1;
48
48
 
49
- for (let i = 0; i < attestations.length; i++) {
50
- const attestation = attestations[i];
51
- const signer = attestation.getSender().toString();
52
- if (!committeeSet.has(signer)) {
53
- logger?.warn(`Attestation from non-committee member ${signer} at slot ${slot}`, { committee });
54
- const reason = 'invalid-attestation';
55
- return {
56
- valid: false,
57
- reason,
58
- invalidIndex: i,
59
- block: publishedBlock.block.toBlockInfo(),
49
+ const failedValidationResult = <TReason extends ValidateBlockNegativeResult['reason']>(reason: TReason) => ({
50
+ valid: false as const,
51
+ reason,
52
+ block: publishedBlock.block.toBlockInfo(),
53
+ committee,
54
+ seed,
55
+ epoch,
56
+ attestors,
57
+ attestations: publishedBlock.attestations,
58
+ });
59
+
60
+ for (let i = 0; i < attestorInfos.length; i++) {
61
+ const info = attestorInfos[i];
62
+
63
+ // Fail on invalid signatures (no address recovered)
64
+ if (info.status === 'invalid-signature' || info.status === 'empty') {
65
+ logger?.warn(`Attestation with empty or invalid signature at slot ${slot}`, {
60
66
  committee,
61
- seed,
62
- epoch,
63
- attestors,
64
- attestations: publishedBlock.attestations,
65
- };
67
+ invalidIndex: i,
68
+ ...logData,
69
+ });
70
+ return { ...failedValidationResult('invalid-attestation'), invalidIndex: i };
71
+ }
72
+
73
+ // Check if the attestor is in the committee
74
+ if (info.status === 'recovered-from-signature' || info.status === 'provided-as-address') {
75
+ 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
+ });
82
+ return { ...failedValidationResult('invalid-attestation'), invalidIndex: i };
83
+ }
66
84
  }
67
85
  }
68
86
 
69
- if (attestations.length < requiredAttestationCount) {
87
+ const validAttestationCount = attestorInfos.filter(info => info.status === 'recovered-from-signature').length;
88
+ if (validAttestationCount < requiredAttestationCount) {
70
89
  logger?.warn(`Insufficient attestations for block at slot ${slot}`, {
71
90
  requiredAttestations: requiredAttestationCount,
72
- actualAttestations: attestations.length,
91
+ actualAttestations: validAttestationCount,
73
92
  ...logData,
74
93
  });
75
- const reason = 'insufficient-attestations';
76
- return {
77
- valid: false,
78
- reason,
79
- block: publishedBlock.block.toBlockInfo(),
80
- committee,
81
- seed,
82
- epoch,
83
- attestors,
84
- attestations: publishedBlock.attestations,
85
- };
94
+ return failedValidationResult('insufficient-attestations');
86
95
  }
87
96
 
88
97
  logger?.debug(`Block attestations validated successfully for block ${block.number} at slot ${slot}`, logData);