From 4857d6c321975e8b72802ba3aff581dc7e04b3e3 Mon Sep 17 00:00:00 2001 From: fluency03 Date: Sat, 14 Apr 2018 19:48:37 +0200 Subject: [PATCH] add timestamp to Transaction --- .../com/fluency03/blockchain/api/Server.scala | 6 +-- .../api/actors/BlockRegistryActor.scala | 12 ++--- .../api/actors/BlockchainRegistryActor.scala | 7 +-- .../api/actors/TransactionRegistryActor.scala | 31 +++++++++++ .../blockchain/api/routes/BlockRoutes.scala | 25 ++++----- .../api/routes/BlockchainRoutes.scala | 12 ++--- .../blockchain/api/routes/Routes.scala | 4 +- .../api/routes/TransactionRoutes.scala | 53 +++++++++++++++++++ .../com/fluency03/blockchain/core/Block.scala | 7 ++- .../blockchain/core/Blockchain.scala | 3 ++ .../blockchain/core/Transaction.scala | 14 +++-- .../fluency03/blockchain/core/package.scala | 3 ++ src/test/resources/genesis-block.json | 19 +------ .../blockchain/core/BlockHeaderTest.scala | 14 ++--- .../fluency03/blockchain/core/BlockTest.scala | 34 +++--------- .../blockchain/core/BlockchainTest.scala | 2 +- .../blockchain/core/TransactionTest.scala | 15 ++++-- 17 files changed, 160 insertions(+), 101 deletions(-) create mode 100644 src/main/scala/com/fluency03/blockchain/api/actors/TransactionRegistryActor.scala create mode 100644 src/main/scala/com/fluency03/blockchain/api/routes/TransactionRoutes.scala diff --git a/src/main/scala/com/fluency03/blockchain/api/Server.scala b/src/main/scala/com/fluency03/blockchain/api/Server.scala index ddcf96f..dd060cc 100644 --- a/src/main/scala/com/fluency03/blockchain/api/Server.scala +++ b/src/main/scala/com/fluency03/blockchain/api/Server.scala @@ -7,7 +7,7 @@ import akka.http.scaladsl.Http.ServerBinding import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route import akka.stream.ActorMaterializer -import com.fluency03.blockchain.api.actors.{BlockRegistryActor, BlockchainRegistryActor} +import com.fluency03.blockchain.api.actors.{BlockRegistryActor, BlockchainRegistryActor, TransactionRegistryActor} import com.fluency03.blockchain.api.routes.{BlockRoutes, BlockchainRoutes} import scala.concurrent.{Await, ExecutionContextExecutor, Future} @@ -18,7 +18,7 @@ object Server extends App with BlockchainRoutes with BlockRoutes { implicit val materializer: ActorMaterializer = ActorMaterializer() implicit val executionContext: ExecutionContextExecutor = system.dispatcher - lazy val log = Logging(system, classOf[App]) + override lazy val log = Logging(system, classOf[App]) val (interface, port) = (args(0), args(1).toInt) @@ -34,7 +34,7 @@ object Server extends App with BlockchainRoutes with BlockRoutes { log.error(ex, "Failed to bind to {}:{}!", interface, port) } - println(s"Server online at http://$interface:$port/") + log.info("Server online at http://{}:{}/", interface, port) Await.result(system.whenTerminated, Duration.Inf) } diff --git a/src/main/scala/com/fluency03/blockchain/api/actors/BlockRegistryActor.scala b/src/main/scala/com/fluency03/blockchain/api/actors/BlockRegistryActor.scala index 96f31f7..a78b25c 100644 --- a/src/main/scala/com/fluency03/blockchain/api/actors/BlockRegistryActor.scala +++ b/src/main/scala/com/fluency03/blockchain/api/actors/BlockRegistryActor.scala @@ -1,6 +1,6 @@ package com.fluency03.blockchain.api.actors -import akka.actor.{Actor, ActorLogging, Props} +import akka.actor.{Actor, ActorLogging, ActorRef, Props} import com.fluency03.blockchain.core.Block object BlockRegistryActor { @@ -10,22 +10,22 @@ object BlockRegistryActor { final case class GetBlock(hash: String) final case class DeleteBlock(hash: String) - def props: Props = Props[BlockRegistryActor] + def props: Props = Props[TransactionRegistryActor] } class BlockRegistryActor extends Actor with ActorLogging { import BlockRegistryActor._ + val blockchainActor: ActorRef = context.actorOf(BlockchainRegistryActor.props) + var blocks = Set.empty[Block] def receive: Receive = { - case GetBlocks => - sender() ! blocks.toList + case GetBlocks => sender() ! blocks.toList case CreateBlock(block) => blocks += block sender() ! ActionPerformed(s"Block ${block.hash} created.") - case GetBlock(hash) => - sender() ! blocks.find(_.hash == hash) + case GetBlock(hash) => sender() ! blocks.find(_.hash == hash) case DeleteBlock(hash) => blocks.find(_.hash == hash) foreach { block => blocks -= block } sender() ! ActionPerformed(s"Block $hash deleted.") diff --git a/src/main/scala/com/fluency03/blockchain/api/actors/BlockchainRegistryActor.scala b/src/main/scala/com/fluency03/blockchain/api/actors/BlockchainRegistryActor.scala index 228475c..ef114c1 100644 --- a/src/main/scala/com/fluency03/blockchain/api/actors/BlockchainRegistryActor.scala +++ b/src/main/scala/com/fluency03/blockchain/api/actors/BlockchainRegistryActor.scala @@ -1,6 +1,6 @@ package com.fluency03.blockchain.api.actors -import akka.actor.{Actor, ActorLogging, Props} +import akka.actor.{Actor, ActorLogging, ActorRef, Props} import com.fluency03.blockchain.core.Blockchain object BlockchainRegistryActor { @@ -15,11 +15,12 @@ object BlockchainRegistryActor { class BlockchainRegistryActor extends Actor with ActorLogging { import BlockchainRegistryActor._ + val blockActor: ActorRef = context.actorOf(BlockRegistryActor.props) + var blockchainOpt: Option[Blockchain] = None def receive: Receive = { - case GetBlockchain => - sender() ! blockchainOpt.get + case GetBlockchain => sender() ! blockchainOpt.get case CreateBlockchain => blockchainOpt = Some(Blockchain()) sender() ! ActionPerformed(s"Blockchain created, with difficulty ${blockchainOpt.get.difficulty}.") diff --git a/src/main/scala/com/fluency03/blockchain/api/actors/TransactionRegistryActor.scala b/src/main/scala/com/fluency03/blockchain/api/actors/TransactionRegistryActor.scala new file mode 100644 index 0000000..b3643c3 --- /dev/null +++ b/src/main/scala/com/fluency03/blockchain/api/actors/TransactionRegistryActor.scala @@ -0,0 +1,31 @@ +package com.fluency03.blockchain.api.actors + +import akka.actor.{Actor, ActorLogging, ActorRef, Props} +import com.fluency03.blockchain.core.{Block, Transaction} + +object TransactionRegistryActor { + final case class ActionPerformed(description: String) + final case object GetTransactions + final case class CreateTransaction(tx: Transaction) + final case class GetTransaction(hash: String) + final case class DeleteTransaction(hash: String) + + def props: Props = Props[TransactionRegistryActor] +} + +class TransactionRegistryActor extends Actor with ActorLogging { + import TransactionRegistryActor._ + + var transactions = Set.empty[Transaction] + + def receive: Receive = { + case GetTransactions => sender() ! transactions.toList + case CreateTransaction(tx) => + transactions += tx + sender() ! ActionPerformed(s"Transaction ${tx.hash} created.") + case GetTransaction(hash) => sender() ! transactions.find(_.hash == hash) + case DeleteTransaction(hash) => + transactions.find(_.hash == hash) foreach { tx => transactions -= tx } + sender() ! ActionPerformed(s"Transaction $hash deleted.") + } +} diff --git a/src/main/scala/com/fluency03/blockchain/api/routes/BlockRoutes.scala b/src/main/scala/com/fluency03/blockchain/api/routes/BlockRoutes.scala index 42d199c..6c2c42c 100644 --- a/src/main/scala/com/fluency03/blockchain/api/routes/BlockRoutes.scala +++ b/src/main/scala/com/fluency03/blockchain/api/routes/BlockRoutes.scala @@ -9,14 +9,13 @@ 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.pattern.ask -import com.fluency03.blockchain.api.JsonSupport import com.fluency03.blockchain.api.actors.BlockRegistryActor._ import com.fluency03.blockchain.core.Block import scala.concurrent.Future -trait BlockRoutes extends JsonSupport with Routes { - lazy val logBlockRoutes = Logging(system, classOf[BlockRoutes]) +trait BlockRoutes extends Routes { + lazy val log = Logging(system, classOf[BlockRoutes]) def blockRegistryActor: ActorRef @@ -24,16 +23,14 @@ trait BlockRoutes extends JsonSupport with Routes { pathPrefix("blocks") { pathEnd { get { - val blocks: Future[List[Block]] = - (blockRegistryActor ? GetBlocks).mapTo[List[Block]] + val blocks: Future[List[Block]] = (blockRegistryActor ? GetBlocks).mapTo[List[Block]] complete(blocks) } ~ post { entity(as[Block]) { block => - val blockCreated: Future[ActionPerformed] = - (blockRegistryActor ? CreateBlock(block)).mapTo[ActionPerformed] + val blockCreated: Future[ActionPerformed] = (blockRegistryActor ? CreateBlock(block)).mapTo[ActionPerformed] onSuccess(blockCreated) { performed => - logBlockRoutes.info("Created user [{}]: {}", block.hash, performed.description) + log.info("Created user [{}]: {}", block.hash, performed.description) complete((StatusCodes.Created, performed)) } } @@ -41,17 +38,13 @@ trait BlockRoutes extends JsonSupport with Routes { } ~ path(Segment) { hash => get { - val maybeBlock: Future[Option[Block]] = - (blockRegistryActor ? GetBlock(hash)).mapTo[Option[Block]] - rejectEmptyResponse { - complete(maybeBlock) - } + val maybeBlock: Future[Option[Block]] = (blockRegistryActor ? GetBlock(hash)).mapTo[Option[Block]] + rejectEmptyResponse { complete(maybeBlock) } } ~ delete { - val blockDeleted: Future[ActionPerformed] = - (blockRegistryActor ? DeleteBlock(hash)).mapTo[ActionPerformed] + val blockDeleted: Future[ActionPerformed] = (blockRegistryActor ? DeleteBlock(hash)).mapTo[ActionPerformed] onSuccess(blockDeleted) { performed => - logBlockRoutes.info("Deleted block [{}]: {}", hash, performed.description) + log.info("Deleted block [{}]: {}", hash, performed.description) complete((StatusCodes.OK, performed)) } } 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 2cbc697..cc120da 100644 --- a/src/main/scala/com/fluency03/blockchain/api/routes/BlockchainRoutes.scala +++ b/src/main/scala/com/fluency03/blockchain/api/routes/BlockchainRoutes.scala @@ -8,15 +8,14 @@ import akka.http.scaladsl.server.Route import akka.http.scaladsl.server.directives.MethodDirectives.{delete, get, post} import akka.http.scaladsl.server.directives.RouteDirectives.complete import akka.pattern.ask -import com.fluency03.blockchain.api.JsonSupport import com.fluency03.blockchain.api.actors.BlockchainRegistryActor._ import com.fluency03.blockchain.core.Blockchain import org.json4s.JsonAST.JValue import scala.concurrent.Future -trait BlockchainRoutes extends JsonSupport with Routes { - lazy val logBlockchainRoutes = Logging(system, classOf[BlockchainRoutes]) +trait BlockchainRoutes extends Routes { + lazy val log = Logging(system, classOf[BlockchainRoutes]) def blockchainRegistryActor: ActorRef @@ -24,8 +23,7 @@ trait BlockchainRoutes extends JsonSupport with Routes { pathPrefix("blockchain") { pathEnd { get { - val users: Future[Blockchain] = - (blockchainRegistryActor ? GetBlockchain).mapTo[Blockchain] + val users: Future[Blockchain] = (blockchainRegistryActor ? GetBlockchain).mapTo[Blockchain] complete(users) } ~ post { @@ -33,7 +31,7 @@ trait BlockchainRoutes extends JsonSupport with Routes { val blockchainCreated: Future[ActionPerformed] = (blockchainRegistryActor ? CreateBlockchain).mapTo[ActionPerformed] onSuccess(blockchainCreated) { performed => - logBlockchainRoutes.info("Created Blockchain: {}", performed.description) + log.info("Created Blockchain: {}", performed.description) complete((StatusCodes.Created, performed)) } } @@ -42,7 +40,7 @@ trait BlockchainRoutes extends JsonSupport with Routes { val blockchainDeleted: Future[ActionPerformed] = (blockchainRegistryActor ? DeleteBlockchain).mapTo[ActionPerformed] onSuccess(blockchainDeleted) { performed => - logBlockchainRoutes.info("Deleted Blockchain: {}", performed.description) + log.info("Deleted Blockchain: {}", performed.description) complete((StatusCodes.OK, performed)) } } diff --git a/src/main/scala/com/fluency03/blockchain/api/routes/Routes.scala b/src/main/scala/com/fluency03/blockchain/api/routes/Routes.scala index 74c296c..ec29adc 100644 --- a/src/main/scala/com/fluency03/blockchain/api/routes/Routes.scala +++ b/src/main/scala/com/fluency03/blockchain/api/routes/Routes.scala @@ -3,15 +3,15 @@ package com.fluency03.blockchain.api.routes import akka.actor.ActorSystem import akka.event.Logging import akka.util.Timeout +import com.fluency03.blockchain.api.JsonSupport import scala.concurrent.duration._ -trait Routes { +trait Routes extends JsonSupport { // we leave these abstract, since they will be provided by the App implicit def system: ActorSystem // Required by the `ask` (?) method below implicit lazy val timeout: Timeout = Timeout(5.seconds) // usually we'd obtain the timeout from the system's configuration - } diff --git a/src/main/scala/com/fluency03/blockchain/api/routes/TransactionRoutes.scala b/src/main/scala/com/fluency03/blockchain/api/routes/TransactionRoutes.scala new file mode 100644 index 0000000..727f180 --- /dev/null +++ b/src/main/scala/com/fluency03/blockchain/api/routes/TransactionRoutes.scala @@ -0,0 +1,53 @@ +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.pattern.ask +import com.fluency03.blockchain.api.actors.BlockRegistryActor._ +import com.fluency03.blockchain.core.Block + +import scala.concurrent.Future + +trait TransactionRoutes extends Routes { + lazy val log = Logging(system, classOf[TransactionRoutes]) + + def txRoutesRegistryActor: ActorRef + +// lazy val transactionRoutes: Route = +// pathPrefix("transactions") { +// pathEnd { +// get { +// val blocks: Future[List[Block]] = (txRoutesRegistryActor ? GetBlocks).mapTo[List[Block]] +// complete(blocks) +// } ~ +// post { +// entity(as[Block]) { block => +// val blockCreated: Future[ActionPerformed] = (txRoutesRegistryActor ? CreateBlock(block)).mapTo[ActionPerformed] +// onSuccess(blockCreated) { performed => +// log.info("Created user [{}]: {}", block.hash, performed.description) +// complete((StatusCodes.Created, performed)) +// } +// } +// } +// } ~ +// path(Segment) { hash => +// get { +// val maybeBlock: Future[Option[Block]] = (txRoutesRegistryActor ? GetBlock(hash)).mapTo[Option[Block]] +// rejectEmptyResponse { complete(maybeBlock) } +// } ~ +// delete { +// val blockDeleted: Future[ActionPerformed] = (txRoutesRegistryActor ? DeleteBlock(hash)).mapTo[ActionPerformed] +// onSuccess(blockDeleted) { performed => +// log.info("Deleted block [{}]: {}", hash, performed.description) +// complete((StatusCodes.OK, performed)) +// } +// } +// } +// } +} diff --git a/src/main/scala/com/fluency03/blockchain/core/Block.scala b/src/main/scala/com/fluency03/blockchain/core/Block.scala index 824df80..7ca5f60 100644 --- a/src/main/scala/com/fluency03/blockchain/core/Block.scala +++ b/src/main/scala/com/fluency03/blockchain/core/Block.scala @@ -30,6 +30,9 @@ case class Block(header: BlockHeader, transactions: List[Transaction] = List()) def addTransaction(sender: String, receiver: String, amount: Double): Block = addTransaction(Transaction(sender, receiver, amount)) + def addTransaction(sender: String, receiver: String, amount: Double, timestamp: Long): Block = + addTransaction(Transaction(sender, receiver, amount, timestamp)) + def addTransactions(trans: List[Transaction]): Block = Block(index, previousHash, data, trans ++ transactions, timestamp, nonce) @@ -65,8 +68,8 @@ object Block { 0, ZERO64, "Welcome to Blockchain in Scala!", - List(Transaction(ZERO64, ZERO64, 50)), - Instant.parse("2018-04-11T18:52:01Z").getEpochSecond, + List(Transaction(ZERO64, ZERO64, 50, genesisTimestamp)), + genesisTimestamp, difficulty) def mineNextBlock( diff --git a/src/main/scala/com/fluency03/blockchain/core/Blockchain.scala b/src/main/scala/com/fluency03/blockchain/core/Blockchain.scala index da93e25..b19ae9d 100644 --- a/src/main/scala/com/fluency03/blockchain/core/Blockchain.scala +++ b/src/main/scala/com/fluency03/blockchain/core/Blockchain.scala @@ -28,6 +28,9 @@ case class Blockchain(difficulty: Int = 4, chain: List[Block] = List(Block.genes def addTransaction(sender: String, receiver: String, amount: Double): Blockchain = addTransaction(Transaction(sender, receiver, amount)) + def addTransaction(sender: String, receiver: String, amount: Double, timestamp: Long): Blockchain = + addTransaction(Transaction(sender, receiver, amount, timestamp)) + def addTransactions(trans: List[Transaction]): Blockchain = { currentTransactions ++= trans this diff --git a/src/main/scala/com/fluency03/blockchain/core/Transaction.scala b/src/main/scala/com/fluency03/blockchain/core/Transaction.scala index 48459e6..204d066 100644 --- a/src/main/scala/com/fluency03/blockchain/core/Transaction.scala +++ b/src/main/scala/com/fluency03/blockchain/core/Transaction.scala @@ -1,6 +1,6 @@ package com.fluency03.blockchain.core -import com.fluency03.blockchain.Util.hashOf +import com.fluency03.blockchain.Util.{hashOf, getCurrentTimestamp} import com.fluency03.blockchain.core.Transaction.hashOfTransaction import org.json4s.native.JsonMethods.{compact, render} import org.json4s.{Extraction, JValue} @@ -10,8 +10,9 @@ import org.json4s.{Extraction, JValue} * @param sender Sender of the current Transaction * @param receiver Receiver of the current Transaction * @param amount Amount of the current Transaction + * @param timestamp Unix epoch time of the current Transaction */ -case class Transaction(sender: String, receiver: String, amount: Double) { +case class Transaction(sender: String, receiver: String, amount: Double, timestamp: Long) { lazy val hash: String = hashOfTransaction(this) def toJson: JValue = Extraction.decompose(this) @@ -21,10 +22,13 @@ case class Transaction(sender: String, receiver: String, amount: Double) { object Transaction { + def apply(sender: String, receiver: String, amount: Double): Transaction = + Transaction(sender, receiver, amount, getCurrentTimestamp) + def hashOfTransaction(tx: Transaction): String = - hashOfTransactionFields(tx.sender, tx.receiver, tx.amount) + hashOfTransactionFields(tx.sender, tx.receiver, tx.amount, tx.timestamp) - def hashOfTransactionFields(sender: String, receiver: String, amount: Double): String = - hashOf(sender, receiver, amount.toString) + def hashOfTransactionFields(sender: String, receiver: String, amount: Double, timestamp: Long): String = + hashOf(sender, receiver, amount.toString, timestamp.toString) } diff --git a/src/main/scala/com/fluency03/blockchain/core/package.scala b/src/main/scala/com/fluency03/blockchain/core/package.scala index e7c5a40..8d3c443 100644 --- a/src/main/scala/com/fluency03/blockchain/core/package.scala +++ b/src/main/scala/com/fluency03/blockchain/core/package.scala @@ -1,5 +1,7 @@ package com.fluency03.blockchain +import java.time.Instant + import org.json4s.NoTypeHints import org.json4s.native.Serialization @@ -7,5 +9,6 @@ package object core { implicit val formats = Serialization.formats(NoTypeHints) lazy val ZERO64: String = "0000000000000000000000000000000000000000000000000000000000000000" + lazy val genesisTimestamp: Long = Instant.parse("2018-04-11T18:52:01Z").getEpochSecond } diff --git a/src/test/resources/genesis-block.json b/src/test/resources/genesis-block.json index 3682150..d7c8c83 100644 --- a/src/test/resources/genesis-block.json +++ b/src/test/resources/genesis-block.json @@ -1,18 +1 @@ -{ - "header": { - "index": 0, - "previousHash": "0000000000000000000000000000000000000000000000000000000000000000", - "data": "Welcome to Blockchain in Scala!", - "merkleHash": "7814a9c43e9015462e5ffec1a3a9a69be024c1aacfa3ec4c879b5cd544761e7e", - "timestamp": 1523472721, - "nonce": 13860, - "hash": "00003607219f7a455e216f19ac3a34e3b158cf7282f7fdc624c93d593c2fc61f" - }, - "transactions": [ - { - "sender": "0000000000000000000000000000000000000000000000000000000000000000", - "receiver": "0000000000000000000000000000000000000000000000000000000000000000", - "amount": 50.0 - } - ] -} \ No newline at end of file +{"header":{"index":0,"previousHash":"0000000000000000000000000000000000000000000000000000000000000000","data":"Welcome to Blockchain in Scala!","merkleHash":"21d1db6630265eb9e991b410d82870a8d3f62cb11d1d0917e926a49bdb3993b5","timestamp":1523472721,"nonce":33660,"hash":"0000a26af9a70022a6c6d270a0ced7478eb40bcfc4301b5e73c0ed3207a3de0e"},"transactions":[{"sender":"0000000000000000000000000000000000000000000000000000000000000000","receiver":"0000000000000000000000000000000000000000000000000000000000000000","amount":50.0,"timestamp":1523472721}]} diff --git a/src/test/scala/com/fluency03/blockchain/core/BlockHeaderTest.scala b/src/test/scala/com/fluency03/blockchain/core/BlockHeaderTest.scala index 3d24c4d..e9f4d81 100644 --- a/src/test/scala/com/fluency03/blockchain/core/BlockHeaderTest.scala +++ b/src/test/scala/com/fluency03/blockchain/core/BlockHeaderTest.scala @@ -8,24 +8,24 @@ import org.scalatest.{FlatSpec, Matchers} class BlockHeaderTest extends FlatSpec with Matchers { val genesisHeader: BlockHeader = Block.genesisBlock.header - val genesisTx: Transaction = Transaction(ZERO64, ZERO64, 50) + val genesisTx: Transaction = Transaction(ZERO64, ZERO64, 50, genesisTimestamp) "Genesis block header" should "be valid." in { genesisHeader.index shouldEqual 0 genesisHeader.previousHash shouldEqual ZERO64 genesisHeader.data shouldEqual "Welcome to Blockchain in Scala!" genesisHeader.merkleHash shouldEqual genesisTx.hash - genesisHeader.timestamp shouldEqual 1523472721 - genesisHeader.nonce shouldEqual 13860 - genesisHeader.hash shouldEqual "00003607219f7a455e216f19ac3a34e3b158cf7282f7fdc624c93d593c2fc61f" + genesisHeader.timestamp shouldEqual genesisTimestamp + genesisHeader.nonce shouldEqual 33660 + genesisHeader.hash shouldEqual "0000a26af9a70022a6c6d270a0ced7478eb40bcfc4301b5e73c0ed3207a3de0e" genesisHeader.isValidWith(4) shouldEqual true val json = ("index" -> 0) ~ ("previousHash" -> ZERO64) ~ ("data" -> "Welcome to Blockchain in Scala!") ~ ("merkleHash" -> genesisTx.hash) ~ - ("timestamp" -> 1523472721) ~ - ("nonce" -> 13860) ~ - ("hash" -> "00003607219f7a455e216f19ac3a34e3b158cf7282f7fdc624c93d593c2fc61f") + ("timestamp" -> genesisTimestamp) ~ + ("nonce" -> 33660) ~ + ("hash" -> "0000a26af9a70022a6c6d270a0ced7478eb40bcfc4301b5e73c0ed3207a3de0e") genesisHeader.toJson shouldEqual json parse(genesisHeader.toString) shouldEqual json } diff --git a/src/test/scala/com/fluency03/blockchain/core/BlockTest.scala b/src/test/scala/com/fluency03/blockchain/core/BlockTest.scala index b2faf8a..cdccb3e 100644 --- a/src/test/scala/com/fluency03/blockchain/core/BlockTest.scala +++ b/src/test/scala/com/fluency03/blockchain/core/BlockTest.scala @@ -7,37 +7,17 @@ import org.scalatest.{FlatSpec, Matchers} class BlockTest extends FlatSpec with Matchers { - /* - {"header": - { - "index":0, - "previousHash":"0000000000000000000000000000000000000000000000000000000000000000", - "data":"Welcome to Blockchain in Scala!", - "merkleHash":"7814a9c43e9015462e5ffec1a3a9a69be024c1aacfa3ec4c879b5cd544761e7e", - "timestamp":1523472721, - "nonce":13860, - "hash":"00003607219f7a455e216f19ac3a34e3b158cf7282f7fdc624c93d593c2fc61f" - }, - "transactions":[ - { - "sender":"0000000000000000000000000000000000000000000000000000000000000000", - "receiver":"0000000000000000000000000000000000000000000000000000000000000000", - "amount":50.0 - } - ] - } - */ val genesis: Block = Block.genesisBlock - val genesisTx: Transaction = Transaction(ZERO64, ZERO64, 50) + val genesisTx: Transaction = Transaction(ZERO64, ZERO64, 50, genesisTimestamp) "Genesis block" should "be a valid Genesis block." in { genesis.index shouldEqual 0 genesis.previousHash shouldEqual ZERO64 genesis.data shouldEqual "Welcome to Blockchain in Scala!" genesis.merkleHash shouldEqual genesisTx.hash - genesis.timestamp shouldEqual 1523472721 - genesis.nonce shouldEqual 13860 - genesis.hash shouldEqual "00003607219f7a455e216f19ac3a34e3b158cf7282f7fdc624c93d593c2fc61f" + genesis.timestamp shouldEqual genesisTimestamp + genesis.nonce shouldEqual 33660 + genesis.hash shouldEqual "0000a26af9a70022a6c6d270a0ced7478eb40bcfc4301b5e73c0ed3207a3de0e" genesis.hasValidMerkleHash shouldEqual true genesis.hasValidHash(4) shouldEqual true genesis.isValid(4) shouldEqual true @@ -47,9 +27,9 @@ class BlockTest extends FlatSpec with Matchers { ("previousHash" -> ZERO64) ~ ("data" -> "Welcome to Blockchain in Scala!") ~ ("merkleHash" -> genesisTx.hash) ~ - ("timestamp" -> 1523472721) ~ - ("nonce" -> 13860) ~ - ("hash" -> "00003607219f7a455e216f19ac3a34e3b158cf7282f7fdc624c93d593c2fc61f")) ~ + ("timestamp" -> genesisTimestamp) ~ + ("nonce" -> 33660) ~ + ("hash" -> "0000a26af9a70022a6c6d270a0ced7478eb40bcfc4301b5e73c0ed3207a3de0e")) ~ ("transactions" -> List(genesisTx).map(_.toJson)) genesis.toJson shouldEqual json parse(genesis.toString) shouldEqual json diff --git a/src/test/scala/com/fluency03/blockchain/core/BlockchainTest.scala b/src/test/scala/com/fluency03/blockchain/core/BlockchainTest.scala index 30cff86..cc892d9 100644 --- a/src/test/scala/com/fluency03/blockchain/core/BlockchainTest.scala +++ b/src/test/scala/com/fluency03/blockchain/core/BlockchainTest.scala @@ -39,7 +39,7 @@ class BlockchainTest extends FlatSpec with Matchers { trans += t1 blockchain.currentTransactions shouldEqual trans - blockchain.addTransaction(ZERO64, ZERO64, 20) + blockchain.addTransaction(t2) blockchain.addTransaction(t3) trans ++= t2 :: t3 :: Nil blockchain.currentTransactions shouldEqual trans diff --git a/src/test/scala/com/fluency03/blockchain/core/TransactionTest.scala b/src/test/scala/com/fluency03/blockchain/core/TransactionTest.scala index 94dc07d..c1c219a 100644 --- a/src/test/scala/com/fluency03/blockchain/core/TransactionTest.scala +++ b/src/test/scala/com/fluency03/blockchain/core/TransactionTest.scala @@ -1,22 +1,29 @@ package com.fluency03.blockchain.core +import java.time.Instant + import com.fluency03.blockchain.Util.hashOf import org.json4s.JsonDSL._ +import org.json4s.native.JsonMethods.parse import org.scalatest.{FlatSpec, Matchers} class TransactionTest extends FlatSpec with Matchers { "A Transaction" should "be valid." in { - val t = Transaction(ZERO64, ZERO64, 50) + val time = Instant.parse("2018-04-11T18:52:01Z").getEpochSecond + val t = Transaction(ZERO64, ZERO64, 50, time) t.sender shouldEqual ZERO64 t.receiver shouldEqual ZERO64 t.amount shouldEqual 50 - t.hash shouldEqual hashOf(t.sender, t.receiver, t.amount.toString) + t.hash shouldEqual hashOf(t.sender, t.receiver, t.amount.toString, time.toString) - val json = ("sender" -> ZERO64) ~ ("receiver" -> ZERO64) ~ ("amount" -> 50.toDouble) + val json = ("sender" -> ZERO64) ~ + ("receiver" -> ZERO64) ~ + ("amount" -> 50.toDouble) ~ + ("timestamp" -> time) t.toJson shouldEqual json - t.toString shouldEqual "{\"sender\":\"" + ZERO64 + "\",\"receiver\":\"" + ZERO64 + "\",\"amount\":50.0}" + parse(t.toString) shouldEqual json } }