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

fix: address issues when using wall-time #8329

Merged
merged 1 commit into from
Sep 3, 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
18 changes: 7 additions & 11 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
*
* @dev TODO(#7346): Verify root proofs rather than block root when batch rollups are integrated.
*
* @dev Will call `_progressState` to update the proven chain. Notice this have potentially
* unbounded gas consumption.
*
* @dev Will emit `L2ProofVerified` if the proof is valid
*
* @dev Will throw if:
Expand Down Expand Up @@ -368,16 +365,15 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
}

/**
* @notice Check if a proposer can propose at a given time
* @notice Check if msg.sender can propose at a given time
*
* @param _ts - The timestamp to check
* @param _proposer - The proposer to check
* @param _archive - The archive to check (should be the latest archive)
*
* @return uint256 - The slot at the given timestamp
* @return uint256 - The block number at the given timestamp
*/
function canProposeAtTime(uint256 _ts, address _proposer, bytes32 _archive)
function canProposeAtTime(uint256 _ts, bytes32 _archive)
external
view
override(IRollup)
Expand All @@ -395,10 +391,10 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
revert Errors.Rollup__InvalidArchive(tipArchive, _archive);
}

address proposer = getProposerAt(_ts);
if (proposer != address(0) && proposer != _proposer) {
revert Errors.Leonidas__InvalidProposer(proposer, _proposer);
}
SignatureLib.Signature[] memory sigs = new SignatureLib.Signature[](0);
DataStructures.ExecutionFlags memory flags =
DataStructures.ExecutionFlags({ignoreDA: true, ignoreSignatures: true});
_validateLeonidas(slot, sigs, _archive, flags);

return (slot, pendingBlockCount);
}
Expand Down Expand Up @@ -575,7 +571,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
revert Errors.Rollup__InvalidEpoch(currentEpoch, epochNumber);
}

_proposePendingBlock(_slot, _signatures, _digest, _flags);
_validateLeonidas(_slot, _signatures, _digest, _flags);
}

/**
Expand Down
5 changes: 1 addition & 4 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ interface IRollup {
event L2ProofVerified(uint256 indexed blockNumber, bytes32 indexed proverId);
event PrunedPending(uint256 provenBlockCount, uint256 pendingBlockCount);

function canProposeAtTime(uint256 _ts, address _proposer, bytes32 _archive)
external
view
returns (uint256, uint256);
function canProposeAtTime(uint256 _ts, bytes32 _archive) external view returns (uint256, uint256);
function validateHeader(
bytes calldata _header,
SignatureLib.Signature[] memory _signatures,
Expand Down
1 change: 1 addition & 0 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ library Constants {
uint256 internal constant ETHEREUM_SLOT_DURATION = 12;
uint256 internal constant AZTEC_SLOT_DURATION = 12;
uint256 internal constant AZTEC_EPOCH_DURATION = 48;
uint256 internal constant AZTEC_TARGET_COMMITTEE_SIZE = 48;
uint256 internal constant GENESIS_ARCHIVE_ROOT =
8142738430000951296386584486068033372964809139261822027365426310856631083550;
uint256 internal constant FEE_JUICE_INITIAL_MINT = 20000000000;
Expand Down
4 changes: 2 additions & 2 deletions l1-contracts/src/core/sequencer_selection/Leonidas.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ contract Leonidas is Ownable, ILeonidas {

// The target number of validators in a committee
// @todo #8021
uint256 public constant TARGET_COMMITTEE_SIZE = EPOCH_DURATION;
uint256 public constant TARGET_COMMITTEE_SIZE = Constants.AZTEC_TARGET_COMMITTEE_SIZE;

// The time that the contract was deployed
uint256 public immutable GENESIS_TIME;
Expand Down Expand Up @@ -344,7 +344,7 @@ contract Leonidas is Ownable, ILeonidas {
* @param _signatures - The signatures of the committee members
* @param _digest - The digest of the block
*/
function _proposePendingBlock(
function _validateLeonidas(
uint256 _slot,
SignatureLib.Signature[] memory _signatures,
bytes32 _digest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ global ETHEREUM_SLOT_DURATION: u32 = 12;
// AZTEC_SLOT_DURATION should be a multiple of ETHEREUM_SLOT_DURATION
global AZTEC_SLOT_DURATION: u32 = ETHEREUM_SLOT_DURATION * 1;
global AZTEC_EPOCH_DURATION: u32 = 48;
global AZTEC_TARGET_COMMITTEE_SIZE: u32 = 48;
// The following is taken from building a block and looking at the `lastArchive` value in it.
// You can run the `integration_l1_publisher.test.ts` and look at the first blocks in the fixtures.
global GENESIS_ARCHIVE_ROOT: Field = 0x1200a06aae1368abe36530b585bd7a4d2ba4de5037b82076412691a187d7621e;
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/circuits.js/src/constants.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const BLOB_SIZE_IN_BYTES = 126976;
export const ETHEREUM_SLOT_DURATION = 12;
export const AZTEC_SLOT_DURATION = 12;
export const AZTEC_EPOCH_DURATION = 48;
export const AZTEC_TARGET_COMMITTEE_SIZE = 48;
export const GENESIS_ARCHIVE_ROOT = 8142738430000951296386584486068033372964809139261822027365426310856631083550n;
export const FEE_JUICE_INITIAL_MINT = 20000000000;
export const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 20000;
Expand Down Expand Up @@ -395,6 +396,7 @@ export enum GeneratorIndex {
SIDE_EFFECT = 29,
FEE_PAYLOAD = 30,
COMBINED_PAYLOAD = 31,
TX_NULLIFIER = 32,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this not there before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't seem so

TX_REQUEST = 33,
SIGNATURE_PAYLOAD = 34,
VK = 41,
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/end-to-end/src/e2e_l1_with_wall_time.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getSchnorrAccount } from '@aztec/accounts/schnorr';
import { type DebugLogger, Fr, GrumpkinScalar, type PXE, type SentTx, TxStatus } from '@aztec/aztec.js';
import { EthAddress } from '@aztec/circuits.js';
import { ETHEREUM_SLOT_DURATION, EthAddress } from '@aztec/circuits.js';
import { type PXEService } from '@aztec/pxe';

import { privateKeyToAccount } from 'viem/accounts';
Expand All @@ -16,7 +16,7 @@ describe('e2e_l1_with_wall_time', () => {
const account = privateKeyToAccount(`0x${getPrivateKeyFromIndex(0)!.toString('hex')}`);
const initialValidators = [EthAddress.fromString(account.address)];

({ teardown, logger, pxe } = await setup(0, { initialValidators, l1BlockTime: 12 }));
({ teardown, logger, pxe } = await setup(0, { initialValidators, l1BlockTime: ETHEREUM_SLOT_DURATION, salt: 420 }));
});

afterEach(() => teardown());
Expand Down
27 changes: 24 additions & 3 deletions yarn-project/end-to-end/src/e2e_p2p_network.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
TxStatus,
sleep,
} from '@aztec/aztec.js';
import { EthAddress } from '@aztec/circuits.js';
import { ETHEREUM_SLOT_DURATION, EthAddress } from '@aztec/circuits.js';
import { RollupAbi } from '@aztec/l1-artifacts';
import { type BootstrapNode } from '@aztec/p2p';
import { type PXEService, createPXEService, getPXEServiceConfig as getRpcConfig } from '@aztec/pxe';
Expand Down Expand Up @@ -60,7 +60,12 @@ describe('e2e_p2p_network', () => {

const initialValidators = [EthAddress.fromString(account.address)];

({ teardown, config, logger, deployL1ContractsValues } = await setup(0, { initialValidators, ...options }));
({ teardown, config, logger, deployL1ContractsValues } = await setup(0, {
initialValidators,
l1BlockTime: ETHEREUM_SLOT_DURATION,
salt: 420,
...options,
}));

bootstrapNode = await createBootstrapNode(BOOT_NODE_UDP_PORT);
bootstrapNodeEnr = bootstrapNode.getENR().encodeTxt();
Expand All @@ -77,15 +82,31 @@ describe('e2e_p2p_network', () => {
for (let i = 0; i < NUM_NODES; i++) {
const account = privateKeyToAccount(`0x${getPrivateKeyFromIndex(i + 1)!.toString('hex')}`);
await rollup.write.addValidator([account.address]);
logger.debug(`Adding ${account.address} as validator`);
}

// Remove the initial sequencer from the set! This was the sequencer we used for perform the setup.
logger.debug(`Removing ${account.address} as validator`);
const txHash = await rollup.write.removeValidator([account.address]);

await deployL1ContractsValues.publicClient.waitForTransactionReceipt({ hash: txHash });

//@note Now we jump ahead to the next epoch such that the validator committee is picked
// INTERVAL MINING: If we are using anvil interval mining this will NOT progress the time!
// Which means that the validator set will still be empty! So anyone can propose.
const slotsInEpoch = await rollup.read.EPOCH_DURATION();
const timestamp = await rollup.read.getTimestampForSlot([slotsInEpoch]);
const cheatCodes = new EthCheatCodes(config.l1RpcUrl);
await cheatCodes.warp(Number(timestamp));
try {
await cheatCodes.warp(Number(timestamp));
} catch (err) {
logger.debug('Warp failed, time already satisfied');
}

// Send and await a tx to make sure we mine a block for the warp to correctly progress.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☠️

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we were to sleep for ETHEREUM_SLOT_DURATION, the same effect would be achieved right?

await deployL1ContractsValues.publicClient.waitForTransactionReceipt({
hash: await deployL1ContractsValues.walletClient.sendTransaction({ to: account.address, value: 1n, account }),
});
});

afterEach(() => teardown());
Expand Down
6 changes: 5 additions & 1 deletion yarn-project/end-to-end/src/fixtures/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,11 @@ export async function setup(
deployL1ContractsValues.l1ContractAddresses.rollupAddress,
deployL1ContractsValues.publicClient,
);
watcher.start();

// If we are NOT using wall time, we should start the watcher to jump in time as needed.
if (!opts.l1BlockTime) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment would be useful here

watcher.start();
}

const wallets = numberOfAccounts > 0 ? await createAccounts(pxe, numberOfAccounts) : [];
const cheatCodes = CheatCodes.create(config.l1RpcUrl, pxe!);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/fixtures/watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class Watcher {
this.logger.info(`Slot ${currentSlot} was filled, jumped to next slot`);
}
} catch (err) {
this.logger.error('mineIfSlotFilled failed', err);
this.logger.error('mineIfSlotFilled failed');
}
}
}
33 changes: 1 addition & 32 deletions yarn-project/sequencer-client/src/publisher/l1-publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,6 @@ export type L1SubmitProofArgs = {
aggregationObject: Buffer;
};

export type MetadataForSlot = {
proposer: EthAddress;
slot: bigint;
pendingBlockNumber: bigint;
archive: Buffer;
};

/**
* Publishes L2 blocks to L1. This implementation does *not* retry a transaction in
* the event of network congestion, but should work for local development.
Expand Down Expand Up @@ -176,11 +169,7 @@ export class L1Publisher {
*/
public async canProposeAtNextEthBlock(archive: Buffer): Promise<[bigint, bigint]> {
const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION));
const [slot, blockNumber] = await this.rollupContract.read.canProposeAtTime([
ts,
this.account.address,
`0x${archive.toString('hex')}`,
]);
const [slot, blockNumber] = await this.rollupContract.read.canProposeAtTime([ts, `0x${archive.toString('hex')}`]);
return [slot, blockNumber];
}

Expand Down Expand Up @@ -227,26 +216,6 @@ export class L1Publisher {
}
}

// @note Assumes that all ethereum slots have blocks
// Using next Ethereum block so we do NOT need to wait for it being mined before seeing the effect
public async getMetadataForSlotAtNextEthBlock(): Promise<MetadataForSlot> {
const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION));

const [submitter, slot, pendingBlockCount, archive] = await Promise.all([
this.rollupContract.read.getProposerAt([ts]),
this.rollupContract.read.getSlotAt([ts]),
this.rollupContract.read.pendingBlockCount(),
this.rollupContract.read.archive(),
]);

return {
proposer: EthAddress.fromString(submitter),
slot,
pendingBlockNumber: pendingBlockCount - 1n,
archive: Buffer.from(archive.replace('0x', ''), 'hex'),
};
}

public async getCurrentEpochCommittee(): Promise<EthAddress[]> {
const committee = await this.rollupContract.read.getCurrentEpochCommittee();
return committee.map(EthAddress.fromString);
Expand Down
6 changes: 5 additions & 1 deletion yarn-project/sequencer-client/src/sequencer/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,11 @@ export class Sequencer {
const revertError = err.walk(err => err instanceof ContractFunctionRevertedError);
if (revertError instanceof ContractFunctionRevertedError) {
const errorName = revertError.data?.errorName ?? '';
this.log.debug(`canProposeAtTime failed with "${errorName}"`);
const args =
revertError.metaMessages && revertError.metaMessages?.length > 1
? revertError.metaMessages[1].trimStart()
: '';
this.log.debug(`canProposeAtTime failed with "${errorName}${args}"`);
}
}
throw err;
Expand Down
Loading