Last active
June 14, 2019 16:19
-
-
Save gmale/04668ab9fd21a0eea139e275665f8fc7 to your computer and use it in GitHub Desktop.
Handling Reorgs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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