Skip to content

Commit

Permalink
fix: Prover node aborts execution at epoch end
Browse files Browse the repository at this point in the history
Prover node aborts all jobs once it hits the end of the next epoch to be
proven.

Fixes #10802
  • Loading branch information
spalladino committed Jan 8, 2025
1 parent 36b640a commit ed5b2a3
Show file tree
Hide file tree
Showing 29 changed files with 454 additions and 103 deletions.
4 changes: 2 additions & 2 deletions yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,8 @@ export class Archiver implements ArchiveSource, Traceable {
return Promise.resolve();
}

public getL1Constants(): L1RollupConstants {
return this.l1constants;
public getL1Constants(): Promise<L1RollupConstants> {
return Promise.resolve(this.l1constants);
}

public getRollupAddress(): Promise<EthAddress> {
Expand Down
7 changes: 6 additions & 1 deletion yarn-project/archiver/src/test/mock_l2_block_source.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {
type L1RollupConstants,
L2Block,
L2BlockHash,
type L2BlockSource,
type L2Tips,
type TxHash,
TxReceipt,
TxStatus,
getSlotRangeForEpoch,
} from '@aztec/circuit-types';
import { getSlotRangeForEpoch } from '@aztec/circuit-types';
import { type BlockHeader, EthAddress } from '@aztec/circuits.js';
import { DefaultL1ContractsConfig } from '@aztec/ethereum';
import { createLogger } from '@aztec/foundation/log';
Expand Down Expand Up @@ -187,6 +188,10 @@ export class MockL2BlockSource implements L2BlockSource {
throw new Error('Method not implemented.');
}

getL1Constants(): Promise<L1RollupConstants> {
throw new Error('Method not implemented.');
}

/**
* Starts the block source. In this mock implementation, this is a noop.
* @returns A promise that signals the initialization of the l2 block source on completion.
Expand Down
1 change: 0 additions & 1 deletion yarn-project/aztec.js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ export {
mockEpochProofQuote,
mockTx,
type AztecNode,
type EpochConstants,
type LogFilter,
type PXE,
type PartialAddress,
Expand Down
5 changes: 2 additions & 3 deletions yarn-project/circuit-types/src/epoch-helpers/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { type EpochConstants, getTimestampRangeForEpoch } from './index.js';
import { type L1RollupConstants, getTimestampRangeForEpoch } from './index.js';

describe('EpochHelpers', () => {
let constants: EpochConstants;
let constants: Omit<L1RollupConstants, 'l1StartBlock'>;
const l1GenesisTime = 1734440000n;

beforeEach(() => {
constants = {
l1GenesisBlock: 10n,
l1GenesisTime: l1GenesisTime,
epochDuration: 4,
slotDuration: 24,
Expand Down
42 changes: 15 additions & 27 deletions yarn-project/circuit-types/src/epoch-helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { type ZodFor, schemas } from '@aztec/foundation/schemas';

import { z } from 'zod';

export type L1RollupConstants = {
l1StartBlock: bigint;
l1GenesisTime: bigint;
Expand All @@ -14,30 +18,29 @@ export const EmptyL1RollupConstants: L1RollupConstants = {
ethereumSlotDuration: 1,
};

// REFACTOR: Merge this type with L1RollupConstants
export type EpochConstants = {
l1GenesisBlock: bigint;
l1GenesisTime: bigint;
epochDuration: number;
slotDuration: number;
ethereumSlotDuration: number;
};
export const L1RollupConstantsSchema = z.object({
l1StartBlock: schemas.BigInt,
l1GenesisTime: schemas.BigInt,
slotDuration: z.number(),
epochDuration: z.number(),
ethereumSlotDuration: z.number(),
}) satisfies ZodFor<L1RollupConstants>;

/** Returns the slot number for a given timestamp. */
export function getSlotAtTimestamp(ts: bigint, constants: Pick<EpochConstants, 'l1GenesisTime' | 'slotDuration'>) {
export function getSlotAtTimestamp(ts: bigint, constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>) {
return ts < constants.l1GenesisTime ? 0n : (ts - constants.l1GenesisTime) / BigInt(constants.slotDuration);
}

/** Returns the epoch number for a given timestamp. */
export function getEpochNumberAtTimestamp(
ts: bigint,
constants: Pick<EpochConstants, 'epochDuration' | 'slotDuration' | 'l1GenesisTime'>,
constants: Pick<L1RollupConstants, 'epochDuration' | 'slotDuration' | 'l1GenesisTime'>,
) {
return getSlotAtTimestamp(ts, constants) / BigInt(constants.epochDuration);
}

/** Returns the range of L2 slots (inclusive) for a given epoch number. */
export function getSlotRangeForEpoch(epochNumber: bigint, constants: Pick<EpochConstants, 'epochDuration'>) {
export function getSlotRangeForEpoch(epochNumber: bigint, constants: Pick<L1RollupConstants, 'epochDuration'>) {
const startSlot = epochNumber * BigInt(constants.epochDuration);
return [startSlot, startSlot + BigInt(constants.epochDuration) - 1n];
}
Expand All @@ -48,7 +51,7 @@ export function getSlotRangeForEpoch(epochNumber: bigint, constants: Pick<EpochC
*/
export function getTimestampRangeForEpoch(
epochNumber: bigint,
constants: Pick<EpochConstants, 'l1GenesisTime' | 'slotDuration' | 'epochDuration' | 'ethereumSlotDuration'>,
constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration' | 'epochDuration' | 'ethereumSlotDuration'>,
) {
const [startSlot, endSlot] = getSlotRangeForEpoch(epochNumber, constants);
const ethereumSlotsPerL2Slot = constants.slotDuration / constants.ethereumSlotDuration;
Expand All @@ -59,18 +62,3 @@ export function getTimestampRangeForEpoch(
BigInt((ethereumSlotsPerL2Slot - 1) * constants.ethereumSlotDuration),
];
}

/**
* Returns the range of L1 blocks (inclusive) for a given epoch number.
* @remarks This assumes no time warp has happened.
*/
export function getL1BlockRangeForEpoch(
epochNumber: bigint,
constants: Pick<EpochConstants, 'l1GenesisBlock' | 'epochDuration' | 'slotDuration'>,
) {
const epochDurationInL1Blocks = BigInt(constants.epochDuration) * BigInt(constants.slotDuration);
return [
epochNumber * epochDurationInL1Blocks + constants.l1GenesisBlock,
(epochNumber + 1n) * epochDurationInL1Blocks + constants.l1GenesisBlock - 1n,
];
}
9 changes: 9 additions & 0 deletions yarn-project/circuit-types/src/interfaces/archiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { readFileSync } from 'fs';
import omit from 'lodash.omit';
import { resolve } from 'path';

import { EmptyL1RollupConstants, type L1RollupConstants } from '../epoch-helpers/index.js';
import { type InBlock, randomInBlock } from '../in_block.js';
import { L2Block } from '../l2_block.js';
import { type L2Tips } from '../l2_block_source.js';
Expand Down Expand Up @@ -248,6 +249,11 @@ describe('ArchiverApiSchema', () => {
privateFunctions: [],
});
});

it('getL1Constants', async () => {
const result = await context.client.getL1Constants();
expect(result).toEqual(EmptyL1RollupConstants);
});
});

class MockArchiver implements ArchiverApi {
Expand Down Expand Up @@ -388,4 +394,7 @@ class MockArchiver implements ArchiverApi {
addContractClass(_contractClass: ContractClassPublic): Promise<void> {
return Promise.resolve();
}
getL1Constants(): Promise<L1RollupConstants> {
return Promise.resolve(EmptyL1RollupConstants);
}
}
2 changes: 2 additions & 0 deletions yarn-project/circuit-types/src/interfaces/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { type ApiSchemaFor, optional, schemas } from '@aztec/foundation/schemas'

import { z } from 'zod';

import { L1RollupConstantsSchema } from '../epoch-helpers/index.js';
import { inBlockSchemaFor } from '../in_block.js';
import { L2Block } from '../l2_block.js';
import { type L2BlockSource, L2TipsSchema } from '../l2_block_source.js';
Expand Down Expand Up @@ -77,4 +78,5 @@ export const ArchiverApiSchema: ApiSchemaFor<ArchiverApi> = {
.function()
.args(schemas.AztecAddress, schemas.FunctionSelector)
.returns(optional(z.string())),
getL1Constants: z.function().args().returns(L1RollupConstantsSchema),
};
11 changes: 11 additions & 0 deletions yarn-project/circuit-types/src/interfaces/prover-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,21 @@ const EpochProvingJobState = [
'publishing-proof',
'completed',
'failed',
'stopped',
'timed-out',
] as const;

export type EpochProvingJobState = (typeof EpochProvingJobState)[number];

export const EpochProvingJobTerminalState: EpochProvingJobState[] = [
'completed',
'failed',
'stopped',
'timed-out',
] as const;

export type EpochProvingJobTerminalState = (typeof EpochProvingJobTerminalState)[number];

/** JSON RPC public interface to a prover node. */
export interface ProverNodeApi {
getJobs(): Promise<{ uuid: string; status: EpochProvingJobState }[]>;
Expand Down
6 changes: 6 additions & 0 deletions yarn-project/circuit-types/src/l2_block_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type BlockHeader, type EthAddress } from '@aztec/circuits.js';

import { z } from 'zod';

import { type L1RollupConstants } from './epoch-helpers/index.js';
import { type InBlock } from './in_block.js';
import { type L2Block } from './l2_block.js';
import { type TxHash } from './tx/tx_hash.js';
Expand Down Expand Up @@ -106,6 +107,11 @@ export interface L2BlockSource {
* Returns the tips of the L2 chain.
*/
getL2Tips(): Promise<L2Tips>;

/**
* Returns the rollup constants for the current chain.
*/
getL1Constants(): Promise<L1RollupConstants>;
}

/**
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/circuits.js/src/structs/proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ export class Proof {
this.buffer.length === EMPTY_PROOF_SIZE && this.buffer.every(byte => byte === 0) && this.numPublicInputs === 0
);
}

/** Returns an empty proof. */
static empty() {
return makeEmptyProof();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,8 @@ export class FeeRecipient {
}
return { recipient: this.recipient.toString(), value: this.value.toString() };
}

static random() {
return new FeeRecipient(EthAddress.random(), Fr.random());
}
}
19 changes: 19 additions & 0 deletions yarn-project/circuits.js/src/structs/rollup/root_rollup.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { makeTuple } from '@aztec/foundation/array';
import { Fr } from '@aztec/foundation/fields';
import { bufferSchemaFor } from '@aztec/foundation/schemas';
import { BufferReader, type Tuple, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize';
Expand Down Expand Up @@ -184,4 +185,22 @@ export class RootRollupPublicInputs {
static get schema() {
return bufferSchemaFor(RootRollupPublicInputs);
}

/** Creates a random instance. */
static random() {
return new RootRollupPublicInputs(
AppendOnlyTreeSnapshot.random(),
AppendOnlyTreeSnapshot.random(),
Fr.random(),
Fr.random(),
Fr.random(),
Fr.random(),
Fr.random(),
makeTuple(AZTEC_MAX_EPOCH_DURATION, FeeRecipient.random),
Fr.random(),
Fr.random(),
Fr.random(),
makeTuple(AZTEC_MAX_EPOCH_DURATION, BlockBlobPublicInputs.empty),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,8 @@ export class AppendOnlyTreeSnapshot {
public equals(other: this) {
return this.root.equals(other.root) && this.nextAvailableLeafIndex === other.nextAvailableLeafIndex;
}

static random() {
return new AppendOnlyTreeSnapshot(Fr.random(), Math.floor(Math.random() * 1000));
}
}
15 changes: 4 additions & 11 deletions yarn-project/end-to-end/src/e2e_block_building.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import { type TestDateProvider } from '@aztec/foundation/timer';
import { StatefulTestContract, StatefulTestContractArtifact } from '@aztec/noir-contracts.js/StatefulTest';
import { TestContract } from '@aztec/noir-contracts.js/Test';
import { TokenContract } from '@aztec/noir-contracts.js/Token';
import { type Sequencer, type SequencerClient, SequencerState } from '@aztec/sequencer-client';
import { type SequencerClient, SequencerState } from '@aztec/sequencer-client';
import { type TestSequencerClient } from '@aztec/sequencer-client/test';
import { PublicProcessorFactory, type PublicTxResult, PublicTxSimulator, type WorldStateDB } from '@aztec/simulator';
import { type TelemetryClient } from '@aztec/telemetry-client';
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
Expand Down Expand Up @@ -59,7 +60,7 @@ describe('e2e_block_building', () => {
const artifact = StatefulTestContractArtifact;

beforeAll(async () => {
let sequencerClient;
let sequencerClient: SequencerClient | undefined;
({
teardown,
pxe,
Expand All @@ -70,8 +71,7 @@ describe('e2e_block_building', () => {
dateProvider,
cheatCodes,
} = await setup(2));
// Bypass accessibility modifiers in sequencer
sequencer = sequencerClient! as unknown as TestSequencerClient;
sequencer = sequencerClient! as TestSequencerClient;
});

afterEach(() => aztecNode.setConfig({ minTxsPerBlock: 1 }));
Expand Down Expand Up @@ -610,13 +610,6 @@ async function sendAndWait(calls: ContractFunctionInteraction[]) {
);
}

type TestSequencer = Omit<Sequencer, 'publicProcessorFactory' | 'timeTable'> & {
publicProcessorFactory: PublicProcessorFactory;
timeTable: Record<SequencerState, number>;
processTxTime: number;
};
type TestSequencerClient = Omit<SequencerClient, 'sequencer'> & { sequencer: TestSequencer };

const TEST_PUBLIC_TX_SIMULATION_DELAY_MS = 300;

class TestPublicTxSimulator extends PublicTxSimulator {
Expand Down
Loading

0 comments on commit ed5b2a3

Please sign in to comment.