Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion yarn-project/archiver/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('@aztec/foundation/eslint-legacy');
module.exports = require('@aztec/foundation/eslint');
18 changes: 13 additions & 5 deletions yarn-project/archiver/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Archiver
To run:
1. Run `anvil`,
2. in the aztec3-l1-contracts repo check out my branch `janb/archiver-test-data`,
3. deploy the contracts and generate initial activity with: `forge script --fork-url "http://127.0.0.1:8545/" --ffi GenerateActivityTest --sig "testGenerateActivity()" --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --broadcast`
4. in this repository run `yarn start:dev` (Note: this repo is currently messy and eslint will not allow it to be built with `yarn start`)
Archiver is a service which is used to fetch data on-chain data and present them in a nice-to-consume form.
The on-chain data specifically are the following events:
1. `L2BlockProcessed` event emitted on Rollup contract,
2. `UnverifiedData` event emitted on UnverifiedDataEmitter contract and
3. `ContractDeployment` event emitted on UnverifiedDataEmitter contract as well.

The interfaces defining how the data can be consumed from the archiver are `L2BlockSource`, `UnverifiedDataSource` and `ContractDataSource`.

## Usage
To install dependencies and build the package run `yarn install` followed by `yarn build`.
To run test execute `yarn test`.

To start the service export `ETHEREUM_HOST` (defaults to `http://127.0.0.1:8545/`), `ARCHIVER_POLLING_INTERVAL` (defaults to `1000 ms`), `ROLLUP_CONTRACT_ADDRESS`, `UNVERIFIED_DATA_EMITTER_ADDRESS` environmental variables and start the service with `yarn start`.
60 changes: 45 additions & 15 deletions yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa
private nextL2BlockFromBlock = 0n;

/**
* Next L1 block number to fetch `UnverifiedData` logs from (i.e. `fromBlock` in eth_getLogs)
* Next L1 block number to fetch `UnverifiedData` logs from (i.e. `fromBlock` in eth_getLogs).
*/
private nextUnverifiedDataFromBlock = 0n;

/**
* Next L1 block number to fetch `ContractPublicData` logs from (i.e. `fromBlock` in eth_getLogs)
* Next L1 block number to fetch `ContractPublicData` logs from (i.e. `fromBlock` in eth_getLogs).
*/
private nextContractDataFromBlock = 0n;

Expand All @@ -74,7 +74,7 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa
* @param publicClient - A client for interacting with the Ethereum node.
* @param rollupAddress - Ethereum address of the rollup contract.
* @param unverifiedDataEmitterAddress - Ethereum address of the unverifiedDataEmitter contract.
* @param pollingInterval - The interval for polling for rollup logs.
* @param pollingIntervalMs - The interval for polling for rollup logs (in milliseconds).
* @param log - A logger.
*/
constructor(
Expand Down Expand Up @@ -136,6 +136,11 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa
await this.syncNewContractData(blockUntilSynced, currentBlockNumber);
}

/**
* Fetches and processes new blocks.
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
* @param currentBlockNumber - Latest available block number in the ETH node.
*/
private async syncBlocks(blockUntilSynced: boolean, currentBlockNumber: bigint) {
do {
if (this.nextL2BlockFromBlock > currentBlockNumber) {
Expand All @@ -157,6 +162,11 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa
} while (blockUntilSynced && this.nextL2BlockFromBlock <= currentBlockNumber);
}

/**
* Fetches and processes new unverified data.
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
* @param currentBlockNumber - Latest available block number in the ETH node.
*/
private async syncUnverifiedData(blockUntilSynced: boolean, currentBlockNumber: bigint) {
do {
if (this.nextUnverifiedDataFromBlock > currentBlockNumber) {
Expand All @@ -176,16 +186,21 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa
} while (blockUntilSynced && this.nextUnverifiedDataFromBlock <= currentBlockNumber);
}

/**
* Fetches and processes new contract data.
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
* @param currentBlockNumber - Latest available block number in the ETH node.
*/
private async syncNewContractData(blockUntilSynced: boolean, currentBlockNumber: bigint) {
do {
if (this.nextContractDataFromBlock > currentBlockNumber) {
break;
}

this.log(`Syncing ContractData logs from block ${this.nextContractDataFromBlock}`);
const contractDataLogs = await this.getContractDataLogs(this.nextContractDataFromBlock);
const contractDataLogs = await this.getContractDeploymentLogs(this.nextContractDataFromBlock);

this.processContractDataLogs(contractDataLogs);
this.processContractDeploymentLogs(contractDataLogs);
this.nextContractDataFromBlock =
(contractDataLogs.findLast(cd => !!cd)?.blockNumber || this.nextContractDataFromBlock) + 1n;
} while (blockUntilSynced && this.nextContractDataFromBlock <= currentBlockNumber);
Expand Down Expand Up @@ -229,7 +244,12 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa
});
}

private async getContractDataLogs(fromBlock: bigint) {
/**
* Gets relevant `ContractDeployment` logs from chain.
* @param fromBlock - First block to get logs from (inclusive).
* @returns An array of `ContractDeployment` logs.
*/
private async getContractDeploymentLogs(fromBlock: bigint): Promise<any[]> {
const abiItem = getAbiItem({
abi: UnverifiedDataEmitterAbi,
name: 'ContractDeployment',
Expand Down Expand Up @@ -289,7 +309,11 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa
this.log('Processed unverifiedData corresponding to ' + logs.length + ' blocks.');
}

private processContractDataLogs(
/**
* Processes newly received UnverifiedData logs.
* @param logs - ContractDeployment logs.
*/
private processContractDeploymentLogs(
logs: Log<bigint, number, undefined, typeof UnverifiedDataEmitterAbi, 'ContractDeployment'>[],
) {
for (const log of logs) {
Expand Down Expand Up @@ -384,8 +408,8 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa

/**
* Lookup all contract data in an L2 block.
* @param blockNumber - The block number to get all contract data from.
* @returns All new contract data in the block (if found)
* @param blockNum - The block number to get all contract data from.
* @returns All new contract data in the block (if found).
*/
public getL2ContractPublicDataInBlock(blockNum: number): Promise<ContractPublicData[]> {
if (blockNum > this.l2Blocks.length) {
Expand Down Expand Up @@ -415,22 +439,28 @@ export class Archiver implements L2BlockSource, UnverifiedDataSource, ContractDa
/**
* Lookup the L2 contract info inside a block.
* Contains contract address & the ethereum portal address.
* @param contractAddress - The contract data address.
* @param l2BlockNum - The L2 block number to get the contract data from.
* @returns ContractData with the portal address (if we didn't throw an error).
*/
public getL2ContractInfoInBlock(blockNum: number): Promise<ContractData[] | undefined> {
if (blockNum > this.l2Blocks.length) {
public getL2ContractInfoInBlock(l2BlockNum: number): Promise<ContractData[] | undefined> {
if (l2BlockNum > this.l2Blocks.length) {
return Promise.resolve([]);
}
const block = this.l2Blocks[blockNum];
const block = this.l2Blocks[l2BlockNum];
return Promise.resolve(block.newContractData);
}

/**
* Gets the public function data for a contract.
* @param contractAddress - The contract address containing the function to fetch.
* @param functionSelector - The function selector of the function to fetch.
* @returns The public function data (if found).
*/
public async getPublicFunction(
address: AztecAddress,
contractAddress: AztecAddress,
functionSelector: Buffer,
): Promise<EncodedContractFunction | undefined> {
const contractData = await this.getL2ContractPublicData(address);
const contractData = await this.getL2ContractPublicData(contractAddress);
const result = contractData?.publicFunctions?.find(fn => fn.functionSelector.equals(functionSelector));
return result;
}
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/archiver/src/archiver/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export interface ArchiverConfig extends L1Addresses {
archiverPollingInterval?: number;
}

/**
* Returns the archiver configuration from the environment variables.
* Note: If an environment variable is not set, the default value is used.
* @returns The archiver configuration.
*/
export function getConfigEnvVars(): ArchiverConfig {
const { ETHEREUM_HOST, ARCHIVER_POLLING_INTERVAL, ROLLUP_CONTRACT_ADDRESS, UNVERIFIED_DATA_EMITTER_ADDRESS } =
process.env;
Expand Down