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

feat: epoch cache, do not attest if not in committee or from current proposer #10327

Merged
merged 29 commits into from
Dec 6, 2024
Merged
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e2d7829
feat: delete attestations older than a slot
Maddiaa0 Nov 30, 2024
67ea59c
fmt
Maddiaa0 Nov 30, 2024
b95bcef
test: attestation pool pruning
Maddiaa0 Nov 30, 2024
f6ac466
fmt
Maddiaa0 Nov 30, 2024
e67eaef
feat: epoch cache, do not attest if not in committee or from current …
Maddiaa0 Nov 30, 2024
0265e47
cleanup
Maddiaa0 Nov 30, 2024
6a795ea
test: validator client tests
Maddiaa0 Nov 30, 2024
50eaa4c
fmt
Maddiaa0 Nov 30, 2024
98b118a
fmt + test
Maddiaa0 Dec 2, 2024
6507c02
tmp
Maddiaa0 Dec 3, 2024
97f35c3
fix: next and current slot
Maddiaa0 Dec 5, 2024
7003114
fmt
Maddiaa0 Dec 5, 2024
452e781
Merge branch 'master' into md/epoch-cache--
Maddiaa0 Dec 5, 2024
8c8df0c
post merge fix
Maddiaa0 Dec 5, 2024
e2b43fb
fix: ordering
Maddiaa0 Dec 5, 2024
e0976bb
fix: ordering
Maddiaa0 Dec 5, 2024
da87b55
fix
Maddiaa0 Dec 5, 2024
5fc9900
fix: linter and test
just-mitch Dec 5, 2024
17353cf
Merge branch 'master' into md/epoch-cache--
just-mitch Dec 5, 2024
bcbcccd
fix: merge conflicts
just-mitch Dec 5, 2024
1309414
fix: function ordering and p2p tests
just-mitch Dec 5, 2024
6aba551
fix: reex test - sending same proposal twice in one slot
Maddiaa0 Dec 6, 2024
82da16b
fix: for a slot ci runner, decrease the time jump length
Maddiaa0 Dec 6, 2024
13ec8e4
fix: epoch cache flake
Maddiaa0 Dec 6, 2024
676b7ed
fix: in native testnet, deploy validators at genesis
Maddiaa0 Dec 6, 2024
ca99658
fix: run interleaved
Maddiaa0 Dec 6, 2024
e955e8d
fix: earthfile
Maddiaa0 Dec 6, 2024
dd88dbf
Merge branch 'master' into md/epoch-cache--
Maddiaa0 Dec 6, 2024
38f4b15
fix: unused import
just-mitch Dec 6, 2024
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
Prev Previous commit
Next Next commit
tmp
  • Loading branch information
Maddiaa0 committed Dec 3, 2024
commit 6507c026e1d1acbfec9f7c3720f8ed3ea166dee7
70 changes: 70 additions & 0 deletions l1-contracts/src/core/Leonidas.sol
Original file line number Diff line number Diff line change
@@ -288,6 +288,65 @@ contract Leonidas is Ownable, TimeFns, ILeonidas {
return committee[_computeProposerIndex(epochNumber, slot, sampleSeed, committee.length)];
}

// DEBUG
function getInternalSampleEncodingAt(Timestamp _ts) public view returns (bytes memory, uint256, uint256, uint256) {
Epoch epochNumber = getEpochAt(_ts);
Slot slot = getSlotAt(_ts);

EpochData storage epoch = epochs[epochNumber];

// If the epoch is setup, we can just return the proposer. Otherwise we have to emulate sampling
if (epoch.sampleSeed != 0) {
uint256 committeeSize = epoch.committee.length;
if (committeeSize == 0) {
return (abi.encode(epochNumber, slot, 0), epochNumber.unwrap(), slot.unwrap(), 0);
}

return (abi.encode(epochNumber, slot, epoch.sampleSeed), epochNumber.unwrap(), slot.unwrap(), epoch.sampleSeed);
}

// Allow anyone if there is no validator set
if (validatorSet.length() == 0) {
return (abi.encode(epochNumber, slot, 0), epochNumber.unwrap(), slot.unwrap(), 0);
}

// Emulate a sampling of the validators
uint256 sampleSeed = _getSampleSeed(epochNumber);
return (abi.encode(epochNumber, slot, sampleSeed), epochNumber.unwrap(), slot.unwrap(), sampleSeed);
}

function getInternalProposerIndexAt(Timestamp _ts) public view returns (uint256) {
Epoch epochNumber = getEpochAt(_ts);
Slot slot = getSlotAt(_ts);

EpochData storage epoch = epochs[epochNumber];

// If the epoch is setup, we can just return the proposer. Otherwise we have to emulate sampling
if (epoch.sampleSeed != 0) {
uint256 committeeSize = epoch.committee.length;
if (committeeSize == 0) {
return 0;
}

return
_computeProposerIndex(epochNumber, slot, epoch.sampleSeed, committeeSize);
}

// Allow anyone if there is no validator set
if (validatorSet.length() == 0) {
return 0;
}

// Emulate a sampling of the validators
uint256 sampleSeed = _getSampleSeed(epochNumber);
address[] memory committee = _sampleValidators(sampleSeed);
return _computeProposerIndex(epochNumber, slot, sampleSeed, committee.length);
}

function getTimestamp() public view returns (uint256) {
return block.timestamp;
}

/**
* @notice Computes the epoch at a specific time
*
@@ -334,6 +393,15 @@ contract Leonidas is Ownable, TimeFns, ILeonidas {
return _getCommitteeAt(_ts);
}

// TODO: make sure this cannot modify state
function getSampleSeedAt(Timestamp _ts) external view returns (uint256) {
return _getSampleSeed(getEpochAt(_ts));
}

function getCurrentSampleSeed() external view returns (uint256) {
return _getSampleSeed(getCurrentEpoch());
}

function _getCommitteeAt(Timestamp _ts) internal view returns (address[] memory) {
Epoch epochNumber = getEpochAt(_ts);
EpochData storage epoch = epochs[epochNumber];
@@ -501,6 +569,7 @@ contract Leonidas is Ownable, TimeFns, ILeonidas {
return lastSeed;
}


/**
* @notice Computes the index of the committee member that acts as proposer for a given slot
*
@@ -518,4 +587,5 @@ contract Leonidas is Ownable, TimeFns, ILeonidas {
{
return uint256(keccak256(abi.encode(_epoch, _slot, _seed))) % _size;
}

}
3 changes: 3 additions & 0 deletions yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
@@ -167,6 +167,9 @@ export class Archiver implements ArchiveSource {
rollup.read.GENESIS_TIME(),
] as const);

console.log('l1GenesisTime', l1GenesisTime);
console.log('l1StartBlock', l1StartBlock);

const { aztecEpochDuration: epochDuration, aztecSlotDuration: slotDuration, ethereumSlotDuration } = config;

const archiver = new Archiver(
1 change: 1 addition & 0 deletions yarn-project/end-to-end/package.json
Original file line number Diff line number Diff line change
@@ -99,6 +99,7 @@
"devDependencies": {
"0x": "^5.7.0",
"@jest/globals": "^29.5.0",
"@sinonjs/fake-timers": "^13.0.5",
"@types/jest": "^29.5.0",
"@types/js-yaml": "^4.0.9",
"@types/lodash.chunk": "^4.2.9",
13 changes: 12 additions & 1 deletion yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts
Original file line number Diff line number Diff line change
@@ -33,13 +33,14 @@ describe('e2e_p2p_network', () => {
let nodes: AztecNodeService[];

beforeEach(async () => {

t = await P2PNetworkTest.create({
testName: 'e2e_p2p_network',
numberOfNodes: NUM_NODES,
basePort: BOOT_NODE_UDP_PORT,
// To collect metrics - run in aztec-packages `docker compose --profile metrics up` and set COLLECT_METRICS=true
metricsPort: shouldCollectMetrics(),
});

await t.applyBaseSnapshots();
await t.setup();
});
@@ -65,6 +66,9 @@ describe('e2e_p2p_network', () => {
throw new Error('Bootstrap node ENR is not available');
}

const t0 = Date.now();
console.log('current time', t0);

t.ctx.aztecNodeConfig.validatorReexecute = true;

// create our network of nodes and submit txs into each of them
@@ -84,6 +88,13 @@ describe('e2e_p2p_network', () => {
shouldCollectMetrics(),
);

const t1 = Date.now();
console.log('time after creating nodes', t1);
console.log('time diff', t1 - t0);

// When using fake timers, we need to keep the system and anvil clocks in sync.
await t.syncMockSystemTime();

// wait a bit for peers to discover each other
await sleep(4000);

30 changes: 25 additions & 5 deletions yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts
Original file line number Diff line number Diff line change
@@ -27,14 +27,16 @@ import {
} from '../fixtures/snapshot_manager.js';
import { getPrivateKeyFromIndex } from '../fixtures/utils.js';
import { getEndToEndTestTelemetryClient } from '../fixtures/with_telemetry_utils.js';
import { InstalledClock } from '@sinonjs/fake-timers';

// Use a fixed bootstrap node private key so that we can re-use the same snapshot and the nodes can find each other
const BOOTSTRAP_NODE_PRIVATE_KEY = '080212208f988fc0899e4a73a5aee4d271a5f20670603a756ad8d84f2c94263a6427c591';
const l1ContractsConfig = getL1ContractsConfigEnvVars();
export const WAIT_FOR_TX_TIMEOUT = l1ContractsConfig.aztecSlotDuration * 3;


export class P2PNetworkTest {
private snapshotManager: ISnapshotManager;
public snapshotManager: ISnapshotManager;
private baseAccount;

public logger: DebugLogger;
@@ -81,6 +83,15 @@ export class P2PNetworkTest {
});
}

/**
* When using fake timers, we need to keep the system and anvil clocks in sync.
*/
public async syncMockSystemTime() {
const { timer, deployL1ContractsValues } = this.ctx!;
const timestamp = await deployL1ContractsValues.publicClient.getBlock({blockTag: 'latest'});
timer.setSystemTime(Number(timestamp.timestamp) * 1000);
}

static async create({
testName,
numberOfNodes,
@@ -112,7 +123,7 @@ export class P2PNetworkTest {
}

async applyBaseSnapshots() {
await this.snapshotManager.snapshot('add-validators', async ({ deployL1ContractsValues, aztecNodeConfig }) => {
await this.snapshotManager.snapshot('add-validators', async ({ deployL1ContractsValues, aztecNodeConfig, timer }) => {
const rollup = getContract({
address: deployL1ContractsValues.l1ContractAddresses.rollupAddress.toString(),
abi: RollupAbi,
@@ -160,6 +171,11 @@ export class P2PNetworkTest {
account: this.baseAccount,
}),
});

// Set the system time in the node, only after we have warped the time and waited for a block
// Time is only set in the NEXT block
timer.setSystemTime(Number(timestamp) * 1000);
console.log("getting system time after jump", Date.now());
});
}

@@ -199,7 +215,7 @@ export class P2PNetworkTest {
async removeInitialNode() {
await this.snapshotManager.snapshot(
'remove-inital-validator',
async ({ deployL1ContractsValues, aztecNodeConfig }) => {
async ({ deployL1ContractsValues, aztecNodeConfig, aztecNode, timer }) => {
const rollup = getContract({
address: deployL1ContractsValues.l1ContractAddresses.rollupAddress.toString(),
abi: RollupAbi,
@@ -227,15 +243,19 @@ export class P2PNetworkTest {
}

// Send and await a tx to make sure we mine a block for the warp to correctly progress.
await deployL1ContractsValues.publicClient.waitForTransactionReceipt({
const receipt = await deployL1ContractsValues.publicClient.waitForTransactionReceipt({
hash: await deployL1ContractsValues.walletClient.sendTransaction({
to: this.baseAccount.address,
value: 1n,
account: this.baseAccount,
}),
});
const block = await deployL1ContractsValues.publicClient.getBlock({
blockNumber: receipt.blockNumber,
});
timer.setSystemTime(Number(block.timestamp) * 1000);

await this.ctx.aztecNode.stop();
await aztecNode.stop();
},
);
}
16 changes: 16 additions & 0 deletions yarn-project/end-to-end/src/fixtures/snapshot_manager.ts
Original file line number Diff line number Diff line change
@@ -38,6 +38,9 @@ import { setupL1Contracts } from './setup_l1_contracts.js';
import { type SetupOptions, createAndSyncProverNode, getPrivateKeyFromIndex } from './utils.js';
import { getEndToEndTestTelemetryClient } from './with_telemetry_utils.js';

import { jest } from '@jest/globals';
import FakeTimers, { InstalledClock } from '@sinonjs/fake-timers';

export type SubsystemsContext = {
anvil: Anvil;
acvmConfig: any;
@@ -49,6 +52,7 @@ export type SubsystemsContext = {
proverNode?: ProverNode;
watcher: AnvilTestWatcher;
cheatCodes: CheatCodes;
timer: InstalledClock;
};

type SnapshotEntry = {
@@ -98,6 +102,7 @@ class MockSnapshotManager implements ISnapshotManager {
this.logger.warn(`No data path given, will not persist any snapshots.`);
}


public async snapshot<T>(
name: string,
apply: (context: SubsystemsContext) => Promise<T>,
@@ -146,6 +151,7 @@ class SnapshotManager implements ISnapshotManager {
this.logger = createDebugLogger(`aztec:snapshot_manager:${testName}`);
}


public async snapshot<T>(
name: string,
apply: (context: SubsystemsContext) => Promise<T>,
@@ -247,6 +253,7 @@ async function teardown(context: SubsystemsContext | undefined) {
await context.acvmConfig?.cleanup();
await context.anvil.stop();
await context.watcher.stop();
await context.timer?.uninstall();
}

/**
@@ -265,6 +272,9 @@ async function setupFromFresh(
): Promise<SubsystemsContext> {
logger.verbose(`Initializing state...`);

// Use sinonjs fake timers
const timer = FakeTimers.install({shouldAdvanceTime: true, advanceTimeDelta: 200, toFake: ['Date']});

// Fetch the AztecNode config.
// TODO: For some reason this is currently the union of a bunch of subsystems. That needs fixing.
const aztecNodeConfig: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
@@ -326,6 +336,7 @@ async function setupFromFresh(
logger.info(`Funding rewardDistributor in ${rewardDistributorMintTxHash}`);
}


const watcher = new AnvilTestWatcher(
new EthCheatCodes(aztecNodeConfig.l1RpcUrl),
deployL1ContractsValues.l1ContractAddresses.rollupAddress,
@@ -382,6 +393,7 @@ async function setupFromFresh(
proverNode,
watcher,
cheatCodes,
timer,
};
}

@@ -391,6 +403,9 @@ async function setupFromFresh(
async function setupFromState(statePath: string, logger: Logger): Promise<SubsystemsContext> {
logger.verbose(`Initializing with saved state at ${statePath}...`);

// TODO: make one function
const timer = FakeTimers.install({shouldAdvanceTime: true, advanceTimeDelta: 20});

// TODO: For some reason this is currently the union of a bunch of subsystems. That needs fixing.
const aztecNodeConfig: AztecNodeConfig & SetupOptions = JSON.parse(
readFileSync(`${statePath}/aztec_node_config.json`, 'utf-8'),
@@ -463,6 +478,7 @@ async function setupFromState(statePath: string, logger: Logger): Promise<Subsys
},
watcher,
cheatCodes,
timer,
};
}

1 change: 1 addition & 0 deletions yarn-project/end-to-end/src/fixtures/utils.ts
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@ import { MNEMONIC } from './fixtures.js';
import { getACVMConfig } from './get_acvm_config.js';
import { getBBConfig } from './get_bb_config.js';
import { isMetricsLoggingRequested, setupMetricsLogger } from './logging.js';
import { InstalledClock } from '@sinonjs/fake-timers';

export { deployAndInitializeTokenAndBridgeContracts } from '../shared/cross_chain_test_harness.js';
export { startAnvil };
7 changes: 7 additions & 0 deletions yarn-project/epoch-cache/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type L1ReaderConfig, type L1ContractsConfig, getL1ContractsConfigEnvVars, getL1ReaderConfigFromEnv } from '@aztec/ethereum';

export type EpochCacheConfig = L1ReaderConfig & L1ContractsConfig;

export function getEpochCacheConfigEnvVars(): EpochCacheConfig {
return { ...getL1ReaderConfigFromEnv(), ...getL1ContractsConfigEnvVars() };
}
Loading