From f4c5e81fb643b79a03261d332ef943082ce70ded Mon Sep 17 00:00:00 2001 From: fluency03 Date: Tue, 1 May 2018 02:55:44 +0200 Subject: [PATCH] add GetTxOfBlock --- README.md | 1 + .../api/actors/BlockchainActor.scala | 17 ++++++++++--- .../api/routes/BlockchainRoutes.scala | 25 +++++++++++++------ .../api/actors/BlockchainActorTest.scala | 16 +++++++++--- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index af11ccb..25e520d 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ com.fluency03.blockchain.api.Server - Complete APIs' Todos - Make states in actor persistent (using Akka Persistent) +- Concurrent collections? - Make data distributed within cluster of peer (using Akka Cluster) - Block propagation among peers - etc. diff --git a/src/main/scala/com/fluency03/blockchain/api/actors/BlockchainActor.scala b/src/main/scala/com/fluency03/blockchain/api/actors/BlockchainActor.scala index f377180..3cd5859 100644 --- a/src/main/scala/com/fluency03/blockchain/api/actors/BlockchainActor.scala +++ b/src/main/scala/com/fluency03/blockchain/api/actors/BlockchainActor.scala @@ -12,6 +12,7 @@ object BlockchainActor { final case object CreateBlockchain final case object DeleteBlockchain final case class GetBlock(hash: String) + final case class GetTxOfBlock(id: String, hash: String) def props: Props = Props[BlockchainActor] } @@ -26,22 +27,21 @@ class BlockchainActor extends ActorSupport { // TODO (Chang): need persistence var blockchainOpt: Option[Blockchain] = None - var hashIndexMapping = mutable.Map.empty[String, Int] + val hashIndexMapping = mutable.Map.empty[String, Int] def receive: Receive = { case GetBlockchain => onGetBlockchain() case CreateBlockchain => onCreateBlockchain() case DeleteBlockchain => onDeleteBlockchain() case GetBlock(hash) => onGetBlock(hash) + case GetTxOfBlock(id, hash) => onGetTxOfBlock(id, hash) case _ => unhandled _ } /** * TODO (Chang): new APIS: * - AddBlockOnBlockchain - * - GetBlockFromBlockchain * - CheckBlockchainIsValid - * - GetTransactionOfABlock * - MineNextBlock * */ @@ -67,7 +67,16 @@ class BlockchainActor extends ActorSupport { sender() ! SuccessMsg(s"Blockchain deleted.") } else sender() ! FailureMsg(s"Blockchain does not exist.") - private def onGetBlock(hash: String): Unit = sender() ! { + private def onGetBlock(hash: String): Unit = sender() ! getBlock(hash) + + private def onGetTxOfBlock(id: String, hash: String): Unit = sender() ! { + getBlock(hash) match { + case Some(block) => block.transactions.find(_.id == id) + case None => None + } + } + + private def getBlock(hash: String): Option[Block] = { hashIndexMapping.get(hash) match { case Some(index) => blockchainOpt match { case Some(blockchain) => Some(blockchain.chain(index)) diff --git a/src/main/scala/com/fluency03/blockchain/api/routes/BlockchainRoutes.scala b/src/main/scala/com/fluency03/blockchain/api/routes/BlockchainRoutes.scala index 3c39593..7d345a1 100644 --- a/src/main/scala/com/fluency03/blockchain/api/routes/BlockchainRoutes.scala +++ b/src/main/scala/com/fluency03/blockchain/api/routes/BlockchainRoutes.scala @@ -9,7 +9,7 @@ import akka.http.scaladsl.server.directives.RouteDirectives.complete import akka.pattern.ask import com.fluency03.blockchain.api.Message import com.fluency03.blockchain.api.actors.BlockchainActor._ -import com.fluency03.blockchain.core.{Block, Blockchain} +import com.fluency03.blockchain.core.{Block, Blockchain, Transaction} import scala.concurrent.Future @@ -21,9 +21,7 @@ trait BlockchainRoutes extends RoutesSupport { /** * TODO (Chang): new APIS: * - AddBlockOnBlockchain - * - GetBlockFromBlockchain * - CheckBlockchainIsValid - * - GetTransactionOfABlock * - MineNextBlock * */ @@ -43,11 +41,22 @@ trait BlockchainRoutes extends RoutesSupport { val blockchainDeleted: Future[Message] = (blockchainActor ? DeleteBlockchain).mapTo[Message] onSuccess(blockchainDeleted) { respondOnDeletion } } - } - path(BLOCK / Segment) { hash => - get { - val maybeBlock: Future[Option[Block]] = (blockchainActor ? GetBlock(hash)).mapTo[Option[Block]] - rejectEmptyResponse { complete(maybeBlock) } + } ~ + pathPrefix(BLOCK / Segment) { hash => + pathEnd { + get { + val maybeBlock: Future[Option[Block]] = (blockchainActor ? GetBlock(hash)).mapTo[Option[Block]] + rejectEmptyResponse { + complete(maybeBlock) + } + } + } ~ + path(TRANSACTION / Segment) { id => + get { + log.info(s"$id; $hash") + val maybeTx: Future[Option[Transaction]] = (blockchainActor ? GetTxOfBlock(id, hash)).mapTo[Option[Transaction]] + rejectEmptyResponse { complete(maybeTx) } + } } } } diff --git a/src/test/scala/com/fluency03/blockchain/api/actors/BlockchainActorTest.scala b/src/test/scala/com/fluency03/blockchain/api/actors/BlockchainActorTest.scala index 2dd94d2..7c2c2ce 100644 --- a/src/test/scala/com/fluency03/blockchain/api/actors/BlockchainActorTest.scala +++ b/src/test/scala/com/fluency03/blockchain/api/actors/BlockchainActorTest.scala @@ -4,7 +4,7 @@ import akka.actor.{ActorRef, ActorSystem, Props} import akka.testkit.{DefaultTimeout, ImplicitSender, TestKit} import com.fluency03.blockchain.api.actors.BlockchainActor._ import com.fluency03.blockchain.api.{FailureMsg, SuccessMsg} -import com.fluency03.blockchain.core.Blockchain +import com.fluency03.blockchain.core.{Block, Blockchain} import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} import scala.concurrent.duration._ @@ -39,8 +39,18 @@ class BlockchainActorTest extends TestKit(ActorSystem("BlockchainActorTest")) wi blockchainActor ! GetBlock("somehash") expectMsg(None) - blockchainActor ! GetBlock(blockchain.chain.head.hash) - expectMsg(Some(blockchain.chain.head)) + val genesis = Block.genesisBlock + blockchainActor ! GetBlock(genesis.hash) + expectMsg(Some(genesis)) + + blockchainActor ! GetTxOfBlock(genesis.transactions.head.id, genesis.hash) + expectMsg(Some(genesis.transactions.head)) + + blockchainActor ! GetTxOfBlock("aa", genesis.hash) + expectMsg(None) + + blockchainActor ! GetTxOfBlock(genesis.transactions.head.id, "bb") + expectMsg(None) blockchainActor ! DeleteBlockchain expectMsg(SuccessMsg(s"Blockchain deleted."))