@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.
- package/dest/archiver/archiver.d.ts +30 -20
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +294 -208
- package/dest/archiver/archiver_store.d.ts +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +5 -4
- package/dest/archiver/config.d.ts +1 -1
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +5 -0
- package/dest/archiver/data_retrieval.d.ts +17 -17
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +110 -86
- package/dest/archiver/errors.d.ts +1 -1
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/index.d.ts +1 -1
- package/dest/archiver/instrumentation.d.ts +3 -3
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/structs/data_retrieval.d.ts +1 -1
- package/dest/archiver/structs/inbox_message.d.ts +1 -1
- package/dest/archiver/structs/published.d.ts +3 -2
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/archiver/validation.d.ts +10 -4
- package/dest/archiver/validation.d.ts.map +1 -1
- package/dest/archiver/validation.js +29 -21
- package/dest/factory.d.ts +1 -1
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/rpc/index.d.ts +2 -2
- package/dest/test/index.d.ts +1 -1
- package/dest/test/mock_archiver.d.ts +1 -1
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.d.ts +7 -6
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +1 -1
- package/dest/test/mock_structs.d.ts +1 -1
- package/package.json +17 -17
- package/src/archiver/archiver.ts +380 -244
- package/src/archiver/archiver_store_test_suite.ts +5 -4
- package/src/archiver/config.ts +5 -0
- package/src/archiver/data_retrieval.ts +156 -125
- package/src/archiver/instrumentation.ts +2 -2
- package/src/archiver/structs/published.ts +2 -1
- package/src/archiver/validation.ts +52 -27
- package/src/index.ts +1 -1
- 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
|
|
6
|
+
type AttestationInfo,
|
|
6
7
|
type ValidateBlockNegativeResult,
|
|
7
8
|
type ValidateBlockResult,
|
|
8
|
-
|
|
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
|
-
*
|
|
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
|
|
19
|
-
|
|
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 =
|
|
39
|
+
const attestorInfos = getAttestationInfoFromPublishedCheckpoint(publishedCheckpoint);
|
|
25
40
|
const attestors = compactArray(attestorInfos.map(info => ('address' in info ? info.address : undefined)));
|
|
26
|
-
const {
|
|
27
|
-
const
|
|
28
|
-
const archiveRoot =
|
|
29
|
-
const slot =
|
|
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 = {
|
|
47
|
+
const logData = { checkpointNumber: checkpoint.number, slot, epoch, headerHash, archiveRoot };
|
|
33
48
|
|
|
34
|
-
logger?.debug(`Validating attestations for
|
|
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:
|
|
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(
|
|
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:
|
|
69
|
+
block: checkpoint.blocks[0].toBlockInfo(),
|
|
53
70
|
committee,
|
|
54
71
|
seed,
|
|
55
72
|
epoch,
|
|
56
73
|
attestors,
|
|
57
|
-
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
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
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(
|
|
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 {
|
|
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:
|
|
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
|
|
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:
|
|
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<
|
|
272
|
+
getL2EpochNumber(): Promise<EpochNumber> {
|
|
272
273
|
throw new Error('Method not implemented.');
|
|
273
274
|
}
|
|
274
275
|
|
|
275
|
-
getL2SlotNumber(): Promise<
|
|
276
|
+
getL2SlotNumber(): Promise<SlotNumber> {
|
|
276
277
|
throw new Error('Method not implemented.');
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
isEpochComplete(_epochNumber:
|
|
280
|
+
isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
|
|
280
281
|
throw new Error('Method not implemented.');
|
|
281
282
|
}
|
|
282
283
|
|