diff --git a/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniBlockMetaTest.kt b/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniBlockMetaTest.kt new file mode 100644 index 00000000..8194c06a --- /dev/null +++ b/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniBlockMetaTest.kt @@ -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(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 + ) + } + } +} diff --git a/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniScanRangeTest.kt b/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniScanRangeTest.kt new file mode 100644 index 00000000..ada935b5 --- /dev/null +++ b/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniScanRangeTest.kt @@ -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(instance) + } + + @Test + fun attributes_not_in_constraints() { + assertFailsWith(IllegalArgumentException::class) { + JniScanRange( + startHeight = Long.MIN_VALUE, + endHeight = Long.MAX_VALUE, + priority = 10 + ) + } + } +} diff --git a/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniSubtreeRootTest.kt b/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniSubtreeRootTest.kt new file mode 100644 index 00000000..a9690f6d --- /dev/null +++ b/backend-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/JniSubtreeRootTest.kt @@ -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(instance) + } + + @Test + fun attributes_not_in_constraints() { + assertFailsWith(IllegalArgumentException::class) { + JniSubtreeRoot( + rootHash = byteArrayOf(), + completingBlockHeight = Long.MAX_VALUE + ) + } + } +} diff --git a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/fixture/WalletSnapshotFixture.kt b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/fixture/WalletSnapshotFixture.kt index cad402d5..01544e21 100644 --- a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/fixture/WalletSnapshotFixture.kt +++ b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/fixture/WalletSnapshotFixture.kt @@ -1,7 +1,7 @@ package cash.z.ecc.android.sdk.demoapp.fixture 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.WalletSnapshot import cash.z.ecc.android.sdk.model.PercentDecimal diff --git a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletSnapshot.kt b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletSnapshot.kt index 78cb3a01..31d9b1c5 100644 --- a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletSnapshot.kt +++ b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletSnapshot.kt @@ -1,7 +1,7 @@ package cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel 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.model.PercentDecimal import cash.z.ecc.android.sdk.model.WalletBalance diff --git a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletViewModel.kt b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletViewModel.kt index e2a55937..a2966530 100644 --- a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletViewModel.kt +++ b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletViewModel.kt @@ -7,7 +7,7 @@ import cash.z.ecc.android.bip39.Mnemonics import cash.z.ecc.android.bip39.toSeed import cash.z.ecc.android.sdk.Synchronizer 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.preference.EncryptedPreferenceKeys import cash.z.ecc.android.sdk.demoapp.preference.EncryptedPreferenceSingleton diff --git a/sdk-incubator-lib/src/main/java/cash/z/ecc/android/sdk/WalletCoordinator.kt b/sdk-incubator-lib/src/main/java/cash/z/ecc/android/sdk/WalletCoordinator.kt index da3224f3..9275f16f 100644 --- a/sdk-incubator-lib/src/main/java/cash/z/ecc/android/sdk/WalletCoordinator.kt +++ b/sdk-incubator-lib/src/main/java/cash/z/ecc/android/sdk/WalletCoordinator.kt @@ -1,7 +1,7 @@ package cash.z.ecc.android.sdk 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.internal.Twig import cash.z.ecc.android.sdk.model.PersistableWallet diff --git a/sdk-lib/src/androidTest/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessorTest.kt b/sdk-lib/src/androidTest/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessorTest.kt new file mode 100644 index 00000000..54df3b6e --- /dev/null +++ b/sdk-lib/src/androidTest/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessorTest.kt @@ -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 diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt index 05eae408..e2efed16 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt @@ -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.SYNCED import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCING -import cash.z.ecc.android.sdk.block.CompactBlockProcessor -import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Disconnected -import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Initialized -import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Stopped -import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Synced -import cash.z.ecc.android.sdk.block.CompactBlockProcessor.State.Syncing +import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor +import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Disconnected +import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Initialized +import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Stopped +import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor.State.Synced +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.TransactionSubmitException import cash.z.ecc.android.sdk.ext.ConsensusBranchId diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/Synchronizer.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/Synchronizer.kt index 0745b8bb..ed531c32 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/Synchronizer.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/Synchronizer.kt @@ -1,7 +1,7 @@ package cash.z.ecc.android.sdk 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.internal.Derivation import cash.z.ecc.android.sdk.internal.SaplingParamTool diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/CompactBlockProcessor.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessor.kt similarity index 95% rename from sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/CompactBlockProcessor.kt rename to sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessor.kt index fa877c4a..af26c40e 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/CompactBlockProcessor.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/CompactBlockProcessor.kt @@ -1,8 +1,16 @@ -package cash.z.ecc.android.sdk.block +package cash.z.ecc.android.sdk.block.processor import androidx.annotation.VisibleForTesting import cash.z.ecc.android.sdk.BuildConfig 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.EnhanceTransactionError.EnhanceTxDecryptError import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.EnhanceTransactionError.EnhanceTxDownloadError @@ -258,8 +266,6 @@ class CompactBlockProcessor internal constructor( } BlockProcessingResult.NoBlocksToProcess -> { 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 summary = if (noWorkDone) { "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) : 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) : 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]: 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?) : 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. * @@ -2034,23 +1969,6 @@ class CompactBlockProcessor internal constructor( 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. * diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/BatchSyncProgress.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/BatchSyncProgress.kt new file mode 100644 index 00000000..4c425bf3 --- /dev/null +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/BatchSyncProgress.kt @@ -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 +) diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/GetSubtreeRootsResult.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/GetSubtreeRootsResult.kt new file mode 100644 index 00000000..f6fb2f96 --- /dev/null +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/GetSubtreeRootsResult.kt @@ -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) : GetSubtreeRootsResult() + object UseLinear : GetSubtreeRootsResult() + object FailureConnection : GetSubtreeRootsResult() + data class OtherFailure(val exception: Throwable) : GetSubtreeRootsResult() +} diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/PutSaplingSubtreeRootsResult.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/PutSaplingSubtreeRootsResult.kt new file mode 100644 index 00000000..d72c4ce6 --- /dev/null +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/PutSaplingSubtreeRootsResult.kt @@ -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() +} diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SuggestScanRangesResult.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SuggestScanRangesResult.kt new file mode 100644 index 00000000..2b886365 --- /dev/null +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SuggestScanRangesResult.kt @@ -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) : SuggestScanRangesResult() + data class Failure(val failedAtHeight: BlockHeight, val exception: Throwable) : SuggestScanRangesResult() +} diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SyncStageResult.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SyncStageResult.kt new file mode 100644 index 00000000..9195254c --- /dev/null +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SyncStageResult.kt @@ -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 +) diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SyncingResult.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SyncingResult.kt new file mode 100644 index 00000000..6b32a7a5 --- /dev/null +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/SyncingResult.kt @@ -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?) : 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() +} diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/UpdateChainTipResult.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/UpdateChainTipResult.kt new file mode 100644 index 00000000..53d218f5 --- /dev/null +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/UpdateChainTipResult.kt @@ -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() +} diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/VerifySuggestedScanRange.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/VerifySuggestedScanRange.kt new file mode 100644 index 00000000..90ed3824 --- /dev/null +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/block/processor/model/VerifySuggestedScanRange.kt @@ -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() +} diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/ext/WalletService.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/ext/WalletService.kt index 786e31d8..743b39df 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/ext/WalletService.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/ext/WalletService.kt @@ -1,10 +1,8 @@ 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.internal.Twig import kotlinx.coroutines.delay -import java.io.File import kotlin.math.pow 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() -} diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/model/ScanRange.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/model/ScanRange.kt index 9ce0973f..39053bf3 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/model/ScanRange.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/model/ScanRange.kt @@ -1,6 +1,5 @@ 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.ZcashNetwork @@ -11,7 +10,6 @@ internal data class ScanRange( override fun toString() = "ScanRange(range=$range, priority=${getSuggestScanRangePriority()})" internal fun getSuggestScanRangePriority(): SuggestScanRangePriority { - Twig.verbose { "Current suggested scan range priority: $priority" } return SuggestScanRangePriority.values() .firstOrNull { it.priority == priority } ?: SuggestScanRangePriority.Scanned } diff --git a/sdk-lib/src/test/java/cash/z/ecc/android/sdk/ext/ExceptionExtTest.kt b/sdk-lib/src/test/java/cash/z/ecc/android/sdk/ext/ExceptionExtTest.kt index fdb69bd3..1288d9a2 100644 --- a/sdk-lib/src/test/java/cash/z/ecc/android/sdk/ext/ExceptionExtTest.kt +++ b/sdk-lib/src/test/java/cash/z/ecc/android/sdk/ext/ExceptionExtTest.kt @@ -1,6 +1,8 @@ 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.TREE_SIZE_MISMATCH import cash.z.ecc.android.sdk.internal.ext.isScanContinuityError import kotlin.test.Test import kotlin.test.assertFalse @@ -10,15 +12,19 @@ class ExceptionExtTest { @Test fun is_scan_continuity_error() { - assertTrue { - RuntimeException(PREV_HASH_MISMATCH).isScanContinuityError() - } + assertTrue { 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 fun is_not_scan_continuity_error() { - assertFalse { - RuntimeException("Text").isScanContinuityError() - } + assertFalse { RuntimeException("Text").isScanContinuityError() } + assertFalse { RuntimeException("").isScanContinuityError() } + assertFalse { RuntimeException(PREV_HASH_MISMATCH.drop(1)).isScanContinuityError() } } } diff --git a/sdk-lib/src/test/java/cash/z/ecc/android/sdk/fixture/ScanRangeFixture.kt b/sdk-lib/src/test/java/cash/z/ecc/android/sdk/fixture/ScanRangeFixture.kt new file mode 100644 index 00000000..249dc099 --- /dev/null +++ b/sdk-lib/src/test/java/cash/z/ecc/android/sdk/fixture/ScanRangeFixture.kt @@ -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 = DEFAULT_CLOSED_RANGE, + priority: Long = DEFAULT_PRIORITY + ) = ScanRange(range, priority) +} diff --git a/sdk-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/ScanRangeTest.kt b/sdk-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/ScanRangeTest.kt new file mode 100644 index 00000000..20f6580a --- /dev/null +++ b/sdk-lib/src/test/java/cash/z/ecc/android/sdk/internal/model/ScanRangeTest.kt @@ -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 } + } +}