@aztec/archiver 0.7.0 → 0.7.2
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/Dockerfile +15 -0
- package/package.json +6 -6
- package/.tsbuildinfo +0 -1
- package/dest/archiver/archiver.d.ts +0 -147
- package/dest/archiver/archiver.d.ts.map +0 -1
- package/dest/archiver/archiver.js +0 -269
- package/dest/archiver/archiver.test.d.ts +0 -2
- package/dest/archiver/archiver.test.d.ts.map +0 -1
- package/dest/archiver/archiver.test.js +0 -184
- package/dest/archiver/archiver_store.d.ts +0 -267
- package/dest/archiver/archiver_store.d.ts.map +0 -1
- package/dest/archiver/archiver_store.js +0 -256
- package/dest/archiver/archiver_store.test.d.ts +0 -2
- package/dest/archiver/archiver_store.test.d.ts.map +0 -1
- package/dest/archiver/archiver_store.test.js +0 -61
- package/dest/archiver/config.d.ts +0 -39
- package/dest/archiver/config.d.ts.map +0 -1
- package/dest/archiver/config.js +0 -22
- package/dest/archiver/data_retrieval.d.ts +0 -64
- package/dest/archiver/data_retrieval.d.ts.map +0 -1
- package/dest/archiver/data_retrieval.js +0 -102
- package/dest/archiver/eth_log_handlers.d.ts +0 -77
- package/dest/archiver/eth_log_handlers.d.ts.map +0 -1
- package/dest/archiver/eth_log_handlers.js +0 -180
- package/dest/archiver/index.d.ts +0 -3
- package/dest/archiver/index.d.ts.map +0 -1
- package/dest/archiver/index.js +0 -3
- package/dest/archiver/l1_to_l2_message_store.d.ts +0 -40
- package/dest/archiver/l1_to_l2_message_store.d.ts.map +0 -1
- package/dest/archiver/l1_to_l2_message_store.js +0 -71
- package/dest/archiver/l1_to_l2_message_store.test.d.ts +0 -2
- package/dest/archiver/l1_to_l2_message_store.test.d.ts.map +0 -1
- package/dest/archiver/l1_to_l2_message_store.test.js +0 -77
- package/dest/index.d.ts +0 -2
- package/dest/index.d.ts.map +0 -1
- package/dest/index.js +0 -37
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { FunctionSelector } from '@aztec/circuits.js';
|
|
2
|
-
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
3
|
-
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
5
|
-
import { DebugLogger } from '@aztec/foundation/log';
|
|
6
|
-
import { ContractData, ContractDataSource, EncodedContractFunction, ExtendedContractData, L1ToL2Message, L1ToL2MessageSource, L2Block, L2BlockL2Logs, L2BlockSource, L2LogsSource, L2Tx, LogType, TxHash } from '@aztec/types';
|
|
7
|
-
import { Chain, HttpTransport, PublicClient } from 'viem';
|
|
8
|
-
import { ArchiverDataStore } from './archiver_store.js';
|
|
9
|
-
import { ArchiverConfig } from './config.js';
|
|
10
|
-
/**
|
|
11
|
-
* Pulls L2 blocks in a non-blocking manner and provides interface for their retrieval.
|
|
12
|
-
* Responsible for handling robust L1 polling so that other components do not need to
|
|
13
|
-
* concern themselves with it.
|
|
14
|
-
*/
|
|
15
|
-
export declare class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource, L1ToL2MessageSource {
|
|
16
|
-
private readonly publicClient;
|
|
17
|
-
private readonly rollupAddress;
|
|
18
|
-
private readonly inboxAddress;
|
|
19
|
-
private readonly contractDeploymentEmitterAddress;
|
|
20
|
-
private readonly store;
|
|
21
|
-
private readonly pollingIntervalMs;
|
|
22
|
-
private readonly log;
|
|
23
|
-
/**
|
|
24
|
-
* A promise in which we will be continually fetching new L2 blocks.
|
|
25
|
-
*/
|
|
26
|
-
private runningPromise?;
|
|
27
|
-
/**
|
|
28
|
-
* Next L1 block number to fetch `L2BlockProcessed` logs from (i.e. `fromBlock` in eth_getLogs).
|
|
29
|
-
*/
|
|
30
|
-
private nextL2BlockFromBlock;
|
|
31
|
-
/**
|
|
32
|
-
* Last Processed Block Number
|
|
33
|
-
*/
|
|
34
|
-
private lastProcessedBlockNumber;
|
|
35
|
-
/**
|
|
36
|
-
* Use this to track logged block in order to avoid repeating the same message.
|
|
37
|
-
*/
|
|
38
|
-
private lastLoggedBlockNumber;
|
|
39
|
-
/**
|
|
40
|
-
* Creates a new instance of the Archiver.
|
|
41
|
-
* @param publicClient - A client for interacting with the Ethereum node.
|
|
42
|
-
* @param rollupAddress - Ethereum address of the rollup contract.
|
|
43
|
-
* @param inboxAddress - Ethereum address of the inbox contract.
|
|
44
|
-
* @param contractDeploymentEmitterAddress - Ethereum address of the contractDeploymentEmitter contract.
|
|
45
|
-
* @param searchStartBlock - The L1 block from which to start searching for new blocks.
|
|
46
|
-
* @param pollingIntervalMs - The interval for polling for L1 logs (in milliseconds).
|
|
47
|
-
* @param store - An archiver data store for storage & retrieval of blocks, encrypted logs & contract data.
|
|
48
|
-
* @param log - A logger.
|
|
49
|
-
*/
|
|
50
|
-
constructor(publicClient: PublicClient<HttpTransport, Chain>, rollupAddress: EthAddress, inboxAddress: EthAddress, contractDeploymentEmitterAddress: EthAddress, searchStartBlock: number, store: ArchiverDataStore, pollingIntervalMs?: number, log?: DebugLogger);
|
|
51
|
-
/**
|
|
52
|
-
* Creates a new instance of the Archiver and blocks until it syncs from chain.
|
|
53
|
-
* @param config - The archiver's desired configuration.
|
|
54
|
-
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
55
|
-
* @returns - An instance of the archiver.
|
|
56
|
-
*/
|
|
57
|
-
static createAndSync(config: ArchiverConfig, blockUntilSynced?: boolean): Promise<Archiver>;
|
|
58
|
-
/**
|
|
59
|
-
* Starts sync process.
|
|
60
|
-
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
61
|
-
*/
|
|
62
|
-
start(blockUntilSynced: boolean): Promise<void>;
|
|
63
|
-
/**
|
|
64
|
-
* Fetches `L2BlockProcessed` and `ContractDeployment` logs from `nextL2BlockFromBlock` and processes them.
|
|
65
|
-
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
66
|
-
*/
|
|
67
|
-
private sync;
|
|
68
|
-
/**
|
|
69
|
-
* Stops the archiver.
|
|
70
|
-
* @returns A promise signalling completion of the stop process.
|
|
71
|
-
*/
|
|
72
|
-
stop(): Promise<void>;
|
|
73
|
-
getRollupAddress(): Promise<EthAddress>;
|
|
74
|
-
/**
|
|
75
|
-
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
76
|
-
* @param from - Number of the first block to return (inclusive).
|
|
77
|
-
* @param limit - The number of blocks to return.
|
|
78
|
-
* @returns The requested L2 blocks.
|
|
79
|
-
*/
|
|
80
|
-
getL2Blocks(from: number, limit: number): Promise<L2Block[]>;
|
|
81
|
-
/**
|
|
82
|
-
* Gets an l2 block.
|
|
83
|
-
* @param number - The block number to return (inclusive).
|
|
84
|
-
* @returns The requested L2 block.
|
|
85
|
-
*/
|
|
86
|
-
getL2Block(number: number): Promise<L2Block | undefined>;
|
|
87
|
-
getL2Tx(txHash: TxHash): Promise<L2Tx | undefined>;
|
|
88
|
-
/**
|
|
89
|
-
* Get the extended contract data for this contract.
|
|
90
|
-
* @param contractAddress - The contract data address.
|
|
91
|
-
* @returns The extended contract data or undefined if not found.
|
|
92
|
-
*/
|
|
93
|
-
getExtendedContractData(contractAddress: AztecAddress): Promise<ExtendedContractData | undefined>;
|
|
94
|
-
/**
|
|
95
|
-
* Lookup all contract data in an L2 block.
|
|
96
|
-
* @param blockNum - The block number to get all contract data from.
|
|
97
|
-
* @returns All new contract data in the block (if found).
|
|
98
|
-
*/
|
|
99
|
-
getExtendedContractDataInBlock(blockNum: number): Promise<ExtendedContractData[]>;
|
|
100
|
-
/**
|
|
101
|
-
* Lookup the contract data for this contract.
|
|
102
|
-
* Contains contract address & the ethereum portal address.
|
|
103
|
-
* @param contractAddress - The contract data address.
|
|
104
|
-
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
105
|
-
*/
|
|
106
|
-
getContractData(contractAddress: AztecAddress): Promise<ContractData | undefined>;
|
|
107
|
-
/**
|
|
108
|
-
* Lookup the L2 contract data inside a block.
|
|
109
|
-
* Contains contract address & the ethereum portal address.
|
|
110
|
-
* @param l2BlockNum - The L2 block number to get the contract data from.
|
|
111
|
-
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
112
|
-
*/
|
|
113
|
-
getContractDataInBlock(l2BlockNum: number): Promise<ContractData[] | undefined>;
|
|
114
|
-
/**
|
|
115
|
-
* Gets the public function data for a contract.
|
|
116
|
-
* @param contractAddress - The contract address containing the function to fetch.
|
|
117
|
-
* @param selector - The function selector of the function to fetch.
|
|
118
|
-
* @returns The public function data (if found).
|
|
119
|
-
*/
|
|
120
|
-
getPublicFunction(contractAddress: AztecAddress, selector: FunctionSelector): Promise<EncodedContractFunction | undefined>;
|
|
121
|
-
/**
|
|
122
|
-
* Gets up to `limit` amount of logs starting from `from`.
|
|
123
|
-
* @param from - Number of the L2 block to which corresponds the first logs to be returned.
|
|
124
|
-
* @param limit - The number of logs to return.
|
|
125
|
-
* @param logType - Specifies whether to return encrypted or unencrypted logs.
|
|
126
|
-
* @returns The requested logs.
|
|
127
|
-
*/
|
|
128
|
-
getLogs(from: number, limit: number, logType: LogType): Promise<L2BlockL2Logs[]>;
|
|
129
|
-
/**
|
|
130
|
-
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
131
|
-
* @returns The number of the latest L2 block processed by the block source implementation.
|
|
132
|
-
*/
|
|
133
|
-
getBlockNumber(): Promise<number>;
|
|
134
|
-
/**
|
|
135
|
-
* Gets up to `limit` amount of pending L1 to L2 messages.
|
|
136
|
-
* @param limit - The number of messages to return.
|
|
137
|
-
* @returns The requested L1 to L2 messages' keys.
|
|
138
|
-
*/
|
|
139
|
-
getPendingL1ToL2Messages(limit: number): Promise<Fr[]>;
|
|
140
|
-
/**
|
|
141
|
-
* Gets the confirmed/consumed L1 to L2 message associated with the given message key
|
|
142
|
-
* @param messageKey - The message key.
|
|
143
|
-
* @returns The L1 to L2 message (throws if not found).
|
|
144
|
-
*/
|
|
145
|
-
getConfirmedL1ToL2Message(messageKey: Fr): Promise<L1ToL2Message>;
|
|
146
|
-
}
|
|
147
|
-
//# sourceMappingURL=archiver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"archiver.d.ts","sourceRoot":"","sources":["../../src/archiver/archiver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
import { createEthereumChain } from '@aztec/ethereum';
|
|
2
|
-
import { createDebugLogger } from '@aztec/foundation/log';
|
|
3
|
-
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
4
|
-
import { INITIAL_L2_BLOCK_NUM, L2Block, LogType, } from '@aztec/types';
|
|
5
|
-
import omit from 'lodash.omit';
|
|
6
|
-
import { createPublicClient, http } from 'viem';
|
|
7
|
-
import { MemoryArchiverStore } from './archiver_store.js';
|
|
8
|
-
import { retrieveBlocks, retrieveNewCancelledL1ToL2Messages, retrieveNewContractData, retrieveNewPendingL1ToL2Messages, } from './data_retrieval.js';
|
|
9
|
-
/**
|
|
10
|
-
* Pulls L2 blocks in a non-blocking manner and provides interface for their retrieval.
|
|
11
|
-
* Responsible for handling robust L1 polling so that other components do not need to
|
|
12
|
-
* concern themselves with it.
|
|
13
|
-
*/
|
|
14
|
-
export class Archiver {
|
|
15
|
-
/**
|
|
16
|
-
* Creates a new instance of the Archiver.
|
|
17
|
-
* @param publicClient - A client for interacting with the Ethereum node.
|
|
18
|
-
* @param rollupAddress - Ethereum address of the rollup contract.
|
|
19
|
-
* @param inboxAddress - Ethereum address of the inbox contract.
|
|
20
|
-
* @param contractDeploymentEmitterAddress - Ethereum address of the contractDeploymentEmitter contract.
|
|
21
|
-
* @param searchStartBlock - The L1 block from which to start searching for new blocks.
|
|
22
|
-
* @param pollingIntervalMs - The interval for polling for L1 logs (in milliseconds).
|
|
23
|
-
* @param store - An archiver data store for storage & retrieval of blocks, encrypted logs & contract data.
|
|
24
|
-
* @param log - A logger.
|
|
25
|
-
*/
|
|
26
|
-
constructor(publicClient, rollupAddress, inboxAddress, contractDeploymentEmitterAddress, searchStartBlock, store, pollingIntervalMs = 10000, log = createDebugLogger('aztec:archiver')) {
|
|
27
|
-
this.publicClient = publicClient;
|
|
28
|
-
this.rollupAddress = rollupAddress;
|
|
29
|
-
this.inboxAddress = inboxAddress;
|
|
30
|
-
this.contractDeploymentEmitterAddress = contractDeploymentEmitterAddress;
|
|
31
|
-
this.store = store;
|
|
32
|
-
this.pollingIntervalMs = pollingIntervalMs;
|
|
33
|
-
this.log = log;
|
|
34
|
-
/**
|
|
35
|
-
* Next L1 block number to fetch `L2BlockProcessed` logs from (i.e. `fromBlock` in eth_getLogs).
|
|
36
|
-
*/
|
|
37
|
-
this.nextL2BlockFromBlock = 0n;
|
|
38
|
-
/**
|
|
39
|
-
* Last Processed Block Number
|
|
40
|
-
*/
|
|
41
|
-
this.lastProcessedBlockNumber = 0n;
|
|
42
|
-
/**
|
|
43
|
-
* Use this to track logged block in order to avoid repeating the same message.
|
|
44
|
-
*/
|
|
45
|
-
this.lastLoggedBlockNumber = 0n;
|
|
46
|
-
this.nextL2BlockFromBlock = BigInt(searchStartBlock);
|
|
47
|
-
this.lastProcessedBlockNumber = BigInt(searchStartBlock);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Creates a new instance of the Archiver and blocks until it syncs from chain.
|
|
51
|
-
* @param config - The archiver's desired configuration.
|
|
52
|
-
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
53
|
-
* @returns - An instance of the archiver.
|
|
54
|
-
*/
|
|
55
|
-
static async createAndSync(config, blockUntilSynced = true) {
|
|
56
|
-
const chain = createEthereumChain(config.rpcUrl, config.apiKey);
|
|
57
|
-
const publicClient = createPublicClient({
|
|
58
|
-
chain: chain.chainInfo,
|
|
59
|
-
transport: http(chain.rpcUrl),
|
|
60
|
-
pollingInterval: config.viemPollingIntervalMS,
|
|
61
|
-
});
|
|
62
|
-
const archiverStore = new MemoryArchiverStore();
|
|
63
|
-
const archiver = new Archiver(publicClient, config.rollupContract, config.inboxContract, config.contractDeploymentEmitterContract, config.searchStartBlock, archiverStore, config.archiverPollingIntervalMS);
|
|
64
|
-
await archiver.start(blockUntilSynced);
|
|
65
|
-
return archiver;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Starts sync process.
|
|
69
|
-
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
70
|
-
*/
|
|
71
|
-
async start(blockUntilSynced) {
|
|
72
|
-
if (this.runningPromise) {
|
|
73
|
-
throw new Error('Archiver is already running');
|
|
74
|
-
}
|
|
75
|
-
if (blockUntilSynced) {
|
|
76
|
-
this.log(`Performing initial chain sync...`);
|
|
77
|
-
await this.sync(blockUntilSynced);
|
|
78
|
-
}
|
|
79
|
-
this.runningPromise = new RunningPromise(() => this.sync(false), this.pollingIntervalMs);
|
|
80
|
-
this.runningPromise.start();
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Fetches `L2BlockProcessed` and `ContractDeployment` logs from `nextL2BlockFromBlock` and processes them.
|
|
84
|
-
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
85
|
-
*/
|
|
86
|
-
async sync(blockUntilSynced) {
|
|
87
|
-
const currentBlockNumber = await this.publicClient.getBlockNumber();
|
|
88
|
-
if (currentBlockNumber <= this.lastProcessedBlockNumber) {
|
|
89
|
-
// reducing logs, otherwise this gets triggered on every loop (1s)
|
|
90
|
-
if (currentBlockNumber !== this.lastLoggedBlockNumber) {
|
|
91
|
-
this.log(`No new blocks to process, current block number: ${currentBlockNumber}`);
|
|
92
|
-
this.lastLoggedBlockNumber = currentBlockNumber;
|
|
93
|
-
}
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
// ********** Events that are processed in between blocks **********
|
|
97
|
-
// Process l1ToL2Messages, these are consumed as time passes, not each block
|
|
98
|
-
const retrievedPendingL1ToL2Messages = await retrieveNewPendingL1ToL2Messages(this.publicClient, this.inboxAddress, blockUntilSynced, currentBlockNumber, this.lastProcessedBlockNumber + 1n);
|
|
99
|
-
const retrievedCancelledL1ToL2Messages = await retrieveNewCancelledL1ToL2Messages(this.publicClient, this.inboxAddress, blockUntilSynced, currentBlockNumber, this.lastProcessedBlockNumber + 1n);
|
|
100
|
-
// TODO (#717): optimise this - there could be messages in confirmed that are also in pending.
|
|
101
|
-
// Or messages in pending that are also cancelled in the same block. No need to modify storage for them.
|
|
102
|
-
// Store l1 to l2 messages
|
|
103
|
-
this.log('Adding pending l1 to l2 messages to store');
|
|
104
|
-
await this.store.addPendingL1ToL2Messages(retrievedPendingL1ToL2Messages.retrievedData);
|
|
105
|
-
// remove cancelled messages from the pending message store:
|
|
106
|
-
this.log('Removing pending l1 to l2 messages from store where messages were cancelled');
|
|
107
|
-
await this.store.cancelPendingL1ToL2Messages(retrievedCancelledL1ToL2Messages.retrievedData);
|
|
108
|
-
this.lastProcessedBlockNumber = currentBlockNumber;
|
|
109
|
-
// ********** Events that are processed per block **********
|
|
110
|
-
// Read all data from chain and then write to our stores at the end
|
|
111
|
-
const nextExpectedL2BlockNum = BigInt(this.store.getBlocksLength() + INITIAL_L2_BLOCK_NUM);
|
|
112
|
-
this.log(`Retrieving chain state from L1 block: ${this.nextL2BlockFromBlock}, next expected l2 block number: ${nextExpectedL2BlockNum}`);
|
|
113
|
-
const retrievedBlocks = await retrieveBlocks(this.publicClient, this.rollupAddress, blockUntilSynced, currentBlockNumber, this.nextL2BlockFromBlock, nextExpectedL2BlockNum);
|
|
114
|
-
// create the block number -> block hash mapping to ensure we retrieve the appropriate events
|
|
115
|
-
const blockHashMapping = {};
|
|
116
|
-
retrievedBlocks.retrievedData.forEach((block) => {
|
|
117
|
-
blockHashMapping[block.number] = block.getCalldataHash();
|
|
118
|
-
});
|
|
119
|
-
const retrievedContracts = await retrieveNewContractData(this.publicClient, this.contractDeploymentEmitterAddress, blockUntilSynced, currentBlockNumber, this.nextL2BlockFromBlock, blockHashMapping);
|
|
120
|
-
if (retrievedBlocks.retrievedData.length === 0) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
this.log(`Retrieved ${retrievedBlocks.retrievedData.length} block(s) from chain`);
|
|
124
|
-
// store encrypted logs from L2 Blocks that we have retrieved
|
|
125
|
-
const encryptedLogs = retrievedBlocks.retrievedData.map(block => {
|
|
126
|
-
return block.newEncryptedLogs;
|
|
127
|
-
});
|
|
128
|
-
await this.store.addLogs(encryptedLogs, LogType.ENCRYPTED);
|
|
129
|
-
// store unencrypted logs from L2 Blocks that we have retrieved
|
|
130
|
-
const unencryptedLogs = retrievedBlocks.retrievedData.map(block => {
|
|
131
|
-
return block.newUnencryptedLogs;
|
|
132
|
-
});
|
|
133
|
-
await this.store.addLogs(unencryptedLogs, LogType.UNENCRYPTED);
|
|
134
|
-
// store contracts for which we have retrieved L2 blocks
|
|
135
|
-
const lastKnownL2BlockNum = retrievedBlocks.retrievedData[retrievedBlocks.retrievedData.length - 1].number;
|
|
136
|
-
retrievedContracts.retrievedData.forEach(async ([contracts, l2BlockNum], index) => {
|
|
137
|
-
this.log(`Retrieved extended contract data for l2 block number: ${index}`);
|
|
138
|
-
if (l2BlockNum <= lastKnownL2BlockNum) {
|
|
139
|
-
await this.store.addExtendedContractData(contracts, l2BlockNum);
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
// from retrieved L2Blocks, confirm L1 to L2 messages that have been published
|
|
143
|
-
// from each l2block fetch all messageKeys in a flattened array:
|
|
144
|
-
const messageKeysToRemove = retrievedBlocks.retrievedData.map(l2block => l2block.newL1ToL2Messages).flat();
|
|
145
|
-
this.log(`Confirming l1 to l2 messages in store`);
|
|
146
|
-
await this.store.confirmL1ToL2Messages(messageKeysToRemove);
|
|
147
|
-
// store retrieved L2 blocks after removing new logs information.
|
|
148
|
-
// remove logs to serve "lightweight" block information. Logs can be fetched separately if needed.
|
|
149
|
-
await this.store.addL2Blocks(retrievedBlocks.retrievedData.map(block => L2Block.fromFields(omit(block, ['newEncryptedLogs', 'newUnencryptedLogs']), block.getBlockHash())));
|
|
150
|
-
// set the L1 block for the next search
|
|
151
|
-
this.nextL2BlockFromBlock = retrievedBlocks.nextEthBlockNumber;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Stops the archiver.
|
|
155
|
-
* @returns A promise signalling completion of the stop process.
|
|
156
|
-
*/
|
|
157
|
-
async stop() {
|
|
158
|
-
this.log('Stopping...');
|
|
159
|
-
await this.runningPromise?.stop();
|
|
160
|
-
this.log('Stopped.');
|
|
161
|
-
return Promise.resolve();
|
|
162
|
-
}
|
|
163
|
-
getRollupAddress() {
|
|
164
|
-
return Promise.resolve(this.rollupAddress);
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
168
|
-
* @param from - Number of the first block to return (inclusive).
|
|
169
|
-
* @param limit - The number of blocks to return.
|
|
170
|
-
* @returns The requested L2 blocks.
|
|
171
|
-
*/
|
|
172
|
-
getL2Blocks(from, limit) {
|
|
173
|
-
return this.store.getL2Blocks(from, limit);
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Gets an l2 block.
|
|
177
|
-
* @param number - The block number to return (inclusive).
|
|
178
|
-
* @returns The requested L2 block.
|
|
179
|
-
*/
|
|
180
|
-
async getL2Block(number) {
|
|
181
|
-
// If the number provided is -ve, then return the latest block.
|
|
182
|
-
if (number < 0) {
|
|
183
|
-
number = this.store.getBlocksLength();
|
|
184
|
-
}
|
|
185
|
-
const blocks = await this.store.getL2Blocks(number, 1);
|
|
186
|
-
return blocks.length === 0 ? undefined : blocks[0];
|
|
187
|
-
}
|
|
188
|
-
getL2Tx(txHash) {
|
|
189
|
-
return this.store.getL2Tx(txHash);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Get the extended contract data for this contract.
|
|
193
|
-
* @param contractAddress - The contract data address.
|
|
194
|
-
* @returns The extended contract data or undefined if not found.
|
|
195
|
-
*/
|
|
196
|
-
getExtendedContractData(contractAddress) {
|
|
197
|
-
return this.store.getExtendedContractData(contractAddress);
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Lookup all contract data in an L2 block.
|
|
201
|
-
* @param blockNum - The block number to get all contract data from.
|
|
202
|
-
* @returns All new contract data in the block (if found).
|
|
203
|
-
*/
|
|
204
|
-
getExtendedContractDataInBlock(blockNum) {
|
|
205
|
-
return this.store.getExtendedContractDataInBlock(blockNum);
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Lookup the contract data for this contract.
|
|
209
|
-
* Contains contract address & the ethereum portal address.
|
|
210
|
-
* @param contractAddress - The contract data address.
|
|
211
|
-
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
212
|
-
*/
|
|
213
|
-
getContractData(contractAddress) {
|
|
214
|
-
return this.store.getContractData(contractAddress);
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Lookup the L2 contract data inside a block.
|
|
218
|
-
* Contains contract address & the ethereum portal address.
|
|
219
|
-
* @param l2BlockNum - The L2 block number to get the contract data from.
|
|
220
|
-
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
221
|
-
*/
|
|
222
|
-
getContractDataInBlock(l2BlockNum) {
|
|
223
|
-
return this.store.getContractDataInBlock(l2BlockNum);
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Gets the public function data for a contract.
|
|
227
|
-
* @param contractAddress - The contract address containing the function to fetch.
|
|
228
|
-
* @param selector - The function selector of the function to fetch.
|
|
229
|
-
* @returns The public function data (if found).
|
|
230
|
-
*/
|
|
231
|
-
async getPublicFunction(contractAddress, selector) {
|
|
232
|
-
const contractData = await this.getExtendedContractData(contractAddress);
|
|
233
|
-
return contractData?.getPublicFunction(selector);
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Gets up to `limit` amount of logs starting from `from`.
|
|
237
|
-
* @param from - Number of the L2 block to which corresponds the first logs to be returned.
|
|
238
|
-
* @param limit - The number of logs to return.
|
|
239
|
-
* @param logType - Specifies whether to return encrypted or unencrypted logs.
|
|
240
|
-
* @returns The requested logs.
|
|
241
|
-
*/
|
|
242
|
-
getLogs(from, limit, logType) {
|
|
243
|
-
return this.store.getLogs(from, limit, logType);
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
247
|
-
* @returns The number of the latest L2 block processed by the block source implementation.
|
|
248
|
-
*/
|
|
249
|
-
getBlockNumber() {
|
|
250
|
-
return this.store.getBlockNumber();
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Gets up to `limit` amount of pending L1 to L2 messages.
|
|
254
|
-
* @param limit - The number of messages to return.
|
|
255
|
-
* @returns The requested L1 to L2 messages' keys.
|
|
256
|
-
*/
|
|
257
|
-
getPendingL1ToL2Messages(limit) {
|
|
258
|
-
return this.store.getPendingL1ToL2MessageKeys(limit);
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Gets the confirmed/consumed L1 to L2 message associated with the given message key
|
|
262
|
-
* @param messageKey - The message key.
|
|
263
|
-
* @returns The L1 to L2 message (throws if not found).
|
|
264
|
-
*/
|
|
265
|
-
getConfirmedL1ToL2Message(messageKey) {
|
|
266
|
-
return this.store.getConfirmedL1ToL2Message(messageKey);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJjaGl2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXJjaGl2ZXIvYXJjaGl2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFJdEQsT0FBTyxFQUFlLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDdkUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ25FLE9BQU8sRUFLTCxvQkFBb0IsRUFHcEIsT0FBTyxFQUtQLE9BQU8sR0FFUixNQUFNLGNBQWMsQ0FBQztBQUV0QixPQUFPLElBQUksTUFBTSxhQUFhLENBQUM7QUFDL0IsT0FBTyxFQUFzQyxrQkFBa0IsRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFcEYsT0FBTyxFQUFxQixtQkFBbUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTdFLE9BQU8sRUFDTCxjQUFjLEVBQ2Qsa0NBQWtDLEVBQ2xDLHVCQUF1QixFQUN2QixnQ0FBZ0MsR0FDakMsTUFBTSxxQkFBcUIsQ0FBQztBQUU3Qjs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLFFBQVE7SUFxQm5COzs7Ozs7Ozs7O09BVUc7SUFDSCxZQUNtQixZQUFnRCxFQUNoRCxhQUF5QixFQUN6QixZQUF3QixFQUN4QixnQ0FBNEMsRUFDN0QsZ0JBQXdCLEVBQ1AsS0FBd0IsRUFDeEIsb0JBQW9CLEtBQU0sRUFDMUIsTUFBbUIsaUJBQWlCLENBQUMsZ0JBQWdCLENBQUM7UUFQdEQsaUJBQVksR0FBWixZQUFZLENBQW9DO1FBQ2hELGtCQUFhLEdBQWIsYUFBYSxDQUFZO1FBQ3pCLGlCQUFZLEdBQVosWUFBWSxDQUFZO1FBQ3hCLHFDQUFnQyxHQUFoQyxnQ0FBZ0MsQ0FBWTtRQUU1QyxVQUFLLEdBQUwsS0FBSyxDQUFtQjtRQUN4QixzQkFBaUIsR0FBakIsaUJBQWlCLENBQVM7UUFDMUIsUUFBRyxHQUFI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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"archiver.test.d.ts","sourceRoot":"","sources":["../../src/archiver/archiver.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
2
|
-
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
4
|
-
import { sleep } from '@aztec/foundation/sleep';
|
|
5
|
-
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
6
|
-
import { ExtendedContractData, L2Block, L2BlockL2Logs, LogType } from '@aztec/types';
|
|
7
|
-
import { mock } from 'jest-mock-extended';
|
|
8
|
-
import { encodeFunctionData, toHex } from 'viem';
|
|
9
|
-
import { Archiver } from './archiver.js';
|
|
10
|
-
import { MemoryArchiverStore } from './archiver_store.js';
|
|
11
|
-
describe('Archiver', () => {
|
|
12
|
-
const rollupAddress = '0x0000000000000000000000000000000000000000';
|
|
13
|
-
const inboxAddress = '0x0000000000000000000000000000000000000000';
|
|
14
|
-
const contractDeploymentEmitterAddress = '0x0000000000000000000000000000000000000001';
|
|
15
|
-
const blockNums = [1, 2, 3];
|
|
16
|
-
let publicClient;
|
|
17
|
-
let archiverStore;
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
publicClient = mock();
|
|
20
|
-
archiverStore = new MemoryArchiverStore();
|
|
21
|
-
});
|
|
22
|
-
it('can start, sync and stop and handle l1 to l2 messages and logs', async () => {
|
|
23
|
-
const archiver = new Archiver(publicClient, EthAddress.fromString(rollupAddress), EthAddress.fromString(inboxAddress), EthAddress.fromString(contractDeploymentEmitterAddress), 0, archiverStore, 1000);
|
|
24
|
-
let latestBlockNum = await archiver.getBlockNumber();
|
|
25
|
-
expect(latestBlockNum).toEqual(0);
|
|
26
|
-
const blocks = blockNums.map(x => L2Block.random(x, 4, x, x + 1, x * 2, x * 3));
|
|
27
|
-
const rollupTxs = blocks.map(makeRollupTx);
|
|
28
|
-
// `L2Block.random(x)` creates some l1 to l2 messages. We add those,
|
|
29
|
-
// since it is expected by the test that these would be consumed.
|
|
30
|
-
// Archiver removes such messages from pending store.
|
|
31
|
-
// Also create some more messages to cancel and some that will stay pending.
|
|
32
|
-
const messageToCancel1 = Fr.random().toString(true);
|
|
33
|
-
const messageToCancel2 = Fr.random().toString(true);
|
|
34
|
-
const l1ToL2MessagesToCancel = [messageToCancel1, messageToCancel2];
|
|
35
|
-
const messageToStayPending1 = Fr.random().toString(true);
|
|
36
|
-
const messageToStayPending2 = Fr.random().toString(true);
|
|
37
|
-
const l1ToL2MessageAddedEvents = [
|
|
38
|
-
makeL1ToL2MessageAddedEvents(100n, blocks[0].newL1ToL2Messages.map(key => key.toString(true))),
|
|
39
|
-
makeL1ToL2MessageAddedEvents(100n, blocks[1].newL1ToL2Messages.map(key => key.toString(true))),
|
|
40
|
-
makeL1ToL2MessageAddedEvents(1000n, blocks[2].newL1ToL2Messages.map(key => key.toString(true))),
|
|
41
|
-
makeL1ToL2MessageAddedEvents(102n, [
|
|
42
|
-
messageToCancel1,
|
|
43
|
-
messageToCancel2,
|
|
44
|
-
messageToStayPending1,
|
|
45
|
-
messageToStayPending2,
|
|
46
|
-
]),
|
|
47
|
-
];
|
|
48
|
-
publicClient.getBlockNumber.mockResolvedValueOnce(2500n).mockResolvedValueOnce(2501n).mockResolvedValueOnce(2502n);
|
|
49
|
-
// logs should be created in order of how archiver syncs.
|
|
50
|
-
publicClient.getLogs
|
|
51
|
-
.mockResolvedValueOnce(l1ToL2MessageAddedEvents.slice(0, 2).flat())
|
|
52
|
-
.mockResolvedValueOnce([]) // no messages to cancel
|
|
53
|
-
.mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)])
|
|
54
|
-
.mockResolvedValueOnce([makeContractDeploymentEvent(103n, blocks[0])])
|
|
55
|
-
.mockResolvedValueOnce(l1ToL2MessageAddedEvents.slice(2, 4).flat())
|
|
56
|
-
.mockResolvedValueOnce(makeL1ToL2MessageCancelledEvents(1100n, l1ToL2MessagesToCancel))
|
|
57
|
-
.mockResolvedValueOnce([makeL2BlockProcessedEvent(1101n, 2n), makeL2BlockProcessedEvent(1150n, 3n)])
|
|
58
|
-
.mockResolvedValueOnce([makeContractDeploymentEvent(1102n, blocks[1])])
|
|
59
|
-
.mockResolvedValue([]);
|
|
60
|
-
rollupTxs.forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx));
|
|
61
|
-
await archiver.start(false);
|
|
62
|
-
// Wait until block 3 is processed. If this won't happen the test will fail with timeout.
|
|
63
|
-
while ((await archiver.getBlockNumber()) !== 3) {
|
|
64
|
-
await sleep(100);
|
|
65
|
-
}
|
|
66
|
-
latestBlockNum = await archiver.getBlockNumber();
|
|
67
|
-
expect(latestBlockNum).toEqual(3);
|
|
68
|
-
// Check that only 2 messages (l1ToL2MessageAddedEvents[3][2] and l1ToL2MessageAddedEvents[3][3]) are pending.
|
|
69
|
-
// Other two (l1ToL2MessageAddedEvents[3][0..2]) were cancelled. And the previous messages were confirmed.
|
|
70
|
-
const expectedPendingMessageKeys = [
|
|
71
|
-
l1ToL2MessageAddedEvents[3][2].args.entryKey,
|
|
72
|
-
l1ToL2MessageAddedEvents[3][3].args.entryKey,
|
|
73
|
-
];
|
|
74
|
-
const actualPendingMessageKeys = (await archiver.getPendingL1ToL2Messages(10)).map(key => key.toString(true));
|
|
75
|
-
expect(expectedPendingMessageKeys).toEqual(actualPendingMessageKeys);
|
|
76
|
-
// Expect logs to correspond to what is set by L2Block.random(...)
|
|
77
|
-
const encryptedLogs = await archiver.getLogs(1, 100, LogType.ENCRYPTED);
|
|
78
|
-
expect(encryptedLogs.length).toEqual(blockNums.length);
|
|
79
|
-
for (const [index, x] of blockNums.entries()) {
|
|
80
|
-
const expectedTotalNumEncryptedLogs = 4 * x * (x * 2);
|
|
81
|
-
const totalNumEncryptedLogs = L2BlockL2Logs.unrollLogs([encryptedLogs[index]]).length;
|
|
82
|
-
expect(totalNumEncryptedLogs).toEqual(expectedTotalNumEncryptedLogs);
|
|
83
|
-
}
|
|
84
|
-
const unencryptedLogs = await archiver.getLogs(1, 100, LogType.UNENCRYPTED);
|
|
85
|
-
expect(unencryptedLogs.length).toEqual(blockNums.length);
|
|
86
|
-
blockNums.forEach((x, index) => {
|
|
87
|
-
const expectedTotalNumUnencryptedLogs = 4 * (x + 1) * (x * 3);
|
|
88
|
-
const totalNumUnencryptedLogs = L2BlockL2Logs.unrollLogs([unencryptedLogs[index]]).length;
|
|
89
|
-
expect(totalNumUnencryptedLogs).toEqual(expectedTotalNumUnencryptedLogs);
|
|
90
|
-
});
|
|
91
|
-
await archiver.stop();
|
|
92
|
-
}, 10000);
|
|
93
|
-
});
|
|
94
|
-
/**
|
|
95
|
-
* Makes a fake L2BlockProcessed event for testing purposes.
|
|
96
|
-
* @param l1BlockNum - L1 block number.
|
|
97
|
-
* @param l2BlockNum - L2Block number.
|
|
98
|
-
* @returns An L2BlockProcessed event log.
|
|
99
|
-
*/
|
|
100
|
-
function makeL2BlockProcessedEvent(l1BlockNum, l2BlockNum) {
|
|
101
|
-
return {
|
|
102
|
-
blockNumber: l1BlockNum,
|
|
103
|
-
args: { blockNum: l2BlockNum },
|
|
104
|
-
transactionHash: `0x${l2BlockNum}`,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Makes a fake ContractDeployment event for testing purposes.
|
|
109
|
-
* @param l1BlockNum - L1 block number.
|
|
110
|
-
* @param l2Block - The l2Block this event is associated with.
|
|
111
|
-
* @returns An ContractDeployment event.
|
|
112
|
-
*/
|
|
113
|
-
function makeContractDeploymentEvent(l1BlockNum, l2Block) {
|
|
114
|
-
const extendedContractData = ExtendedContractData.random();
|
|
115
|
-
const acir = extendedContractData.bytecode?.toString('hex');
|
|
116
|
-
return {
|
|
117
|
-
blockNumber: l1BlockNum,
|
|
118
|
-
args: {
|
|
119
|
-
l2BlockNum: BigInt(l2Block.number),
|
|
120
|
-
aztecAddress: extendedContractData.contractData.contractAddress.toString(),
|
|
121
|
-
portalAddress: extendedContractData.contractData.portalContractAddress.toString(),
|
|
122
|
-
l2BlockHash: `0x${l2Block.getCalldataHash().toString('hex')}`,
|
|
123
|
-
partialAddress: extendedContractData.partialAddress.toString(true),
|
|
124
|
-
pubKeyX: extendedContractData.publicKey.x.toString(true),
|
|
125
|
-
pubKeyY: extendedContractData.publicKey.y.toString(true),
|
|
126
|
-
acir: '0x' + acir,
|
|
127
|
-
},
|
|
128
|
-
transactionHash: `0x${l2Block.number}`,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Makes fake L1ToL2 MessageAdded events for testing purposes.
|
|
133
|
-
* @param l1BlockNum - L1 block number.
|
|
134
|
-
* @param entryKeys - The entry keys of the messages to add.
|
|
135
|
-
* @returns MessageAdded event logs.
|
|
136
|
-
*/
|
|
137
|
-
function makeL1ToL2MessageAddedEvents(l1BlockNum, entryKeys) {
|
|
138
|
-
return entryKeys.map(entryKey => {
|
|
139
|
-
return {
|
|
140
|
-
blockNumber: l1BlockNum,
|
|
141
|
-
args: {
|
|
142
|
-
sender: EthAddress.random().toString(),
|
|
143
|
-
senderChainId: 1n,
|
|
144
|
-
recipient: AztecAddress.random().toString(),
|
|
145
|
-
recipientVersion: 1n,
|
|
146
|
-
content: Fr.random().toString(true),
|
|
147
|
-
secretHash: Fr.random().toString(true),
|
|
148
|
-
deadline: 100,
|
|
149
|
-
fee: 1n,
|
|
150
|
-
entryKey: entryKey,
|
|
151
|
-
},
|
|
152
|
-
transactionHash: `0x${l1BlockNum}`,
|
|
153
|
-
};
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Makes fake L1ToL2 MessageCancelled events for testing purposes.
|
|
158
|
-
* @param l1BlockNum - L1 block number.
|
|
159
|
-
* @param entryKey - The entry keys of the message to cancel.
|
|
160
|
-
* @returns MessageCancelled event logs.
|
|
161
|
-
*/
|
|
162
|
-
function makeL1ToL2MessageCancelledEvents(l1BlockNum, entryKeys) {
|
|
163
|
-
return entryKeys.map(entryKey => {
|
|
164
|
-
return {
|
|
165
|
-
blockNumber: l1BlockNum,
|
|
166
|
-
args: {
|
|
167
|
-
entryKey,
|
|
168
|
-
},
|
|
169
|
-
transactionHash: `0x${l1BlockNum}`,
|
|
170
|
-
};
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Makes a fake rollup tx for testing purposes.
|
|
175
|
-
* @param block - The L2Block.
|
|
176
|
-
* @returns A fake tx with calldata that corresponds to calling process in the Rollup contract.
|
|
177
|
-
*/
|
|
178
|
-
function makeRollupTx(l2Block) {
|
|
179
|
-
const proof = `0x`;
|
|
180
|
-
const block = toHex(l2Block.encode());
|
|
181
|
-
const input = encodeFunctionData({ abi: RollupAbi, functionName: 'process', args: [proof, block] });
|
|
182
|
-
return { input };
|
|
183
|
-
}
|
|
184
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJjaGl2ZXIudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcmNoaXZlci9hcmNoaXZlci50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMvRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNoRCxPQUFPLEVBQTBDLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3hGLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUVyRixPQUFPLEVBQWEsSUFBSSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUF3RCxrQkFBa0IsRUFBRSxLQUFLLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFdkcsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQXFCLG1CQUFtQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFN0UsUUFBUSxDQUFDLFVBQVUsRUFBRSxHQUFHLEVBQUU7SUFDeEIsTUFBTSxhQUFhLEdBQUcsNENBQTRDLENBQUM7SUFDbkUsTUFBTSxZQUFZLEdBQUcsNENBQTRDLENBQUM7SUFDbEUsTUFBTSxnQ0FBZ0MsR0FBRyw0Q0FBNEMsQ0FBQztJQUN0RixNQUFNLFNBQVMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDNUIsSUFBSSxZQUEyRCxDQUFDO0lBQ2hFLElBQUksYUFBZ0MsQ0FBQztJQUVyQyxVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2QsWUFBWSxHQUFHLElBQUksRUFBc0MsQ0FBQztR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
|