Make ChainApi.processHeaders() return a failed future in the case we … (#2436)

* Rename NodeUnitTest.confg -> NodeUnitTest.getFreshConfig()

* Rename CachedBitcoinSAppConfig.config -> CachedBitcoinSAppConfig.cachedConfig

* Make CachedChainAppConfig extend CachedBitcoinSAppConfig

* Make ChainApi.processHeaders() return a failed future in the case we have no valid headers

* Run scalafmt

* Fix test case to check if promise is completed yet

* WIP: Get something working that isn't network specific

Start putting things back in place

Add comment

Revert logback file

Remove BitcoinSLogger object

* Fix unused import

* Get rid of annoying diff

* Fix spacing nit
This commit is contained in:
Chris Stewart 2021-01-12 06:11:19 -06:00 committed by GitHub
parent 93dae6c239
commit 4e285e6746
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 27 deletions

View file

@ -94,6 +94,16 @@ class ChainHandlerTest extends ChainDbUnitTest {
} yield succeed } yield succeed
} }
it must "fail if we give a header that cannot be connected to anything" in {
chainHandler: ChainHandler =>
val newHeader = BlockHeaderHelper.badPrevHash
recoverToSucceededIf[RuntimeException] {
for {
result <- chainHandler.processHeader(newHeader)
} yield result
}
}
// B // B
// C -> D // C -> D
it must "handle a very basic reorg where one chain is one block behind the best chain" in { it must "handle a very basic reorg where one chain is one block behind the best chain" in {

View file

@ -135,35 +135,44 @@ class ChainHandler(
successfullyValidatedHeaders.distinct successfullyValidatedHeaders.distinct
} }
val chains = blockchainUpdates.map(_.blockchain) if (headersToBeCreated.isEmpty) {
//this means we are given zero headers that were valid.
//Return a failure in this case to avoid issue 2365
//https://github.com/bitcoin-s/bitcoin-s/issues/2365
Future.failed(new RuntimeException(
s"Failed to connect any headers to our internal chain state, failures=$blockchainUpdates"))
} else {
val chains = blockchainUpdates.map(_.blockchain)
val createdF = blockHeaderDAO.createAll(headersToBeCreated) val createdF = blockHeaderDAO.createAll(headersToBeCreated)
val newChainHandler = ChainHandler(blockHeaderDAO, val newChainHandler = ChainHandler(blockHeaderDAO,
filterHeaderDAO, filterHeaderDAO,
filterDAO, filterDAO,
blockFilterCheckpoints = blockFilterCheckpoints =
blockFilterCheckpoints) blockFilterCheckpoints)
createdF.map { headers => createdF.map { headers =>
if (chainConfig.chainCallbacks.onBlockHeaderConnected.nonEmpty) { if (chainConfig.chainCallbacks.onBlockHeaderConnected.nonEmpty) {
headersToBeCreated.reverseIterator.foldLeft(FutureUtil.unit) { headersToBeCreated.reverseIterator.foldLeft(FutureUtil.unit) {
(acc, header) => (acc, header) =>
for { for {
_ <- acc _ <- acc
_ <- _ <-
chainConfig.chainCallbacks chainConfig.chainCallbacks
.executeOnBlockHeaderConnectedCallbacks(logger, .executeOnBlockHeaderConnectedCallbacks(
header.height, logger,
header.blockHeader) header.height,
} yield () header.blockHeader)
} yield ()
}
} }
chains.foreach { c =>
logger.info(
s"Processed headers from height=${c.height - headers.length} to ${c.height}. Best hash=${c.tip.hashBE.hex}")
}
newChainHandler
} }
chains.foreach { c =>
logger.info(
s"Processed headers from height=${c.height - headers.length} to ${c.height}. Best hash=${c.tip.hashBE.hex}")
}
newChainHandler
} }
} }
} }

View file

@ -19,7 +19,9 @@ import scala.concurrent.Future
trait ChainApi extends ChainQueryApi { trait ChainApi extends ChainQueryApi {
/** /**
* Adds a block header to our chain project * Adds a block header to our chain project.
* This will return a failed future when the
* given header is invalid.
* @param header * @param header
* @return * @return
*/ */
@ -29,7 +31,9 @@ trait ChainApi extends ChainQueryApi {
/** Process all of the given headers and returns a new [[ChainApi chain api]] /** Process all of the given headers and returns a new [[ChainApi chain api]]
* that contains these headers. This method processes headers in the order * that contains these headers. This method processes headers in the order
* that they are given. If the headers are out of order, this method will fail * that they are given. If the headers are out of order, this method will fail.
*
* This method will also fail when there are zero headers given that are valid.
* @param headers * @param headers
* @return * @return
*/ */

View file

@ -105,7 +105,9 @@ class DataMessageHandlerTest extends NodeUnitTest {
val callback: OnBlockHeadersReceived = (headers: Vector[BlockHeader]) => { val callback: OnBlockHeadersReceived = (headers: Vector[BlockHeader]) => {
Future { Future {
resultP.success(headers) if (!resultP.isCompleted) {
resultP.success(headers)
}
() ()
} }
} }