1
1
import Semaphore from 'semaphore-async-await'
2
2
import { Block , BlockData , BlockHeader } from '@ethereumjs/block'
3
3
import Common , { Chain , ConsensusAlgorithm , ConsensusType , Hardfork } from '@ethereumjs/common'
4
- import { toBuffer } from 'ethereumjs-util'
5
4
import { DBManager } from './db/manager'
6
5
import { DBOp , DBSetBlockOrHeader , DBSetTD , DBSetHashToNumber , DBSaveLookups } from './db/helpers'
7
6
import { DBTarget } from './db/operation'
@@ -215,12 +214,6 @@ export default class Blockchain implements BlockchainInterface {
215
214
* {@link BlockchainOptions}.
216
215
*/
217
216
protected constructor ( opts : BlockchainOptions = { } ) {
218
- // Throw on chain or hardfork options removed in latest major release to
219
- // prevent implicit chain setup on a wrong chain
220
- if ( 'chain' in opts || 'hardfork' in opts ) {
221
- throw new Error ( 'Chain/hardfork options are not allowed any more on initialization' )
222
- }
223
-
224
217
if ( opts . common ) {
225
218
this . _common = opts . common
226
219
} else {
@@ -328,7 +321,7 @@ export default class Blockchain implements BlockchainInterface {
328
321
} else {
329
322
stateRoot = await genesisStateRoot ( this . genesisState ( ) )
330
323
}
331
- genesisBlock = this . genesisBlock ( stateRoot )
324
+ genesisBlock = this . createGenesisBlock ( stateRoot )
332
325
}
333
326
334
327
// If the DB has a genesis block, then verify that the genesis block in the
@@ -726,11 +719,7 @@ export default class Blockchain implements BlockchainInterface {
726
719
async getIteratorHead ( name = 'vm' ) : Promise < Block > {
727
720
return await this . runWithLock < Block > ( async ( ) => {
728
721
// if the head is not found return the genesis hash
729
- const hash = this . _heads [ name ] ?? this . _genesisBlock ?. hash ( )
730
- if ( ! hash ) {
731
- throw new Error ( 'No head found.' )
732
- }
733
-
722
+ const hash = this . _heads [ name ] ?? this . genesisBlock . hash ( )
734
723
const block = await this . _getBlock ( hash )
735
724
return block
736
725
} )
@@ -750,11 +739,8 @@ export default class Blockchain implements BlockchainInterface {
750
739
async getHead ( name = 'vm' ) : Promise < Block > {
751
740
return await this . runWithLock < Block > ( async ( ) => {
752
741
// if the head is not found return the headHeader
753
- const hash = this . _heads [ name ] || this . _headBlockHash
754
- if ( ! hash ) {
755
- throw new Error ( 'No head found.' )
756
- }
757
-
742
+ const hash = this . _heads [ name ] ?? this . _headBlockHash
743
+ if ( ! hash ) throw new Error ( 'No head found.' )
758
744
const block = await this . _getBlock ( hash )
759
745
return block
760
746
} )
@@ -765,9 +751,7 @@ export default class Blockchain implements BlockchainInterface {
765
751
*/
766
752
async getCanonicalHeadHeader ( ) : Promise < BlockHeader > {
767
753
return await this . runWithLock < BlockHeader > ( async ( ) => {
768
- if ( ! this . _headHeaderHash ) {
769
- throw new Error ( 'No head header set' )
770
- }
754
+ if ( ! this . _headHeaderHash ) throw new Error ( 'No head header set' )
771
755
const block = await this . _getBlock ( this . _headHeaderHash )
772
756
return block . header
773
757
} )
@@ -778,10 +762,7 @@ export default class Blockchain implements BlockchainInterface {
778
762
*/
779
763
async getCanonicalHeadBlock ( ) : Promise < Block > {
780
764
return this . runWithLock < Block > ( async ( ) => {
781
- if ( ! this . _headBlockHash ) {
782
- throw new Error ( 'No head block set' )
783
- }
784
-
765
+ if ( ! this . _headBlockHash ) throw new Error ( 'No head block set' )
785
766
const block = this . _getBlock ( this . _headBlockHash )
786
767
return block
787
768
} )
@@ -1183,12 +1164,7 @@ export default class Blockchain implements BlockchainInterface {
1183
1164
*/
1184
1165
private async _iterator ( name : string , onBlock : OnBlock , maxBlocks ?: number ) : Promise < number > {
1185
1166
return await this . runWithLock < number > ( async ( ) : Promise < number > => {
1186
- const headHash = this . _heads [ name ] ?? this . _genesisBlock ?. hash ( )
1187
- let lastBlock : Block | undefined
1188
-
1189
- if ( ! headHash ) {
1190
- return 0
1191
- }
1167
+ const headHash = this . _heads [ name ] ?? this . genesisBlock . hash ( )
1192
1168
1193
1169
if ( maxBlocks && maxBlocks < 0 ) {
1194
1170
throw 'If maxBlocks is provided, it has to be a non-negative number'
@@ -1197,6 +1173,7 @@ export default class Blockchain implements BlockchainInterface {
1197
1173
const headBlockNumber = await this . dbManager . hashToNumber ( headHash )
1198
1174
let nextBlockNumber = headBlockNumber + BigInt ( 1 )
1199
1175
let blocksRanCounter = 0
1176
+ let lastBlock : Block | undefined
1200
1177
1201
1178
while ( maxBlocks !== blocksRanCounter ) {
1202
1179
try {
@@ -1205,7 +1182,7 @@ export default class Blockchain implements BlockchainInterface {
1205
1182
const reorg = lastBlock ? lastBlock . hash ( ) . equals ( nextBlock . header . parentHash ) : false
1206
1183
lastBlock = nextBlock
1207
1184
await onBlock ( nextBlock , reorg )
1208
- nextBlockNumber += BigInt ( 1 )
1185
+ nextBlockNumber ++
1209
1186
blocksRanCounter ++
1210
1187
} catch ( error : any ) {
1211
1188
if ( error . type === 'NotFoundError' ) {
@@ -1241,10 +1218,7 @@ export default class Blockchain implements BlockchainInterface {
1241
1218
* @param newHeader - the new block header
1242
1219
*/
1243
1220
private async findCommonAncestor ( newHeader : BlockHeader ) {
1244
- if ( ! this . _headHeaderHash ) {
1245
- throw new Error ( 'No head header set' )
1246
- }
1247
-
1221
+ if ( ! this . _headHeaderHash ) throw new Error ( 'No head header set' )
1248
1222
const ancestorHeaders = new Set < BlockHeader > ( )
1249
1223
1250
1224
let { header } = await this . _getBlock ( this . _headHeaderHash )
@@ -1303,20 +1277,20 @@ export default class Blockchain implements BlockchainInterface {
1303
1277
// instance, make the VM run "older" (i.e. lower number blocks than last
1304
1278
// executed block) blocks to verify the chain up to the current, actual,
1305
1279
// head.
1306
- Object . keys ( this . _heads ) . forEach ( ( name ) => {
1280
+ for ( const name of Object . keys ( this . _heads ) ) {
1307
1281
if ( this . _heads [ name ] . equals ( < Buffer > hash ) ) {
1308
1282
// explicitly cast as Buffer: it is not possible that `hash` is false
1309
1283
// here, but TypeScript does not understand this.
1310
1284
this . _heads [ name ] = headHash
1311
1285
}
1312
- } )
1286
+ }
1313
1287
1314
1288
// reset stale headBlock to current canonical
1315
1289
if ( this . _headBlockHash ?. equals ( hash ) ) {
1316
1290
this . _headBlockHash = headHash
1317
1291
}
1318
1292
1319
- blockNumber += BigInt ( 1 )
1293
+ blockNumber ++
1320
1294
1321
1295
hash = await this . safeNumberToHash ( blockNumber )
1322
1296
}
@@ -1368,11 +1342,11 @@ export default class Blockchain implements BlockchainInterface {
1368
1342
1369
1343
// mark each key `_heads` which is currently set to the hash in the DB as
1370
1344
// stale to overwrite this later.
1371
- Object . keys ( this . _heads ) . forEach ( ( name ) => {
1345
+ for ( const name of Object . keys ( this . _heads ) ) {
1372
1346
if ( staleHash && this . _heads [ name ] . equals ( staleHash ) ) {
1373
1347
staleHeads . push ( name )
1374
1348
}
1375
- } )
1349
+ }
1376
1350
// flag stale headBlock for reset
1377
1351
if ( staleHash && this . _headBlockHash ?. equals ( staleHash ) ) {
1378
1352
staleHeadBlock = true
@@ -1390,9 +1364,9 @@ export default class Blockchain implements BlockchainInterface {
1390
1364
}
1391
1365
// the stale hash is equal to the blockHash set stale heads to last
1392
1366
// previously valid canonical block
1393
- staleHeads . forEach ( ( name : string ) => {
1367
+ for ( const name of staleHeads ) {
1394
1368
this . _heads [ name ] = currentCanonicalHash
1395
- } )
1369
+ }
1396
1370
// set stale headBlock to last previously valid canonical block
1397
1371
if ( staleHeadBlock ) {
1398
1372
this . _headBlockHash = currentCanonicalHash
@@ -1463,37 +1437,27 @@ export default class Blockchain implements BlockchainInterface {
1463
1437
}
1464
1438
1465
1439
/**
1466
- * Returns the genesis {@link Block} for the blockchain.
1467
- * @param stateRoot When initializing the block, pass the genesis stateRoot.
1468
- * After the blockchain is initialized, this parameter is not used
1469
- * as the cached genesis block is returned.
1440
+ * The genesis {@link Block} for the blockchain.
1470
1441
*/
1471
- genesisBlock ( stateRoot ?: Buffer ) : Block {
1472
- if ( this . _genesisBlock ) {
1473
- return this . _genesisBlock
1474
- }
1475
-
1476
- if ( ! stateRoot ) throw new Error ( 'stateRoot required for genesis block creation' )
1442
+ get genesisBlock ( ) : Block {
1443
+ if ( ! this . _genesisBlock ) throw new Error ( 'genesis block not set (init may not be finished)' )
1444
+ return this . _genesisBlock
1445
+ }
1477
1446
1447
+ /**
1448
+ * Creates a genesis {@link Block} for the blockchain with params from {@link Common.genesis}
1449
+ * @param stateRoot The genesis stateRoot
1450
+ */
1451
+ createGenesisBlock ( stateRoot : Buffer ) : Block {
1478
1452
const common = this . _common . copy ( )
1479
1453
common . setHardforkByBlockNumber ( 0 )
1480
1454
1481
- const { gasLimit, timestamp, difficulty, extraData, nonce, baseFeePerGas } = common . genesis ( )
1482
-
1483
1455
const header : BlockData [ 'header' ] = {
1456
+ ...common . genesis ( ) ,
1484
1457
number : 0 ,
1485
- gasLimit : BigInt ( gasLimit ) ,
1486
- timestamp : BigInt ( timestamp ?? 0 ) ,
1487
- difficulty : BigInt ( difficulty ) ,
1488
- extraData : toBuffer ( extraData ) ,
1489
- nonce : toBuffer ( nonce ) ,
1490
1458
stateRoot,
1491
1459
}
1492
1460
1493
- if ( baseFeePerGas !== undefined && common . gteHardfork ( Hardfork . London ) ) {
1494
- header . baseFeePerGas = BigInt ( baseFeePerGas )
1495
- }
1496
-
1497
1461
return Block . fromBlockData ( { header } , { common } )
1498
1462
}
1499
1463
0 commit comments