Skip to content

Commit

Permalink
feat(p2p): persist node private p2p keys (#10324)
Browse files Browse the repository at this point in the history
  • Loading branch information
Maddiaa0 authored Dec 3, 2024
1 parent fcbff0d commit 1c32eda
Show file tree
Hide file tree
Showing 24 changed files with 194 additions and 108 deletions.
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,
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 } 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

0 comments on commit 1c32eda

Please sign in to comment.