From d0d92305f6be4055a94c6c7d9566f0e50a743bb7 Mon Sep 17 00:00:00 2001 From: catena Date: Mon, 9 Nov 2015 12:59:54 +0300 Subject: [PATCH 01/12] Call methods with side-effects with parentheses --- .../scala/scorex/network/BlockchainSyncer.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/scala/scorex/network/BlockchainSyncer.scala b/src/main/scala/scorex/network/BlockchainSyncer.scala index 04a48fbb..f3c0a31d 100644 --- a/src/main/scala/scorex/network/BlockchainSyncer.scala +++ b/src/main/scala/scorex/network/BlockchainSyncer.scala @@ -33,7 +33,7 @@ case class BlockchainSyncer(application: LagonakiApplication) extends FSM[Status case Event(Unit, _) => log.info("Initializing") - stay + stay() } when(Syncing) { @@ -45,7 +45,7 @@ case class BlockchainSyncer(application: LagonakiApplication) extends FSM[Status val sigs = application.blockchainImpl.lastSignatures(application.settings.MaxBlocksChunks) val msg = GetSignaturesMessage(sigs) networkController ! NetworkController.SendMessageToBestPeer(msg) - stay + stay() } else goto(Generating) case None => @@ -55,13 +55,13 @@ case class BlockchainSyncer(application: LagonakiApplication) extends FSM[Status case Event(NewBlock(block, remoteOpt), _) => assert(remoteOpt.isDefined, "Local generation attempt while syncing") processNewBlock(block, remoteOpt) - stay + stay() } when(Generating) { case Event(NewBlock(block, remoteOpt), _) => processNewBlock(block, remoteOpt) - stay + stay() case Event(MaxChainScore(scoreOpt), _) => scoreOpt match { case Some(maxScore) => @@ -70,12 +70,12 @@ case class BlockchainSyncer(application: LagonakiApplication) extends FSM[Status if (maxScore > localScore) goto(Syncing) else { tryToGenerateABlock() - stay + stay() } case None => tryToGenerateABlock() - stay + stay() } } @@ -93,11 +93,11 @@ case class BlockchainSyncer(application: LagonakiApplication) extends FSM[Status case Event(GetStatus, _) => sender() ! super.stateName.name - stay + stay() case Event(e, s) => log.warning(s"received unhandled request {$e} in state {$stateName}/{$s}") - stay + stay() } initialize() From c8b79c1e6530edc3da8d41f403dc9f12d9d373b5 Mon Sep 17 00:00:00 2001 From: catena2w Date: Mon, 9 Nov 2015 13:39:30 +0300 Subject: [PATCH 02/12] Don't pass default param to function --- src/main/scala/scorex/network/BlockchainSyncer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scorex/network/BlockchainSyncer.scala b/src/main/scala/scorex/network/BlockchainSyncer.scala index f3c0a31d..fe3254ce 100644 --- a/src/main/scala/scorex/network/BlockchainSyncer.scala +++ b/src/main/scala/scorex/network/BlockchainSyncer.scala @@ -115,7 +115,7 @@ case class BlockchainSyncer(application: LagonakiApplication) extends FSM[Status //broadcast block only if it is generated locally if (remoteOpt.isEmpty) { - networkController ! NetworkController.BroadcastMessage(BlockMessage(height, block), List()) + networkController ! NetworkController.BroadcastMessage(BlockMessage(height, block)) } } else { log.warning(s"Non-valid block: $block from $fromStr") From dfbe9937983feecab2bdc43a305a2b170d03770a Mon Sep 17 00:00:00 2001 From: catena Date: Mon, 9 Nov 2015 16:27:08 +0300 Subject: [PATCH 03/12] Refactoring --- src/main/scala/scorex/app/LagonakiApplication.scala | 4 ++-- src/main/scala/scorex/network/BlockchainSyncer.scala | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/scala/scorex/app/LagonakiApplication.scala b/src/main/scala/scorex/app/LagonakiApplication.scala index 8d6e6b01..799b9187 100644 --- a/src/main/scala/scorex/app/LagonakiApplication.scala +++ b/src/main/scala/scorex/app/LagonakiApplication.scala @@ -39,8 +39,8 @@ class LagonakiApplication(val settingsFilename: String) extends ScorexLogging { lazy val blockchainImpl = transactionModule.history private implicit lazy val actorSystem = ActorSystem("lagonaki") - lazy val networkController = actorSystem.actorOf(Props(classOf[NetworkController], this)) - lazy val blockchainSyncer = actorSystem.actorOf(Props(classOf[BlockchainSyncer], this)) + lazy val networkController = actorSystem.actorOf(Props(new NetworkController(this))) + lazy val blockchainSyncer = actorSystem.actorOf(Props(new BlockchainSyncer(this, networkController))) private lazy val walletFileOpt = settings.walletDirOpt.map(walletDir => new java.io.File(walletDir, "wallet.s.dat")) implicit lazy val wallet = new Wallet(walletFileOpt, settings.walletPassword, settings.walletSeed.get) diff --git a/src/main/scala/scorex/network/BlockchainSyncer.scala b/src/main/scala/scorex/network/BlockchainSyncer.scala index fe3254ce..4095ee95 100644 --- a/src/main/scala/scorex/network/BlockchainSyncer.scala +++ b/src/main/scala/scorex/network/BlockchainSyncer.scala @@ -2,7 +2,7 @@ package scorex.network import java.net.InetSocketAddress -import akka.actor.FSM +import akka.actor.{ActorRef, FSM} import scorex.app.LagonakiApplication import scorex.block.Block import scorex.network.BlockchainSyncer._ @@ -15,11 +15,7 @@ import scala.concurrent.duration._ case class NewBlock(block: Block, sender: Option[InetSocketAddress]) - -//todo: reduce boilerplate code -case class BlockchainSyncer(application: LagonakiApplication) extends FSM[Status, Unit] { - - private lazy val networkController = application.networkController +class BlockchainSyncer(application: LagonakiApplication, networkController: ActorRef) extends FSM[Status, Unit] { private val stateTimeout = 1.second From baf3da6ab7aefe044e26edff11b42e0673c5a77e Mon Sep 17 00:00:00 2001 From: catena Date: Mon, 9 Nov 2015 18:08:29 +0300 Subject: [PATCH 04/12] Refactoring processMaxChainScore() --- .../scorex/network/BlockchainSyncer.scala | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/main/scala/scorex/network/BlockchainSyncer.scala b/src/main/scala/scorex/network/BlockchainSyncer.scala index 4095ee95..d166b5d6 100644 --- a/src/main/scala/scorex/network/BlockchainSyncer.scala +++ b/src/main/scala/scorex/network/BlockchainSyncer.scala @@ -33,20 +33,16 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto } when(Syncing) { - case Event(MaxChainScore(scoreOpt), _) => scoreOpt match { - case Some(maxScore) => - val localScore = application.blockchainImpl.score() - log.info(s"maxScore: $maxScore, localScore: $localScore") - if (maxScore > localScore) { + case Event(MaxChainScore(scoreOpt), _) => + processMaxScore( + scoreOpt, + onLocal = () => { val sigs = application.blockchainImpl.lastSignatures(application.settings.MaxBlocksChunks) val msg = GetSignaturesMessage(sigs) networkController ! NetworkController.SendMessageToBestPeer(msg) stay() - } else goto(Generating) - - case None => - if (application.settings.offlineGeneration) goto(Generating).using(Unit) else goto(Offline) - } + } + ) case Event(NewBlock(block, remoteOpt), _) => assert(remoteOpt.isDefined, "Local generation attempt while syncing") @@ -59,33 +55,24 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto processNewBlock(block, remoteOpt) stay() - case Event(MaxChainScore(scoreOpt), _) => scoreOpt match { - case Some(maxScore) => - val localScore = application.blockchainImpl.score() - log.info(s"maxScore: $maxScore, localScore: $localScore") - if (maxScore > localScore) goto(Syncing) - else { + case Event(MaxChainScore(scoreOpt), _) => + processMaxScore( + scoreOpt, + onNone = () => { + tryToGenerateABlock() + stay() + }, + onMax = () => { tryToGenerateABlock() stay() } - - case None => - tryToGenerateABlock() - stay() - } + ) } //common logic for all the states whenUnhandled { - case Event(MaxChainScore(scoreOpt), _) => scoreOpt match { - case Some(maxScore) => - val localScore = application.blockchainImpl.score() - log.info(s"maxScore: $maxScore, localScore: $localScore") - if (maxScore > localScore) goto(Syncing) else goto(Generating) - - case None => - if (application.settings.offlineGeneration) goto(Generating).using(Unit) else goto(Offline) - } + case Event(MaxChainScore(scoreOpt), _) => + processMaxScore(scoreOpt) case Event(GetStatus, _) => sender() ! super.stateName.name @@ -98,6 +85,20 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto initialize() + def processMaxScore( + scoreOpt: Option[BigInt], + onLocal: () => State = () => goto(Syncing), + onMax: () => State = () => goto(Generating), + onNone: () => State = () => + if (application.settings.offlineGeneration) goto(Generating).using(Unit) else goto(Offline) + ): State = scoreOpt match { + case Some(maxScore) => + val localScore = application.blockchainImpl.score() + log.info(s"maxScore: $maxScore, localScore: $localScore") + if (localScore > maxScore) onLocal() else onMax() + case None => + onNone() + } def processNewBlock(block: Block, remoteOpt: Option[InetSocketAddress]) = { val fromStr = remoteOpt.map(_.toString).getOrElse("local") From e844497b146f63a00a76842036cbf1e7a19def1c Mon Sep 17 00:00:00 2001 From: kushti Date: Mon, 9 Nov 2015 18:43:19 +0300 Subject: [PATCH 05/12] blocks.maxBy(consModule.blockScore), no new() in actorOf again --- .../scorex/lagonaki/network/BlockchainSyncer.scala | 13 ++++++++++--- .../lagonaki/server/LagonakiApplication.scala | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/scala/scorex/lagonaki/network/BlockchainSyncer.scala b/src/main/scala/scorex/lagonaki/network/BlockchainSyncer.scala index 2e9194ef..5f08b504 100644 --- a/src/main/scala/scorex/lagonaki/network/BlockchainSyncer.scala +++ b/src/main/scala/scorex/lagonaki/network/BlockchainSyncer.scala @@ -91,7 +91,7 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto onMax: () => State = () => goto(Generating), onNone: () => State = () => if (application.settings.offlineGeneration) goto(Generating).using(Unit) else goto(Offline) - ): State = scoreOpt match { + ): State = scoreOpt match { case Some(maxScore) => val localScore = application.blockchainImpl.score() log.info(s"maxScore: $maxScore, localScore: $localScore") @@ -120,10 +120,17 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto } def tryToGenerateABlock() = { + val consModule = application.consensusModule + implicit val transModule = application.transactionModule + log.info("Trying to generate a new block") val accounts = application.wallet.privateKeyAccounts() - application.consensusModule.generateNextBlocks(accounts)(application.transactionModule) onComplete { - case Success(blocks: Seq[Block]) => blocks.foreach { self ! NewBlock(_, None)} + consModule.generateNextBlocks(accounts)(transModule) onComplete { + case Success(blocks: Seq[Block]) => + if (blocks.nonEmpty) { + val bestBlock = blocks.maxBy(consModule.blockScore) + self ! NewBlock(bestBlock, None) + } case Failure(ex) => log.error("Failed to generate new block: {}", ex) case m => log.error("Unexpected message: {}", m) } diff --git a/src/main/scala/scorex/lagonaki/server/LagonakiApplication.scala b/src/main/scala/scorex/lagonaki/server/LagonakiApplication.scala index 4a598540..b438a6f6 100644 --- a/src/main/scala/scorex/lagonaki/server/LagonakiApplication.scala +++ b/src/main/scala/scorex/lagonaki/server/LagonakiApplication.scala @@ -45,8 +45,8 @@ class LagonakiApplication(val settingsFilename: String) extends ScorexLogging { lazy val blockchainImpl = transactionModule.history private implicit lazy val actorSystem = ActorSystem("lagonaki") - lazy val networkController = actorSystem.actorOf(Props(new NetworkController(this))) - lazy val blockchainSyncer = actorSystem.actorOf(Props(new BlockchainSyncer(this, networkController))) + lazy val networkController = actorSystem.actorOf(Props(classOf[NetworkController], this)) + lazy val blockchainSyncer = actorSystem.actorOf(Props(classOf[BlockchainSyncer], this, networkController)) private lazy val walletFileOpt = settings.walletDirOpt.map(walletDir => new java.io.File(walletDir, "wallet.s.dat")) implicit lazy val wallet = new Wallet(walletFileOpt, settings.walletPassword, settings.walletSeed.get) From aae1114507f78c089b053afc30ac8ae7375476e3 Mon Sep 17 00:00:00 2001 From: catena Date: Mon, 9 Nov 2015 18:58:33 +0300 Subject: [PATCH 06/12] try to generate new block refactoring --- .../scorex/consensus/ConsensusModule.scala | 12 ++++++++--- .../scorex/network/BlockchainSyncer.scala | 21 ++++++------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/scorex-basics/src/main/scala/scorex/consensus/ConsensusModule.scala b/scorex-basics/src/main/scala/scorex/consensus/ConsensusModule.scala index 4d2d473e..38e405a0 100644 --- a/scorex-basics/src/main/scala/scorex/consensus/ConsensusModule.scala +++ b/scorex-basics/src/main/scala/scorex/consensus/ConsensusModule.scala @@ -1,9 +1,10 @@ package scorex.consensus -import scorex.account.{PrivateKeyAccount, Account} -import scorex.block.{BlockProcessingModule, Block} -import scorex.transaction.{TransactionModule, History, State} +import scorex.account.{Account, PrivateKeyAccount} +import scorex.block.{Block, BlockProcessingModule} +import scorex.transaction.TransactionModule +import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future @@ -29,4 +30,9 @@ trait ConsensusModule[ConsensusBlockData] extends BlockProcessingModule[Consensu def generateNextBlock[TT](account: PrivateKeyAccount) (implicit transactionModule: TransactionModule[TT]): Future[Option[Block]] + + def generateNextBlocks[T](accounts: Seq[PrivateKeyAccount]) + (implicit transactionModule: TransactionModule[T]): Future[Seq[Block]] = { + Future.sequence(accounts.map(acc => generateNextBlock(acc))).map(_.flatten) + } } diff --git a/src/main/scala/scorex/network/BlockchainSyncer.scala b/src/main/scala/scorex/network/BlockchainSyncer.scala index d166b5d6..c4579bca 100644 --- a/src/main/scala/scorex/network/BlockchainSyncer.scala +++ b/src/main/scala/scorex/network/BlockchainSyncer.scala @@ -11,6 +11,7 @@ import scorex.network.message.{BlockMessage, GetSignaturesMessage} import scala.concurrent.Await import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ +import scala.util.{Failure, Success} case class NewBlock(block: Block, sender: Option[InetSocketAddress]) @@ -121,25 +122,15 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto def tryToGenerateABlock() = { log.info("Trying to generate a new block") - val appState = application.storedState - val nonEmptyAccs = application.wallet.privateKeyAccounts().filter(acc => appState.balance(acc.address) > 0) - nonEmptyAccs.find { - privKeyAcc => - implicit val transactionModule = application.transactionModule - - //As Proof-of-Stake is being used for Scorex Lagonaki, generateNextBlock() finishes quickly - // (it should be, at least) so we're just going to wait for a result - Await.result(application.consensusModule.generateNextBlock(privKeyAcc), 500.millis) match { - case Some(block) => - self ! NewBlock(block, None) - true - case None => false - } + val accounts = application.wallet.privateKeyAccounts() + application.consensusModule.generateNextBlocks(accounts)(application.transactionModule) onComplete { + case Success(blocks: Seq[Block]) => blocks.foreach { self ! NewBlock(_, None)} + case Failure(ex) => log.error("Failed to generate new block: {}", ex) + case m => log.error("Unexpected message: {}", m) } } } - object BlockchainSyncer { sealed trait Status { From 417865228247598710ab280d49825251a79f8883 Mon Sep 17 00:00:00 2001 From: catena Date: Mon, 9 Nov 2015 21:02:36 +0300 Subject: [PATCH 07/12] BlockchainSyncer test --- .../scorex/lagonaki/LagonakiTestSuite.scala | 15 ++++---- .../BlockchainSyncerSpecification.scala | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala diff --git a/src/test/scala/scorex/lagonaki/LagonakiTestSuite.scala b/src/test/scala/scorex/lagonaki/LagonakiTestSuite.scala index 30b803f8..439c8c11 100644 --- a/src/test/scala/scorex/lagonaki/LagonakiTestSuite.scala +++ b/src/test/scala/scorex/lagonaki/LagonakiTestSuite.scala @@ -1,21 +1,22 @@ package scorex.lagonaki import org.scalatest.{BeforeAndAfterAll, Suites} -import scorex.lagonaki.integration.{BlocksRoutingSpecification, ValidChainGenerationSpecification} +import scorex.lagonaki.integration.{BlockchainSyncerSpecification, BlocksRoutingSpecification, ValidChainGenerationSpecification} import scorex.lagonaki.unit._ class LagonakiTestSuite extends Suites( //unit tests new MessageSpecification - ,new BlockSpecification - ,new BlockchainStorageSpecification - ,new WalletSpecification - ,new BlocksRoutingSpecification + , new BlockSpecification + , new BlockchainStorageSpecification + , new WalletSpecification + , new BlockchainSyncerSpecification + , new BlocksRoutingSpecification //integration tests - slow! - ,new ValidChainGenerationSpecification + , new ValidChainGenerationSpecification -) with BeforeAndAfterAll { +) with BeforeAndAfterAll { override def beforeAll() = {} diff --git a/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala b/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala new file mode 100644 index 00000000..2ed1f9d5 --- /dev/null +++ b/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala @@ -0,0 +1,35 @@ +package scorex.lagonaki.integration + +import akka.actor.ActorSystem +import akka.testkit._ +import org.scalatest.{Matchers, WordSpecLike} +import scorex.lagonaki.network.BlockchainSyncer.{Generating, GetStatus, Offline} +import scorex.lagonaki.server.LagonakiApplication + + +class BlockchainSyncerSpecification(_system: ActorSystem) + extends TestKit(_system) + with ImplicitSender + with WordSpecLike + with Matchers { + + def this() = this(ActorSystem("MySpec")) + + val application = new LagonakiApplication("settings-test.json") + application.checkGenesis() + val bcs = application.blockchainSyncer + + "BlockchainSyncer actor" must { + "be offline on load" in { + bcs ! GetStatus + expectMsg(Offline.name) + } + "generate after downloading state" in { + bcs ! Unit + Thread.sleep(1000) + bcs ! GetStatus + expectMsg(Generating.name) + } + } + +} \ No newline at end of file From 072fd862184828fec00d9048b9e63f2b7ab40e04 Mon Sep 17 00:00:00 2001 From: catena Date: Mon, 9 Nov 2015 23:08:19 +0300 Subject: [PATCH 08/12] Retry to get BlockchainsSyncer status --- .../src/main/scala/scorex/utils/package.scala | 19 +++++++++++++++++++ .../BlockchainSyncerSpecification.scala | 10 ++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 scorex-basics/src/main/scala/scorex/utils/package.scala diff --git a/scorex-basics/src/main/scala/scorex/utils/package.scala b/scorex-basics/src/main/scala/scorex/utils/package.scala new file mode 100644 index 00000000..28c91c49 --- /dev/null +++ b/scorex-basics/src/main/scala/scorex/utils/package.scala @@ -0,0 +1,19 @@ +package scorex + +import scala.annotation.tailrec + +package object utils { + + @tailrec + final def retry[T](timeout: Int, delay: Int = 100)(fn: => T): T = { + util.Try { + fn + } match { + case util.Success(x) => x + case _ if timeout > delay => + Thread.sleep(delay) + retry(timeout - delay, delay)(fn) + case util.Failure(e) => throw e + } + } +} diff --git a/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala b/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala index 2ed1f9d5..705e4838 100644 --- a/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala +++ b/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala @@ -5,7 +5,7 @@ import akka.testkit._ import org.scalatest.{Matchers, WordSpecLike} import scorex.lagonaki.network.BlockchainSyncer.{Generating, GetStatus, Offline} import scorex.lagonaki.server.LagonakiApplication - +import scorex.utils.retry class BlockchainSyncerSpecification(_system: ActorSystem) extends TestKit(_system) @@ -26,9 +26,11 @@ class BlockchainSyncerSpecification(_system: ActorSystem) } "generate after downloading state" in { bcs ! Unit - Thread.sleep(1000) - bcs ! GetStatus - expectMsg(Generating.name) + //Wait up to 5 seconds to download blockchain and become generating + retry(5000) { + bcs ! GetStatus + expectMsg(Generating.name) + } } } From 593031650c3679da7b195695a63fb95db280ca9a Mon Sep 17 00:00:00 2001 From: catena Date: Tue, 10 Nov 2015 12:47:36 +0300 Subject: [PATCH 09/12] rename onMax & onLocal --- .../scorex/lagonaki/network/BlockchainSyncer.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/scala/scorex/lagonaki/network/BlockchainSyncer.scala b/src/main/scala/scorex/lagonaki/network/BlockchainSyncer.scala index 5f08b504..a3d7d3a5 100644 --- a/src/main/scala/scorex/lagonaki/network/BlockchainSyncer.scala +++ b/src/main/scala/scorex/lagonaki/network/BlockchainSyncer.scala @@ -36,7 +36,7 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto case Event(MaxChainScore(scoreOpt), _) => processMaxScore( scoreOpt, - onLocal = () => { + onMax = () => { val sigs = application.blockchainImpl.lastSignatures(application.settings.MaxBlocksChunks) val msg = GetSignaturesMessage(sigs) networkController ! NetworkController.SendMessageToBestPeer(msg) @@ -62,7 +62,7 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto tryToGenerateABlock() stay() }, - onMax = () => { + onLocal = () => { tryToGenerateABlock() stay() } @@ -87,15 +87,15 @@ class BlockchainSyncer(application: LagonakiApplication, networkController: Acto def processMaxScore( scoreOpt: Option[BigInt], - onLocal: () => State = () => goto(Syncing), - onMax: () => State = () => goto(Generating), + onLocal: () => State = () => goto(Generating), + onMax: () => State = () => goto(Syncing), onNone: () => State = () => if (application.settings.offlineGeneration) goto(Generating).using(Unit) else goto(Offline) ): State = scoreOpt match { case Some(maxScore) => val localScore = application.blockchainImpl.score() log.info(s"maxScore: $maxScore, localScore: $localScore") - if (localScore > maxScore) onLocal() else onMax() + if (maxScore > localScore) onMax() else onLocal() case None => onNone() } From 9497b175c28cfc6ead748a75c515c86fb85e7645 Mon Sep 17 00:00:00 2001 From: catena Date: Tue, 10 Nov 2015 13:09:56 +0300 Subject: [PATCH 10/12] package.scala => utils.scala --- .../src/main/scala/scorex/utils/package.scala | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 scorex-basics/src/main/scala/scorex/utils/package.scala diff --git a/scorex-basics/src/main/scala/scorex/utils/package.scala b/scorex-basics/src/main/scala/scorex/utils/package.scala deleted file mode 100644 index 28c91c49..00000000 --- a/scorex-basics/src/main/scala/scorex/utils/package.scala +++ /dev/null @@ -1,19 +0,0 @@ -package scorex - -import scala.annotation.tailrec - -package object utils { - - @tailrec - final def retry[T](timeout: Int, delay: Int = 100)(fn: => T): T = { - util.Try { - fn - } match { - case util.Success(x) => x - case _ if timeout > delay => - Thread.sleep(delay) - retry(timeout - delay, delay)(fn) - case util.Failure(e) => throw e - } - } -} From dde1fd9415a3b6af26006849f530ffea9df09eb8 Mon Sep 17 00:00:00 2001 From: catena Date: Tue, 10 Nov 2015 13:16:43 +0300 Subject: [PATCH 11/12] utils scala --- .../src/main/scala/scorex/utils/utils.scala | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 scorex-basics/src/main/scala/scorex/utils/utils.scala diff --git a/scorex-basics/src/main/scala/scorex/utils/utils.scala b/scorex-basics/src/main/scala/scorex/utils/utils.scala new file mode 100644 index 00000000..28c91c49 --- /dev/null +++ b/scorex-basics/src/main/scala/scorex/utils/utils.scala @@ -0,0 +1,19 @@ +package scorex + +import scala.annotation.tailrec + +package object utils { + + @tailrec + final def retry[T](timeout: Int, delay: Int = 100)(fn: => T): T = { + util.Try { + fn + } match { + case util.Success(x) => x + case _ if timeout > delay => + Thread.sleep(delay) + retry(timeout - delay, delay)(fn) + case util.Failure(e) => throw e + } + } +} From ad331803f193cc200049208b3dbea8634b6fc7a1 Mon Sep 17 00:00:00 2001 From: kushti Date: Tue, 10 Nov 2015 10:23:30 +0300 Subject: [PATCH 12/12] retry -> untilTimeout, FiniteDuration instead of Int --- scorex-basics/src/main/scala/scorex/utils/utils.scala | 9 ++++++--- .../integration/BlockchainSyncerSpecification.scala | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/scorex-basics/src/main/scala/scorex/utils/utils.scala b/scorex-basics/src/main/scala/scorex/utils/utils.scala index 28c91c49..8167718a 100644 --- a/scorex-basics/src/main/scala/scorex/utils/utils.scala +++ b/scorex-basics/src/main/scala/scorex/utils/utils.scala @@ -2,17 +2,20 @@ package scorex import scala.annotation.tailrec +import scala.concurrent.duration._ + package object utils { @tailrec - final def retry[T](timeout: Int, delay: Int = 100)(fn: => T): T = { + final def untilTimeout[T](timeout: FiniteDuration, + delay: FiniteDuration = 100.milliseconds)(fn: => T): T = { util.Try { fn } match { case util.Success(x) => x case _ if timeout > delay => - Thread.sleep(delay) - retry(timeout - delay, delay)(fn) + Thread.sleep(delay.toMillis) + untilTimeout(timeout - delay, delay)(fn) case util.Failure(e) => throw e } } diff --git a/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala b/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala index 705e4838..c64eaeed 100644 --- a/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala +++ b/src/test/scala/scorex/lagonaki/integration/BlockchainSyncerSpecification.scala @@ -5,7 +5,8 @@ import akka.testkit._ import org.scalatest.{Matchers, WordSpecLike} import scorex.lagonaki.network.BlockchainSyncer.{Generating, GetStatus, Offline} import scorex.lagonaki.server.LagonakiApplication -import scorex.utils.retry +import scorex.utils.untilTimeout +import scala.concurrent.duration._ class BlockchainSyncerSpecification(_system: ActorSystem) extends TestKit(_system) @@ -27,11 +28,10 @@ class BlockchainSyncerSpecification(_system: ActorSystem) "generate after downloading state" in { bcs ! Unit //Wait up to 5 seconds to download blockchain and become generating - retry(5000) { + untilTimeout(5.seconds) { bcs ! GetStatus expectMsg(Generating.name) } } } - } \ No newline at end of file