Skip to content

Commit

Permalink
add last- new- next- block
Browse files Browse the repository at this point in the history
  • Loading branch information
fluency03 committed May 4, 2018
1 parent d583b4c commit 5ae6051
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import scala.collection.mutable
object BlockPoolActor {
final case object GetBlocks
final case class GetBlocks(hashes: Set[String])
final case class CreateBlock(block: Block)
final case class AddBlock(block: Block)
final case class GetBlock(hash: String)
final case class DeleteBlock(hash: String)
final case class GetTxOfBlock(id: String, hash: String)

def props: Props = Props[BlockPoolActor]
}
Expand All @@ -31,19 +32,17 @@ class BlockPoolActor extends ActorSupport {
def receive: Receive = {
case GetBlocks => onGetBlocks()
case GetBlocks(hashes) => onGetBlocks(hashes)
case CreateBlock(block) => onCreateBlock(block)
case AddBlock(block) => onAddBlock(block)
case GetBlock(hash) => onGetBlock(hash)
case DeleteBlock(hash) => onDeleteBlock(hash)
case GetTxOfBlock(id, hash) => onGetTxOfBlock(id, hash)
case _ => unhandled _
}

/**
* TODO (Chang): new APIS:
* - CreateBlock
* - GetBlock (onChain or offChain)
* - GetTransactionOfABlock
* - ContainsBlock
* - AddBlockOnChain
*
*/

Expand All @@ -53,7 +52,7 @@ class BlockPoolActor extends ActorSupport {
k => hashes.contains(k)
).values.toSeq

private[this] def onCreateBlock(block: Block): Unit = {
private[this] def onAddBlock(block: Block): Unit = {
if (blocksPool.contains(block.hash)) sender() ! FailureMsg(s"Block ${block.hash} already exists in the Pool.")
else {
blocksPool += (block.hash -> block)
Expand All @@ -69,4 +68,9 @@ class BlockPoolActor extends ActorSupport {
sender() ! SuccessMsg(s"Block $hash deleted from the Pool.")
} else sender() ! FailureMsg(s"Block $hash does not exist in the Pool.")

private def onGetTxOfBlock(id: String, hash: String): Unit = blocksPool.get(hash) match {
case Some(block) => sender() ! block.transactions.find(_.id == id)
case None => sender() ! None
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ object BlockchainActor {
final case object CreateBlockchain
final case object DeleteBlockchain
final case class GetBlockFromChain(hash: String)
final case object GetLastBlock
final case class GetTxOfBlock(id: String, hash: String)
final case class AddBlock(block: Block)
final case class AddBlockFromPool(hash: String)
final case object RemoveBlock
final case class AppendBlock(block: Block)
final case class AppendBlockFromPool(hash: String)
final case object RemoveLastBlock
final case class MineNextBlock(data: String, ids: Seq[String])
final case object CheckBlockchainValidity
final case class GetBlockFromPool(hash: String)
Expand All @@ -45,10 +46,11 @@ class BlockchainActor extends ActorSupport {
case CreateBlockchain => onCreateBlockchain()
case DeleteBlockchain => onDeleteBlockchain()
case GetBlockFromChain(hash) => onGetBlockFromChain(hash)
case GetLastBlock => onGetLastBlock()
case GetTxOfBlock(id, hash) => onGetTxOfBlock(id, hash)
case AddBlock(block) => onAddBlock(block)
case AddBlockFromPool(hash) => onAddBlockFromPool(hash)
case RemoveBlock => onRemoveBlock()
case AppendBlock(block) => onAppendBlock(block)
case AppendBlockFromPool(hash) => onAppendBlockFromPool(hash)
case RemoveLastBlock => onRemoveLastBlock()
case MineNextBlock(data, ids) => onMineNextBlock(data, ids)
case CheckBlockchainValidity => onCheckBlockchainValidity()
case GetBlockFromPool(hash) => onGetBlockFromPool(hash)
Expand All @@ -57,6 +59,7 @@ class BlockchainActor extends ActorSupport {

/**
* TODO (Chang):
* - GetLastBlock
*
*/

Expand All @@ -83,12 +86,20 @@ class BlockchainActor extends ActorSupport {

private def onGetBlockFromChain(hash: String): Unit = sender() ! getBlockFromChain(hash)

private def onGetLastBlock(): Unit = blockchainOpt match {
case Some(blockchain) => sender() ! blockchain.lastBlock()
case None =>
log.error("Blockchain does not exist! Clear the hash-to-index mapping!")
hashIndexMapping.clear()
None
}

private def onGetTxOfBlock(id: String, hash: String): Unit = getBlockFromChain(hash) match {
case Some(block) => sender() ! block.transactions.find(_.id == id)
case None => sender() ! None
}

private def onAddBlock(block: Block): Unit = blockchainOpt match {
private def onAppendBlock(block: Block): Unit = blockchainOpt match {
case Some(blockchain) =>
blockchainOpt = Some(blockchain.addBlock(block))
hashIndexMapping += (block.hash -> blockchain.length)
Expand All @@ -99,7 +110,7 @@ class BlockchainActor extends ActorSupport {
sender() ! FailureMsg("Blockchain does not exist.")
}

private def onAddBlockFromPool(hash: String): Unit = blockchainOpt match {
private def onAppendBlockFromPool(hash: String): Unit = blockchainOpt match {
case Some(blockchain) =>
val maybeBlock: Future[Option[Block]] = (blockPoolActor ? BlockPoolActor.GetBlock(hash)).mapTo[Option[Block]]
val theSender: ActorRef = sender()
Expand All @@ -120,7 +131,7 @@ class BlockchainActor extends ActorSupport {
sender() ! FailureMsg("Blockchain does not exist.")
}

private def onRemoveBlock(): Unit = blockchainOpt match {
private def onRemoveLastBlock(): Unit = blockchainOpt match {
case Some(blockchain) =>
val toBeRemoved = blockchain.chain.head
blockchainOpt = Some(blockchain.removeBlock())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import scala.collection.mutable
object TxPoolActor {
final case object GetTransactions
final case class GetTransactions(ids: Seq[String])
final case class CreateTransaction(tx: Transaction)
final case class AddTransaction(tx: Transaction)
final case class GetTransaction(id: String)
final case class DeleteTransaction(id: String)
final case class UpdateTransaction(tx: Transaction)
Expand Down Expand Up @@ -39,7 +39,7 @@ class TxPoolActor extends ActorSupport {
def receive: Receive = {
case GetTransactions => onGetTransactions()
case GetTransactions(ids) => onGetTransactions(ids)
case CreateTransaction(tx) => onCreateTransaction(tx)
case AddTransaction(tx) => onAddTransaction(tx)
case GetTransaction(id) => onGetTransaction(id)
case DeleteTransaction(id) => onDeleteTransaction(id)
case UpdateTransaction(tx) => onUpdateTransaction(tx)
Expand All @@ -51,7 +51,7 @@ class TxPoolActor extends ActorSupport {
private def onGetTransactions(ids: Seq[String]): Unit =
sender() ! ids.map(id => transPool.get(id)).filter(_.isDefined).map(_.get)

private def onCreateTransaction(tx: Transaction): Unit =
private def onAddTransaction(tx: Transaction): Unit =
if (transPool.contains(tx.id)) sender() ! FailureMsg(s"Transaction ${tx.id} already exists in the Pool.")
else {
transPool += (tx.id -> tx)
Expand Down
6 changes: 6 additions & 0 deletions src/main/scala/com/fluency03/blockchain/api/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ package object api {
val PARENT_UP = "../"








}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import akka.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers.CsvSeq
import akka.pattern.ask
import com.fluency03.blockchain.api.{Blocks, Message}
import com.fluency03.blockchain.api.actors.BlockPoolActor._
import com.fluency03.blockchain.core.Block
import com.fluency03.blockchain.core.{Block, Transaction}

import scala.concurrent.Future

Expand All @@ -23,16 +23,14 @@ trait BlockPoolRoutes extends RoutesSupport {
/**
* TODO (Chang): new APIS:
* - CreateBlock
* - GetBlock (onChain or offChain)
* - GetTransactionOfABlock
* - ContainsBlock
* - AddBlockOnChain
*
*/

lazy val blockPoolRoutes: Route =
path(BLOCKS) {
parameters( 'hashes.as(CsvSeq[String]).? ) { hashesOpt =>
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]
Expand All @@ -44,19 +42,27 @@ trait BlockPoolRoutes extends RoutesSupport {
pathEnd {
post {
entity(as[Block]) { block =>
val blockCreated: Future[Message] = (blockPoolActor ? CreateBlock(block)).mapTo[Message]
val blockCreated: Future[Message] = (blockPoolActor ? AddBlock(block)).mapTo[Message]
onSuccess(blockCreated) { respondOnCreation }
}
}
} ~
path(Segment) { hash =>
get {
val maybeBlock: Future[Option[Block]] = (blockPoolActor ? GetBlock(hash)).mapTo[Option[Block]]
rejectEmptyResponse { complete(maybeBlock) }
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 }
}
} ~
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) }
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,38 @@ trait BlockchainRoutes extends RoutesSupport {
onSuccess(validity) { respondOnUpdate }
}
} ~
path(LAST_BLOCK) {
get {
val maybeLastBlock: Future[Option[Block]] = (blockchainActor ? GetLastBlock).mapTo[Option[Block]]
rejectEmptyResponse { complete(maybeLastBlock) }
} ~
delete {
val blockchainUpdated: Future[Message] = (blockchainActor ? RemoveLastBlock).mapTo[Message]
onSuccess(blockchainUpdated) { respondOnUpdate }
}
} ~
path(NEW_BLOCK) {
parameters('hash.?) {
case Some(hash) =>
val blockchainUpdated: Future[Message] = (blockchainActor ? AppendBlockFromPool(hash)).mapTo[Message]
onSuccess(blockchainUpdated) { respondOnUpdate }
case None => entity(as[Block]) { block =>
val blockchainUpdated: Future[Message] = (blockchainActor ? AppendBlock(block)).mapTo[Message]
onSuccess(blockchainUpdated) { respondOnUpdate }
}
}
} ~
path(NEXT_BLOCK) {
post {
parameters('id.as(CsvSeq[String]).?) { idsOpt: Option[Seq[String]] =>
entity(as[Input]) { in =>
val maybeNextBlock: Future[Option[Block]] =
(blockchainActor ? MineNextBlock(in.content, idsOpt.getOrElse(Seq.empty[String]))).mapTo[Option[Block]]
rejectEmptyResponse { complete(maybeNextBlock) }
}
}
}
} ~
pathEnd {
get {
val blockchain: Future[Option[Blockchain]] = (blockchainActor ? GetBlockchain).mapTo[Option[Blockchain]]
Expand All @@ -42,30 +74,6 @@ trait BlockchainRoutes extends RoutesSupport {
val blockchainCreated: Future[Message] = (blockchainActor ? CreateBlockchain).mapTo[Message]
onSuccess(blockchainCreated) { respondOnCreation }
} ~
put {
parameters('action, 'hash.?, 'id.as(CsvSeq[String]).?) {
(action, hashOpt: Option[String], idsOpt: Option[Seq[String]]) => action match {
case ADD_BLOCK_ACTION => hashOpt match {
case Some(hash) =>
val blockchainUpdated: Future[Message] = (blockchainActor ? AddBlockFromPool(hash)).mapTo[Message]
onSuccess(blockchainUpdated) { respondOnUpdate }
case None => entity(as[Block]) { block =>
val blockchainUpdated: Future[Message] = (blockchainActor ? AddBlock(block)).mapTo[Message]
onSuccess(blockchainUpdated) { respondOnUpdate }
}
}
case REMOVE_BLOCK_ACTION =>
val blockchainUpdated: Future[Message] = (blockchainActor ? RemoveBlock).mapTo[Message]
onSuccess(blockchainUpdated) { respondOnUpdate }
case MINE_NEXT_BLOCK_ACTION => entity(as[Input]) { in =>
val maybeNextBlock: Future[Option[Block]] =
(blockchainActor ? MineNextBlock(in.content, idsOpt.getOrElse(Seq.empty[String]))).mapTo[Option[Block]]
rejectEmptyResponse { complete(maybeNextBlock) }
}
case act => complete((StatusCodes.BadRequest, FailureMsg(s"Action Not Supported: $act")))
}
}
} ~
delete {
val blockchainDeleted: Future[Message] = (blockchainActor ? DeleteBlockchain).mapTo[Message]
onSuccess(blockchainDeleted) { respondOnDeletion }
Expand All @@ -80,7 +88,6 @@ trait BlockchainRoutes extends RoutesSupport {
} ~
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) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ trait TxPoolRoutes extends RoutesSupport {

/**
* TODO (Chang):
* - Update transaction
* - Sign transaction
*
*/
Expand All @@ -42,7 +41,7 @@ trait TxPoolRoutes extends RoutesSupport {
pathEnd {
post {
entity(as[Transaction]) { tx =>
val msgOnCreate: Future[Message] = (txPoolActor ? CreateTransaction(tx)).mapTo[Message]
val msgOnCreate: Future[Message] = (txPoolActor ? AddTransaction(tx)).mapTo[Message]
onSuccess(msgOnCreate) { respondOnCreation }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ package object routes {
// blockchain
val BLOCKCHAIN = "blockchain"
val VALIDITY = "validity"
val ADD_BLOCK_ACTION = "addBlock"
val REMOVE_BLOCK_ACTION = "removeBlock"
val MINE_NEXT_BLOCK_ACTION = "mineNextBlock"
val LAST_BLOCK = "last-block"
val NEW_BLOCK = "new-block"
val NEXT_BLOCK = "next-block"

// block
val BLOCKS = "blocks"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ class BlockPoolActorTest extends TestKit(ActorSystem("BlocksActorTest")) with Im
blockPoolActor ! GetBlocks(Set("somehash"))
expectMsg(Seq.empty[Block])

blockPoolActor ! CreateBlock(Block.genesisBlock)
blockPoolActor ! AddBlock(Block.genesisBlock)
expectMsg(SuccessMsg(s"Block ${Block.genesisBlock.hash} created in the Pool."))

blockPoolActor ! CreateBlock(Block.genesisBlock)
blockPoolActor ! AddBlock(Block.genesisBlock)
expectMsg(FailureMsg(s"Block ${Block.genesisBlock.hash} already exists in the Pool."))

blockPoolActor ! GetBlocks
Expand Down
Loading

0 comments on commit 5ae6051

Please sign in to comment.