[#1130] Initial Suggested Ranges Parsing
* [#1130] Initial suggested ranges parsing
This commit is contained in:
parent
b811305e53
commit
c8b481a12f
|
@ -25,6 +25,7 @@ import cash.z.ecc.android.sdk.internal.ext.toHexReversed
|
||||||
import cash.z.ecc.android.sdk.internal.model.BlockBatch
|
import cash.z.ecc.android.sdk.internal.model.BlockBatch
|
||||||
import cash.z.ecc.android.sdk.internal.model.DbTransactionOverview
|
import cash.z.ecc.android.sdk.internal.model.DbTransactionOverview
|
||||||
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ScanRange
|
||||||
import cash.z.ecc.android.sdk.internal.model.SubtreeRoot
|
import cash.z.ecc.android.sdk.internal.model.SubtreeRoot
|
||||||
import cash.z.ecc.android.sdk.internal.model.ext.from
|
import cash.z.ecc.android.sdk.internal.model.ext.from
|
||||||
import cash.z.ecc.android.sdk.internal.model.ext.toBlockHeight
|
import cash.z.ecc.android.sdk.internal.model.ext.toBlockHeight
|
||||||
|
@ -179,7 +180,7 @@ class CompactBlockProcessor internal constructor(
|
||||||
/**
|
/**
|
||||||
* Download compact blocks, verify and scan them until [stop] is called.
|
* Download compact blocks, verify and scan them until [stop] is called.
|
||||||
*/
|
*/
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
suspend fun start() {
|
suspend fun start() {
|
||||||
verifySetup()
|
verifySetup()
|
||||||
|
|
||||||
|
@ -194,7 +195,7 @@ class CompactBlockProcessor internal constructor(
|
||||||
// Download note commitment tree data from lightwalletd to decide if we communicate with linear
|
// Download note commitment tree data from lightwalletd to decide if we communicate with linear
|
||||||
// or non-linear node
|
// or non-linear node
|
||||||
val subTreeRootList = getSubtreeRoots(downloader, network)
|
val subTreeRootList = getSubtreeRoots(downloader, network)
|
||||||
Twig.info { "Fetched SubTreeRoot list: $subTreeRootList" }
|
Twig.info { "Fetched SubTreeRoot list size: ${subTreeRootList?.size ?: 0}" }
|
||||||
|
|
||||||
Twig.debug { "Setup verified. Processor starting..." }
|
Twig.debug { "Setup verified. Processor starting..." }
|
||||||
|
|
||||||
|
@ -221,6 +222,8 @@ class CompactBlockProcessor internal constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockProcessingResult.NoBlocksToProcess -> {
|
BlockProcessingResult.NoBlocksToProcess -> {
|
||||||
|
// TODO [#1129]: Refactor work with lastSyncRange and lastSyncedHeight
|
||||||
|
// TODO [#1129]: https://github.com/zcash/zcash-android-wallet-sdk/issues/1129
|
||||||
val noWorkDone = _processorInfo.value.lastSyncRange?.isEmpty() ?: true
|
val noWorkDone = _processorInfo.value.lastSyncRange?.isEmpty() ?: true
|
||||||
val summary = if (noWorkDone) {
|
val summary = if (noWorkDone) {
|
||||||
"Nothing to process: no new blocks to sync"
|
"Nothing to process: no new blocks to sync"
|
||||||
|
@ -344,6 +347,31 @@ class CompactBlockProcessor internal constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal sealed class SuggestScanRangesResult {
|
||||||
|
data class Success(val ranges: List<ScanRange>) : SuggestScanRangesResult()
|
||||||
|
|
||||||
|
// Fix it: consider failed at height parameter and more concrete exception type
|
||||||
|
data class Failure(val exception: Throwable) : SuggestScanRangesResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
internal enum class SuggestScanRangePriority(val priority: Long) {
|
||||||
|
Scanned(10),
|
||||||
|
Historic(20),
|
||||||
|
OpenAdjacent(30),
|
||||||
|
FoundNote(40),
|
||||||
|
ChainTip(50),
|
||||||
|
Verify(60);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromPriority(priority: Long): SuggestScanRangePriority {
|
||||||
|
Twig.verbose { "Current suggested scan range priority: $priority" }
|
||||||
|
return values().firstOrNull { it.priority == priority } ?: Scanned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("ReturnCount")
|
||||||
private suspend fun processNewBlocksInNonLinearOrder(subTreeRootList: List<SubtreeRoot>): BlockProcessingResult {
|
private suspend fun processNewBlocksInNonLinearOrder(subTreeRootList: List<SubtreeRoot>): BlockProcessingResult {
|
||||||
Twig.debug {
|
Twig.debug {
|
||||||
"Beginning to process new blocks with DAG approach (with roots: $subTreeRootList, and lower " +
|
"Beginning to process new blocks with DAG approach (with roots: $subTreeRootList, and lower " +
|
||||||
|
@ -367,14 +395,98 @@ class CompactBlockProcessor internal constructor(
|
||||||
return BlockProcessingResult.Reconnecting
|
return BlockProcessingResult.Reconnecting
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: print to suppress unused warning
|
// Notify the wallet of the updated chain tip.
|
||||||
Twig.debug { "${chainTip.value}" }
|
backend.updateChainTip(chainTip)
|
||||||
|
|
||||||
// 4) Notify the wallet of the updated chain tip.
|
// Get the suggested scan ranges from the wallet database
|
||||||
// wallet_db.update_chain_tip(tip_height).map_err(Error::Wallet)?;
|
when (val suggestedRangesResult = suggestScanRanges(backend)) {
|
||||||
|
is SuggestScanRangesResult.Failure -> {
|
||||||
|
Twig.error { "Process suggested scan ranges failure: ${suggestedRangesResult.exception}" }
|
||||||
|
// Fix it: process failure
|
||||||
|
}
|
||||||
|
is SuggestScanRangesResult.Success -> {
|
||||||
|
Twig.debug { "Process suggested scan ranges result: ${suggestedRangesResult.ranges}" }
|
||||||
|
|
||||||
// 5) Get the suggested scan ranges from the wallet database
|
if (suggestedRangesResult.ranges.isEmpty()) {
|
||||||
// let mut scan_ranges = wallet_db.suggest_scan_ranges().map_err(Error::Wallet)?;
|
// Nothing to sync - break out of the processing
|
||||||
|
return BlockProcessingResult.NoBlocksToProcess
|
||||||
|
} else {
|
||||||
|
val firstRangePriority = SuggestScanRangePriority.fromPriority(
|
||||||
|
suggestedRangesResult.ranges[0].priority
|
||||||
|
)
|
||||||
|
when (firstRangePriority) {
|
||||||
|
SuggestScanRangePriority.Verify -> {}
|
||||||
|
SuggestScanRangePriority.ChainTip -> {}
|
||||||
|
SuggestScanRangePriority.FoundNote -> {}
|
||||||
|
SuggestScanRangePriority.OpenAdjacent -> {}
|
||||||
|
SuggestScanRangePriority.Historic -> {}
|
||||||
|
SuggestScanRangePriority.Scanned -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the following loop until the wallet's view of the chain tip as of the previous wallet session is valid
|
||||||
|
// loop {
|
||||||
|
// // If there is a range of blocks that needs to be verified, it will always be returned as
|
||||||
|
// // the first element of the vector of suggested ranges.
|
||||||
|
// match scan_ranges.first() {
|
||||||
|
// Some(scan_range) if scan_range.priority() == ScanPriority::Verify => {
|
||||||
|
// // Download the blocks in `scan_range` into the block source, overwriting any
|
||||||
|
// // existing blocks in this range.
|
||||||
|
// unimplemented!();
|
||||||
|
//
|
||||||
|
// // Scan the downloaded blocks
|
||||||
|
// let scan_result = scan_cached_blocks(
|
||||||
|
// &network,
|
||||||
|
// &block_source,
|
||||||
|
// &mut wallet_db,
|
||||||
|
// scan_range.block_range().start,
|
||||||
|
// scan_range.len()
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // Check for scanning errors that indicate that the wallet's chain tip is out of
|
||||||
|
// // sync with blockchain history.
|
||||||
|
// match scan_result {
|
||||||
|
// Ok(_) => {
|
||||||
|
// // At this point, the cache and scanned data are locally consistent (though
|
||||||
|
// // not necessarily consistent with the latest chain tip - this would be
|
||||||
|
// // discovered the next time this codepath is executed after new blocks are
|
||||||
|
// // received) so we can break out of the loop.
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// Err(Error::Scan(err)) if err.is_continuity_error() => {
|
||||||
|
// // Pick a height to rewind to, which must be at least one block before
|
||||||
|
// // the height at which the error occurred, but may be an earlier height
|
||||||
|
// // determined based on heuristics such as the platform, available bandwidth,
|
||||||
|
// // size of recent CompactBlocks, etc.
|
||||||
|
// let rewind_height = err.at_height().saturating_sub(10);
|
||||||
|
//
|
||||||
|
// // Rewind to the chosen height.
|
||||||
|
// wallet_db.truncate_to_height(rewind_height).map_err(Error::Wallet)?;
|
||||||
|
//
|
||||||
|
// // Delete cached blocks from rewind_height onwards.
|
||||||
|
// //
|
||||||
|
// // This does imply that assumed-valid blocks will be re-downloaded, but it
|
||||||
|
// // is also possible that in the intervening time, a chain reorg has
|
||||||
|
// // occurred that orphaned some of those blocks.
|
||||||
|
// unimplemented!();
|
||||||
|
// }
|
||||||
|
// Err(other) => {
|
||||||
|
// // Handle or return other errors
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Truncation will have updated the suggested scan ranges, so we now
|
||||||
|
// // re_request
|
||||||
|
// scan_ranges = wallet_db.suggest_scan_ranges().map_err(Error::Wallet)?;
|
||||||
|
// }
|
||||||
|
// _ => {
|
||||||
|
// // Nothing to verify; break out of the loop
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
return BlockProcessingResult.NoBlocksToProcess
|
return BlockProcessingResult.NoBlocksToProcess
|
||||||
}
|
}
|
||||||
|
@ -801,6 +913,20 @@ class CompactBlockProcessor internal constructor(
|
||||||
return subTreeRootList
|
return subTreeRootList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
internal suspend fun suggestScanRanges(backend: TypesafeBackend): SuggestScanRangesResult {
|
||||||
|
return runCatching {
|
||||||
|
backend.suggestScanRanges()
|
||||||
|
}.onSuccess { ranges ->
|
||||||
|
Twig.info { "Successfully got newly suggested ranges: $ranges" }
|
||||||
|
}.onFailure { exception ->
|
||||||
|
Twig.error { "Failed to get newly suggested ranges with: $exception" }
|
||||||
|
}.fold(
|
||||||
|
onSuccess = { SuggestScanRangesResult.Success(it) },
|
||||||
|
onFailure = { SuggestScanRangesResult.Failure(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests, processes and persists all blocks from the given range.
|
* Requests, processes and persists all blocks from the given range.
|
||||||
*
|
*
|
||||||
|
@ -1610,6 +1736,8 @@ class CompactBlockProcessor internal constructor(
|
||||||
* @param firstUnenhancedHeight the height in which the enhancing should start, or null in case of no previous
|
* @param firstUnenhancedHeight the height in which the enhancing should start, or null in case of no previous
|
||||||
* transaction enhancing done yet
|
* transaction enhancing done yet
|
||||||
*/
|
*/
|
||||||
|
// TODO [#1129]: Refactor work with lastSyncRange and lastSyncedHeight
|
||||||
|
// TODO [#1129]: https://github.com/zcash/zcash-android-wallet-sdk/issues/1129
|
||||||
data class ProcessorInfo(
|
data class ProcessorInfo(
|
||||||
val networkBlockHeight: BlockHeight?,
|
val networkBlockHeight: BlockHeight?,
|
||||||
val lastSyncedHeight: BlockHeight?,
|
val lastSyncedHeight: BlockHeight?,
|
||||||
|
|
Loading…
Reference in New Issue