Skip to content

Instantly share code, notes, and snippets.

@gmale
Last active June 14, 2019 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gmale/04668ab9fd21a0eea139e275665f8fc7 to your computer and use it in GitHub Desktop.
Save gmale/04668ab9fd21a0eea139e275665f8fc7 to your computer and use it in GitHub Desktop.
Handling Reorgs
/*
* Example of handling Reorgs when you don't care about scanning (like lightwalletd). Coroutines and other details have also been removed for simplicity.
*/
fun start() {
do {
// we must increase the number of blocks that we download after each failure in order to handle larger reorgs
retryUpTo(config.retries) {
val result = processNewBlocks()
// immediately process again after failures in order to download new blocks right away
if (result > -1) {
if(consecutiveErrors.get() >= config.retries) {
fail(CompactBlockProcessorException.FailedReorgRepair())
} else {
handleChainError(result)
}
consecutiveErrors.getAndIncrement()
} else {
consecutiveErrors.set(0)
delay(config.blockPollFrequencyMillis)
}
}
} while (isActive)
}
// download blocks and veryify them by checking all the prevHashes to make sure each block is on the same chain
private fun processNewBlocks(): Int {
// define ranges
val latestBlockHeight = downloader.getLatestBlockHeight()
val lastDownloadedHeight = Math.max(getLastDownloadedHeight(), SAPLING_ACTIVATION_HEIGHT - 1)
val rangeToDownload = (lastDownloadedHeight + 1)..latestBlockHeight
downloadNewBlocks(rangeToDownload)
return validateNewBlocks(rangeToScan) // validateNewBlocks just checks all the prevHashes
}
// rewind state to return to a height before the error was found
private fun handleChainError(errorHeight: Int) {
val lowerBound = determineLowerBound(errorHeight)
rustBackend.rewindToHeight(config.dataDbPath, lowerBound)
downloader.rewindTo(lowerBound)
}
// going back 10 blocks is a good starting point. It should increase a bit from there up to a limit of 100
// because 100 is an upperBound that exists in many other places in the protocol.
private fun determineLowerBound(errorHeight: Int): Int {
val offset = Math.min(MAX_REORG_SIZE, config.rewindDistance * (consecutiveErrors.get() + 1))
return Math.max(errorHeight - offset, SAPLING_ACTIVATION_HEIGHT)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment