diff --git a/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala b/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala index f23d72d7f0..42da038438 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala @@ -39,7 +39,6 @@ import io.iohk.ethereum.db.storage.pruning.PruningMode import io.iohk.ethereum.domain.Block import io.iohk.ethereum.domain.Blockchain import io.iohk.ethereum.domain.BlockchainImpl -import io.iohk.ethereum.domain.BlockchainMetadata import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.domain.BlockchainWriter import io.iohk.ethereum.domain.ChainWeight @@ -138,13 +137,9 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu ) ) - val blockchainMetadata = new BlockchainMetadata( - storagesInstance.storages.appStateStorage.getBestBlockNumber(), - storagesInstance.storages.appStateStorage.getLatestCheckpointBlockNumber() - ) - val blockchainReader: BlockchainReader = BlockchainReader(storagesInstance.storages, blockchainMetadata) - val blockchainWriter: BlockchainWriter = BlockchainWriter(storagesInstance.storages, blockchainMetadata) - val bl: BlockchainImpl = BlockchainImpl(storagesInstance.storages, blockchainReader, blockchainMetadata) + val blockchainReader: BlockchainReader = BlockchainReader(storagesInstance.storages) + val blockchainWriter: BlockchainWriter = BlockchainWriter(storagesInstance.storages) + val bl: BlockchainImpl = BlockchainImpl(storagesInstance.storages, blockchainReader) val evmCodeStorage = storagesInstance.storages.evmCodeStorage val genesis: Block = Block( diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala index f76a34c552..30249a737f 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala @@ -80,10 +80,9 @@ class ECIP1017Test extends AnyFlatSpec with Matchers { (startBlock to endBlock).foreach { blockToExecute => val storages = FixtureProvider.prepareStorages(blockToExecute - 1, fixtures) - val blockchainMetadata = getNewBlockchainMetadata - val blockchainReader = BlockchainReader(storages, blockchainMetadata) - val blockchainWriter = BlockchainWriter(storages, blockchainMetadata) - val blockchain = BlockchainImpl(storages, blockchainReader, blockchainMetadata) + val blockchainReader = BlockchainReader(storages) + val blockchainWriter = BlockchainWriter(storages) + val blockchain = BlockchainImpl(storages, blockchainReader) val blockValidation = new BlockValidation(mining, blockchainReader, BlockQueue(blockchain, blockchainReader, syncConfig)) val blockExecution = diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala index 33c7bcb40b..1b7822cccc 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala @@ -56,10 +56,9 @@ class ForksTest extends AnyFlatSpec with Matchers { (startBlock to endBlock).foreach { blockToExecute => val storages = FixtureProvider.prepareStorages(blockToExecute - 1, fixtures) - val blockchainMetadata = getNewBlockchainMetadata - val blockchainReader = BlockchainReader(storages, blockchainMetadata) - val blockchainWriter = BlockchainWriter(storages, blockchainMetadata) - val blockchain = BlockchainImpl(storages, blockchainReader, blockchainMetadata) + val blockchainReader = BlockchainReader(storages) + val blockchainWriter = BlockchainWriter(storages) + val blockchain = BlockchainImpl(storages, blockchainReader) val blockValidation = new BlockValidation(mining, blockchainReader, BlockQueue(blockchain, blockchainReader, syncConfig)) val blockExecution = diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala index d75eb8997a..a92ed9b41b 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala @@ -10,10 +10,8 @@ import io.iohk.ethereum.ledger.VMImpl trait ScenarioSetup extends EphemBlockchainTestSetup { protected val testBlockchainStorages: BlockchainStorages - val blockchainMetadata = getNewBlockchainMetadata - override lazy val blockchainReader: BlockchainReader = BlockchainReader(testBlockchainStorages, blockchainMetadata) - override lazy val blockchainWriter: BlockchainWriter = BlockchainWriter(testBlockchainStorages, blockchainMetadata) - override lazy val blockchain: BlockchainImpl = - BlockchainImpl(testBlockchainStorages, blockchainReader, blockchainMetadata) + override lazy val blockchainReader: BlockchainReader = BlockchainReader(testBlockchainStorages) + override lazy val blockchainWriter: BlockchainWriter = BlockchainWriter(testBlockchainStorages) + override lazy val blockchain: BlockchainImpl = BlockchainImpl(testBlockchainStorages, blockchainReader) override lazy val vm: VMImpl = new VMImpl } diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala index 39accb2bba..14138276b0 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala @@ -184,12 +184,10 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain { ethCompatibleStorage: Boolean ): StorageProof = EmptyStorageValueProof(StorageProofKey(position)) - override def removeBlock(hash: ByteString, withState: Boolean = true): Unit = ??? + override def removeBlock(hash: ByteString): Unit = ??? override def getChainWeightByHash(blockhash: ByteString): Option[ChainWeight] = ??? - def getAccount(address: Address, blockNumber: BigInt): Option[Account] = ??? - override def getAccountStorageAt(rootHash: ByteString, position: BigInt, ethCompatibleStorage: Boolean): ByteString = ??? @@ -198,8 +196,6 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain { def getBestBlockNumber(): BigInt = ??? - def saveBlockNumber(number: BigInt, hash: NodeHash): Unit = ??? - def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit = ??? def getBestBlock(): Option[Block] = ??? diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala index 272f192fa7..526ee5123f 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala @@ -70,7 +70,7 @@ class SyncController( def start(): Unit = { import syncConfig.doFastSync - appStateStorage.putSyncStartingBlock(appStateStorage.getBestBlockNumber()) + appStateStorage.putSyncStartingBlock(appStateStorage.getBestBlockNumber()).commit() (appStateStorage.isFastSyncDone(), doFastSync) match { case (false, true) => startFastSync() diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSync.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSync.scala index 707fdadc52..c425ce22c1 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSync.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSync.scala @@ -567,16 +567,13 @@ class FastSync( } // TODO [ETCM-676]: Move to blockchain and make sure it's atomic - private def discardLastBlocks(startBlock: BigInt, blocksToDiscard: Int): Unit = { + private def discardLastBlocks(startBlock: BigInt, blocksToDiscard: Int): Unit = // TODO (maybe ETCM-77): Manage last checkpoint number too - appStateStorage.putBestBlockNumber((startBlock - blocksToDiscard - 1).max(0)).commit() - (startBlock to ((startBlock - blocksToDiscard).max(1)) by -1).foreach { n => blockchainReader.getBlockHeaderByNumber(n).foreach { headerToRemove => - blockchain.removeBlock(headerToRemove.hash, withState = false) + blockchain.removeBlock(headerToRemove.hash) } } - } private def validateHeader(header: BlockHeader, peer: Peer): Either[HeaderProcessingResult, BlockHeader] = { val shouldValidate = header.number >= syncState.nextBlockToFullyValidate @@ -790,7 +787,7 @@ class FastSync( |Peers waiting_for_response/connected: ${assignedHandlers.size}/${handshakedPeers.size} (${blacklistedIds.size} blacklisted). |State: ${syncState.downloadedNodesCount}/${syncState.totalNodesCount} nodes. |""".stripMargin.replace("\n", " "), - appStateStorage.getBestBlockNumber() + blockchainReader.getBestBlockNumber() ) log.debug( s"""|Connection status: connected({})/ @@ -1136,9 +1133,8 @@ class FastSync( if (fullBlocks.nonEmpty) { val bestReceivedBlock = fullBlocks.maxBy(_.number) - val lastStoredBestBlockNumber = appStateStorage.getBestBlockNumber() + val lastStoredBestBlockNumber = blockchainReader.getBestBlockNumber() if (lastStoredBestBlockNumber < bestReceivedBlock.number) { - blockchain.saveBestKnownBlocks(bestReceivedBlock.number) // TODO ETCM-1089 move direct calls to storages to blockchain or blockchain writer appStateStorage .putBestBlockNumber(bestReceivedBlock.number) diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolver.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolver.scala index 347d8debae..46cc0926c4 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolver.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolver.scala @@ -25,7 +25,7 @@ trait FastSyncBranchResolver { blocksToBeRemoved.foreach { toBeRemoved => blockchainReader .getBlockHeaderByNumber(toBeRemoved) - .foreach(header => blockchain.removeBlock(header.hash, withState = false)) + .foreach(header => blockchain.removeBlock(header.hash)) } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/ConsensusImpl.scala b/src/main/scala/io/iohk/ethereum/consensus/ConsensusImpl.scala index adbeef8d0a..f2b899936c 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ConsensusImpl.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ConsensusImpl.scala @@ -333,7 +333,7 @@ class ConsensusImpl( weight <- blockchain.getChainWeightByHash(hash) } yield BlockData(block, receipts, weight) - blockchain.removeBlock(hash, withState = true) + blockchain.removeBlock(hash) removeBlocksUntil(parent, fromNumber - 1, blockDataOpt.map(_ :: acc).getOrElse(acc)) diff --git a/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala b/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala index 09a1c8953e..34efff79b1 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala @@ -62,7 +62,7 @@ trait Blockchain { def getLatestCheckpointBlockNumber(): BigInt - def removeBlock(hash: ByteString, withState: Boolean): Unit + def removeBlock(hash: ByteString): Unit def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit @@ -77,15 +77,13 @@ class BlockchainImpl( protected val transactionMappingStorage: TransactionMappingStorage, protected val appStateStorage: AppStateStorage, protected val stateStorage: StateStorage, - blockchainReader: BlockchainReader, - blockchainMetadata: BlockchainMetadata + blockchainReader: BlockchainReader ) extends Blockchain with Logger { override def getChainWeightByHash(blockhash: ByteString): Option[ChainWeight] = chainWeightStorage.get(blockhash) - override def getLatestCheckpointBlockNumber(): BigInt = - blockchainMetadata.bestKnownBlockAndLatestCheckpoint.get().latestCheckpointNumber + override def getLatestCheckpointBlockNumber(): BigInt = appStateStorage.getLatestCheckpointBlockNumber() override def getAccountStorageAt( rootHash: ByteString, @@ -128,22 +126,6 @@ class BlockchainImpl( def getReadOnlyMptStorage(): MptStorage = stateStorage.getReadOnlyStorage - private def persistBestBlocksData(): Unit = { - val currentBestBlockNumber = blockchainReader.getBestBlockNumber() - val currentBestCheckpointNumber = getLatestCheckpointBlockNumber() - log.debug( - "Persisting app info data into database. Persisted block number is {}. " + - "Persisted checkpoint number is {}", - currentBestBlockNumber, - currentBestCheckpointNumber - ) - - appStateStorage - .putBestBlockNumber(currentBestBlockNumber) - .and(appStateStorage.putLatestCheckpointBlockNumber(currentBestCheckpointNumber)) - .commit() - } - override def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit = latestCheckpointNumber match { case Some(number) => @@ -153,28 +135,29 @@ class BlockchainImpl( } private def saveBestKnownBlock(bestBlockNumber: BigInt): Unit = - blockchainMetadata.bestKnownBlockAndLatestCheckpoint.updateAndGet(_.copy(bestBlockNumber = bestBlockNumber)) + appStateStorage.putBestBlockNumber(bestBlockNumber).commit() private def saveBestKnownBlockAndLatestCheckpointNumber(number: BigInt, latestCheckpointNumber: BigInt): Unit = - blockchainMetadata.bestKnownBlockAndLatestCheckpoint.set( - BestBlockLatestCheckpointNumbers(number, latestCheckpointNumber) - ) + appStateStorage + .putBestBlockNumber(number) + .and(appStateStorage.putLatestCheckpointBlockNumber(latestCheckpointNumber)) + .commit() private def removeBlockNumberMapping(number: BigInt): DataSourceBatchUpdate = blockNumberMappingStorage.remove(number) - override def removeBlock(blockHash: ByteString, withState: Boolean): Unit = { + override def removeBlock(blockHash: ByteString): Unit = { val maybeBlock = blockchainReader.getBlockByHash(blockHash) maybeBlock match { - case Some(block) => removeBlock(block, withState) + case Some(block) => removeBlock(block) case None => log.warn(s"Attempted removing block with hash ${ByteStringUtils.hash2string(blockHash)} that we don't have") } } // scalastyle:off method.length - private def removeBlock(block: Block, withState: Boolean): Unit = { + private def removeBlock(block: Block): Unit = { val blockHash = block.hash log.debug(s"Trying to remove block ${block.idTag}") @@ -229,17 +212,12 @@ class BlockchainImpl( .and(latestCheckpointNumberUpdates) .commit() - saveBestKnownBlocks(newBestBlockNumber, Some(newLatestCheckpointNumber)) log.debug( "Removed block with hash {}. New best block number - {}, new best checkpoint block number - {}", ByteStringUtils.hash2string(blockHash), newBestBlockNumber, newLatestCheckpointNumber ) - - // not transactional part - if (withState) - stateStorage.onBlockRollback(block.number, bestBlockNumber)(() => persistBestBlocksData()) } // scalastyle:on method.length @@ -288,8 +266,7 @@ trait BlockchainStorages { object BlockchainImpl { def apply( storages: BlockchainStorages, - blockchainReader: BlockchainReader, - metadata: BlockchainMetadata + blockchainReader: BlockchainReader ): BlockchainImpl = new BlockchainImpl( blockHeadersStorage = storages.blockHeadersStorage, @@ -300,7 +277,6 @@ object BlockchainImpl { transactionMappingStorage = storages.transactionMappingStorage, appStateStorage = storages.appStateStorage, stateStorage = storages.stateStorage, - blockchainReader = blockchainReader, - blockchainMetadata = metadata + blockchainReader = blockchainReader ) } diff --git a/src/main/scala/io/iohk/ethereum/domain/BlockchainMetadata.scala b/src/main/scala/io/iohk/ethereum/domain/BlockchainMetadata.scala deleted file mode 100644 index e387dabdc9..0000000000 --- a/src/main/scala/io/iohk/ethereum/domain/BlockchainMetadata.scala +++ /dev/null @@ -1,10 +0,0 @@ -package io.iohk.ethereum.domain - -import java.util.concurrent.atomic.AtomicReference - -class BlockchainMetadata(bestBlockNumber: BigInt, latestCheckpointNumber: BigInt) { - lazy val bestKnownBlockAndLatestCheckpoint: AtomicReference[BestBlockLatestCheckpointNumbers] = - new AtomicReference(BestBlockLatestCheckpointNumbers(bestBlockNumber, latestCheckpointNumber)) -} - -case class BestBlockLatestCheckpointNumbers(bestBlockNumber: BigInt, latestCheckpointNumber: BigInt) diff --git a/src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala b/src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala index bcf240a1dd..d248d2e032 100644 --- a/src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala +++ b/src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala @@ -21,8 +21,7 @@ class BlockchainReader( blockNumberMappingStorage: BlockNumberMappingStorage, stateStorage: StateStorage, receiptStorage: ReceiptStorage, - appStateStorage: AppStateStorage, - blockchainMetadata: BlockchainMetadata + appStateStorage: AppStateStorage ) extends Logger { /** Allows to query a blockHeader by block hash @@ -81,29 +80,13 @@ class BlockchainReader( .getOrElse(EmptyBranch) } - def getBestBlockNumber(): BigInt = { - val bestSavedBlockNumber = appStateStorage.getBestBlockNumber() - val bestKnownBlockNumber = blockchainMetadata.bestKnownBlockAndLatestCheckpoint.get().bestBlockNumber - log.debug( - "Current best saved block number {}. Current best known block number {}", - bestSavedBlockNumber, - bestKnownBlockNumber - ) - - // The cached best block number should always be more up-to-date than the one on disk, we are keeping access to disk - // above only for logging purposes - bestKnownBlockNumber - } + def getBestBlockNumber(): BigInt = appStateStorage.getBestBlockNumber() - //returns the best known block if it's available in the storage, otherwise the best stored block + //returns the best known block if it's available in the storage def getBestBlock(): Option[Block] = { val bestBlockNumber = getBestBlockNumber() log.debug("Trying to get best block with number {}", bestBlockNumber) - getBlockByNumber(bestBlockNumber).orElse( - getBlockByNumber( - appStateStorage.getBestBlockNumber() - ) - ) + getBlockByNumber(bestBlockNumber) } def genesisHeader: BlockHeader = @@ -199,16 +182,14 @@ class BlockchainReader( object BlockchainReader { def apply( - storages: BlockchainStorages, - blockchainMetadata: BlockchainMetadata + storages: BlockchainStorages ): BlockchainReader = new BlockchainReader( storages.blockHeadersStorage, storages.blockBodiesStorage, storages.blockNumberMappingStorage, storages.stateStorage, storages.receiptStorage, - storages.appStateStorage, - blockchainMetadata + storages.appStateStorage ) } diff --git a/src/main/scala/io/iohk/ethereum/domain/BlockchainWriter.scala b/src/main/scala/io/iohk/ethereum/domain/BlockchainWriter.scala index 8b2db6c8ca..db7d31f6d9 100644 --- a/src/main/scala/io/iohk/ethereum/domain/BlockchainWriter.scala +++ b/src/main/scala/io/iohk/ethereum/domain/BlockchainWriter.scala @@ -9,7 +9,6 @@ import io.iohk.ethereum.db.storage.BlockHeadersStorage import io.iohk.ethereum.db.storage.BlockNumberMappingStorage import io.iohk.ethereum.db.storage.ChainWeightStorage import io.iohk.ethereum.db.storage.ReceiptStorage -import io.iohk.ethereum.db.storage.StateStorage import io.iohk.ethereum.db.storage.TransactionMappingStorage import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation import io.iohk.ethereum.utils.Logger @@ -21,36 +20,35 @@ class BlockchainWriter( transactionMappingStorage: TransactionMappingStorage, receiptStorage: ReceiptStorage, chainWeightStorage: ChainWeightStorage, - stateStorage: StateStorage, - appStateStorage: AppStateStorage, - blockchainMetadata: BlockchainMetadata + appStateStorage: AppStateStorage ) extends Logger { def save(block: Block, receipts: Seq[Receipt], weight: ChainWeight, saveAsBestBlock: Boolean): Unit = { - if (saveAsBestBlock && block.hasCheckpoint) { + val updateBestBlocks = if (saveAsBestBlock && block.hasCheckpoint) { log.debug( "New best known block number - {}, new best checkpoint number - {}", block.header.number, block.header.number ) - saveBestKnownBlockAndLatestCheckpointNumber(block.header.number, block.header.number) + appStateStorage + .putBestBlockNumber(block.header.number) + .and(appStateStorage.putLatestCheckpointBlockNumber(block.header.number)) } else if (saveAsBestBlock) { log.debug( "New best known block number - {}", block.header.number ) - saveBestKnownBlock(block.header.number) + appStateStorage.putBestBlockNumber(block.header.number) + } else { + appStateStorage.emptyBatchUpdate } log.debug("Saving new block {} to database", block.idTag) storeBlock(block) .and(storeReceipts(block.header.hash, receipts)) .and(storeChainWeight(block.header.hash, weight)) + .and(updateBestBlocks) .commit() - - // not transactional part - // the best blocks data will be persisted only when the cache will be persisted - stateStorage.onBlockSave(block.header.number, appStateStorage.getBestBlockNumber())(persistBestBlocksData) } def storeReceipts(blockHash: ByteString, receipts: Seq[Receipt]): DataSourceBatchUpdate = @@ -59,9 +57,6 @@ class BlockchainWriter( def storeChainWeight(blockHash: ByteString, weight: ChainWeight): DataSourceBatchUpdate = chainWeightStorage.put(blockHash, weight) - private def saveBestKnownBlock(bestBlockNumber: BigInt): Unit = - blockchainMetadata.bestKnownBlockAndLatestCheckpoint.updateAndGet(_.copy(bestBlockNumber = bestBlockNumber)) - /** Persists a block in the underlying Blockchain Database * Note: all store* do not update the database immediately, rather they create * a [[io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate]] which then has to be committed (atomic operation) @@ -87,31 +82,10 @@ class BlockchainWriter( case (updates, (tx, index)) => updates.and(transactionMappingStorage.put(tx.hash, TransactionLocation(blockHash, index))) } - - private def saveBestKnownBlockAndLatestCheckpointNumber(number: BigInt, latestCheckpointNumber: BigInt): Unit = - blockchainMetadata.bestKnownBlockAndLatestCheckpoint.set( - BestBlockLatestCheckpointNumbers(number, latestCheckpointNumber) - ) - - private def persistBestBlocksData: () => Unit = () => { - val currentBestBlockNumber = blockchainMetadata.bestKnownBlockAndLatestCheckpoint.get().bestBlockNumber - val currentBestCheckpointNumber = blockchainMetadata.bestKnownBlockAndLatestCheckpoint.get().latestCheckpointNumber - log.debug( - "Persisting app info data into database. Persisted block number is {}. " + - "Persisted checkpoint number is {}", - currentBestBlockNumber, - currentBestCheckpointNumber - ) - - appStateStorage - .putBestBlockNumber(currentBestBlockNumber) - .and(appStateStorage.putLatestCheckpointBlockNumber(currentBestCheckpointNumber)) - .commit() - } } object BlockchainWriter { - def apply(storages: BlockchainStorages, metadata: BlockchainMetadata): BlockchainWriter = + def apply(storages: BlockchainStorages): BlockchainWriter = new BlockchainWriter( storages.blockHeadersStorage, storages.blockBodiesStorage, @@ -119,8 +93,6 @@ object BlockchainWriter { storages.transactionMappingStorage, storages.receiptStorage, storages.chainWeightStorage, - storages.stateStorage, - storages.appStateStorage, - metadata + storages.appStateStorage ) } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala index 9652419baa..35bb139521 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala @@ -187,7 +187,7 @@ class TestService( resetPreimages(genesisData) // remove current genesis (Try because it may not exist) - Try(blockchain.removeBlock(blockchainReader.genesisHeader.hash, withState = false)) + Try(blockchain.removeBlock(blockchainReader.genesisHeader.hash)) // TODO clear the storage ? When relaunching some tests on the same running test mantis client, // we end up with duplicate blocks because they are still present in the storage layer // for example: bcMultiChainTest/ChainAtoChainB_BlockHash_Istanbul @@ -291,7 +291,7 @@ class TestService( def rewindToBlock(request: RewindToBlockRequest): ServiceResponse[RewindToBlockResponse] = { pendingTransactionsManager ! PendingTransactionsManager.ClearPendingTransactions (blockchainReader.getBestBlockNumber() until request.blockNum by -1).foreach { n => - blockchain.removeBlock(blockchainReader.getBlockHeaderByNumber(n).get.hash, withState = false) + blockchain.removeBlock(blockchainReader.getBlockHeaderByNumber(n).get.hash) } RewindToBlockResponse().rightNow } diff --git a/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala b/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala index 445b3f4f8e..5b7e44aaef 100644 --- a/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala +++ b/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala @@ -210,7 +210,7 @@ class EtcPeerManagerActor( } else { val (maxBlockNumber, maxBlockHash) = ns.maxBy(_._1) if (maxBlockNumber > appStateStorage.getEstimatedHighestBlock()) - appStateStorage.putEstimatedHighestBlock(maxBlockNumber) + appStateStorage.putEstimatedHighestBlock(maxBlockNumber).commit() if (maxBlockNumber > initialPeerInfo.maxBlockNumber) { initialPeerInfo.withBestBlockData(maxBlockNumber, maxBlockHash) diff --git a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala index 485ad15d26..ff9425ea57 100644 --- a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala @@ -34,7 +34,6 @@ import io.iohk.ethereum.db.components.Storages.PruningModeComponent import io.iohk.ethereum.db.components._ import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.db.storage.pruning.PruningMode -import io.iohk.ethereum.domain.BlockchainMetadata import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.NetService.NetServiceConfig import io.iohk.ethereum.jsonrpc._ @@ -176,14 +175,9 @@ trait NodeStatusBuilder { trait BlockchainBuilder { self: StorageBuilder => - private lazy val blockchainMetadata: BlockchainMetadata = - new BlockchainMetadata( - storagesInstance.storages.appStateStorage.getBestBlockNumber(), - storagesInstance.storages.appStateStorage.getLatestCheckpointBlockNumber() - ) - lazy val blockchainReader: BlockchainReader = BlockchainReader(storagesInstance.storages, blockchainMetadata) - lazy val blockchainWriter: BlockchainWriter = BlockchainWriter(storagesInstance.storages, blockchainMetadata) - lazy val blockchain: BlockchainImpl = BlockchainImpl(storagesInstance.storages, blockchainReader, blockchainMetadata) + lazy val blockchainReader: BlockchainReader = BlockchainReader(storagesInstance.storages) + lazy val blockchainWriter: BlockchainWriter = BlockchainWriter(storagesInstance.storages) + lazy val blockchain: BlockchainImpl = BlockchainImpl(storagesInstance.storages, blockchainReader) } trait BlockQueueBuilder { diff --git a/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala b/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala index 72ccfadc09..3269e557a1 100644 --- a/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala +++ b/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala @@ -33,6 +33,8 @@ trait ObjectGenerators { def intGen(min: Int, max: Int): Gen[Int] = Gen.choose(min, max) + def posIntGen(min: Int, max: Int): Gen[Int] = Gen.choose(min, max).suchThat(_ > 0) + def intGen: Gen[Int] = Gen.choose(Int.MinValue, Int.MaxValue) def longGen: Gen[Long] = Gen.choose(Long.MinValue, Long.MaxValue) diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala index 1b78124676..17754acc3e 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala @@ -4,7 +4,6 @@ import io.iohk.ethereum.db.components.EphemDataSourceComponent import io.iohk.ethereum.db.components.Storages import io.iohk.ethereum.db.storage.pruning.ArchivePruning import io.iohk.ethereum.db.storage.pruning.PruningMode -import io.iohk.ethereum.domain.BlockchainMetadata import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.nodebuilder.PruningConfigBuilder @@ -23,6 +22,4 @@ trait EphemBlockchainTestSetup extends ScenarioSetup { def getNewStorages: EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages = new EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages - - def getNewBlockchainMetadata = new BlockchainMetadata(0, 0) } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala index e6e935e7aa..1de032d05c 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala @@ -110,9 +110,8 @@ class StateSyncSpec it should "start state sync when receiving start signal while bloom filter is loading" in new TestSetup() { override def buildBlockChain(): (BlockchainReader, BlockchainImpl) = { val storages = getNewStorages.storages - val blockchainMetadata = getNewBlockchainMetadata - val blockchainReader = BlockchainReader(storages, blockchainMetadata) - (blockchainReader, BlockchainImpl(storages, blockchainReader, blockchainMetadata)) + val blockchainReader = BlockchainReader(storages) + (blockchainReader, BlockchainImpl(storages, blockchainReader)) } val nodeData = (0 until 1000).map(i => MptNodeData(Address(i), None, Seq(), i)) @@ -229,14 +228,9 @@ class StateSyncSpec def buildBlockChain(): (BlockchainReader, BlockchainImpl) = { val storages = getNewStorages.storages - val blockchainMetadata = getNewBlockchainMetadata ( - BlockchainReader(storages, blockchainMetadata), - BlockchainImpl( - storages, - BlockchainReader(storages, blockchainMetadata), - blockchainMetadata - ) + BlockchainReader(storages), + BlockchainImpl(storages, BlockchainReader(storages)) ) } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala index 39b107a5ec..8132059f98 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala @@ -77,10 +77,9 @@ object StateSyncUtils extends EphemBlockchainTestSetup { object TrieProvider { def apply(): TrieProvider = { val freshStorage = getNewStorages - val freshBlockchainMetadata = getNewBlockchainMetadata - val blockchainReader = BlockchainReader(freshStorage.storages, freshBlockchainMetadata) + val blockchainReader = BlockchainReader(freshStorage.storages) new TrieProvider( - BlockchainImpl(freshStorage.storages, blockchainReader, freshBlockchainMetadata), + BlockchainImpl(freshStorage.storages, blockchainReader), blockchainReader, freshStorage.storages.evmCodeStorage, blockchainConfig diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala index c260831f7d..f1dc618ccc 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala @@ -280,9 +280,8 @@ class SyncStateSchedulerSpec trait TestSetup extends EphemBlockchainTestSetup { def getTrieProvider: TrieProvider = { val freshStorage = getNewStorages - val freshBlockchainMetadata = getNewBlockchainMetadata - val freshBlockchainReader = BlockchainReader(freshStorage.storages, freshBlockchainMetadata) - val freshBlockchain = BlockchainImpl(freshStorage.storages, freshBlockchainReader, freshBlockchainMetadata) + val freshBlockchainReader = BlockchainReader(freshStorage.storages) + val freshBlockchain = BlockchainImpl(freshStorage.storages, freshBlockchainReader) new TrieProvider(freshBlockchain, freshBlockchainReader, freshStorage.storages.evmCodeStorage, blockchainConfig) } val bloomFilterSize = 1000 @@ -310,10 +309,9 @@ class SyncStateSchedulerSpec EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages ) = { val freshStorage = getNewStorages - val freshBlockchainMetadata = getNewBlockchainMetadata - val freshBlockchainReader = BlockchainReader(freshStorage.storages, freshBlockchainMetadata) - val freshBlockchain = BlockchainImpl(freshStorage.storages, freshBlockchainReader, freshBlockchainMetadata) - val freshBlockchainWriter = BlockchainWriter(freshStorage.storages, freshBlockchainMetadata) + val freshBlockchainReader = BlockchainReader(freshStorage.storages) + val freshBlockchain = BlockchainImpl(freshStorage.storages, freshBlockchainReader) + val freshBlockchainWriter = BlockchainWriter(freshStorage.storages) ( SyncStateScheduler( freshBlockchainReader, diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverSpec.scala index 2c7ff49417..19cb8aa00d 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverSpec.scala @@ -53,11 +53,11 @@ class FastSyncBranchResolverSpec extends AnyWordSpec with Matchers with MockFact inSequence { (mockedBlockchainReader.getBestBlockNumber _).expects().returning(BigInt(100)).once() (mockedBlockchainReader.getBlockHeaderByNumber _).expects(BigInt(100)).returning(headers.get(100)) - (mockedBlockchain.removeBlock _).expects(headers(100).hash, false).returning(()) + (mockedBlockchain.removeBlock _).expects(headers(100).hash).returning(()) (mockedBlockchainReader.getBlockHeaderByNumber _).expects(BigInt(99)).returning(headers.get(99)) - (mockedBlockchain.removeBlock _).expects(headers(99).hash, false).returning(()) + (mockedBlockchain.removeBlock _).expects(headers(99).hash).returning(()) (mockedBlockchainReader.getBlockHeaderByNumber _).expects(BigInt(98)).returning(headers.get(98)) - (mockedBlockchain.removeBlock _).expects(headers(98).hash, false).returning(()) + (mockedBlockchain.removeBlock _).expects(headers(98).hash).returning(()) } val resolver = new FastSyncBranchResolver { diff --git a/src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala index 77c2fdcab7..763dcbf024 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/ConsensusSpec.scala @@ -197,61 +197,6 @@ class ConsensusSpec extends AnyFlatSpec with Matchers with ScalaFutures { blockQueue.isQueued(oldBlock3.header.hash) shouldBe true } - it should "get best stored block after reorganisation of the longer chain to a shorter one if desync state happened between cache and db" in new EphemBlockchain { - val block1: Block = getBlock(bestNum - 2) - // new chain is shorter but has a higher weight - val newBlock2: Block = getBlock(bestNum - 1, difficulty = 101, parent = block1.header.hash) - val newBlock3: Block = getBlock(bestNum, difficulty = 333, parent = newBlock2.header.hash) - val oldBlock2: Block = getBlock(bestNum - 1, difficulty = 102, parent = block1.header.hash) - val oldBlock3: Block = getBlock(bestNum, difficulty = 103, parent = oldBlock2.header.hash) - val oldBlock4: Block = getBlock(bestNum + 1, difficulty = 104, parent = oldBlock3.header.hash) - - val weight1 = ChainWeight.totalDifficultyOnly(block1.header.difficulty + 999) - val newWeight2 = weight1.increase(newBlock2.header) - val newWeight3 = newWeight2.increase(newBlock3.header) - val oldWeight2 = weight1.increase(oldBlock2.header) - val oldWeight3 = oldWeight2.increase(oldBlock3.header) - val oldWeight4 = oldWeight3.increase(oldBlock4.header) - - blockchainWriter.save(block1, Nil, weight1, saveAsBestBlock = true) - blockchainWriter.save(oldBlock2, receipts, oldWeight2, saveAsBestBlock = true) - blockchainWriter.save(oldBlock3, Nil, oldWeight3, saveAsBestBlock = true) - blockchainWriter.save(oldBlock4, Nil, oldWeight4, saveAsBestBlock = true) - - val ancestorForValidation: Block = getBlock(0, difficulty = 1) - blockchainWriter.save(ancestorForValidation, Nil, ChainWeight.totalDifficultyOnly(1), saveAsBestBlock = false) - - val oldBranch = List(oldBlock2, oldBlock3, oldBlock4) - val newBranch = List(newBlock2, newBlock3) - val blockData2 = BlockData(newBlock2, Seq.empty[Receipt], newWeight2) - val blockData3 = BlockData(newBlock3, Seq.empty[Receipt], newWeight3) - - val mockExecution = mock[BlockExecution] - (mockExecution - .executeAndValidateBlocks(_: List[Block], _: ChainWeight)(_: BlockchainConfig)) - .expects(newBranch, *, *) - .returning((List(blockData2, blockData3), None)) - - val withMockedBlockExecution = blockImportWithMockedBlockExecution(mockExecution) - whenReady(withMockedBlockExecution.evaluateBranchBlock(newBlock3).runToFuture)( - _ shouldEqual BlockEnqueued - ) - whenReady(withMockedBlockExecution.evaluateBranchBlock(newBlock2).runToFuture) { result => - result shouldEqual ChainReorganised(oldBranch, newBranch, List(newWeight2, newWeight3)) - } - - // Saving new blocks, because it's part of executeBlocks method mechanism - blockchainWriter.save(blockData2.block, blockData2.receipts, blockData2.weight, saveAsBestBlock = true) - blockchainWriter.save(blockData3.block, blockData3.receipts, blockData3.weight, saveAsBestBlock = true) - - // saving to cache the value of the best block from the initial chain. This recreates the bug ETCM-626, - // where (possibly) because of the thread of execution - // dying before updating the storage but after updating the cache, inconsistency is created - blockchain.saveBestKnownBlocks(oldBlock4.number) - - blockchainReader.getBestBlock() shouldBe Some(newBlock3) - } - it should "handle error when trying to reorganise chain" in new EphemBlockchain { val block1: Block = getBlock(bestNum - 2) val newBlock2: Block = getBlock(bestNum - 1, difficulty = 101, parent = block1.header.hash) diff --git a/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala b/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala index d503c6b4a1..b932c4ac09 100644 --- a/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala +++ b/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala @@ -117,7 +117,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh blockchainWriter.save(secondBlock, Seq.empty, ChainWeight(0, 0), saveAsBestBlock = true) blockchainWriter.save(thirdBlock, Seq.empty, ChainWeight(0, 0), saveAsBestBlock = true) - blockchain.removeBlock(thirdBlock.hash, withState = true) + blockchain.removeBlock(thirdBlock.hash) blockchain.getLatestCheckpointBlockNumber() should ===(firstBlock.number) blockchainReader.getBestBlockNumber() should ===(secondBlock.number) @@ -131,7 +131,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh blockchainWriter.save(validBlock, Seq.empty, ChainWeight(0, 0), saveAsBestBlock = true) - blockchain.removeBlock(validBlock.hash, withState = true) + blockchain.removeBlock(validBlock.hash) blockchain.getLatestCheckpointBlockNumber() should ===(genesis.number) blockchainReader.getBestBlockNumber() should ===(genesis.number) @@ -213,15 +213,15 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh mptWithAcc.get(wrongAddress) shouldBe None } - it should "return correct best block number after applying and rollbacking blocks" in new TestSetup { - forAll(intGen(min = 1: Int, max = maxNumberBlocksToImport)) { numberBlocksToImport => + it should "return correct best block number after saving and rolling back blocks" in new TestSetup { + forAll(posIntGen(min = 1, max = maxNumberBlocksToImport)) { numberBlocksToImport => val testSetup = newSetup() import testSetup._ // Import blocks val blocksToImport = BlockHelpers.generateChain(numberBlocksToImport, Fixtures.Blocks.Genesis.block) - // Randomly select the block import to persist (empty means no persistance) + // Randomly select the block import to persist (empty means no persistence) val blockImportToPersist = Gen.option(Gen.oneOf(blocksToImport)).sample.get (stubStateStorage .onBlockSave(_: BigInt, _: BigInt)(_: () => Unit)) @@ -231,19 +231,16 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh } blocksToImport.foreach { block => - blockchainWriterWithStubPersisting.save(block, Nil, ChainWeight.zero, true) + blockchainWriterWithStubPersisting.save(block, Nil, ChainWeight.zero, saveAsBestBlock = true) } blockchainReaderWithStubPersisting.getBestBlockNumber() shouldBe blocksToImport.last.number - blockchainStoragesWithStubPersisting.appStateStorage.getBestBlockNumber() shouldBe blockImportToPersist.fold( - 0: BigInt - )(_.number) // Rollback blocks val numberBlocksToRollback = intGen(0, numberBlocksToImport).sample.get - val (blocksNotRollbacked, blocksToRollback) = blocksToImport.splitAt(numberBlocksToRollback) + val (_, blocksToRollback) = blocksToImport.splitAt(numberBlocksToRollback) - // Randomly select the block rollback to persist (empty means no persistance) + // Randomly select the block rollback to persist (empty means no persistence) val blockRollbackToPersist = if (blocksToRollback.isEmpty) None else Gen.option(Gen.oneOf(blocksToRollback)).sample.get (stubStateStorage @@ -254,17 +251,15 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh } blocksToRollback.reverse.foreach { block => - blockchainWithStubPersisting.removeBlock(block.hash, true) + blockchainWithStubPersisting.removeBlock(block.hash) } - val expectedMemoryBestBlock = blocksNotRollbacked.lastOption.fold(0: BigInt)(_.number) val expectedPersistedBestBlock = calculatePersistedBestBlock( blockImportToPersist.map(_.number), blockRollbackToPersist.map(_.number), blocksToRollback.map(_.number) ) - blockchainReaderWithStubPersisting.getBestBlockNumber() shouldBe expectedMemoryBestBlock - blockchainStoragesWithStubPersisting.appStateStorage.getBestBlockNumber() shouldBe expectedPersistedBestBlock + blockchainReaderWithStubPersisting.getBestBlockNumber() shouldBe expectedPersistedBestBlock } } @@ -274,21 +269,21 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh def calculatePersistedBestBlock( blockImportPersisted: Option[BigInt], blockRollbackPersisted: Option[BigInt], - blocksRollbacked: Seq[BigInt] + blocksRolledback: Seq[BigInt] ): BigInt = - (blocksRollbacked, blockImportPersisted) match { + (blocksRolledback, blockImportPersisted) match { case (Nil, Some(bi)) => - // No blocks rollbacked, last persist was the persist during import + // No blocks rolledback, last persist was the persist during import bi - case (nonEmptyRollbackedBlocks, Some(bi)) => + case (nonEmptyRolledbackBlocks, Some(bi)) => // Last forced persist during apply/rollback val maxForcedPersist = blockRollbackPersisted.fold(bi)(br => (br - 1).max(bi)) // The above number would have been decreased by any rollbacked blocks - (nonEmptyRollbackedBlocks.head - 1).min(maxForcedPersist) + (nonEmptyRolledbackBlocks.head - 1).min(maxForcedPersist) case (_, None) => // If persisted rollback, then it was decreased by the future rollbacks, if not no persistance was ever done - blockRollbackPersisted.fold(0: BigInt)(_ => blocksRollbacked.head - 1) + blockRollbackPersisted.fold(0: BigInt)(_ => blocksRolledback.head - 1) } trait StubPersistingBlockchainSetup { @@ -313,16 +308,14 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh val appStateStorage = storagesInstance.storages.appStateStorage val stateStorage = stubStateStorage } - val freshBlockchainMetadata = getNewBlockchainMetadata override val blockchainReaderWithStubPersisting = - BlockchainReader(blockchainStoragesWithStubPersisting, freshBlockchainMetadata) + BlockchainReader(blockchainStoragesWithStubPersisting) override val blockchainWriterWithStubPersisting = - BlockchainWriter(blockchainStoragesWithStubPersisting, freshBlockchainMetadata) + BlockchainWriter(blockchainStoragesWithStubPersisting) override val blockchainWithStubPersisting = BlockchainImpl( blockchainStoragesWithStubPersisting, - blockchainReaderWithStubPersisting, - freshBlockchainMetadata + blockchainReaderWithStubPersisting ) blockchainWriterWithStubPersisting.storeBlock(Fixtures.Blocks.Genesis.block)