Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Batch archiver requests #10442

Merged
merged 1 commit into from
Dec 6, 2024
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: 0 additions & 2 deletions yarn-project/archiver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
"formatting": "run -T prettier --check ./src && run -T eslint ./src",
"formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src",
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests",
"start": "node ./dest",
"start:dev": "tsc-watch -p tsconfig.json --onSuccess 'yarn start'",
"test:integration": "concurrently -k -s first -c reset,dim -n test,anvil \"yarn test:integration:run\" \"anvil\"",
"test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json"
},
Expand Down
205 changes: 91 additions & 114 deletions yarn-project/archiver/src/archiver/archiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,27 +56,50 @@ describe('Archiver', () => {
let archiver: Archiver;
let blocks: L2Block[];

let l2BlockProposedLogs: Log<bigint, number, false, undefined, true, typeof RollupAbi, 'L2BlockProposed'>[];
let l2MessageSentLogs: Log<bigint, number, false, undefined, true, typeof InboxAbi, 'MessageSent'>[];

const GENESIS_ROOT = new Fr(GENESIS_ARCHIVE_ROOT).toString();

beforeEach(() => {
now = +new Date();
publicClient = mock<PublicClient<HttpTransport, Chain>>({
// Return a block with a reasonable timestamp
getBlock: ((args: any) => ({
timestamp: args.blockNumber * BigInt(DefaultL1ContractsConfig.ethereumSlotDuration) + BigInt(now),
})) as any,
// Return the logs mocked whenever the public client is queried
getLogs: ((args: any) => {
let logs = undefined;
if (args!.event!.name === 'MessageSent') {
logs = l2MessageSentLogs;
} else if (args!.event!.name === 'L2BlockProposed') {
logs = l2BlockProposedLogs;
} else {
throw new Error(`Unknown event: ${args!.event!.name}`);
}
return Promise.resolve(
logs.filter(log => log.blockNumber >= args.fromBlock && log.blockNumber <= args.toBlock),
);
}) as any,
});

instrumentation = mock({ isEnabled: () => true });
archiverStore = new MemoryArchiverStore(1000);

archiver = new Archiver(
publicClient,
rollupAddress,
inboxAddress,
registryAddress,
{ rollupAddress, inboxAddress, registryAddress },
archiverStore,
1000,
{ pollingIntervalMs: 1000, batchSize: 1000 },
instrumentation,
{
l1GenesisTime: BigInt(now),
l1StartBlock: 0n,
epochDuration: 4,
slotDuration: 24,
ethereumSlotDuration: 12,
},
);

blocks = blockNumbers.map(x => L2Block.random(x, txsPerBlock, x + 1, 2));
Expand All @@ -97,6 +120,9 @@ describe('Archiver', () => {

inboxRead = mock<MockInboxContractRead>();
((archiver as any).inbox as any).read = inboxRead;

l2MessageSentLogs = [];
l2BlockProposedLogs = [];
});

afterEach(async () => {
Expand Down Expand Up @@ -127,27 +153,16 @@ describe('Archiver', () => {

inboxRead.totalMessagesInserted.mockResolvedValueOnce(2n).mockResolvedValueOnce(6n);

mockGetLogs({
messageSent: [
makeMessageSentEventWithIndexInL2BlockSubtree(98n, 1n, 0n),
makeMessageSentEventWithIndexInL2BlockSubtree(99n, 1n, 1n),
],
L2BlockProposed: [makeL2BlockProposedEvent(101n, 1n, blocks[0].archive.root.toString())],
});

mockGetLogs({
messageSent: [
makeMessageSentEventWithIndexInL2BlockSubtree(2504n, 2n, 0n),
makeMessageSentEventWithIndexInL2BlockSubtree(2505n, 2n, 1n),
makeMessageSentEventWithIndexInL2BlockSubtree(2505n, 2n, 2n),
makeMessageSentEventWithIndexInL2BlockSubtree(2506n, 3n, 1n),
],
L2BlockProposed: [
makeL2BlockProposedEvent(2510n, 2n, blocks[1].archive.root.toString()),
makeL2BlockProposedEvent(2520n, 3n, blocks[2].archive.root.toString()),
],
});
makeMessageSentEvent(98n, 1n, 0n);
makeMessageSentEvent(99n, 1n, 1n);
makeL2BlockProposedEvent(101n, 1n, blocks[0].archive.root.toString());

makeMessageSentEvent(2504n, 2n, 0n);
makeMessageSentEvent(2505n, 2n, 1n);
makeMessageSentEvent(2505n, 2n, 2n);
makeMessageSentEvent(2506n, 3n, 1n);
makeL2BlockProposedEvent(2510n, 2n, blocks[1].archive.root.toString());
makeL2BlockProposedEvent(2520n, 3n, blocks[2].archive.root.toString());
publicClient.getTransaction.mockResolvedValueOnce(rollupTxs[0]);

rollupTxs.slice(1).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx));
Expand Down Expand Up @@ -228,17 +243,11 @@ describe('Archiver', () => {

inboxRead.totalMessagesInserted.mockResolvedValueOnce(2n).mockResolvedValueOnce(2n);

mockGetLogs({
messageSent: [
makeMessageSentEventWithIndexInL2BlockSubtree(66n, 1n, 0n),
makeMessageSentEventWithIndexInL2BlockSubtree(68n, 1n, 1n),
],
L2BlockProposed: [
makeL2BlockProposedEvent(70n, 1n, blocks[0].archive.root.toString()),
makeL2BlockProposedEvent(80n, 2n, blocks[1].archive.root.toString()),
makeL2BlockProposedEvent(90n, 3n, badArchive),
],
});
makeMessageSentEvent(66n, 1n, 0n);
makeMessageSentEvent(68n, 1n, 1n);
makeL2BlockProposedEvent(70n, 1n, blocks[0].archive.root.toString());
makeL2BlockProposedEvent(80n, 2n, blocks[1].archive.root.toString());
makeL2BlockProposedEvent(90n, 3n, badArchive);

rollupTxs.forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx));

Expand All @@ -250,8 +259,10 @@ describe('Archiver', () => {

latestBlockNum = await archiver.getBlockNumber();
expect(latestBlockNum).toEqual(numL2BlocksInTest);
const errorMessage = `Archive mismatch matching, ignoring block ${3} with archive: ${badArchive}, expected ${blocks[2].archive.root.toString()}`;
expect(loggerSpy).toHaveBeenCalledWith(errorMessage);
expect(loggerSpy).toHaveBeenCalledWith(expect.stringMatching(/archive root mismatch/i), {
actual: badArchive,
expected: blocks[2].archive.root.toString(),
});
}, 10_000);

it('skip event search if no changes found', async () => {
Expand All @@ -271,16 +282,10 @@ describe('Archiver', () => {

inboxRead.totalMessagesInserted.mockResolvedValueOnce(0n).mockResolvedValueOnce(2n);

mockGetLogs({
messageSent: [
makeMessageSentEventWithIndexInL2BlockSubtree(66n, 1n, 0n),
makeMessageSentEventWithIndexInL2BlockSubtree(68n, 1n, 1n),
],
L2BlockProposed: [
makeL2BlockProposedEvent(70n, 1n, blocks[0].archive.root.toString()),
makeL2BlockProposedEvent(80n, 2n, blocks[1].archive.root.toString()),
],
});
makeMessageSentEvent(66n, 1n, 0n);
makeMessageSentEvent(68n, 1n, 1n);
makeL2BlockProposedEvent(70n, 1n, blocks[0].archive.root.toString());
makeL2BlockProposedEvent(80n, 2n, blocks[1].archive.root.toString());

rollupTxs.forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx));

Expand All @@ -292,10 +297,7 @@ describe('Archiver', () => {

latestBlockNum = await archiver.getBlockNumber();
expect(latestBlockNum).toEqual(numL2BlocksInTest);

// For some reason, this is 1-indexed.
expect(loggerSpy).toHaveBeenNthCalledWith(1, `Retrieved no new L1 to L2 messages between L1 blocks 1 and 50.`);
expect(loggerSpy).toHaveBeenNthCalledWith(2, `No blocks to retrieve from 1 to 50`);
expect(loggerSpy).toHaveBeenCalledWith(`No blocks to retrieve from 1 to 50`);
}, 10_000);

it('handles L2 reorg', async () => {
Expand Down Expand Up @@ -328,16 +330,10 @@ describe('Archiver', () => {
.mockResolvedValueOnce(2n)
.mockResolvedValueOnce(2n);

mockGetLogs({
messageSent: [
makeMessageSentEventWithIndexInL2BlockSubtree(66n, 1n, 0n),
makeMessageSentEventWithIndexInL2BlockSubtree(68n, 1n, 1n),
],
L2BlockProposed: [
makeL2BlockProposedEvent(70n, 1n, blocks[0].archive.root.toString()),
makeL2BlockProposedEvent(80n, 2n, blocks[1].archive.root.toString()),
],
});
makeMessageSentEvent(66n, 1n, 0n);
makeMessageSentEvent(68n, 1n, 1n);
makeL2BlockProposedEvent(70n, 1n, blocks[0].archive.root.toString());
makeL2BlockProposedEvent(80n, 2n, blocks[1].archive.root.toString());

rollupTxs.forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx));

Expand All @@ -350,14 +346,12 @@ describe('Archiver', () => {
latestBlockNum = await archiver.getBlockNumber();
expect(latestBlockNum).toEqual(numL2BlocksInTest);

// For some reason, this is 1-indexed.
expect(loggerSpy).toHaveBeenNthCalledWith(1, `Retrieved no new L1 to L2 messages between L1 blocks 1 and 50.`);
expect(loggerSpy).toHaveBeenNthCalledWith(2, `No blocks to retrieve from 1 to 50`);
expect(loggerSpy).toHaveBeenCalledWith(`No blocks to retrieve from 1 to 50`);

// Lets take a look to see if we can find re-org stuff!
await sleep(1000);

expect(loggerSpy).toHaveBeenNthCalledWith(9, `L2 prune has been detected.`);
expect(loggerSpy).toHaveBeenCalledWith(`L2 prune has been detected.`);

// Should also see the block number be reduced
latestBlockNum = await archiver.getBlockNumber();
Expand All @@ -375,57 +369,40 @@ describe('Archiver', () => {
// TODO(palla/reorg): Add a unit test for the archiver handleEpochPrune
xit('handles an upcoming L2 prune', () => {});

// logs should be created in order of how archiver syncs.
const mockGetLogs = (logs: {
messageSent?: ReturnType<typeof makeMessageSentEventWithIndexInL2BlockSubtree>[];
L2BlockProposed?: ReturnType<typeof makeL2BlockProposedEvent>[];
}) => {
if (logs.messageSent) {
publicClient.getLogs.mockResolvedValueOnce(logs.messageSent);
}
if (logs.L2BlockProposed) {
publicClient.getLogs.mockResolvedValueOnce(logs.L2BlockProposed);
}
/**
* Makes a fake L2BlockProposed event for testing purposes and registers it to be returned by the public client.
* @param l1BlockNum - L1 block number.
* @param l2BlockNum - L2 Block number.
*/
const makeL2BlockProposedEvent = (l1BlockNum: bigint, l2BlockNum: bigint, archive: `0x${string}`) => {
const log = {
blockNumber: l1BlockNum,
args: { blockNumber: l2BlockNum, archive },
transactionHash: `0x${l2BlockNum}`,
} as Log<bigint, number, false, undefined, true, typeof RollupAbi, 'L2BlockProposed'>;
l2BlockProposedLogs.push(log);
};
});

/**
* Makes a fake L2BlockProposed event for testing purposes.
* @param l1BlockNum - L1 block number.
* @param l2BlockNum - L2 Block number.
* @returns An L2BlockProposed event log.
*/
function makeL2BlockProposedEvent(l1BlockNum: bigint, l2BlockNum: bigint, archive: `0x${string}`) {
return {
blockNumber: l1BlockNum,
args: { blockNumber: l2BlockNum, archive },
transactionHash: `0x${l2BlockNum}`,
} as Log<bigint, number, false, undefined, true, typeof RollupAbi, 'L2BlockProposed'>;
}

/**
* Makes fake L1ToL2 MessageSent events for testing purposes.
* @param l1BlockNum - L1 block number.
* @param l2BlockNumber - The L2 block number for which the message was included.
* @param indexInSubtree - the index in the l2Block's subtree in the L1 to L2 Messages Tree.
* @returns MessageSent event logs.
*/
function makeMessageSentEventWithIndexInL2BlockSubtree(
l1BlockNum: bigint,
l2BlockNumber: bigint,
indexInSubtree: bigint,
) {
const index = indexInSubtree + InboxLeaf.smallestIndexFromL2Block(l2BlockNumber);
return {
blockNumber: l1BlockNum,
args: {
l2BlockNumber,
index,
hash: Fr.random().toString(),
},
transactionHash: `0x${l1BlockNum}`,
} as Log<bigint, number, false, undefined, true, typeof InboxAbi, 'MessageSent'>;
}
/**
* Makes fake L1ToL2 MessageSent events for testing purposes and registers it to be returned by the public client.
* @param l1BlockNum - L1 block number.
* @param l2BlockNumber - The L2 block number for which the message was included.
* @param indexInSubtree - the index in the l2Block's subtree in the L1 to L2 Messages Tree.
*/
const makeMessageSentEvent = (l1BlockNum: bigint, l2BlockNumber: bigint, indexInSubtree: bigint) => {
const index = indexInSubtree + InboxLeaf.smallestIndexFromL2Block(l2BlockNumber);
const log = {
blockNumber: l1BlockNum,
args: {
l2BlockNumber,
index,
hash: Fr.random().toString(),
},
transactionHash: `0x${l1BlockNum}`,
} as Log<bigint, number, false, undefined, true, typeof InboxAbi, 'MessageSent'>;
l2MessageSentLogs.push(log);
};
});

/**
* Makes a fake rollup tx for testing purposes.
Expand Down
Loading
Loading