@@ -224,7 +224,12 @@ class BlockchainImpl(
224224 // There is always only one writer thread (ensured by actor), but can by many readers (api calls)
225225 // to ensure visibility of writes, needs to be volatile or atomic ref
226226 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+ )
228233
229234 override def getBlockHeaderByHash (hash : ByteString ): Option [BlockHeader ] =
230235 blockHeadersStorage.get(hash)
@@ -246,22 +251,15 @@ class BlockchainImpl(
246251 bestSavedBlockNumber,
247252 bestKnownBlockNumber
248253 )
249- if (bestKnownBlockNumber > bestSavedBlockNumber)
250- bestKnownBlockNumber
251- else
252- bestSavedBlockNumber
253- }
254254
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
263258 }
264259
260+ override def getLatestCheckpointBlockNumber (): BigInt =
261+ bestKnownBlockAndLatestCheckpoint.get().latestCheckpointNumber
262+
265263 override def getBestBlock (): Block = {
266264 val bestBlockNumber = getBestBlockNumber()
267265 log.debug(" Trying to get best block with number {}" , bestBlockNumber)
@@ -313,10 +311,6 @@ class BlockchainImpl(
313311 .and(storeChainWeight(block.header.hash, weight))
314312 .commit()
315313
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-
320314 if (saveAsBestBlock && block.hasCheckpoint) {
321315 log.debug(
322316 " New best known block block number - {}, new best checkpoint number - {}" ,
@@ -331,6 +325,10 @@ class BlockchainImpl(
331325 )
332326 saveBestKnownBlock(block.header.number)
333327 }
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)
334332 }
335333
336334 override def storeBlockHeader (blockHeader : BlockHeader ): DataSourceBatchUpdate = {
@@ -388,87 +386,77 @@ class BlockchainImpl(
388386 blockNumberMappingStorage.remove(number)
389387 }
390388
391- // scalastyle:off method.length
392389 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)
400391
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 " )
410396 }
397+ }
411398
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
419402
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}" )
435404
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+ )
437437
438438 blockHeadersStorage
439439 .remove(blockHash)
440440 .and(blockBodiesStorage.remove(blockHash))
441441 .and(chainWeightStorage.remove(blockHash))
442442 .and(receiptStorage.remove(blockHash))
443- .and(maybeTxList.fold(transactionMappingStorage.emptyBatchUpdate)( removeTxsLocations))
443+ .and(removeTxsLocations(txList ))
444444 .and(blockNumberMappingUpdates)
445+ .and(bestBlockNumberUpdates)
446+ .and(latestCheckpointNumberUpdates)
445447 .commit()
446448
447449 // not transactional part
448- saveBestKnownBlocks(newBestBlockNumber, prevCheckpointNumber )
450+ saveBestKnownBlocks(newBestBlockNumber, Some (newLatestCheckpointNumber) )
449451 log.debug(
450452 " Removed block with hash {}. New best block number - {}, new best checkpoint block number - {}" ,
451453 ByteStringUtils .hash2string(blockHash),
452454 newBestBlockNumber,
453- prevCheckpointNumber
455+ newLatestCheckpointNumber
454456 )
455457
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() }
472460 }
473461 // scalastyle:on method.length
474462
@@ -485,7 +473,7 @@ class BlockchainImpl(
485473 private def findPreviousCheckpointBlockNumber (
486474 blockNumberToCheck : BigInt ,
487475 latestCheckpointBlockNumber : BigInt
488- ): Option [ BigInt ] = {
476+ ): BigInt = {
489477 if (blockNumberToCheck > 0 ) {
490478 val maybePreviousCheckpointBlockNumber = for {
491479 currentBlock <- getBlockByNumber(blockNumberToCheck)
@@ -494,10 +482,10 @@ class BlockchainImpl(
494482 } yield currentBlock.number
495483
496484 maybePreviousCheckpointBlockNumber match {
497- case Some (_ ) => maybePreviousCheckpointBlockNumber
485+ case Some (previousCheckpointBlockNumber ) => previousCheckpointBlockNumber
498486 case None => findPreviousCheckpointBlockNumber(blockNumberToCheck - 1 , latestCheckpointBlockNumber)
499487 }
500- } else None
488+ } else 0
501489 }
502490
503491 private def saveTxsLocations (blockHash : ByteString , blockBody : BlockBody ): DataSourceBatchUpdate =
0 commit comments