Skip to content

Commit

Permalink
resolve conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
fluency03 committed Apr 29, 2018
2 parents 4b52536 + 0e57819 commit bf3fcf6
Show file tree
Hide file tree
Showing 23 changed files with 226 additions and 63 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@ Inspired by:
- [Naivecoin](https://github.com/lhartikk/naivecoin) of [@lhartikk](https://github.com/lhartikk)

REST API service is built on the open source projects [akka](https://github.com/akka/akka) and [akka-http](https://github.com/akka/akka-http).

API Documentation on Postman: [blockchain-in-scala](https://documenter.getpostman.com/view/1231202/blockchain-in-scala/RVu8iTUP)

Start the service, run this Class:

```
com.fluency03.blockchain.api.Server
```
5 changes: 4 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ organization := "com.fluency03"

name := "blockchain-in-scala"

version := "0.0.2"
version := "0.0.6"

scalaVersion := "2.12.0"

Expand Down Expand Up @@ -43,3 +43,6 @@ libraryDependencies ++= {
"org.bouncycastle" % "bcprov-jdk15on" % "1.59"
)
} ++ httpDependencies ++ testDependencies


mainClass in assembly := Some("com.fluency03.blockchain.api.Server")
1 change: 1 addition & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0")
addSbtPlugin("com.artima.supersafe" %% "sbtplugin" % "1.1.3")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.4")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package com.fluency03.blockchain.api.actors
import akka.actor.{ActorSelection, Props}
import com.fluency03.blockchain.api.actors.BlockchainActor._
import com.fluency03.blockchain.api._
import com.fluency03.blockchain.core.Blockchain
import com.fluency03.blockchain.core.{Block, Blockchain}

import scala.collection.mutable

object BlockchainActor {
final case object GetBlockchain
Expand All @@ -23,6 +25,7 @@ class BlockchainActor extends ActorSupport {

// TODO (Chang): need persistence
var blockchainOpt: Option[Blockchain] = None
var hashIndexMapping = mutable.Map.empty[String, Int]

def receive: Receive = {
case GetBlockchain => onGetBlockchain()
Expand All @@ -31,6 +34,16 @@ class BlockchainActor extends ActorSupport {
case _ => unhandled _
}

/**
* TODO (Chang): new APIS:
* - AddBlockOnBlockchain
* - GetBlockFromBlockchain
* - CheckBlockchainIsValid
* - GetTransactionOfABlock
* - MineNextBlock
*
*/

private def onGetBlockchain(): Unit = sender() ! blockchainOpt

private def onCreateBlockchain(): Unit =
Expand All @@ -46,8 +59,5 @@ class BlockchainActor extends ActorSupport {
sender() ! SuccessMsg(s"Blockchain deleted.")
} else sender() ! FailureMsg(s"Blockchain does not exist.")

// TODO (Chang): APIs for adding new Block on the chain



}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import scala.collection.mutable

object BlocksActor {
final case object GetBlocks
final case class GetBlocks(hashes: Set[String])
final case class CreateBlock(block: Block)
final case class GetBlock(hash: String)
final case class DeleteBlock(hash: String)
Expand All @@ -25,35 +26,48 @@ class BlocksActor extends ActorSupport {
val transActor: ActorSelection = context.actorSelection(PARENT_UP + TRANS_ACTOR_NAME)

// TODO (Chang): need persistence
var blocks = mutable.Map.empty[String, Block]
var blocksPool = mutable.Map.empty[String, Block]

def receive: Receive = {
case GetBlocks => onGetBlocks()
case GetBlocks(hashes) => onGetBlocks(hashes)
case CreateBlock(block) => onCreateBlock(block)
case GetBlock(hash) => onGetBlock(hash)
case DeleteBlock(hash) => onDeleteBlock(hash)
case _ => unhandled _
}

private[this] def onGetBlocks(): Unit = sender() ! blocks.values.toSeq
/**
* TODO (Chang): new APIS:
* - CreateBlock
* - GetBlock (onChain or offChain)
* - GetTransactionOfABlock
* - AddBlockOnChain
*
*/

private[this] def onGetBlocks(): Unit = sender() ! blocksPool.values.toSeq

private[this] def onGetBlocks(hashes: Set[String]): Unit = sender() ! blocksPool.filterKeys(
k => hashes.contains(k)
).values.toSeq

private[this] def onCreateBlock(block: Block): Unit = {
if (blocks.contains(block.hash)) sender() ! FailureMsg(s"Block ${block.hash} already exists.")
if (blocksPool.contains(block.hash)) sender() ! FailureMsg(s"Block ${block.hash} already exists.")
else {
blocks += (block.hash -> block)
blocksPool += (block.hash -> block)
sender() ! SuccessMsg(s"Block ${block.hash} created.")
}
}

private[this] def onGetBlock(hash: String): Unit = sender() ! blocks.get(hash)
private[this] def onGetBlock(hash: String): Unit = sender() ! blocksPool.get(hash)

private[this] def onDeleteBlock(hash: String): Unit = {
if (blocks.contains(hash)) {
blocks -= hash
if (blocksPool.contains(hash)) {
blocksPool -= hash
sender() ! SuccessMsg(s"Block $hash deleted.")
} else sender() ! FailureMsg(s"Block $hash does not exist.")
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import com.fluency03.blockchain.api.actors.NetworkActor._
import com.fluency03.blockchain.api.actors.PeerActor.GetPublicKeys
import com.fluency03.blockchain.core.Peer

import scala.concurrent.Future

object NetworkActor {
final case object GetNetwork
final case object GetPeers
final case class GetPeers(names: Set[String])
final case class CreatePeer(name: String)
final case class GetPeer(name: String)
final case class DeletePeer(name: String)
Expand All @@ -28,15 +32,33 @@ class NetworkActor extends ActorSupport {

// TODO (Chang): need persistence

/**
* TODO (Chang):
* - Remove wallet
* - Sign transaction
*
*/

def receive: Receive = {
case GetNetwork => onGetNetwork()
case GetPeers => onGetPeers()
case GetPeers(names) => onGetPeers(names)
case CreatePeer(name) => onCreatePeer(name)
case GetPeer(name) => onGetPeer(name)
case DeletePeer(name) => onDeletePeer(name)
case _ => unhandled _
}

private def onGetPeers(): Unit = sender() ! context.children.map(_.path.name).toSet
private def onGetNetwork(): Unit = sender() ! context.children.map(_.path.name).toSet

private def onGetPeers(): Unit = Future.sequence(context.children.map(p => {
(p ? GetPublicKeys).mapTo[Set[String]].map(keys => p.path.name -> keys)
})).map(_.toMap).pipeTo(sender())

private def onGetPeers(names: Set[String]): Unit = Future.sequence(context.children
.filter(p => names.contains(p.path.name))
.map(p => { (p ? GetPublicKeys).mapTo[Set[String]].map(keys => p.path.name -> keys) })
).map(_.toMap).pipeTo(sender())

private def onCreatePeer(name: String): Unit =
if (context.child(name).isDefined) sender() ! FailureMsg(s"Peer $name has been created.")
Expand All @@ -59,8 +81,4 @@ class NetworkActor extends ActorSupport {
sender() ! SuccessMsg(s"Peer $name deleted.")
} else sender() ! FailureMsg(s"Peer $name does not exist.")

// TODO (Chang): APIs for selecting Peers based on Seq of ids



}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ class PeerActor extends ActorSupport {
val wallets = mutable.Map.empty[String, Wallet]
val others = mutable.Map.empty[String, Peer]

/**
* TODO (Chang):
* - Remove wallet
* - Sign transactions
*
*/

def receive: Receive = {
case GetPublicKeys => sender() ! wallets.values.map(_.address).toSet
case CreateWallet => sender() ! addWallet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import scala.collection.mutable

object TransactionsActor {
final case object GetTransactions
final case class GetTransactions(ids: Set[String])
final case class CreateTransaction(tx: Transaction)
final case class GetTransaction(hash: String)
final case class DeleteTransaction(hash: String)
final case class GetTransaction(id: String)
final case class DeleteTransaction(id: String)

def props: Props = Props[TransactionsActor]
}
Expand All @@ -21,40 +22,49 @@ class TransactionsActor extends ActorSupport {
override def postStop(): Unit = log.info("{} stopped!", this.getClass.getSimpleName)

// TODO (Chang): need persistence
val currentTransactions: mutable.Map[String, Transaction] = mutable.Map.empty[String, Transaction]
val transPool: mutable.Map[String, Transaction] = mutable.Map.empty[String, Transaction]
val uTxOs: mutable.Map[Outpoint, TxOut] = mutable.Map.empty[Outpoint, TxOut]

val blockchainActor: ActorSelection = context.actorSelection(PARENT_UP + BLOCKCHAIN_ACTOR_NAME)
val blockActor: ActorSelection = context.actorSelection(PARENT_UP + BLOCKS_ACTOR_NAME)
val networkActor: ActorSelection = context.actorSelection(PARENT_UP + NETWORK_ACTOR_NAME)

/**
* TODO (Chang):
* - Update transaction
* - Sign transaction
*
*/

def receive: Receive = {
case GetTransactions => onGetTransactions()
case GetTransactions(ids) => onGetTransactions(ids)
case CreateTransaction(tx) => onCreateTransaction(tx)
case GetTransaction(hash) => onGetTransaction(hash)
case DeleteTransaction(hash) => onDeleteTransaction(hash)
case GetTransaction(id) => onGetTransaction(id)
case DeleteTransaction(id) => onDeleteTransaction(id)
case _ => unhandled _
}

private def onGetTransactions(): Unit = sender() ! currentTransactions.values.toSeq
private def onGetTransactions(): Unit = sender() ! transPool.values.toSeq

private def onGetTransactions(ids: Set[String]): Unit = sender() ! transPool.filterKeys(
k => ids.contains(k)
).values.toSeq

private def onCreateTransaction(tx: Transaction): Unit = {
if (currentTransactions.contains(tx.id)) sender() ! FailureMsg(s"Transaction ${tx.id} already exists.")
if (transPool.contains(tx.id)) sender() ! FailureMsg(s"Transaction ${tx.id} already exists.")
else {
currentTransactions += (tx.id -> tx)
transPool += (tx.id -> tx)
sender() ! SuccessMsg(s"Transaction ${tx.id} created.")
}
}

private def onGetTransaction(id: String): Unit = sender() ! currentTransactions.get(id)
private def onGetTransaction(id: String): Unit = sender() ! transPool.get(id)

private def onDeleteTransaction(id: String): Unit =
if (currentTransactions contains id) {
currentTransactions -= id
if (transPool contains id) {
transPool -= id
sender() ! SuccessMsg(s"Transaction $id deleted.")
} else sender() ! FailureMsg(s"Transaction $id does not exist.")

// TODO (Chang): APIs for selecting transactions based on Seq of ids


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package com.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}
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.fluency03.blockchain.api.{Blocks, FailureMsg, Message, SuccessMsg}
import com.fluency03.blockchain.api.{Blocks, Message}
import com.fluency03.blockchain.api.actors.BlocksActor._
import com.fluency03.blockchain.core.Block

Expand All @@ -20,10 +20,21 @@ trait BlockRoutes extends RoutesSupport {

def blocksActor: ActorRef

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

lazy val blockRoutes: Route =
path(BLOCKS) {
get {
val blocks: Future[Blocks] = (blocksActor ? GetBlocks).mapTo[Blocks]
parameters( 'hashes.as(CsvSeq[String]) ? ) { hashes =>
val blocks: Future[Blocks] =
if (hashes.isDefined) (blocksActor ? GetBlocks(hashes.get.toSet)).mapTo[Blocks]
else (blocksActor ? GetBlocks).mapTo[Blocks]
complete(blocks)
}
} ~
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ trait BlockchainRoutes extends RoutesSupport {

def blockchainActor: ActorRef

/**
* TODO (Chang): new APIS:
* - AddBlockOnBlockchain
* - GetBlockFromBlockchain
* - CheckBlockchainIsValid
* - GetTransactionOfABlock
* - MineNextBlock
*
*/

lazy val blockchainRoutes: Route =
pathPrefix(BLOCKCHAIN) {
pathEnd {
Expand Down
Loading

0 comments on commit bf3fcf6

Please sign in to comment.