Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { sleep } from '@aztec/foundation/sleep';
import { MockZKPassportVerifierAbi } from '@aztec/l1-artifacts/MockZKPassportVerifierAbi';
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
import type { SequencerClient } from '@aztec/sequencer-client';
import { CheckpointAttestation, ConsensusPayload } from '@aztec/stdlib/p2p';
import { CheckpointAttestation, ConsensusPayload, TopicType } from '@aztec/stdlib/p2p';
import { ZkPassportProofParams } from '@aztec/stdlib/zkpassport';

import { jest } from '@jest/globals';
Expand Down Expand Up @@ -201,8 +201,21 @@ describe('e2e_p2p_network', () => {
shouldCollectMetrics(),
);

// wait a bit for peers to discover each other
await sleep(8000);
// Wait for the gossipsub mesh to fully form before the committee starts producing. With
// skipInitialSequencer, the first blocks are built by this committee, and the first checkpoint
// must reach quorum (all 4 validators) to land on L1. If the proposal/checkpoint meshes are only
// partly formed, some committee members miss the first proposal, the first checkpoint stalls at
// 2/3, and every later slot rebuilds a competing un-checkpointed block 1 that peers reject as
// `block_number_already_exists` — a permanent 2/3 deadlock. Require a full mesh (N-1 peers per
// node) on the proposal/checkpoint topics so the first proposal reaches the whole committee.
await t.waitForP2PMeshConnectivity(
nodes,
NUM_VALIDATORS,
60,
0.5,
[TopicType.block_proposal, TopicType.checkpoint_proposal, TopicType.checkpoint_attestation],
NUM_VALIDATORS - 1,
);

// Wait for the first checkpoint to be published to L1 before submitting transactions.
// With skipInitialSequencer, no blocks exist from setup, so the first blocks are built by the
Expand Down
17 changes: 10 additions & 7 deletions yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ export class P2PNetworkTest {
timeoutSeconds = 30,
checkIntervalSeconds = 0.1,
topics: TopicType[] = [TopicType.tx],
minMeshPeerCount = 1,
) {
const nodeCount = expectedNodeCount ?? nodes.length;
const minPeerCount = nodeCount - 1;
Expand All @@ -457,27 +458,29 @@ export class P2PNetworkTest {

this.logger.warn('All nodes connected to P2P mesh');

// Wait for GossipSub mesh to form for all specified topics.
// We only require at least 1 mesh peer per node because GossipSub
// stops grafting once it reaches Dlo peers and won't fill the mesh to all available peers.
// Wait for the GossipSub mesh to form for all specified topics. By default we only require at
// least 1 mesh peer per node, since GossipSub stops grafting once it reaches Dlo peers and won't
// fill the mesh to every available peer. Callers that need a proposal to reach the whole
// committee within a slot (e.g. quorum-from-genesis tests) raise `minMeshPeerCount` so the mesh
// is fully formed — a single mesh peer can leave some committee members unreached at first.
for (const topic of topics) {
this.logger.warn(`Waiting for GossipSub mesh to form for ${topic} topic...`);
this.logger.warn(`Waiting for GossipSub mesh (>= ${minMeshPeerCount} peers per node) for ${topic} topic...`);
await Promise.all(
nodes.map(async (node, index) => {
const p2p = node.getP2P();
await retryUntil(
async () => {
const meshPeers = await p2p.getGossipMeshPeerCount(topic);
this.logger.debug(`Node ${index} has ${meshPeers} gossip mesh peers for ${topic} topic`);
return meshPeers >= 1 ? true : undefined;
return meshPeers >= minMeshPeerCount ? true : undefined;
},
`Node ${index} to have gossip mesh peers for ${topic} topic`,
`Node ${index} to have >= ${minMeshPeerCount} gossip mesh peers for ${topic} topic`,
timeoutSeconds,
checkIntervalSeconds,
);
}),
);
this.logger.warn(`All nodes have gossip mesh peers for ${topic} topic`);
this.logger.warn(`All nodes have >= ${minMeshPeerCount} gossip mesh peers for ${topic} topic`);
}
}

Expand Down
Loading