[#1136] Tests for the new helper extensions
* Jni objects attribute constraint tests * Extend continuity error test * ScanRange model tests * [#1174] Move model classes out of the CompactBlockProcessor * [#1174] SbS: Move model classes out of the CompactBlockProcessor * Move SyncingResult out of the processor * Add issue link
This commit is contained in:
parent
7277a7ecca
commit
9795610bb9
|
@ -0,0 +1,32 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal.model
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertIs
|
||||||
|
|
||||||
|
class JniBlockMetaTest {
|
||||||
|
@Test
|
||||||
|
fun attributes_within_constraints() {
|
||||||
|
val instance = JniBlockMeta(
|
||||||
|
height = UInt.MAX_VALUE.toLong(),
|
||||||
|
hash = byteArrayOf(),
|
||||||
|
time = 0L,
|
||||||
|
saplingOutputsCount = UInt.MIN_VALUE.toLong(),
|
||||||
|
orchardOutputsCount = UInt.MIN_VALUE.toLong()
|
||||||
|
)
|
||||||
|
assertIs<JniBlockMeta>(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun attributes_not_in_constraints() {
|
||||||
|
assertFailsWith(IllegalArgumentException::class) {
|
||||||
|
JniBlockMeta(
|
||||||
|
height = Long.MAX_VALUE,
|
||||||
|
hash = byteArrayOf(),
|
||||||
|
time = 0L,
|
||||||
|
saplingOutputsCount = Long.MIN_VALUE,
|
||||||
|
orchardOutputsCount = Long.MIN_VALUE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal.model
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertIs
|
||||||
|
|
||||||
|
class JniScanRangeTest {
|
||||||
|
@Test
|
||||||
|
fun attributes_within_constraints() {
|
||||||
|
val instance = JniScanRange(
|
||||||
|
startHeight = UInt.MIN_VALUE.toLong(),
|
||||||
|
endHeight = UInt.MAX_VALUE.toLong(),
|
||||||
|
priority = 10
|
||||||
|
)
|
||||||
|
assertIs<JniScanRange>(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun attributes_not_in_constraints() {
|
||||||
|
assertFailsWith(IllegalArgumentException::class) {
|
||||||
|
JniScanRange(
|
||||||
|
startHeight = Long.MIN_VALUE,
|
||||||
|
endHeight = Long.MAX_VALUE,
|
||||||
|
priority = 10
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal.model
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertIs
|
||||||
|
|
||||||
|
class JniSubtreeRootTest {
|
||||||
|
@Test
|
||||||
|
fun attributes_within_constraints() {
|
||||||
|
val instance = JniSubtreeRoot(
|
||||||
|
rootHash = byteArrayOf(),
|
||||||
|
completingBlockHeight = UInt.MAX_VALUE.toLong()
|
||||||
|
)
|
||||||
|
assertIs<JniSubtreeRoot>(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun attributes_not_in_constraints() {
|
||||||
|
assertFailsWith(IllegalArgumentException::class) {
|
||||||
|
JniSubtreeRoot(
|
||||||
|
rootHash = byteArrayOf(),
|
||||||
|
completingBlockHeight = Long.MAX_VALUE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package cash.z.ecc.android.sdk.demoapp.fixture
|
package cash.z.ecc.android.sdk.demoapp.fixture
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||||
import cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel.SynchronizerError
|
import cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel.SynchronizerError
|
||||||
import cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel.WalletSnapshot
|
import cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel.WalletSnapshot
|
||||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel
|
package cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||||
|
|
|
@ -7,7 +7,7 @@ import cash.z.ecc.android.bip39.Mnemonics
|
||||||
import cash.z.ecc.android.bip39.toSeed
|
import cash.z.ecc.android.bip39.toSeed
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.WalletCoordinator
|
import cash.z.ecc.android.sdk.WalletCoordinator
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||||
import cash.z.ecc.android.sdk.demoapp.getInstance
|
import cash.z.ecc.android.sdk.demoapp.getInstance
|
||||||
import cash.z.ecc.android.sdk.demoapp.preference.EncryptedPreferenceKeys
|
import cash.z.ecc.android.sdk.demoapp.preference.EncryptedPreferenceKeys
|
||||||
import cash.z.ecc.android.sdk.demoapp.preference.EncryptedPreferenceSingleton
|
import cash.z.ecc.android.sdk.demoapp.preference.EncryptedPreferenceSingleton
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cash.z.ecc.android.sdk
|
package cash.z.ecc.android.sdk
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||||
import cash.z.ecc.android.sdk.ext.onFirst
|
import cash.z.ecc.android.sdk.ext.onFirst
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
import cash.z.ecc.android.sdk.internal.Twig
|
||||||
import cash.z.ecc.android.sdk.model.PersistableWallet
|
import cash.z.ecc.android.sdk.model.PersistableWallet
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor
|
||||||
|
|
||||||
|
// TODO [#1094]: Consider fake SDK sync related components
|
||||||
|
// TODO [#1094]: Testing the CompactBlockProcessor is only available once we can mock the necessary core components like
|
||||||
|
// [CompactBlockDownloader], [DerivedDataRepository], or [TypesafeBackend]
|
||||||
|
// TODO [#1094]: https://github.com/zcash/zcash-android-wallet-sdk/issues/1094
|
||||||
|
@Suppress("EmptyClassBlock")
|
||||||
|
class CompactBlockProcessorTest
|
|
@ -5,12 +5,12 @@ import cash.z.ecc.android.sdk.Synchronizer.Status.DISCONNECTED
|
||||||
import cash.z.ecc.android.sdk.Synchronizer.Status.STOPPED
|
import cash.z.ecc.android.sdk.Synchronizer.Status.STOPPED
|
||||||
import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCED
|
import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCED
|
||||||
import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCING
|
import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCING
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Disconnected
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Disconnected
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Initialized
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Initialized
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Stopped
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Stopped
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Synced
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Synced
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Syncing
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Syncing
|
||||||
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
import cash.z.ecc.android.sdk.exception.TransactionEncoderException
|
||||||
import cash.z.ecc.android.sdk.exception.TransactionSubmitException
|
import cash.z.ecc.android.sdk.exception.TransactionSubmitException
|
||||||
import cash.z.ecc.android.sdk.ext.ConsensusBranchId
|
import cash.z.ecc.android.sdk.ext.ConsensusBranchId
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cash.z.ecc.android.sdk
|
package cash.z.ecc.android.sdk
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import cash.z.ecc.android.sdk.block.CompactBlockProcessor
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
import cash.z.ecc.android.sdk.internal.Derivation
|
import cash.z.ecc.android.sdk.internal.Derivation
|
||||||
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
import cash.z.ecc.android.sdk.internal.SaplingParamTool
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
package cash.z.ecc.android.sdk.block
|
package cash.z.ecc.android.sdk.block.processor
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import cash.z.ecc.android.sdk.BuildConfig
|
import cash.z.ecc.android.sdk.BuildConfig
|
||||||
import cash.z.ecc.android.sdk.annotation.OpenForTesting
|
import cash.z.ecc.android.sdk.annotation.OpenForTesting
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.model.BatchSyncProgress
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.model.GetSubtreeRootsResult
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.model.PutSaplingSubtreeRootsResult
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.model.SuggestScanRangesResult
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.model.SyncStageResult
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.model.SyncingResult
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.model.UpdateChainTipResult
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.model.VerifySuggestedScanRange
|
||||||
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException
|
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException
|
||||||
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.EnhanceTransactionError.EnhanceTxDecryptError
|
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.EnhanceTransactionError.EnhanceTxDecryptError
|
||||||
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.EnhanceTransactionError.EnhanceTxDownloadError
|
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.EnhanceTransactionError.EnhanceTxDownloadError
|
||||||
|
@ -258,8 +266,6 @@ class CompactBlockProcessor internal constructor(
|
||||||
}
|
}
|
||||||
BlockProcessingResult.NoBlocksToProcess -> {
|
BlockProcessingResult.NoBlocksToProcess -> {
|
||||||
setState(State.Synced(_processorInfo.value.overallSyncRange))
|
setState(State.Synced(_processorInfo.value.overallSyncRange))
|
||||||
// TODO [#1129]: Refactor work with lastSyncRange and lastSyncedHeight
|
|
||||||
// TODO [#1129]: https://github.com/zcash/zcash-android-wallet-sdk/issues/1129
|
|
||||||
val noWorkDone = _processorInfo.value.overallSyncRange?.isEmpty() ?: true
|
val noWorkDone = _processorInfo.value.overallSyncRange?.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"
|
||||||
|
@ -354,34 +360,6 @@ class CompactBlockProcessor internal constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class SuggestScanRangesResult {
|
|
||||||
data class Success(val ranges: List<ScanRange>) : SuggestScanRangesResult()
|
|
||||||
data class Failure(val failedAtHeight: BlockHeight, val exception: Throwable) : SuggestScanRangesResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class GetSubtreeRootsResult {
|
|
||||||
// SbS: Spend-before-Sync
|
|
||||||
data class UseSbS(val subTreeRootList: List<SubtreeRoot>) : GetSubtreeRootsResult()
|
|
||||||
object UseLinear : GetSubtreeRootsResult()
|
|
||||||
object FailureConnection : GetSubtreeRootsResult()
|
|
||||||
data class OtherFailure(val exception: Throwable) : GetSubtreeRootsResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class PutSaplingSubtreeRootsResult {
|
|
||||||
object Success : PutSaplingSubtreeRootsResult()
|
|
||||||
data class Failure(val failedAtHeight: BlockHeight, val exception: Throwable) : PutSaplingSubtreeRootsResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class UpdateChainTipResult {
|
|
||||||
data class Success(val height: BlockHeight) : UpdateChainTipResult()
|
|
||||||
data class Failure(val failedAtHeight: BlockHeight, val exception: Throwable) : UpdateChainTipResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class VerifySuggestedScanRange {
|
|
||||||
data class ShouldVerify(val scanRange: ScanRange) : VerifySuggestedScanRange()
|
|
||||||
object NoRangeToVerify : VerifySuggestedScanRange()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO [#1137]: Refactor processNewBlocksInSbSOrder
|
// TODO [#1137]: Refactor processNewBlocksInSbSOrder
|
||||||
// TODO [#1137]: https://github.com/zcash/zcash-android-wallet-sdk/issues/1137
|
// TODO [#1137]: https://github.com/zcash/zcash-android-wallet-sdk/issues/1137
|
||||||
/**
|
/**
|
||||||
|
@ -1192,49 +1170,6 @@ class CompactBlockProcessor internal constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
internal sealed class SyncingResult {
|
|
||||||
object AllSuccess : SyncingResult()
|
|
||||||
data class DownloadSuccess(val downloadedBlocks: List<JniBlockMeta>?) : SyncingResult() {
|
|
||||||
override fun toString(): String {
|
|
||||||
return "DownloadSuccess with ${downloadedBlocks?.size ?: "none"} blocks"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
interface Failure {
|
|
||||||
val failedAtHeight: BlockHeight
|
|
||||||
val exception: CompactBlockProcessorException
|
|
||||||
fun toBlockProcessingResult(): BlockProcessingResult =
|
|
||||||
BlockProcessingResult.SyncFailure(
|
|
||||||
this.failedAtHeight,
|
|
||||||
this.exception
|
|
||||||
)
|
|
||||||
}
|
|
||||||
data class DownloadFailed(
|
|
||||||
override val failedAtHeight: BlockHeight,
|
|
||||||
override val exception: CompactBlockProcessorException
|
|
||||||
) : Failure, SyncingResult()
|
|
||||||
object ScanSuccess : SyncingResult()
|
|
||||||
data class ScanFailed(
|
|
||||||
override val failedAtHeight: BlockHeight,
|
|
||||||
override val exception: CompactBlockProcessorException
|
|
||||||
) : Failure, SyncingResult()
|
|
||||||
object DeleteSuccess : SyncingResult()
|
|
||||||
data class DeleteFailed(
|
|
||||||
override val failedAtHeight: BlockHeight,
|
|
||||||
override val exception: CompactBlockProcessorException
|
|
||||||
) : Failure, SyncingResult()
|
|
||||||
object EnhanceSuccess : SyncingResult()
|
|
||||||
data class EnhanceFailed(
|
|
||||||
override val failedAtHeight: BlockHeight,
|
|
||||||
override val exception: CompactBlockProcessorException
|
|
||||||
) : Failure, SyncingResult()
|
|
||||||
object UpdateBirthday : SyncingResult()
|
|
||||||
data class ContinuityError(
|
|
||||||
override val failedAtHeight: BlockHeight,
|
|
||||||
override val exception: CompactBlockProcessorException
|
|
||||||
) : Failure, SyncingResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests, processes and persists all blocks from the given range.
|
* Requests, processes and persists all blocks from the given range.
|
||||||
*
|
*
|
||||||
|
@ -2034,23 +1969,6 @@ class CompactBlockProcessor internal constructor(
|
||||||
object Initialized : State()
|
object Initialized : State()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Progress model class for sharing the whole batch sync progress out of the sync process.
|
|
||||||
*/
|
|
||||||
internal data class BatchSyncProgress(
|
|
||||||
val inRangeOrder: Long = 0,
|
|
||||||
val overallOrder: Long = 0,
|
|
||||||
val resultState: SyncingResult = SyncingResult.AllSuccess
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Progress model class for sharing particular sync stage result internally in the sync process.
|
|
||||||
*/
|
|
||||||
private data class SyncStageResult(
|
|
||||||
val batch: BlockBatch,
|
|
||||||
val stageResult: SyncingResult
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data class for holding detailed information about the processor.
|
* Data class for holding detailed information about the processor.
|
||||||
*
|
*
|
|
@ -0,0 +1,11 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor.model
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Progress model class for sharing the whole batch synchronization progress out of the synchronization process.
|
||||||
|
*/
|
||||||
|
internal data class BatchSyncProgress(
|
||||||
|
val inRangeOrder: Long = 0,
|
||||||
|
val overallOrder: Long = 0,
|
||||||
|
val resultState: SyncingResult =
|
||||||
|
SyncingResult.AllSuccess
|
||||||
|
)
|
|
@ -0,0 +1,14 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor.model
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.SubtreeRoot
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class for get subtree roots action result.
|
||||||
|
*/
|
||||||
|
internal sealed class GetSubtreeRootsResult {
|
||||||
|
// SbS: Spend-before-Sync
|
||||||
|
data class UseSbS(val subTreeRootList: List<SubtreeRoot>) : GetSubtreeRootsResult()
|
||||||
|
object UseLinear : GetSubtreeRootsResult()
|
||||||
|
object FailureConnection : GetSubtreeRootsResult()
|
||||||
|
data class OtherFailure(val exception: Throwable) : GetSubtreeRootsResult()
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor.model
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class for sharing put sapling subtree roots action result.
|
||||||
|
*/
|
||||||
|
internal sealed class PutSaplingSubtreeRootsResult {
|
||||||
|
object Success : PutSaplingSubtreeRootsResult()
|
||||||
|
data class Failure(val failedAtHeight: BlockHeight, val exception: Throwable) : PutSaplingSubtreeRootsResult()
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor.model
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ScanRange
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class for sharing suggested scan ranges action result.
|
||||||
|
*/
|
||||||
|
internal sealed class SuggestScanRangesResult {
|
||||||
|
data class Success(val ranges: List<ScanRange>) : SuggestScanRangesResult()
|
||||||
|
data class Failure(val failedAtHeight: BlockHeight, val exception: Throwable) : SuggestScanRangesResult()
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor.model
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.BlockBatch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common progress model class for sharing a batch synchronization stage result internally in the synchronization loop.
|
||||||
|
*/
|
||||||
|
internal data class SyncStageResult(
|
||||||
|
val batch: BlockBatch,
|
||||||
|
val stageResult: SyncingResult
|
||||||
|
)
|
|
@ -0,0 +1,51 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor.model
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||||
|
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class for the overall synchronization process result reporting.
|
||||||
|
*/
|
||||||
|
internal sealed class SyncingResult {
|
||||||
|
object AllSuccess : SyncingResult()
|
||||||
|
data class DownloadSuccess(val downloadedBlocks: List<JniBlockMeta>?) : SyncingResult() {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "DownloadSuccess with ${downloadedBlocks?.size ?: "none"} blocks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interface Failure {
|
||||||
|
val failedAtHeight: BlockHeight
|
||||||
|
val exception: CompactBlockProcessorException
|
||||||
|
fun toBlockProcessingResult(): CompactBlockProcessor.BlockProcessingResult =
|
||||||
|
CompactBlockProcessor.BlockProcessingResult.SyncFailure(
|
||||||
|
this.failedAtHeight,
|
||||||
|
this.exception
|
||||||
|
)
|
||||||
|
}
|
||||||
|
data class DownloadFailed(
|
||||||
|
override val failedAtHeight: BlockHeight,
|
||||||
|
override val exception: CompactBlockProcessorException
|
||||||
|
) : Failure, SyncingResult()
|
||||||
|
object ScanSuccess : SyncingResult()
|
||||||
|
data class ScanFailed(
|
||||||
|
override val failedAtHeight: BlockHeight,
|
||||||
|
override val exception: CompactBlockProcessorException
|
||||||
|
) : Failure, SyncingResult()
|
||||||
|
object DeleteSuccess : SyncingResult()
|
||||||
|
data class DeleteFailed(
|
||||||
|
override val failedAtHeight: BlockHeight,
|
||||||
|
override val exception: CompactBlockProcessorException
|
||||||
|
) : Failure, SyncingResult()
|
||||||
|
object EnhanceSuccess : SyncingResult()
|
||||||
|
data class EnhanceFailed(
|
||||||
|
override val failedAtHeight: BlockHeight,
|
||||||
|
override val exception: CompactBlockProcessorException
|
||||||
|
) : Failure, SyncingResult()
|
||||||
|
object UpdateBirthday : SyncingResult()
|
||||||
|
data class ContinuityError(
|
||||||
|
override val failedAtHeight: BlockHeight,
|
||||||
|
override val exception: CompactBlockProcessorException
|
||||||
|
) : Failure, SyncingResult()
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor.model
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class for sharing update chain tip action result.
|
||||||
|
*/
|
||||||
|
internal sealed class UpdateChainTipResult {
|
||||||
|
data class Success(val height: BlockHeight) : UpdateChainTipResult()
|
||||||
|
data class Failure(val failedAtHeight: BlockHeight, val exception: Throwable) : UpdateChainTipResult()
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package cash.z.ecc.android.sdk.block.processor.model
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ScanRange
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class for sharing verify suggested scan range action result.
|
||||||
|
*/
|
||||||
|
internal sealed class VerifySuggestedScanRange {
|
||||||
|
data class ShouldVerify(val scanRange: ScanRange) : VerifySuggestedScanRange()
|
||||||
|
object NoRangeToVerify : VerifySuggestedScanRange()
|
||||||
|
}
|
|
@ -1,10 +1,8 @@
|
||||||
package cash.z.ecc.android.sdk.internal.ext
|
package cash.z.ecc.android.sdk.internal.ext
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk.MAX_BACKOFF_INTERVAL
|
import cash.z.ecc.android.sdk.ext.ZcashSdk.MAX_BACKOFF_INTERVAL
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
import cash.z.ecc.android.sdk.internal.Twig
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import java.io.File
|
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
@ -120,12 +118,3 @@ suspend inline fun retryWithBackoff(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the given database already exists.
|
|
||||||
*
|
|
||||||
* @return true when the given database exists in the given context.
|
|
||||||
*/
|
|
||||||
internal fun dbExists(appContext: Context, dbFileName: String): Boolean {
|
|
||||||
return File(appContext.getDatabasePath(dbFileName).absolutePath).exists()
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package cash.z.ecc.android.sdk.internal.model
|
package cash.z.ecc.android.sdk.internal.model
|
||||||
|
|
||||||
import cash.z.ecc.android.sdk.internal.Twig
|
|
||||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
|
||||||
|
@ -11,7 +10,6 @@ internal data class ScanRange(
|
||||||
override fun toString() = "ScanRange(range=$range, priority=${getSuggestScanRangePriority()})"
|
override fun toString() = "ScanRange(range=$range, priority=${getSuggestScanRangePriority()})"
|
||||||
|
|
||||||
internal fun getSuggestScanRangePriority(): SuggestScanRangePriority {
|
internal fun getSuggestScanRangePriority(): SuggestScanRangePriority {
|
||||||
Twig.verbose { "Current suggested scan range priority: $priority" }
|
|
||||||
return SuggestScanRangePriority.values()
|
return SuggestScanRangePriority.values()
|
||||||
.firstOrNull { it.priority == priority } ?: SuggestScanRangePriority.Scanned
|
.firstOrNull { it.priority == priority } ?: SuggestScanRangePriority.Scanned
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cash.z.ecc.android.sdk.ext
|
package cash.z.ecc.android.sdk.ext
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.ext.BLOCK_HEIGHT_DISCONTINUITY
|
||||||
import cash.z.ecc.android.sdk.internal.ext.PREV_HASH_MISMATCH
|
import cash.z.ecc.android.sdk.internal.ext.PREV_HASH_MISMATCH
|
||||||
|
import cash.z.ecc.android.sdk.internal.ext.TREE_SIZE_MISMATCH
|
||||||
import cash.z.ecc.android.sdk.internal.ext.isScanContinuityError
|
import cash.z.ecc.android.sdk.internal.ext.isScanContinuityError
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
|
@ -10,15 +12,19 @@ class ExceptionExtTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun is_scan_continuity_error() {
|
fun is_scan_continuity_error() {
|
||||||
assertTrue {
|
assertTrue { RuntimeException(PREV_HASH_MISMATCH).isScanContinuityError() }
|
||||||
RuntimeException(PREV_HASH_MISMATCH).isScanContinuityError()
|
assertTrue { RuntimeException(TREE_SIZE_MISMATCH).isScanContinuityError() }
|
||||||
}
|
assertTrue { RuntimeException(BLOCK_HEIGHT_DISCONTINUITY).isScanContinuityError() }
|
||||||
|
|
||||||
|
assertTrue { RuntimeException(PREV_HASH_MISMATCH.lowercase()).isScanContinuityError() }
|
||||||
|
|
||||||
|
assertTrue { RuntimeException(PREV_HASH_MISMATCH.plus("Text")).isScanContinuityError() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun is_not_scan_continuity_error() {
|
fun is_not_scan_continuity_error() {
|
||||||
assertFalse {
|
assertFalse { RuntimeException("Text").isScanContinuityError() }
|
||||||
RuntimeException("Text").isScanContinuityError()
|
assertFalse { RuntimeException("").isScanContinuityError() }
|
||||||
}
|
assertFalse { RuntimeException(PREV_HASH_MISMATCH.drop(1)).isScanContinuityError() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package cash.z.ecc.android.sdk.fixture
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.ScanRange
|
||||||
|
import cash.z.ecc.android.sdk.internal.model.SuggestScanRangePriority
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
|
||||||
|
object ScanRangeFixture {
|
||||||
|
internal val DEFAULT_CLOSED_RANGE =
|
||||||
|
ZcashNetwork.Testnet.saplingActivationHeight..ZcashNetwork.Testnet.saplingActivationHeight + 9
|
||||||
|
internal val DEFAULT_PRIORITY = SuggestScanRangePriority.Verify.priority
|
||||||
|
|
||||||
|
internal fun new(
|
||||||
|
range: ClosedRange<BlockHeight> = DEFAULT_CLOSED_RANGE,
|
||||||
|
priority: Long = DEFAULT_PRIORITY
|
||||||
|
) = ScanRange(range, priority)
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package cash.z.ecc.android.sdk.internal.model
|
||||||
|
|
||||||
|
import cash.z.ecc.android.sdk.fixture.ScanRangeFixture
|
||||||
|
import cash.z.ecc.android.sdk.internal.ext.isNotEmpty
|
||||||
|
import cash.z.ecc.android.sdk.internal.ext.length
|
||||||
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class ScanRangeTest {
|
||||||
|
@Test
|
||||||
|
fun get_suggest_scan_range_priority_test() {
|
||||||
|
val scanRange = ScanRangeFixture.new(
|
||||||
|
priority = SuggestScanRangePriority.Verify.priority
|
||||||
|
)
|
||||||
|
assertTrue {
|
||||||
|
scanRange.getSuggestScanRangePriority() == SuggestScanRangePriority.Verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun scan_range_boundaries_test() {
|
||||||
|
val scanRange = ScanRangeFixture.new(
|
||||||
|
range = ZcashNetwork.Testnet.saplingActivationHeight..ZcashNetwork.Testnet.saplingActivationHeight + 9
|
||||||
|
)
|
||||||
|
assertTrue { scanRange.range.isNotEmpty() }
|
||||||
|
assertTrue { scanRange.range.length() == 10L }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue