Get `WalletSummary` on CBP start and use it to bound subtree roots

This improves performance in two ways:
- The `SdkSynchronizer` now reports balances of existing wallets and
  sync progress almost immediately, instead of after the first batch
  of blocks is scanned.
- In the steady state case, only a few subtree roots are downloaded,
  reducing the time until the first batch of blocks is scanned.

Closes Electric-Coin-Company/zcash-android-wallet-sdk#1310.
This commit is contained in:
Jack Grigg 2024-01-27 03:26:54 +00:00 committed by str4d
parent a8965b01c6
commit 22407a593d
2 changed files with 22 additions and 9 deletions

View File

@ -203,6 +203,8 @@ class CompactBlockProcessor internal constructor(
*/
@Suppress("LongMethod", "CyclomaticComplexMethod")
suspend fun start() {
val startIndex = refreshWalletSummary()
verifySetup()
updateBirthdayHeight()
@ -220,7 +222,7 @@ class CompactBlockProcessor internal constructor(
// Download note commitment tree data from lightwalletd to decide if we communicate with linear
// or spend-before-sync node.
var subTreeRootResult = getSubtreeRoots(downloader, network)
var subTreeRootResult = getSubtreeRoots(downloader, network, startIndex)
Twig.info { "Fetched SubTreeRoot result: $subTreeRootResult" }
Twig.debug { "Setup verified. Processor starting..." }
@ -244,7 +246,7 @@ class CompactBlockProcessor internal constructor(
val result =
putSaplingSubtreeRoots(
backend = backend,
startIndex = 0,
startIndex = startIndex,
subTreeRootList =
(subTreeRootResult as GetSubtreeRootsResult.SpendBeforeSync)
.subTreeRootList,
@ -282,7 +284,7 @@ class CompactBlockProcessor internal constructor(
}
GetSubtreeRootsResult.FailureConnection -> {
// SubtreeRoot fetching retry
subTreeRootResult = getSubtreeRoots(downloader, network)
subTreeRootResult = getSubtreeRoots(downloader, network, startIndex)
BlockProcessingResult.Reconnecting
}
}
@ -739,16 +741,23 @@ class CompactBlockProcessor internal constructor(
/**
* Refreshes the SDK's wallet summary from the Rust backend, and transmits this information
* into the related internal flows. Note that the Orchard balance is not yet supported.
*
* @return the next subtree index to fetch.
*/
internal suspend fun refreshWalletSummary() {
internal suspend fun refreshWalletSummary(): UInt {
when (val result = getWalletSummary(backend)) {
is GetWalletSummaryResult.Success -> {
val resultProgress = result.scanProgressPercentDecimal()
Twig.info { "Progress from rust: ${resultProgress.decimal}" }
setProgress(resultProgress)
updateAllBalances(result.walletSummary)
return result.walletSummary.nextSaplingSubtreeIndex
}
else -> {
// Do not report the progress and balances in case of any error, and
// tell the caller to fetch all subtree roots.
return UInt.MIN_VALUE
}
else -> { /* Do not report the progress and balances in case of any error */ }
}
}
@ -1107,7 +1116,8 @@ class CompactBlockProcessor internal constructor(
@VisibleForTesting
internal suspend fun getSubtreeRoots(
downloader: CompactBlockDownloader,
network: ZcashNetwork
network: ZcashNetwork,
startIndex: UInt
): GetSubtreeRootsResult {
Twig.debug { "Fetching SubtreeRoots..." }
@ -1115,7 +1125,7 @@ class CompactBlockProcessor internal constructor(
retryUpToAndContinue(GET_SUBTREE_ROOTS_RETRIES) {
downloader.getSubtreeRoots(
startIndex = UInt.MIN_VALUE,
startIndex,
maxEntries = UInt.MIN_VALUE,
shieldedProtocol = ShieldedProtocolEnum.SAPLING
).onEach { response ->
@ -1159,7 +1169,7 @@ class CompactBlockProcessor internal constructor(
if (it.isEmpty()) {
GetSubtreeRootsResult.Linear
} else {
GetSubtreeRootsResult.SpendBeforeSync(it)
GetSubtreeRootsResult.SpendBeforeSync(startIndex, it)
}
}
}

View File

@ -6,7 +6,10 @@ import cash.z.ecc.android.sdk.internal.model.SubtreeRoot
* Internal class for get subtree roots action result.
*/
internal sealed class GetSubtreeRootsResult {
data class SpendBeforeSync(val subTreeRootList: List<SubtreeRoot>) : GetSubtreeRootsResult()
data class SpendBeforeSync(
val startIndex: UInt,
val subTreeRootList: List<SubtreeRoot>
) : GetSubtreeRootsResult()
data object Linear : GetSubtreeRootsResult()