@@ -224,7 +224,12 @@ class BlockchainImpl(
224
224
// There is always only one writer thread (ensured by actor), but can by many readers (api calls)
225
225
// to ensure visibility of writes, needs to be volatile or atomic ref
226
226
private val bestKnownBlockAndLatestCheckpoint : AtomicReference [BestBlockLatestCheckpointNumbers ] =
227
- new AtomicReference (BestBlockLatestCheckpointNumbers (BigInt (0 ), BigInt (0 )))
227
+ new AtomicReference (
228
+ BestBlockLatestCheckpointNumbers (
229
+ appStateStorage.getBestBlockNumber(),
230
+ appStateStorage.getLatestCheckpointBlockNumber()
231
+ )
232
+ )
228
233
229
234
override def getBlockHeaderByHash (hash : ByteString ): Option [BlockHeader ] =
230
235
blockHeadersStorage.get(hash)
@@ -246,22 +251,15 @@ class BlockchainImpl(
246
251
bestSavedBlockNumber,
247
252
bestKnownBlockNumber
248
253
)
249
- if (bestKnownBlockNumber > bestSavedBlockNumber)
250
- bestKnownBlockNumber
251
- else
252
- bestSavedBlockNumber
253
- }
254
254
255
- override def getLatestCheckpointBlockNumber (): BigInt = {
256
- val latestCheckpointNumberInStorage = appStateStorage.getLatestCheckpointBlockNumber()
257
- // The latest checkpoint number is firstly saved in memory and then persisted to the storage only when it's time to persist cache.
258
- // The latest checkpoint number in memory can be bigger than the number in storage because the cache wasn't persisted yet
259
- if (bestKnownBlockAndLatestCheckpoint.get().latestCheckpointNumber > latestCheckpointNumberInStorage)
260
- bestKnownBlockAndLatestCheckpoint.get().latestCheckpointNumber
261
- else
262
- latestCheckpointNumberInStorage
255
+ // The cached best block number should always be more up-to-date than the one on disk, we are keeping access to disk
256
+ // above only for logging purposes
257
+ bestKnownBlockNumber
263
258
}
264
259
260
+ override def getLatestCheckpointBlockNumber (): BigInt =
261
+ bestKnownBlockAndLatestCheckpoint.get().latestCheckpointNumber
262
+
265
263
override def getBestBlock (): Block = {
266
264
val bestBlockNumber = getBestBlockNumber()
267
265
log.debug(" Trying to get best block with number {}" , bestBlockNumber)
@@ -313,10 +311,6 @@ class BlockchainImpl(
313
311
.and(storeChainWeight(block.header.hash, weight))
314
312
.commit()
315
313
316
- // not transactional part
317
- // the best blocks data will be persisted only when the cache will be persisted
318
- stateStorage.onBlockSave(block.header.number, appStateStorage.getBestBlockNumber())(persistBestBlocksData)
319
-
320
314
if (saveAsBestBlock && block.hasCheckpoint) {
321
315
log.debug(
322
316
" New best known block block number - {}, new best checkpoint number - {}" ,
@@ -331,6 +325,10 @@ class BlockchainImpl(
331
325
)
332
326
saveBestKnownBlock(block.header.number)
333
327
}
328
+
329
+ // not transactional part
330
+ // the best blocks data will be persisted only when the cache will be persisted
331
+ stateStorage.onBlockSave(block.header.number, appStateStorage.getBestBlockNumber())(persistBestBlocksData)
334
332
}
335
333
336
334
override def storeBlockHeader (blockHeader : BlockHeader ): DataSourceBatchUpdate = {
@@ -388,87 +386,77 @@ class BlockchainImpl(
388
386
blockNumberMappingStorage.remove(number)
389
387
}
390
388
391
- // scalastyle:off method.length
392
389
override def removeBlock (blockHash : ByteString , withState : Boolean ): Unit = {
393
- val maybeBlockHeader = getBlockHeaderByHash(blockHash)
394
-
395
- log.debug(
396
- " Trying to remove block with hash {} and number {}" ,
397
- ByteStringUtils .hash2string(blockHash),
398
- maybeBlockHeader.map(_.number)
399
- )
390
+ val maybeBlock = getBlockByHash(blockHash)
400
391
401
- val maybeTxList = getBlockBodyByHash(blockHash).map(_.transactionList)
402
- val bestBlocks = bestKnownBlockAndLatestCheckpoint.get()
403
- // as we are decreasing block numbers in memory more often than in storage,
404
- // we can't use here getBestBlockNumber / getLatestCheckpointBlockNumber
405
- val bestBlockNumber =
406
- if (bestBlocks.bestBlockNumber != 0 ) bestBlocks.bestBlockNumber else appStateStorage.getBestBlockNumber()
407
- val latestCheckpointNumber = {
408
- if (bestBlocks.latestCheckpointNumber != 0 ) bestBlocks.latestCheckpointNumber
409
- else appStateStorage.getLatestCheckpointBlockNumber()
392
+ maybeBlock match {
393
+ case Some (block) => removeBlock(block, withState)
394
+ case None =>
395
+ log.warn(s " Attempted removing block with hash $blockHash that we don't have " )
410
396
}
397
+ }
411
398
412
- val blockNumberMappingUpdates = {
413
- maybeBlockHeader.fold(blockNumberMappingStorage.emptyBatchUpdate)(h =>
414
- if (getHashByBlockNumber(h.number).contains(blockHash))
415
- removeBlockNumberMapping(h.number)
416
- else blockNumberMappingStorage.emptyBatchUpdate
417
- )
418
- }
399
+ // scalastyle:off method.length
400
+ private def removeBlock (block : Block , withState : Boolean ): Unit = {
401
+ val blockHash = block.hash
419
402
420
- val (checkpointUpdates, prevCheckpointNumber): (DataSourceBatchUpdate , Option [BigInt ]) = maybeBlockHeader match {
421
- case Some (header) =>
422
- if (header.hasCheckpoint && header.number == latestCheckpointNumber) {
423
- val prev = findPreviousCheckpointBlockNumber(header.number, header.number)
424
- prev
425
- .map { num =>
426
- (appStateStorage.putLatestCheckpointBlockNumber(num), Some (num))
427
- }
428
- .getOrElse {
429
- (appStateStorage.removeLatestCheckpointBlockNumber(), Some (0 ))
430
- }
431
- } else (appStateStorage.emptyBatchUpdate, None )
432
- case None =>
433
- (appStateStorage.emptyBatchUpdate, None )
434
- }
403
+ log.debug(s " Trying to remove block block ${block.idTag}" )
435
404
436
- val newBestBlockNumber : BigInt = if (bestBlockNumber >= 1 ) bestBlockNumber - 1 else 0
405
+ val txList = block.body.transactionList
406
+ val bestBlockNumber = getBestBlockNumber()
407
+ val latestCheckpointNumber = getLatestCheckpointBlockNumber()
408
+
409
+ val blockNumberMappingUpdates =
410
+ if (getHashByBlockNumber(block.number).contains(blockHash))
411
+ removeBlockNumberMapping(block.number)
412
+ else blockNumberMappingStorage.emptyBatchUpdate
413
+
414
+ val newBestBlockNumber : BigInt = (bestBlockNumber - 1 ).max(0 )
415
+ val newLatestCheckpointNumber : BigInt =
416
+ if (block.hasCheckpoint && block.number == latestCheckpointNumber) {
417
+ findPreviousCheckpointBlockNumber(block.number, block.number)
418
+ } else latestCheckpointNumber
419
+
420
+ // Block number updates are only done if the persisted value is larger, as we won't have the associated mpt nodes if not
421
+ val bestBlockNumberUpdates =
422
+ if (appStateStorage.getBestBlockNumber() > newBestBlockNumber)
423
+ appStateStorage.putBestBlockNumber(newBestBlockNumber)
424
+ else appStateStorage.emptyBatchUpdate
425
+
426
+ // Checkpoint number updates are only done if the persisted value is larger, as we won't have the associated mpt nodes if not
427
+ val latestCheckpointNumberUpdates =
428
+ if (appStateStorage.getLatestCheckpointBlockNumber() > newLatestCheckpointNumber)
429
+ appStateStorage.putLatestCheckpointBlockNumber(newLatestCheckpointNumber)
430
+ else appStateStorage.emptyBatchUpdate
431
+
432
+ log.debug(
433
+ " Persisting block info data into database. Persisted block number is {}. Persisted checkpoint number is {}" ,
434
+ newBestBlockNumber,
435
+ newLatestCheckpointNumber
436
+ )
437
437
438
438
blockHeadersStorage
439
439
.remove(blockHash)
440
440
.and(blockBodiesStorage.remove(blockHash))
441
441
.and(chainWeightStorage.remove(blockHash))
442
442
.and(receiptStorage.remove(blockHash))
443
- .and(maybeTxList.fold(transactionMappingStorage.emptyBatchUpdate)( removeTxsLocations))
443
+ .and(removeTxsLocations(txList ))
444
444
.and(blockNumberMappingUpdates)
445
+ .and(bestBlockNumberUpdates)
446
+ .and(latestCheckpointNumberUpdates)
445
447
.commit()
446
448
447
449
// not transactional part
448
- saveBestKnownBlocks(newBestBlockNumber, prevCheckpointNumber )
450
+ saveBestKnownBlocks(newBestBlockNumber, Some (newLatestCheckpointNumber) )
449
451
log.debug(
450
452
" Removed block with hash {}. New best block number - {}, new best checkpoint block number - {}" ,
451
453
ByteStringUtils .hash2string(blockHash),
452
454
newBestBlockNumber,
453
- prevCheckpointNumber
455
+ newLatestCheckpointNumber
454
456
)
455
457
456
- maybeBlockHeader.foreach { h =>
457
- if (withState) {
458
- val bestBlocksUpdates = appStateStorage
459
- .putBestBlockNumber(newBestBlockNumber)
460
- .and(checkpointUpdates)
461
- stateStorage.onBlockRollback(h.number, bestBlockNumber) { () =>
462
- log.debug(
463
- " Persisting block info data into database. Persisted block number is {}. " +
464
- " Persisted checkpoint number is {}" ,
465
- newBestBlockNumber,
466
- prevCheckpointNumber
467
- )
468
- bestBlocksUpdates.commit()
469
- }
470
- }
471
- }
458
+ if (withState)
459
+ stateStorage.onBlockRollback(block.number, bestBlockNumber) { () => persistBestBlocksData() }
472
460
}
473
461
// scalastyle:on method.length
474
462
@@ -485,7 +473,7 @@ class BlockchainImpl(
485
473
private def findPreviousCheckpointBlockNumber (
486
474
blockNumberToCheck : BigInt ,
487
475
latestCheckpointBlockNumber : BigInt
488
- ): Option [ BigInt ] = {
476
+ ): BigInt = {
489
477
if (blockNumberToCheck > 0 ) {
490
478
val maybePreviousCheckpointBlockNumber = for {
491
479
currentBlock <- getBlockByNumber(blockNumberToCheck)
@@ -494,10 +482,10 @@ class BlockchainImpl(
494
482
} yield currentBlock.number
495
483
496
484
maybePreviousCheckpointBlockNumber match {
497
- case Some (_ ) => maybePreviousCheckpointBlockNumber
485
+ case Some (previousCheckpointBlockNumber ) => previousCheckpointBlockNumber
498
486
case None => findPreviousCheckpointBlockNumber(blockNumberToCheck - 1 , latestCheckpointBlockNumber)
499
487
}
500
- } else None
488
+ } else 0
501
489
}
502
490
503
491
private def saveTxsLocations (blockHash : ByteString , blockBody : BlockBody ): DataSourceBatchUpdate =
0 commit comments