diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BlockchainTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BlockchainTest.scala index 8d114f81eb..ca94bdfe73 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BlockchainTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BlockchainTest.scala @@ -21,6 +21,17 @@ class BlockchainTest extends ChainUnitTest { behavior of "Blockchain" + it must "have the correct toString" inFixtured { + case ChainFixture.Empty => + val genesis = ChainUnitTest.genesisHeaderDb + val headerDb = + BlockHeaderHelper.buildNextHeader(genesis) + val chain = Blockchain(Vector(headerDb, genesis)) + + assert( + chain.toString == s"BaseBlockchain(tip=$headerDb,last=$genesis,length=2)") + } + it must "connect a new header to the current tip of a blockchain" inFixtured { case ChainFixture.Empty => val blockchain = Blockchain.fromHeaders( diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerTest.scala index 5780e70dfe..ae273bafdc 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerTest.scala @@ -3,6 +3,7 @@ package org.bitcoins.chain.blockchain import org.bitcoins.chain.{ChainCallbacks, OnBlockHeaderConnected} import org.bitcoins.chain.pow.Pow import org.bitcoins.core.api.chain.ChainApi +import org.bitcoins.core.api.chain.ChainQueryApi.FilterResponse import org.bitcoins.core.api.chain.db.{BlockHeaderDb, BlockHeaderDbHelper} import org.bitcoins.core.gcs.{BlockFilter, FilterHeader} import org.bitcoins.core.number.{Int32, UInt32} @@ -519,14 +520,40 @@ class ChainHandlerTest extends ChainDbUnitTest { bestBlock <- chainHandler.getBestBlockHeader() stamp1 = BlockStamp.BlockHash(bestBlock.hashBE) stamp2 = BlockStamp.BlockHeight(bestBlock.height) - stamp3 = BlockStamp.BlockTime(bestBlock.time) height1 <- chainHandler.getHeightByBlockStamp(stamp1) height2 <- chainHandler.getHeightByBlockStamp(stamp2) - // TODO implement BlockTime -// height3 <- chainHandler.getHeightByBlockStamp(stamp3) } yield { assert(height1 == height2) -// assert(height1 == height3) + } + } + + it must "fail to return the height by block time" in { + chainHandler: ChainHandler => + recoverToSucceededIf[RuntimeException] { + for { + bestBlock <- chainHandler.getBestBlockHeader() + stamp = BlockStamp.BlockTime(bestBlock.time) + height <- chainHandler.getHeightByBlockStamp(stamp) + } yield height + } + } + + it must "fail to return the height by block stamp with an unknown hash" in { + chainHandler: ChainHandler => + recoverToSucceededIf[UnknownBlockHash] { + val stamp = BlockStamp.BlockHash(DoubleSha256DigestBE.empty) + chainHandler.getHeightByBlockStamp(stamp) + } + } + + it must "find filters between heights" in { chainHandler: ChainHandler => + chainHandler.getFiltersBetweenHeights(0, 1).map { filters => + val genesis = ChainUnitTest.genesisFilterDb + val genesisFilterResponse = FilterResponse(genesis.golombFilter, + genesis.blockHashBE, + genesis.height) + + assert(filters == Vector(genesisFilterResponse)) } } @@ -567,6 +594,27 @@ class ChainHandlerTest extends ChainDbUnitTest { } } + it must "check isMissingChainWork when there is over a 100 headers" in { + chainHandler: ChainHandler => + val genesis = ChainUnitTest.genesisHeaderDb + val headers = 0.to(101).foldLeft(Vector(genesis)) { (accum, _) => + val next = BlockHeaderHelper.buildNextHeader(accum.last) + accum :+ next + } + + val noWork = BlockHeaderHelper + .buildNextHeader(headers.last) + .copy(chainWork = BigInt(0)) + + for { + _ <- chainHandler.blockHeaderDAO.upsertAll(headers) + isMissingFirst100 <- chainHandler.isMissingChainWork + _ = assert(!isMissingFirst100) + _ <- chainHandler.blockHeaderDAO.create(noWork) + isMissingLast100 <- chainHandler.isMissingChainWork + } yield assert(isMissingLast100) + } + it must "process a new valid block header with a callback" in { chainHandler: ChainHandler => val resultP: Promise[Boolean] = Promise() @@ -578,7 +626,7 @@ class ChainHandlerTest extends ChainDbUnitTest { } } - val callbacks = ChainCallbacks(Vector(callback)) + val callbacks = ChainCallbacks.onBlockHeaderConnected(callback) chainHandler.chainConfig.addCallbacks(callbacks) val newValidHeader = diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/MainnetChainHandlerTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/MainnetChainHandlerTest.scala index 49ab42009d..0857f98a40 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/MainnetChainHandlerTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/MainnetChainHandlerTest.scala @@ -190,13 +190,18 @@ class MainnetChainHandlerTest extends ChainDbUnitTest { ChainTestUtil.blockHeader562462) ) + val noWorkGenesis = genesis.copy(chainWork = BigInt(0)) + val blockchain = - Blockchain(headersWithNoWork :+ genesis.copy(chainWork = BigInt(0))) + Blockchain(headersWithNoWork :+ noWorkGenesis) val chainHandler = tempHandler.copy(blockchains = Vector(blockchain)) for { + _ <- chainHandler.blockHeaderDAO.update(noWorkGenesis) _ <- chainHandler.blockHeaderDAO.createAll(headersWithNoWork) + lowestNoWork <- chainHandler.blockHeaderDAO.getLowestNoWorkHeight + _ = assert(lowestNoWork == 0) isMissingWork <- chainHandler.isMissingChainWork _ = assert(isMissingWork) newHandler <- chainHandler.recalculateChainWork diff --git a/chain/src/main/scala/org/bitcoins/chain/ChainCallbacks.scala b/chain/src/main/scala/org/bitcoins/chain/ChainCallbacks.scala index 831305a56c..96b8272bbc 100644 --- a/chain/src/main/scala/org/bitcoins/chain/ChainCallbacks.scala +++ b/chain/src/main/scala/org/bitcoins/chain/ChainCallbacks.scala @@ -37,12 +37,12 @@ object ChainCallbacks { override def +(other: ChainCallbacks): ChainCallbacks = copy(onBlockHeaderConnected = onBlockHeaderConnected ++ other.onBlockHeaderConnected) - - /** Constructs a set of callbacks that only acts on block headers connected */ - def onBlockHeaderConnected(f: OnBlockHeaderConnected): ChainCallbacks = - ChainCallbacks(onBlockHeaderConnected = Vector(f)) } + /** Constructs a set of callbacks that only acts on block headers connected */ + def onBlockHeaderConnected(f: OnBlockHeaderConnected): ChainCallbacks = + ChainCallbacks(onBlockHeaderConnected = Vector(f)) + lazy val empty: ChainCallbacks = ChainCallbacks(onBlockHeaderConnected = Vector.empty)