@aztec/archiver 3.0.0-nightly.20250910 → 3.0.0-nightly.20250912
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/README.md +25 -4
- package/dest/archiver/archiver.d.ts +8 -4
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +50 -25
- package/dest/archiver/archiver_store.d.ts +5 -1
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +103 -5
- package/dest/archiver/config.d.ts +4 -18
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +5 -1
- package/dest/archiver/data_retrieval.d.ts +2 -2
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +3 -3
- package/dest/archiver/kv_archiver_store/block_store.d.ts +11 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +27 -3
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +3 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +6 -0
- package/dest/archiver/validation.d.ts.map +1 -1
- package/dest/archiver/validation.js +7 -4
- package/dest/test/mock_l2_block_source.d.ts +2 -10
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +2 -2
- package/package.json +13 -13
- package/src/archiver/archiver.ts +54 -27
- package/src/archiver/archiver_store.ts +7 -1
- package/src/archiver/archiver_store_test_suite.ts +120 -18
- package/src/archiver/config.ts +13 -28
- package/src/archiver/data_retrieval.ts +3 -7
- package/src/archiver/kv_archiver_store/block_store.ts +44 -4
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +9 -1
- package/src/archiver/validation.ts +22 -2
- package/src/test/mock_l2_block_source.ts +19 -10
|
@@ -12,7 +12,16 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
12
12
|
import { toArray } from '@aztec/foundation/iterable';
|
|
13
13
|
import { sleep } from '@aztec/foundation/sleep';
|
|
14
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
CommitteeAttestation,
|
|
17
|
+
EthAddress,
|
|
18
|
+
L2Block,
|
|
19
|
+
L2BlockHash,
|
|
20
|
+
PublishedL2Block,
|
|
21
|
+
type ValidateBlockResult,
|
|
22
|
+
randomBlockInfo,
|
|
23
|
+
wrapInBlock,
|
|
24
|
+
} from '@aztec/stdlib/block';
|
|
16
25
|
import {
|
|
17
26
|
type ContractClassPublic,
|
|
18
27
|
type ContractInstanceWithAddress,
|
|
@@ -34,7 +43,6 @@ import type { ArchiverDataStore, ArchiverL1SynchPoint } from './archiver_store.j
|
|
|
34
43
|
import { BlockNumberNotSequentialError, InitialBlockNumberNotSequentialError } from './errors.js';
|
|
35
44
|
import { MessageStoreError } from './kv_archiver_store/message_store.js';
|
|
36
45
|
import type { InboxMessage } from './structs/inbox_message.js';
|
|
37
|
-
import type { PublishedL2Block } from './structs/published.js';
|
|
38
46
|
|
|
39
47
|
/**
|
|
40
48
|
* @param testName - The name of the test suite.
|
|
@@ -58,15 +66,16 @@ export function describeArchiverDataStore(
|
|
|
58
66
|
|
|
59
67
|
const makeBlockHash = (blockNumber: number) => `0x${blockNumber.toString(16).padStart(64, '0')}`;
|
|
60
68
|
|
|
61
|
-
const makePublished = (block: L2Block, l1BlockNumber: number): PublishedL2Block =>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
const makePublished = (block: L2Block, l1BlockNumber: number): PublishedL2Block =>
|
|
70
|
+
PublishedL2Block.fromFields({
|
|
71
|
+
block: block,
|
|
72
|
+
l1: {
|
|
73
|
+
blockNumber: BigInt(l1BlockNumber),
|
|
74
|
+
blockHash: makeBlockHash(l1BlockNumber),
|
|
75
|
+
timestamp: BigInt(l1BlockNumber * 1000),
|
|
76
|
+
},
|
|
77
|
+
attestations: times(3, CommitteeAttestation.random),
|
|
78
|
+
});
|
|
70
79
|
|
|
71
80
|
const expectBlocksEqual = (actual: PublishedL2Block[], expected: PublishedL2Block[]) => {
|
|
72
81
|
expect(actual.length).toEqual(expected.length);
|
|
@@ -757,7 +766,7 @@ export function describeArchiverDataStore(
|
|
|
757
766
|
return txEffect;
|
|
758
767
|
});
|
|
759
768
|
|
|
760
|
-
return {
|
|
769
|
+
return PublishedL2Block.fromFields({
|
|
761
770
|
block: block,
|
|
762
771
|
attestations: times(3, CommitteeAttestation.random),
|
|
763
772
|
l1: {
|
|
@@ -765,7 +774,7 @@ export function describeArchiverDataStore(
|
|
|
765
774
|
blockHash: makeBlockHash(blockNumber),
|
|
766
775
|
timestamp: BigInt(blockNumber),
|
|
767
776
|
},
|
|
768
|
-
};
|
|
777
|
+
});
|
|
769
778
|
};
|
|
770
779
|
|
|
771
780
|
beforeEach(async () => {
|
|
@@ -878,11 +887,13 @@ export function describeArchiverDataStore(
|
|
|
878
887
|
let blocks: PublishedL2Block[];
|
|
879
888
|
|
|
880
889
|
beforeEach(async () => {
|
|
881
|
-
blocks = await timesParallel(numBlocks, async (index: number) =>
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
890
|
+
blocks = await timesParallel(numBlocks, async (index: number) =>
|
|
891
|
+
PublishedL2Block.fromFields({
|
|
892
|
+
block: await L2Block.random(index + 1, txsPerBlock, numPublicFunctionCalls, numPublicLogs),
|
|
893
|
+
l1: { blockNumber: BigInt(index), blockHash: makeBlockHash(index), timestamp: BigInt(index) },
|
|
894
|
+
attestations: times(3, CommitteeAttestation.random),
|
|
895
|
+
}),
|
|
896
|
+
);
|
|
886
897
|
|
|
887
898
|
await store.addBlocks(blocks);
|
|
888
899
|
await store.addLogs(blocks.map(b => b.block));
|
|
@@ -1056,5 +1067,96 @@ export function describeArchiverDataStore(
|
|
|
1056
1067
|
}
|
|
1057
1068
|
});
|
|
1058
1069
|
});
|
|
1070
|
+
|
|
1071
|
+
describe('pendingChainValidationStatus', () => {
|
|
1072
|
+
it('should return undefined when no status is set', async () => {
|
|
1073
|
+
const status = await store.getPendingChainValidationStatus();
|
|
1074
|
+
expect(status).toBeUndefined();
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
it('should store and retrieve a valid validation status', async () => {
|
|
1078
|
+
const validStatus: ValidateBlockResult = { valid: true };
|
|
1079
|
+
|
|
1080
|
+
await store.setPendingChainValidationStatus(validStatus);
|
|
1081
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1082
|
+
|
|
1083
|
+
expect(retrievedStatus).toEqual(validStatus);
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
it('should store and retrieve an invalid validation status with insufficient attestations', async () => {
|
|
1087
|
+
const invalidStatus: ValidateBlockResult = {
|
|
1088
|
+
valid: false,
|
|
1089
|
+
block: randomBlockInfo(1),
|
|
1090
|
+
committee: [EthAddress.random(), EthAddress.random()],
|
|
1091
|
+
epoch: 123n,
|
|
1092
|
+
seed: 456n,
|
|
1093
|
+
attestors: [EthAddress.random()],
|
|
1094
|
+
attestations: [CommitteeAttestation.random()],
|
|
1095
|
+
reason: 'insufficient-attestations',
|
|
1096
|
+
};
|
|
1097
|
+
|
|
1098
|
+
await store.setPendingChainValidationStatus(invalidStatus);
|
|
1099
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1100
|
+
|
|
1101
|
+
expect(retrievedStatus).toEqual(invalidStatus);
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
it('should store and retrieve an invalid validation status with invalid attestation', async () => {
|
|
1105
|
+
const invalidStatus: ValidateBlockResult = {
|
|
1106
|
+
valid: false,
|
|
1107
|
+
block: randomBlockInfo(2),
|
|
1108
|
+
committee: [EthAddress.random()],
|
|
1109
|
+
attestors: [EthAddress.random()],
|
|
1110
|
+
epoch: 789n,
|
|
1111
|
+
seed: 101n,
|
|
1112
|
+
attestations: [CommitteeAttestation.random()],
|
|
1113
|
+
reason: 'invalid-attestation',
|
|
1114
|
+
invalidIndex: 5,
|
|
1115
|
+
};
|
|
1116
|
+
|
|
1117
|
+
await store.setPendingChainValidationStatus(invalidStatus);
|
|
1118
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1119
|
+
|
|
1120
|
+
expect(retrievedStatus).toEqual(invalidStatus);
|
|
1121
|
+
});
|
|
1122
|
+
|
|
1123
|
+
it('should overwrite existing status when setting a new one', async () => {
|
|
1124
|
+
const firstStatus: ValidateBlockResult = { valid: true };
|
|
1125
|
+
const secondStatus: ValidateBlockResult = {
|
|
1126
|
+
valid: false,
|
|
1127
|
+
block: randomBlockInfo(3),
|
|
1128
|
+
committee: [EthAddress.random()],
|
|
1129
|
+
epoch: 999n,
|
|
1130
|
+
seed: 888n,
|
|
1131
|
+
attestors: [EthAddress.random()],
|
|
1132
|
+
attestations: [CommitteeAttestation.random()],
|
|
1133
|
+
reason: 'insufficient-attestations',
|
|
1134
|
+
};
|
|
1135
|
+
|
|
1136
|
+
await store.setPendingChainValidationStatus(firstStatus);
|
|
1137
|
+
await store.setPendingChainValidationStatus(secondStatus);
|
|
1138
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1139
|
+
|
|
1140
|
+
expect(retrievedStatus).toEqual(secondStatus);
|
|
1141
|
+
});
|
|
1142
|
+
|
|
1143
|
+
it('should handle empty committee and attestations arrays', async () => {
|
|
1144
|
+
const statusWithEmptyArrays: ValidateBlockResult = {
|
|
1145
|
+
valid: false,
|
|
1146
|
+
block: randomBlockInfo(4),
|
|
1147
|
+
committee: [],
|
|
1148
|
+
epoch: 0n,
|
|
1149
|
+
seed: 0n,
|
|
1150
|
+
attestors: [],
|
|
1151
|
+
attestations: [],
|
|
1152
|
+
reason: 'insufficient-attestations',
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
await store.setPendingChainValidationStatus(statusWithEmptyArrays);
|
|
1156
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1157
|
+
|
|
1158
|
+
expect(retrievedStatus).toEqual(statusWithEmptyArrays);
|
|
1159
|
+
});
|
|
1160
|
+
});
|
|
1059
1161
|
});
|
|
1060
1162
|
}
|
package/src/archiver/config.ts
CHANGED
|
@@ -1,47 +1,28 @@
|
|
|
1
1
|
import { type BlobSinkConfig, blobSinkConfigMapping } from '@aztec/blob-sink/client';
|
|
2
2
|
import {
|
|
3
|
-
type L1ContractAddresses,
|
|
4
3
|
type L1ContractsConfig,
|
|
5
4
|
type L1ReaderConfig,
|
|
6
5
|
l1ContractAddressesMapping,
|
|
7
6
|
l1ContractsConfigMappings,
|
|
8
7
|
l1ReaderConfigMappings,
|
|
9
8
|
} from '@aztec/ethereum';
|
|
10
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
type ConfigMappingsType,
|
|
11
|
+
booleanConfigHelper,
|
|
12
|
+
getConfigFromMappings,
|
|
13
|
+
numberConfigHelper,
|
|
14
|
+
} from '@aztec/foundation/config';
|
|
11
15
|
import { type ChainConfig, chainConfigMappings } from '@aztec/stdlib/config';
|
|
16
|
+
import type { ArchiverSpecificConfig } from '@aztec/stdlib/interfaces/server';
|
|
12
17
|
|
|
13
18
|
/**
|
|
19
|
+
* The archiver configuration.
|
|
14
20
|
* There are 2 polling intervals used in this configuration. The first is the archiver polling interval, archiverPollingIntervalMS.
|
|
15
21
|
* This is the interval between successive calls to eth_blockNumber via viem.
|
|
16
22
|
* Results of calls to eth_blockNumber are cached by viem with this cache being updated periodically at the interval specified by viemPollingIntervalMS.
|
|
17
23
|
* As a result the maximum observed polling time for new blocks will be viemPollingIntervalMS + archiverPollingIntervalMS.
|
|
18
24
|
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* The archiver configuration.
|
|
22
|
-
*/
|
|
23
|
-
export type ArchiverConfig = {
|
|
24
|
-
/** The polling interval in ms for retrieving new L2 blocks and encrypted logs. */
|
|
25
|
-
archiverPollingIntervalMS?: number;
|
|
26
|
-
|
|
27
|
-
/** The number of L2 blocks the archiver will attempt to download at a time. */
|
|
28
|
-
archiverBatchSize?: number;
|
|
29
|
-
|
|
30
|
-
/** The polling interval viem uses in ms */
|
|
31
|
-
viemPollingIntervalMS?: number;
|
|
32
|
-
|
|
33
|
-
/** The deployed L1 contract addresses */
|
|
34
|
-
l1Contracts: L1ContractAddresses;
|
|
35
|
-
|
|
36
|
-
/** The max number of logs that can be obtained in 1 "getPublicLogs" call. */
|
|
37
|
-
maxLogs?: number;
|
|
38
|
-
|
|
39
|
-
/** The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKB. */
|
|
40
|
-
archiverStoreMapSizeKb?: number;
|
|
41
|
-
} & L1ReaderConfig &
|
|
42
|
-
L1ContractsConfig &
|
|
43
|
-
BlobSinkConfig &
|
|
44
|
-
ChainConfig;
|
|
25
|
+
export type ArchiverConfig = ArchiverSpecificConfig & L1ReaderConfig & L1ContractsConfig & BlobSinkConfig & ChainConfig;
|
|
45
26
|
|
|
46
27
|
export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
47
28
|
...blobSinkConfigMapping,
|
|
@@ -65,6 +46,10 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
|
65
46
|
parseEnv: (val: string | undefined) => (val ? +val : undefined),
|
|
66
47
|
description: 'The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKB.',
|
|
67
48
|
},
|
|
49
|
+
skipValidateBlockAttestations: {
|
|
50
|
+
description: 'Whether to skip validating block attestations (use only for testing).',
|
|
51
|
+
...booleanConfigHelper(false),
|
|
52
|
+
},
|
|
68
53
|
...chainConfigMappings,
|
|
69
54
|
...l1ReaderConfigMappings,
|
|
70
55
|
viemPollingIntervalMS: {
|
|
@@ -15,7 +15,7 @@ import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
|
15
15
|
import { Fr } from '@aztec/foundation/fields';
|
|
16
16
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
17
17
|
import { type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
18
|
-
import { Body, CommitteeAttestation, L2Block } from '@aztec/stdlib/block';
|
|
18
|
+
import { Body, CommitteeAttestation, L2Block, PublishedL2Block } from '@aztec/stdlib/block';
|
|
19
19
|
import { Proof } from '@aztec/stdlib/proofs';
|
|
20
20
|
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
21
21
|
import { BlockHeader, GlobalVariables, ProposedBlockHeader, StateReference } from '@aztec/stdlib/tx';
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
import { NoBlobBodiesFoundError } from './errors.js';
|
|
34
34
|
import type { DataRetrieval } from './structs/data_retrieval.js';
|
|
35
35
|
import type { InboxMessage } from './structs/inbox_message.js';
|
|
36
|
-
import type { L1PublishedData
|
|
36
|
+
import type { L1PublishedData } from './structs/published.js';
|
|
37
37
|
|
|
38
38
|
export type RetrievedL2Block = {
|
|
39
39
|
l2BlockNumber: number;
|
|
@@ -87,11 +87,7 @@ export function retrievedBlockToPublishedL2Block(retrievedBlock: RetrievedL2Bloc
|
|
|
87
87
|
|
|
88
88
|
const block = new L2Block(archive, header, body);
|
|
89
89
|
|
|
90
|
-
return {
|
|
91
|
-
block,
|
|
92
|
-
l1,
|
|
93
|
-
attestations,
|
|
94
|
-
};
|
|
90
|
+
return PublishedL2Block.fromFields({ block, l1, attestations });
|
|
95
91
|
}
|
|
96
92
|
|
|
97
93
|
/**
|
|
@@ -6,7 +6,15 @@ import { BufferReader } from '@aztec/foundation/serialize';
|
|
|
6
6
|
import { bufferToHex } from '@aztec/foundation/string';
|
|
7
7
|
import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton, Range } from '@aztec/kv-store';
|
|
8
8
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
Body,
|
|
11
|
+
CommitteeAttestation,
|
|
12
|
+
L2Block,
|
|
13
|
+
L2BlockHash,
|
|
14
|
+
PublishedL2Block,
|
|
15
|
+
type ValidateBlockResult,
|
|
16
|
+
} from '@aztec/stdlib/block';
|
|
17
|
+
import { deserializeValidateBlockResult, serializeValidateBlockResult } from '@aztec/stdlib/block';
|
|
10
18
|
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
11
19
|
import {
|
|
12
20
|
BlockHeader,
|
|
@@ -19,7 +27,7 @@ import {
|
|
|
19
27
|
} from '@aztec/stdlib/tx';
|
|
20
28
|
|
|
21
29
|
import { BlockNumberNotSequentialError, InitialBlockNumberNotSequentialError } from '../errors.js';
|
|
22
|
-
import type { L1PublishedData
|
|
30
|
+
import type { L1PublishedData } from '../structs/published.js';
|
|
23
31
|
|
|
24
32
|
export { TxReceipt, type TxEffect, type TxHash } from '@aztec/stdlib/tx';
|
|
25
33
|
|
|
@@ -52,6 +60,9 @@ export class BlockStore {
|
|
|
52
60
|
/** Stores l2 block number of the last proven block */
|
|
53
61
|
#lastProvenL2Block: AztecAsyncSingleton<number>;
|
|
54
62
|
|
|
63
|
+
/** Stores the pending chain validation status */
|
|
64
|
+
#pendingChainValidationStatus: AztecAsyncSingleton<Buffer>;
|
|
65
|
+
|
|
55
66
|
/** Index mapping a contract's address (as a string) to its location in a block */
|
|
56
67
|
#contractIndex: AztecAsyncMap<string, BlockIndexValue>;
|
|
57
68
|
|
|
@@ -64,6 +75,7 @@ export class BlockStore {
|
|
|
64
75
|
this.#contractIndex = db.openMap('archiver_contract_index');
|
|
65
76
|
this.#lastSynchedL1Block = db.openSingleton('archiver_last_synched_l1_block');
|
|
66
77
|
this.#lastProvenL2Block = db.openSingleton('archiver_last_proven_l2_block');
|
|
78
|
+
this.#pendingChainValidationStatus = db.openSingleton('archiver_pending_chain_validation_status');
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
/**
|
|
@@ -224,7 +236,10 @@ export class BlockStore {
|
|
|
224
236
|
}
|
|
225
237
|
}
|
|
226
238
|
|
|
227
|
-
private async getBlockFromBlockStorage(
|
|
239
|
+
private async getBlockFromBlockStorage(
|
|
240
|
+
blockNumber: number,
|
|
241
|
+
blockStorage: BlockStorage,
|
|
242
|
+
): Promise<PublishedL2Block | undefined> {
|
|
228
243
|
const header = BlockHeader.fromBuffer(blockStorage.header);
|
|
229
244
|
const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
|
|
230
245
|
const blockHash = blockStorage.blockHash;
|
|
@@ -257,7 +272,7 @@ export class BlockStore {
|
|
|
257
272
|
);
|
|
258
273
|
}
|
|
259
274
|
const attestations = blockStorage.attestations.map(CommitteeAttestation.fromBuffer);
|
|
260
|
-
return { block, l1: blockStorage.l1, attestations };
|
|
275
|
+
return PublishedL2Block.fromFields({ block, l1: blockStorage.l1, attestations });
|
|
261
276
|
}
|
|
262
277
|
|
|
263
278
|
/**
|
|
@@ -361,4 +376,29 @@ export class BlockStore {
|
|
|
361
376
|
|
|
362
377
|
return { start, limit };
|
|
363
378
|
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Gets the pending chain validation status.
|
|
382
|
+
* @returns The validation status or undefined if not set.
|
|
383
|
+
*/
|
|
384
|
+
async getPendingChainValidationStatus(): Promise<ValidateBlockResult | undefined> {
|
|
385
|
+
const buffer = await this.#pendingChainValidationStatus.getAsync();
|
|
386
|
+
if (!buffer) {
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
return deserializeValidateBlockResult(buffer);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Sets the pending chain validation status.
|
|
394
|
+
* @param status - The validation status to store.
|
|
395
|
+
*/
|
|
396
|
+
async setPendingChainValidationStatus(status: ValidateBlockResult | undefined): Promise<void> {
|
|
397
|
+
if (status) {
|
|
398
|
+
const buffer = serializeValidateBlockResult(status);
|
|
399
|
+
await this.#pendingChainValidationStatus.set(buffer);
|
|
400
|
+
} else {
|
|
401
|
+
await this.#pendingChainValidationStatus.delete();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
364
404
|
}
|
|
@@ -5,7 +5,7 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
5
5
|
import type { AztecAsyncKVStore, CustomRange, StoreSize } from '@aztec/kv-store';
|
|
6
6
|
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
7
7
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
8
|
-
import type { L2Block } from '@aztec/stdlib/block';
|
|
8
|
+
import type { L2Block, ValidateBlockResult } from '@aztec/stdlib/block';
|
|
9
9
|
import type {
|
|
10
10
|
ContractClassPublic,
|
|
11
11
|
ContractDataSource,
|
|
@@ -395,4 +395,12 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
395
395
|
public removeL1ToL2Messages(startIndex: bigint): Promise<void> {
|
|
396
396
|
return this.#messageStore.removeL1ToL2Messages(startIndex);
|
|
397
397
|
}
|
|
398
|
+
|
|
399
|
+
public getPendingChainValidationStatus(): Promise<ValidateBlockResult | undefined> {
|
|
400
|
+
return this.#blockStore.getPendingChainValidationStatus();
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
public setPendingChainValidationStatus(status: ValidateBlockResult | undefined): Promise<void> {
|
|
404
|
+
return this.#blockStore.setPendingChainValidationStatus(status);
|
|
405
|
+
}
|
|
398
406
|
}
|
|
@@ -20,6 +20,7 @@ export async function validateBlockAttestations(
|
|
|
20
20
|
logger?: Logger,
|
|
21
21
|
): Promise<ValidateBlockResult> {
|
|
22
22
|
const attestations = getAttestationsFromPublishedL2Block(publishedBlock);
|
|
23
|
+
const attestors = attestations.map(a => a.getSender());
|
|
23
24
|
const { block } = publishedBlock;
|
|
24
25
|
const blockHash = await block.hash().then(hash => hash.toString());
|
|
25
26
|
const archiveRoot = block.archive.root.toString();
|
|
@@ -51,7 +52,17 @@ export async function validateBlockAttestations(
|
|
|
51
52
|
if (!committeeSet.has(signer)) {
|
|
52
53
|
logger?.warn(`Attestation from non-committee member ${signer} at slot ${slot}`, { committee });
|
|
53
54
|
const reason = 'invalid-attestation';
|
|
54
|
-
return {
|
|
55
|
+
return {
|
|
56
|
+
valid: false,
|
|
57
|
+
reason,
|
|
58
|
+
invalidIndex: i,
|
|
59
|
+
block: publishedBlock.block.toBlockInfo(),
|
|
60
|
+
committee,
|
|
61
|
+
seed,
|
|
62
|
+
epoch,
|
|
63
|
+
attestors,
|
|
64
|
+
attestations: publishedBlock.attestations,
|
|
65
|
+
};
|
|
55
66
|
}
|
|
56
67
|
}
|
|
57
68
|
|
|
@@ -62,7 +73,16 @@ export async function validateBlockAttestations(
|
|
|
62
73
|
...logData,
|
|
63
74
|
});
|
|
64
75
|
const reason = 'insufficient-attestations';
|
|
65
|
-
return {
|
|
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
|
+
};
|
|
66
86
|
}
|
|
67
87
|
|
|
68
88
|
logger?.debug(`Block attestations validated successfully for block ${block.number} at slot ${slot}`, logData);
|
|
@@ -5,7 +5,14 @@ import type { Fr } from '@aztec/foundation/fields';
|
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
6
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
7
7
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
L2Block,
|
|
10
|
+
L2BlockHash,
|
|
11
|
+
type L2BlockSource,
|
|
12
|
+
type L2Tips,
|
|
13
|
+
PublishedL2Block,
|
|
14
|
+
type ValidateBlockResult,
|
|
15
|
+
} from '@aztec/stdlib/block';
|
|
9
16
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
10
17
|
import { EmptyL1RollupConstants, type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
11
18
|
import { type BlockHeader, TxHash, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
@@ -106,15 +113,17 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
106
113
|
|
|
107
114
|
public async getPublishedBlocks(from: number, limit: number, proven?: boolean) {
|
|
108
115
|
const blocks = await this.getBlocks(from, limit, proven);
|
|
109
|
-
return blocks.map(block =>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
return blocks.map(block =>
|
|
117
|
+
PublishedL2Block.fromFields({
|
|
118
|
+
block,
|
|
119
|
+
l1: {
|
|
120
|
+
blockNumber: BigInt(block.number),
|
|
121
|
+
blockHash: Buffer32.random().toString(),
|
|
122
|
+
timestamp: BigInt(block.number),
|
|
123
|
+
},
|
|
124
|
+
attestations: [],
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
118
127
|
}
|
|
119
128
|
|
|
120
129
|
getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
|