Skip to content

Commit

Permalink
feat: Claim epoch proof rights without a block
Browse files Browse the repository at this point in the history
If the sequencer does not have enough txs to build a block, it will
still try to submit an epoch proof if there's one available.

Fixes #9404
  • Loading branch information
spalladino committed Dec 18, 2024
1 parent 9981078 commit 45187ee
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ export class EpochProofQuote extends Gossipable {
};
}

toInspect() {
return {
signature: this.signature.toString(),
...this.payload.toInspect(),
};
}

/**
* Get the size of the epoch proof quote in bytes.
* @returns The size of the epoch proof quote in bytes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ export class EpochProofQuotePayload {
};
}

toInspect() {
return {
epochToProve: Number(this.epochToProve),
validUntilSlot: this.validUntilSlot.toString(),
bondAmount: this.bondAmount.toString(),
prover: this.prover.toString(),
basisPointFee: this.basisPointFee,
};
}

getSize(): number {
// We cache size to avoid recalculating it
if (this.size) {
Expand Down
22 changes: 19 additions & 3 deletions yarn-project/end-to-end/src/e2e_epochs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ describe('e2e_epochs', () => {

const EPOCH_DURATION_IN_L2_SLOTS = 4;
const L2_SLOT_DURATION_IN_L1_SLOTS = 2;
const L1_BLOCK_TIME_IN_S = 8;
const L1_BLOCK_TIME_IN_S = process.env.L1_BLOCK_TIME ? parseInt(process.env.L1_BLOCK_TIME) : 8;

beforeAll(async () => {
beforeEach(async () => {
// Set up system without any account nor protocol contracts
// and with faster block times and shorter epochs.
context = await setup(0, {
Expand Down Expand Up @@ -99,7 +99,7 @@ describe('e2e_epochs', () => {
logger.info(`L2 genesis at L1 block ${constants.l1GenesisBlock} (timestamp ${constants.l1GenesisTime})`);
});

afterAll(async () => {
afterEach(async () => {
clearInterval(handle);
await context.teardown();
});
Expand All @@ -117,6 +117,11 @@ describe('e2e_epochs', () => {
await retryUntil(() => Promise.resolve(target === l2BlockNumber), `Wait until L2 block ${target}`, 60, 0.1);
};

/** Waits until the given L2 block number is marked as proven. */
const waitUntilProvenL2BlockNumber = async (target: number) => {
await retryUntil(() => Promise.resolve(target === l2ProvenBlockNumber), `Wait proven L2 block ${target}`, 60, 0.1);
};

it('does not allow submitting proof after epoch end', async () => {
await waitUntilEpochStarts(1);
const blockNumberAtEndOfEpoch0 = Number(await rollup.getBlockNumber());
Expand Down Expand Up @@ -149,4 +154,15 @@ describe('e2e_epochs', () => {
expect(lastL2BlockTxReceipt.blockNumber).toBeGreaterThan(lastProverTxReceipt!.blockNumber);
logger.info(`Test succeeded`);
});

it('submits proof claim alone if there is no txs to build a block', async () => {
context.sequencer?.updateSequencerConfig({ minTxsPerBlock: 1 });
await waitUntilEpochStarts(1);
const blockNumberAtEndOfEpoch0 = Number(await rollup.getBlockNumber());
logger.info(`Starting epoch 1 after L2 block ${blockNumberAtEndOfEpoch0}`);

await waitUntilProvenL2BlockNumber(blockNumberAtEndOfEpoch0);
expect(l2BlockNumber).toEqual(blockNumberAtEndOfEpoch0);
logger.info(`Test succeeded`);
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { L1PublishBlockStats, L1PublishProofStats } from '@aztec/circuit-types/stats';
import type { L1PublishBlockStats, L1PublishProofStats, L1PublishStats } from '@aztec/circuit-types/stats';
import {
Attributes,
type Histogram,
Expand All @@ -10,7 +10,7 @@ import {

import { formatEther } from 'viem/utils';

export type L1TxType = 'submitProof' | 'process';
export type L1TxType = 'submitProof' | 'process' | 'claimEpochProofRight';

export class L1PublisherMetrics {
private gasPrice: Histogram;
Expand Down Expand Up @@ -74,7 +74,11 @@ export class L1PublisherMetrics {
this.recordTx('process', durationMs, stats);
}

private recordTx(txType: L1TxType, durationMs: number, stats: Omit<L1PublishProofStats, 'eventName'>) {
recordClaimEpochProofRightTx(durationMs: number, stats: L1PublishStats) {
this.recordTx('claimEpochProofRight', durationMs, stats);
}

private recordTx(txType: L1TxType, durationMs: number, stats: L1PublishStats) {
const attributes = {
[Attributes.L1_TX_TYPE]: txType,
[Attributes.L1_SENDER]: stats.sender,
Expand Down
62 changes: 51 additions & 11 deletions yarn-project/sequencer-client/src/publisher/l1-publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
type TxHash,
getHashedSignaturePayload,
} from '@aztec/circuit-types';
import { type L1PublishBlockStats, type L1PublishProofStats } from '@aztec/circuit-types/stats';
import { type L1PublishBlockStats, type L1PublishProofStats, type L1PublishStats } from '@aztec/circuit-types/stats';
import {
AGGREGATION_OBJECT_LENGTH,
AZTEC_MAX_EPOCH_DURATION,
Expand Down Expand Up @@ -38,7 +38,6 @@ import { ExtRollupLibAbi, GovernanceProposerAbi, LeonidasLibAbi, RollupAbi } fro
import { type TelemetryClient } from '@aztec/telemetry-client';

import pick from 'lodash.pick';
import { inspect } from 'util';
import {
type BaseError,
type Chain,
Expand Down Expand Up @@ -71,7 +70,7 @@ import { privateKeyToAccount } from 'viem/accounts';

import { type PublisherConfig, type TxSenderConfig } from './config.js';
import { L1PublisherMetrics } from './l1-publisher-metrics.js';
import { prettyLogViemError, prettyLogViemErrorMsg } from './utils.js';
import { prettyLogViemErrorMsg } from './utils.js';

/**
* Stats for a sent transaction.
Expand Down Expand Up @@ -615,6 +614,53 @@ export class L1Publisher {
return false;
}

/** Calls claimEpochProofRight in the Rollup contract to submit a chosen prover quote for the previous epoch. */
public async claimEpochProofRight(proofQuote: EpochProofQuote) {
const timer = new Timer();

let receipt;
try {
this.log.debug(`Submitting claimEpochProofRight transaction`);
receipt = await this.l1TxUtils.sendAndMonitorTransaction({
to: this.rollupContract.address,
data: encodeFunctionData({
abi: RollupAbi,
functionName: 'claimEpochProofRight',
args: [proofQuote.toViemArgs()],
}),
});
} catch (err) {
this.log.error(`Failed to claim epoch proof right: ${prettyLogViemErrorMsg(err)}`, err, {
proofQuote: proofQuote.toInspect(),
});
return false;
}

if (receipt.status === 'success') {
const tx = await this.getTransactionStats(receipt.transactionHash);
const stats: L1PublishStats = {
gasPrice: receipt.effectiveGasPrice,
gasUsed: receipt.gasUsed,
transactionHash: receipt.transactionHash,
...pick(tx!, 'calldataGas', 'calldataSize', 'sender'),
};
this.log.verbose(`Submitted claim epoch proof right to L1 rollup contract`, {
...stats,
...proofQuote.toInspect(),
});
this.metrics.recordClaimEpochProofRightTx(timer.ms(), stats);
return true;
} else {
this.metrics.recordFailedTx('claimEpochProofRight');
// TODO: Get the error message from the reverted tx
this.log.error(`Claim epoch proof right tx reverted`, {
txHash: receipt.transactionHash,
...proofQuote.toInspect(),
});
return false;
}
}

private async tryGetErrorFromRevertedTx(
data: Hex,
args: {
Expand Down Expand Up @@ -958,8 +1004,7 @@ export class L1Publisher {
data,
};
} catch (err) {
prettyLogViemError(err, this.log);
this.log.error(`Rollup publish failed`, err);
this.log.error(`Rollup publish failed: ${prettyLogViemErrorMsg(err)}`, err);
return undefined;
}
}
Expand All @@ -972,9 +1017,6 @@ export class L1Publisher {
return undefined;
}
try {
this.log.info(`ProposeAndClaim`);
this.log.info(inspect(quote.payload));

const kzg = Blob.getViemKzgInstance();
const { args, gas } = await this.prepareProposeTx(encodedData);
const data = encodeFunctionData({
Expand Down Expand Up @@ -1002,9 +1044,7 @@ export class L1Publisher {
data,
};
} catch (err) {
prettyLogViemError(err, this.log);
const errorMessage = err instanceof Error ? err.message : String(err);
this.log.error(`Rollup publish failed`, errorMessage);
this.log.error(`Rollup publish failed: ${prettyLogViemErrorMsg(err)}`, err);
return undefined;
}
}
Expand Down
11 changes: 1 addition & 10 deletions yarn-project/sequencer-client/src/publisher/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { type Logger } from '@aztec/foundation/log';

import { BaseError, ContractFunctionRevertedError } from 'viem';

export function prettyLogViemErrorMsg(err: any) {
Expand All @@ -12,12 +10,5 @@ export function prettyLogViemErrorMsg(err: any) {
return `${errorName}${args}`;
}
}
}

// TODO(palla/log): Review this method
export function prettyLogViemError(err: any, logger: Logger) {
const msg = prettyLogViemErrorMsg(err);
if (msg) {
logger.debug(`canProposeAtTime failed with "${msg}"`);
}
return err?.message ?? err;
}
Loading

0 comments on commit 45187ee

Please sign in to comment.