11import Common from '@ethereumjs/common'
22import VM from '@ethereumjs/vm'
3+ import { genPrivateKey } from '@ethereumjs/devp2p'
34import Multiaddr from 'multiaddr'
45import { getLogger , Logger } from './logging'
56import { Libp2pServer , RlpxServer } from './net/server'
67import { parseTransports } from './util'
8+ import type { LevelUp } from 'levelup'
9+ const level = require ( 'level' )
710
811export interface ConfigOptions {
912 /**
@@ -40,6 +43,13 @@ export interface ConfigOptions {
4043 */
4144 datadir ?: string
4245
46+ /**
47+ * Private key for the client.
48+ * Use return value of `await Config.getClientKey(datadir, common)`
49+ * If left blank, a random key will be generated and used.
50+ */
51+ key ?: Buffer
52+
4353 /**
4454 * Network transports ('rlpx' and/or 'libp2p')
4555 *
@@ -172,6 +182,7 @@ export class Config {
172182 public readonly vm ?: VM
173183 public readonly lightserv : boolean
174184 public readonly datadir : string
185+ public readonly key : Buffer
175186 public readonly transports : string [ ]
176187 public readonly bootnodes ?: Multiaddr [ ]
177188 public readonly multiaddrs ?: Multiaddr [ ]
@@ -199,6 +210,7 @@ export class Config {
199210 this . bootnodes = options . bootnodes
200211 this . multiaddrs = options . multiaddrs
201212 this . datadir = options . datadir ?? Config . DATADIR_DEFAULT
213+ this . key = options . key ?? genPrivateKey ( )
202214 this . rpc = options . rpc ?? Config . RPC_DEFAULT
203215 this . rpcport = options . rpcport ?? Config . RPCPORT_DEFAULT
204216 this . rpcaddr = options . rpcaddr ?? Config . RPCADDR_DEFAULT
@@ -243,25 +255,33 @@ export class Config {
243255 const bootnodes = this . bootnodes ?? this . chainCommon . bootstrapNodes ( )
244256 const dnsNetworks = options . dnsNetworks ?? this . chainCommon . dnsNetworks ( )
245257 return new RlpxServer ( { config : this , bootnodes, dnsNetworks } )
246- } else {
247- // t.name === 'libp2p'
258+ } else if ( t . name === 'libp2p' ) {
248259 const multiaddrs = this . multiaddrs
249260 const bootnodes = this . bootnodes
250261 return new Libp2pServer ( { config : this , multiaddrs, bootnodes } )
262+ } else {
263+ throw new Error ( `unknown transport: ${ t . name } ` )
251264 }
252265 } )
253266 }
254267 }
255268
269+ /**
270+ * Returns the network directory for the chain.
271+ */
272+ getNetworkDirectory ( ) : string {
273+ const networkDirName = this . chainCommon . chainName ( )
274+ const dataDir = `${ this . datadir } /${ networkDirName } `
275+ return dataDir
276+ }
277+
256278 /**
257279 * Returns the directory for storing the client chain data
258280 * based on syncmode and selected chain (subdirectory of 'datadir')
259281 */
260282 getChainDataDirectory ( ) : string {
261- const networkDirName = this . chainCommon . chainName ( )
262283 const chainDataDirName = this . syncmode === 'light' ? 'lightchain' : 'chain'
263-
264- const dataDir = `${ this . datadir } /${ networkDirName } /${ chainDataDirName } `
284+ const dataDir = `${ this . getNetworkDirectory ( ) } /${ chainDataDirName } `
265285 return dataDir
266286 }
267287
@@ -270,10 +290,36 @@ export class Config {
270290 * based selected chain (subdirectory of 'datadir')
271291 */
272292 getStateDataDirectory ( ) : string {
273- const networkDirName = this . chainCommon . chainName ( )
293+ return `${ this . getNetworkDirectory ( ) } /state`
294+ }
274295
275- const dataDir = `${ this . datadir } /${ networkDirName } /state`
276- return dataDir
296+ /**
297+ * Returns the config level db.
298+ */
299+ static getConfigDB ( networkDir : string ) : LevelUp {
300+ const db = level ( `${ networkDir } /config` as any )
301+ return db
302+ }
303+
304+ /**
305+ * Gets the client private key from the config db.
306+ */
307+ static async getClientKey ( datadir : string , common : Common ) {
308+ const networkDir = `${ datadir } /${ common . chainName ( ) } `
309+ const db = this . getConfigDB ( networkDir )
310+ const encodingOpts = { keyEncoding : 'utf8' , valueEncoding : 'binary' }
311+ const dbKey = 'config:client_key'
312+ let key
313+ try {
314+ key = await db . get ( dbKey , encodingOpts )
315+ } catch ( error ) {
316+ if ( error . type === 'NotFoundError' ) {
317+ // generate and save a new key
318+ key = genPrivateKey ( )
319+ await db . put ( dbKey , key , encodingOpts )
320+ }
321+ }
322+ return key
277323 }
278324
279325 /**
@@ -294,11 +340,4 @@ export class Config {
294340 if ( option !== undefined ) return option
295341 return this . chainCommon . chainName ( ) === 'mainnet'
296342 }
297-
298- getNetworkDir ( ) : string {
299- const networkDirName = this . common . chainName ( )
300- const dataDir = `${ this . datadir } /${ networkDirName } `
301-
302- return dataDir
303- }
304343}
0 commit comments