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(reqresp): request l2 blocks #11337

Merged
merged 1 commit into from
Jan 20, 2025
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
2 changes: 2 additions & 0 deletions yarn-project/p2p/src/mocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ export const MOCK_SUB_PROTOCOL_HANDLERS: ReqRespSubProtocolHandlers = {
[ReqRespSubProtocol.STATUS]: statusHandler,
[ReqRespSubProtocol.TX]: (_msg: any) => Promise.resolve(Buffer.from('tx')),
[ReqRespSubProtocol.GOODBYE]: (_msg: any) => Promise.resolve(Buffer.from('goodbye')),
[ReqRespSubProtocol.BLOCK]: (_msg: any) => Promise.resolve(Buffer.from('block')),
};

// By default, all requests are valid
Expand All @@ -162,6 +163,7 @@ export const MOCK_SUB_PROTOCOL_VALIDATORS: ReqRespSubProtocolValidators = {
[ReqRespSubProtocol.STATUS]: noopValidator,
[ReqRespSubProtocol.TX]: noopValidator,
[ReqRespSubProtocol.GOODBYE]: noopValidator,
[ReqRespSubProtocol.BLOCK]: noopValidator,
};

/**
Expand Down
6 changes: 4 additions & 2 deletions yarn-project/p2p/src/services/libp2p/libp2p_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ import { PeerManager } from '../peer-manager/peer_manager.js';
import { PeerScoring } from '../peer-manager/peer_scoring.js';
import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, type SubProtocolMap } from '../reqresp/interface.js';
import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
import { pingHandler, statusHandler } from '../reqresp/protocols/index.js';
import { reqRespTxHandler } from '../reqresp/protocols/tx.js';
import { pingHandler, reqRespBlockHandler, reqRespTxHandler, statusHandler } from '../reqresp/protocols/index.js';
import { ReqResp } from '../reqresp/reqresp.js';
import type { P2PService, PeerDiscoveryService } from '../service.js';
import { GossipSubEvent } from '../types.js';
Expand Down Expand Up @@ -300,12 +299,14 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
// Create request response protocol handlers
const txHandler = reqRespTxHandler(this.mempools);
const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
const blockHandler = reqRespBlockHandler(this.l2BlockSource);

const requestResponseHandlers = {
[ReqRespSubProtocol.PING]: pingHandler,
[ReqRespSubProtocol.STATUS]: statusHandler,
[ReqRespSubProtocol.TX]: txHandler.bind(this),
[ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
[ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
};

// Add p2p topic validators
Expand Down Expand Up @@ -335,6 +336,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
// Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
const reqrespSubProtocolValidators = {
...DEFAULT_SUB_PROTOCOL_VALIDATORS,
// TODO(#11336): A request validator for blocks
[ReqRespSubProtocol.TX]: this.validateRequestedTx.bind(this),
};
await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
Expand Down
11 changes: 10 additions & 1 deletion yarn-project/p2p/src/services/reqresp/interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Tx, TxHash } from '@aztec/circuit-types';
import { L2Block, Tx, TxHash } from '@aztec/circuit-types';
import { Fr } from '@aztec/foundation/fields';

import { type PeerId } from '@libp2p/interface';

Expand All @@ -9,12 +10,14 @@ export const PING_PROTOCOL = '/aztec/req/ping/0.1.0';
export const STATUS_PROTOCOL = '/aztec/req/status/0.1.0';
export const GOODBYE_PROTOCOL = '/aztec/req/goodbye/0.1.0';
export const TX_REQ_PROTOCOL = '/aztec/req/tx/0.1.0';
export const BLOCK_REQ_PROTOCOL = '/aztec/req/block/0.1.0';

export enum ReqRespSubProtocol {
PING = PING_PROTOCOL,
STATUS = STATUS_PROTOCOL,
GOODBYE = GOODBYE_PROTOCOL,
TX = TX_REQ_PROTOCOL,
BLOCK = BLOCK_REQ_PROTOCOL,
}

/**
Expand Down Expand Up @@ -75,6 +78,7 @@ export const DEFAULT_SUB_PROTOCOL_VALIDATORS: ReqRespSubProtocolValidators = {
[ReqRespSubProtocol.STATUS]: noopValidator,
[ReqRespSubProtocol.TX]: noopValidator,
[ReqRespSubProtocol.GOODBYE]: noopValidator,
[ReqRespSubProtocol.BLOCK]: noopValidator,
};

/**
Expand All @@ -101,6 +105,7 @@ export const DEFAULT_SUB_PROTOCOL_HANDLERS: ReqRespSubProtocolHandlers = {
[ReqRespSubProtocol.STATUS]: defaultHandler,
[ReqRespSubProtocol.TX]: defaultHandler,
[ReqRespSubProtocol.GOODBYE]: defaultHandler,
[ReqRespSubProtocol.BLOCK]: defaultHandler,
};

/**
Expand Down Expand Up @@ -158,4 +163,8 @@ export const subProtocolMap: SubProtocolMap = {
request: RequestableBuffer,
response: RequestableBuffer,
},
[ReqRespSubProtocol.BLOCK]: {
request: Fr, // block number
response: L2Block,
},
};
15 changes: 15 additions & 0 deletions yarn-project/p2p/src/services/reqresp/protocols/block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { type L2BlockSource } from '@aztec/circuit-types';
import { Fr } from '@aztec/foundation/fields';

import { type PeerId } from '@libp2p/interface';

import { type ReqRespSubProtocolHandler } from '../interface.js';

export function reqRespBlockHandler(l2BlockSource: L2BlockSource): ReqRespSubProtocolHandler {
return async (_peerId: PeerId, msg: Buffer) => {
const blockNumber = Fr.fromBuffer(msg);

const foundBlock = await l2BlockSource.getBlock(Number(blockNumber));
return foundBlock ? foundBlock.toBuffer() : Buffer.alloc(0);
};
}
1 change: 1 addition & 0 deletions yarn-project/p2p/src/services/reqresp/protocols/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './ping.js';
export * from './status.js';
export * from './tx.js';
export * from './goodbye.js';
export * from './block.js';
10 changes: 10 additions & 0 deletions yarn-project/p2p/src/services/reqresp/rate-limiter/rate_limits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ export const DEFAULT_RATE_LIMITS: ReqRespSubProtocolRateLimits = {
quotaCount: 10,
},
},
[ReqRespSubProtocol.BLOCK]: {
peerLimit: {
quotaTimeMs: 1000,
quotaCount: 2,
},
globalLimit: {
quotaTimeMs: 1000,
quotaCount: 5,
},
},
[ReqRespSubProtocol.GOODBYE]: {
peerLimit: {
quotaTimeMs: 1000,
Expand Down
30 changes: 29 additions & 1 deletion yarn-project/p2p/src/services/reqresp/reqresp.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PeerErrorSeverity, TxHash, mockTx } from '@aztec/circuit-types';
import { L2Block, type L2BlockSource, PeerErrorSeverity, TxHash, mockTx } from '@aztec/circuit-types';
import { Fr } from '@aztec/foundation/fields';
import { createLogger } from '@aztec/foundation/log';
import { sleep } from '@aztec/foundation/sleep';

Expand All @@ -19,6 +20,7 @@ import {
import { type PeerManager } from '../peer-manager/peer_manager.js';
import { type PeerScoring } from '../peer-manager/peer_scoring.js';
import { ReqRespSubProtocol, RequestableBuffer } from './interface.js';
import { reqRespBlockHandler } from './protocols/block.js';
import { GoodByeReason, reqGoodbyeHandler } from './protocols/goodbye.js';

const PING_REQUEST = RequestableBuffer.fromBuffer(Buffer.from('ping'));
Expand Down Expand Up @@ -341,6 +343,32 @@ describe('ReqResp', () => {
});
});

describe('Block protocol', () => {
it('should handle block requests', async () => {
const blockNumber = 1;
const blockNumberFr = Fr.ONE;
const block = L2Block.random(blockNumber);

const l2BlockSource: MockProxy<L2BlockSource> = mock<L2BlockSource>();
l2BlockSource.getBlock.mockImplementation((_blockNumber: number) => {
return Promise.resolve(block);
});

const protocolHandlers = MOCK_SUB_PROTOCOL_HANDLERS;
protocolHandlers[ReqRespSubProtocol.BLOCK] = reqRespBlockHandler(l2BlockSource);

nodes = await createNodes(peerScoring, 2);

await startNodes(nodes, protocolHandlers);
await sleep(500);
await connectToPeers(nodes);
await sleep(500);

const res = await nodes[0].req.sendRequest(ReqRespSubProtocol.BLOCK, blockNumberFr);
expect(res).toEqual(block);
});
});

describe('Batch requests', () => {
it('should send a batch request between many peers', async () => {
const batchSize = 9;
Expand Down
Loading