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  /** 
0 commit comments