@@ -17,13 +17,12 @@ import {
1717 CLIQUE_NONCE_AUTH ,
1818 CLIQUE_NONCE_DROP ,
1919} from './clique'
20-
21- const debug = createDebugLogger ( 'blockchain:clique' )
22-
2320// eslint-disable-next-line implicit-dependencies/no-implicit
2421import type { LevelUp } from 'levelup'
2522const level = require ( 'level-mem' )
2623
24+ const debug = createDebugLogger ( 'blockchain:clique' )
25+
2726type OnBlock = ( block : Block , reorg : boolean ) => Promise < void > | void
2827
2928export interface BlockchainInterface {
@@ -112,7 +111,7 @@ export interface BlockchainOptions {
112111 validateBlocks ?: boolean
113112
114113 /**
115- * The blockchain only initializes succesfully if it has a genesis block. If
114+ * The blockchain only initializes successfully if it has a genesis block. If
116115 * there is no block available in the DB and a `genesisBlock` is provided,
117116 * then the provided `genesisBlock` will be used as genesis. If no block is
118117 * present in the DB and no block is provided, then the genesis block as
@@ -130,18 +129,25 @@ export default class Blockchain implements BlockchainInterface {
130129
131130 private _genesis ?: Buffer // the genesis hash of this blockchain
132131
133- // The following two heads and the heads stored within the `_heads` always point
134- // to a hash in the canonical chain and never to a stale hash.
135- // With the exception of `_headHeaderHash` this does not necessarily need to be
136- // the hash with the highest total difficulty.
137- private _headBlockHash ?: Buffer // the hash of the current head block
138- private _headHeaderHash ?: Buffer // the hash of the current head header
139- // A Map which stores the head of each key (for instance the "vm" key) which is
140- // updated along a {@link Blockchain.iterator } method run and can be used to (re)run
141- // non-verified blocks (for instance in the VM).
132+ /**
133+ * The following two heads and the heads stored within the `_heads` always point
134+ * to a hash in the canonical chain and never to a stale hash.
135+ * With the exception of `_headHeaderHash` this does not necessarily need to be
136+ * the hash with the highest total difficulty.
137+ */
138+ /** The hash of the current head block */
139+ private _headBlockHash ?: Buffer
140+ /** The hash of the current head header */
141+ private _headHeaderHash ?: Buffer
142+
143+ /**
144+ * A Map which stores the head of each key (for instance the "vm" key) which is
145+ * updated along a {@link Blockchain.iterator} method run and can be used to (re)run
146+ * non-verified blocks (for instance in the VM).
147+ */
142148 private _heads : { [ key : string ] : Buffer }
143149
144- public initPromise : Promise < void >
150+ protected _isInitialized = false
145151 private _lock : Semaphore
146152
147153 private _common : Common
@@ -207,9 +213,7 @@ export default class Blockchain implements BlockchainInterface {
207213
208214 public static async create ( opts : BlockchainOptions = { } ) {
209215 const blockchain = new Blockchain ( opts )
210- await blockchain . initPromise ! . catch ( ( e ) => {
211- throw e
212- } )
216+ await blockchain . _init ( opts . genesisBlock )
213217 return blockchain
214218 }
215219
@@ -233,16 +237,16 @@ export default class Blockchain implements BlockchainInterface {
233237 }
234238
235239 /**
236- * Creates new Blockchain object
240+ * Creates new Blockchain object.
237241 *
238- * @deprecated - The direct usage of this constructor is discouraged since
242+ * @deprecated The direct usage of this constructor is discouraged since
239243 * non-finalized async initialization might lead to side effects. Please
240244 * use the async {@link Blockchain.create} constructor instead (same API).
241245 *
242- * @param opts - An object with the options that this constructor takes. See
246+ * @param opts An object with the options that this constructor takes. See
243247 * {@link BlockchainOptions}.
244248 */
245- constructor ( opts : BlockchainOptions = { } ) {
249+ protected constructor ( opts : BlockchainOptions = { } ) {
246250 // Throw on chain or hardfork options removed in latest major release to
247251 // prevent implicit chain setup on a wrong chain
248252 if ( 'chain' in opts || 'hardfork' in opts ) {
@@ -291,9 +295,6 @@ export default class Blockchain implements BlockchainInterface {
291295 if ( opts . genesisBlock && ! opts . genesisBlock . isGenesis ( ) ) {
292296 throw 'supplied block is not a genesis block'
293297 }
294-
295- // eslint-disable-next-line @typescript-eslint/no-floating-promises
296- this . initPromise = this . _init ( opts . genesisBlock )
297298 }
298299
299300 /**
@@ -329,13 +330,14 @@ export default class Blockchain implements BlockchainInterface {
329330 }
330331
331332 /**
332- * This method is called in the constructor and either sets up the DB or reads
333+ * This method is called in { @link Blockchain.create} and either sets up the DB or reads
333334 * values from the DB and makes these available to the consumers of
334335 * Blockchain.
335336 *
336337 * @hidden
337338 */
338339 private async _init ( genesisBlock ?: Block ) : Promise < void > {
340+ if ( this . _isInitialized ) return
339341 let dbGenesisBlock
340342 try {
341343 const genesisHash = await this . dbManager . numberToHash ( BigInt ( 0 ) )
@@ -421,23 +423,14 @@ export default class Blockchain implements BlockchainInterface {
421423 }
422424 this . _headBlockHash = genesisHash
423425 }
426+
424427 if ( this . _hardforkByHeadBlockNumber ) {
425428 const latestHeader = await this . _getHeader ( this . _headHeaderHash )
426429 const td = await this . getTotalDifficulty ( this . _headHeaderHash )
427430 this . _common . setHardforkByBlockNumber ( latestHeader . number , td )
428431 }
429- }
430432
431- /**
432- * Perform the `action` function after we have initialized this module and
433- * have acquired a lock
434- * @param action - the action function to run after initializing and acquiring
435- * a lock
436- * @hidden
437- */
438- private async initAndLock < T > ( action : ( ) => Promise < T > ) : Promise < T > {
439- await this . initPromise
440- return await this . runWithLock ( action )
433+ this . _isInitialized = true
441434 }
442435
443436 /**
@@ -763,7 +756,7 @@ export default class Blockchain implements BlockchainInterface {
763756 * @param name - Optional name of the iterator head (default: 'vm')
764757 */
765758 async getIteratorHead ( name = 'vm' ) : Promise < Block > {
766- return await this . initAndLock < Block > ( async ( ) => {
759+ return await this . runWithLock < Block > ( async ( ) => {
767760 // if the head is not found return the genesis hash
768761 const hash = this . _heads [ name ] || this . _genesis
769762 if ( ! hash ) {
@@ -787,7 +780,7 @@ export default class Blockchain implements BlockchainInterface {
787780 * on a first run)
788781 */
789782 async getHead ( name = 'vm' ) : Promise < Block > {
790- return await this . initAndLock < Block > ( async ( ) => {
783+ return await this . runWithLock < Block > ( async ( ) => {
791784 // if the head is not found return the headHeader
792785 const hash = this . _heads [ name ] || this . _headBlockHash
793786 if ( ! hash ) {
@@ -803,7 +796,7 @@ export default class Blockchain implements BlockchainInterface {
803796 * Returns the latest header in the canonical chain.
804797 */
805798 async getLatestHeader ( ) : Promise < BlockHeader > {
806- return await this . initAndLock < BlockHeader > ( async ( ) => {
799+ return await this . runWithLock < BlockHeader > ( async ( ) => {
807800 if ( ! this . _headHeaderHash ) {
808801 throw new Error ( 'No head header set' )
809802 }
@@ -816,7 +809,7 @@ export default class Blockchain implements BlockchainInterface {
816809 * Returns the latest full block in the canonical chain.
817810 */
818811 async getLatestBlock ( ) : Promise < Block > {
819- return this . initAndLock < Block > ( async ( ) => {
812+ return this . runWithLock < Block > ( async ( ) => {
820813 if ( ! this . _headBlockHash ) {
821814 throw new Error ( 'No head block set' )
822815 }
@@ -836,7 +829,6 @@ export default class Blockchain implements BlockchainInterface {
836829 * @param blocks - The blocks to be added to the blockchain
837830 */
838831 async putBlocks ( blocks : Block [ ] ) {
839- await this . initPromise
840832 for ( let i = 0 ; i < blocks . length ; i ++ ) {
841833 await this . putBlock ( blocks [ i ] )
842834 }
@@ -851,7 +843,6 @@ export default class Blockchain implements BlockchainInterface {
851843 * @param block - The block to be added to the blockchain
852844 */
853845 async putBlock ( block : Block ) {
854- await this . initPromise
855846 await this . _putBlockOrHeader ( block )
856847 }
857848
@@ -865,7 +856,6 @@ export default class Blockchain implements BlockchainInterface {
865856 * @param headers - The headers to be added to the blockchain
866857 */
867858 async putHeaders ( headers : Array < any > ) {
868- await this . initPromise
869859 for ( let i = 0 ; i < headers . length ; i ++ ) {
870860 await this . putHeader ( headers [ i ] )
871861 }
@@ -880,7 +870,6 @@ export default class Blockchain implements BlockchainInterface {
880870 * @param header - The header to be added to the blockchain
881871 */
882872 async putHeader ( header : BlockHeader ) {
883- await this . initPromise
884873 await this . _putBlockOrHeader ( header )
885874 }
886875
@@ -1061,7 +1050,6 @@ export default class Blockchain implements BlockchainInterface {
10611050 // in the `VM` if we encounter a `BLOCKHASH` opcode: then a bigint is used we
10621051 // need to then read the block from the canonical chain Q: is this safe? We
10631052 // know it is OK if we call it from the iterator... (runBlock)
1064- await this . initPromise
10651053 return await this . _getBlock ( blockId )
10661054 }
10671055
@@ -1096,7 +1084,7 @@ export default class Blockchain implements BlockchainInterface {
10961084 skip : number ,
10971085 reverse : boolean
10981086 ) : Promise < Block [ ] > {
1099- return await this . initAndLock < Block [ ] > ( async ( ) => {
1087+ return await this . runWithLock < Block [ ] > ( async ( ) => {
11001088 const blocks : Block [ ] = [ ]
11011089 let i = - 1
11021090
@@ -1133,7 +1121,7 @@ export default class Blockchain implements BlockchainInterface {
11331121 * @param hashes - Ordered array of hashes (ordered on `number`).
11341122 */
11351123 async selectNeededHashes ( hashes : Array < Buffer > ) : Promise < Buffer [ ] > {
1136- return await this . initAndLock < Buffer [ ] > ( async ( ) => {
1124+ return await this . runWithLock < Buffer [ ] > ( async ( ) => {
11371125 let max : number
11381126 let mid : number
11391127 let min : number
@@ -1178,7 +1166,6 @@ export default class Blockchain implements BlockchainInterface {
11781166 // But is this the way to go? If we know this is called from the
11791167 // iterator/runBlockchain we are safe, but if this is called from anywhere
11801168 // else then this might lead to a concurrency problem?
1181- await this . initPromise
11821169 await this . _delBlock ( blockHash )
11831170 }
11841171
@@ -1278,7 +1265,7 @@ export default class Blockchain implements BlockchainInterface {
12781265 * @hidden
12791266 */
12801267 private async _iterator ( name : string , onBlock : OnBlock , maxBlocks ?: number ) : Promise < number > {
1281- return await this . initAndLock < number > ( async ( ) : Promise < number > => {
1268+ return await this . runWithLock < number > ( async ( ) : Promise < number > => {
12821269 const headHash = this . _heads [ name ] || this . _genesis
12831270 let lastBlock : Block | undefined
12841271
@@ -1319,7 +1306,7 @@ export default class Blockchain implements BlockchainInterface {
13191306
13201307 /**
13211308 * Set header hash of a certain `tag`.
1322- * When calling the iterator, the iterator will start running the first child block after the header hash currenntly stored.
1309+ * When calling the iterator, the iterator will start running the first child block after the header hash currently stored.
13231310 * @param tag - The tag to save the headHash to
13241311 * @param headHash - The head hash to save
13251312 */
@@ -1329,14 +1316,14 @@ export default class Blockchain implements BlockchainInterface {
13291316
13301317 /**
13311318 * Set header hash of a certain `tag`.
1332- * When calling the iterator, the iterator will start running the first child block after the header hash currenntly stored.
1319+ * When calling the iterator, the iterator will start running the first child block after the header hash currently stored.
13331320 * @param tag - The tag to save the headHash to
13341321 * @param headHash - The head hash to save
13351322 *
13361323 * @deprecated use {@link Blockchain.setIteratorHead()} instead
13371324 */
13381325 async setHead ( tag : string , headHash : Buffer ) {
1339- await this . initAndLock < void > ( async ( ) => {
1326+ await this . runWithLock < void > ( async ( ) => {
13401327 this . _heads [ tag ] = headHash
13411328 await this . _saveHeads ( )
13421329 } )
0 commit comments