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 f33822cb14..4b62772389 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 @@ -45,8 +45,8 @@ class BlockImporter( start() } - private def idle: Receive = { - case Start => start() + private def idle: Receive = { case Start => + start() } private def handleTopMessages(state: ImporterState, currentBehavior: Behavior): Receive = { @@ -63,8 +63,6 @@ class BlockImporter( case MinedBlock(block) => if (!state.importing) { importMinedBlock(block, state) - } else { - ommersPool ! AddOmmers(block.header) } case ImportNewBlock(block, peerId) if state.isOnTop && !state.importing => importNewBlock(block, peerId, state) case ImportDone(newBehavior) => @@ -96,9 +94,10 @@ class BlockImporter( } private def pickBlocks(state: ImporterState): Unit = { - val msg = state.resolvingBranchFrom.fold[BlockFetcher.FetchMsg]( - BlockFetcher.PickBlocks(syncConfig.blocksBatchSize))( - from => BlockFetcher.StrictPickBlocks(from, startingBlockNumber)) + val msg = + state.resolvingBranchFrom.fold[BlockFetcher.FetchMsg](BlockFetcher.PickBlocks(syncConfig.blocksBatchSize))(from => + BlockFetcher.StrictPickBlocks(from, startingBlockNumber) + ) fetcher ! msg } @@ -142,8 +141,9 @@ class BlockImporter( } } - private def tryImportBlocks(blocks: List[Block], importedBlocks: List[Block] = Nil)( - implicit ec: ExecutionContext): Future[(List[Block], Option[Any])] = + private def tryImportBlocks(blocks: List[Block], importedBlocks: List[Block] = Nil)(implicit + ec: ExecutionContext + ): Future[(List[Block], Option[Any])] = if (blocks.isEmpty) { Future.successful((importedBlocks, None)) } else { @@ -290,9 +290,11 @@ object BlockImporter { syncConfig: SyncConfig, ommersPool: ActorRef, broadcaster: ActorRef, - pendingTransactionsManager: ActorRef): Props = + pendingTransactionsManager: ActorRef + ): Props = Props( - new BlockImporter(fetcher, ledger, blockchain, syncConfig, ommersPool, broadcaster, pendingTransactionsManager)) + new BlockImporter(fetcher, ledger, blockchain, syncConfig, ommersPool, broadcaster, pendingTransactionsManager) + ) type Behavior = ImporterState => Receive type ImportFn = ImporterState => Unit diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala index 93c6888602..24c6769a26 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/EthashBlockCreator.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.consensus.ethash import akka.actor.ActorRef import akka.pattern.ask -import akka.util.Timeout +import akka.util.{Timeout, ByteString} import io.iohk.ethereum.consensus.blocks.PendingBlock import io.iohk.ethereum.consensus.ethash.blocks.EthashBlockGenerator import io.iohk.ethereum.domain.{Address, Block} @@ -28,23 +28,21 @@ class EthashBlockCreator( def getBlockForMining(parentBlock: Block, withTransactions: Boolean = true): Future[PendingBlock] = { val transactions = if (withTransactions) getTransactionsFromPool else Future.successful(PendingTransactionsResponse(Nil)) - getOmmersFromPool(parentBlock.header.number + 1).zip(transactions).flatMap { - case (ommers, pendingTxs) => - blockGenerator - .generateBlock(parentBlock, pendingTxs.pendingTransactions.map(_.stx.tx), coinbase, ommers.headers) match { - case Right(pb) => Future.successful(pb) - case Left(err) => Future.failed(new RuntimeException(s"Error while generating block for mining: $err")) - } + getOmmersFromPool(parentBlock.hash).zip(transactions).flatMap { case (ommers, pendingTxs) => + blockGenerator + .generateBlock(parentBlock, pendingTxs.pendingTransactions.map(_.stx.tx), coinbase, ommers.headers) match { + case Right(pb) => Future.successful(pb) + case Left(err) => Future.failed(new RuntimeException(s"Error while generating block for mining: $err")) + } } } - private def getOmmersFromPool(blockNumber: BigInt): Future[OmmersPool.Ommers] = { - (ommersPool ? OmmersPool.GetOmmers(blockNumber))(Timeout(miningConfig.ommerPoolQueryTimeout)) + private def getOmmersFromPool(parentBlockHash: ByteString): Future[OmmersPool.Ommers] = { + (ommersPool ? OmmersPool.GetOmmers(parentBlockHash))(Timeout(miningConfig.ommerPoolQueryTimeout)) .mapTo[OmmersPool.Ommers] - .recover { - case ex => - log.error("Failed to get ommers, mining block with empty ommers list", ex) - OmmersPool.Ommers(Nil) + .recover { case ex => + log.error("Failed to get ommers, mining block with empty ommers list", ex) + OmmersPool.Ommers(Nil) } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala index dc4e5febb3..b23662ca16 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthService.scala @@ -507,7 +507,7 @@ class EthService( import io.iohk.ethereum.consensus.ethash.EthashUtils.{epoch, seed} val bestBlock = blockchain.getBestBlock() - getOmmersFromPool(bestBlock.header.number + 1).zip(getTransactionsFromPool).map { case (ommers, pendingTxs) => + getOmmersFromPool(bestBlock.hash).zip(getTransactionsFromPool).map { case (ommers, pendingTxs) => val blockGenerator = ethash.blockGenerator blockGenerator.generateBlock( bestBlock, @@ -530,12 +530,12 @@ class EthService( } })(Future.successful(Left(JsonRpcErrors.ConsensusIsNotEthash))) - private def getOmmersFromPool(blockNumber: BigInt): Future[OmmersPool.Ommers] = + private def getOmmersFromPool(parentBlockHash: ByteString): Future[OmmersPool.Ommers] = consensus.ifEthash(ethash => { val miningConfig = ethash.config.specific implicit val timeout: Timeout = Timeout(miningConfig.ommerPoolQueryTimeout) - (ommersPool ? OmmersPool.GetOmmers(blockNumber)) + (ommersPool ? OmmersPool.GetOmmers(parentBlockHash)) .mapTo[OmmersPool.Ommers] .recover { case ex => log.error("failed to get ommer, mining block with empty ommers list", ex) diff --git a/src/main/scala/io/iohk/ethereum/ommers/OmmersPool.scala b/src/main/scala/io/iohk/ethereum/ommers/OmmersPool.scala index 51566a3864..08616e5c9d 100644 --- a/src/main/scala/io/iohk/ethereum/ommers/OmmersPool.scala +++ b/src/main/scala/io/iohk/ethereum/ommers/OmmersPool.scala @@ -1,37 +1,79 @@ package io.iohk.ethereum.ommers -import akka.actor.{Actor, Props} +import akka.util.ByteString +import akka.actor.{Actor, ActorLogging, Props} +import org.bouncycastle.util.encoders.Hex import io.iohk.ethereum.domain.{BlockHeader, Blockchain} import io.iohk.ethereum.ommers.OmmersPool.{AddOmmers, GetOmmers, RemoveOmmers} +import scala.annotation.tailrec -class OmmersPool(blockchain: Blockchain, ommersPoolSize: Int) extends Actor { +class OmmersPool(blockchain: Blockchain, ommersPoolSize: Int, ommerGenerationLimit: Int, returnedOmmersSizeLimit: Int) + extends Actor + with ActorLogging { var ommersPool: Seq[BlockHeader] = Nil - val ommerGenerationLimit: Int = 6 //Stated on section 11.1, eq. (143) of the YP - val ommerSizeLimit: Int = 2 - override def receive: Receive = { case AddOmmers(ommers) => ommersPool = (ommers ++ ommersPool).take(ommersPoolSize).distinct + logStatus(event = "Ommers after add", ommers = ommersPool) case RemoveOmmers(ommers) => val toDelete = ommers.map(_.hash).toSet ommersPool = ommersPool.filter(b => !toDelete.contains(b.hash)) + logStatus(event = "Ommers after remove", ommers = ommersPool) - case GetOmmers(blockNumber) => - val ommers = ommersPool.filter { b => - val generationDifference = blockNumber - b.number - generationDifference > 0 && generationDifference <= ommerGenerationLimit - }.filter { b => - blockchain.getBlockHeaderByHash(b.parentHash).isDefined - }.take(ommerSizeLimit) + case GetOmmers(parentBlockHash) => + val ancestors = collectAncestors(parentBlockHash, ommerGenerationLimit) + val ommers = ommersPool + .filter { b => + val notAncestor = ancestors.find(_.hash == b.hash).isEmpty + ancestors.find(_.hash == b.parentHash).isDefined && notAncestor + } + .take(returnedOmmersSizeLimit) + logStatus(event = s"Ommers given parent block ${Hex.toHexString(parentBlockHash.toArray)}", ommers) sender() ! OmmersPool.Ommers(ommers) } + + private def collectAncestors(parentHash: ByteString, generationLimit: Int): List[BlockHeader] = { + @tailrec + def rec(hash: ByteString, limit: Int, acc: List[BlockHeader]): List[BlockHeader] = { + if (limit > 0) { + blockchain.getBlockHeaderByHash(hash) match { + case Some(bh) => rec(bh.parentHash, limit - 1, acc :+ bh) + case None => acc + } + } else { + acc + } + } + rec(parentHash, generationLimit, List.empty) + } + + private def logStatus(event: String, ommers: Seq[BlockHeader]): Unit = { + lazy val ommersAsString: Seq[String] = ommers.map { bh => s"[number = ${bh.number}, hash = ${bh.hashAsHexString}]" } + log.debug(s"$event ${ommersAsString}") + } } object OmmersPool { - def props(blockchain: Blockchain, ommersPoolSize: Int): Props = Props(new OmmersPool(blockchain, ommersPoolSize)) + + /** + * As is stated on section 11.1, eq. (143) of the YP + * + * @param ommerGenerationLimit should be === 6 + * @param returnedOmmersSizeLimit should be === 2 + * + * ^ Probably not worthy but those params could be placed in consensus config. + */ + def props( + blockchain: Blockchain, + ommersPoolSize: Int, + ommerGenerationLimit: Int = 6, + returnedOmmersSizeLimit: Int = 2 + ): Props = Props( + new OmmersPool(blockchain, ommersPoolSize, ommerGenerationLimit, returnedOmmersSizeLimit) + ) case class AddOmmers(ommers: List[BlockHeader]) @@ -45,7 +87,7 @@ object OmmersPool { def apply(b: BlockHeader*): RemoveOmmers = RemoveOmmers(b.toList) } - case class GetOmmers(blockNumber: BigInt) + case class GetOmmers(parentBlockHash: ByteString) case class Ommers(headers: Seq[BlockHeader]) } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala index dff1d0a445..9e2ea27fcf 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala @@ -427,7 +427,7 @@ class EthServiceSpec pendingTransactionsManager.expectMsg(PendingTransactionsManager.GetPendingTransactions) pendingTransactionsManager.reply(PendingTransactionsManager.PendingTransactionsResponse(Nil)) - ommersPool.expectMsg(OmmersPool.GetOmmers(1)) + ommersPool.expectMsg(OmmersPool.GetOmmers(parentBlock.hash)) ommersPool.reply(OmmersPool.Ommers(Nil)) response.futureValue shouldEqual Right(GetWorkResponse(powHash, seedHash, target)) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala index d0935cc8dd..7b6739e7cb 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala @@ -224,7 +224,8 @@ class JsonRpcControllerSpec val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) val blockTd = blockToRequest.header.difficulty - blockchain.storeBlock(blockToRequest) + blockchain + .storeBlock(blockToRequest) .and(blockchain.storeTotalDifficulty(blockToRequest.header.hash, blockTd)) .commit() @@ -250,7 +251,8 @@ class JsonRpcControllerSpec val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) val blockTd = blockToRequest.header.difficulty - blockchain.storeBlock(blockToRequest) + blockchain + .storeBlock(blockToRequest) .and(blockchain.storeTotalDifficulty(blockToRequest.header.hash, blockTd)) .commit() @@ -628,7 +630,7 @@ class JsonRpcControllerSpec pendingTransactionsManager.expectMsg(PendingTransactionsManager.GetPendingTransactions) pendingTransactionsManager.reply(PendingTransactionsManager.PendingTransactionsResponse(Nil)) - ommersPool.expectMsg(OmmersPool.GetOmmers(2)) + ommersPool.expectMsg(OmmersPool.GetOmmers(parentBlock.hash)) ommersPool.reply(Ommers(Nil)) val response = result.futureValue @@ -674,7 +676,7 @@ class JsonRpcControllerSpec val result: Future[JsonRpcResponse] = jsonRpcController.handleRequest(request) pendingTransactionsManager.expectMsg(PendingTransactionsManager.GetPendingTransactions) - ommersPool.expectMsg(OmmersPool.GetOmmers(2)) + ommersPool.expectMsg(OmmersPool.GetOmmers(parentBlock.hash)) //on time out it should respond with empty list val response = result.futureValue(timeout(Timeouts.longTimeout)) @@ -786,7 +788,9 @@ class JsonRpcControllerSpec } it should "eth_gasPrice" in new TestSetup { - blockchain.storeBlock(Block(Fixtures.Blocks.Block3125369.header.copy(number = 42), Fixtures.Blocks.Block3125369.body)).commit() + blockchain + .storeBlock(Block(Fixtures.Blocks.Block3125369.header.copy(number = 42), Fixtures.Blocks.Block3125369.body)) + .commit() blockchain.saveBestKnownBlock(42) val request: JsonRpcRequest = JsonRpcRequest( diff --git a/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala b/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala index 9605d2a3c0..53b30d4d2b 100644 --- a/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala @@ -1,61 +1,212 @@ package io.iohk.ethereum.ommers import akka.actor.ActorSystem -import akka.testkit.TestProbe +import akka.testkit.{TestProbe, TestKit, ImplicitSender} import io.iohk.ethereum.Fixtures.Blocks.Block3125369 import io.iohk.ethereum.Timeouts import io.iohk.ethereum.domain.BlockchainImpl import io.iohk.ethereum.ommers.OmmersPool.{AddOmmers, GetOmmers, RemoveOmmers} +import io.iohk.ethereum.WithActorSystemShutDown import org.scalamock.scalatest.MockFactory -import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.freespec.AnyFreeSpecLike import org.scalatest.matchers.should.Matchers -class OmmersPoolSpec extends AnyFlatSpec with Matchers with MockFactory { +class OmmersPoolSpec + extends TestKit(ActorSystem("OmmersPoolSpec_System")) + with AnyFreeSpecLike + with ImplicitSender + with WithActorSystemShutDown + with Matchers + with MockFactory { - "OmmersPool" should "accept ommers" in new TestSetup { - //just return header - (blockchain.getBlockHeaderByHash _).expects(*).returns(Some(Block3125369.header)) + "OmmersPool" - { - ommersPool ! AddOmmers(Block3125369.header) - ommersPool.!(GetOmmers(Block3125369.header.number + 1))(testProbe.ref) + "should not return ommers if there is no any" in new TestSetup { - testProbe.expectMsg(Timeouts.normalTimeout, OmmersPool.Ommers(Seq(Block3125369.header))) - } + /** + * 00 --> 11 --> 21 --> [31] (chain1) + * \-> 14 (chain4) + * [] new block, reference! + * () ommer given the new block + */ + (blockchain.getBlockHeaderByHash _).expects(block2Chain1.hash).returns(Some(block2Chain1)) + (blockchain.getBlockHeaderByHash _).expects(block1Chain1.hash).returns(Some(block1Chain1)) + (blockchain.getBlockHeaderByHash _).expects(block0.hash).returns(Some(block0)) - "OmmersPool" should "removes ommers ommers" in new TestSetup { - //just return header - (blockchain.getBlockHeaderByHash _).expects(*).returns(Some(Block3125369.header)) + ommersPool ! AddOmmers( + block0, + block1Chain1, + block1Chain4, + block2Chain1 + ) - ommersPool ! AddOmmers(Block3125369.header) - ommersPool ! AddOmmers(Block3125369.header.copy(number = 2)) - ommersPool ! RemoveOmmers(Block3125369.header) + ommersPool ! GetOmmers(block3Chain1.parentHash) + expectMsg(Timeouts.normalTimeout, OmmersPool.Ommers(Seq.empty)) + } - ommersPool.!(GetOmmers(3))(testProbe.ref) + "should return ommers properly" - { - testProbe.expectMsg(Timeouts.normalTimeout, OmmersPool.Ommers(Seq(Block3125369.header.copy(number = 2)))) - } + "in case of a chain with less length than the generation limit" in new TestSetup { + + /** + * 00 --> (11) --> 21 --> 31 (chain1) + * \ \ \-> 33 (chain3) + * \ \--> 22 --> 32 (chain2) + * \-> [14] (chain4) + * [] new block, reference! + * () ommer given the new block + */ + (blockchain.getBlockHeaderByHash _).expects(block0.hash).returns(Some(block0)) + (blockchain.getBlockHeaderByHash _).expects(block0.parentHash).returns(None) + + ommersPool ! AddOmmers( + block0, + block1Chain1, + block2Chain1, + block2Chain2, + block3Chain1, + block3Chain2, + block3Chain3 + ) + + ommersPool ! GetOmmers(block1Chain4.parentHash) + expectMsg(Timeouts.normalTimeout, OmmersPool.Ommers(Seq(block1Chain1))) + } + + "despite of start losing older ommers candidates" in new TestSetup { + + /** + * XX --> (11) --> 21 --> 31 (chain1) + * \ \ \-> 33 (chain3) + * \ \--> 22 --> 32 (chain2) + * \--> 14 ---> [24] (chain4) + * \-> (15) (chain5) + * [] new block, reference! + * () ommer given the new block + * XX removed block + */ + (blockchain.getBlockHeaderByHash _).expects(block1Chain4.hash).returns(Some(block1Chain4)).once() + (blockchain.getBlockHeaderByHash _).expects(block0.hash).returns(Some(block0)).once() + (blockchain.getBlockHeaderByHash _).expects(block0.parentHash).returns(None).once() + + ommersPool ! AddOmmers( + block0, + block1Chain1, + block2Chain1, + block3Chain1, + block1Chain4, + block2Chain2, + block3Chain2, + block3Chain3 + ) + + // Ommers pool size limit is reach, block0 will be removed. + // Notice that in terms of additions, current pool implementation is behaving as a queue with a fixed size! + ommersPool ! AddOmmers(block1Chain5) + + ommersPool ! GetOmmers(block2Chain4.parentHash) + expectMsg(Timeouts.normalTimeout, OmmersPool.Ommers(Seq(block1Chain5, block1Chain1))) + } + + "by respecting size and generation limits" in new TestSetup { + + /** + * 00 --> 11 --> 21 --> [31] (chain1) + * \ \ \-> (33) (chain3) + * \ \--> (22) --> 32 (chain2) + * \-> 14 (chain4) + * [] new block, reference! + * () ommer given the new block + */ + (blockchain.getBlockHeaderByHash _).expects(block2Chain1.hash).returns(Some(block2Chain1)) + (blockchain.getBlockHeaderByHash _).expects(block1Chain1.hash).returns(Some(block1Chain1)) + (blockchain.getBlockHeaderByHash _).expects(block0.hash).returns(Some(block0)) + + ommersPool ! AddOmmers( + block0, + block1Chain1, + block2Chain1, + block1Chain4, + block2Chain2, + block3Chain2, + block3Chain3 + ) - "OmmersPool" should "returns ommers when out of pool siez" in new TestSetup { - //just return header - (blockchain.getBlockHeaderByHash _).expects(*).returns(Some(Block3125369.header)) + ommersPool ! GetOmmers(block3Chain1.parentHash) + expectMsg(Timeouts.normalTimeout, OmmersPool.Ommers(Seq(block2Chain2, block3Chain3))) + } - ommersPool ! AddOmmers(Block3125369.header.copy(number = 4)) - ommersPool ! AddOmmers(Block3125369.header.copy(number = 20)) - ommersPool ! AddOmmers(Block3125369.header.copy(number = 30)) - ommersPool ! AddOmmers(Block3125369.header.copy(number = 40)) - ommersPool ! AddOmmers(Block3125369.header.copy(number = 5)) - ommersPool.!(GetOmmers(6))(testProbe.ref) + } - testProbe.expectMsg(Timeouts.normalTimeout, OmmersPool.Ommers(Seq(Block3125369.header.copy(number = 5)))) + "removes ommers properly" in new TestSetup { + + /** + * 00 --> 11 --> 21 --> [31] (chain1) + * \ \ \-> (XX) (chain3) + * \ \--> (22) --> 32 (chain2) + * \-> 14 (chain4) + * [] new block, reference! + * () ommer given the new block + * XX removed block + */ + (blockchain.getBlockHeaderByHash _).expects(block2Chain1.hash).returns(Some(block2Chain1)) + (blockchain.getBlockHeaderByHash _).expects(block1Chain1.hash).returns(Some(block1Chain1)) + (blockchain.getBlockHeaderByHash _).expects(block0.hash).returns(Some(block0)) + + ommersPool ! AddOmmers( + block0, + block1Chain1, + block2Chain1, + block1Chain4, + block2Chain2, + block3Chain2, + block3Chain3 + ) + + ommersPool ! RemoveOmmers(block3Chain3) + + ommersPool ! GetOmmers(block3Chain1.parentHash) + expectMsg(Timeouts.normalTimeout, OmmersPool.Ommers(Seq(block2Chain2))) + } } trait TestSetup extends MockFactory { - implicit val system = ActorSystem("OmmersPoolSpec_System") - val ommersPoolSize: Int = 3 + // In order to support all the blocks for the given scenarios + val ommersPoolSize: Int = 8 + + // Originally it should be 6 as is stated on section 11.1, eq. (143) of the YP + // Here we are using a simplification for testing purposes + val ommerGenerationLimit: Int = 2 + val returnedOmmerSizeLimit: Int = 2 // Max amount of ommers allowed per block + + /** + * 00 ---> 11 --> 21 --> 31 (chain1) + * \ \ \--> 33 (chain3) + * \ \--> 22 --> 32 (chain2) + * \--> 14 --> 24 (chain4) + * \-> 15 (chain5) + */ + val block0 = Block3125369.header.copy(number = 0, difficulty = 0) + + val block1Chain1 = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 11) + val block2Chain1 = Block3125369.header.copy(number = 2, parentHash = block1Chain1.hash, difficulty = 21) + val block3Chain1 = Block3125369.header.copy(number = 3, parentHash = block2Chain1.hash, difficulty = 31) + + val block2Chain2 = Block3125369.header.copy(number = 2, parentHash = block1Chain1.hash, difficulty = 22) + val block3Chain2 = Block3125369.header.copy(number = 2, parentHash = block2Chain2.hash, difficulty = 32) + + val block3Chain3 = Block3125369.header.copy(number = 3, parentHash = block2Chain1.hash, difficulty = 33) + + val block1Chain4 = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 14) + val block2Chain4 = Block3125369.header.copy(number = 2, parentHash = block1Chain4.hash, difficulty = 24) + + val block1Chain5 = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 15) + val testProbe = TestProbe() val blockchain = mock[BlockchainImpl] - val ommersPool = system.actorOf(OmmersPool.props(blockchain, ommersPoolSize)) + val ommersPool = + system.actorOf(OmmersPool.props(blockchain, ommersPoolSize, ommerGenerationLimit, returnedOmmerSizeLimit)) } }