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(p2p): persist node private p2p keys #10324

Merged
merged 12 commits into from
Dec 3, 2024
1 change: 0 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
Expand Up @@ -75,7 +75,6 @@ describe('e2e_p2p_network', () => {
t.logger.info('Creating nodes');
nodes = await createNodes(
t.ctx.aztecNodeConfig,
t.peerIdPrivateKeys,
Copy link
Member Author

Choose a reason for hiding this comment

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

rediscovery test is not longer provided the same private keys, it is expected to store it on its own

t.bootstrapNodeEnr,
NUM_NODES,
BOOT_NODE_UDP_PORT,
Expand Down
2 changes: 0 additions & 2 deletions yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
PRIVATE_KEYS_START_INDEX,
createValidatorConfig,
generateNodePrivateKeys,
generatePeerIdPrivateKeys,
} from '../fixtures/setup_p2p_test.js';
import {
type ISnapshotManager,
Expand Down Expand Up @@ -66,7 +65,6 @@ export class P2PNetworkTest {
this.baseAccount = privateKeyToAccount(`0x${getPrivateKeyFromIndex(0)!.toString('hex')}`);
this.nodePrivateKeys = generateNodePrivateKeys(PRIVATE_KEYS_START_INDEX, numberOfNodes);
this.nodePublicKeys = this.nodePrivateKeys.map(privateKey => privateKeyToAccount(privateKey).address);
this.peerIdPrivateKeys = generatePeerIdPrivateKeys(numberOfNodes);

this.bootstrapNodeEnr = bootstrapNode.getENR().encodeTxt();

Expand Down
2 changes: 0 additions & 2 deletions yarn-project/end-to-end/src/e2e_p2p/rediscovery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ describe('e2e_p2p_rediscovery', () => {
const contexts: NodeContext[] = [];
nodes = await createNodes(
t.ctx.aztecNodeConfig,
t.peerIdPrivateKeys,
t.bootstrapNodeEnr,
NUM_NODES,
BOOT_NODE_UDP_PORT,
Expand All @@ -73,7 +72,6 @@ describe('e2e_p2p_rediscovery', () => {

const newNode = await createNode(
t.ctx.aztecNodeConfig,
t.peerIdPrivateKeys[i],
i + 1 + BOOT_NODE_UDP_PORT,
undefined,
i,
Expand Down
1 change: 0 additions & 1 deletion yarn-project/end-to-end/src/e2e_p2p/reex.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ describe('e2e_p2p_reex', () => {

nodes = await createNodes(
t.ctx.aztecNodeConfig,
t.peerIdPrivateKeys,
t.bootstrapNodeEnr,
NUM_NODES,
BOOT_NODE_UDP_PORT,
Expand Down
1 change: 0 additions & 1 deletion yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ describe('e2e_p2p_reqresp_tx', () => {
t.logger.info('Creating nodes');
nodes = await createNodes(
t.ctx.aztecNodeConfig,
t.peerIdPrivateKeys,
t.bootstrapNodeEnr,
NUM_NODES,
BOOT_NODE_UDP_PORT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ describe('e2e_p2p_governance_proposer', () => {
t.logger.info('Creating nodes');
nodes = await createNodes(
{ ...t.ctx.aztecNodeConfig, governanceProposerPayload: newPayloadAddress },
t.peerIdPrivateKeys,
t.bootstrapNodeEnr,
NUM_NODES,
BOOT_NODE_UDP_PORT,
Expand Down
30 changes: 1 addition & 29 deletions yarn-project/end-to-end/src/fixtures/setup_p2p_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { type AztecAddress } from '@aztec/circuits.js';
import { type PXEService } from '@aztec/pxe';

import getPort from 'get-port';
import { generatePrivateKey } from 'viem/accounts';

import { getPrivateKeyFromIndex } from './utils.js';
import { getEndToEndTestTelemetryClient } from './with_telemetry_utils.js';
Expand All @@ -32,22 +31,8 @@ export function generateNodePrivateKeys(startIndex: number, numberOfNodes: numbe
return nodePrivateKeys;
}

export function generatePeerIdPrivateKey(): string {
// magic number is multiaddr prefix: https://multiformats.io/multiaddr/ for secp256k1
return '08021220' + generatePrivateKey().substr(2, 66);
}

export function generatePeerIdPrivateKeys(numberOfPeers: number): string[] {
const peerIdPrivateKeys = [];
for (let i = 0; i < numberOfPeers; i++) {
peerIdPrivateKeys.push(generatePeerIdPrivateKey());
}
return peerIdPrivateKeys;
}

export function createNodes(
config: AztecNodeConfig,
peerIdPrivateKeys: string[],
bootstrapNodeEnr: string,
numNodes: number,
bootNodePort: number,
Expand All @@ -60,15 +45,7 @@ export function createNodes(
const port = bootNodePort + i + 1;

const dataDir = dataDirectory ? `${dataDirectory}-${i}` : undefined;
const nodePromise = createNode(
config,
peerIdPrivateKeys[i],
port,
bootstrapNodeEnr,
i + PRIVATE_KEYS_START_INDEX,
dataDir,
metricsPort,
);
const nodePromise = createNode(config, port, bootstrapNodeEnr, i + PRIVATE_KEYS_START_INDEX, dataDir, metricsPort);
nodePromises.push(nodePromise);
}
return Promise.all(nodePromises);
Expand All @@ -77,7 +54,6 @@ export function createNodes(
// creates a P2P enabled instance of Aztec Node Service
export async function createNode(
config: AztecNodeConfig,
peerIdPrivateKey: string,
tcpPort: number,
bootstrapNode: string | undefined,
publisherAddressIndex: number,
Expand All @@ -88,7 +64,6 @@ export async function createNode(
config,
bootstrapNode,
tcpPort,
peerIdPrivateKey,
publisherAddressIndex,
dataDirectory,
);
Expand All @@ -105,11 +80,9 @@ export async function createValidatorConfig(
config: AztecNodeConfig,
bootstrapNodeEnr?: string,
port?: number,
peerIdPrivateKey?: string,
accountIndex: number = 1,
dataDirectory?: string,
) {
peerIdPrivateKey = peerIdPrivateKey ?? generatePeerIdPrivateKey();
port = port ?? (await getPort());

const privateKey = getPrivateKeyFromIndex(accountIndex);
Expand All @@ -120,7 +93,6 @@ export async function createValidatorConfig(

const nodeConfig: AztecNodeConfig = {
...config,
peerIdPrivateKey: peerIdPrivateKey,
udpListenAddress: `0.0.0.0:${port}`,
tcpListenAddress: `0.0.0.0:${port}`,
tcpAnnounceAddress: `127.0.0.1:${port}`,
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/kv-store/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { type EthAddress } from '@aztec/foundation/eth-address';
export type DataStoreConfig = {
dataDirectory: string | undefined;
dataStoreMapSizeKB: number;
l1Contracts: { rollupAddress: EthAddress };
l1Contracts?: { rollupAddress: EthAddress };
};

export const dataConfigMappings: ConfigMappingsType<DataStoreConfig> = {
Expand Down
11 changes: 6 additions & 5 deletions yarn-project/kv-store/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ export function createStore(name: string, config: DataStoreConfig, log: Logger =
? `Creating ${name} data store at directory ${dataDirectory} with map size ${config.dataStoreMapSizeKB} KB`
: `Creating ${name} ephemeral data store with map size ${config.dataStoreMapSizeKB} KB`,
);
return initStoreForRollup(
AztecLmdbStore.open(dataDirectory, config.dataStoreMapSizeKB, false),
config.l1Contracts.rollupAddress,
log,
);

const store = AztecLmdbStore.open(dataDirectory, config.dataStoreMapSizeKB, false);
if (config.l1Contracts?.rollupAddress) {
return initStoreForRollup(store, config.l1Contracts.rollupAddress, log);
}
return store;
}

/**
Expand Down
1 change: 1 addition & 0 deletions yarn-project/p2p-bootstrap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
],
"dependencies": {
"@aztec/foundation": "workspace:^",
"@aztec/kv-store": "workspace:^",
"@aztec/p2p": "workspace:^",
"@aztec/telemetry-client": "workspace:^",
"dotenv": "^16.0.3",
Expand Down
5 changes: 4 additions & 1 deletion yarn-project/p2p-bootstrap/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createDebugLogger } from '@aztec/foundation/log';
import { createStore, openTmpStore } from '@aztec/kv-store/utils';
import { type BootnodeConfig, BootstrapNode } from '@aztec/p2p';
import { type TelemetryClient } from '@aztec/telemetry-client';
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
Expand All @@ -18,7 +19,9 @@ async function main(
telemetryClient: TelemetryClient = new NoopTelemetryClient(),
logger = debugLogger,
) {
const bootstrapNode = new BootstrapNode(telemetryClient, logger);
const store = await createStore('p2p-bootstrap', config, logger);

const bootstrapNode = new BootstrapNode(store, telemetryClient, logger);
await bootstrapNode.start(config);
logger.info('DiscV5 Bootnode started');

Expand Down
3 changes: 3 additions & 0 deletions yarn-project/p2p-bootstrap/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
{
"path": "../foundation"
},
{
"path": "../kv-store"
},
{
"path": "../p2p"
},
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/p2p/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"@chainsafe/libp2p-noise": "^15.0.0",
"@chainsafe/libp2p-yamux": "^6.0.2",
"@libp2p/bootstrap": "10.0.0",
"@libp2p/crypto": "4.0.3",
"@libp2p/crypto": "^4.1.1",
"@libp2p/identify": "1.0.18",
"@libp2p/interface": "1.3.1",
"@libp2p/kad-dht": "10.0.4",
Expand Down
16 changes: 11 additions & 5 deletions yarn-project/p2p/src/bootstrap/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createDebugLogger } from '@aztec/foundation/log';
import { type AztecKVStore } from '@aztec/kv-store';
import { OtelMetricsAdapter, type TelemetryClient } from '@aztec/telemetry-client';

import { Discv5, type Discv5EventEmitter } from '@chainsafe/discv5';
Expand All @@ -8,8 +9,7 @@ import { type Multiaddr, multiaddr } from '@multiformats/multiaddr';

import type { BootnodeConfig } from '../config.js';
import { AZTEC_ENR_KEY, AZTEC_NET } from '../service/discV5_service.js';
import { createLibP2PPeerId } from '../service/index.js';
import { convertToMultiaddr } from '../util.js';
import { convertToMultiaddr, createLibP2PPeerIdFromPrivateKey, getPeerIdPrivateKey } from '../util.js';

/**
* Encapsulates a 'Bootstrap' node, used for the purpose of assisting new joiners in acquiring peers.
Expand All @@ -18,16 +18,22 @@ export class BootstrapNode {
private node?: Discv5 = undefined;
private peerId?: PeerId;

constructor(private telemetry: TelemetryClient, private logger = createDebugLogger('aztec:p2p_bootstrap')) {}
constructor(
private store: AztecKVStore,
private telemetry: TelemetryClient,
private logger = createDebugLogger('aztec:p2p_bootstrap'),
) {}

/**
* Starts the bootstrap node.
* @param config - A partial P2P configuration. No need for TCP values as well as aztec node specific values.
* @returns An empty promise.
*/
public async start(config: BootnodeConfig) {
const { peerIdPrivateKey, udpListenAddress, udpAnnounceAddress } = config;
const peerId = await createLibP2PPeerId(peerIdPrivateKey);
const { udpListenAddress, udpAnnounceAddress } = config;

const peerIdPrivateKey = await getPeerIdPrivateKey(config, this.store);
const peerId = await createLibP2PPeerIdFromPrivateKey(peerIdPrivateKey);
this.peerId = peerId;
const enr = SignableENR.createFromPeerId(peerId);

Expand Down
7 changes: 4 additions & 3 deletions yarn-project/p2p/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { type MemPools } from '../mem_pools/interface.js';
import { AztecKVTxPool, type TxPool } from '../mem_pools/tx_pool/index.js';
import { DiscV5Service } from '../service/discV5_service.js';
import { DummyP2PService } from '../service/dummy_service.js';
import { LibP2PService, createLibP2PPeerId } from '../service/index.js';
import { configureP2PClientAddresses } from '../util.js';
import { LibP2PService } from '../service/index.js';
import { configureP2PClientAddresses, createLibP2PPeerIdFromPrivateKey, getPeerIdPrivateKey } from '../util.js';

export * from './p2p_client.js';

Expand Down Expand Up @@ -49,7 +49,8 @@ export const createP2PClient = async (
config = await configureP2PClientAddresses(_config);

// Create peer discovery service
const peerId = await createLibP2PPeerId(config.peerIdPrivateKey);
const peerIdPrivateKey = await getPeerIdPrivateKey(config, store);
const peerId = await createLibP2PPeerIdFromPrivateKey(peerIdPrivateKey);
const discoveryService = new DiscV5Service(peerId, config, telemetry);

p2pService = await LibP2PService.new(
Expand Down
11 changes: 9 additions & 2 deletions yarn-project/p2p/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
numberConfigHelper,
pickConfigMappings,
} from '@aztec/foundation/config';
import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';

import { type P2PReqRespConfig, p2pReqRespConfigMappings } from './service/reqresp/config.js';

Expand Down Expand Up @@ -318,14 +319,20 @@ export type BootnodeConfig = Pick<
P2PConfig,
'udpAnnounceAddress' | 'peerIdPrivateKey' | 'minPeerCount' | 'maxPeerCount'
> &
Required<Pick<P2PConfig, 'udpListenAddress'>>;
Required<Pick<P2PConfig, 'udpListenAddress'>> &
Pick<DataStoreConfig, 'dataDirectory' | 'dataStoreMapSizeKB'>;

const bootnodeConfigKeys: (keyof BootnodeConfig)[] = [
'udpAnnounceAddress',
'peerIdPrivateKey',
'minPeerCount',
'maxPeerCount',
'udpListenAddress',
'dataDirectory',
'dataStoreMapSizeKB',
];

export const bootnodeConfigMappings = pickConfigMappings(p2pConfigMappings, bootnodeConfigKeys);
export const bootnodeConfigMappings = pickConfigMappings(
{ ...p2pConfigMappings, ...dataConfigMappings },
bootnodeConfigKeys,
);
14 changes: 10 additions & 4 deletions yarn-project/p2p/src/mocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
type WorldStateSynchronizer,
} from '@aztec/circuit-types';
import { type DataStoreConfig } from '@aztec/kv-store/config';
import { openTmpStore } from '@aztec/kv-store/utils';
import { type TelemetryClient } from '@aztec/telemetry-client';
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';

Expand All @@ -14,6 +15,7 @@ import { yamux } from '@chainsafe/libp2p-yamux';
import { bootstrap } from '@libp2p/bootstrap';
import { identify } from '@libp2p/identify';
import { type PeerId } from '@libp2p/interface';
import { createSecp256k1PeerId } from '@libp2p/peer-id-factory';
import { tcp } from '@libp2p/tcp';
import getPort from 'get-port';
import { type Libp2p, type Libp2pOptions, createLibp2p } from 'libp2p';
Expand All @@ -22,7 +24,7 @@ import { BootstrapNode } from '../bootstrap/bootstrap.js';
import { type BootnodeConfig, type P2PConfig } from '../config.js';
import { type MemPools } from '../mem_pools/interface.js';
import { DiscV5Service } from '../service/discV5_service.js';
import { LibP2PService, createLibP2PPeerId } from '../service/libp2p_service.js';
import { LibP2PService } from '../service/libp2p_service.js';
import { type PeerManager } from '../service/peer_manager.js';
import { type P2PReqRespConfig } from '../service/reqresp/config.js';
import { pingHandler, statusHandler } from '../service/reqresp/handlers.js';
Expand Down Expand Up @@ -102,7 +104,7 @@ export async function createTestLibP2PService(
port: number = 0,
peerId?: PeerId,
) {
peerId = peerId ?? (await createLibP2PPeerId());
peerId = peerId ?? (await createSecp256k1PeerId());
const config = {
tcpAnnounceAddress: `127.0.0.1:${port}`,
udpAnnounceAddress: `127.0.0.1:${port}`,
Expand Down Expand Up @@ -231,6 +233,8 @@ export function createBootstrapNodeConfig(privateKey: string, port: number): Boo
peerIdPrivateKey: privateKey,
minPeerCount: 10,
maxPeerCount: 100,
dataDirectory: undefined,
dataStoreMapSizeKB: 0,
};
}

Expand All @@ -247,14 +251,16 @@ export async function createBootstrapNode(
port: number,
telemetry: TelemetryClient = new NoopTelemetryClient(),
): Promise<BootstrapNode> {
const peerId = await createLibP2PPeerId();
const peerId = await createSecp256k1PeerId();
const config = createBootstrapNodeConfig(Buffer.from(peerId.privateKey!).toString('hex'), port);

return startBootstrapNode(config, telemetry);
}

async function startBootstrapNode(config: BootnodeConfig, telemetry: TelemetryClient) {
const bootstrapNode = new BootstrapNode(telemetry);
// Open an ephemeral store that will only exist in memory
const store = openTmpStore(true);
const bootstrapNode = new BootstrapNode(store, telemetry);
await bootstrapNode.start(config);
return bootstrapNode;
}
Loading
Loading