From 194a85c187017016e3f68ec39be0d00d5133c928 Mon Sep 17 00:00:00 2001 From: fluency03 Date: Sat, 5 May 2018 17:57:13 +0200 Subject: [PATCH] add MineAndAddNextBlock in BlockPool --- .../api/actors/BlockPoolActor.scala | 25 ++++++- .../api/actors/BlockchainActor.scala | 26 ++++--- .../api/routes/BlockPoolRoutes.scala | 70 +++++++++++-------- .../api/routes/BlockchainRoutes.scala | 1 - .../blockchain/api/routes/TxPoolRoutes.scala | 62 ++++++++-------- .../blockchain/api/routes/package.scala | 6 +- 6 files changed, 115 insertions(+), 75 deletions(-) diff --git a/src/main/scala/com/github/fluency03/blockchain/api/actors/BlockPoolActor.scala b/src/main/scala/com/github/fluency03/blockchain/api/actors/BlockPoolActor.scala index b182ede..c2e703d 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/actors/BlockPoolActor.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/actors/BlockPoolActor.scala @@ -1,11 +1,15 @@ package com.github.fluency03.blockchain.api.actors -import akka.actor.{ActorSelection, Props} +import akka.actor.{ActorRef, ActorSelection, Props} +import akka.pattern.ask import com.github.fluency03.blockchain.api.actors.BlockPoolActor._ import com.github.fluency03.blockchain.api._ +import com.github.fluency03.blockchain.api.actors.BlockchainActor import com.github.fluency03.blockchain.core.Block import scala.collection.mutable +import scala.concurrent.Future +import scala.util.{Failure, Success} object BlockPoolActor { final case object GetBlocks @@ -14,6 +18,7 @@ object BlockPoolActor { final case class GetBlock(hash: String) final case class DeleteBlock(hash: String) final case class GetTxOfBlock(id: String, hash: String) + final case class MineAndAddNextBlock(data: String, ids: Seq[String]) def props: Props = Props[BlockPoolActor] } @@ -36,13 +41,13 @@ class BlockPoolActor extends ActorSupport { case GetBlock(hash) => onGetBlock(hash) case DeleteBlock(hash) => onDeleteBlock(hash) case GetTxOfBlock(id, hash) => onGetTxOfBlock(id, hash) + case MineAndAddNextBlock(data, ids) => onMineAndAddNextBlock(data, ids) case _ => unhandled _ } /** * TODO (Chang): new APIS: * - CreateBlock - * - ContainsBlock * */ @@ -77,4 +82,20 @@ class BlockPoolActor extends ActorSupport { case None => sender() ! None } + private def onMineAndAddNextBlock(data: String, ids: Seq[String]): Unit = { + val maybeBlock: Future[Option[Block]] = + (blockchainActor ? BlockchainActor.MineNextBlock(data, ids)).mapTo[Option[Block]] + val theSender: ActorRef = sender() + maybeBlock onComplete { + case Success(blockOpt) => blockOpt match { + case Some(block) => + blocksPool += (block.hash -> block) + Some(block) + case None => theSender ! None + } + case Failure(_) => theSender ! None + } + } + + } diff --git a/src/main/scala/com/github/fluency03/blockchain/api/actors/BlockchainActor.scala b/src/main/scala/com/github/fluency03/blockchain/api/actors/BlockchainActor.scala index 5db332e..7272050 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/actors/BlockchainActor.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/actors/BlockchainActor.scala @@ -70,7 +70,7 @@ class BlockchainActor extends ActorSupport { } /** - * Handlers for each of the Messages. + * Handlers for each of the BlockchainMsg. */ private def onGetBlockchain(): Unit = sender() ! blockchainOpt @@ -94,6 +94,20 @@ class BlockchainActor extends ActorSupport { sender() ! SuccessMsg("Blockchain deleted.") } else sender() ! FailureMsg("Blockchain does not exist.") + private def onCheckBlockchainValidity(): Unit = blockchainOpt match { + case Some(blockchain) => + if (blockchain.isValid) sender() ! SuccessMsg("true") + else sender() ! SuccessMsg("false") + case None => + log.error("Blockchain does not exist! Clear the hash-to-index mapping!") + hashIndexMapping.clear() + sender() ! FailureMsg("Blockchain does not exist.") + } + + /** + * Handlers for each of the BlockMsg. + */ + private def onGetBlockFromChain(hash: String): Unit = sender() ! getBlockFromChain(hash) private def onGetLastBlock(): Unit = blockchainOpt match { @@ -171,16 +185,6 @@ class BlockchainActor extends ActorSupport { sender() ! None } - private def onCheckBlockchainValidity(): Unit = blockchainOpt match { - case Some(blockchain) => - if (blockchain.isValid) sender() ! SuccessMsg("true") - else sender() ! SuccessMsg("false") - case None => - log.error("Blockchain does not exist! Clear the hash-to-index mapping!") - hashIndexMapping.clear() - sender() ! FailureMsg("Blockchain does not exist.") - } - private def onGetBlockFromPool(hash: String): Unit = blockPoolActor forward BlockPoolActor.GetBlock(hash) diff --git a/src/main/scala/com/github/fluency03/blockchain/api/routes/BlockPoolRoutes.scala b/src/main/scala/com/github/fluency03/blockchain/api/routes/BlockPoolRoutes.scala index 6cd0d26..999a5b2 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/routes/BlockPoolRoutes.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/routes/BlockPoolRoutes.scala @@ -2,15 +2,16 @@ package com.github.fluency03.blockchain.api.routes import akka.actor.ActorRef import akka.event.Logging -import akka.http.scaladsl.server.Directives._ +import akka.http.scaladsl.server.Directives.{path, _} import akka.http.scaladsl.server.Route import akka.http.scaladsl.server.directives.MethodDirectives.{delete, get, post} import akka.http.scaladsl.server.directives.PathDirectives.path import akka.http.scaladsl.server.directives.RouteDirectives.complete import akka.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers.CsvSeq import akka.pattern.ask -import com.github.fluency03.blockchain.api.{Blocks, Message} +import com.github.fluency03.blockchain.api.{Blocks, Input, Message} import com.github.fluency03.blockchain.api.actors.BlockPoolActor._ +import com.github.fluency03.blockchain.api.actors.BlockchainActor.MineNextBlock import com.github.fluency03.blockchain.core.{Block, Transaction} import scala.concurrent.Future @@ -23,45 +24,56 @@ trait BlockPoolRoutes extends RoutesSupport { /** * TODO (Chang): new APIS: * - CreateBlock - * - GetTransactionOfABlock - * - ContainsBlock * */ lazy val blockPoolRoutes: Route = - path(BLOCKS) { - parameters( 'hashes.as(CsvSeq[String]).? ) { hashesOpt: Option[Seq[String]] => - val blocks: Future[Blocks] = hashesOpt match { - case Some(hashes) => (blockPoolActor ? GetBlocks(hashes.toSet)).mapTo[Blocks] - case None => (blockPoolActor ? GetBlocks).mapTo[Blocks] + path(BLOCK_POOL) { + path(BLOCKS) { + parameters('hashes.as(CsvSeq[String]).?) { hashesOpt: Option[Seq[String]] => + val blocks: Future[Blocks] = hashesOpt match { + case Some(hashes) => (blockPoolActor ? GetBlocks(hashes.toSet)).mapTo[Blocks] + case None => (blockPoolActor ? GetBlocks).mapTo[Blocks] + } + complete(blocks) } - complete(blocks) - } - } ~ - pathPrefix(BLOCK) { - pathEnd { + } ~ + path(NEXT_BLOCK) { post { - entity(as[Block]) { block => - val blockCreated: Future[Message] = (blockPoolActor ? AddBlock(block)).mapTo[Message] - onSuccess(blockCreated) { respondOnCreation } + parameters('id.as(CsvSeq[String]).?) { idsOpt: Option[Seq[String]] => + entity(as[Input]) { in => + val maybeNextBlock: Future[Option[Block]] = + (blockPoolActor ? MineAndAddNextBlock(in.content, idsOpt.getOrElse(Seq.empty[String]))).mapTo[Option[Block]] + rejectEmptyResponse { complete(maybeNextBlock) } + } } } } ~ - pathPrefix(Segment) { hash => + pathPrefix(BLOCK) { pathEnd { - get { - val maybeBlock: Future[Option[Block]] = (blockPoolActor ? GetBlock(hash)).mapTo[Option[Block]] - rejectEmptyResponse { complete(maybeBlock) } - } ~ - delete { - val blockDeleted: Future[Message] = (blockPoolActor ? DeleteBlock(hash)).mapTo[Message] - onSuccess(blockDeleted) { respondOnDeletion } + post { + entity(as[Block]) { block => + val blockCreated: Future[Message] = (blockPoolActor ? AddBlock(block)).mapTo[Message] + onSuccess(blockCreated) { respondOnCreation } } + } } ~ - path(TRANSACTION / Segment) { id => - get { - val maybeTx: Future[Option[Transaction]] = (blockPoolActor ? GetTxOfBlock(id, hash)).mapTo[Option[Transaction]] - rejectEmptyResponse { complete(maybeTx) } + pathPrefix(Segment) { hash => + pathEnd { + get { + val maybeBlock: Future[Option[Block]] = (blockPoolActor ? GetBlock(hash)).mapTo[Option[Block]] + rejectEmptyResponse { complete(maybeBlock) } + } ~ + delete { + val blockDeleted: Future[Message] = (blockPoolActor ? DeleteBlock(hash)).mapTo[Message] + onSuccess(blockDeleted) { respondOnDeletion } + } + } ~ + path(TRANSACTION / Segment) { id => + get { + val maybeTx: Future[Option[Transaction]] = (blockPoolActor ? GetTxOfBlock(id, hash)).mapTo[Option[Transaction]] + rejectEmptyResponse { complete(maybeTx) } + } } } } diff --git a/src/main/scala/com/github/fluency03/blockchain/api/routes/BlockchainRoutes.scala b/src/main/scala/com/github/fluency03/blockchain/api/routes/BlockchainRoutes.scala index 116e4ec..83e16ee 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/routes/BlockchainRoutes.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/routes/BlockchainRoutes.scala @@ -2,7 +2,6 @@ package com.github.fluency03.blockchain.api.routes import akka.actor.ActorRef import akka.event.Logging -import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route import akka.http.scaladsl.server.directives.MethodDirectives.{delete, get, post} diff --git a/src/main/scala/com/github/fluency03/blockchain/api/routes/TxPoolRoutes.scala b/src/main/scala/com/github/fluency03/blockchain/api/routes/TxPoolRoutes.scala index 8362964..968ad8b 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/routes/TxPoolRoutes.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/routes/TxPoolRoutes.scala @@ -28,40 +28,42 @@ trait TxPoolRoutes extends RoutesSupport { */ lazy val txPoolRoutes: Route = - path(TRANSACTIONS) { - parameters( 'ids.as(CsvSeq[String]).? ) { idsOpt => - val transactions: Future[Transactions] = idsOpt match { - case Some(ids) => (txPoolActor ? GetTransactions(ids)).mapTo[Transactions] - case None => (txPoolActor ? GetTransactions).mapTo[Transactions] - } - complete(transactions) - } - } ~ - pathPrefix(TRANSACTION) { - pathEnd { - post { - entity(as[Transaction]) { tx => - val msgOnCreate: Future[Message] = (txPoolActor ? AddTransaction(tx)).mapTo[Message] - onSuccess(msgOnCreate) { respondOnCreation } + path(TX_POOL) { + path(TRANSACTIONS) { + parameters('ids.as(CsvSeq[String]).?) { idsOpt => + val transactions: Future[Transactions] = idsOpt match { + case Some(ids) => (txPoolActor ? GetTransactions(ids)).mapTo[Transactions] + case None => (txPoolActor ? GetTransactions).mapTo[Transactions] } + complete(transactions) } } ~ - path(Segment) { id => - get { - val maybeTx: Future[Option[Transaction]] = (txPoolActor ? GetTransaction(id)).mapTo[Option[Transaction]] - rejectEmptyResponse { complete(maybeTx) } - } ~ - delete { - val txDeleted: Future[Message] = (txPoolActor ? DeleteTransaction(id)).mapTo[Message] - onSuccess(txDeleted) { respondOnDeletion } + pathPrefix(TRANSACTION) { + pathEnd { + post { + entity(as[Transaction]) { tx => + val msgOnCreate: Future[Message] = (txPoolActor ? AddTransaction(tx)).mapTo[Message] + onSuccess(msgOnCreate) { respondOnCreation } + } + } } ~ - put { - entity(as[Transaction]) { tx => - if (tx.id != id) - complete((StatusCodes.InternalServerError, FailureMsg("Transaction ID in the data does not match ID on the path."))) - else { - val msgOnUpdate: Future[Message] = (txPoolActor ? UpdateTransaction(tx)).mapTo[Message] - onSuccess(msgOnUpdate) { respondOnUpdate } + path(Segment) { id => + get { + val maybeTx: Future[Option[Transaction]] = (txPoolActor ? GetTransaction(id)).mapTo[Option[Transaction]] + rejectEmptyResponse { complete(maybeTx) } + } ~ + delete { + val txDeleted: Future[Message] = (txPoolActor ? DeleteTransaction(id)).mapTo[Message] + onSuccess(txDeleted) { respondOnDeletion } + } ~ + put { + entity(as[Transaction]) { tx => + if (tx.id != id) + complete((StatusCodes.InternalServerError, FailureMsg("Transaction ID in the data does not match ID on the path."))) + else { + val msgOnUpdate: Future[Message] = (txPoolActor ? UpdateTransaction(tx)).mapTo[Message] + onSuccess(msgOnUpdate) { respondOnUpdate } + } } } } diff --git a/src/main/scala/com/github/fluency03/blockchain/api/routes/package.scala b/src/main/scala/com/github/fluency03/blockchain/api/routes/package.scala index ab3165b..d047e3d 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/routes/package.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/routes/package.scala @@ -20,7 +20,8 @@ package object routes { val NEW_BLOCK = "new-block" val NEXT_BLOCK = "next-block" - // block + // block-pool + val BLOCK_POOL = "block-pool" val BLOCKS = "blocks" val BLOCK = "block" @@ -29,7 +30,8 @@ package object routes { val PEERS = "peers" val PEER = "peer" - // transaction + // tx-pool + val TX_POOL = "tx-pool" val TRANSACTIONS = "transactions" val TRANSACTION = "transaction"