From 59f06b59b45253f0f6259b19ba2b3ffc7e016583 Mon Sep 17 00:00:00 2001 From: fluency03 Date: Sat, 12 May 2018 21:17:11 +0200 Subject: [PATCH] change type --- .../api/actors/BlockPoolActor.scala | 25 ++++----- .../api/actors/BlockchainActor.scala | 33 ++++++------ .../blockchain/api/actors/NetworkActor.scala | 9 ++-- .../blockchain/api/actors/PeerActor.scala | 4 +- .../blockchain/api/actors/TxPoolActor.scala | 17 ++++--- .../api/routes/BlockPoolRoutes.scala | 9 ++-- .../api/routes/BlockchainRoutes.scala | 13 ++--- .../blockchain/api/routes/NetworkRoutes.scala | 9 ++-- .../blockchain/api/routes/RoutesSupport.scala | 5 +- .../blockchain/api/routes/TxPoolRoutes.scala | 5 +- .../blockchain/core/KeyContainer.scala | 6 +-- .../fluency03/blockchain/crypto/Base58.scala | 12 ++--- .../blockchain/crypto/RIPEMD160.scala | 10 ++-- .../fluency03/blockchain/crypto/SHA256.scala | 23 +++------ .../blockchain/crypto/Secp256k1.scala | 14 ++--- .../blockchain/{ => misc}/Serde.scala | 4 +- .../github/fluency03/blockchain/package.scala | 51 +++++++++---------- .../blockchain/crypto/RIPEMD160Test.scala | 2 +- .../blockchain/crypto/SHA256Test.scala | 4 +- .../fluency03/blockchain/misc/SerdeTest.scala | 9 ++++ 20 files changed, 137 insertions(+), 127 deletions(-) rename src/main/scala/com/github/fluency03/blockchain/{ => misc}/Serde.scala (86%) create mode 100644 src/test/scala/com/github/fluency03/blockchain/misc/SerdeTest.scala 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 8944a44..ba4ff32 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,4 +1,5 @@ -package com.github.fluency03.blockchain.api.actors +package com.github.fluency03.blockchain +package api.actors import akka.actor.{ActorRef, ActorSelection, Props} import akka.pattern.ask @@ -11,12 +12,12 @@ import scala.util.{Failure, Success} object BlockPoolActor { final case object GetBlocks - final case class GetBlocks(hashes: Set[String]) + final case class GetBlocks(hashes: Set[HexString]) 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) - final case class MineAndAddNextBlock(data: String, ids: Seq[String]) + final case class GetBlock(hash: HexString) + final case class DeleteBlock(hash: HexString) + final case class GetTxOfBlock(id: HexString, hash: HexString) + final case class MineAndAddNextBlock(data: String, ids: Seq[HexString]) def props: Props = Props[BlockPoolActor] } @@ -32,7 +33,7 @@ class BlockPoolActor extends ActorSupport { val txPoolActor: ActorSelection = context.actorSelection(PARENT_UP + TX_POOL_ACTOR_NAME) // TODO (Chang): need persistence - var blocksPool: mutable.Map[String, Block] = mutable.Map.empty[String, Block] + var blocksPool: mutable.Map[HexString, Block] = mutable.Map.empty[HexString, Block] def receive: Receive = { case GetBlocks => onGetBlocks() @@ -50,7 +51,7 @@ class BlockPoolActor extends ActorSupport { */ private[this] def onGetBlocks(): Unit = sender() ! blocksPool.values.toSeq - private[this] def onGetBlocks(hashes: Set[String]): Unit = + private[this] def onGetBlocks(hashes: Set[HexString]): Unit = sender() ! blocksPool.filterKeys(hashes.contains).values.toSeq private[this] def onAddBlock(block: Block): Unit = { @@ -62,20 +63,20 @@ class BlockPoolActor extends ActorSupport { } } - private[this] def onGetBlock(hash: String): Unit = sender() ! blocksPool.get(hash) + private[this] def onGetBlock(hash: HexString): Unit = sender() ! blocksPool.get(hash) - private[this] def onDeleteBlock(hash: String): Unit = + private[this] def onDeleteBlock(hash: HexString): Unit = if (blocksPool.contains(hash)) { blocksPool -= hash 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 { + private def onGetTxOfBlock(id: HexString, hash: HexString): Unit = blocksPool.get(hash) match { case Some(block) => sender() ! block.transactions.find(_.id == id) case None => sender() ! None } - private def onMineAndAddNextBlock(data: String, ids: Seq[String]): Unit = { + private def onMineAndAddNextBlock(data: String, ids: Seq[HexString]): Unit = { val theSender: ActorRef = sender() (blockchainActor ? BlockchainActor.MineNextBlock(data, ids)) .mapTo[Option[Block]] 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 e4f0af6..e6ef6b4 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 @@ -1,4 +1,5 @@ -package com.github.fluency03.blockchain.api.actors +package com.github.fluency03.blockchain +package api.actors import akka.actor.{ActorRef, ActorSelection, Props} import akka.pattern.ask @@ -18,15 +19,15 @@ object BlockchainActor { final case object DeleteBlockchain extends BlockchainMsg final case object CheckBlockchainValidity extends BlockchainMsg - final case class GetBlockByHash(hash: String) extends BlockMsg - final case class GetBlocksByHashesAndIndices(hashes: Set[String], indices: Set[Int]) extends BlockMsg + final case class GetBlockByHash(hash: HexString) extends BlockMsg + final case class GetBlocksByHashesAndIndices(hashes: Set[HexString], indices: Set[Int]) extends BlockMsg final case object GetLastBlock extends BlockMsg - final case class GetTxOfBlock(id: String, hash: String) extends BlockMsg + final case class GetTxOfBlock(id: HexString, hash: HexString) extends BlockMsg final case class AppendBlock(block: Block) extends BlockMsg - final case class AppendBlockFromPool(hash: String) extends BlockMsg + final case class AppendBlockFromPool(hash: HexString) extends BlockMsg final case object RemoveLastBlock extends BlockMsg - final case class MineNextBlock(data: String, ids: Seq[String]) extends BlockMsg - final case class GetBlockFromPool(hash: String) extends BlockMsg + final case class MineNextBlock(data: String, ids: Seq[HexString]) extends BlockMsg + final case class GetBlockFromPool(hash: HexString) extends BlockMsg def props: Props = Props[BlockchainActor] } @@ -43,7 +44,7 @@ class BlockchainActor extends ActorSupport { // TODO (Chang): need persistence var blockchainOpt: Option[Blockchain] = None - val hashIndexMapping: mutable.Map[String, Int] = mutable.Map.empty[String, Int] + val hashIndexMapping: mutable.Map[HexString, Int] = mutable.Map.empty[HexString, Int] def receive: Receive = { case msg: BlockchainMsg => inCaseOfBlockchainMsg(msg) @@ -105,9 +106,9 @@ class BlockchainActor extends ActorSupport { /** * Handlers for each of the BlockMsg. */ - private def onGetBlockByHash(hash: String): Unit = sender() ! getBlockByHash(hash) + private def onGetBlockByHash(hash: HexString): Unit = sender() ! getBlockByHash(hash) - private def onGetBlocksByHashesAndIndices(hashes: Set[String], indices: Set[Int]): Unit = + private def onGetBlocksByHashesAndIndices(hashes: Set[HexString], indices: Set[Int]): Unit = sender() ! getBlocksByHashesAndIndices(hashes, indices) private def onGetLastBlock(): Unit = blockchainOpt match { @@ -117,7 +118,7 @@ class BlockchainActor extends ActorSupport { sender() ! None } - private def onGetTxOfBlock(id: String, hash: String): Unit = getBlockByHash(hash) match { + private def onGetTxOfBlock(id: HexString, hash: HexString): Unit = getBlockByHash(hash) match { case Some(block) => sender() ! block.transactions.find(_.id == id) case None => sender() ! None } @@ -131,7 +132,7 @@ class BlockchainActor extends ActorSupport { sender() ! FailureMsg("Blockchain does not exist.") } - private def onAppendBlockFromPool(hash: String): Unit = blockchainOpt match { + private def onAppendBlockFromPool(hash: HexString): Unit = blockchainOpt match { case Some(blockchain) => val theSender: ActorRef = sender() (blockPoolActor ? BlockPoolActor.GetBlock(hash)) @@ -162,7 +163,7 @@ class BlockchainActor extends ActorSupport { sender() ! FailureMsg("Blockchain does not exist.") } - private def onMineNextBlock(data: String, ids: Seq[String]): Unit = blockchainOpt match { + private def onMineNextBlock(data: String, ids: Seq[HexString]): Unit = blockchainOpt match { case Some(blockchain) => if (ids.isEmpty) sender() ! Some(blockchain.mineNextBlock(data, Seq.empty[Transaction])) else { @@ -179,13 +180,13 @@ class BlockchainActor extends ActorSupport { sender() ! None } - private def onGetBlockFromPool(hash: String): Unit = + private def onGetBlockFromPool(hash: HexString): Unit = blockPoolActor forward BlockPoolActor.GetBlock(hash) /** * Private helper methods. */ - private def getBlockByHash(hash: String): Option[Block] = hashIndexMapping.get(hash) match { + private def getBlockByHash(hash: HexString): Option[Block] = hashIndexMapping.get(hash) match { case Some(index) => blockchainOpt match { case Some(blockchain) => Some(blockchain.chain(index)) case None => @@ -195,7 +196,7 @@ class BlockchainActor extends ActorSupport { case None => None } - private def getBlocksByHashesAndIndices(hashes: Set[String], indices: Set[Int]): Set[Block] = { + private def getBlocksByHashesAndIndices(hashes: Set[HexString], indices: Set[Int]): Set[Block] = { ??? } diff --git a/src/main/scala/com/github/fluency03/blockchain/api/actors/NetworkActor.scala b/src/main/scala/com/github/fluency03/blockchain/api/actors/NetworkActor.scala index 85dae99..c581bef 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/actors/NetworkActor.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/actors/NetworkActor.scala @@ -1,4 +1,5 @@ -package com.github.fluency03.blockchain.api.actors +package com.github.fluency03.blockchain +package api.actors import akka.actor.{ActorSelection, Props} import akka.pattern.{ask, pipe} @@ -56,7 +57,7 @@ class NetworkActor extends ActorSupport { private def onGetPeers(): Unit = { val peers = context.children.map { p => - (p ? GetPublicKeys).mapTo[Set[String]].map(p.path.name -> _) + (p ? GetPublicKeys).mapTo[Set[HexString]].map(p.path.name -> _) } Future.sequence(peers).map(_.toMap).pipeTo(sender()) } @@ -64,7 +65,7 @@ class NetworkActor extends ActorSupport { private def onGetPeers(names: Set[String]): Unit = { val peers = context.children .filter { p => names.contains(p.path.name) } - .map { p => (p ? GetPublicKeys).mapTo[Set[String]].map(p.path.name -> _) } + .map { p => (p ? GetPublicKeys).mapTo[Set[HexString]].map(p.path.name -> _) } Future.sequence(peers).map(_.toMap).pipeTo(sender()) } @@ -77,7 +78,7 @@ class NetworkActor extends ActorSupport { private def onGetPeer(name: String): Unit = context.child(name) match { case Some(_) => (context.child(name).get ? GetPublicKeys) - .mapTo[Set[String]] + .mapTo[Set[HexString]] .map { keys => Some(Peer(name, keys)) } .pipeTo(sender()) case None => sender() ! None diff --git a/src/main/scala/com/github/fluency03/blockchain/api/actors/PeerActor.scala b/src/main/scala/com/github/fluency03/blockchain/api/actors/PeerActor.scala index 817d0a7..70826d4 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/actors/PeerActor.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/actors/PeerActor.scala @@ -22,7 +22,7 @@ class PeerActor extends ActorSupport { override def postStop(): Unit = log.info("{} stopped!", this.getClass.getSimpleName) // TODO (Chang): need persistence - val wallet: mutable.Map[String, KeyContainer] = mutable.Map.empty[String, KeyContainer] + val wallet: mutable.Map[HexString, KeyContainer] = mutable.Map.empty[HexString, KeyContainer] val others: mutable.Map[String, Peer] = mutable.Map.empty[String, Peer] /** @@ -38,7 +38,7 @@ class PeerActor extends ActorSupport { case _ => unhandled _ } - private def addWallet(): String = { + private def addWallet(): HexString = { val kc = KeyContainer() wallet += (kc.address -> kc) kc.address diff --git a/src/main/scala/com/github/fluency03/blockchain/api/actors/TxPoolActor.scala b/src/main/scala/com/github/fluency03/blockchain/api/actors/TxPoolActor.scala index 9442171..5cf593c 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/actors/TxPoolActor.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/actors/TxPoolActor.scala @@ -1,4 +1,5 @@ -package com.github.fluency03.blockchain.api.actors +package com.github.fluency03.blockchain +package api.actors import akka.actor.{ActorSelection, Props} import com.github.fluency03.blockchain.api.actors.TxPoolActor._ @@ -10,10 +11,10 @@ import scala.collection.mutable object TxPoolActor { final case object GetTransactions - final case class GetTransactions(ids: Seq[String]) + final case class GetTransactions(ids: Seq[HexString]) final case class AddTransaction(tx: Transaction) - final case class GetTransaction(id: String) - final case class DeleteTransaction(id: String) + final case class GetTransaction(id: HexString) + final case class DeleteTransaction(id: HexString) final case class UpdateTransaction(tx: Transaction) def props: Props = Props[TxPoolActor] } @@ -23,7 +24,7 @@ class TxPoolActor extends ActorSupport { override def postStop(): Unit = log.info("{} stopped!", this.getClass.getSimpleName) // TODO (Chang): need persistence - val transPool: mutable.Map[String, Transaction] = mutable.Map.empty[String, Transaction] + val transPool: mutable.Map[HexString, Transaction] = mutable.Map.empty[HexString, Transaction] val uTxOs: mutable.Map[Outpoint, TxOut] = mutable.Map.empty[Outpoint, TxOut] val blockchainActor: ActorSelection = context.actorSelection(PARENT_UP + BLOCKCHAIN_ACTOR_NAME) @@ -51,7 +52,7 @@ class TxPoolActor extends ActorSupport { */ private def onGetTransactions(): Unit = sender() ! transPool.values.toSeq - private def onGetTransactions(ids: Seq[String]): Unit = + private def onGetTransactions(ids: Seq[HexString]): Unit = sender() ! ids.map(transPool.get).filter(_.isDefined).map(_.get) private def onAddTransaction(tx: Transaction): Unit = @@ -62,9 +63,9 @@ class TxPoolActor extends ActorSupport { sender() ! SuccessMsg(s"Transaction ${tx.id} created in the Pool.") } - private def onGetTransaction(id: String): Unit = sender() ! transPool.get(id) + private def onGetTransaction(id: HexString): Unit = sender() ! transPool.get(id) - private def onDeleteTransaction(id: String): Unit = + private def onDeleteTransaction(id: HexString): Unit = if (transPool.contains(id)) { transPool -= id sender() ! SuccessMsg(s"Transaction $id deleted from the Pool.") 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 e2ee671..1147e19 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 @@ -1,4 +1,5 @@ -package com.github.fluency03.blockchain.api.routes +package com.github.fluency03.blockchain +package api.routes import akka.actor.ActorRef import akka.event.Logging @@ -22,7 +23,7 @@ trait BlockPoolRoutes extends RoutesSupport { lazy val blockPoolRoutes: Route = pathPrefix(BLOCK_POOL) { path(BLOCKS) { - parameters('hashes.as(CsvSeq[String]).?) { hashesOpt: Option[Seq[String]] => + parameters('hashes.as(CsvSeq[HexString]).?) { hashesOpt: Option[Seq[HexString]] => val blocks: Future[Blocks] = hashesOpt match { case Some(hashes) => (blockPoolActor ? GetBlocks(hashes.toSet)).mapTo[Blocks] case None => (blockPoolActor ? GetBlocks).mapTo[Blocks] @@ -32,9 +33,9 @@ trait BlockPoolRoutes extends RoutesSupport { } ~ path(NEXT_BLOCK) { post { - parameters('ids.as(CsvSeq[String]).?) { idsOpt: Option[Seq[String]] => + parameters('ids.as(CsvSeq[HexString]).?) { idsOpt: Option[Seq[HexString]] => entity(as[Input]) { in => - val action = MineAndAddNextBlock(in.content, idsOpt.getOrElse(Seq.empty[String])) + val action = MineAndAddNextBlock(in.content, idsOpt.getOrElse(Seq.empty[HexString])) val maybeNextBlock: Future[Option[Block]] = (blockPoolActor ? action).mapTo[Option[Block]] rejectEmptyResponse { 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 2b12db4..4a564fa 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 @@ -1,4 +1,5 @@ -package com.github.fluency03.blockchain.api.routes +package com.github.fluency03.blockchain +package api.routes import akka.actor.ActorRef import akka.event.Logging @@ -55,10 +56,10 @@ trait BlockchainRoutes extends RoutesSupport { } ~ path(NEXT_BLOCK) { post { - parameters('id.as(CsvSeq[String]).?) { idsOpt: Option[Seq[String]] => + parameters('id.as(CsvSeq[HexString]).?) { idsOpt: Option[Seq[HexString]] => entity(as[Input]) { in => val maybeNextBlock: Future[Option[Block]] = - (blockchainActor ? MineNextBlock(in.content, idsOpt.getOrElse(Seq.empty[String]))) + (blockchainActor ? MineNextBlock(in.content, idsOpt.getOrElse(Seq.empty[HexString]))) .mapTo[Option[Block]] rejectEmptyResponse { complete(maybeNextBlock) @@ -86,9 +87,9 @@ trait BlockchainRoutes extends RoutesSupport { } ~ path(BLOCKS) { get { - parameters('hashes.as(CsvSeq[String]).?, 'indices.as(CsvSeq[Int]).?) { - (hashesOpt: Option[Seq[String]], indicesOpt: Option[Seq[Int]]) => - val (hashes, indices) = (hashesOpt.getOrElse(Seq.empty[String]).toSet, + parameters('hashes.as(CsvSeq[HexString]).?, 'indices.as(CsvSeq[Int]).?) { + (hashesOpt: Option[Seq[HexString]], indicesOpt: Option[Seq[Int]]) => + val (hashes, indices) = (hashesOpt.getOrElse(Seq.empty[HexString]).toSet, indicesOpt.getOrElse(Seq.empty[Int]).toSet) val blocks: Future[Set[Block]] = (blockchainActor ? GetBlocksByHashesAndIndices(hashes, indices)).mapTo[Set[Block]] diff --git a/src/main/scala/com/github/fluency03/blockchain/api/routes/NetworkRoutes.scala b/src/main/scala/com/github/fluency03/blockchain/api/routes/NetworkRoutes.scala index 7f2dfd3..9f8116e 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/routes/NetworkRoutes.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/routes/NetworkRoutes.scala @@ -1,4 +1,5 @@ -package com.github.fluency03.blockchain.api.routes +package com.github.fluency03.blockchain +package api.routes import akka.actor.ActorRef import akka.event.Logging @@ -35,10 +36,10 @@ trait NetworkRoutes extends RoutesSupport { path(PEERS) { get { parameters( 'names.as(CsvSeq[String]).? ) { namesOpt => - val peers: Future[Map[String, Set[String]]] = namesOpt match { + val peers: Future[Map[String, Set[HexString]]] = namesOpt match { case Some(names) => - (networkActor ? GetPeers(names.toSet)).mapTo[Map[String, Set[String]]] - case None => (networkActor ? GetPeers).mapTo[Map[String, Set[String]]] + (networkActor ? GetPeers(names.toSet)).mapTo[Map[String, Set[HexString]]] + case None => (networkActor ? GetPeers).mapTo[Map[String, Set[HexString]]] } complete(peers) } diff --git a/src/main/scala/com/github/fluency03/blockchain/api/routes/RoutesSupport.scala b/src/main/scala/com/github/fluency03/blockchain/api/routes/RoutesSupport.scala index fe66ddf..7428e69 100644 --- a/src/main/scala/com/github/fluency03/blockchain/api/routes/RoutesSupport.scala +++ b/src/main/scala/com/github/fluency03/blockchain/api/routes/RoutesSupport.scala @@ -1,8 +1,9 @@ -package com.github.fluency03.blockchain.api.routes +package com.github.fluency03.blockchain +package api.routes import akka.actor.ActorSystem import akka.http.scaladsl.model.StatusCodes -import akka.http.scaladsl.server.{RequestContext, StandardRoute} +import akka.http.scaladsl.server.StandardRoute import akka.http.scaladsl.server.directives.RouteDirectives.complete import akka.util.Timeout import com.github.fluency03.blockchain.api.{FailureMsg, JsonSupport, Message, SuccessMsg} 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 68aa302..3ef570c 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 @@ -1,4 +1,5 @@ -package com.github.fluency03.blockchain.api.routes +package com.github.fluency03.blockchain +package api.routes import akka.actor.ActorRef import akka.event.Logging @@ -30,7 +31,7 @@ trait TxPoolRoutes extends RoutesSupport { lazy val txPoolRoutes: Route = pathPrefix(TX_POOL) { path(TRANSACTIONS) { - parameters('ids.as(CsvSeq[String]).?) { idsOpt => + parameters('ids.as(CsvSeq[HexString]).?) { idsOpt => val transactions: Future[Transactions] = idsOpt match { case Some(ids) => (txPoolActor ? GetTransactions(ids)).mapTo[Transactions] case None => (txPoolActor ? GetTransactions).mapTo[Transactions] diff --git a/src/main/scala/com/github/fluency03/blockchain/core/KeyContainer.scala b/src/main/scala/com/github/fluency03/blockchain/core/KeyContainer.scala index accbfb0..1f550a9 100644 --- a/src/main/scala/com/github/fluency03/blockchain/core/KeyContainer.scala +++ b/src/main/scala/com/github/fluency03/blockchain/core/KeyContainer.scala @@ -13,10 +13,10 @@ case class KeyContainer() { private[this] val keyPair: KeyPair = Secp256k1.generateKeyPair() - // TODO (Chang): change it to actual address of a PublicKey - lazy val address: String = keyPair.getPublic.toHex + // TODO (Chang): change it to actual address (which is a Base58) of a PublicKey + lazy val address: HexString = keyPair.getPublic.toHex - lazy val publicKeyHex: String = keyPair.getPublic.toHex + lazy val publicKeyHex: HexString = keyPair.getPublic.toHex def balance(uTxOs: mutable.Map[Outpoint, TxOut]): Long = balanceOfKey(this, uTxOs) diff --git a/src/main/scala/com/github/fluency03/blockchain/crypto/Base58.scala b/src/main/scala/com/github/fluency03/blockchain/crypto/Base58.scala index afee4ab..d2abd48 100644 --- a/src/main/scala/com/github/fluency03/blockchain/crypto/Base58.scala +++ b/src/main/scala/com/github/fluency03/blockchain/crypto/Base58.scala @@ -10,11 +10,11 @@ object Base58 { lazy val ALPHABET: Array[Char] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray private val ENCODED_ZERO = ALPHABET(0) - def encodeString(str: String): String = encode(str.getBytes) + def encodeString(str: String): Base58 = encode(str.getBytes) - def encodeHex(hex: String): String = encode(hex.hex2Bytes) + def encodeHex(hex: HexString): Base58 = encode(hex.hex2Bytes) - def encode(bytes: Bytes): String = { + def encode(bytes: Bytes): Base58 = { @tailrec def buildBase58(res: String, bi: BigInt): String = if (bi <= 0) res @@ -28,7 +28,7 @@ object Base58 { confirmZeroByte(buildBase58("", bytes.toBigInt), bytes, 0) } - def decode(str: String): Bytes = { + def decode(str: Base58): Bytes = { @tailrec def restoreBigInt(chars: Array[Char], bi: BigInt, idx: Int): BigInt = if (idx >= chars.length) bi @@ -44,9 +44,9 @@ object Base58 { zeroes ++ Hex.decode(bi.toString(16)) } - def decodeToHex(str: String): String = new String(decode(str)) + def decodeToHex(str: Base58): HexString = new String(decode(str)) - def checkEncode(bytes: Bytes): String = + def checkEncode(bytes: Bytes): Base58 = encode(bytes ++ bytes.toSha256Digest.toSha256Digest.slice(0, 4)) diff --git a/src/main/scala/com/github/fluency03/blockchain/crypto/RIPEMD160.scala b/src/main/scala/com/github/fluency03/blockchain/crypto/RIPEMD160.scala index 13af413..99771b7 100644 --- a/src/main/scala/com/github/fluency03/blockchain/crypto/RIPEMD160.scala +++ b/src/main/scala/com/github/fluency03/blockchain/crypto/RIPEMD160.scala @@ -5,11 +5,11 @@ import org.bouncycastle.crypto.digests.RIPEMD160Digest object RIPEMD160 { - def hash(str: String): String = hash(str.getBytes) + def hash(str: String): HexString = hash(str.getBytes) - def hash(bytes: Bytes): String = hashToDigest(bytes).map("%02x".format(_)).mkString + def hash(bytes: Bytes): HexString = hashDigest(bytes).map("%02x".format(_)).mkString - def hashToDigest(bytes: Bytes): Bytes = { + def hashDigest(bytes: Bytes): Bytes = { val (raw, messageDigest) = (bytes, new RIPEMD160Digest()) messageDigest.update(raw, 0, raw.length) val out = Array.fill[Byte](messageDigest.getDigestSize)(0) @@ -17,8 +17,8 @@ object RIPEMD160 { out } - def hash160(bytes: Bytes): String = hash(SHA256.hashToDigest(bytes)) + def hash160(bytes: Bytes): HexString = hash(SHA256.hashDigest(bytes)) - def hash160ToDigest(bytes: Bytes): Bytes = hashToDigest(SHA256.hashToDigest(bytes)) + def hash160Digest(bytes: Bytes): Bytes = hashDigest(SHA256.hashDigest(bytes)) } diff --git a/src/main/scala/com/github/fluency03/blockchain/crypto/SHA256.scala b/src/main/scala/com/github/fluency03/blockchain/crypto/SHA256.scala index fd022eb..353a26d 100644 --- a/src/main/scala/com/github/fluency03/blockchain/crypto/SHA256.scala +++ b/src/main/scala/com/github/fluency03/blockchain/crypto/SHA256.scala @@ -9,27 +9,18 @@ object SHA256 { * Generate SHA256 Hash from a input String. * https://gist.github.com/navicore/6234040bbfce3aa58f866db314c07c15 */ - def hash(text: String) : String = hash(text.getBytes) + def hash(text: String) : HexString = hash(text.getBytes) - /** - * Generate SHA256 Hash from a input Array of Byte. - */ - def hash(bytes: Bytes) : String = String.format("%064x", - new java.math.BigInteger(1, hashToDigest(bytes))) + def hash(bytes: Bytes) : HexString = String.format("%064x", + new java.math.BigInteger(1, hashDigest(bytes))) - /** - * Generate digest from a input Array of Byte. - */ - def hashToDigest(bytes: Bytes): Bytes = + def hashDigest(bytes: Bytes): Bytes = MessageDigest.getInstance("SHA-256").digest(bytes) - /** - * Calculate the hash of concatenation a Seq of Strings. - */ - def hashAll(strings: String*): String = hash(strings mkString "") + def hashAll(strings: String*): HexString = hash(strings mkString "") - def hash256(bytes: Bytes): String = hash(hashToDigest(bytes)) + def hash256(bytes: Bytes): HexString = hash(hashDigest(bytes)) - def hash256ToDigest(bytes: Bytes): Bytes = hashToDigest(hashToDigest(bytes)) + def hash256ToDigest(bytes: Bytes): Bytes = hashDigest(hashDigest(bytes)) } diff --git a/src/main/scala/com/github/fluency03/blockchain/crypto/Secp256k1.scala b/src/main/scala/com/github/fluency03/blockchain/crypto/Secp256k1.scala index 9910b07..9c8a44d 100644 --- a/src/main/scala/com/github/fluency03/blockchain/crypto/Secp256k1.scala +++ b/src/main/scala/com/github/fluency03/blockchain/crypto/Secp256k1.scala @@ -60,9 +60,9 @@ object Secp256k1 { KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate( new ECPrivateKeySpec(new BigInteger(hex, 16), ecSpec)) - def publicKeyToHex(publicKey: PublicKey): String = publicKeyToBytes(publicKey).toHex + def publicKeyToHex(publicKey: PublicKey): HexString = publicKeyToBytes(publicKey).toHex - def privateKeyToHex(privateKey: PrivateKey): String = + def privateKeyToHex(privateKey: PrivateKey): HexString = privateKey.asInstanceOf[ECPrivateKey].getD.toString(16) def publicKeyToBytes(publicKey: PublicKey): Bytes = @@ -71,7 +71,7 @@ object Secp256k1 { def privateKeyToBytes(privateKey: PrivateKey): Bytes = privateKey.asInstanceOf[ECPrivateKey].getD.toByteArray - def publicKeyHexToAddress(publicKey: String, networkBytes: String = "00"): String = + def publicKeyHexToAddress(publicKey: HexString, networkBytes: String = "00"): String = Base58.checkEncode(networkBytes.hex2Bytes ++ publicKey.hex2Bytes.toHash160Digest) /** @@ -87,15 +87,15 @@ object Secp256k1 { * 8 - Adding 7 at the end of 4 * 9 - Base58 encoding of 8 */ - def publicKeyToAddress(publicKey: PublicKey, networkBytes: String = "00"): String = + def publicKeyToAddress(publicKey: PublicKey, networkBytes: String = "00"): Base58 = Base58.checkEncode(networkBytes.hex2Bytes ++ publicKeyToBytes(publicKey).toHash160Digest) - def hash160ToAddress(hash160: String, networkBytes: String = "00"): String = + def hash160ToAddress(hash160: HexString, networkBytes: String = "00"): Base58 = Base58.checkEncode(networkBytes.hex2Bytes ++ hash160.hex2Bytes) - def addressToHash160(address: String, networkBytes: String = "00"): (String, String) = { + def addressToHash160(address: Base58, networkBytes: String = "00"): (HexString, HexString) = { val decoded: Bytes = Base58.decode(address) - val (preBytes, fourBytes) = decoded.splitAt(decoded.length - 4) + val (preBytes, _) = decoded.splitAt(decoded.length - 4) preBytes.toHex.splitAt(2) } diff --git a/src/main/scala/com/github/fluency03/blockchain/Serde.scala b/src/main/scala/com/github/fluency03/blockchain/misc/Serde.scala similarity index 86% rename from src/main/scala/com/github/fluency03/blockchain/Serde.scala rename to src/main/scala/com/github/fluency03/blockchain/misc/Serde.scala index c31fc97..adc783d 100644 --- a/src/main/scala/com/github/fluency03/blockchain/Serde.scala +++ b/src/main/scala/com/github/fluency03/blockchain/misc/Serde.scala @@ -1,7 +1,9 @@ -package com.github.fluency03.blockchain +package com.github.fluency03.blockchain.misc import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream} +import com.github.fluency03.blockchain.Bytes + /** * Ser(ialization) and De(serialization) */ diff --git a/src/main/scala/com/github/fluency03/blockchain/package.scala b/src/main/scala/com/github/fluency03/blockchain/package.scala index 5e40551..2f6890a 100644 --- a/src/main/scala/com/github/fluency03/blockchain/package.scala +++ b/src/main/scala/com/github/fluency03/blockchain/package.scala @@ -4,7 +4,6 @@ import java.nio.charset.Charset import java.security.{PrivateKey, PublicKey} import java.time.Instant -import com.github.fluency03.blockchain.crypto.Secp256k1 import com.github.fluency03.blockchain.core.{Peer, PeerSimple, TxIn, TxOut} import com.github.fluency03.blockchain.crypto.{RIPEMD160, SHA256, Secp256k1} import org.bouncycastle.util.encoders.{Base64, Hex} @@ -17,8 +16,8 @@ package object blockchain { type Bytes = Array[Byte] type UTXO = (TxIn, TxOut) - type Hex = String - type Binary = String + type HexString = String + type BinaryString = String type Base64 = String type Base58 = String @@ -32,12 +31,12 @@ package object blockchain { def getResource(re: String): String = Source.fromResource(re).getLines.mkString - val ZERO64: String = "0000000000000000000000000000000000000000000000000000000000000000" + val ZERO64: HexString = "0000000000000000000000000000000000000000000000000000000000000000" val genesisTime: String = "2018-04-11T18:52:01Z" val genesisTimestamp: Long = Instant.parse(genesisTime).getEpochSecond - val genesisMiner: String = getResource(GENESIS_MINER_PUBLIC_KEY_RESOURCE) + val genesisMiner: HexString = getResource(GENESIS_MINER_PUBLIC_KEY_RESOURCE) val SLOGAN: String = "Welcome to Blockchain in Scala!" @@ -45,33 +44,33 @@ package object blockchain { def hex2Long: Long = java.lang.Long.parseLong(str, 16) def hex2BigInt: BigInt = BigInt(str, 16) def hex2Bytes: Bytes = Hex.decode(str) - def hex2Binary: String = binaryOfHex(str) - def toBase64: String = base64Of(str.getBytes) - def toSha256: String = SHA256.hash(str) - def toRipemd160: String = RIPEMD160.hash(str) + def hex2Binary: BinaryString = binaryOfHex(str) + def toBase64: Base64 = base64Of(str.getBytes) + def toSha256: HexString = SHA256.hash(str) + def toRipemd160: HexString = RIPEMD160.hash(str) } implicit class BytesImplicit(val bytes: Bytes) { - def toHex: String = Hex.toHexString(bytes) + def toHex: HexString = Hex.toHexString(bytes) def toBigInt: BigInt = BigInt(bytes) - def toBase64: String = base64Of(bytes) - def toSha256: String = SHA256.hash(bytes) - def toSha256Digest: Bytes = SHA256.hashToDigest(bytes) - def toRipemd160: String = RIPEMD160.hash(bytes) - def toRipemd160ODigest: Bytes = RIPEMD160.hashToDigest(bytes) - def toHash160: String = RIPEMD160.hash160(bytes) - def toHash160Digest: Bytes = RIPEMD160.hash160ToDigest(bytes) + def toBase64: Base64 = base64Of(bytes) + def toSha256: HexString = SHA256.hash(bytes) + def toSha256Digest: Bytes = SHA256.hashDigest(bytes) + def toRipemd160: HexString = RIPEMD160.hash(bytes) + def toRipemd160ODigest: Bytes = RIPEMD160.hashDigest(bytes) + def toHash160: HexString = RIPEMD160.hash160(bytes) + def toHash160Digest: Bytes = RIPEMD160.hash160Digest(bytes) } implicit class PublicKeyImplicit(val publicKey: PublicKey) { - def toHex: String = Secp256k1.publicKeyToHex(publicKey) + def toHex: HexString = Secp256k1.publicKeyToHex(publicKey) def toBytes: Bytes = Secp256k1.publicKeyToBytes(publicKey) - def toHash160: String = Secp256k1.publicKeyToBytes(publicKey).toHash160 - def address: String = Secp256k1.publicKeyToAddress(publicKey) + def toHash160: HexString = Secp256k1.publicKeyToBytes(publicKey).toHash160 + def address: Base58 = Secp256k1.publicKeyToAddress(publicKey) } implicit class PrivateKeyImplicit(val privateKey: PrivateKey) { - def toHex: String = Secp256k1.privateKeyToHex(privateKey) + def toHex: HexString = Secp256k1.privateKeyToHex(privateKey) def toBytes: Bytes = Secp256k1.privateKeyToBytes(privateKey) } @@ -93,27 +92,27 @@ package object blockchain { /** * Get binary representation of a hash. */ - def binaryOfHex(hash: String): String = BigInt(hash, 16).toString(2) + def binaryOfHex(hex: HexString): BinaryString = BigInt(hex, 16).toString(2) /** * Check whether the given hash is with valid difficulty. */ - def isWithValidDifficulty(hash: String, difficulty: Int): Boolean = + def isWithValidDifficulty(hash: HexString, difficulty: Int): Boolean = hash.startsWith("0" * difficulty) /** * Encode a String to Base64. */ - def base64Of(text: String): String = Base64.toBase64String(text.getBytes) + def base64Of(text: String): Base64 = Base64.toBase64String(text.getBytes) /** * Encode an Array of Bytes String to Base64. */ - def base64Of(data: Bytes): String = Base64.toBase64String(data) + def base64Of(data: Bytes): Base64 = Base64.toBase64String(data) /** * Decode a Base64 to String. */ - def fromBase64(base64: String): String = new String(Base64.decode(base64)) + def fromBase64(base64: Base64): String = new String(Base64.decode(base64)) } diff --git a/src/test/scala/com/github/fluency03/blockchain/crypto/RIPEMD160Test.scala b/src/test/scala/com/github/fluency03/blockchain/crypto/RIPEMD160Test.scala index 0ad9efe..8d9c05a 100644 --- a/src/test/scala/com/github/fluency03/blockchain/crypto/RIPEMD160Test.scala +++ b/src/test/scala/com/github/fluency03/blockchain/crypto/RIPEMD160Test.scala @@ -10,7 +10,7 @@ class RIPEMD160Test extends FlatSpec with Matchers { RIPEMD160.hash("173BDED8F2A2069C193E63EA30DC8FD20E815EC3642B9C24AD7002C03D1BFB9B".hex2Bytes) shouldEqual "88C2D2FA846282C870A76CADECBE45C4ACD72BB6".toLowerCase - RIPEMD160.hash160ToDigest(("04b4d653fcbb4b96000c99343f23b08a44fa306031e0587f9e657ab4a25411" + + RIPEMD160.hash160Digest(("04b4d653fcbb4b96000c99343f23b08a44fa306031e0587f9e657ab4a25411" + "29368d7d9bb05cd8afbdf7705a6540d98028236965553f91bf1c5b4f70073f55b55d").hex2Bytes) shouldEqual "88C2D2FA846282C870A76CADECBE45C4ACD72BB6".hex2Bytes diff --git a/src/test/scala/com/github/fluency03/blockchain/crypto/SHA256Test.scala b/src/test/scala/com/github/fluency03/blockchain/crypto/SHA256Test.scala index a3cc0cd..07791fe 100644 --- a/src/test/scala/com/github/fluency03/blockchain/crypto/SHA256Test.scala +++ b/src/test/scala/com/github/fluency03/blockchain/crypto/SHA256Test.scala @@ -15,7 +15,7 @@ class SHA256Test extends FlatSpec with Matchers { "29368d7d9bb05cd8afbdf7705a6540d98028236965553f91bf1c5b4f70073f55b55d").hex2Bytes) shouldEqual "173BDED8F2A2069C193E63EA30DC8FD20E815EC3642B9C24AD7002C03D1BFB9B".toLowerCase - SHA256.hashToDigest(("04b4d653fcbb4b96000c99343f23b08a44fa306031e0587f9e657ab4a25411" + + SHA256.hashDigest(("04b4d653fcbb4b96000c99343f23b08a44fa306031e0587f9e657ab4a25411" + "29368d7d9bb05cd8afbdf7705a6540d98028236965553f91bf1c5b4f70073f55b55d").hex2Bytes) shouldEqual "173BDED8F2A2069C193E63EA30DC8FD20E815EC3642B9C24AD7002C03D1BFB9B".hex2Bytes @@ -25,7 +25,7 @@ class SHA256Test extends FlatSpec with Matchers { SHA256.hash("1F87490FC565C795595563D56412A0100CD1F29FFB60A3779789FE0C018C6164".hex2Bytes) shouldEqual "55DA1216A5EF5BAE605B543A5A9CE2AC8A8FA1781AA037F35DE3F2222BAD8127".toLowerCase - SHA256.hashToDigest("00".hex2Bytes ++ "88C2D2FA846282C870A76CADECBE45C4ACD72BB6".hex2Bytes) shouldEqual + SHA256.hashDigest("00".hex2Bytes ++ "88C2D2FA846282C870A76CADECBE45C4ACD72BB6".hex2Bytes) shouldEqual "1F87490FC565C795595563D56412A0100CD1F29FFB60A3779789FE0C018C6164".hex2Bytes SHA256.hash(("048FEF639C6FA82AB575532B5B9A4552A6FDEFF141D788CDF3C7AFBA3" + diff --git a/src/test/scala/com/github/fluency03/blockchain/misc/SerdeTest.scala b/src/test/scala/com/github/fluency03/blockchain/misc/SerdeTest.scala new file mode 100644 index 0000000..c9fe997 --- /dev/null +++ b/src/test/scala/com/github/fluency03/blockchain/misc/SerdeTest.scala @@ -0,0 +1,9 @@ +package com.github.fluency03.blockchain.misc + +import org.scalatest.{FlatSpec, Matchers} + +class SerdeTest extends FlatSpec with Matchers with { + + + +}