diff --git a/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala b/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala index 030c47493b..ec54acabd8 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala @@ -85,10 +85,12 @@ abstract class ScenarioSetup(_vm: VMImpl, scenario: BlockchainScenario) { Block(scenario.genesisBlockHeader.toBlockHeader, BlockBody(Nil, Nil)) } + val genesisWeight = ChainWeight.zero.increase(genesisBlock.header) + blockchain .storeBlock(genesisBlock) - .and(blockchain.storeReceipts(genesisBlock.header.hash, Nil)) - .and(blockchain.storeTotalDifficulty(genesisBlock.header.hash, genesisBlock.header.difficulty)) + .and(blockchain.storeReceipts(genesisBlock.hash, Nil)) + .and(blockchain.storeChainWeight(genesisBlock.hash, genesisWeight)) .commit() genesisBlock diff --git a/src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala b/src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala index a152646a96..4e4e639c62 100644 --- a/src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala +++ b/src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala @@ -84,13 +84,13 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumer + 3) } yield { assert( - peer1.bl.getTotalDifficultyByHash(peer1.bl.getBestBlock().hash) == peer2.bl.getTotalDifficultyByHash( + peer1.bl.getChainWeightByHash(peer1.bl.getBestBlock().hash) == peer2.bl.getChainWeightByHash( peer2.bl.getBestBlock().hash ) ) (peer1.bl.getBlockByNumber(blockNumer + 1), peer2.bl.getBlockByNumber(blockNumer + 1)) match { case (Some(blockP1), Some(blockP2)) => - assert(peer1.bl.getTotalDifficultyByHash(blockP1.hash) == peer2.bl.getTotalDifficultyByHash(blockP2.hash)) + assert(peer1.bl.getChainWeightByHash(blockP1.hash) == peer2.bl.getChainWeightByHash(blockP2.hash)) case (_, _) => fail("invalid difficulty validation") } } 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 207a2b1394..0d7adfdb9d 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala @@ -13,7 +13,7 @@ import io.iohk.ethereum.db.components.{RocksDbDataSourceComponent, Storages} import io.iohk.ethereum.db.dataSource.{RocksDbConfig, RocksDbDataSource} import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} import io.iohk.ethereum.db.storage.{AppStateStorage, Namespaces} -import io.iohk.ethereum.domain.{Block, Blockchain, BlockchainImpl} +import io.iohk.ethereum.domain.{Block, Blockchain, BlockchainImpl, ChainWeight} import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo @@ -116,8 +116,9 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu Fixtures.Blocks.Genesis.header.copy(stateRoot = ByteString(MerklePatriciaTrie.EmptyRootHash)), Fixtures.Blocks.Genesis.body ) + val genesisWeight = ChainWeight.zero.increase(genesis.header) - bl.save(genesis, Seq(), genesis.header.difficulty, saveAsBestBlock = true) + bl.save(genesis, Seq(), genesisWeight, saveAsBestBlock = true) lazy val nh = nodeStatusHolder @@ -228,15 +229,15 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu ) } - private def broadcastBlock(block: Block, td: BigInt) = { - broadcasterActor ! BroadcastBlock(NewBlock(block, td)) + private def broadcastBlock(block: Block, weight: ChainWeight) = { + broadcasterActor ! BroadcastBlock(NewBlock(block, weight)) } def getCurrentState(): BlockchainState = { val bestBlock = bl.getBestBlock() val currentWorldState = getMptForBlock(bestBlock) - val currentTd = bl.getTotalDifficultyByHash(bestBlock.hash).get - BlockchainState(bestBlock, currentWorldState, currentTd) + val currentWeight = bl.getChainWeightByHash(bestBlock.hash).get + BlockchainState(bestBlock, currentWorldState, currentWeight) } def startPeer(): Task[Unit] = { @@ -272,16 +273,16 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu } yield () } - private def createChildBlock(parent: Block, parentTd: BigInt, parentWorld: InMemoryWorldStateProxy)( + private def createChildBlock(parent: Block, parentWeight: ChainWeight, parentWorld: InMemoryWorldStateProxy)( updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy - ): (Block, BigInt, InMemoryWorldStateProxy) = { + ): (Block, ChainWeight, InMemoryWorldStateProxy) = { val newBlockNumber = parent.header.number + 1 val newWorld = updateWorldForBlock(newBlockNumber, parentWorld) val newBlock = parent.copy(header = parent.header.copy(parentHash = parent.header.hash, number = newBlockNumber, stateRoot = newWorld.stateRootHash) ) - val newTd = newBlock.header.difficulty + parentTd - (newBlock, newTd, parentWorld) + val newWeight = parentWeight.increase(newBlock.header) + (newBlock, newWeight, parentWorld) } def importBlocksUntil( @@ -292,12 +293,12 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu Task(()) } else { Task { - val currentTd = bl.getTotalDifficultyByHash(block.hash).get + val currentWeight = bl.getChainWeightByHash(block.hash).get val currentWolrd = getMptForBlock(block) - val (newBlock, newTd, newWorld) = createChildBlock(block, currentTd, currentWolrd)(updateWorldForBlock) - bl.save(newBlock, Seq(), newTd, saveAsBestBlock = true) + val (newBlock, newWeight, _) = createChildBlock(block, currentWeight, currentWolrd)(updateWorldForBlock) + bl.save(newBlock, Seq(), newWeight, saveAsBestBlock = true) bl.persistCachedNodes() - broadcastBlock(newBlock, newTd) + broadcastBlock(newBlock, newWeight) }.flatMap(_ => importBlocksUntil(n)(updateWorldForBlock)) } } diff --git a/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala b/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala index 981b3b0e66..0fed272a32 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala @@ -92,12 +92,12 @@ object RegularSyncItSpecUtils { case None => bl.getBestBlock() }).flatMap { block => Task { - val currentTd = bl - .getTotalDifficultyByHash(block.hash) - .getOrElse(throw new RuntimeException(s"block by hash: ${block.hash} doesn't exist")) - val currentWolrd = getMptForBlock(block) - val (newBlock, newTd, newWorld) = createChildBlock(block, currentTd, currentWolrd)(updateWorldForBlock) - broadcastBlock(newBlock, newTd) + val currentWeight = bl + .getChainWeightByHash(block.hash) + .getOrElse(throw new RuntimeException(s"ChainWeight by hash: ${block.hash} doesn't exist")) + val currentWorld = getMptForBlock(block) + val (newBlock, newWeight, _) = createChildBlock(block, currentWeight, currentWorld)(updateWorldForBlock) + broadcastBlock(newBlock, newWeight) } } } @@ -110,12 +110,12 @@ object RegularSyncItSpecUtils { plusDifficulty: BigInt = 0 )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = Task { val block: Block = bl.getBestBlock() - val currentTd = bl - .getTotalDifficultyByHash(block.hash) - .getOrElse(throw new RuntimeException(s"block by hash: ${block.hash} doesn't exist")) + val currentWeight = bl + .getChainWeightByHash(block.hash) + .getOrElse(throw new RuntimeException(s"ChainWeight by hash: ${block.hash} doesn't exist")) val currentWolrd = getMptForBlock(block) - val (newBlock, newTd, newWorld) = - createChildBlock(block, currentTd, currentWolrd, plusDifficulty)(updateWorldForBlock) + val (newBlock, _, _) = + createChildBlock(block, currentWeight, currentWolrd, plusDifficulty)(updateWorldForBlock) regularSync ! SyncProtocol.MinedBlock(newBlock) } @@ -139,18 +139,18 @@ object RegularSyncItSpecUtils { ) } - private def broadcastBlock(block: Block, td: BigInt) = { - broadcasterActor ! BroadcastBlock(NewBlock(block, td)) + private def broadcastBlock(block: Block, weight: ChainWeight) = { + broadcasterActor ! BroadcastBlock(NewBlock(block, weight)) } private def createChildBlock( parent: Block, - parentTd: BigInt, + parentWeight: ChainWeight, parentWorld: InMemoryWorldStateProxy, plusDifficulty: BigInt = 0 )( updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy - ): (Block, BigInt, InMemoryWorldStateProxy) = { + ): (Block, ChainWeight, InMemoryWorldStateProxy) = { val newBlockNumber = parent.header.number + 1 val newWorld = updateWorldForBlock(newBlockNumber, parentWorld) val newBlock = parent.copy(header = @@ -161,8 +161,8 @@ object RegularSyncItSpecUtils { difficulty = plusDifficulty + parent.header.difficulty ) ) - val newTd = newBlock.header.difficulty + parentTd - (newBlock, newTd, parentWorld) + val newWeight = parentWeight.increase(newBlock.header) + (newBlock, newWeight, parentWorld) } } diff --git a/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala b/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala index b01ec468c4..2c85bfde8f 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.sync.util import java.net.{InetSocketAddress, ServerSocket} -import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.{Block, ChainWeight} import io.iohk.ethereum.ledger.InMemoryWorldStateProxy object SyncCommonItSpec { @@ -17,5 +17,9 @@ object SyncCommonItSpec { } } - final case class BlockchainState(bestBlock: Block, currentWorldState: InMemoryWorldStateProxy, currentTd: BigInt) + final case class BlockchainState( + bestBlock: Block, + currentWorldState: InMemoryWorldStateProxy, + currentWeight: ChainWeight + ) } 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 1ac08d1d2f..396d779fe8 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala @@ -148,13 +148,13 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain { override def storeEvmCode(hash: ByteString, evmCode: ByteString): DataSourceBatchUpdate = ??? - override def storeTotalDifficulty(blockhash: ByteString, totalDifficulty: BigInt): DataSourceBatchUpdate = ??? + override def storeChainWeight(blockhash: ByteString, chainWeight: ChainWeight): DataSourceBatchUpdate = ??? override def saveNode(nodeHash: NodeHash, nodeEncoded: NodeEncoded, blockNumber: BigInt): Unit = ??? override def removeBlock(hash: ByteString, withState: Boolean = true): Unit = ??? - override def getTotalDifficultyByHash(blockhash: ByteString): Option[BigInt] = ??? + override def getChainWeightByHash(blockhash: ByteString): Option[ChainWeight] = ??? override def getEvmCodeByHash(hash: ByteString): Option[ByteString] = ??? @@ -194,7 +194,7 @@ class BlockchainMock(genesisHash: ByteString) extends Blockchain { def getBestBlock(): Block = ??? - override def save(block: Block, receipts: Seq[Receipt], totalDifficulty: BigInt, saveAsBestBlock: Boolean): Unit = ??? + override def save(block: Block, receipts: Seq[Receipt], weight: ChainWeight, saveAsBestBlock: Boolean): Unit = ??? override def getStateStorage: StateStorage = ??? diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/FixtureProvider.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/FixtureProvider.scala index 72875eeb5f..07734114d2 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/FixtureProvider.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/FixtureProvider.scala @@ -44,7 +44,7 @@ object FixtureProvider { override val blockHeadersStorage: BlockHeadersStorage = new BlockHeadersStorage(dataSource) override val blockNumberMappingStorage: BlockNumberMappingStorage = new BlockNumberMappingStorage(dataSource) override val blockBodiesStorage: BlockBodiesStorage = new BlockBodiesStorage(dataSource) - override val totalDifficultyStorage: TotalDifficultyStorage = new TotalDifficultyStorage(dataSource) + override val chainWeightStorage: ChainWeightStorage = new ChainWeightStorage(dataSource) override val transactionMappingStorage: TransactionMappingStorage = new TransactionMappingStorage(dataSource) override val nodeStorage: NodeStorage = new NodeStorage(dataSource) override val cachedNodeStorage: CachedNodeStorage = new CachedNodeStorage(nodeStorage, caches.nodeCache) diff --git a/src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala b/src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala index bfd6c096d4..50d68f3923 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala @@ -118,7 +118,12 @@ class GenesisDataLoader(blockchain: Blockchain, blockchainConfig: BlockchainConf case None => storage.persist() stateStorage.forcePersist(GenesisDataLoad) - blockchain.save(Block(header, BlockBody(Nil, Nil)), Nil, header.difficulty, saveAsBestBlock = true) + blockchain.save( + Block(header, BlockBody(Nil, Nil)), + Nil, + ChainWeight.totalDifficultyOnly(header.difficulty), + saveAsBestBlock = true + ) Success(()) } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcast.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcast.scala index 736bf4f9d2..c395339205 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcast.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcast.scala @@ -36,8 +36,7 @@ class BlockBroadcast(val etcPeerManager: ActorRef, syncConfig: SyncConfig) { private def shouldSendNewBlock(newBlock: NewBlock, peerInfo: PeerInfo): Boolean = newBlock.block.header.number > peerInfo.maxBlockNumber || - newBlock.totalDifficulty > peerInfo.totalDifficulty || - newBlock.latestCheckpointNumber > peerInfo.latestCheckpointNumber + newBlock.chainWeight > peerInfo.chainWeight private def broadcastNewBlock(newBlock: NewBlock, peers: Set[Peer]): Unit = obtainRandomPeerSubset(peers).foreach { peer => diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/FastSync.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/FastSync.scala index 94ff9c5c0e..2954a502e0 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/FastSync.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/FastSync.scala @@ -341,8 +341,8 @@ class FastSync( val header = headers.head processHeader(header, peer) match { case Left(result) => result - case Right(headerAndDif) => - updateSyncState(headerAndDif._1, headerAndDif._2) + case Right((header, weight)) => + updateSyncState(header, weight) if (header.number == syncState.safeDownloadTarget) { ImportedPivotBlock } else { @@ -371,10 +371,10 @@ class FastSync( } } - private def updateSyncState(header: BlockHeader, parentTd: BigInt): Unit = { + private def updateSyncState(header: BlockHeader, parentWeight: ChainWeight): Unit = { blockchain .storeBlockHeader(header) - .and(blockchain.storeTotalDifficulty(header.hash, parentTd + header.difficulty)) + .and(blockchain.storeChainWeight(header.hash, parentWeight.increase(header))) .commit() if (header.number > syncState.bestBlockHeaderNumber) { @@ -391,14 +391,17 @@ class FastSync( syncState = syncState.updateNextBlockToValidate(header, K, X) } - private def processHeader(header: BlockHeader, peer: Peer): Either[HeaderProcessingResult, (BlockHeader, BigInt)] = + private def processHeader( + header: BlockHeader, + peer: Peer + ): Either[HeaderProcessingResult, (BlockHeader, ChainWeight)] = for { validatedHeader <- validateHeader(header, peer) - parentDifficulty <- getParentDifficulty(header) - } yield (validatedHeader, parentDifficulty) + parentWeight <- getParentChainWeight(header) + } yield (validatedHeader, parentWeight) - private def getParentDifficulty(header: BlockHeader) = { - blockchain.getTotalDifficultyByHash(header.parentHash).toRight(ParentDifficultyNotFound(header)) + private def getParentChainWeight(header: BlockHeader) = { + blockchain.getChainWeightByHash(header.parentHash).toRight(ParentChainWeightNotFound(header)) } private def handleRewind(header: BlockHeader, peer: Peer, N: Int): Unit = { @@ -419,11 +422,11 @@ class FastSync( private def handleBlockHeaders(peer: Peer, headers: Seq[BlockHeader]) = { if (checkHeadersChain(headers)) { processHeaders(peer, headers) match { - case ParentDifficultyNotFound(header) => + case ParentChainWeightNotFound(header) => // We could end in wrong fork and get blocked so we should rewind our state a little // we blacklist peer just in case we got malicious peer which would send us bad blocks, forcing us to rollback // to genesis - log.warning("Parent difficulty not found for block {}, not processing rest of headers", header.idTag) + log.warning("Parent chain weight not found for block {}, not processing rest of headers", header.idTag) handleRewind(header, peer, syncConfig.fastSyncBlockValidationN) case HeadersProcessingFinished => processSyncing() @@ -890,7 +893,7 @@ object FastSync { sealed abstract class HeaderProcessingResult case object HeadersProcessingFinished extends HeaderProcessingResult - case class ParentDifficultyNotFound(header: BlockHeader) extends HeaderProcessingResult + case class ParentChainWeightNotFound(header: BlockHeader) extends HeaderProcessingResult case class ValidationFailed(header: BlockHeader, peer: Peer) extends HeaderProcessingResult case object ImportedPivotBlock extends HeaderProcessingResult diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/PeersClient.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/PeersClient.scala index d5cf824434..ac823f4916 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/PeersClient.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/PeersClient.scala @@ -161,12 +161,12 @@ object PeersClient { def bestPeer(peersToDownloadFrom: Map[Peer, PeerInfo]): Option[Peer] = { val peersToUse = peersToDownloadFrom - .collect { case (ref, PeerInfo(_, totalDifficulty, latestChkp, true, _, _)) => - (ref, totalDifficulty, latestChkp) + .collect { case (ref, PeerInfo(_, chainWeight, true, _, _)) => + (ref, chainWeight) } if (peersToUse.nonEmpty) { - val (peer, _, _) = peersToUse.maxBy { case (_, td, latestChkp) => latestChkp -> td } + val (peer, _) = peersToUse.maxBy(_._2) Some(peer) } else { None diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelector.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelector.scala index 50150ceae2..2c3f10e93b 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelector.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelector.scala @@ -173,9 +173,8 @@ class PivotBlockSelector( } private def collectVoters: ElectionDetails = { - val peersUsedToChooseTarget = peersToDownloadFrom.collect { - case (peer, PeerInfo(_, _, _, true, maxBlockNumber, _)) => - (peer, maxBlockNumber) + val peersUsedToChooseTarget = peersToDownloadFrom.collect { case (peer, PeerInfo(_, _, true, maxBlockNumber, _)) => + (peer, maxBlockNumber) } val peersSortedByBestNumber = peersUsedToChooseTarget.toList.sortBy { case (_, number) => -number } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerActor.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerActor.scala index b732c69fac..307315ba9f 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerActor.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerActor.scala @@ -98,7 +98,8 @@ class SyncStateSchedulerActor( case Some((startSignal: StartSyncingTo, sender)) => val initStats = ProcessingStatistics().addSaved(result.writtenElements) startSyncing(startSignal.stateRoot, startSignal.blockNumber, initStats, sender) - case Some((restartSignal: RestartRequested.type, sender)) => + case Some((RestartRequested, sender)) => + // TODO: are we testing this path? sender ! WaitingForNewTargetBlock context.become(idle(ProcessingStatistics().addSaved(result.writtenElements))) case _ => diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala index 5be786a039..306a27305e 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala @@ -192,7 +192,7 @@ class BlockFetcher( supervisor ! ProgressProtocol.GotNewBlock(newState.knownTop) fetchBlocks(newState) - case MessageFromPeer(NewBlock(block, _, _), peerId) => + case MessageFromPeer(NewBlock(_, block, _), peerId) => val newBlockNr = block.number val nextExpectedBlock = state.lastFullBlockNumber + 1 diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala index bd226d9278..dac4d11ec3 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala @@ -9,17 +9,17 @@ import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcasterActor.BroadcastB import io.iohk.ethereum.blockchain.sync.regular.RegularSync.ProgressProtocol import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.crypto.{ECDSASignature, kec256} -import io.iohk.ethereum.domain.{Block, Blockchain, Checkpoint, SignedTransaction} +import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger._ import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingNodeException import io.iohk.ethereum.network.PeerId -import io.iohk.ethereum.network.p2p.messages.CommonMessages.{NewBlock, NewBlock63, NewBlock64} +import io.iohk.ethereum.network.p2p.messages.CommonMessages.NewBlock import io.iohk.ethereum.ommers.OmmersPool.AddOmmers import io.iohk.ethereum.transactions.PendingTransactionsManager import io.iohk.ethereum.transactions.PendingTransactionsManager.{AddUncheckedTransactions, RemoveTransactions} -import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils} import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.utils.FunctorOps._ +import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils} import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} @@ -246,8 +246,8 @@ class BlockImporter( .tap(importMessages.messageForImportResult _ andThen doLog) .tap { case BlockImportedToTop(importedBlocksData) => - val (blocks, tds) = importedBlocksData.map(data => (data.block, data.td)).unzip - broadcastBlocks(blocks, tds) + val (blocks, weights) = importedBlocksData.map(data => (data.block, data.weight)).unzip + broadcastBlocks(blocks, weights) updateTxPool(importedBlocksData.map(_.block), Seq.empty) supervisor ! ProgressProtocol.ImportedBlock(block.number, internally) @@ -257,9 +257,9 @@ class BlockImporter( case UnknownParent => () // This is normal when receiving broadcast blocks - case ChainReorganised(oldBranch, newBranch, totalDifficulties) => + case ChainReorganised(oldBranch, newBranch, weights) => updateTxPool(newBranch, oldBranch) - broadcastBlocks(newBranch, totalDifficulties) + broadcastBlocks(newBranch, weights) newBranch.lastOption match { case Some(newBlock) => supervisor ! ProgressProtocol.ImportedBlock(newBlock.number, internally) case None => () @@ -280,22 +280,12 @@ class BlockImporter( } } - private def broadcastBlocks( - blocks: List[Block], - totalDifficulties: List[BigInt] - ): Unit = { - val constructNewBlock = { - //FIXME: instead of choosing the message version based on block we should rely on the receiving - // peer's `Capability`. To be addressed in ETCM-280 - if (blocks.lastOption.exists(_.number < blockchainConfig.ecip1097BlockNumber)) - NewBlock63.apply _ - else - //FIXME: we should use checkpoint number corresponding to the block we're broadcasting. This will be addressed - // in ETCM-263 by using ChainWeight for that block - NewBlock64.apply(_, _, blockchain.getLatestCheckpointBlockNumber()) + private def broadcastBlocks(blocks: List[Block], weights: List[ChainWeight]): Unit = { + val newBlocks = (blocks, weights).mapN(NewBlock(_, _)).map { nb => + if (nb.block.number < blockchainConfig.ecip1097BlockNumber) nb.as63 else nb.as64 } - val newBlocks = (blocks, totalDifficulties).mapN(constructNewBlock) + //TODO: use the target PeerInfo to determine code and encoding when sending the message: ETCM-280 broadcastNewBlocks(newBlocks) } diff --git a/src/main/scala/io/iohk/ethereum/db/components/Storages.scala b/src/main/scala/io/iohk/ethereum/db/components/Storages.scala index b91cb528f4..05d7ecfa5a 100644 --- a/src/main/scala/io/iohk/ethereum/db/components/Storages.scala +++ b/src/main/scala/io/iohk/ethereum/db/components/Storages.scala @@ -36,8 +36,8 @@ object Storages { override val evmCodeStorage: EvmCodeStorage = new EvmCodeStorage(dataSource) - override val totalDifficultyStorage: TotalDifficultyStorage = - new TotalDifficultyStorage(dataSource) + override val chainWeightStorage: ChainWeightStorage = + new ChainWeightStorage(dataSource) override val appStateStorage: AppStateStorage = new AppStateStorage(dataSource) diff --git a/src/main/scala/io/iohk/ethereum/db/components/StoragesComponent.scala b/src/main/scala/io/iohk/ethereum/db/components/StoragesComponent.scala index 83a4487b0b..fe5fe65cb5 100644 --- a/src/main/scala/io/iohk/ethereum/db/components/StoragesComponent.scala +++ b/src/main/scala/io/iohk/ethereum/db/components/StoragesComponent.scala @@ -22,7 +22,7 @@ trait StoragesComponent { val evmCodeStorage: EvmCodeStorage - val totalDifficultyStorage: TotalDifficultyStorage + val chainWeightStorage: ChainWeightStorage val appStateStorage: AppStateStorage diff --git a/src/main/scala/io/iohk/ethereum/db/storage/BlockBodiesStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/BlockBodiesStorage.scala index 2e3f7aea70..479621634f 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/BlockBodiesStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/BlockBodiesStorage.scala @@ -1,13 +1,11 @@ package io.iohk.ethereum.db.storage -import java.nio.ByteBuffer - import akka.util.ByteString import boopickle.Default.{Pickle, Unpickle} import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.storage.BlockBodiesStorage.BlockBodyHash import io.iohk.ethereum.domain.BlockBody -import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes +import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} import io.iohk.ethereum.utils.Picklers._ /** @@ -28,7 +26,7 @@ class BlockBodiesStorage(val dataSource: DataSource) extends TransactionalKeyVal compactPickledBytes(Pickle.intoBytes(blockBody)) override def valueDeserializer: IndexedSeq[Byte] => BlockBody = - bytes => Unpickle[BlockBody].fromBytes(ByteBuffer.wrap(bytes.toArray[Byte])) + byteSequenceToBuffer _ andThen Unpickle[BlockBody].fromBytes } object BlockBodiesStorage { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/BlockHeadersStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/BlockHeadersStorage.scala index 230489499e..c2ca24e633 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/BlockHeadersStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/BlockHeadersStorage.scala @@ -1,14 +1,12 @@ package io.iohk.ethereum.db.storage -import java.nio.ByteBuffer - import akka.util.ByteString import boopickle.Default.{Pickle, Unpickle} import boopickle.DefaultBasic._ import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.storage.BlockHeadersStorage.BlockHeaderHash import io.iohk.ethereum.domain.BlockHeader -import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes +import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} import io.iohk.ethereum.utils.Picklers._ /** @@ -31,7 +29,8 @@ class BlockHeadersStorage(val dataSource: DataSource) blockHeader => compactPickledBytes(Pickle.intoBytes(blockHeader)) override def valueDeserializer: IndexedSeq[Byte] => BlockHeader = - bytes => Unpickle[BlockHeader].fromBytes(ByteBuffer.wrap(bytes.toArray[Byte])) + // TODO: consider reusing this formula in other storages: ETCM-322 + byteSequenceToBuffer _ andThen Unpickle[BlockHeader].fromBytes } object BlockHeadersStorage { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/ChainWeightStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/ChainWeightStorage.scala new file mode 100644 index 0000000000..4f918320a2 --- /dev/null +++ b/src/main/scala/io/iohk/ethereum/db/storage/ChainWeightStorage.scala @@ -0,0 +1,26 @@ +package io.iohk.ethereum.db.storage + +import akka.util.ByteString +import boopickle.Default._ +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.storage.ChainWeightStorage._ +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} + +/** + * This class is used to store the ChainWeight of blocks, by using: + * Key: hash of the block + * Value: ChainWeight + */ +class ChainWeightStorage(val dataSource: DataSource) extends TransactionalKeyValueStorage[BlockHash, ChainWeight] { + val namespace: IndexedSeq[Byte] = Namespaces.ChainWeightNamespace + val keySerializer: BlockHash => ByteString = identity + val keyDeserializer: IndexedSeq[Byte] => BlockHash = bytes => ByteString(bytes: _*) + val valueSerializer: ChainWeight => IndexedSeq[Byte] = Pickle.intoBytes[ChainWeight] _ andThen compactPickledBytes + val valueDeserializer: IndexedSeq[Byte] => ChainWeight = + byteSequenceToBuffer _ andThen Unpickle[ChainWeight].fromBytes +} + +object ChainWeightStorage { + type BlockHash = ByteString +} diff --git a/src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala b/src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala index 58b8ebf52c..f8550942db 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala @@ -6,7 +6,7 @@ object Namespaces { val BodyNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('b'.toByte) val NodeNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('n'.toByte) val CodeNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('c'.toByte) - val TotalDifficultyNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('t'.toByte) + val ChainWeightNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('w'.toByte) val AppStateNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('s'.toByte) val KnownNodesNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('k'.toByte) val HeightsNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('i'.toByte) @@ -19,7 +19,7 @@ object Namespaces { BodyNamespace, NodeNamespace, CodeNamespace, - TotalDifficultyNamespace, + ChainWeightNamespace, AppStateNamespace, KnownNodesNamespace, HeightsNamespace, diff --git a/src/main/scala/io/iohk/ethereum/db/storage/ReceiptStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/ReceiptStorage.scala index e1d75fac57..c6819f31e8 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/ReceiptStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/ReceiptStorage.scala @@ -1,13 +1,11 @@ package io.iohk.ethereum.db.storage -import java.nio.ByteBuffer - import akka.util.ByteString import boopickle.Default.{Pickle, Unpickle} import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.storage.ReceiptStorage._ import io.iohk.ethereum.domain.{Address, SuccessOutcome, _} -import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes +import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} import boopickle.DefaultBasic._ /** @@ -23,13 +21,14 @@ class ReceiptStorage(val dataSource: DataSource) extends TransactionalKeyValueSt override def keySerializer: BlockHash => IndexedSeq[Byte] = _.toIndexedSeq + // FIXME: perhaps we should just operate on ByteString to avoid such strange conversions: ETCM-322 override def keyDeserializer: IndexedSeq[Byte] => BlockHash = k => ByteString.fromArrayUnsafe(k.toArray) override def valueSerializer: ReceiptSeq => IndexedSeq[Byte] = receipts => compactPickledBytes(Pickle.intoBytes(receipts)) override def valueDeserializer: IndexedSeq[Byte] => ReceiptSeq = - bytes => Unpickle[Seq[Receipt]].fromBytes(ByteBuffer.wrap(bytes.toArray[Byte])) + byteSequenceToBuffer _ andThen Unpickle[Seq[Receipt]].fromBytes } object ReceiptStorage { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/TotalDifficultyStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/TotalDifficultyStorage.scala deleted file mode 100644 index fb11c7632e..0000000000 --- a/src/main/scala/io/iohk/ethereum/db/storage/TotalDifficultyStorage.scala +++ /dev/null @@ -1,24 +0,0 @@ -package io.iohk.ethereum.db.storage - -import akka.util.ByteString -import io.iohk.ethereum.db.dataSource.DataSource -import io.iohk.ethereum.db.storage.TotalDifficultyStorage._ - -/** - * This class is used to store the total difficulty of blocks, by using: - * Key: hash of the block - * Value: the total difficulty - */ -class TotalDifficultyStorage(val dataSource: DataSource) - extends TransactionalKeyValueStorage[BlockHash, TotalDifficulty] { - val namespace: IndexedSeq[Byte] = Namespaces.TotalDifficultyNamespace - def keySerializer: BlockHash => IndexedSeq[Byte] = _.toIndexedSeq - def keyDeserializer: IndexedSeq[Byte] => BlockHash = k => ByteString.fromArrayUnsafe(k.toArray) - def valueSerializer: TotalDifficulty => IndexedSeq[Byte] = _.toByteArray.toIndexedSeq - def valueDeserializer: IndexedSeq[Byte] => BigInt = (valueBytes: IndexedSeq[Byte]) => BigInt(1, valueBytes.toArray) -} - -object TotalDifficultyStorage { - type BlockHash = ByteString - type TotalDifficulty = BigInt -} diff --git a/src/main/scala/io/iohk/ethereum/db/storage/TransactionMappingStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/TransactionMappingStorage.scala index fe9ca7f7cd..71de2cf870 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/TransactionMappingStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/TransactionMappingStorage.scala @@ -1,11 +1,9 @@ package io.iohk.ethereum.db.storage -import java.nio.ByteBuffer - import akka.util.ByteString import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.storage.TransactionMappingStorage.{TransactionLocation, TxHash} -import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes +import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} import boopickle.Default._ class TransactionMappingStorage(val dataSource: DataSource) @@ -16,7 +14,7 @@ class TransactionMappingStorage(val dataSource: DataSource) def keyDeserializer: IndexedSeq[Byte] => TxHash = identity def valueSerializer: TransactionLocation => IndexedSeq[Byte] = tl => compactPickledBytes(Pickle.intoBytes(tl)) def valueDeserializer: IndexedSeq[Byte] => TransactionLocation = - bytes => Unpickle[TransactionLocation].fromBytes(ByteBuffer.wrap(bytes.toArray[Byte])) + byteSequenceToBuffer _ andThen Unpickle[TransactionLocation].fromBytes implicit val byteStringPickler: Pickler[ByteString] = transformPickler[ByteString, Array[Byte]](ByteString(_))(_.toArray[Byte]) diff --git a/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala b/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala index 0d2b33958b..296176bf63 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala @@ -113,14 +113,14 @@ trait Blockchain { def getMptNodeByHash(hash: ByteString): Option[MptNode] /** - * Returns the total difficulty based on a block hash - * @param blockhash - * @return total difficulty if found + * Looks up ChainWeight for a given chain + * @param blockhash Hash of top block in the chain + * @return ChainWeight if found */ - def getTotalDifficultyByHash(blockhash: ByteString): Option[BigInt] + def getChainWeightByHash(blockhash: ByteString): Option[ChainWeight] - def getTotalDifficultyByNumber(blockNumber: BigInt): Option[BigInt] = - getHashByBlockNumber(blockNumber).flatMap(getTotalDifficultyByHash) + def getChainWeightByNumber(blockNumber: BigInt): Option[ChainWeight] = + getHashByBlockNumber(blockNumber).flatMap(getChainWeightByHash) def getTransactionLocation(txHash: ByteString): Option[TransactionLocation] @@ -131,10 +131,10 @@ trait Blockchain { def getLatestCheckpointBlockNumber(): BigInt /** - * Persists full block along with receipts and total difficulty + * Persists full block along with receipts and chain weight * @param saveAsBestBlock - whether to save the block's number as current best block */ - def save(block: Block, receipts: Seq[Receipt], totalDifficulty: BigInt, saveAsBestBlock: Boolean): Unit + def save(block: Block, receipts: Seq[Receipt], chainWeight: ChainWeight, saveAsBestBlock: Boolean): Unit /** * Persists a block in the underlying Blockchain Database @@ -162,7 +162,7 @@ trait Blockchain { def storeEvmCode(hash: ByteString, evmCode: ByteString): DataSourceBatchUpdate - def storeTotalDifficulty(blockhash: ByteString, totalDifficulty: BigInt): DataSourceBatchUpdate + def storeChainWeight(blockhash: ByteString, weight: ChainWeight): DataSourceBatchUpdate def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit @@ -211,7 +211,7 @@ class BlockchainImpl( protected val pruningMode: PruningMode, protected val nodeStorage: NodeStorage, protected val cachedNodeStorage: CachedNodeStorage, - protected val totalDifficultyStorage: TotalDifficultyStorage, + protected val chainWeightStorage: ChainWeightStorage, protected val transactionMappingStorage: TransactionMappingStorage, protected val appStateStorage: AppStateStorage, protected val stateStorage: StateStorage @@ -234,7 +234,7 @@ class BlockchainImpl( override def getEvmCodeByHash(hash: ByteString): Option[ByteString] = evmCodeStorage.get(hash) - override def getTotalDifficultyByHash(blockhash: ByteString): Option[BigInt] = totalDifficultyStorage.get(blockhash) + override def getChainWeightByHash(blockhash: ByteString): Option[ChainWeight] = chainWeightStorage.get(blockhash) override def getBestBlockNumber(): BigInt = { val bestBlockNum = appStateStorage.getBestBlockNumber() @@ -286,10 +286,10 @@ class BlockchainImpl( .commit() } - def save(block: Block, receipts: Seq[Receipt], totalDifficulty: BigInt, saveAsBestBlock: Boolean): Unit = { + def save(block: Block, receipts: Seq[Receipt], weight: ChainWeight, saveAsBestBlock: Boolean): Unit = { storeBlock(block) .and(storeReceipts(block.header.hash, receipts)) - .and(storeTotalDifficulty(block.header.hash, totalDifficulty)) + .and(storeChainWeight(block.header.hash, weight)) .commit() // not transactional part @@ -341,8 +341,8 @@ class BlockchainImpl( bestKnownBlockAndLatestCheckpoint.set(BestBlockLatestCheckpointNumbers(number, latestCheckpointNumber)) } - def storeTotalDifficulty(blockhash: ByteString, td: BigInt): DataSourceBatchUpdate = - totalDifficultyStorage.put(blockhash, td) + def storeChainWeight(blockhash: ByteString, weight: ChainWeight): DataSourceBatchUpdate = + chainWeightStorage.put(blockhash, weight) def saveNode(nodeHash: NodeHash, nodeEncoded: NodeEncoded, blockNumber: BigInt): Unit = { stateStorage.saveNode(nodeHash, nodeEncoded, blockNumber) @@ -401,7 +401,7 @@ class BlockchainImpl( blockHeadersStorage .remove(blockHash) .and(blockBodiesStorage.remove(blockHash)) - .and(totalDifficultyStorage.remove(blockHash)) + .and(chainWeightStorage.remove(blockHash)) .and(receiptStorage.remove(blockHash)) .and(maybeTxList.fold(transactionMappingStorage.emptyBatchUpdate)(removeTxsLocations)) .and(blockNumberMappingUpdates) @@ -513,7 +513,7 @@ trait BlockchainStorages { val blockNumberMappingStorage: BlockNumberMappingStorage val receiptStorage: ReceiptStorage val evmCodeStorage: EvmCodeStorage - val totalDifficultyStorage: TotalDifficultyStorage + val chainWeightStorage: ChainWeightStorage val transactionMappingStorage: TransactionMappingStorage val nodeStorage: NodeStorage val pruningMode: PruningMode @@ -533,7 +533,7 @@ object BlockchainImpl { pruningMode = storages.pruningMode, nodeStorage = storages.nodeStorage, cachedNodeStorage = storages.cachedNodeStorage, - totalDifficultyStorage = storages.totalDifficultyStorage, + chainWeightStorage = storages.chainWeightStorage, transactionMappingStorage = storages.transactionMappingStorage, appStateStorage = storages.appStateStorage, stateStorage = storages.stateStorage diff --git a/src/main/scala/io/iohk/ethereum/domain/ChainWeight.scala b/src/main/scala/io/iohk/ethereum/domain/ChainWeight.scala new file mode 100644 index 0000000000..7adba7db67 --- /dev/null +++ b/src/main/scala/io/iohk/ethereum/domain/ChainWeight.scala @@ -0,0 +1,33 @@ +package io.iohk.ethereum.domain + +object ChainWeight { + //FIXME: a shorter name? + def totalDifficultyOnly(td: BigInt): ChainWeight = + ChainWeight(0, td) + + val zero: ChainWeight = + ChainWeight(0, 0) +} + +case class ChainWeight( + lastCheckpointNumber: BigInt, + totalDifficulty: BigInt +) extends Ordered[ChainWeight] { + + override def compare(that: ChainWeight): Int = + this.asTuple.compare(that.asTuple) + + def increase(header: BlockHeader): ChainWeight = { + val isNewerCheckpoint = header.hasCheckpoint && header.number > lastCheckpointNumber + val checkpointNum = if (isNewerCheckpoint) header.number else lastCheckpointNumber + ChainWeight(checkpointNum, totalDifficulty + header.difficulty) + } + + def asTuple: (BigInt, BigInt) = + ChainWeight.unapply(this).get + + //Test API + + def increaseTotalDifficulty(td: BigInt): ChainWeight = + copy(totalDifficulty = totalDifficulty + td) +} diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala index fed9a8803e..c646968ec5 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala @@ -1,8 +1,9 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString +import cats.implicits._ import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader} +import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} case class CheckpointResponse(signatures: Seq[ECDSASignature], signers: Seq[ByteString]) @@ -19,6 +20,7 @@ case class BlockResponse( miner: Option[ByteString], difficulty: BigInt, totalDifficulty: Option[BigInt], + lastCheckpointNumber: Option[BigInt], extraData: ByteString, size: BigInt, gasLimit: BigInt, @@ -28,13 +30,18 @@ case class BlockResponse( treasuryOptOut: Option[Boolean], transactions: Either[Seq[ByteString], Seq[TransactionResponse]], uncles: Seq[ByteString] -) +) { + val chainWeight: Option[ChainWeight] = for { + lcn <- lastCheckpointNumber + td <- totalDifficulty + } yield ChainWeight(lcn, td) +} object BlockResponse { def apply( block: Block, - totalDifficulty: Option[BigInt] = None, + weight: Option[ChainWeight] = None, fullTxs: Boolean = false, pendingBlock: Boolean = false ): BlockResponse = { @@ -52,6 +59,8 @@ object BlockResponse { CheckpointResponse(checkpoint.signatures, signers) } + val (lcn, td) = weight.map(_.asTuple).separate + BlockResponse( number = block.header.number, hash = if (pendingBlock) None else Some(block.header.hash), @@ -64,7 +73,8 @@ object BlockResponse { receiptsRoot = block.header.receiptsRoot, miner = if (pendingBlock) None else Some(block.header.beneficiary), difficulty = block.header.difficulty, - totalDifficulty = totalDifficulty, + totalDifficulty = td, + lastCheckpointNumber = lcn, extraData = block.header.extraData, size = Block.size(block), gasLimit = block.header.gasLimit, @@ -77,10 +87,10 @@ object BlockResponse { ) } - def apply(blockHeader: BlockHeader, totalDifficulty: Option[BigInt], pendingBlock: Boolean): BlockResponse = + def apply(blockHeader: BlockHeader, weight: Option[ChainWeight], pendingBlock: Boolean): BlockResponse = BlockResponse( block = Block(blockHeader, BlockBody(Nil, Nil)), - totalDifficulty = totalDifficulty, + weight = weight, pendingBlock = pendingBlock ) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala index 11b7e50cde..d76f278793 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala @@ -277,9 +277,9 @@ class EthService( def getByBlockHash(request: BlockByBlockHashRequest): ServiceResponse[BlockByBlockHashResponse] = Task { val BlockByBlockHashRequest(blockHash, fullTxs) = request val blockOpt = blockchain.getBlockByHash(blockHash) - val totalDifficulty = blockchain.getTotalDifficultyByHash(blockHash) + val weight = blockchain.getChainWeightByHash(blockHash) - val blockResponseOpt = blockOpt.map(block => BlockResponse(block, totalDifficulty, fullTxs = fullTxs)) + val blockResponseOpt = blockOpt.map(block => BlockResponse(block, weight, fullTxs = fullTxs)) Right(BlockByBlockHashResponse(blockResponseOpt)) } @@ -292,8 +292,8 @@ class EthService( def getBlockByNumber(request: BlockByNumberRequest): ServiceResponse[BlockByNumberResponse] = Task { val BlockByNumberRequest(blockParam, fullTxs) = request val blockResponseOpt = resolveBlock(blockParam).toOption.map { case ResolvedBlock(block, pending) => - val totalDifficulty = blockchain.getTotalDifficultyByHash(block.header.hash) - BlockResponse(block, totalDifficulty, fullTxs = fullTxs, pendingBlock = pending.isDefined) + val weight = blockchain.getChainWeightByHash(block.header.hash) + BlockResponse(block, weight, fullTxs = fullTxs, pendingBlock = pending.isDefined) } Right(BlockByNumberResponse(blockResponseOpt)) } @@ -438,11 +438,11 @@ class EthService( else None } - val totalDifficulty = uncleHeaderOpt.flatMap(uncleHeader => blockchain.getTotalDifficultyByHash(uncleHeader.hash)) + val weight = uncleHeaderOpt.flatMap(uncleHeader => blockchain.getChainWeightByHash(uncleHeader.hash)) //The block in the response will not have any txs or uncles val uncleBlockResponseOpt = uncleHeaderOpt.map { uncleHeader => - BlockResponse(blockHeader = uncleHeader, totalDifficulty = totalDifficulty, pendingBlock = false) + BlockResponse(blockHeader = uncleHeader, weight = weight, pendingBlock = false) } Right(UncleByBlockHashAndIndexResponse(uncleBlockResponseOpt)) } @@ -461,13 +461,13 @@ class EthService( .flatMap { case ResolvedBlock(block, pending) => if (uncleIndex >= 0 && uncleIndex < block.body.uncleNodesList.size) { val uncleHeader = block.body.uncleNodesList.apply(uncleIndex.toInt) - val totalDifficulty = blockchain.getTotalDifficultyByHash(uncleHeader.hash) + val weight = blockchain.getChainWeightByHash(uncleHeader.hash) //The block in the response will not have any txs or uncles Some( BlockResponse( blockHeader = uncleHeader, - totalDifficulty = totalDifficulty, + weight = weight, pendingBlock = pending.isDefined ) ) diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala index 8363aa3557..94eff9d5b7 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala @@ -121,40 +121,38 @@ class BlockExecution( /** Executes and validates a list of blocks, storing the results in the blockchain. * * @param blocks blocks to be executed - * @param parentTd transaction difficulty of the parent + * @param parentChainWeight parent weight * * @return a list of blocks in incremental order that were correctly executed and an optional [[BlockExecutionError]] */ def executeAndValidateBlocks( blocks: List[Block], - parentTd: BigInt + parentChainWeight: ChainWeight ): (List[BlockData], Option[BlockExecutionError]) = { @tailrec def go( executedBlocksDecOrder: List[BlockData], remainingBlocksIncOrder: List[Block], - parentTd: BigInt, + parentWeight: ChainWeight, error: Option[BlockExecutionError] ): (List[BlockData], Option[BlockExecutionError]) = { if (remainingBlocksIncOrder.isEmpty) { (executedBlocksDecOrder.reverse, None) - } else if (error.isDefined) { - (executedBlocksDecOrder.reverse, error) } else { val blockToExecute = remainingBlocksIncOrder.head executeAndValidateBlock(blockToExecute, alreadyValidated = true) match { case Right(receipts) => - val td = parentTd + blockToExecute.header.difficulty - val newBlockData = BlockData(blockToExecute, receipts, td) - blockchain.save(newBlockData.block, newBlockData.receipts, newBlockData.td, saveAsBestBlock = true) - go(newBlockData :: executedBlocksDecOrder, remainingBlocksIncOrder.tail, td, None) + val newWeight = parentWeight.increase(blockToExecute.header) + val newBlockData = BlockData(blockToExecute, receipts, newWeight) + blockchain.save(newBlockData.block, newBlockData.receipts, newBlockData.weight, saveAsBestBlock = true) + go(newBlockData :: executedBlocksDecOrder, remainingBlocksIncOrder.tail, newWeight, None) case Left(executionError) => - go(executedBlocksDecOrder, remainingBlocksIncOrder, 0, Some(executionError)) + (executedBlocksDecOrder.reverse, Some(executionError)) } } } - go(List.empty[BlockData], blocks, parentTd, None) + go(List.empty[BlockData], blocks, parentChainWeight, None) } } @@ -176,6 +174,4 @@ object BlockExecutionError { extends BlockExecutionError case class ValidationAfterExecError(reason: String) extends BlockExecutionError - - case class UnKnownExecutionError(reason: String) extends BlockExecutionError } diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala index ecad82ebb6..869ce06242 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala @@ -3,7 +3,7 @@ package io.iohk.ethereum.ledger import akka.util.ByteString import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.BlockExecutionError.{UnKnownExecutionError, ValidationBeforeExecError} +import io.iohk.ethereum.ledger.BlockExecutionError.ValidationBeforeExecError import io.iohk.ethereum.ledger.BlockQueue.Leaf import io.iohk.ethereum.utils.{BlockchainConfig, Logger} import org.bouncycastle.util.encoders.Hex @@ -22,10 +22,11 @@ class BlockImport( private[ledger] def importToTop( block: Block, currentBestBlock: Block, - currentTd: BigInt + currentWeight: ChainWeight )(implicit blockExecutionContext: ExecutionContext): Future[BlockImportResult] = { val validationResult = Future(blockValidation.validateBlockBeforeExecution(block))(validationContext) - val importResult = Future(importBlockToTop(block, currentBestBlock.header.number, currentTd))(blockExecutionContext) + val importResult = + Future(importBlockToTop(block, currentBestBlock.header.number, currentWeight))(blockExecutionContext) for { validationResult <- validationResult @@ -38,11 +39,11 @@ class BlockImport( } } - private def importBlockToTop(block: Block, bestBlockNumber: BigInt, currentTd: BigInt): BlockImportResult = { + private def importBlockToTop(block: Block, bestBlockNumber: BigInt, currentWeight: ChainWeight): BlockImportResult = { val executionResult = for { topBlock <- blockQueue.enqueueBlock(block, bestBlockNumber) topBlocks = blockQueue.getBranch(topBlock.hash, dequeue = true) - (executed, errors) = blockExecution.executeAndValidateBlocks(topBlocks, currentTd) + (executed, errors) = blockExecution.executeAndValidateBlocks(topBlocks, currentWeight) } yield (executed, errors, topBlocks) executionResult match { @@ -113,7 +114,7 @@ class BlockImport( private[ledger] def reorganise( block: Block, currentBestBlock: Block, - currentTd: BigInt + currentWeight: ChainWeight )(implicit blockExecutionContext: ExecutionContext): Future[BlockImportResult] = Future { blockValidation .validateBlockBeforeExecution(block) @@ -121,9 +122,9 @@ class BlockImport( error => handleBlockValidationError(error, block), _ => { blockQueue.enqueueBlock(block, currentBestBlock.header.number) match { - case Some(Leaf(leafHash, leafTd)) if isBetterBranch(block, currentBestBlock, leafTd, currentTd) => + case Some(Leaf(leafHash, leafWeight)) if leafWeight > currentWeight => log.debug("Found a better chain, about to reorganise") - reorganiseChain(leafHash, leafTd) + reorganiseChainFromQueue(leafHash) case _ => BlockEnqueued @@ -132,32 +133,6 @@ class BlockImport( ) } - private def isBetterBranch(block: Block, bestBlock: Block, newTd: BigInt, currentTd: BigInt): Boolean = { - lazy val betterTd = newTd > currentTd - lazy val tieBreaker = - blockchainConfig.gasTieBreaker && newTd == currentTd && block.header.gasUsed > bestBlock.header.gasUsed - - (block.hasCheckpoint, bestBlock.hasCheckpoint) match { - case (true, true) => false - case (false, true) => false - case (true, false) => true - case (false, false) => betterTd || tieBreaker - } - } - - private def reorganiseChain(leafHash: ByteString, leafTd: BigInt): BlockImportResult = { - reorganiseChainFromQueue(leafHash) match { - case Right((oldBranch, newBranch)) => - val totalDifficulties = newBranch.tail.foldRight(List(leafTd)) { (b, tds) => - (tds.head - b.header.difficulty) :: tds - } - ChainReorganised(oldBranch, newBranch, totalDifficulties) - - case Left(error) => - BlockImportFailed(s"Error while trying to reorganise chain: $error") - } - } - /** Once a better branch was found this attempts to reorganise the chain * * @param queuedLeaf a block hash that determines a new branch stored in the queue (newest block from the branch) @@ -165,35 +140,42 @@ class BlockImport( * @return [[BlockExecutionError]] if one of the blocks in the new branch failed to execute, otherwise: * (oldBranch, newBranch) as lists of blocks */ - private def reorganiseChainFromQueue( - queuedLeaf: ByteString - ): Either[BlockExecutionError, (List[Block], List[Block])] = { + private def reorganiseChainFromQueue(queuedLeaf: ByteString): BlockImportResult = { blockchain.persistCachedNodes() val newBranch = blockQueue.getBranch(queuedLeaf, dequeue = true) val bestNumber = blockchain.getBestBlockNumber() - val result = for { + val reorgResult = for { parent <- newBranch.headOption parentHash = parent.header.parentHash - parentTd <- blockchain.getTotalDifficultyByHash(parentHash) + parentWeight <- blockchain.getChainWeightByHash(parentHash) } yield { val oldBlocksData = removeBlocksUntil(parentHash, bestNumber).reverse oldBlocksData.foreach(block => blockQueue.enqueueBlock(block.block)) - handleBlockExecResult(newBranch, parentTd, oldBlocksData) + handleBlockExecResult(newBranch, parentWeight, oldBlocksData) } - result.getOrElse(Left(UnKnownExecutionError("Error while trying to reorganise chain with parent of new branch"))) + reorgResult match { + case Some(execResult) => + execResult.fold( + err => BlockImportFailed(s"Error while trying to reorganise chain: $err"), + ChainReorganised.tupled + ) + + case None => + BlockImportFailed("Error while trying to reorganise chain with parent of new branch") + } } private def handleBlockExecResult( newBranch: List[Block], - parentTd: BigInt, + parentWeight: ChainWeight, oldBlocksData: List[BlockData] - ): Either[BlockExecutionError, (List[Block], List[Block])] = { - val (executedBlocks, maybeError) = blockExecution.executeAndValidateBlocks(newBranch, parentTd) + ): Either[BlockExecutionError, (List[Block], List[Block], List[ChainWeight])] = { + val (executedBlocks, maybeError) = blockExecution.executeAndValidateBlocks(newBranch, parentWeight) maybeError match { case None => - Right(oldBlocksData.map(_.block), executedBlocks.map(_.block)) + Right(oldBlocksData.map(_.block), executedBlocks.map(_.block), executedBlocks.map(_.weight)) case Some(error) => revertChainReorganisation(newBranch, oldBlocksData, executedBlocks) @@ -216,8 +198,8 @@ class BlockImport( removeBlocksUntil(executedBlocks.head.block.header.parentHash, executedBlocks.last.block.header.number) } - oldBranch.foreach { case BlockData(block, receipts, td) => - blockchain.save(block, receipts, td, saveAsBestBlock = false) + oldBranch.foreach { case BlockData(block, receipts, weight) => + blockchain.save(block, receipts, weight, saveAsBestBlock = false) } import cats.implicits._ @@ -251,8 +233,8 @@ class BlockImport( val blockList = for { receipts <- blockchain.getReceiptsByHash(hash) - td <- blockchain.getTotalDifficultyByHash(hash) - } yield BlockData(block, receipts, td) :: removeBlocksUntil(parent, fromNumber - 1) + weight <- blockchain.getChainWeightByHash(hash) + } yield BlockData(block, receipts, weight) :: removeBlocksUntil(parent, fromNumber - 1) // Not updating best block number for efficiency, it will be updated in the callers anyway blockchain.removeBlock(hash, withState = true) @@ -277,7 +259,7 @@ case object DuplicateBlock extends BlockImportResult case class ChainReorganised( oldBranch: List[Block], newBranch: List[Block], - totalDifficulties: List[BigInt] + weights: List[ChainWeight] ) extends BlockImportResult case class BlockImportFailed(error: String) extends BlockImportResult diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala index a41c305724..3f34278f71 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala @@ -1,17 +1,16 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.domain.{Block, Blockchain} +import io.iohk.ethereum.domain.{Block, Blockchain, ChainWeight} import io.iohk.ethereum.ledger.BlockQueue.{Leaf, QueuedBlock} import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.utils.Logger import scala.annotation.tailrec - import scala.collection.JavaConverters._ object BlockQueue { - case class QueuedBlock(block: Block, totalDifficulty: Option[BigInt]) - case class Leaf(hash: ByteString, totalDifficulty: BigInt) + case class QueuedBlock(block: Block, weight: Option[ChainWeight]) + case class Leaf(hash: ByteString, weight: ChainWeight) def apply(blockchain: Blockchain, syncConfig: SyncConfig): BlockQueue = new BlockQueue(blockchain, syncConfig.maxQueuedBlockNumberAhead, syncConfig.maxQueuedBlockNumberBehind) @@ -53,21 +52,21 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val None case None => - val parentTd = blockchain.getTotalDifficultyByHash(parentHash) + val parentWeight = blockchain.getChainWeightByHash(parentHash) - parentTd match { + parentWeight match { case Some(_) => - addBlock(block, parentTd) + addBlock(block, parentWeight) log.debug(s"Enqueued new block (${block.idTag}) with parent on the main chain") - updateTotalDifficulties(hash) + updateChainWeights(hash) case None => - addBlock(block, parentTd) + addBlock(block, parentWeight) findClosestChainedAncestor(block) match { case Some(ancestor) => log.debug(s"Enqueued new block (${block.idTag}) to a rooted sidechain") - updateTotalDifficulties(ancestor) + updateChainWeights(ancestor) case None => log.debug(s"Enqueued new block (${block.idTag}) with unknown relation to the main chain") @@ -81,7 +80,7 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val blocks.get(hash).map(_.block) def isQueued(hash: ByteString): Boolean = - blocks.get(hash).isDefined + blocks.contains(hash) /** * Takes a branch going from descendant block upwards to the oldest ancestor @@ -105,7 +104,7 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val block :: recur(parentHash, isShared) - case None => + case _ => Nil } } @@ -140,23 +139,23 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val } /** - * Updated total difficulties for a subtree. + * Updates chain weights for a subtree. * @param ancestor An ancestor's hash that determines the subtree * @return Best leaf from the affected subtree */ - private def updateTotalDifficulties(ancestor: ByteString): Option[Leaf] = { - blocks.get(ancestor).flatMap(_.totalDifficulty).map { td => + private def updateChainWeights(ancestor: ByteString): Option[Leaf] = { + blocks.get(ancestor).flatMap(_.weight).map { weight => parentToChildren.get(ancestor) match { case Some(children) if children.nonEmpty => val updatedChildren = children .flatMap(blocks.get) - .map(qb => qb.copy(totalDifficulty = Some(td + qb.block.header.difficulty))) + .map(qb => qb.copy(weight = Some(weight.increase(qb.block.header)))) updatedChildren.foreach(qb => blocks += qb.block.header.hash -> qb) - updatedChildren.flatMap(qb => updateTotalDifficulties(qb.block.header.hash)).maxBy(_.totalDifficulty) + updatedChildren.flatMap(qb => updateChainWeights(qb.block.header.hash)).maxBy(_.weight) case _ => - Leaf(ancestor, td) + Leaf(ancestor, weight) } } } @@ -181,11 +180,11 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val None } - private def addBlock(block: Block, parentTd: Option[BigInt]): Unit = { + private def addBlock(block: Block, parentWeight: Option[ChainWeight]): Unit = { import block.header._ - val td = parentTd.map(_ + difficulty) - blocks += hash -> QueuedBlock(block, td) + val weight = parentWeight.map(_.increase(block.header)) + blocks += hash -> QueuedBlock(block, weight) val siblings = parentToChildren.getOrElse(parentHash, Set.empty) parentToChildren += parentHash -> (siblings + hash) diff --git a/src/main/scala/io/iohk/ethereum/ledger/BranchResolution.scala b/src/main/scala/io/iohk/ethereum/ledger/BranchResolution.scala index 7e473afb29..e5e2a425fd 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BranchResolution.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BranchResolution.scala @@ -1,9 +1,10 @@ package io.iohk.ethereum.ledger import cats.data.NonEmptyList -import io.iohk.ethereum.domain.{Block, BlockHeader, Blockchain} +import io.iohk.ethereum.domain.{Block, BlockHeader, Blockchain, ChainWeight} +import io.iohk.ethereum.utils.Logger -class BranchResolution(blockchain: Blockchain) { +class BranchResolution(blockchain: Blockchain) extends Logger { def resolveBranch(headers: NonEmptyList[BlockHeader]): BranchResolutionResult = { if (!doHeadersFormChain(headers)) { @@ -37,52 +38,41 @@ class BranchResolution(blockchain: Blockchain) { val oldBlocks = oldBlocksWithCommonPrefix.drop(commonPrefixLength) val newHeaders = headersList.drop(commonPrefixLength) - if (compareByCheckpoints(newHeaders, oldBlocks.map(_.header))) - NewBetterBranch(oldBlocks) - else - NoChainSwitch - } - - /** - * @return true if newBranch is better than oldBranch - */ - private def compareByCheckpoints(newBranch: Seq[BlockHeader], oldBranch: Seq[BlockHeader]): Boolean = - (branchLatestCheckpoint(newBranch), branchLatestCheckpoint(oldBranch)) match { - case (Some(newCheckpoint), Some(oldCheckpoint)) => - if (newCheckpoint.number == oldCheckpoint.number) - compareByDifficulty(newBranch, oldBranch) + val maybeParentWeight: Option[Either[String, ChainWeight]] = + oldBlocks.headOption + .map(_.header) + .orElse(newHeaders.headOption) + .map { header => + blockchain + .getChainWeightByHash(header.parentHash) + .toRight(s"ChainWeight for ${header.idTag} not found when resolving branch: $newHeaders") + } + + maybeParentWeight match { + case Some(Right(parentWeight)) => + val oldWeight = oldBlocks.foldLeft(parentWeight)((w, b) => w.increase(b.header)) + val newWeight = newHeaders.foldLeft(parentWeight)((w, h) => w.increase(h)) + + if (newWeight > oldWeight) + NewBetterBranch(oldBlocks) else - newCheckpoint.number > oldCheckpoint.number - - case (Some(_), None) => - true + NoChainSwitch - case (None, Some(_)) => - false + case Some(Left(err)) => + log.error(err) + NoChainSwitch - case (None, None) => - compareByDifficulty(newBranch, oldBranch) + case None => + // after removing common prefix both 'new' and 'old` were empty + log.warn("Attempted to compare identical branches") + NoChainSwitch } - - /** - * @return true if newBranch is better than oldBranch - */ - private def compareByDifficulty(newBranch: Seq[BlockHeader], oldBranch: Seq[BlockHeader]): Boolean = { - val newDifficulty = newBranch.map(_.difficulty).sum - val oldDifficulty = oldBranch.map(_.difficulty).sum - newDifficulty > oldDifficulty } private def getTopBlocksFromNumber(from: BigInt): List[Block] = (from to blockchain.getBestBlockNumber()) .flatMap(blockchain.getBlockByNumber) .toList - - private def branchLatestCheckpoint(headers: Seq[BlockHeader]): Option[BlockHeader] = - headers.filter(_.hasCheckpoint) match { - case Seq() => None - case checkpoints => Some(checkpoints.maxBy(_.number)) - } } sealed trait BranchResolutionResult diff --git a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala index f41c0987bb..1894328b20 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala @@ -95,9 +95,16 @@ class LedgerImpl( private[ledger] lazy val blockValidation = new BlockValidation(consensus, blockchain, blockQueue) private[ledger] lazy val blockExecution = new BlockExecution(blockchain, blockchainConfig, consensus.blockPreparator, blockValidation) - private[ledger] val blockImport = - new BlockImport(blockchain, blockQueue, blockchainConfig, blockValidation, blockExecution, validationContext) private[ledger] val branchResolution = new BranchResolution(blockchain) + private[ledger] val blockImport = + new BlockImport( + blockchain, + blockQueue, + blockchainConfig, + blockValidation, + blockExecution, + validationContext + ) override def checkBlockStatus(blockHash: ByteString): BlockStatus = { if (blockchain.getBlockByHash(blockHash).isDefined) @@ -122,12 +129,12 @@ class LedgerImpl( Future.successful(DuplicateBlock) } else { val hash = currentBestBlock.header.hash - blockchain.getTotalDifficultyByHash(hash) match { - case Some(currentTd) => + blockchain.getChainWeightByHash(hash) match { + case Some(weight) => if (isPossibleNewBestBlock(block.header, currentBestBlock.header)) { - blockImport.importToTop(block, currentBestBlock, currentTd) + blockImport.importToTop(block, currentBestBlock, weight) } else { - blockImport.reorganise(block, currentBestBlock, currentTd) + blockImport.reorganise(block, currentBestBlock, weight) } case None => @@ -171,7 +178,7 @@ object Ledger { ) } -case class BlockData(block: Block, receipts: Seq[Receipt], td: BigInt) +case class BlockData(block: Block, receipts: Seq[Receipt], weight: ChainWeight) sealed trait BlockStatus case object InChain extends BlockStatus diff --git a/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala b/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala index 01d56896da..071d8cc8de 100644 --- a/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala +++ b/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala @@ -3,6 +3,7 @@ package io.iohk.ethereum.network import akka.actor.{Actor, ActorLogging, ActorRef, Props} import akka.util.ByteString import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.PeerActor.{DisconnectPeer, SendMessage} import io.iohk.ethereum.network.EtcPeerManagerActor._ import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe, Unsubscribe} @@ -143,25 +144,21 @@ class EtcPeerManagerActor( * @return new updated peer info */ private def handleReceivedMessage(message: Message, initialPeerWithInfo: PeerWithInfo): PeerInfo = { - (updateTotalDifficultyAndCheckpoint(message) _ + (updateChainWeight(message) _ andThen updateForkAccepted(message, initialPeerWithInfo.peer) andThen updateMaxBlock(message))(initialPeerWithInfo.peerInfo) } /** - * Processes the message and updates the total difficulty of the peer + * Processes the message and updates the chain weight of the peer * * @param message to be processed * @param initialPeerInfo from before the message was processed * @return new peer info with the total difficulty updated */ - private def updateTotalDifficultyAndCheckpoint(message: Message)(initialPeerInfo: PeerInfo): PeerInfo = + private def updateChainWeight(message: Message)(initialPeerInfo: PeerInfo): PeerInfo = message match { - case newBlock: NewBlock => - initialPeerInfo.copy( - totalDifficulty = newBlock.totalDifficulty, - latestCheckpointNumber = newBlock.latestCheckpointNumber - ) + case newBlock: NewBlock => initialPeerInfo.copy(chainWeight = newBlock.chainWeight) case _ => initialPeerInfo } @@ -236,23 +233,23 @@ object EtcPeerManagerActor { case class PeerInfo( remoteStatus: Status, // Updated only after handshaking - totalDifficulty: BigInt, - latestCheckpointNumber: BigInt, + chainWeight: ChainWeight, forkAccepted: Boolean, maxBlockNumber: BigInt, bestBlockHash: ByteString ) extends HandshakeResult { - def withTotalDifficulty(totalDifficulty: BigInt): PeerInfo = copy(totalDifficulty = totalDifficulty) - def withForkAccepted(forkAccepted: Boolean): PeerInfo = copy(forkAccepted = forkAccepted) def withBestBlockData(maxBlockNumber: BigInt, bestBlockHash: ByteString): PeerInfo = copy(maxBlockNumber = maxBlockNumber, bestBlockHash = bestBlockHash) + def withChainWeight(weight: ChainWeight): PeerInfo = + copy(chainWeight = weight) + override def toString: String = s"PeerInfo {" + - s" totalDifficulty: $totalDifficulty," + + s" chainWeight: $chainWeight," + s" forkAccepted: $forkAccepted," + s" maxBlockNumber: $maxBlockNumber," + s" bestBlockHash: ${ByteStringUtils.hash2string(bestBlockHash)}," + @@ -264,8 +261,7 @@ object EtcPeerManagerActor { def apply(remoteStatus: Status, forkAccepted: Boolean): PeerInfo = { PeerInfo( remoteStatus, - remoteStatus.totalDifficulty, - remoteStatus.latestCheckpointNumber, + remoteStatus.chainWeight, forkAccepted, 0, remoteStatus.bestHash diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala index 677747ab33..0d29b40ec7 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala @@ -51,21 +51,19 @@ case class EtcNodeStatusExchangeState(handshakerConfiguration: EtcHandshakerConf private def createStatusMsg(): Status = { val bestBlockHeader = getBestBlockHeader() - val totalDifficulty = blockchain.getTotalDifficultyByHash(bestBlockHeader.hash).get - val latestCheckpointNumber = - if (bestBlockHeader.number < blockchainConfig.ecip1097BlockNumber) None - else Some(blockchain.getLatestCheckpointBlockNumber()) + val chainWeight = blockchain.getChainWeightByHash(bestBlockHeader.hash).get val status = Status( protocolVersion = Versions.PV63, networkId = peerConfiguration.networkId, - totalDifficulty = totalDifficulty, - latestCheckpointNumber = latestCheckpointNumber, + chainWeight = chainWeight, bestHash = bestBlockHeader.hash, genesisHash = blockchain.genesisHeader.hash ) - log.debug(s"sending status $status") - status + + val adjustedStatus = if (bestBlockHeader.number < blockchainConfig.ecip1097BlockNumber) status.as63 else status.as64 + log.debug(s"sending status $adjustedStatus") + adjustedStatus } } diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala b/src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala index 28a1dd6829..3616c7fa66 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala @@ -43,6 +43,8 @@ object EthereumMessageDecoder extends MessageDecoder { //wire protocol case (_, Hello.code) => payload.toHello + //FIXME: I still have an issue with protocolVersion, we are use PV62 and PV63 and code names for Status and NewBlock + // suggest that there is PV64, but there isn't //common case (_, Status.code63 | Status.code64) => payload.toStatus(msgCode) case (_, SignedTransactions.code) => payload.toSignedTransactions diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala b/src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala index 19631b0e4f..975cdb43ee 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala @@ -3,6 +3,7 @@ package io.iohk.ethereum.network.p2p /** * Helper class */ +//FIXME: msg is redundant since `MessageSerializable` already exposes `underlyingMessage` abstract class MessageSerializableImplicit[T <: Message](val msg: T) extends MessageSerializable { override def equals(that: Any): Boolean = that match { diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/messages/CommonMessages.scala b/src/main/scala/io/iohk/ethereum/network/p2p/messages/CommonMessages.scala index 8dd8a4b761..a5c29f4c6d 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/messages/CommonMessages.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/messages/CommonMessages.scala @@ -22,12 +22,19 @@ object CommonMessages { override def toRLPEncodable: RLPEncodeable = { import msg._ - msg match { - case _: Status63 => - RLPList(protocolVersion, networkId, totalDifficulty, bestHash, genesisHash) + msg.code match { + case `code63` => + RLPList(protocolVersion, networkId, chainWeight.totalDifficulty, bestHash, genesisHash) - case _: Status64 => - RLPList(protocolVersion, networkId, totalDifficulty, latestCheckpointNumber, bestHash, genesisHash) + case `code64` => + RLPList( + protocolVersion, + networkId, + chainWeight.totalDifficulty, + chainWeight.lastCheckpointNumber, + bestHash, + genesisHash + ) } } } @@ -44,7 +51,14 @@ object CommonMessages { genesisHash ) ) => - Status63(protocolVersion, networkId, totalDifficulty, bestHash, genesisHash) + Status( + code63, + protocolVersion, + networkId, + ChainWeight.totalDifficultyOnly(totalDifficulty), + bestHash, + genesisHash + ) case ( `code64`, @@ -52,91 +66,67 @@ object CommonMessages { protocolVersion, networkId, totalDifficulty, - latestCheckpointNumber, + lastCheckpointNumber, bestHash, genesisHash ) ) => - Status64(protocolVersion, networkId, totalDifficulty, latestCheckpointNumber, bestHash, genesisHash) + Status( + code64, + protocolVersion, + networkId, + ChainWeight(lastCheckpointNumber, totalDifficulty), + bestHash, + genesisHash + ) case _ => throw new RuntimeException("Cannot decode Status") } } + /** + * Constructs the message with it specifying the code. The code should be regarded as undefined at this stage. + * It should be later made concrete with `as63` or `as64` methods. + * + * FIXME this approach was taken to minimise the required refactoring and should be reconsidered in ETCM-280 + */ def apply( protocolVersion: Int, networkId: Int, - totalDifficulty: BigInt, + chainWeight: ChainWeight, bestHash: ByteString, - genesisHash: ByteString, - latestCheckpointNumber: Option[BigInt] = None - ): Status = latestCheckpointNumber match { - case Some(num) => - Status64(protocolVersion, networkId, totalDifficulty, num, bestHash, genesisHash) - - case None => - Status63(protocolVersion, networkId, totalDifficulty, bestHash, genesisHash) - } - } - - sealed trait Status extends Message { - def protocolVersion: Int - def networkId: Int - def totalDifficulty: BigInt - def latestCheckpointNumber: BigInt - def bestHash: ByteString - def genesisHash: ByteString + genesisHash: ByteString + ): Status = + Status(Status.code63, protocolVersion, networkId, chainWeight, bestHash, genesisHash) - // Test API - def as63: Status63 = - Status63(protocolVersion, networkId, totalDifficulty, bestHash, genesisHash) - - def as64: Status64 = - Status64(protocolVersion, networkId, totalDifficulty, latestCheckpointNumber, bestHash, genesisHash) } - case class Status63( + case class Status( + code: Int, protocolVersion: Int, networkId: Int, - totalDifficulty: BigInt, + chainWeight: ChainWeight, bestHash: ByteString, genesisHash: ByteString - ) extends Status { - override val code: Int = Status.code63 + ) extends Message { + require(code == Status.code63 || code == Status.code64, s"Invalid code for Status: $code") override def toString: String = { - s"""Status63 { + s"""Status { + |code: $code |protocolVersion: $protocolVersion |networkId: $networkId - |totalDifficulty: $totalDifficulty + |chainWeight: $chainWeight |bestHash: ${Hex.toHexString(bestHash.toArray[Byte])} |genesisHash: ${Hex.toHexString(genesisHash.toArray[Byte])} |}""".stripMargin } - override val latestCheckpointNumber: BigInt = 0 - } + def as63: Status = + copy(code = Status.code63) - case class Status64( - protocolVersion: Int, - networkId: Int, - totalDifficulty: BigInt, - latestCheckpointNumber: BigInt, - bestHash: ByteString, - genesisHash: ByteString - ) extends Status { - override val code: Int = Status.code64 - - override def toString: String = { - s"""Status64 { - |protocolVersion: $protocolVersion - |networkId: $networkId - |totalDifficulty: $totalDifficulty - |bestHash: ${Hex.toHexString(bestHash.toArray[Byte])} - |genesisHash: ${Hex.toHexString(genesisHash.toArray[Byte])} - |latestCheckpointNumber: $latestCheckpointNumber - |}""".stripMargin - } + def as64: Status = + copy(code = Status.code64) } object SignedTransactions { @@ -226,26 +216,26 @@ object CommonMessages { override def toRLPEncodable: RLPEncodeable = { import msg._ - msg match { - case _: NewBlock63 => + msg.code match { + case `code63` => RLPList( RLPList( block.header.toRLPEncodable, RLPList(block.body.transactionList.map(_.toRLPEncodable): _*), RLPList(block.body.uncleNodesList.map(_.toRLPEncodable): _*) ), - totalDifficulty + chainWeight.totalDifficulty ) - case _: NewBlock64 => + case `code64` => RLPList( RLPList( block.header.toRLPEncodable, RLPList(block.body.transactionList.map(_.toRLPEncodable): _*), RLPList(block.body.uncleNodesList.map(_.toRLPEncodable): _*) ), - totalDifficulty, - latestCheckpointNumber + chainWeight.totalDifficulty, + chainWeight.lastCheckpointNumber ) } @@ -260,12 +250,13 @@ object CommonMessages { `code63`, RLPList(RLPList(blockHeader, (transactionList: RLPList), (uncleNodesList: RLPList)), totalDifficulty) ) => - NewBlock63( + NewBlock( + code63, Block( blockHeader.toBlockHeader, BlockBody(transactionList.items.map(_.toSignedTransaction), uncleNodesList.items.map(_.toBlockHeader)) ), - totalDifficulty + ChainWeight.totalDifficultyOnly(totalDifficulty) ) case ( @@ -273,67 +264,47 @@ object CommonMessages { RLPList( RLPList(blockHeader, (transactionList: RLPList), (uncleNodesList: RLPList)), totalDifficulty, - latestCheckpointNumber + lastCheckpointNumber ) ) => - NewBlock64( + NewBlock( + code64, Block( blockHeader.toBlockHeader, BlockBody(transactionList.items.map(_.toSignedTransaction), uncleNodesList.items.map(_.toBlockHeader)) ), - totalDifficulty, - latestCheckpointNumber + ChainWeight(lastCheckpointNumber, totalDifficulty) ) case _ => throw new RuntimeException("Cannot decode NewBlock") } } - def apply(block: Block, totalDifficulty: BigInt, latestCheckpointNumber: Option[BigInt] = None): NewBlock = - latestCheckpointNumber match { - case Some(num) => NewBlock64(block, totalDifficulty, num) - case None => NewBlock63(block, totalDifficulty) - } - - def unapply(nb: NewBlock): Option[(Block, BigInt, BigInt)] = - Some((nb.block, nb.totalDifficulty, nb.latestCheckpointNumber)) - - } - - sealed trait NewBlock extends Message { - def block: Block - def totalDifficulty: BigInt - def latestCheckpointNumber: BigInt - - // Test API - def as63: NewBlock63 = - NewBlock63(block, totalDifficulty) + /** + * Constructs the message with it specifying the code. The code should be regarded as undefined at this stage. + * It should be later made concrete with `as63` or `as64` methods. + * + * FIXME this approach was taken to minimise the required refactoring and should be reconsidered in ETCM-280 + */ + def apply(block: Block, chainWeight: ChainWeight): NewBlock = + NewBlock(NewBlock.code63, block, chainWeight) - def as64: NewBlock64 = - NewBlock64(block, totalDifficulty, latestCheckpointNumber) } - case class NewBlock63(block: Block, totalDifficulty: BigInt) extends NewBlock { - override val code: Int = NewBlock.code63 + case class NewBlock(code: Int, block: Block, chainWeight: ChainWeight) extends Message { + require(code == NewBlock.code63 || code == NewBlock.code64, s"Invalid code for NewBlock: $code") override def toString: String = { - s"""NewBlock63 { + s"""NewBlock { + |code: $code |block: $block - |totalDifficulty: $totalDifficulty + |chainWeight: $chainWeight |}""".stripMargin } - override val latestCheckpointNumber: BigInt = 0 - } - - case class NewBlock64(block: Block, totalDifficulty: BigInt, latestCheckpointNumber: BigInt) extends NewBlock { - override val code: Int = NewBlock.code64 + def as63: NewBlock = + copy(code = NewBlock.code63) - override def toString: String = { - s"""NewBlock64 { - |block: $block - |totalDifficulty: $totalDifficulty - |latestCheckpointNumber: $latestCheckpointNumber - |}""".stripMargin - } + def as64: NewBlock = + copy(code = NewBlock.code64) } } diff --git a/src/main/scala/io/iohk/ethereum/utils/ByteUtils.scala b/src/main/scala/io/iohk/ethereum/utils/ByteUtils.scala index 59e009470e..56166e1057 100644 --- a/src/main/scala/io/iohk/ethereum/utils/ByteUtils.scala +++ b/src/main/scala/io/iohk/ethereum/utils/ByteUtils.scala @@ -106,6 +106,9 @@ object ByteUtils { ByteString(compactPickledBytesToArray(buffer)) } + def byteSequenceToBuffer(bytes: IndexedSeq[Byte]): ByteBuffer = + ByteBuffer.wrap(bytes.toArray) + def bytesToInts(bytes: Array[Byte], bigEndian: Boolean): Array[Int] = { val ret = new Array[Int](bytes.length / 4) bytesToIntsMut(bytes, ret, bigEndian) diff --git a/src/test/scala/io/iohk/ethereum/Mocks.scala b/src/test/scala/io/iohk/ethereum/Mocks.scala index 844ecc0f84..eec1a9d3cc 100644 --- a/src/test/scala/io/iohk/ethereum/Mocks.scala +++ b/src/test/scala/io/iohk/ethereum/Mocks.scala @@ -136,8 +136,7 @@ object Mocks { ConnectedState( PeerInfo( initialStatus, - initialStatus.totalDifficulty, - initialStatus.latestCheckpointNumber, + initialStatus.chainWeight, forkAccepted, currentMaxBlockNumber, initialStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala b/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala index 1efb3b1bca..201f063ce7 100644 --- a/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala +++ b/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala @@ -145,8 +145,9 @@ trait ObjectGenerators { blockHeader <- blockHeaderGen stxs <- signedTxSeqGen(10, secureRandom, chainId) uncles <- seqBlockHeaderGen + lastChkp <- bigIntGen td <- bigIntGen - } yield NewBlock(Block(blockHeader, BlockBody(stxs, uncles)), td) + } yield NewBlock(Block(blockHeader, BlockBody(stxs, uncles)), ChainWeight(lastChkp, td)) def extraFieldsGen: Gen[HeaderExtraFields] = for { optOut <- Arbitrary.arbitrary[Option[Boolean]] @@ -229,6 +230,11 @@ trait ObjectGenerators { n <- intGen(1, max) list <- Gen.listOfN(n, genMptNodeData) } yield list + + val chainWeightGen = for { + lcn <- bigIntGen + td <- bigIntGen + } yield ChainWeight(lcn, td) } object ObjectGenerators extends ObjectGenerators diff --git a/src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala b/src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala index 90d93f4208..f7f30e78fa 100644 --- a/src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala +++ b/src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala @@ -8,6 +8,6 @@ trait WithActorSystemShutDown extends BeforeAndAfterAll { this: Suite => implicit val system: ActorSystem override def afterAll: Unit = { - TestKit.shutdownActorSystem(system) + TestKit.shutdownActorSystem(system, verifySystemShutdown = true) } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcastSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcastSpec.scala index 2523fcc88b..1b75092b02 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcastSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcastSpec.scala @@ -5,7 +5,7 @@ import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.testkit.{TestKit, TestProbe} import io.iohk.ethereum.{Fixtures, WithActorSystemShutDown} -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader} +import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer} import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo import io.iohk.ethereum.network.p2p.messages.CommonMessages.{NewBlock, Status} @@ -23,12 +23,13 @@ class BlockBroadcastSpec with WithActorSystemShutDown with Matchers { - it should "send a new block when it is not known by the peer (known by comparing total difficulties)" in new TestSetup { + it should "send a new block when it is not known by the peer (known by comparing chain weights)" in new TestSetup { //given //Block that should be sent as it's total difficulty is higher than known by peer val blockHeader: BlockHeader = baseBlockHeader.copy(number = initialPeerInfo.maxBlockNumber - 3) val newBlockNewHashes = NewBlockHashes(Seq(PV62.BlockHash(blockHeader.hash, blockHeader.number))) - val newBlock = NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.totalDifficulty + 2) + val newBlock = + NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.chainWeight.increaseTotalDifficulty(2)) //when blockBroadcast.broadcastBlock(newBlock, Map(peer -> initialPeerInfo)) @@ -43,7 +44,8 @@ class BlockBroadcastSpec //given //Block that shouldn't be sent as it's number and total difficulty is lower than known by peer val blockHeader: BlockHeader = baseBlockHeader.copy(number = initialPeerInfo.maxBlockNumber - 2) - val newBlock = NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.totalDifficulty - 2) + val newBlock = + NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.chainWeight.increaseTotalDifficulty(-2)) //when blockBroadcast.broadcastBlock(newBlock, Map(peer -> initialPeerInfo)) @@ -56,7 +58,8 @@ class BlockBroadcastSpec //given val blockHeader: BlockHeader = baseBlockHeader.copy(number = initialPeerInfo.maxBlockNumber + 4) val newBlockNewHashes = NewBlockHashes(Seq(PV62.BlockHash(blockHeader.hash, blockHeader.number))) - val newBlock = NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.totalDifficulty - 2) + val newBlock = + NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.chainWeight.increaseTotalDifficulty(-2)) //when blockBroadcast.broadcastBlock(newBlock, Map(peer -> initialPeerInfo)) @@ -71,7 +74,8 @@ class BlockBroadcastSpec //given //Block should already be known by the peer due to max block known val blockHeader: BlockHeader = baseBlockHeader.copy(number = initialPeerInfo.maxBlockNumber - 2) - val newBlock = NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.totalDifficulty - 2) + val newBlock = + NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.chainWeight.increaseTotalDifficulty(-2)) //when blockBroadcast.broadcastBlock(newBlock, Map(peer -> initialPeerInfo)) @@ -84,7 +88,8 @@ class BlockBroadcastSpec //given val firstHeader: BlockHeader = baseBlockHeader.copy(number = initialPeerInfo.maxBlockNumber + 4) val firstBlockNewHashes = NewBlockHashes(Seq(PV62.BlockHash(firstHeader.hash, firstHeader.number))) - val firstBlock = NewBlock(Block(firstHeader, BlockBody(Nil, Nil)), initialPeerInfo.totalDifficulty - 2) + val firstBlock = + NewBlock(Block(firstHeader, BlockBody(Nil, Nil)), initialPeerInfo.chainWeight.increaseTotalDifficulty(-2)) val peer2Probe = TestProbe() val peer2 = Peer(new InetSocketAddress("127.0.0.1", 0), peer2Probe.ref, false) @@ -121,7 +126,7 @@ class BlockBroadcastSpec override val blockBroadcast = new BlockBroadcast(etcPeerManagerProbe.ref, updatedConfig) val blockHeader: BlockHeader = baseBlockHeader.copy(number = initialPeerInfo.maxBlockNumber + 1) - val newBlock = NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.totalDifficulty + 1) + val newBlock = NewBlock(Block(blockHeader, BlockBody(Nil, Nil)), initialPeerInfo.chainWeight.increase(blockHeader)) blockBroadcast.broadcastBlock(newBlock, Map(peer -> initialPeerInfo)) @@ -141,14 +146,13 @@ class BlockBroadcastSpec val peerStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = BigInt(10000), + chainWeight = ChainWeight(10, 10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) val initialPeerInfo = PeerInfo( remoteStatus = peerStatus, - totalDifficulty = peerStatus.totalDifficulty, - latestCheckpointNumber = peerStatus.latestCheckpointNumber, + chainWeight = peerStatus.chainWeight, forkAccepted = false, maxBlockNumber = Fixtures.Blocks.Block3125369.header.number, bestBlockHash = peerStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/FastSyncSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/FastSyncSpec.scala index 1723e1daff..c3ef5798e3 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/FastSyncSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/FastSyncSpec.scala @@ -12,7 +12,7 @@ import io.iohk.ethereum.{FreeSpecBase, ObjectGenerators, SpecFixtures, WithActor import monix.eval.Task import monix.reactive.Observable import io.iohk.ethereum.BlockHelpers -import io.iohk.ethereum.network.p2p.messages.CommonMessages +import io.iohk.ethereum.domain.ChainWeight import scala.concurrent.duration.DurationInt @@ -24,6 +24,8 @@ class FastSyncSpec implicit val timeout: Timeout = Timeout(10.seconds) class Fixture extends EphemBlockchainTestSetup with TestSyncConfig with TestSyncPeers { + override implicit lazy val system = FastSyncSpec.this.system + override lazy val syncConfig: SyncConfig = defaultSyncConfig.copy(pivotBlockOffset = 5, fastSyncBlockValidationX = 5, fastSyncThrottle = 1.millis) lazy val (stateRoot, trieProvider) = { @@ -44,15 +46,12 @@ class FastSyncSpec lazy val bestBlockAtStart = testBlocks(10) lazy val expectedPivotBlockNumber = bestBlockAtStart.number - syncConfig.pivotBlockOffset lazy val expectedTargetBlockNumber = expectedPivotBlockNumber + syncConfig.fastSyncBlockValidationX - lazy val testPeers = twoAcceptedPeers.mapValues(peerInfo => { + lazy val testPeers = twoAcceptedPeers.mapValues { peerInfo => val lastBlock = bestBlockAtStart peerInfo .withBestBlockData(lastBlock.number, lastBlock.hash) - .copy(remoteStatus = peerInfo.remoteStatus match { - case s63: CommonMessages.Status63 => s63.copy(bestHash = lastBlock.hash) - case s64: CommonMessages.Status64 => s64.copy(bestHash = lastBlock.hash) - }) - }) + .copy(remoteStatus = peerInfo.remoteStatus.copy(bestHash = lastBlock.hash)) + } lazy val etcPeerManager = new EtcPeerManagerFake( syncConfig, @@ -75,7 +74,7 @@ class FastSyncSpec ) val saveGenesis: Task[Unit] = Task { - blockchain.save(BlockHelpers.genesis, receipts = Nil, totalDifficulty = 1, saveAsBestBlock = true) + blockchain.save(BlockHelpers.genesis, receipts = Nil, ChainWeight.totalDifficultyOnly(1), saveAsBestBlock = true) } val startSync: Task[Unit] = Task { fastSync ! SyncProtocol.Start } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/PeersClientSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/PeersClientSpec.scala index f031ea4d52..10e7859b04 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/PeersClientSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/PeersClientSpec.scala @@ -5,9 +5,10 @@ import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo import io.iohk.ethereum.network.Peer -import io.iohk.ethereum.network.p2p.messages.CommonMessages.Status64 +import io.iohk.ethereum.network.p2p.messages.CommonMessages.Status import io.iohk.ethereum.network.p2p.messages.Versions import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -63,20 +64,18 @@ class PeersClientSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC val peer2 = Peer(new InetSocketAddress("127.0.0.1", 2), TestProbe().ref, false) val peer3 = Peer(new InetSocketAddress("127.0.0.1", 3), TestProbe().ref, false) - private val peerStatus = Status64( + private val peerStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = 0, - latestCheckpointNumber = 0, + chainWeight = ChainWeight(0, 0), bestHash = ByteString.empty, genesisHash = ByteString.empty ) def peerInfo(chkp: Int, td: Int, fork: Boolean = true): PeerInfo = PeerInfo( - peerStatus.copy(latestCheckpointNumber = chkp, totalDifficulty = td), - td, - chkp, + peerStatus, + ChainWeight(chkp, td), forkAccepted = fork, maxBlockNumber = 42, bestBlockHash = ByteString.empty diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelectorSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelectorSpec.scala index da741ad955..2c1cd65d7a 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelectorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelectorSpec.scala @@ -4,8 +4,8 @@ import akka.actor.{ActorRef, ActorSystem} import akka.testkit.{TestKit, TestProbe} import akka.util.ByteString import com.miguno.akka.testing.VirtualTime -import io.iohk.ethereum.blockchain.sync.PivotBlockSelector.{SelectPivotBlock, Result} -import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.blockchain.sync.PivotBlockSelector.{Result, SelectPivotBlock} +import io.iohk.ethereum.domain.{BlockHeader, ChainWeight} import io.iohk.ethereum.network.EtcPeerManagerActor.{HandshakedPeers, PeerInfo} import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.{MessageClassifier, PeerDisconnectedClassifier} @@ -17,9 +17,11 @@ import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer} import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.{Fixtures, WithActorSystemShutDown} import java.net.InetSocketAddress + import org.scalatest.BeforeAndAfter import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers + import scala.concurrent.duration._ class PivotBlockSelectorSpec @@ -487,41 +489,38 @@ class PivotBlockSelectorSpec val peer3 = Peer(new InetSocketAddress("127.0.0.3", 0), peer3TestProbe.ref, false) val peer4 = Peer(new InetSocketAddress("127.0.0.4", 0), peer4TestProbe.ref, false) - val peer1Status = Status(1, 1, 20, ByteString("peer1_bestHash"), ByteString("unused")) - val peer2Status = Status(1, 1, 20, ByteString("peer2_bestHash"), ByteString("unused")) - val peer3Status = Status(1, 1, 20, ByteString("peer3_bestHash"), ByteString("unused")) - val peer4Status = Status(1, 1, 20, ByteString("peer4_bestHash"), ByteString("unused")) + val peer1Status = + Status(1, 1, ChainWeight.totalDifficultyOnly(20), ByteString("peer1_bestHash"), ByteString("unused")) + val peer2Status = peer1Status.copy(bestHash = ByteString("peer2_bestHash")) + val peer3Status = peer1Status.copy(bestHash = ByteString("peer3_bestHash")) + val peer4Status = peer1Status.copy(bestHash = ByteString("peer4_bestHash")) val allPeers = Map( peer1 -> PeerInfo( peer1Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer1Status.bestHash ), peer2 -> PeerInfo( peer2Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer2Status.bestHash ), peer3 -> PeerInfo( peer3Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer3Status.bestHash ), peer4 -> PeerInfo( peer4Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer4Status.bestHash ) @@ -531,24 +530,21 @@ class PivotBlockSelectorSpec peer1 -> PeerInfo( peer1Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer1Status.bestHash ), peer2 -> PeerInfo( peer2Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer2Status.bestHash ), peer3 -> PeerInfo( peer3Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer3Status.bestHash ) @@ -558,8 +554,7 @@ class PivotBlockSelectorSpec peer1 -> PeerInfo( peer1Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer1Status.bestHash ) @@ -569,32 +564,28 @@ class PivotBlockSelectorSpec peer1 -> PeerInfo( peer1Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer1Status.bestHash ), peer2 -> PeerInfo( peer2Status, forkAccepted = false, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer2Status.bestHash ), peer3 -> PeerInfo( peer3Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer3Status.bestHash ), peer4 -> PeerInfo( peer4Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, - latestCheckpointNumber = peer1Status.latestCheckpointNumber, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, bestBlockHash = peer4Status.bestHash ) 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 d89e89f1a7..f7ef38d703 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala @@ -12,10 +12,11 @@ import io.iohk.ethereum.blockchain.sync.SyncStateSchedulerActor.{ RestartRequested, StartSyncingTo, StateSyncFinished, + StateSyncStats, WaitingForNewTargetBlock } import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import io.iohk.ethereum.domain.{Address, BlockchainImpl} +import io.iohk.ethereum.domain.{Address, BlockchainImpl, ChainWeight} import io.iohk.ethereum.network.EtcPeerManagerActor.{GetHandshakedPeers, HandshakedPeers, PeerInfo, SendMessage} import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer import io.iohk.ethereum.network.p2p.messages.CommonMessages.Status @@ -37,15 +38,13 @@ import scala.concurrent.duration._ import scala.util.Random class StateSyncSpec - extends TestKit(ActorSystem("MySpec")) + extends TestKit(ActorSystem("StateSyncSpec")) with AnyFlatSpecLike with Matchers with BeforeAndAfterAll with ScalaCheckPropertyChecks with WithActorSystemShutDown { - val actorSystem = system - // those tests are somewhat long running 3 successful evaluation should be fine implicit override val generatorDrivenConfig = PropertyCheckConfiguration(minSuccessful = PosInt(3)) @@ -85,27 +84,18 @@ class StateSyncSpec } } - it should "stop state sync when requested" in new TestSetup() { + it should "restart state sync when requested" in new TestSetup() { forAll(ObjectGenerators.genMultipleNodeData(1000)) { nodeData => val initiator = TestProbe() val trieProvider1 = TrieProvider() val target = trieProvider1.buildWorld(nodeData) setAutoPilotWithProvider(trieProvider1) - lazy val testScheduler = system.actorOf( - SyncStateSchedulerActor.props( - SyncStateScheduler( - buildBlockChain(), - syncConfig.stateSyncBloomFilterSize - ), - syncConfig, - etcPeerManager.ref, - peerEventBus.ref, - system.scheduler - ) - ) - initiator.send(testScheduler, StartSyncingTo(target, 1)) - initiator.send(testScheduler, RestartRequested) - initiator.expectMsg(WaitingForNewTargetBlock) + initiator.send(scheduler, StartSyncingTo(target, 1)) + initiator.send(scheduler, RestartRequested) + initiator.fishForMessage(20.seconds) { + case _: StateSyncStats => false + case WaitingForNewTargetBlock => true + } } } @@ -126,7 +116,7 @@ class StateSyncSpec pruningMode = storages.pruningMode, nodeStorage = storages.nodeStorage, cachedNodeStorage = storages.cachedNodeStorage, - totalDifficultyStorage = storages.totalDifficultyStorage, + chainWeightStorage = storages.chainWeightStorage, transactionMappingStorage = storages.transactionMappingStorage, appStateStorage = storages.appStateStorage, stateStorage = storages.stateStorage @@ -152,21 +142,20 @@ class StateSyncSpec } class TestSetup extends EphemBlockchainTestSetup with TestSyncConfig { - override implicit lazy val system = actorSystem + override implicit lazy val system = StateSyncSpec.this.system type PeerConfig = Map[PeerId, PeerAction] val syncInit = TestProbe() val peerStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = BigInt(10000), + chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) val initialPeerInfo = PeerInfo( remoteStatus = peerStatus, - totalDifficulty = peerStatus.totalDifficulty, - latestCheckpointNumber = peerStatus.latestCheckpointNumber, + chainWeight = peerStatus.chainWeight, forkAccepted = false, maxBlockNumber = Fixtures.Blocks.Block3125369.header.number, bestBlockHash = peerStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncControllerSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncControllerSpec.scala index 8a19f8252e..923378c308 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncControllerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncControllerSpec.scala @@ -9,7 +9,7 @@ import io.iohk.ethereum.consensus.TestConsensus import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError import io.iohk.ethereum.consensus.validators.{BlockHeaderValid, BlockHeaderValidator, Validators} -import io.iohk.ethereum.domain.{Account, BlockBody, BlockHeader, Receipt} +import io.iohk.ethereum.domain.{Account, BlockBody, BlockHeader, ChainWeight, Receipt} import io.iohk.ethereum.ledger.Ledger import io.iohk.ethereum.ledger.Ledger.VMImpl import io.iohk.ethereum.network.EtcPeerManagerActor @@ -491,7 +491,7 @@ class SyncControllerSpec extends AnyFlatSpec with Matchers with BeforeAndAfter w val EmptyTrieRootHash: ByteString = Account.EmptyStorageRootHash val baseBlockHeader = Fixtures.Blocks.Genesis.header - blockchain.storeTotalDifficulty(baseBlockHeader.parentHash, BigInt(0)).commit() + blockchain.storeChainWeight(baseBlockHeader.parentHash, ChainWeight.zero).commit() val startDelayMillis = 200 diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncPeers.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncPeers.scala index 20e06477de..395f181733 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncPeers.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncPeers.scala @@ -4,6 +4,7 @@ import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.p2p.messages.CommonMessages.Status @@ -19,8 +20,9 @@ trait TestSyncPeers { self: TestSyncConfig => val peer2 = Peer(new InetSocketAddress("127.0.0.2", 0), peer2TestProbe.ref, false) val peer3 = Peer(new InetSocketAddress("127.0.0.3", 0), peer3TestProbe.ref, false) - val peer1Status = Status(1, 1, 20, ByteString("peer1_bestHash"), ByteString("unused")) - val peer2Status = Status(1, 1, 20, ByteString("peer2_bestHash"), ByteString("unused")) + val peer1Status = + Status(1, 1, ChainWeight.totalDifficultyOnly(20), ByteString("peer1_bestHash"), ByteString("unused")) + val peer2Status = peer1Status.copy(bestHash = ByteString("peer2_bestHash")) val bestBlock = 400000 val expectedPivotBlock = bestBlock - syncConfig.pivotBlockOffset @@ -28,28 +30,25 @@ trait TestSyncPeers { self: TestSyncConfig => val defaultPeer1Info = PeerInfo( peer1Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, - bestBlockHash = peer1Status.bestHash, - latestCheckpointNumber = peer1Status.latestCheckpointNumber + bestBlockHash = peer1Status.bestHash ) val twoAcceptedPeers = Map( peer1 -> PeerInfo( peer1Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, - bestBlockHash = peer1Status.bestHash, - latestCheckpointNumber = peer1Status.latestCheckpointNumber + bestBlockHash = peer1Status.bestHash ), peer2 -> PeerInfo( peer2Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, - bestBlockHash = peer2Status.bestHash, - latestCheckpointNumber = peer1Status.latestCheckpointNumber + bestBlockHash = peer2Status.bestHash ) ) @@ -57,10 +56,9 @@ trait TestSyncPeers { self: TestSyncConfig => peer1 -> PeerInfo( peer1Status, forkAccepted = true, - totalDifficulty = peer1Status.totalDifficulty, + chainWeight = peer1Status.chainWeight, maxBlockNumber = bestBlock, - bestBlockHash = peer1Status.bestHash, - latestCheckpointNumber = peer1Status.latestCheckpointNumber + bestBlockHash = peer1Status.bestHash ) ) } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala index 5f9b1abac8..446bfabff0 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala @@ -10,7 +10,7 @@ import io.iohk.ethereum.Fixtures.{Blocks => FixtureBlocks} import io.iohk.ethereum.blockchain.sync.PeersClient.BlacklistPeer import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.InvalidateBlocksFrom import io.iohk.ethereum.blockchain.sync.{PeersClient, TestSyncConfig} -import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.{Block, ChainWeight} import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} @@ -172,10 +172,10 @@ class BlockFetcherSpec extends TestKit(ActorSystem("BlockFetcherSpec_System")) w // Sending a far away block as a NewBlock message // Currently BlockFetcher only downloads first block-headers-per-request blocks without this def triggerFetching(): Unit = { - val farAwayBlockTd = 100000 + val farAwayBlockWeight = ChainWeight.totalDifficultyOnly(100000) val farAwayBlock = Block(FixtureBlocks.ValidBlock.header.copy(number = 1000), FixtureBlocks.ValidBlock.body) - blockFetcher ! MessageFromPeer(NewBlock(farAwayBlock, farAwayBlockTd), fakePeer.id) + blockFetcher ! MessageFromPeer(NewBlock(farAwayBlock, farAwayBlockWeight), fakePeer.id) } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncFixtures.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncFixtures.scala index 61400c18aa..a2d98014eb 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncFixtures.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncFixtures.scala @@ -87,7 +87,7 @@ trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => blockchain.save( block = BlockHelpers.genesis, receipts = Nil, - totalDifficulty = BigInt(10000), + weight = ChainWeight.totalDifficultyOnly(10000), saveAsBestBlock = true ) // scalastyle:on magic.number @@ -101,12 +101,12 @@ trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => Peer(new InetSocketAddress("127.0.0.1", 0), TestProbe(id.value).ref, incomingConnection = false) def getPeerInfo(peer: Peer): PeerInfo = { - val status = Status(1, 1, 1, ByteString(s"${peer.id}_bestHash"), ByteString("unused")) + val status = + Status(1, 1, ChainWeight.totalDifficultyOnly(1), ByteString(s"${peer.id}_bestHash"), ByteString("unused")) PeerInfo( status, forkAccepted = true, - totalDifficulty = status.totalDifficulty, - latestCheckpointNumber = status.latestCheckpointNumber, + chainWeight = status.chainWeight, maxBlockNumber = 0, bestBlockHash = status.bestHash ) @@ -294,7 +294,9 @@ trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => .onCall((block, _) => { if (block == newBlock) { importedNewBlock = true - Future.successful(BlockImportedToTop(List(BlockData(newBlock, Nil, newBlock.number)))) + Future.successful( + BlockImportedToTop(List(BlockData(newBlock, Nil, ChainWeight(0, newBlock.number)))) + ) } else { if (block == testBlocks.last) { importedLastTestBlock = true @@ -313,7 +315,7 @@ trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => def sendLastTestBlockAsTop(): Unit = sendNewBlock(testBlocks.last) def sendNewBlock(block: Block = newBlock, peer: Peer = defaultPeer): Unit = - blockFetcher ! MessageFromPeer(NewBlock(block, block.number), peer.id) + blockFetcher ! MessageFromPeer(NewBlock(block, ChainWeight(0, block.number)), peer.id) def goToTop(): Unit = { regularSync ! SyncProtocol.Start diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala index c23efc67d0..5d4e7dddc0 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala @@ -22,7 +22,7 @@ import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.Message import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} import io.iohk.ethereum.network.p2p.messages.CommonMessages.NewBlock import io.iohk.ethereum.domain.BlockHeaderImplicits._ -import io.iohk.ethereum.network.p2p.messages.CommonMessages.{NewBlock, NewBlock63, NewBlock64} +import io.iohk.ethereum.network.p2p.messages.CommonMessages.NewBlock import io.iohk.ethereum.network.p2p.messages.PV62._ import io.iohk.ethereum.network.p2p.messages.PV63.{GetNodeData, NodeData} import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerEventBusActor} @@ -92,7 +92,10 @@ class RegularSyncSpec regularSync ! SyncProtocol.Start peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.number), defaultPeer.id)) + // It's weird that we're using block number for total difficulty but I'm too scared to fight this dragon + peerEventBus.reply( + MessageFromPeer(NewBlock(testBlocks.last, ChainWeight(0, testBlocks.last.number)), defaultPeer.id) + ) peersClient.expectMsgEq(blockHeadersChunkRequest(0)) peersClient.reply(PeersClient.Response(defaultPeer, BlockHeaders(testBlocksChunked.head.headers))) @@ -162,7 +165,7 @@ class RegularSyncSpec peerEventBus.expectMsgClass(classOf[Subscribe]) peerEventBus.reply( - MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.header.difficulty), defaultPeer.id) + MessageFromPeer(NewBlock(testBlocks.last, ChainWeight(0, testBlocks.last.header.difficulty)), defaultPeer.id) ) peersClient.expectMsgEq(blockHeadersChunkRequest(0)) @@ -223,7 +226,10 @@ class RegularSyncSpec peerEventBus.expectMsgClass(classOf[Subscribe]) peerEventBus.reply( - MessageFromPeer(NewBlock(alternativeBlocks.last, alternativeBlocks.last.number), defaultPeer.id) + MessageFromPeer( + NewBlock(alternativeBlocks.last, ChainWeight(0, alternativeBlocks.last.number)), + defaultPeer.id + ) ) awaitCond(ledger.bestBlock == alternativeBlocks.last, 5.seconds) @@ -271,12 +277,17 @@ class RegularSyncSpec peerEventBus.expectMsgClass(classOf[Subscribe]) val blockFetcher = peerEventBus.sender() - peerEventBus.reply(MessageFromPeer(NewBlock(originalBranch.last, originalBranch.last.number), defaultPeer.id)) + peerEventBus.reply( + MessageFromPeer(NewBlock(originalBranch.last, ChainWeight(0, originalBranch.last.number)), defaultPeer.id) + ) awaitCond(ledger.bestBlock == originalBranch.last, 5.seconds) // As node will be on top, we have to re-trigger the fetching process by simulating a block from the fork being broadcasted - blockFetcher ! MessageFromPeer(NewBlock(betterBranch.last, betterBranch.last.number), defaultPeer.id) + blockFetcher ! MessageFromPeer( + NewBlock(betterBranch.last, ChainWeight(0, betterBranch.last.number)), + defaultPeer.id + ) awaitCond(ledger.bestBlock == betterBranch.last, 5.seconds) } ) @@ -390,7 +401,7 @@ class RegularSyncSpec regularSync ! SyncProtocol.Start peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(newBlock, 1), defaultPeer.id)) + peerEventBus.reply(MessageFromPeer(NewBlock(newBlock, ChainWeight(0, 1)), defaultPeer.id)) Thread.sleep(remainingOrDefault.toMillis) @@ -408,7 +419,9 @@ class RegularSyncSpec regularSync ! SyncProtocol.Start peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.number), defaultPeer.id)) + peerEventBus.reply( + MessageFromPeer(NewBlock(testBlocks.last, ChainWeight(0, testBlocks.last.number)), defaultPeer.id) + ) awaitCond(ledger.didTryToImportBlock(failingBlock)) @@ -436,7 +449,7 @@ class RegularSyncSpec etcPeerManager.fishForSpecificMessageMatching() { case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { - case NewBlock(block, _, _) if block == newBlock => true + case NewBlock(_, block, _) if block == newBlock => true case _ => false } case _ => false @@ -465,7 +478,9 @@ class RegularSyncSpec regularSync ! SyncProtocol.Start peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.number), defaultPeer.id)) + peerEventBus.reply( + MessageFromPeer(NewBlock(testBlocks.last, ChainWeight(0, testBlocks.last.number)), defaultPeer.id) + ) awaitCond(ledger.didTryToImportBlock(testBlocks.head)) regularSync ! SyncProtocol.MinedBlock(minedBlock) @@ -504,7 +519,7 @@ class RegularSyncSpec etcPeerManager.fishForSpecificMessageMatching() { case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { - case NewBlock(block, _, _) if block == newBlock => true + case NewBlock(_, block, _) if block == newBlock => true case _ => false } case _ => false @@ -529,8 +544,6 @@ class RegularSyncSpec regularSync ! SyncProtocol.Start peersClient.setAutoPilot(new PeersClientAutoPilot()) - peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(block, block.number), defaultPeer.id)) awaitCond(ledger.didTryToImportBlock(block)) regularSync ! newCheckpointMsg @@ -554,7 +567,11 @@ class RegularSyncSpec val checkpointBlock = checkpointBlockGenerator.generate(parentBlock, checkpoint) ledger.setImportResult( checkpointBlock, - () => Future.successful(BlockImportedToTop(List(BlockData(checkpointBlock, Nil, 42)))) + // FIXME: lastCheckpointNumber == 0, refactor FakeLedger? + () => + Future.successful( + BlockImportedToTop(List(BlockData(checkpointBlock, Nil, ChainWeight(parentBlock.number + 1, 42)))) + ) ) etcPeerManager.expectMsg(GetHandshakedPeers) @@ -566,7 +583,7 @@ class RegularSyncSpec etcPeerManager.fishForSpecificMessageMatching() { case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { - case NewBlock(block, _, _) if block == checkpointBlock => true + case NewBlock(_, block, _) if block == checkpointBlock => true case _ => false } case _ => false @@ -575,6 +592,7 @@ class RegularSyncSpec } "broadcasting blocks" should { + // FIXME: this should reflect peers capabilities after ETCM-280 "send a NewBlock message without latest checkpoint number when before ECIP-1097" in sync( new OnTopFixture(testSystem) { override lazy val blockchainConfig: BlockchainConfig = @@ -590,7 +608,7 @@ class RegularSyncSpec etcPeerManager.fishForSpecificMessageMatching() { case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { - case NewBlock63(`newBlock`, _) => true + case NewBlock(NewBlock.code63, `newBlock`, _) => true case _ => false } case _ => false @@ -598,6 +616,7 @@ class RegularSyncSpec } ) + // FIXME: this should reflect peers capabilities after ETCM-280 "send a NewBlock message with latest checkpoint number when after ECIP-1097" in sync( new OnTopFixture(testSystem) { override lazy val blockchainConfig: BlockchainConfig = @@ -616,7 +635,7 @@ class RegularSyncSpec etcPeerManager.fishForSpecificMessageMatching() { case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { - case NewBlock64(`newBlock`, _, `num`) => true + case NewBlock(NewBlock.code64, `newBlock`, _) => true case _ => false } case _ => false @@ -634,7 +653,12 @@ class RegularSyncSpec before <- getSyncStatus _ <- Task { peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.number), defaultPeer.id)) + peerEventBus.reply( + MessageFromPeer( + NewBlock(testBlocks.last, ChainWeight.totalDifficultyOnly(testBlocks.last.number)), + defaultPeer.id + ) + ) } after <- getSyncStatus } yield { @@ -647,12 +671,21 @@ class RegularSyncSpec import fixture._ for { - _ <- testBlocks.take(5).traverse(block => Task { blockchain.save(block, Nil, 10000, saveAsBestBlock = true) }) + _ <- testBlocks + .take(5) + .traverse(block => + Task { blockchain.save(block, Nil, ChainWeight.totalDifficultyOnly(10000), saveAsBestBlock = true) } + ) _ <- Task { regularSync ! SyncProtocol.Start peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.number), defaultPeer.id)) + peerEventBus.reply( + MessageFromPeer( + NewBlock(testBlocks.last, ChainWeight.totalDifficultyOnly(testBlocks.last.number)), + defaultPeer.id + ) + ) peersClient.expectMsgEq(blockHeadersRequest(6)) peersClient.reply(PeersClient.Response(defaultPeer, BlockHeaders(testBlocksChunked.head.headers))) @@ -672,7 +705,12 @@ class RegularSyncSpec regularSync ! SyncProtocol.Start peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.number), defaultPeer.id)) + peerEventBus.reply( + MessageFromPeer( + NewBlock(testBlocks.last, ChainWeight.totalDifficultyOnly(testBlocks.last.number)), + defaultPeer.id + ) + ) peersClient.expectMsgEq(blockHeadersChunkRequest(0)) peersClient.reply(PeersClient.Response(defaultPeer, BlockHeaders(testBlocksChunked.head.headers))) @@ -696,7 +734,12 @@ class RegularSyncSpec regularSync ! SyncProtocol.Start peerEventBus.expectMsgClass(classOf[Subscribe]) - peerEventBus.reply(MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.number), defaultPeer.id)) + peerEventBus.reply( + MessageFromPeer( + NewBlock(testBlocks.last, ChainWeight.totalDifficultyOnly(testBlocks.last.number)), + defaultPeer.id + ) + ) } _ <- ledger.importedBlocks.take(5).lastL _ <- fishForStatus { @@ -730,7 +773,7 @@ class RegularSyncSpec importedBlocksSet.isEmpty || bestBlock.isParentOf(block) || importedBlocksSet.exists(_.isParentOf(block)) ) { importedBlocksSet.add(block) - BlockImportedToTop(List(BlockData(block, Nil, block.header.difficulty))) + BlockImportedToTop(List(BlockData(block, Nil, ChainWeight.totalDifficultyOnly(block.header.difficulty)))) } else if (block.number > bestBlock.number) { importedBlocksSet.add(block) BlockEnqueued diff --git a/src/test/scala/io/iohk/ethereum/db/storage/BlockBodiesStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/BlockBodiesStorageSpec.scala index af382792c4..f5b6caaa19 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/BlockBodiesStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/BlockBodiesStorageSpec.scala @@ -25,7 +25,7 @@ class BlockBodiesStorageSpec val blocks = newBlocks.distinct val totalStorage = insertBlockBodiesMapping(newBlocks) - blocks.foreach { case NewBlock(block, _, _) => + blocks.foreach { case NewBlock(_, block, _) => assert(totalStorage.get(block.header.hash).contains(block.body)) } } @@ -39,23 +39,23 @@ class BlockBodiesStorageSpec // Mapping of block bodies is deleted val (toDelete, toLeave) = blocks.splitAt(Gen.choose(0, blocks.size).sample.get) - val batchUpdates = toDelete.foldLeft(storage.emptyBatchUpdate) { case (updates, NewBlock(block, _, _)) => + val batchUpdates = toDelete.foldLeft(storage.emptyBatchUpdate) { case (updates, NewBlock(_, block, _)) => updates.and(storage.remove(block.header.hash)) } batchUpdates.commit() - toLeave.foreach { case NewBlock(block, _, _) => + toLeave.foreach { case NewBlock(_, block, _) => assert(storage.get(block.header.hash).contains(block.body)) } - toDelete.foreach { case NewBlock(block, _, _) => assert(storage.get(block.header.hash).isEmpty) } + toDelete.foreach { case NewBlock(_, block, _) => assert(storage.get(block.header.hash).isEmpty) } } } def insertBlockBodiesMapping(newBlocks: Seq[CommonMessages.NewBlock]): BlockBodiesStorage = { val storage = new BlockBodiesStorage(EphemDataSource()) - val batchUpdates = newBlocks.foldLeft(storage.emptyBatchUpdate) { case (updates, NewBlock(block, _, _)) => + val batchUpdates = newBlocks.foldLeft(storage.emptyBatchUpdate) { case (updates, NewBlock(_, block, _)) => updates.and(storage.put(block.header.hash, block.body)) } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/ChainWeightStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/ChainWeightStorageSuite.scala new file mode 100644 index 0000000000..e4ccc6b753 --- /dev/null +++ b/src/test/scala/io/iohk/ethereum/db/storage/ChainWeightStorageSuite.scala @@ -0,0 +1,54 @@ +package io.iohk.ethereum.db.storage + +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.db.dataSource.EphemDataSource +import org.scalacheck.Gen +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import org.scalatest.funsuite.AnyFunSuite + +class ChainWeightStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { + test("ChainWeightStorage insert") { + forAll(Gen.listOf(byteStringOfLengthNGen(32))) { blockByteArrayHashes => + val blockHashes = blockByteArrayHashes.distinct + val weightList = Gen.listOf(chainWeightGen).sample.get + val blockHashesWeightsPairs = weightList.zip(blockHashes) + + val storage = new ChainWeightStorage(EphemDataSource()) + val batchUpdates = blockHashesWeightsPairs.foldLeft(storage.emptyBatchUpdate) { + case (updates, (weight, blockHash)) => + updates.and(storage.put(blockHash, weight)) + } + batchUpdates.commit() + + blockHashesWeightsPairs.foreach { case (weight, blockHash) => assert(storage.get(blockHash).contains(weight)) } + } + } + + test("ChainWeightStorage delete") { + forAll(Gen.listOf(byteStringOfLengthNGen(32))) { blockByteArrayHashes => + val blockHashes = blockByteArrayHashes.distinct + val weightList = Gen.listOf(chainWeightGen).sample.get + val blockHashesWeightsPairs = weightList.zip(blockHashes) + + //Chain weight of blocks is inserted + val storage = new ChainWeightStorage(EphemDataSource()) + val storageInsertions = blockHashesWeightsPairs.foldLeft(storage.emptyBatchUpdate) { + case (updates, (td, blockHash)) => + updates.and(storage.put(blockHash, td)) + } + storageInsertions.commit() + + //Chain weight of blocks is deleted + val (toDelete, toLeave) = blockHashesWeightsPairs.splitAt(Gen.choose(0, blockHashesWeightsPairs.size).sample.get) + val storageDeletions = toDelete.foldLeft(storage.emptyBatchUpdate) { case (updates, (_, blockHash)) => + updates.and(storage.remove(blockHash)) + } + storageDeletions.commit() + + toLeave.foreach { case (weight, blockHeader) => + assert(storage.get(blockHeader).contains(weight)) + } + toDelete.foreach { case (_, bh) => assert(storage.get(bh).isEmpty) } + } + } +} diff --git a/src/test/scala/io/iohk/ethereum/db/storage/TotalDifficultyStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/TotalDifficultyStorageSuite.scala deleted file mode 100644 index ea4dcc5c4d..0000000000 --- a/src/test/scala/io/iohk/ethereum/db/storage/TotalDifficultyStorageSuite.scala +++ /dev/null @@ -1,52 +0,0 @@ -package io.iohk.ethereum.db.storage - -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.EphemDataSource -import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.funsuite.AnyFunSuite - -class TotalDifficultyStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { - test("TotalDifficultyStorage insert") { - forAll(Gen.listOf(byteStringOfLengthNGen(32))) { blockByteArrayHashes => - val blockHashes = blockByteArrayHashes.distinct - val tdList = Gen.listOf(bigIntGen).sample.get - val blockHashesTdPair = tdList.zip(blockHashes) - - val storage = new TotalDifficultyStorage(EphemDataSource()) - val batchUpdates = blockHashesTdPair.foldLeft(storage.emptyBatchUpdate) { case (updates, (td, blockHash)) => - updates.and(storage.put(blockHash, td)) - } - batchUpdates.commit() - - blockHashesTdPair.foreach { case (td, blockHash) => assert(storage.get(blockHash).contains(td)) } - } - } - - test("TotalDifficultyStorage delete") { - forAll(Gen.listOf(byteStringOfLengthNGen(32))) { blockByteArrayHashes => - val blockHashes = blockByteArrayHashes.distinct - val tdList = Gen.listOf(bigIntGen).sample.get - val blockHashesTdPair = tdList.zip(blockHashes) - - //Total difficulty of blocks is inserted - val storage = new TotalDifficultyStorage(EphemDataSource()) - val storageInsertions = blockHashesTdPair.foldLeft(storage.emptyBatchUpdate) { case (updates, (td, blockHash)) => - updates.and(storage.put(blockHash, td)) - } - storageInsertions.commit() - - //Total difficulty of blocks is deleted - val (toDelete, toLeave) = blockHashesTdPair.splitAt(Gen.choose(0, blockHashesTdPair.size).sample.get) - val storageDeletions = toDelete.foldLeft(storage.emptyBatchUpdate) { case (updates, (_, blockHash)) => - updates.and(storage.remove(blockHash)) - } - storageDeletions.commit() - - toLeave.foreach { case (td, blockHeader) => - assert(storage.get(blockHeader).contains(td)) - } - toDelete.foreach { case (_, bh) => assert(storage.get(bh).isEmpty) } - } - } -} diff --git a/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala b/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala index d37c1443b3..4afd27e39f 100644 --- a/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala +++ b/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala @@ -57,7 +57,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers { val validBlock = new CheckpointBlockGenerator().generate(parent, checkpoint) - blockchain.save(validBlock, Seq.empty, BigInt(0), saveAsBestBlock = true) + blockchain.save(validBlock, Seq.empty, ChainWeight(0, 0), saveAsBestBlock = true) val retrievedBlock = blockchain.getBlockByHash(validBlock.header.hash) assert(retrievedBlock.isDefined) @@ -85,9 +85,9 @@ class BlockchainSpec extends AnyFlatSpec with Matchers { val secondBlock = nextBlock(firstBlock) val thirdBlock = checkpointBlockGenerator.generate(secondBlock, checkpoint) - blockchain.save(firstBlock, Seq.empty, BigInt(0), saveAsBestBlock = true) - blockchain.save(secondBlock, Seq.empty, BigInt(0), saveAsBestBlock = true) - blockchain.save(thirdBlock, Seq.empty, BigInt(0), saveAsBestBlock = true) + blockchain.save(firstBlock, Seq.empty, ChainWeight(0, 0), saveAsBestBlock = true) + blockchain.save(secondBlock, Seq.empty, ChainWeight(0, 0), saveAsBestBlock = true) + blockchain.save(thirdBlock, Seq.empty, ChainWeight(0, 0), saveAsBestBlock = true) blockchain.removeBlock(thirdBlock.hash, withState = true) @@ -101,7 +101,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers { val validBlock = checkpointBlockGenerator.generate(genesis, checkpoint) - blockchain.save(validBlock, Seq.empty, BigInt(0), saveAsBestBlock = true) + blockchain.save(validBlock, Seq.empty, ChainWeight(0, 0), saveAsBestBlock = true) blockchain.removeBlock(validBlock.hash, withState = true) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/DebugServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/DebugServiceSpec.scala index 99438d26c4..be7cd00a75 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/DebugServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/DebugServiceSpec.scala @@ -5,6 +5,7 @@ import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.testkit.{TestKit, TestProbe} import io.iohk.ethereum.{Fixtures, WithActorSystemShutDown} +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse} import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo import io.iohk.ethereum.network.PeerManagerActor.Peers @@ -67,14 +68,13 @@ class DebugServiceSpec val peerStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = BigInt("10000"), + chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) val initialPeerInfo = PeerInfo( remoteStatus = peerStatus, - totalDifficulty = peerStatus.totalDifficulty, - latestCheckpointNumber = peerStatus.latestCheckpointNumber, + chainWeight = peerStatus.chainWeight, forkAccepted = false, maxBlockNumber = Fixtures.Blocks.Block3125369.header.number, bestBlockHash = peerStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala index 9f5bc6001f..e857d17254 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala @@ -250,7 +250,7 @@ class EthServiceSpec blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequestHash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequestHash, blockWeight)) .commit() blockchain.saveBestKnownBlocks(blockToRequest.header.number) @@ -267,10 +267,10 @@ class EthServiceSpec response.blockResponse shouldBe None } - it should "answer eth_getBlockByNumber with the block response correctly when it's totalDifficulty is in blockchain" in new TestSetup { + it should "answer eth_getBlockByNumber with the block response correctly when it's chain weight is in blockchain" in new TestSetup { blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequestHash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequestHash, blockWeight)) .commit() val request = BlockByNumberRequest(BlockParam.WithNumber(blockToRequestNumber), fullTxs = true) @@ -280,12 +280,14 @@ class EthServiceSpec TransactionResponse(stx, Some(blockToRequest.header), Some(txIndex)) } - response.blockResponse shouldBe Some(BlockResponse(blockToRequest, fullTxs = true, totalDifficulty = Some(blockTd))) - response.blockResponse.get.totalDifficulty shouldBe Some(blockTd) + response.blockResponse shouldBe Some( + BlockResponse(blockToRequest, fullTxs = true, weight = Some(blockWeight)) + ) + response.blockResponse.get.chainWeight shouldBe Some(blockWeight) response.blockResponse.get.transactions.right.toOption shouldBe Some(stxResponses) } - it should "answer eth_getBlockByNumber with the block response correctly when it's totalDifficulty is not in blockchain" in new TestSetup { + it should "answer eth_getBlockByNumber with the block response correctly when it's chain weight is not in blockchain" in new TestSetup { blockchain.storeBlock(blockToRequest).commit() val request = BlockByNumberRequest(BlockParam.WithNumber(blockToRequestNumber), fullTxs = true) @@ -296,23 +298,23 @@ class EthServiceSpec } response.blockResponse shouldBe Some(BlockResponse(blockToRequest, fullTxs = true)) - response.blockResponse.get.totalDifficulty shouldBe None + response.blockResponse.get.chainWeight shouldBe None response.blockResponse.get.transactions.right.toOption shouldBe Some(stxResponses) } it should "answer eth_getBlockByNumber with the block response correctly when the txs should be hashed" in new TestSetup { blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequestHash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequestHash, blockWeight)) .commit() val request = BlockByNumberRequest(BlockParam.WithNumber(blockToRequestNumber), fullTxs = true) val response = ethService.getBlockByNumber(request.copy(fullTxs = false)).runSyncUnsafe(Duration.Inf).right.get response.blockResponse shouldBe Some( - BlockResponse(blockToRequest, fullTxs = false, totalDifficulty = Some(blockTd)) + BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight)) ) - response.blockResponse.get.totalDifficulty shouldBe Some(blockTd) + response.blockResponse.get.chainWeight shouldBe Some(blockWeight) response.blockResponse.get.transactions.left.toOption shouldBe Some(blockToRequest.body.transactionList.map(_.hash)) } @@ -322,10 +324,10 @@ class EthServiceSpec response.blockResponse shouldBe None } - it should "answer eth_getBlockByHash with the block response correctly when it's totalDifficulty is in blockchain" in new TestSetup { + it should "answer eth_getBlockByHash with the block response correctly when it's chain weight is in blockchain" in new TestSetup { blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequestHash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequestHash, blockWeight)) .commit() val request = BlockByBlockHashRequest(blockToRequestHash, fullTxs = true) @@ -335,12 +337,14 @@ class EthServiceSpec TransactionResponse(stx, Some(blockToRequest.header), Some(txIndex)) } - response.blockResponse shouldBe Some(BlockResponse(blockToRequest, fullTxs = true, totalDifficulty = Some(blockTd))) - response.blockResponse.get.totalDifficulty shouldBe Some(blockTd) + response.blockResponse shouldBe Some( + BlockResponse(blockToRequest, fullTxs = true, weight = Some(blockWeight)) + ) + response.blockResponse.get.chainWeight shouldBe Some(blockWeight) response.blockResponse.get.transactions.right.toOption shouldBe Some(stxResponses) } - it should "answer eth_getBlockByHash with the block response correctly when it's totalDifficulty is not in blockchain" in new TestSetup { + it should "answer eth_getBlockByHash with the block response correctly when it's chain weight is not in blockchain" in new TestSetup { blockchain.storeBlock(blockToRequest).commit() val request = BlockByBlockHashRequest(blockToRequestHash, fullTxs = true) @@ -351,23 +355,23 @@ class EthServiceSpec } response.blockResponse shouldBe Some(BlockResponse(blockToRequest, fullTxs = true)) - response.blockResponse.get.totalDifficulty shouldBe None + response.blockResponse.get.chainWeight shouldBe None response.blockResponse.get.transactions.right.toOption shouldBe Some(stxResponses) } it should "answer eth_getBlockByHash with the block response correctly when the txs should be hashed" in new TestSetup { blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequestHash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequestHash, blockWeight)) .commit() val request = BlockByBlockHashRequest(blockToRequestHash, fullTxs = true) val response = ethService.getByBlockHash(request.copy(fullTxs = false)).runSyncUnsafe(Duration.Inf).right.get response.blockResponse shouldBe Some( - BlockResponse(blockToRequest, fullTxs = false, totalDifficulty = Some(blockTd)) + BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight)) ) - response.blockResponse.get.totalDifficulty shouldBe Some(blockTd) + response.blockResponse.get.chainWeight shouldBe Some(blockWeight) response.blockResponse.get.transactions.left.toOption shouldBe Some(blockToRequest.body.transactionList.map(_.hash)) } @@ -402,7 +406,7 @@ class EthServiceSpec response2.uncleBlockResponse shouldBe None } - it should "answer eth_getUncleByBlockHashAndIndex correctly when the requested index has one but there's no total difficulty for it" in new TestSetup { + it should "answer eth_getUncleByBlockHashAndIndex correctly when the requested index has one but there's no chain weight for it" in new TestSetup { blockchain.storeBlock(blockToRequestWithUncles).commit() val uncleIndexToRequest = 0 @@ -410,23 +414,23 @@ class EthServiceSpec val response = ethService.getUncleByBlockHashAndIndex(request).runSyncUnsafe(Duration.Inf).right.get response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, None, pendingBlock = false)) - response.uncleBlockResponse.get.totalDifficulty shouldBe None + response.uncleBlockResponse.get.chainWeight shouldBe None response.uncleBlockResponse.get.transactions shouldBe Left(Nil) response.uncleBlockResponse.get.uncles shouldBe Nil } - it should "anwer eth_getUncleByBlockHashAndIndex correctly when the requested index has one and there's total difficulty for it" in new TestSetup { + it should "anwer eth_getUncleByBlockHashAndIndex correctly when the requested index has one and there's chain weight for it" in new TestSetup { blockchain .storeBlock(blockToRequestWithUncles) - .and(blockchain.storeTotalDifficulty(uncle.hash, uncleTd)) + .and(blockchain.storeChainWeight(uncle.hash, uncleWeight)) .commit() val uncleIndexToRequest = 0 val request = UncleByBlockHashAndIndexRequest(blockToRequestHash, uncleIndexToRequest) val response = ethService.getUncleByBlockHashAndIndex(request).runSyncUnsafe(Duration.Inf).right.get - response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, Some(uncleTd), pendingBlock = false)) - response.uncleBlockResponse.get.totalDifficulty shouldBe Some(uncleTd) + response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, Some(uncleWeight), pendingBlock = false)) + response.uncleBlockResponse.get.chainWeight shouldBe Some(uncleWeight) response.uncleBlockResponse.get.transactions shouldBe Left(Nil) response.uncleBlockResponse.get.uncles shouldBe Nil } @@ -462,7 +466,7 @@ class EthServiceSpec response2.uncleBlockResponse shouldBe None } - it should "answer eth_getUncleByBlockNumberAndIndex correctly when the requested index has one but there's no total difficulty for it" in new TestSetup { + it should "answer eth_getUncleByBlockNumberAndIndex correctly when the requested index has one but there's no chain weight for it" in new TestSetup { blockchain.storeBlock(blockToRequestWithUncles).commit() val uncleIndexToRequest = 0 @@ -470,23 +474,23 @@ class EthServiceSpec val response = ethService.getUncleByBlockNumberAndIndex(request).runSyncUnsafe(Duration.Inf).right.get response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, None, pendingBlock = false)) - response.uncleBlockResponse.get.totalDifficulty shouldBe None + response.uncleBlockResponse.get.chainWeight shouldBe None response.uncleBlockResponse.get.transactions shouldBe Left(Nil) response.uncleBlockResponse.get.uncles shouldBe Nil } - it should "anwer eth_getUncleByBlockNumberAndIndex correctly when the requested index has one and there's total difficulty for it" in new TestSetup { + it should "anwer eth_getUncleByBlockNumberAndIndex correctly when the requested index has one and there's chain weight for it" in new TestSetup { blockchain .storeBlock(blockToRequestWithUncles) - .and(blockchain.storeTotalDifficulty(uncle.hash, uncleTd)) + .and(blockchain.storeChainWeight(uncle.hash, uncleWeight)) .commit() val uncleIndexToRequest = 0 val request = UncleByBlockNumberAndIndexRequest(BlockParam.WithNumber(blockToRequestNumber), uncleIndexToRequest) val response = ethService.getUncleByBlockNumberAndIndex(request).runSyncUnsafe(Duration.Inf).right.get - response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, Some(uncleTd), pendingBlock = false)) - response.uncleBlockResponse.get.totalDifficulty shouldBe Some(uncleTd) + response.uncleBlockResponse shouldBe Some(BlockResponse(uncle, Some(uncleWeight), pendingBlock = false)) + response.uncleBlockResponse.get.chainWeight shouldBe Some(uncleWeight) response.uncleBlockResponse.get.transactions shouldBe Left(Nil) response.uncleBlockResponse.get.uncles shouldBe Nil } @@ -536,7 +540,7 @@ class EthServiceSpec (ledger.consensus _: (() => Consensus)).expects().returns(consensus).anyNumberOfTimes() (blockGenerator.generateBlock _).expects(parentBlock, Nil, *, *).returning(PendingBlock(block, Nil)) - blockchain.save(parentBlock, Nil, parentBlock.header.difficulty, true) + blockchain.save(parentBlock, Nil, ChainWeight.totalDifficultyOnly(parentBlock.header.difficulty), true) val response = ethService.getWork(GetWorkRequest()).runSyncUnsafe() pendingTransactionsManager.expectMsg(PendingTransactionsManager.GetPendingTransactions) @@ -1231,10 +1235,10 @@ class EthServiceSpec val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) val blockToRequestNumber = blockToRequest.header.number val blockToRequestHash = blockToRequest.header.hash - val blockTd = blockToRequest.header.difficulty + val blockWeight = ChainWeight.totalDifficultyOnly(blockToRequest.header.difficulty) val uncle = Fixtures.Blocks.DaoForkBlock.header - val uncleTd = uncle.difficulty + val uncleWeight = ChainWeight.totalDifficultyOnly(uncle.difficulty) val blockToRequestWithUncles = blockToRequest.copy(body = BlockBody(Nil, Seq(uncle))) val difficulty = 131072 diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala index be749d7b7f..897db69e45 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala @@ -92,11 +92,11 @@ class JsonRpcControllerEthSpec it should "handle eth_getBlockByHash request" in new JsonRpcControllerFixture { val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) - val blockTd = blockToRequest.header.difficulty + val blockWeight = ChainWeight.zero.increase(blockToRequest.header) blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequest.header.hash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequest.header.hash, blockWeight)) .commit() val request = newJsonRpcRequest( @@ -106,18 +106,18 @@ class JsonRpcControllerEthSpec val response = jsonRpcController.handleRequest(request).runSyncUnsafe() val expectedBlockResponse = - Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, totalDifficulty = Some(blockTd))) + Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight))) response should haveResult(expectedBlockResponse) } it should "handle eth_getBlockByHash request (block with checkpoint)" in new JsonRpcControllerFixture { val blockToRequest = blockWithCheckpoint - val blockTd = blockToRequest.header.difficulty + val blockWeight = ChainWeight.zero.increase(blockToRequest.header) blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequest.header.hash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequest.header.hash, blockWeight)) .commit() val request = newJsonRpcRequest( @@ -127,18 +127,18 @@ class JsonRpcControllerEthSpec val response = jsonRpcController.handleRequest(request).runSyncUnsafe() val expectedBlockResponse = - Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, totalDifficulty = Some(blockTd))) + Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight))) response should haveResult(expectedBlockResponse) } it should "handle eth_getBlockByHash request (block with treasuryOptOut)" in new JsonRpcControllerFixture { val blockToRequest = blockWithTreasuryOptOut - val blockTd = blockToRequest.header.difficulty + val blockWeight = ChainWeight.zero.increase(blockToRequest.header) blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequest.header.hash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequest.header.hash, blockWeight)) .commit() val request = newJsonRpcRequest( @@ -148,18 +148,18 @@ class JsonRpcControllerEthSpec val response = jsonRpcController.handleRequest(request).runSyncUnsafe() val expectedBlockResponse = - Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, totalDifficulty = Some(blockTd))) + Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight))) response should haveResult(expectedBlockResponse) } it should "handle eth_getBlockByNumber request" in new JsonRpcControllerFixture { val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) - val blockTd = blockToRequest.header.difficulty + val blockWeight = ChainWeight.zero.increase(blockToRequest.header) blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequest.header.hash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequest.header.hash, blockWeight)) .commit() val request = newJsonRpcRequest( @@ -169,18 +169,18 @@ class JsonRpcControllerEthSpec val response = jsonRpcController.handleRequest(request).runSyncUnsafe() val expectedBlockResponse = - Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, totalDifficulty = Some(blockTd))) + Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight))) response should haveResult(expectedBlockResponse) } it should "handle eth_getBlockByNumber request (block with treasuryOptOut)" in new JsonRpcControllerFixture { val blockToRequest = blockWithTreasuryOptOut - val blockTd = blockToRequest.header.difficulty + val blockWeight = ChainWeight.zero.increase(blockToRequest.header) blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequest.header.hash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequest.header.hash, blockWeight)) .commit() val request = newJsonRpcRequest( @@ -190,18 +190,18 @@ class JsonRpcControllerEthSpec val response = jsonRpcController.handleRequest(request).runSyncUnsafe() val expectedBlockResponse = - Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, totalDifficulty = Some(blockTd))) + Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight))) response should haveResult(expectedBlockResponse) } it should "handle eth_getBlockByNumber request (block with checkpoint)" in new JsonRpcControllerFixture { val blockToRequest = blockWithCheckpoint - val blockTd = blockToRequest.header.difficulty + val blockWeight = ChainWeight.zero.increase(blockToRequest.header) blockchain .storeBlock(blockToRequest) - .and(blockchain.storeTotalDifficulty(blockToRequest.header.hash, blockTd)) + .and(blockchain.storeChainWeight(blockToRequest.header.hash, blockWeight)) .commit() val request = newJsonRpcRequest( @@ -211,7 +211,7 @@ class JsonRpcControllerEthSpec val response = jsonRpcController.handleRequest(request).runSyncUnsafe() val expectedBlockResponse = - Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, totalDifficulty = Some(blockTd))) + Extraction.decompose(BlockResponse(blockToRequest, fullTxs = false, weight = Some(blockWeight))) response should haveResult(expectedBlockResponse) } @@ -279,7 +279,7 @@ class JsonRpcControllerEthSpec val target = "0x1999999999999999999999999999999999999999999999999999999999999999" val headerPowHash = s"0x${Hex.toHexString(kec256(BlockHeader.getEncodedWithoutNonce(blockHeader)))}" - blockchain.save(parentBlock, Nil, parentBlock.header.difficulty, true) + blockchain.save(parentBlock, Nil, ChainWeight.zero.increase(parentBlock.header), true) (blockGenerator.generateBlock _) .expects(parentBlock, *, *, *) .returns(PendingBlock(Block(blockHeader, BlockBody(Nil, Nil)), Nil)) @@ -318,7 +318,7 @@ class JsonRpcControllerEthSpec val target = "0x1999999999999999999999999999999999999999999999999999999999999999" val headerPowHash = s"0x${Hex.toHexString(kec256(BlockHeader.getEncodedWithoutNonce(blockHeader)))}" - blockchain.save(parentBlock, Nil, parentBlock.header.difficulty, true) + blockchain.save(parentBlock, Nil, ChainWeight.zero.increase(parentBlock.header), true) (blockGenerator.generateBlock _) .expects(parentBlock, *, *, *) .returns(PendingBlock(Block(blockHeader, BlockBody(Nil, Nil)), Nil)) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala index bc9012a772..b467d4dcab 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala @@ -2,6 +2,7 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestKit +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse} import io.iohk.ethereum.jsonrpc.EthService._ import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig @@ -121,14 +122,13 @@ class JsonRpcControllerSpec val peerStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = BigInt("10000"), + chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) val initialPeerInfo = PeerInfo( remoteStatus = peerStatus, - totalDifficulty = peerStatus.totalDifficulty, - latestCheckpointNumber = peerStatus.latestCheckpointNumber, + chainWeight = peerStatus.chainWeight, forkAccepted = true, maxBlockNumber = Fixtures.Blocks.Block3125369.header.number, bestBlockHash = peerStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala index b64261b09e..8a825099ee 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala @@ -49,8 +49,7 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper val blockExecution = new BlockExecution(blockchain, blockchainConfig, newConsensus.blockPreparator, blockValidation) - val (blocks, error) = - blockExecution.executeAndValidateBlocks(List(block1, block2), defaultBlockHeader.difficulty) + val (blocks, error) = blockExecution.executeAndValidateBlocks(List(block1, block2), defaultChainWeight) // No block should be executed if first one has invalid transactions blocks.isEmpty shouldBe true @@ -84,8 +83,7 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper val blockExecution = new BlockExecution(blockchain, blockchainConfig, newConsensus.blockPreparator, blockValidation) - val (blocks, error) = - blockExecution.executeAndValidateBlocks(List(block1, block2), defaultBlockHeader.difficulty) + val (blocks, error) = blockExecution.executeAndValidateBlocks(List(block1, block2), defaultChainWeight) // Only first block should be executed blocks.size shouldBe 1 @@ -112,7 +110,7 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper val blockExecution = new BlockExecution(blockchain, blockchainConfig, newConsensus.blockPreparator, blockValidation) - val (blocks, error) = blockExecution.executeAndValidateBlocks(chain, defaultBlockHeader.difficulty) + val (blocks, error) = blockExecution.executeAndValidateBlocks(chain, defaultChainWeight) // All blocks but the last should be executed, and they should be returned in incremental order blocks.map(_.block) shouldBe chain.init @@ -132,7 +130,7 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper new BlockExecution(blockchain, blockchainConfig, newConsensus.blockPreparator, blockValidation) val (blocks, error) = - blockExecution.executeAndValidateBlocks(List(blockWithCheckpoint), defaultBlockHeader.difficulty) + blockExecution.executeAndValidateBlocks(List(blockWithCheckpoint), defaultChainWeight) val beneficiaryAccount = blockchain.getAccount(Address(blockWithCheckpoint.header.beneficiary), blockWithCheckpoint.number) val treasuryAccountAfter = blockchain.getAccount(blockchainConfig.treasuryAddress, blockWithCheckpoint.number) diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala index 4f29449312..77a3302b5f 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala @@ -42,23 +42,23 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { setBlockExists(block, inChain = false, inQueue = false) setBestBlock(bestBlock) - setTotalDifficultyForBlock(bestBlock, currentTd) + setChainWeightForBlock(bestBlock, currentWeight) - val newTd: BigInt = currentTd + difficulty - val blockData = BlockData(block, Seq.empty[Receipt], newTd) + val newWeight = currentWeight.increaseTotalDifficulty(difficulty) + val blockData = BlockData(block, Seq.empty[Receipt], newWeight) val emptyWorld: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) .getWorldStateProxy(-1, UInt256.Zero, None, noEmptyAccounts = false, ethCompatibleStorage = true) // Just to bypass metrics needs (blockchain.getBlockByHash _).expects(*).returning(None) - (blockQueue.enqueueBlock _).expects(block, bestNum).returning(Some(Leaf(hash, newTd))) + (blockQueue.enqueueBlock _).expects(block, bestNum).returning(Some(Leaf(hash, newWeight))) (blockQueue.getBranch _).expects(hash, true).returning(List(block)) (blockchain.getBlockHeaderByHash _).expects(*).returning(Some(block.header)) (blockchain.getWorldStateProxy _).expects(*, *, *, *, *).returning(emptyWorld) - expectBlockSaved(block, Seq.empty[Receipt], newTd, saveAsBestBlock = true) + expectBlockSaved(block, Seq.empty[Receipt], newWeight, saveAsBestBlock = true) whenReady(ledgerNotFailingAfterExecValidation.importBlock(block)) { _ shouldEqual BlockImportedToTop(List(blockData)) @@ -70,10 +70,12 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { setBlockExists(block, inChain = false, inQueue = false) setBestBlock(bestBlock) - setTotalDifficultyForBlock(bestBlock, currentTd) + setChainWeightForBlock(bestBlock, currentWeight) val hash: ByteString = block.header.hash - (blockQueue.enqueueBlock _).expects(block, bestNum).returning(Some(Leaf(hash, currentTd + block.header.difficulty))) + (blockQueue.enqueueBlock _) + .expects(block, bestNum) + .returning(Some(Leaf(hash, currentWeight.increase(block.header)))) (blockQueue.getBranch _).expects(hash, true).returning(List(block)) val emptyWorld: InMemoryWorldStateProxy = BlockchainImpl(storagesInstance.storages) @@ -94,23 +96,23 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val oldBlock2: Block = getBlock(bestNum - 1, difficulty = 102, parent = block1.header.hash) val oldBlock3: Block = getBlock(bestNum, difficulty = 103, parent = oldBlock2.header.hash) - val td1: BigInt = block1.header.difficulty + 999 - val newTd2: BigInt = td1 + newBlock2.header.difficulty - val newTd3: BigInt = newTd2 + newBlock3.header.difficulty - val oldTd2: BigInt = td1 + oldBlock2.header.difficulty - val oldTd3: BigInt = oldTd2 + oldBlock3.header.difficulty + 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) - blockchain.save(block1, Nil, td1, saveAsBestBlock = true) - blockchain.save(oldBlock2, receipts, oldTd2, saveAsBestBlock = true) - blockchain.save(oldBlock3, Nil, oldTd3, saveAsBestBlock = true) + blockchain.save(block1, Nil, weight1, saveAsBestBlock = true) + blockchain.save(oldBlock2, receipts, oldWeight2, saveAsBestBlock = true) + blockchain.save(oldBlock3, Nil, oldWeight3, saveAsBestBlock = true) val ancestorForValidation: Block = getBlock(0, difficulty = 1) - blockchain.save(ancestorForValidation, Nil, 1, saveAsBestBlock = false) + blockchain.save(ancestorForValidation, Nil, ChainWeight.totalDifficultyOnly(1), saveAsBestBlock = false) val oldBranch = List(oldBlock2, oldBlock3) val newBranch = List(newBlock2, newBlock3) - val blockData2 = BlockData(newBlock2, Seq.empty[Receipt], newTd2) - val blockData3 = BlockData(newBlock3, Seq.empty[Receipt], newTd3) + val blockData2 = BlockData(newBlock2, Seq.empty[Receipt], newWeight2) + val blockData3 = BlockData(newBlock3, Seq.empty[Receipt], newWeight3) (ledgerWithMockedBlockExecution.blockExecution.executeAndValidateBlocks _) .expects(newBranch, *) @@ -118,15 +120,15 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { whenReady(ledgerWithMockedBlockExecution.importBlock(newBlock3)) { result => result shouldEqual BlockEnqueued } whenReady(ledgerWithMockedBlockExecution.importBlock(newBlock2)) { result => - result shouldEqual ChainReorganised(oldBranch, newBranch, List(newTd2, newTd3)) + result shouldEqual ChainReorganised(oldBranch, newBranch, List(newWeight2, newWeight3)) } // Saving new blocks, because it's part of executeBlocks method mechanism - blockchain.save(blockData2.block, blockData2.receipts, blockData2.td, saveAsBestBlock = true) - blockchain.save(blockData3.block, blockData3.receipts, blockData3.td, saveAsBestBlock = true) + blockchain.save(blockData2.block, blockData2.receipts, blockData2.weight, saveAsBestBlock = true) + blockchain.save(blockData3.block, blockData3.receipts, blockData3.weight, saveAsBestBlock = true) blockchain.getBestBlock() shouldEqual newBlock3 - blockchain.getTotalDifficultyByHash(newBlock3.header.hash) shouldEqual Some(newTd3) + blockchain.getChainWeightByHash(newBlock3.header.hash) shouldEqual Some(newWeight3) blockQueue.isQueued(oldBlock2.header.hash) shouldBe true blockQueue.isQueued(oldBlock3.header.hash) shouldBe true @@ -139,23 +141,24 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val oldBlock2: Block = getBlock(bestNum - 1, difficulty = 102, parent = block1.header.hash) val oldBlock3: Block = getBlock(bestNum, difficulty = 103, parent = oldBlock2.header.hash) - val td1: BigInt = block1.header.difficulty + 999 - val newTd2: BigInt = td1 + newBlock2.header.difficulty - val newTd3: BigInt = newTd2 + newBlock3.header.difficulty - val oldTd2: BigInt = td1 + oldBlock2.header.difficulty - val oldTd3: BigInt = oldTd2 + oldBlock3.header.difficulty + 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) - blockchain.save(block1, Nil, td1, saveAsBestBlock = true) - blockchain.save(oldBlock2, receipts, oldTd2, saveAsBestBlock = true) - blockchain.save(oldBlock3, Nil, oldTd3, saveAsBestBlock = true) + blockchain.save(block1, Nil, weight1, saveAsBestBlock = true) + blockchain.save(oldBlock2, receipts, oldWeight2, saveAsBestBlock = true) + blockchain.save(oldBlock3, Nil, oldWeight3, saveAsBestBlock = true) val ancestorForValidation: Block = getBlock(0, difficulty = 1) - blockchain.save(ancestorForValidation, Nil, 1, saveAsBestBlock = false) + blockchain.save(ancestorForValidation, Nil, ChainWeight.totalDifficultyOnly(1), saveAsBestBlock = false) + //FIXME: unused vals??? val oldBranch = List(oldBlock2, oldBlock3) val newBranch = List(newBlock2, newBlock3) - val blockData2 = BlockData(newBlock2, Seq.empty[Receipt], newTd2) - val blockData3 = BlockData(newBlock3, Seq.empty[Receipt], newTd3) + val blockData2 = BlockData(newBlock2, Seq.empty[Receipt], newWeight2) + val blockData3 = BlockData(newBlock3, Seq.empty[Receipt], newWeight3) (ledgerWithMockedBlockExecution.blockExecution.executeAndValidateBlocks _) .expects(newBranch, *) @@ -165,7 +168,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { whenReady(ledgerWithMockedBlockExecution.importBlock(newBlock2)) { _ shouldBe a[BlockImportFailed] } blockchain.getBestBlock() shouldEqual oldBlock3 - blockchain.getTotalDifficultyByHash(oldBlock3.header.hash) shouldEqual Some(oldTd3) + blockchain.getChainWeightByHash(oldBlock3.header.hash) shouldEqual Some(oldWeight3) blockQueue.isQueued(newBlock2.header.hash) shouldBe true blockQueue.isQueued(newBlock3.header.hash) shouldBe false @@ -183,7 +186,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val newBlock: Block = getBlock(number = bestNum + 1) setBlockExists(newBlock, inChain = false, inQueue = false) setBestBlock(bestBlock) - setTotalDifficultyForBlock(bestBlock, currentTd) + setChainWeightForBlock(bestBlock, currentWeight) (validators.blockHeaderValidator .validate(_: BlockHeader, _: GetBlockHeaderByHash)) @@ -205,7 +208,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val newBlock: Block = getBlock(number = bestNum + 1) setBlockExists(newBlock, inChain = false, inQueue = false) setBestBlock(bestBlock) - setTotalDifficultyForBlock(bestBlock, currentTd) + setChainWeightForBlock(bestBlock, currentWeight) (validators.blockHeaderValidator .validate(_: BlockHeader, _: GetBlockHeaderByHash)) @@ -240,25 +243,25 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val newBlock3WithOmmer: Block = getBlock(bestNum, difficulty = 105, parent = newBlock2.header.hash, ommers = Seq(ommerBlock.header)) - val td1: BigInt = block1.header.difficulty + 999 - val oldTd2: BigInt = td1 + oldBlock2.header.difficulty - val oldTd3: BigInt = oldTd2 + oldBlock3.header.difficulty + val weight1 = ChainWeight.totalDifficultyOnly(block1.header.difficulty + 999) + val oldWeight2 = weight1.increase(oldBlock2.header) + val oldWeight3 = oldWeight2.increase(oldBlock3.header) - val newTd2: BigInt = td1 + newBlock2.header.difficulty - val newTd3: BigInt = newTd2 + newBlock3WithOmmer.header.difficulty + val newWeight2 = weight1.increase(newBlock2.header) + val newWeight3 = newWeight2.increase(newBlock3WithOmmer.header) - blockchain.save(ancestorForValidation, Nil, 1, saveAsBestBlock = false) - blockchain.save(ancestorForValidation1, Nil, 3, saveAsBestBlock = false) - blockchain.save(ancestorForValidation2, Nil, 6, saveAsBestBlock = false) + blockchain.save(ancestorForValidation, Nil, ChainWeight.totalDifficultyOnly(1), saveAsBestBlock = false) + blockchain.save(ancestorForValidation1, Nil, ChainWeight.totalDifficultyOnly(3), saveAsBestBlock = false) + blockchain.save(ancestorForValidation2, Nil, ChainWeight.totalDifficultyOnly(6), saveAsBestBlock = false) - blockchain.save(block1, Nil, td1, saveAsBestBlock = true) - blockchain.save(oldBlock2, receipts, oldTd2, saveAsBestBlock = true) - blockchain.save(oldBlock3, Nil, oldTd3, saveAsBestBlock = true) + blockchain.save(block1, Nil, weight1, saveAsBestBlock = true) + blockchain.save(oldBlock2, receipts, oldWeight2, saveAsBestBlock = true) + blockchain.save(oldBlock3, Nil, oldWeight3, saveAsBestBlock = true) val oldBranch = List(oldBlock2, oldBlock3) val newBranch = List(newBlock2, newBlock3WithOmmer) - val blockData2 = BlockData(newBlock2, Seq.empty[Receipt], newTd2) - val blockData3 = BlockData(newBlock3WithOmmer, Seq.empty[Receipt], newTd3) + val blockData2 = BlockData(newBlock2, Seq.empty[Receipt], newWeight2) + val blockData3 = BlockData(newBlock3WithOmmer, Seq.empty[Receipt], newWeight3) (ledgerWithMockedBlockExecution.blockExecution.executeAndValidateBlocks _) .expects(newBranch, *) @@ -266,12 +269,12 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { whenReady(ledgerWithMockedBlockExecution.importBlock(newBlock2)) { _ shouldEqual BlockEnqueued } whenReady(ledgerWithMockedBlockExecution.importBlock(newBlock3WithOmmer)) { result => - result shouldEqual ChainReorganised(oldBranch, newBranch, List(newTd2, newTd3)) + result shouldEqual ChainReorganised(oldBranch, newBranch, List(newWeight2, newWeight3)) } // Saving new blocks, because it's part of executeBlocks method mechanism - blockchain.save(blockData2.block, blockData2.receipts, blockData2.td, saveAsBestBlock = true) - blockchain.save(blockData3.block, blockData3.receipts, blockData3.td, saveAsBestBlock = true) + blockchain.save(blockData2.block, blockData2.receipts, blockData2.weight, saveAsBestBlock = true) + blockchain.save(blockData3.block, blockData3.receipts, blockData3.weight, saveAsBestBlock = true) blockchain.getBestBlock() shouldEqual newBlock3WithOmmer } @@ -281,30 +284,30 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val regularBlock: Block = getBlock(bestNum + 1, difficulty = 200, parent = parentBlock.hash) val checkpointBlock: Block = getCheckpointBlock(parentBlock, difficulty = 100) - val tdParent = parentBlock.header.difficulty + 999 - val tdRegular = tdParent + regularBlock.header.difficulty - val tdCheckpoint = tdParent + checkpointBlock.header.difficulty + val weightParent = ChainWeight.totalDifficultyOnly(parentBlock.header.difficulty + 999) + val weightRegular = weightParent.increase(regularBlock.header) + val weightCheckpoint = weightParent.increase(checkpointBlock.header) - blockchain.save(parentBlock, Nil, tdParent, saveAsBestBlock = true) - blockchain.save(regularBlock, Nil, tdRegular, saveAsBestBlock = true) + blockchain.save(parentBlock, Nil, weightParent, saveAsBestBlock = true) + blockchain.save(regularBlock, Nil, weightRegular, saveAsBestBlock = true) (ledgerWithMockedBlockExecution.blockExecution.executeAndValidateBlocks _) .expects(List(checkpointBlock), *) - .returning((List(BlockData(checkpointBlock, Nil, tdCheckpoint)), None)) + .returning((List(BlockData(checkpointBlock, Nil, weightCheckpoint)), None)) whenReady(ledgerWithMockedBlockExecution.importBlock(checkpointBlock)) { result => result shouldEqual ChainReorganised( List(regularBlock), List(checkpointBlock), - List(tdCheckpoint) + List(weightCheckpoint) ) } // Saving new blocks, because it's part of executeBlocks method mechanism - blockchain.save(checkpointBlock, Nil, tdCheckpoint, saveAsBestBlock = true) + blockchain.save(checkpointBlock, Nil, weightCheckpoint, saveAsBestBlock = true) blockchain.getBestBlock() shouldEqual checkpointBlock - blockchain.getTotalDifficultyByHash(checkpointBlock.hash) shouldEqual Some(tdCheckpoint) + blockchain.getChainWeightByHash(checkpointBlock.hash) shouldEqual Some(weightCheckpoint) } it should "not import a block with higher difficulty that does not follow a checkpoint" in new EphemBlockchain @@ -314,11 +317,11 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val regularBlock: Block = getBlock(bestNum + 1, difficulty = 200, parent = parentBlock.hash) val checkpointBlock: Block = getCheckpointBlock(parentBlock, difficulty = 100) - val tdParent = parentBlock.header.difficulty + 999 - val tdCheckpoint = tdParent + checkpointBlock.header.difficulty + val weightParent = ChainWeight.totalDifficultyOnly(parentBlock.header.difficulty + 999) + val weightCheckpoint = weightParent.increase(checkpointBlock.header) - blockchain.save(parentBlock, Nil, tdParent, saveAsBestBlock = true) - blockchain.save(checkpointBlock, Nil, tdCheckpoint, saveAsBestBlock = true) + blockchain.save(parentBlock, Nil, weightParent, saveAsBestBlock = true) + blockchain.save(checkpointBlock, Nil, weightCheckpoint, saveAsBestBlock = true) whenReady(ledgerWithMockedBlockExecution.importBlock(regularBlock)) { result => result shouldEqual BlockEnqueued diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockQueueSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockQueueSpec.scala index fe228f1aa2..f1211345da 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockQueueSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockQueueSpec.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.ledger import akka.util.ByteString import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.domain.{Block, BlockBody, BlockchainImpl} +import io.iohk.ethereum.domain.{Block, BlockBody, BlockchainImpl, ChainWeight} import io.iohk.ethereum.Fixtures import io.iohk.ethereum.ledger.BlockQueue.Leaf import io.iohk.ethereum.utils.Config @@ -15,10 +15,11 @@ class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { "BlockQueue" should "ignore block if it's already in the queue" in new TestConfig { val block = getBlock(1) + val parentWeight = ChainWeight.zero setBestBlockNumber(1).twice() - setTotalDifficultyForParent(block, Some(0)) + setChainWeightForParent(block, Some(parentWeight)) - blockQueue.enqueueBlock(block) shouldEqual Some(Leaf(block.header.hash, block.header.difficulty)) + blockQueue.enqueueBlock(block) shouldEqual Some(Leaf(block.header.hash, parentWeight.increase(block.header))) blockQueue.enqueueBlock(block) shouldEqual None blockQueue.isQueued(block.header.hash) shouldBe true } @@ -38,14 +39,14 @@ class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { it should "remove the blocks that fall out of range" in new TestConfig { val block1 = getBlock(1) setBestBlockNumber(1) - setTotalDifficultyForParent(block1) + setChainWeightForParent(block1) blockQueue.enqueueBlock(block1) blockQueue.isQueued(block1.header.hash) shouldBe true val block20 = getBlock(20) setBestBlockNumber(20) - setTotalDifficultyForParent(block20) + setChainWeightForParent(block20) blockQueue.enqueueBlock(block20) blockQueue.isQueued(block20.header.hash) shouldBe true @@ -54,10 +55,11 @@ class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { it should "enqueue a block with parent on the main chain updating its total difficulty" in new TestConfig { val block1 = getBlock(1, 13) + val parentWeight = ChainWeight.totalDifficultyOnly(42) setBestBlockNumber(1) - setTotalDifficultyForParent(block1, Some(42)) + setChainWeightForParent(block1, Some(parentWeight)) - blockQueue.enqueueBlock(block1) shouldEqual Some(Leaf(block1.header.hash, block1.header.difficulty + 42)) + blockQueue.enqueueBlock(block1) shouldEqual Some(Leaf(block1.header.hash, parentWeight.increase(block1.header))) } it should "enqueue a block with queued ancestors rooted to the main chain updating its total difficulty" in new TestConfig { @@ -66,24 +68,26 @@ class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { val block2b = getBlock(2, 99, block1.header.hash) val block3 = getBlock(3, 103, block2a.header.hash) + val parentWeight = ChainWeight.totalDifficultyOnly(42) + setBestBlockNumber(1).anyNumberOfTimes() - setTotalDifficultyForParent(block1, Some(42)) - setTotalDifficultyForParent(block2a, None) - setTotalDifficultyForParent(block2b, None) - setTotalDifficultyForParent(block3, None) + setChainWeightForParent(block1, Some(parentWeight)) + setChainWeightForParent(block2a, None) + setChainWeightForParent(block2b, None) + setChainWeightForParent(block3, None) blockQueue.enqueueBlock(block1) blockQueue.enqueueBlock(block2a) blockQueue.enqueueBlock(block2b) - val expectedTd = 42 + List(block1, block2a, block3).map(_.header.difficulty).sum - blockQueue.enqueueBlock(block3) shouldEqual Some(Leaf(block3.header.hash, expectedTd)) + val expectedWeight = List(block1, block2a, block3).map(_.header).foldLeft(parentWeight)(_ increase _) + blockQueue.enqueueBlock(block3) shouldEqual Some(Leaf(block3.header.hash, expectedWeight)) } it should "enqueue an orphaned block" in new TestConfig { val block1 = getBlock(1) setBestBlockNumber(1) - setTotalDifficultyForParent(block1) + setChainWeightForParent(block1) blockQueue.enqueueBlock(block1) shouldBe None blockQueue.isQueued(block1.header.hash) shouldBe true @@ -96,10 +100,10 @@ class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { val block3 = getBlock(3, parent = block2a.header.hash) setBestBlockNumber(1).anyNumberOfTimes() - setTotalDifficultyForParent(block1) - setTotalDifficultyForParent(block2a) - setTotalDifficultyForParent(block2b) - setTotalDifficultyForParent(block3) + setChainWeightForParent(block1) + setChainWeightForParent(block2a) + setChainWeightForParent(block2b) + setChainWeightForParent(block3) blockQueue.enqueueBlock(block1) blockQueue.enqueueBlock(block2a) @@ -122,11 +126,11 @@ class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { val block3 = getBlock(3, parent = block2a.header.hash) setBestBlockNumber(1).anyNumberOfTimes() - setTotalDifficultyForParent(block1a) - setTotalDifficultyForParent(block1b) - setTotalDifficultyForParent(block2a) - setTotalDifficultyForParent(block2b) - setTotalDifficultyForParent(block3) + setChainWeightForParent(block1a) + setChainWeightForParent(block1b) + setChainWeightForParent(block2a) + setChainWeightForParent(block2b) + setChainWeightForParent(block3) blockQueue.enqueueBlock(block1a) blockQueue.enqueueBlock(block1b) @@ -157,8 +161,8 @@ class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { def setBestBlockNumber(n: BigInt) = (blockchain.getBestBlockNumber _).expects().returning(n) - def setTotalDifficultyForParent(block: Block, td: Option[BigInt] = None) = - (blockchain.getTotalDifficultyByHash _).expects(block.header.parentHash).returning(td) + def setChainWeightForParent(block: Block, weight: Option[ChainWeight] = None) = + (blockchain.getChainWeightByHash _).expects(block.header.parentHash).returning(weight) def randomHash(): ByteString = ObjectGenerators.byteStringOfLengthNGen(32).sample.get diff --git a/src/test/scala/io/iohk/ethereum/ledger/BranchResolutionSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BranchResolutionSpec.scala index 5b7b1b1f90..3771aa7429 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BranchResolutionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BranchResolutionSpec.scala @@ -3,7 +3,7 @@ package io.iohk.ethereum.ledger import akka.util.ByteString import cats.data.NonEmptyList import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader} +import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} import org.scalacheck.Gen import org.scalatest.concurrent.ScalaFutures import org.scalatest.matchers.should.Matchers @@ -47,31 +47,29 @@ class BranchResolutionSpec ledger.resolveBranch(headers) shouldEqual UnknownBranch } - "report new better branch found when headers form a branch of higher difficulty than corresponding know headers" in + "report new better branch found when headers form a branch of higher chain weight than corresponding known headers" in new BranchResolutionTestSetup { val headers = getChainHeadersNel(1, 10) - setGenesisHeader(genesisHeader) // Check genesis block - setBestBlockNumber(10) setHeaderByHash(headers.head.parentHash, Some(getBlock(0).header)) + setChainWeightByHash(headers.head.parentHash, ChainWeight.zero) - val oldBlocks = headers.map(h => getBlock(h.number, h.difficulty - 1)) + val oldBlocks = getChain(1, 10, headers.head.parentHash, headers.head.difficulty - 1) oldBlocks.map(b => setBlockByNumber(b.header.number, Some(b))) ledger.resolveBranch(headers) shouldEqual NewBetterBranch(oldBlocks.toList) } - "report no need for a chain switch the headers do not have difficulty greater than currently known branch" in + "report no need for a chain switch the headers do not have chain weight greater than currently known branch" in new BranchResolutionTestSetup { val headers = getChainHeadersNel(1, 10) - setGenesisHeader(genesisHeader) // Check genesis block - setBestBlockNumber(10) setHeaderByHash(headers.head.parentHash, Some(getBlock(0).header)) + setChainWeightByHash(headers.head.parentHash, ChainWeight.zero) - val oldBlocks = headers.map(h => getBlock(h.number, h.difficulty)) + val oldBlocks = getChain(1, 10, headers.head.parentHash, headers.head.difficulty) oldBlocks.map(b => setBlockByNumber(b.header.number, Some(b))) ledger.resolveBranch(headers) shouldEqual NoChainSwitch @@ -82,10 +80,12 @@ class BranchResolutionSpec setGenesisHeader(genesisHeader) setBestBlockNumber(10) - val oldBlocks: List[Block] = headers.tail.map(h => getBlock(h.number, h.difficulty - 1)) - oldBlocks.foreach(b => setBlockByNumber(b.header.number, Some(b))) + setChainWeightByHash(genesisHeader.hash, ChainWeight.zero) setBlockByNumber(0, Some(Block(genesisHeader, BlockBody(Nil, Nil)))) + val oldBlocks: List[Block] = getChain(1, 10, genesisHeader.hash, headers.tail.head.difficulty - 1) + oldBlocks.foreach(b => setBlockByNumber(b.header.number, Some(b))) + ledger.resolveBranch(headers) shouldEqual NewBetterBranch(oldBlocks) } @@ -101,33 +101,35 @@ class BranchResolutionSpec "not include common prefix as result when finding a new better branch" in new BranchResolutionTestSetup { val headers = getChainHeadersNel(1, 10) - - setGenesisHeader(genesisHeader) // Check genesis block + val commonParent = headers.toList(1) setBestBlockNumber(8) setHeaderByHash(headers.head.parentHash, Some(getBlock(0).header)) + setChainWeightByHash(commonParent.hash, ChainWeight.zero) - val oldBlocks = headers.toList.slice(2, 8).map(h => getBlock(h.number, h.difficulty - 1)) + val oldBlocks = getChain(3, 8, commonParent.hash) oldBlocks.foreach(b => setBlockByNumber(b.header.number, Some(b))) + setBlockByNumber(1, Some(Block(headers.head, BlockBody(Nil, Nil)))) setBlockByNumber(2, Some(Block(headers.tail.head, BlockBody(Nil, Nil)))) - setBlockByNumber(9, None) ledger.resolveBranch(headers) shouldEqual NewBetterBranch(oldBlocks) assert(oldBlocks.map(_.header.number) == List[BigInt](3, 4, 5, 6, 7, 8)) } - "report a new better branch with higher TD even if its shorter than the current " in new BranchResolutionTestSetup { + "report a new better branch with higher chain weight even if its shorter than the current " in new BranchResolutionTestSetup { val commonParent = getBlock(1, parent = genesisHeader.hash) - val longerBranchLowerTd = getChain(2, 10, commonParent.hash, difficulty = 100) - val shorterBranchHigherTd = getChainNel(2, 8, commonParent.hash, difficulty = 200) + val parentWeight = ChainWeight.zero.increase(commonParent.header) + val longerBranchLowerWeight = getChain(2, 10, commonParent.hash, difficulty = 100) + val shorterBranchHigherWeight = getChainNel(2, 8, commonParent.hash, difficulty = 200) setHeaderByHash(commonParent.hash, Some(commonParent.header)) - setBestBlockNumber(longerBranchLowerTd.last.number) - longerBranchLowerTd.foreach(b => setBlockByNumber(b.number, Some(b))) + setChainWeightForBlock(commonParent, parentWeight) + setBestBlockNumber(longerBranchLowerWeight.last.number) + longerBranchLowerWeight.foreach(b => setBlockByNumber(b.number, Some(b))) - ledger.resolveBranch(shorterBranchHigherTd.map(_.header)) shouldEqual NewBetterBranch( - longerBranchLowerTd + ledger.resolveBranch(shorterBranchHigherWeight.map(_.header)) shouldEqual NewBetterBranch( + longerBranchLowerWeight ) } @@ -138,6 +140,7 @@ class BranchResolutionSpec // test checkpoint at random position in the chain forAll(Gen.choose(2, checkpointBranchLength)) { checkpointPos => val commonParent = getBlock(1, parent = genesisHeader.hash) + val parentWeight = ChainWeight.zero.increase(commonParent.header) val checkpointBranch = NonEmptyList.fromListUnsafe { val beforeCheckpoint = commonParent :: getChain(2, checkpointPos - 1, commonParent.hash) val checkpoint = getCheckpointBlock(beforeCheckpoint.last, commonParent.header.difficulty) @@ -148,6 +151,7 @@ class BranchResolutionSpec val noCheckpointBranch = getChain(2, checkpointBranchLength + 2, commonParent.hash) setHeaderByHash(commonParent.hash, Some(commonParent.header)) + setChainWeightForBlock(commonParent, parentWeight) setBestBlockNumber(noCheckpointBranch.last.number) noCheckpointBranch.foreach(b => setBlockByNumber(b.number, Some(b))) @@ -162,6 +166,7 @@ class BranchResolutionSpec // test checkpoint at random position in the chain forAll(Gen.choose(2, checkpointBranchLength)) { checkpointPos => val commonParent = getBlock(1, parent = genesisHeader.hash) + val parentWeight = ChainWeight.zero.increase(commonParent.header) val checkpointBranch = NonEmptyList.fromListUnsafe { val beforeCheckpoint = commonParent :: getChain(2, checkpointPos - 1, commonParent.hash) val checkpoint = getCheckpointBlock(beforeCheckpoint.last, commonParent.header.difficulty) @@ -172,6 +177,7 @@ class BranchResolutionSpec val noCheckpointBranch = getChainNel(2, checkpointBranchLength + 2, commonParent.hash) setHeaderByHash(commonParent.hash, Some(commonParent.header)) + setChainWeightForBlock(commonParent, parentWeight) setBestBlockNumber(checkpointBranch.last.number) checkpointBranch.map(b => setBlockByNumber(b.number, Some(b))) diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala index d40d673ebd..99057e7f91 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala @@ -71,6 +71,8 @@ trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { data = ByteString(Hex.decode("1" * 128)) ) + val defaultChainWeight = ChainWeight.zero.increase(defaultBlockHeader) + val initialOriginBalance: UInt256 = 100000000 val initialMinerBalance: UInt256 = 2000000 @@ -173,7 +175,7 @@ trait BlockchainSetup extends TestSetup { .storeBlockHeader(validBlockParentHeader) .and(blockchain.storeBlockBody(validBlockParentHeader.hash, validBlockBodyWithNoTxs)) .and(storagesInstance.storages.appStateStorage.putBestBlockNumber(validBlockParentHeader.number)) - .and(storagesInstance.storages.totalDifficultyStorage.put(validBlockParentHeader.hash, 0)) + .and(storagesInstance.storages.chainWeightStorage.put(validBlockParentHeader.hash, ChainWeight.zero)) .commit() val validTx: Transaction = defaultTx.copy( @@ -316,11 +318,11 @@ trait TestSetupWithVmAndValidators extends EphemBlockchainTestSetup { val receipts = Seq(Receipt.withHashOutcome(randomHash(), 50000, randomHash(), Nil)) - val currentTd = 99999 + val currentWeight = ChainWeight.totalDifficultyOnly(99999) val bestNum = BigInt(5) - val bestBlock: Block = getBlock(bestNum, currentTd / 2) + val bestBlock: Block = getBlock(bestNum, currentWeight.totalDifficulty / 2) val execError = ValidationAfterExecError("error") @@ -367,18 +369,21 @@ trait MockBlockchain extends MockFactory { self: TestSetupWithVmAndValidators => def setBestBlockNumber(num: BigInt): CallHandler0[BigInt] = (blockchain.getBestBlockNumber _).expects().returning(num) - def setTotalDifficultyForBlock(block: Block, td: BigInt): CallHandler1[ByteString, Option[BigInt]] = - (blockchain.getTotalDifficultyByHash _).expects(block.header.hash).returning(Some(td)) + def setChainWeightForBlock(block: Block, weight: ChainWeight): CallHandler1[ByteString, Option[ChainWeight]] = + setChainWeightByHash(block.hash, weight) + + def setChainWeightByHash(hash: ByteString, weight: ChainWeight): CallHandler1[ByteString, Option[ChainWeight]] = + (blockchain.getChainWeightByHash _).expects(hash).returning(Some(weight)) def expectBlockSaved( block: Block, receipts: Seq[Receipt], - td: BigInt, + weight: ChainWeight, saveAsBestBlock: Boolean - ): CallHandler4[Block, Seq[Receipt], BigInt, Boolean, Unit] = { + ): CallHandler4[Block, Seq[Receipt], ChainWeight, Boolean, Unit] = { (blockchain - .save(_: Block, _: Seq[Receipt], _: BigInt, _: Boolean)) - .expects(block, receipts, td, saveAsBestBlock) + .save(_: Block, _: Seq[Receipt], _: ChainWeight, _: Boolean)) + .expects(block, receipts, weight, saveAsBestBlock) .once() } @@ -388,7 +393,7 @@ trait MockBlockchain extends MockFactory { self: TestSetupWithVmAndValidators => def setBlockByNumber(number: BigInt, block: Option[Block]): CallHandler1[BigInt, Option[Block]] = (blockchain.getBlockByNumber _).expects(number).returning(block) - def setGenesisHeader(header: BlockHeader): CallHandler1[ByteString, Option[BlockHeader]] = { + def setGenesisHeader(header: BlockHeader): Unit = { (blockchain.genesisHeader _).expects().returning(header) setHeaderByHash(header.parentHash, None) } diff --git a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala index 1b0e6b6107..f3bf2c9b44 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala @@ -198,11 +198,12 @@ trait ScenarioSetup extends EphemBlockchainTestSetup { block.copy(header = block.header.copy(stateRoot = worldWithAccount.stateRootHash, gasLimit = 1000000)) val genesisHash: ByteString = genesisBlock.header.hash val genesisHeader: BlockHeader = genesisBlock.header + val genesisWeight = ChainWeight.zero.increase(genesisHeader) val lastBlockGasLimit: BigInt = genesisBlock.header.gasLimit blockchain .storeBlock(genesisBlock) .and(blockchain.storeReceipts(genesisHash, Nil)) - .and(blockchain.storeTotalDifficulty(genesisHash, genesisBlock.header.difficulty)) + .and(blockchain.storeChainWeight(genesisHash, genesisWeight)) .commit() } diff --git a/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala index 477e53c592..f04a0964fc 100644 --- a/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala @@ -8,7 +8,7 @@ import akka.util.ByteString import io.iohk.ethereum.Fixtures import io.iohk.ethereum.Fixtures.Blocks.{DaoForkBlock, Genesis} import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader} +import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} import io.iohk.ethereum.network.EtcPeerManagerActor._ import io.iohk.ethereum.network.PeerActor.DisconnectPeer import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.{MessageFromPeer, PeerDisconnected, PeerHandshakeSuccessful} @@ -48,12 +48,12 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { setupNewPeer(peer1, peer1Probe, peer1Info) //given - val newBlockTD = 300 + val newBlockWeight = ChainWeight.totalDifficultyOnly(300) val firstHeader: BlockHeader = baseBlockHeader.copy(number = peer1Info.maxBlockNumber + 4) - val firstBlock = NewBlock(Block(firstHeader, BlockBody(Nil, Nil)), newBlockTD) + val firstBlock = NewBlock(Block(firstHeader, BlockBody(Nil, Nil)), newBlockWeight) val secondHeader: BlockHeader = baseBlockHeader.copy(number = peer2Info.maxBlockNumber + 2) - val secondBlock = NewBlock(Block(secondHeader, BlockBody(Nil, Nil)), newBlockTD) + val secondBlock = NewBlock(Block(secondHeader, BlockBody(Nil, Nil)), newBlockWeight) //when peersInfoHolder ! MessageFromPeer(firstBlock, peer1.id) @@ -63,7 +63,7 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { requestSender.send(peersInfoHolder, PeerInfoRequest(peer1.id)) val expectedPeerInfo = initialPeerInfo .withBestBlockData(initialPeerInfo.maxBlockNumber + 4, firstHeader.hash) - .withTotalDifficulty(newBlockTD) + .withChainWeight(newBlockWeight) requestSender.expectMsg(PeerInfoResponse(Some(expectedPeerInfo))) } @@ -108,14 +108,14 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { setupNewPeer(peer1, peer1Probe, peer1Info) //given - val newBlock = NewBlock(baseBlock, initialPeerInfo.totalDifficulty + 1) + val newBlock = NewBlock(baseBlock, initialPeerInfo.chainWeight.increaseTotalDifficulty(1)) //when peersInfoHolder ! MessageFromPeer(newBlock, peer1.id) //then requestSender.send(peersInfoHolder, PeerInfoRequest(peer1.id)) - requestSender.expectMsg(PeerInfoResponse(Some(peer1Info.withTotalDifficulty(newBlock.totalDifficulty)))) + requestSender.expectMsg(PeerInfoResponse(Some(peer1Info.withChainWeight(newBlock.chainWeight)))) } it should "update the fork accepted when receiving the fork block" in new TestSetup { @@ -241,15 +241,14 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { val peerStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = BigInt(10000), + chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ).as63 val initialPeerInfo = PeerInfo( remoteStatus = peerStatus, - totalDifficulty = peerStatus.totalDifficulty, - latestCheckpointNumber = peerStatus.latestCheckpointNumber, + chainWeight = peerStatus.chainWeight, forkAccepted = false, maxBlockNumber = Fixtures.Blocks.Block3125369.header.number, bestBlockHash = peerStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/network/PeerActorHandshakingSpec.scala b/src/test/scala/io/iohk/ethereum/network/PeerActorHandshakingSpec.scala index 39daeab3cd..0b2d539948 100644 --- a/src/test/scala/io/iohk/ethereum/network/PeerActorHandshakingSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/PeerActorHandshakingSpec.scala @@ -9,6 +9,7 @@ import com.miguno.akka.testing.VirtualTime import io.iohk.ethereum.{Fixtures, Timeouts} import io.iohk.ethereum.Mocks.{MockHandshakerAlwaysFails, MockHandshakerAlwaysSucceeds} import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.PeerActor.Status.Handshaked import io.iohk.ethereum.network.PeerActor.{ConnectTo, GetStatus, StatusResponse} import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo @@ -170,7 +171,7 @@ class PeerActorHandshakingSpec extends AnyFlatSpec with Matchers { val defaultStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = Fixtures.Blocks.Genesis.header.difficulty, + chainWeight = ChainWeight.totalDifficultyOnly(Fixtures.Blocks.Genesis.header.difficulty), bestHash = Fixtures.Blocks.Genesis.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) @@ -179,8 +180,7 @@ class PeerActorHandshakingSpec extends AnyFlatSpec with Matchers { val defaultPeerInfo = PeerInfo( defaultStatus, - defaultStatus.totalDifficulty, - defaultStatus.latestCheckpointNumber, + defaultStatus.chainWeight, defaultForkAccepted, defaultBlockNumber, defaultStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/network/PeerEventBusActorSpec.scala b/src/test/scala/io/iohk/ethereum/network/PeerEventBusActorSpec.scala index 64be00f2c9..5946b9602f 100644 --- a/src/test/scala/io/iohk/ethereum/network/PeerEventBusActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/PeerEventBusActorSpec.scala @@ -5,6 +5,7 @@ import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.testkit.TestProbe import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.{MessageFromPeer, PeerDisconnected, PeerHandshakeSuccessful} import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier._ @@ -243,14 +244,13 @@ class PeerEventBusActorSpec extends AnyFlatSpec with Matchers { val peerStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = BigInt(10000), + chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) val initialPeerInfo = PeerInfo( remoteStatus = peerStatus, - totalDifficulty = peerStatus.totalDifficulty, - latestCheckpointNumber = peerStatus.latestCheckpointNumber, + chainWeight = peerStatus.chainWeight, forkAccepted = false, maxBlockNumber = Fixtures.Blocks.Block3125369.header.number, bestBlockHash = peerStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala index 8333a4d0fa..d8ed34da64 100644 --- a/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala @@ -5,7 +5,7 @@ import java.net.{InetSocketAddress, URI} import akka.actor._ import akka.testkit.{TestActorRef, TestProbe} import com.miguno.akka.testing.VirtualTime -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader} +import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo import io.iohk.ethereum.network.PeerActor.PeerClosedConnection import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerDisconnected @@ -160,7 +160,7 @@ class PeerManagerSpec extends AnyFlatSpec with Matchers with Eventually with Nor val baseBlockHeader: BlockHeader = Fixtures.Blocks.Block3125369.header val header: BlockHeader = baseBlockHeader.copy(number = initialPeerInfo.maxBlockNumber + 4) - val block = NewBlock(Block(header, BlockBody(Nil, Nil)), 300) + val block = NewBlock(Block(header, BlockBody(Nil, Nil)), ChainWeight.totalDifficultyOnly(300)) peerManager ! SendMessage(block, PeerId(probe.ref.path.name)) probe.expectMsg(PeerActor.SendMessage(block)) @@ -204,14 +204,13 @@ class PeerManagerSpec extends AnyFlatSpec with Matchers with Eventually with Nor val peerStatus = Status( protocolVersion = Versions.PV63, networkId = 1, - totalDifficulty = BigInt(10000), + chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) val initialPeerInfo = PeerInfo( remoteStatus = peerStatus, - totalDifficulty = peerStatus.totalDifficulty, - latestCheckpointNumber = 0, + chainWeight = peerStatus.chainWeight, forkAccepted = false, maxBlockNumber = Fixtures.Blocks.Block3125369.header.number, bestBlockHash = peerStatus.bestHash diff --git a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala index b8d66a37ae..5391008516 100644 --- a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala @@ -41,8 +41,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { HandshakeSuccess( PeerInfo( initialStatus, - totalDifficulty, - latestCheckpointNumber, + chainWeight, forkAccepted, currentMaxBlockNumber, bestBlockHash @@ -50,8 +49,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { ) ) => initialStatus shouldBe remoteStatus - totalDifficulty shouldBe remoteStatus.totalDifficulty - latestCheckpointNumber shouldBe remoteStatus.latestCheckpointNumber + chainWeight shouldBe remoteStatus.chainWeight bestBlockHash shouldBe remoteStatus.bestHash currentMaxBlockNumber shouldBe 0 forkAccepted shouldBe true @@ -69,12 +67,12 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { bc.copy(ecip1097BlockNumber = firstBlock.number + 1) }) - val newTotalDifficulty = genesisBlock.header.difficulty + firstBlock.header.difficulty + val newChainWeight = ChainWeight.zero.increase(genesisBlock.header).increase(firstBlock.header) - blockchain.save(firstBlock, Nil, newTotalDifficulty, saveAsBestBlock = true) + blockchain.save(firstBlock, Nil, newChainWeight, saveAsBestBlock = true) val newLocalStatus = - localStatus.copy(totalDifficulty = newTotalDifficulty, bestHash = firstBlock.header.hash) + localStatus.copy(chainWeight = newChainWeight, bestHash = firstBlock.header.hash) handshaker.nextMessage.map(_.messageToSend) shouldBe Right(localHello: HelloEnc) val handshakerAfterHelloOpt = handshaker.applyMessage(remoteHello) @@ -92,17 +90,18 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { bc.copy(ecip1097BlockNumber = firstBlock.number) }) - val newTotalDifficulty = genesisBlock.header.difficulty + firstBlock.header.difficulty + val newChainWeight = ChainWeight.zero.increase(genesisBlock.header).increase(firstBlock.header) - blockchain.save(firstBlock, Nil, newTotalDifficulty, saveAsBestBlock = true) + blockchain.save(firstBlock, Nil, newChainWeight, saveAsBestBlock = true) blockchain.saveBestKnownBlocks(firstBlock.number, Some(42)) // doesn't matter what number this is val newLocalStatus = - localStatus.as64.copy( - totalDifficulty = newTotalDifficulty, - bestHash = firstBlock.header.hash, - latestCheckpointNumber = 42 - ) + localStatus + .copy( + chainWeight = newChainWeight, + bestHash = firstBlock.header.hash + ) + .as64 handshaker.nextMessage.map(_.messageToSend) shouldBe Right(localHello: HelloEnc) val handshakerAfterHelloOpt = handshaker.applyMessage(remoteHello) @@ -128,8 +127,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { HandshakeSuccess( PeerInfo( initialStatus, - totalDifficulty, - latestCheckpointNumber, + chainWeight, forkAccepted, currentMaxBlockNumber, bestBlockHash @@ -137,8 +135,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { ) ) => initialStatus shouldBe remoteStatus - totalDifficulty shouldBe remoteStatus.totalDifficulty - latestCheckpointNumber shouldBe remoteStatus.latestCheckpointNumber + chainWeight shouldBe remoteStatus.chainWeight bestBlockHash shouldBe remoteStatus.bestHash currentMaxBlockNumber shouldBe 0 forkAccepted shouldBe true @@ -164,8 +161,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { HandshakeSuccess( PeerInfo( initialStatus, - totalDifficulty, - latestCheckpointNumber, + chainWeight, forkAccepted, currentMaxBlockNumber, bestBlockHash @@ -173,8 +169,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { ) ) => initialStatus shouldBe remoteStatus - totalDifficulty shouldBe remoteStatus.totalDifficulty - latestCheckpointNumber shouldBe remoteStatus.latestCheckpointNumber + chainWeight shouldBe remoteStatus.chainWeight bestBlockHash shouldBe remoteStatus.bestHash currentMaxBlockNumber shouldBe 0 forkAccepted shouldBe false @@ -267,9 +262,11 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { Fixtures.Blocks.Genesis.body ) + val genesisWeight = ChainWeight.zero.increase(genesisBlock.header) + val forkBlockHeader = Fixtures.Blocks.DaoForkBlock.header - blockchain.save(genesisBlock, Nil, genesisBlock.header.difficulty, saveAsBestBlock = true) + blockchain.save(genesisBlock, Nil, genesisWeight, saveAsBestBlock = true) val nodeStatus = NodeStatus( key = generateKeyPair(secureRandom), @@ -312,7 +309,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { val localStatus = Status( protocolVersion = Versions.PV63, networkId = Config.Network.peer.networkId, - totalDifficulty = genesisBlock.header.difficulty, + chainWeight = ChainWeight.zero.increase(genesisBlock.header), bestHash = genesisBlock.header.hash, genesisHash = genesisBlock.header.hash ).as63 @@ -341,7 +338,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { Status( protocolVersion = Versions.PV63, networkId = Config.Network.peer.networkId, - totalDifficulty = 0, + chainWeight = ChainWeight.zero, bestHash = genesisBlock.header.hash, genesisHash = genesisBlock.header.hash ).as63 diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/MessageCodecSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/MessageCodecSpec.scala index fb0ac66295..dc319ec869 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/MessageCodecSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/MessageCodecSpec.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.network.p2p import akka.util.ByteString +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.handshaker.EtcHelloExchangeState import io.iohk.ethereum.network.p2p.messages.CommonMessages.Status import io.iohk.ethereum.network.p2p.messages.Versions @@ -86,7 +87,7 @@ class MessageCodecSpec extends AnyFlatSpec with Matchers { val status = Status( protocolVersion = Versions.PV63, networkId = Config.Network.peer.networkId, - totalDifficulty = 1, + chainWeight = ChainWeight.totalDifficultyOnly(1), bestHash = ByteString(1), genesisHash = ByteString(1) ) diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala index f2c4dc96aa..6e5c6466f6 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala @@ -135,7 +135,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty + 100000, // remote is after the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(100000), // remote is after the fork bestHash = ByteString("blockhash"), genesisHash = genesisHash ) @@ -173,7 +173,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty + 100000, // remote is after the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(100000), // remote is after the fork bestHash = ByteString("blockhash"), genesisHash = genesisHash ) @@ -205,7 +205,8 @@ class PeerActorSpec rlpxConnection.send(peer, RLPxConnectionHandler.MessageReceived(remoteHello)) val header = - Fixtures.Blocks.ValidBlock.header.copy(difficulty = daoForkBlockTotalDifficulty + 100000, number = 3000000) + Fixtures.Blocks.ValidBlock.header + .copy(difficulty = daoForkBlockChainWeight.totalDifficulty + 100000, number = 3000000) storagesInstance.storages.appStateStorage .putBestBlockNumber(3000000) // after the fork .and(blockchain.storeBlockHeader(header)) @@ -215,7 +216,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty + 100000, // remote is after the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(100000), // remote is after the fork bestHash = ByteString("blockhash"), genesisHash = genesisHash ) @@ -241,7 +242,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty + 100000, // remote is after the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(100000), // remote is after the fork bestHash = ByteString("blockhash"), genesisHash = genesisHash ) @@ -288,7 +289,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty + 100000, // remote is after the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(100000), // remote is after the fork bestHash = ByteString("blockhash"), genesisHash = genesisHash ) @@ -320,7 +321,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty + 100000, // remote is after the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(100000), // remote is after the fork bestHash = ByteString("blockhash"), genesisHash = genesisHash ) @@ -339,7 +340,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty - 2000000, // remote is before the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(-200000), // remote is before the fork bestHash = ByteString("blockhash"), genesisHash = Fixtures.Blocks.Genesis.header.hash ) @@ -381,7 +382,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty + 100000, // remote is after the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(100000), // remote is after the fork bestHash = ByteString("blockhash"), genesisHash = genesisHash ) @@ -439,8 +440,9 @@ class PeerActorSpec val nodeStatusHolder = new AtomicReference(nodeStatus) val genesisBlock = Fixtures.Blocks.Genesis.block + val genesisWeight = ChainWeight.totalDifficultyOnly(genesisBlock.header.difficulty) - blockchain.save(genesisBlock, Nil, genesisBlock.header.difficulty, saveAsBestBlock = true) + blockchain.save(genesisBlock, Nil, genesisWeight, saveAsBestBlock = true) val daoForkBlockNumber = 1920000 @@ -493,7 +495,7 @@ class PeerActorSpec val genesisHash = genesisBlock.hash - val daoForkBlockTotalDifficulty: BigInt = BigInt("39490964433395682584") + val daoForkBlockChainWeight = ChainWeight.totalDifficultyOnly(BigInt("39490964433395682584")) def setupConnection(): Unit = { peer ! PeerActor.ConnectTo(new URI("encode://localhost:9000")) @@ -509,7 +511,7 @@ class PeerActorSpec val remoteStatus = Status( protocolVersion = Versions.PV63, networkId = peerConf.networkId, - totalDifficulty = daoForkBlockTotalDifficulty + 100000, // remote is after the fork + chainWeight = daoForkBlockChainWeight.increaseTotalDifficulty(100000), // remote is after the fork bestHash = ByteString("blockhash"), genesisHash = genesisHash ) diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/messages/MessagesSerializationSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/messages/MessagesSerializationSpec.scala index cf8c35a09c..7533deaef5 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/messages/MessagesSerializationSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/messages/MessagesSerializationSpec.scala @@ -2,6 +2,7 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.p2p.messages.CommonMessages._ import io.iohk.ethereum.network.p2p.messages.PV61.BlockHashesFromNumber import io.iohk.ethereum.network.p2p.messages.PV62._ @@ -52,13 +53,13 @@ class MessagesSerializationSpec extends AnyWordSpec with ScalaCheckPropertyCheck "Common Messages" when { "encoding and decoding Status" should { - "return same result for Status63" in { - val msg = Status63(1, 2, 2, ByteString("HASH"), ByteString("HASH2")) + "return same result for Status v63" in { + val msg = Status(1, 2, ChainWeight.totalDifficultyOnly(2), ByteString("HASH"), ByteString("HASH2")).as63 verify(msg, (m: Status) => m.toBytes, Status.code63, Versions.PV63) } - "return same result for Status64" in { - val msg = Status64(1, 2, 2, 5, ByteString("HASH"), ByteString("HASH2")) + "return same result for Status v64" in { + val msg = Status(1, 2, ChainWeight(2, 5), ByteString("HASH"), ByteString("HASH2")).as64 verify(msg, (m: Status) => m.toBytes, Status.code64, Versions.PV63) } } @@ -71,13 +72,13 @@ class MessagesSerializationSpec extends AnyWordSpec with ScalaCheckPropertyCheck } "encoding and decoding NewBlock" should { - "return same result for NewBlock63" in { - val msg = NewBlock(Fixtures.Blocks.Block3125369.block, 2323) + "return same result for NewBlock v63" in { + val msg = NewBlock(Fixtures.Blocks.Block3125369.block, ChainWeight.totalDifficultyOnly(2323)).as63 verify(msg, (m: NewBlock) => m.toBytes, NewBlock.code63, Versions.PV63) } - "return same result for NewBlock64" in { - val msg = NewBlock64(Fixtures.Blocks.Block3125369.block, 2323, 21) + "return same result for NewBlock v64" in { + val msg = NewBlock(Fixtures.Blocks.Block3125369.block, ChainWeight(2323, 21)).as64 verify(msg, (m: NewBlock) => m.toBytes, NewBlock.code64, Versions.PV63) } } diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala index dc05092b61..d5446826d3 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader} +import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} import io.iohk.ethereum.network.p2p.messages.CommonMessages.NewBlock import org.bouncycastle.util.encoders.Hex import NewBlock._ @@ -14,30 +14,37 @@ class NewBlockSpec extends AnyFunSuite with ScalaCheckPropertyChecks with Object val chainId = Hex.decode("3d").head - test("NewBlock messages are encoded and decoded properly") { - forAll(newBlockGen(secureRandom, Some(chainId))) { newBlock => + test("NewBlock v63 messages are encoded and decoded properly") { + forAll(newBlockGen(secureRandom, Some(chainId)).map(_.as63)) { newBlock => val encoded: Array[Byte] = newBlock.toBytes val decoded: NewBlock = encoded.toNewBlock(NewBlock.code63) + val newBlockWithoutCheckpointNumber = + newBlock.copy(chainWeight = ChainWeight.totalDifficultyOnly(newBlock.chainWeight.totalDifficulty)) + assert(decoded == newBlockWithoutCheckpointNumber) + } + } + + test("NewBlock v64 messages are encoded and decoded properly") { + forAll(newBlockGen(secureRandom, Some(chainId)).map(_.as64)) { newBlock => + val encoded: Array[Byte] = newBlock.toBytes + val decoded: NewBlock = encoded.toNewBlock(NewBlock.code64) assert(decoded == newBlock) } } //Expected encoded NewBlock obtained from EthereumJ test("NewBlock messages are properly encoded") { - val obtainEncoded = Hex.toHexString(newBlock.toBytes) + val obtainEncoded = Hex.toHexString(newBlock.as63.toBytes) val expectedEncoded = "f90200f901f9f901f4a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347943333333333333333333333333333333333333333a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f0000808408000000808000a0000000000000000000000000000000000000000000000000000000000000000088deadbeefdeadbeefc0c0830f0000" assert(obtainEncoded == expectedEncoded) - val obtainEncoded2 = Hex.toHexString(newBlock2.toBytes) + val obtainEncoded2 = Hex.toHexString(newBlock2.as63.toBytes) val expectedEncoded2 = "f9021cf90215f90210a098352d9c1300bd82334cb3e5034c3ec622d437963f55cf5a00a49642806c2f32a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942cad6e80c7c0b58845fcd71ecad6867c3bd4de20a09b56d589ad6a12373e212fdb6cb4f64d1d7745aea551c7116c665a81a31f9492a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f0b3f0a8407ec167f808458a6eb7098d783010507846765746887676f312e372e33856c696e7578a0ea0dec34a635401af44f5245a77b2cd838345615c555c322a3001df4dd0505fe8860d53a11c10d46fbc0c0830f0b3f" assert(obtainEncoded2 == expectedEncoded2) } - //TODO: ETCM-263 will modify the structure of NewBlock message. Relevant tests will be written then - ignore("Tests for NewBlock64?? - or are the ones in MessagesSerializationSpec sufficient") {} - val newBlock = NewBlock( Block( BlockHeader( @@ -59,7 +66,7 @@ class NewBlockSpec extends AnyFunSuite with ScalaCheckPropertyChecks with Object ), BlockBody(Seq(), Seq()) ), - BigInt("983040") + ChainWeight.totalDifficultyOnly(983040) ) val newBlock2 = NewBlock( @@ -87,6 +94,6 @@ class NewBlockSpec extends AnyFunSuite with ScalaCheckPropertyChecks with Object ), BlockBody(Seq(), Seq()) ), - BigInt("985919") + ChainWeight(4, 985919) ) }