mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
2020 08 14 issue 1829 (#1833)
* Fix O(n^2) behavior in BaseBlockchain.connectWalkBackwards, cache BlockHeader.hash after the first time it is called * Revert a few files
This commit is contained in:
parent
48e3cb8e14
commit
c9f78a2a40
3 changed files with 35 additions and 19 deletions
|
@ -597,14 +597,20 @@ class ChainHandlerTest extends ChainDbUnitTest {
|
|||
getHeaderF.map(headerOpt =>
|
||||
assert(headerOpt.contains(expectedBlockHeaderDb)))
|
||||
val newAccum = accum.:+(assertionF)
|
||||
loop(headersTail, Some(expectedBlockHeaderDb), height + 1, newAccum)
|
||||
loop(remainingHeaders = headersTail,
|
||||
prevHeaderDbOpt = Some(expectedBlockHeaderDb),
|
||||
height = height + 1,
|
||||
accum = newAccum)
|
||||
case Vector() =>
|
||||
accum
|
||||
}
|
||||
}
|
||||
|
||||
val vecFutAssert: Vector[Future[Assertion]] =
|
||||
loop(headers, None, height, Vector.empty)
|
||||
loop(remainingHeaders = headers,
|
||||
prevHeaderDbOpt = None,
|
||||
height = height,
|
||||
accum = Vector.empty)
|
||||
|
||||
ScalaTestUtil.toAssertF(vecFutAssert)
|
||||
}
|
||||
|
|
|
@ -239,22 +239,33 @@ private[blockchain] trait BaseBlockChainCompObject
|
|||
/** Walks backwards from the current header searching through ancestors if [[current.previousBlockHashBE]] is in [[ancestors]]
|
||||
* This does not validate other things such as POW.
|
||||
*/
|
||||
@tailrec
|
||||
final def connectWalkBackwards(
|
||||
current: BlockHeaderDb,
|
||||
ancestors: Vector[BlockHeaderDb],
|
||||
accum: Vector[BlockHeaderDb] = Vector.empty)(implicit
|
||||
chainAppConfig: ChainAppConfig): Vector[BlockHeaderDb] = {
|
||||
val prevHeaderOpt = ancestors.find(_.hashBE == current.previousBlockHashBE)
|
||||
prevHeaderOpt match {
|
||||
case Some(h) =>
|
||||
connectWalkBackwards(current = h,
|
||||
accum = current +: accum,
|
||||
ancestors = ancestors)
|
||||
case None =>
|
||||
logger.debug(s"No prev found for $current hashBE=${current.hashBE}")
|
||||
current +: accum
|
||||
ancestors: Vector[BlockHeaderDb]): Vector[BlockHeaderDb] = {
|
||||
val groupByHeight: Map[Int, Vector[BlockHeaderDb]] = {
|
||||
ancestors.groupBy(_.height)
|
||||
}
|
||||
|
||||
@tailrec
|
||||
def loop(
|
||||
current: BlockHeaderDb,
|
||||
accum: Vector[BlockHeaderDb]): Vector[BlockHeaderDb] = {
|
||||
val prevHeight = current.height - 1
|
||||
val possibleHeadersOpt: Option[Vector[BlockHeaderDb]] =
|
||||
groupByHeight.get(prevHeight)
|
||||
|
||||
val prevHeaderOpt = possibleHeadersOpt.flatMap(
|
||||
_.find(_.hashBE == current.previousBlockHashBE)
|
||||
)
|
||||
prevHeaderOpt match {
|
||||
case Some(prevHeader) =>
|
||||
loop(prevHeader, current +: accum)
|
||||
case None =>
|
||||
current +: accum
|
||||
}
|
||||
}
|
||||
|
||||
loop(current, Vector.empty)
|
||||
}
|
||||
|
||||
/** Walks backwards from a child header reconstructing a blockchain
|
||||
|
@ -266,9 +277,8 @@ private[blockchain] trait BaseBlockChainCompObject
|
|||
chainAppConfig: ChainAppConfig): Vector[Blockchain] = {
|
||||
//now all hashes are connected correctly forming a
|
||||
//valid blockchain in term of hashes connected to each other
|
||||
val orderedHeaders = connectWalkBackwards(current = childHeader,
|
||||
accum = Vector.empty,
|
||||
ancestors = ancestors)
|
||||
val orderedHeaders =
|
||||
connectWalkBackwards(current = childHeader, ancestors = ancestors)
|
||||
|
||||
val initBlockchainOpt = orderedHeaders match {
|
||||
case Vector() | _ +: Vector() =>
|
||||
|
|
|
@ -116,7 +116,7 @@ sealed trait BlockHeader extends NetworkElement {
|
|||
def nonce: UInt32
|
||||
|
||||
/** Returns the block's hash in the protocol level little endian encoding */
|
||||
def hash: DoubleSha256Digest = CryptoUtil.doubleSHA256(bytes)
|
||||
lazy val hash: DoubleSha256Digest = CryptoUtil.doubleSHA256(bytes)
|
||||
|
||||
/**
|
||||
* Returns the block hash in big endian format, this is useful for rpc
|
||||
|
|
Loading…
Add table
Reference in a new issue