Skip to content

Commit 4f95bd5

Browse files
feat: static enr (#372)
1 parent 2397ea2 commit 4f95bd5

6 files changed

Lines changed: 62 additions & 6 deletions

File tree

packages/cli/src/cmds/node/handler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export async function nodeHandler(args: IGlobalArgs): Promise<void> {
9595
peerId,
9696
metricsOptions: params.metrics,
9797
version,
98+
retainPeerId: params.p2p.retainPeerId,
9899
});
99100

100101
await node.start();
@@ -127,6 +128,7 @@ export async function getNodeConfigFromArgs(args: IGlobalArgs): Promise<{
127128
enrPort: entries.get("p2p.enrPort"),
128129
bootEnrs: entries.get("p2p.bootEnrs"),
129130
retainPeerId: entries.get("p2p.retainPeerId"),
131+
enrSeq: entries.get("p2p.enrSeq"),
130132
},
131133
api: {
132134
address: entries.get("api.address"),

packages/cli/src/cmds/node/initPeerIdAndEnr.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,27 @@ export function overwriteEnrWithCliArgs(
1919
enr: SignableENR,
2020
args: IGlobalArgs
2121
): void {
22-
const [host, enrPort] = [args["p2p.enrHost"], args["p2p.enrPort"]];
23-
enr.ip = host ?? defaultP2POptions.enrHost;
24-
enr.tcp = enrPort ?? defaultP2POptions.enrPort;
25-
enr.udp = enrPort ?? defaultP2POptions.enrPort;
22+
const [host, enrPort, enrSeq] = [args["p2p.enrHost"], args["p2p.enrPort"], args["p2p.enrSeq"]];
23+
24+
const newHost = host ?? defaultP2POptions.enrHost;
25+
// Normalize port to a number to avoid accidental mismatches
26+
const newPort =
27+
enrPort !== undefined && enrPort !== null
28+
? Number(enrPort)
29+
: defaultP2POptions.enrPort;
30+
31+
// Only update when a value actually changes to avoid bumping the ENR seq
32+
if (enr.ip !== newHost) {
33+
enr.ip = newHost;
34+
}
35+
if (enr.tcp !== newPort) {
36+
enr.tcp = newPort;
37+
}
38+
if (enr.udp !== newPort) {
39+
enr.udp = newPort;
40+
}
41+
42+
enr.seq = enrSeq ? BigInt(enrSeq) : BigInt(defaultP2POptions.enrSeq)
2643
}
2744

2845
export async function initPeerIdAndEnr(

packages/cli/src/options/bundlerOptions/network.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface INetworkArgs {
99
"p2p.enrPort": number;
1010
"p2p.bootEnrs": string[];
1111
"p2p.retainPeerId": boolean;
12+
"p2p.enrSeq": number;
1213
}
1314

1415
export function parseArgs(args: INetworkArgs): IBundlerOptions["p2p"] {
@@ -19,6 +20,7 @@ export function parseArgs(args: INetworkArgs): IBundlerOptions["p2p"] {
1920
enrPort: args["p2p.enrPort"],
2021
bootEnrs: args["p2p.bootEnrs"],
2122
retainPeerId: args["p2p.retainPeerId"],
23+
enrSeq: args["p2p.enrSeq"]
2224
};
2325
}
2426

@@ -65,4 +67,11 @@ export const options: ICliCommandOptions<INetworkArgs> = {
6567
group: "p2p",
6668
demandOption: false,
6769
},
70+
"p2p.enrSeq": {
71+
type: "number",
72+
description: "P2P sequence for enr",
73+
default: defaultP2POptions.enrSeq,
74+
group: "p2p",
75+
demandOption: false,
76+
}
6877
};

packages/node/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export interface BundlerNodeInitOptions {
4545
bundlingMode: BundlingMode;
4646
metricsOptions: MetricsOptions;
4747
version: SkandhaVersion;
48+
retainPeerId?: boolean;
4849
}
4950

5051
export class BundlerNode {
@@ -72,6 +73,7 @@ export class BundlerNode {
7273
bundlingMode,
7374
metricsOptions,
7475
version,
76+
retainPeerId,
7577
} = opts;
7678
let { peerId } = opts;
7779

@@ -121,6 +123,8 @@ export class BundlerNode {
121123
peerStoreDir: nodeOptions.network.dataDir,
122124
executor, // ok: is null at the moment
123125
metrics: metrics?.chains || null,
126+
dataDir: nodeOptions.network.dataDir,
127+
retainPeerId: retainPeerId,
124128
});
125129

126130
const syncService = new SyncService({

packages/node/src/network/network.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { getCoreTopics } from "./gossip/topic.js";
2525
import { Discv5Worker } from "./discv5/index.js";
2626
import { NetworkProcessor } from "./processor/index.js";
2727
import { pooledUserOpHashes, pooledUserOpsByHash } from "./reqresp/index.js";
28+
import fs from "node:fs";
29+
import path from "node:path";
2830

2931
type NetworkModules = {
3032
libp2p: Libp2p;
@@ -47,6 +49,8 @@ export type NetworkInitOptions = {
4749
executor: Executor;
4850
peerStoreDir?: string;
4951
metrics: AllChainsMetrics | null;
52+
dataDir?: string;
53+
retainPeerId?: boolean;
5054
};
5155

5256
export class Network implements INetwork {
@@ -66,6 +70,8 @@ export class Network implements INetwork {
6670

6771
relayersConfig: Config;
6872
subscribedMempools = new Set<string>();
73+
dataDir?: string;
74+
retainPeerId?: boolean;
6975

7076
constructor(opts: NetworkModules) {
7177
const {
@@ -97,7 +103,7 @@ export class Network implements INetwork {
97103
}
98104

99105
static async init(options: NetworkInitOptions): Promise<Network> {
100-
const { peerId, relayersConfig, executor, metrics } = options;
106+
const { peerId, relayersConfig, executor, metrics, dataDir, retainPeerId } = options;
101107
const libp2p = await createNodeJsLibp2p(peerId, options.opts, {
102108
peerStoreDir: options.peerStoreDir,
103109
});
@@ -150,7 +156,7 @@ export class Network implements INetwork {
150156
};
151157
const peerManager = new PeerManager(peerManagerModules, options.opts);
152158

153-
return new Network({
159+
const network = new Network({
154160
libp2p,
155161
gossip,
156162
reqResp,
@@ -163,6 +169,9 @@ export class Network implements INetwork {
163169
executor,
164170
metrics,
165171
});
172+
network.dataDir = dataDir;
173+
network.retainPeerId = retainPeerId;
174+
return network;
166175
}
167176

168177
/** Shutdown the bundler node */
@@ -185,6 +194,19 @@ export class Network implements INetwork {
185194
const setEnrValue = discv5?.setEnrValue.bind(discv5);
186195
this.metadata.start(setEnrValue);
187196

197+
// Save ENR after metadata updates if retainPeerId is enabled
198+
if (this.retainPeerId && this.dataDir) {
199+
try {
200+
const enr = await this.getEnr();
201+
if (enr) {
202+
const enrFile = path.join(this.dataDir, "enr");
203+
fs.writeFileSync(enrFile, enr.encodeTxt(), { mode: 0o600 });
204+
}
205+
} catch (error) {
206+
this.logger.warn("Failed to save ENR after metadata update", error);
207+
}
208+
}
209+
188210
await this.gossip.start();
189211

190212
const multiaddresses = this.libp2p

packages/types/src/options/network.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export type P2POptions = {
55
enrPort: number;
66
bootEnrs: string[];
77
retainPeerId: boolean;
8+
enrSeq: number;
89
};
910

1011
export const defaultP2POptions: P2POptions = {
@@ -14,4 +15,5 @@ export const defaultP2POptions: P2POptions = {
1415
enrPort: 4337,
1516
bootEnrs: [],
1617
retainPeerId: true,
18+
enrSeq: 0,
1719
};

0 commit comments

Comments
 (0)