package com.xsn.explorer.data import com.xsn.explorer.data.anorm.BlockPostgresDataHandler import com.xsn.explorer.data.anorm.dao.BlockPostgresDAO import com.xsn.explorer.data.common.PostgresDataHandlerSpec import com.xsn.explorer.errors.{BlockNotFoundError, RepeatedBlockHeightError, RepeatedBlockhashError} import com.xsn.explorer.helpers.BlockLoader import com.xsn.explorer.models.Blockhash import com.xsn.explorer.models.rpc.Block import org.scalactic.Bad import org.scalatest.BeforeAndAfter class BlockPostgresDataHandlerSpec extends PostgresDataHandlerSpec with BeforeAndAfter { before { clearDatabase() } lazy val dataHandler = new BlockPostgresDataHandler(database, new BlockPostgresDAO) "insert" should { "add a new block" in { // PoS block val block = BlockLoader.get("1ca318b7a26ed67ca7c8c9b5069d653ba224bf86989125d1dfbb0973b7d6a5e0") .copy(previousBlockhash = None) val result = dataHandler.insert(block) result.isGood mustEqual true matches(block, result.get) } "fail on existing blockhash" in { val block = BlockLoader.get("1ca318b7a26ed67ca7c8c9b5069d653ba224bf86989125d1dfbb0973b7d6a5e0") .copy(previousBlockhash = None) dataHandler.insert(block).isGood mustEqual true val newBlock = BlockLoader.get("25762bf01143f7fe34912c926e0b95528b082c6323de35516de0fc321f5d8058") .copy(hash = block.hash) val result = dataHandler.insert(newBlock) result mustEqual Bad(RepeatedBlockhashError).accumulating } "fail on existing height" in { val block = BlockLoader.get("1ca318b7a26ed67ca7c8c9b5069d653ba224bf86989125d1dfbb0973b7d6a5e0") .copy(previousBlockhash = None) dataHandler.insert(block).isGood mustEqual true val newBlock = BlockLoader.get("25762bf01143f7fe34912c926e0b95528b082c6323de35516de0fc321f5d8058") .copy(height = block.height) val result = dataHandler.insert(newBlock) result mustEqual Bad(RepeatedBlockHeightError).accumulating } } "getBy blockhash" should { "return a block" in { val block = BlockLoader.get("1ca318b7a26ed67ca7c8c9b5069d653ba224bf86989125d1dfbb0973b7d6a5e0") .copy(previousBlockhash = None) dataHandler.insert(block) val result = dataHandler.getBy(block.hash) result.isGood mustEqual true matches(block, result.get) } "fail on block not found" in { val blockhash = Blockhash.from("b858d38a3552c83aea58f66fe00ae220352a235e33fcf1f3af04507a61a9dc32").get val result = dataHandler.getBy(blockhash) result mustEqual Bad(BlockNotFoundError).accumulating } } "getBy height" should { "return a block" in { val block = BlockLoader.get("1ca318b7a26ed67ca7c8c9b5069d653ba224bf86989125d1dfbb0973b7d6a5e0") .copy(previousBlockhash = None) dataHandler.insert(block).isGood mustEqual true val result = dataHandler.getBy(block.height) result.isGood mustEqual true matches(block, result.get) } "fail on block not found" in { val block = BlockLoader.get("1ca318b7a26ed67ca7c8c9b5069d653ba224bf86989125d1dfbb0973b7d6a5e0") val result = dataHandler.getBy(block.height) result mustEqual Bad(BlockNotFoundError).accumulating } } "delete" should { "delete a block" in { val block = BlockLoader.get("1ca318b7a26ed67ca7c8c9b5069d653ba224bf86989125d1dfbb0973b7d6a5e0") .copy(previousBlockhash = None) dataHandler.insert(block).isGood mustEqual true val result = dataHandler.delete(block.hash) result.isGood mustEqual true matches(block, result.get) } "fail on block not found" in { val blockhash = Blockhash.from("b858d38a3552c83aea58f66fe00ae220352a235e33fcf1f3af04507a61a9dc32").get val result = dataHandler.delete(blockhash) result mustEqual Bad(BlockNotFoundError).accumulating } } "getLatestBlock" should { "return the block" in { clearDatabase() val block0 = BlockLoader.get("00000c822abdbb23e28f79a49d29b41429737c6c7e15df40d1b1f1b35907ae34") .copy(previousBlockhash = None) val block1 = BlockLoader.get("000003fb382f6892ae96594b81aa916a8923c70701de4e7054aac556c7271ef7") val block2 = BlockLoader.get("000004645e2717b556682e3c642a4c6e473bf25c653ff8e8c114a3006040ffb8") List(block0, block1, block2).map(dataHandler.insert).foreach(_.isGood mustEqual true) val result = dataHandler.getLatestBlock() result.isGood mustEqual true matches(block2, result.get) } "fail on no blocks" in { clearDatabase() val result = dataHandler.getLatestBlock() result mustEqual Bad(BlockNotFoundError).accumulating } } "getFirstBlock" should { "return the block" in { clearDatabase() val block0 = BlockLoader.get("00000c822abdbb23e28f79a49d29b41429737c6c7e15df40d1b1f1b35907ae34") .copy(previousBlockhash = None) val block1 = BlockLoader.get("000003fb382f6892ae96594b81aa916a8923c70701de4e7054aac556c7271ef7") val block2 = BlockLoader.get("000004645e2717b556682e3c642a4c6e473bf25c653ff8e8c114a3006040ffb8") List(block0, block1, block2).map(dataHandler.insert).foreach(_.isGood mustEqual true) val result = dataHandler.getFirstBlock() result.isGood mustEqual true println(result.get.height.int) matches(block0, result.get) } "fail on no blocks" in { clearDatabase() val result = dataHandler.getLatestBlock() result mustEqual Bad(BlockNotFoundError).accumulating } } private def matches(expected: Block, result: Block) = { // NOTE: transactions and confirmations are not matched intentionally result.hash mustEqual expected.hash result.tposContract mustEqual expected.tposContract result.nextBlockhash mustEqual expected.nextBlockhash result.previousBlockhash mustEqual expected.previousBlockhash result.merkleRoot mustEqual expected.merkleRoot result.size mustEqual expected.size result.height mustEqual expected.height result.version mustEqual expected.version result.medianTime mustEqual expected.medianTime result.time mustEqual expected.time result.bits mustEqual expected.bits result.chainwork mustEqual expected.chainwork result.difficulty mustEqual expected.difficulty result.nonce mustEqual expected.nonce } }