diff --git a/src/main/scala/com/fluency03/blockchain/core/Block.scala b/src/main/scala/com/fluency03/blockchain/core/Block.scala index 0b612f2..a3e3ed9 100644 --- a/src/main/scala/com/fluency03/blockchain/core/Block.scala +++ b/src/main/scala/com/fluency03/blockchain/core/Block.scala @@ -21,8 +21,6 @@ case class Block(header: BlockHeader, transactions: Seq[Transaction], hash: Stri lazy val difficulty: Int = header.difficulty lazy val nonce: Int = header.nonce -// lazy val hash: String = header.hash - def nextTrial(): Block = Block(header.nextTrial(), transactions) def addTransaction(tx: Transaction): Block = @@ -34,10 +32,12 @@ case class Block(header: BlockHeader, transactions: Seq[Transaction], hash: Stri def removeTransaction(tx: Transaction): Block = Block(index, previousHash, data, timestamp, difficulty, nonce, transactions.filter(_ != tx)) - def isValid: Boolean = isWithValidDifficulty(hash, difficulty) && hasValidMerkleHash + def hasValidHash: Boolean = hasValidHeaderHash && isWithValidDifficulty(hash, difficulty) && hasValidMerkleHash def hasValidMerkleHash: Boolean = merkleHash == Merkle.computeRoot(transactions) + def hasValidHeaderHash: Boolean = hash == header.hash + def toJson: JValue = Extraction.decompose(this) override def toString: String = compact(render(toJson)) diff --git a/src/main/scala/com/fluency03/blockchain/core/Blockchain.scala b/src/main/scala/com/fluency03/blockchain/core/Blockchain.scala index 5f5cb3c..d365c34 100644 --- a/src/main/scala/com/fluency03/blockchain/core/Blockchain.scala +++ b/src/main/scala/com/fluency03/blockchain/core/Blockchain.scala @@ -47,8 +47,8 @@ object Blockchain { def isValidChain(chain: Seq[Block]): Boolean = chain match { case Nil => true - case g +: Nil => g.previousHash == ZERO64 && g.index == 0 && g.isValid - case a +: b +: tail => canBeChained(a, b) && a.isValid && isValidChain(b +: tail) + case g +: Nil => g.previousHash == ZERO64 && g.index == 0 && g.hasValidHash + case a +: b +: tail => canBeChained(a, b) && a.hasValidHash && isValidChain(b +: tail) } diff --git a/src/main/scala/com/fluency03/blockchain/core/Transaction.scala b/src/main/scala/com/fluency03/blockchain/core/Transaction.scala index 1662d38..cd0e1d2 100644 --- a/src/main/scala/com/fluency03/blockchain/core/Transaction.scala +++ b/src/main/scala/com/fluency03/blockchain/core/Transaction.scala @@ -18,7 +18,6 @@ case class TxIn(previousOut: Outpoint, signature: String) case class TxOut(address: String, amount: Long) case class Transaction(txIns: Seq[TxIn], txOuts: Seq[TxOut], timestamp: Long, id: String) { -// lazy val id: String = hashOfTransaction(this) def addTxIn(in: TxIn): Transaction = Transaction(in +: txIns, txOuts, timestamp) @@ -32,6 +31,8 @@ case class Transaction(txIns: Seq[TxIn], txOuts: Seq[TxOut], timestamp: Long, id def removeTxOut(txOut: TxOut): Transaction = Transaction(txIns, txOuts.filter(_ != txOut), timestamp) + def hasValidId: Boolean = id == hashOfTransaction(this) + def toJson: JValue = Extraction.decompose(this) override def toString: String = compact(render(toJson)) diff --git a/src/test/scala/com/fluency03/blockchain/core/BlockTest.scala b/src/test/scala/com/fluency03/blockchain/core/BlockTest.scala index cd6857a..b4f6384 100644 --- a/src/test/scala/com/fluency03/blockchain/core/BlockTest.scala +++ b/src/test/scala/com/fluency03/blockchain/core/BlockTest.scala @@ -30,7 +30,7 @@ class BlockTest extends FlatSpec with Matchers { genesis.timestamp shouldEqual expectedHeader.timestamp genesis.nonce shouldEqual expectedHeader.nonce genesis.hash shouldEqual expectedHeader.hash - genesis.isValid shouldEqual true + genesis.hasValidHash shouldEqual true genesis.toJson shouldEqual expectedBlockJson parse(genesis.toString) shouldEqual expectedBlockJson @@ -68,7 +68,7 @@ class BlockTest extends FlatSpec with Matchers { genesisNextTrial.hash shouldEqual newHash genesisNextTrial.hash shouldEqual newExpectedHeader.hash genesisNextTrial.hasValidMerkleHash shouldEqual true - genesisNextTrial.isValid shouldEqual false + genesisNextTrial.hasValidHash shouldEqual false val headerJson = expectedHeader.toJson.transformField { case ("nonce", JInt(x)) => ("nonce", JInt(x+1)) } @@ -95,7 +95,7 @@ class BlockTest extends FlatSpec with Matchers { val newHash = hashOfBlockHeader(newBlock.header) newBlock.hash shouldEqual newHash newBlock.hasValidMerkleHash shouldEqual true - newBlock.isValid shouldEqual false + newBlock.hasValidHash shouldEqual false val headerJson = expectedHeader.toJson.transformField { case ("merkleHash", JString(_)) => ("merkleHash", newMerkleHash) } @@ -127,7 +127,7 @@ class BlockTest extends FlatSpec with Matchers { val newHash = hashOfBlockHeader(newBlock.header) newBlock.hash shouldEqual newHash newBlock.hasValidMerkleHash shouldEqual true - newBlock.isValid shouldEqual false + newBlock.hasValidHash shouldEqual false val headerJson = expectedHeader.toJson.transformField { case ("merkleHash", JString(_)) => ("merkleHash", newMerkleHash) } diff --git a/src/test/scala/com/fluency03/blockchain/core/BlockchainTest.scala b/src/test/scala/com/fluency03/blockchain/core/BlockchainTest.scala index 5990065..21b0ddb 100644 --- a/src/test/scala/com/fluency03/blockchain/core/BlockchainTest.scala +++ b/src/test/scala/com/fluency03/blockchain/core/BlockchainTest.scala @@ -2,8 +2,10 @@ package com.fluency03.blockchain package core import com.fluency03.blockchain.core.Transaction.createCoinbaseTx +import org.json4s.JsonDSL._ import org.json4s.JValue -import org.json4s.native.JsonMethods.parse +import org.json4s.JsonAST.JArray +import org.json4s.native.JsonMethods.{compact, parse, render} import org.scalatest.{FlatSpec, Matchers} import scala.io.Source @@ -31,6 +33,11 @@ class BlockchainTest extends FlatSpec with Matchers { blockchain.lastBlock().isEmpty shouldEqual false blockchain.lastBlock().get shouldEqual expectedGenesisBlock blockchain.isValid shouldEqual true + val json = ("difficulty" -> blockchain.difficulty) ~ ("chain" -> JArray(List(expectedBlockJson))) + blockchain.toJson shouldEqual json + parse(blockchain.toString) shouldEqual json + + a[NoSuchElementException] should be thrownBy Blockchain(4, Seq.empty[Block]).isValid } "A new Blockchain with different difficulty" should "have all default values but the difficulty." in {