Merge pull request #225 from zcash/hotfix/1.3.0-beta06

Hotfix/1.3.0 beta06
This commit is contained in:
Kevin Gorham 2021-04-29 15:59:26 -04:00 committed by GitHub
commit fb2e9cff51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 170 additions and 116 deletions

View File

@ -1,6 +1,14 @@
Change Log Change Log
========== ==========
Version 1.3.0-beta06 *(2021-04-29)*
------------------------------------
- Fix: Repair publishing so that AARs work on Windows machines [issue #222].
- Fix: Incorrect BranchId on 32-bit devics [issue #224].
- Fix: Rescan should not go beyond the wallet checkpoint.
- New: Drop Android Jetifier since it is no longer used.
- Updated checkpoints, improved tests (added Test Suites) and better error messages.
Version 1.3.0-beta05 *(2021-04-23)* Version 1.3.0-beta05 *(2021-04-23)*
------------------------------------ ------------------------------------
- Major: Consolidate product flavors into one library for the SDK instead of two. - Major: Consolidate product flavors into one library for the SDK instead of two.

View File

@ -47,6 +47,7 @@ apply plugin: 'com.vanniktech.maven.publish'
repositories { repositories {
google() google()
mavenCentral()
jcenter() jcenter()
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
} }
@ -109,6 +110,8 @@ android {
jvmTarget = "1.8" jvmTarget = "1.8"
freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi"
freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.FlowPreview" freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.FlowPreview"
// Tricky: fix: By default, the kotlin_module name will not include the version (in classes.jar/META-INF). Instead it has a colon, which breaks compilation on Windows. This is one way to set it explicitly to the proper value. See https://github.com/zcash/zcash-android-wallet-sdk/issues/222 for more info.
freeCompilerArgs += ["-module-name", "${config.publish.artifactId}-${config.publish.versionName}_${config.publish.target}"]
} }
packagingOptions { packagingOptions {

View File

@ -9,8 +9,8 @@ targetSdkVersion = 30
publish { publish {
group = 'cash.z.ecc.android' group = 'cash.z.ecc.android'
versionName = '1.3.0-beta05' versionName = '1.3.0-beta06'
versionCode = 1_03_00_205 // last digits are alpha(0XX) beta(2XX) rc(4XX) release(8XX). Ex: 1_08_04_401 is an release candidate build of version 1.8.4 and 1_08_04_800 would be the final release. versionCode = 1_03_00_206 // last digits are alpha(0XX) beta(2XX) rc(4XX) release(8XX). Ex: 1_08_04_401 is an release candidate build of version 1.8.4 and 1_08_04_800 would be the final release.
artifactId = 'zcash-android-sdk' artifactId = 'zcash-android-sdk'
target = 'release' target = 'release'
} }

View File

@ -14,9 +14,11 @@ org.gradle.jvmargs=-Xmx1536m
# AndroidX package structure to make it clearer which packages are bundled with the # AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK # Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # support libraries have long been changed to AndroidX I think we can stop leaning on jetifier now!
android.enableJetifier=true #android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official

View File

@ -0,0 +1,33 @@
package cash.z.ecc.android.sdk
import cash.z.ecc.android.sdk.integration.SanityTest
import cash.z.ecc.android.sdk.integration.SmokeTest
import cash.z.ecc.android.sdk.integration.service.ChangeServiceTest
import cash.z.ecc.android.sdk.jni.BranchIdTest
import cash.z.ecc.android.sdk.jni.TransparentTest
import cash.z.ecc.android.sdk.transaction.PersistentTransactionManagerTest
import org.junit.runner.RunWith
import org.junit.runners.Suite
/**
* Suite of tests to run before submitting a pull request.
*
* For now, these are just the tests that are known to be recently updated and that pass. In the
* near future this suite will contain only fast running tests that can be used to quickly validate
* that a PR hasn't broken anything major.
*/
@RunWith(Suite::class)
@Suite.SuiteClasses(
// Fast tests that only run locally and don't require darksidewalletd or lightwalletd
BranchIdTest::class,
TransparentTest::class,
PersistentTransactionManagerTest::class,
// potentially exclude because these are long-running (and hit external srvcs)
SanityTest::class,
// potentially exclude because these hit external services
ChangeServiceTest::class,
SmokeTest::class,
)
class PullRequestSuite

View File

@ -126,7 +126,7 @@ class SanityTest(
TestWallet(TestWallet.Backups.SAMPLE_WALLET, ZcashNetwork.Mainnet), TestWallet(TestWallet.Backups.SAMPLE_WALLET, ZcashNetwork.Mainnet),
"zxviews1q0hxkupsqqqqpqzsffgrk2smjuccedua7zswf5e3rgtv3ga9nhvhjug670egshd6me53r5n083s2m9mf4va4z7t39ltd3wr7hawnjcw09eu85q0ammsg0tsgx24p4ma0uvr4p8ltx5laum2slh2whc23ctwlnxme9w4dw92kalwk5u4wyem8dynknvvqvs68ktvm8qh7nx9zg22xfc77acv8hk3qqll9k3x4v2fa26puu2939ea7hy4hh60ywma69xtqhcy4037ne8g2sg8sq", "zxviews1q0hxkupsqqqqpqzsffgrk2smjuccedua7zswf5e3rgtv3ga9nhvhjug670egshd6me53r5n083s2m9mf4va4z7t39ltd3wr7hawnjcw09eu85q0ammsg0tsgx24p4ma0uvr4p8ltx5laum2slh2whc23ctwlnxme9w4dw92kalwk5u4wyem8dynknvvqvs68ktvm8qh7nx9zg22xfc77acv8hk3qqll9k3x4v2fa26puu2939ea7hy4hh60ywma69xtqhcy4037ne8g2sg8sq",
"031c6355641237643317e2d338f5e8734c57e8aa8ce960ee22283cf2d76bef73be", "031c6355641237643317e2d338f5e8734c57e8aa8ce960ee22283cf2d76bef73be",
1195000 1000000
) )
) )
} }

View File

@ -47,7 +47,7 @@ class SmokeTest {
@Test @Test
fun testSync() = runBlocking<Unit> { fun testSync() = runBlocking<Unit> {
wallet.sync(120_000L) wallet.sync(300_000L)
} }
companion object { companion object {

View File

@ -121,7 +121,7 @@ class ChangeServiceTest : ScopedTest() {
} }
assertNotNull("Using an invalid host should generate an exception.", caughtException) assertNotNull("Using an invalid host should generate an exception.", caughtException)
assertTrue( assertTrue(
"Exception was of the wrong type.", "Exception was of the wrong type. Expected ${ChainInfoNotMatching::class.simpleName} but was ${caughtException!!::class.simpleName}",
caughtException is ChainInfoNotMatching caughtException is ChainInfoNotMatching
) )
(caughtException as ChainInfoNotMatching).propertyNames.let { props -> (caughtException as ChainInfoNotMatching).propertyNames.let { props ->

View File

@ -0,0 +1,63 @@
package cash.z.ecc.android.sdk.jni
import cash.z.ecc.android.sdk.annotation.MaintainedTest
import cash.z.ecc.android.sdk.annotation.TestPurpose
import cash.z.ecc.android.sdk.type.ZcashNetwork
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
/**
* This test is intended to run to make sure that branch ID logic works across all target devices.
*/
@MaintainedTest(TestPurpose.REGRESSION)
@RunWith(Parameterized::class)
class BranchIdTest(
private val networkName: String,
private val height: Int,
private val branchId: Long,
private val branchHex: String,
private val rustBackend: RustBackendWelding
) {
@Test
fun testBranchId_Hex() {
val branchId = rustBackend.getBranchIdForHeight(height)
val clientBranch = "%x".format(branchId)
assertEquals("Invalid branch Id Hex value for $networkName at height $height on ${rustBackend.network.networkName}", branchHex, clientBranch)
}
@Test
fun testBranchId_Numeric() {
val actual = rustBackend.getBranchIdForHeight(height)
assertEquals("Invalid branch ID for $networkName at height $height on ${rustBackend.network.networkName}", branchId, actual)
}
companion object {
@JvmStatic
@Parameterized.Parameters
fun wallets(): List<Array<Any>> {
// init values don't matter for this test because we're just checking branchIds, which
// is an abnormal use of the SDK because this really should run at the rust level
// However, due to quirks on certain devices, we created this test at the Android level,
// as a sanity check
val testnetBackend = RustBackend.init("", "", "", ZcashNetwork.Testnet)
val mainnetBackend = RustBackend.init("", "", "", ZcashNetwork.Mainnet)
return listOf(
// Mainnet Cases
arrayOf("Sapling", 419_200, 1991772603L, "76b809bb", mainnetBackend),
arrayOf("Blossom", 653_600, 733220448L, "2bb40e60", mainnetBackend),
arrayOf("Heartwood", 903_000, 4122551051L, "f5b9230b", mainnetBackend),
arrayOf("Canopy", 1_046_400, 3925833126L, "e9ff75a6", mainnetBackend),
// Testnet Cases
arrayOf("Sapling", 280_000, 1991772603L, "76b809bb", testnetBackend),
arrayOf("Blossom", 584_000, 733220448L, "2bb40e60", testnetBackend),
arrayOf("Heartwood", 903_800, 4122551051L, "f5b9230b", testnetBackend),
arrayOf("Canopy", 1_028_500, 3925833126L, "e9ff75a6", testnetBackend),
)
}
}
}

View File

@ -1,23 +1,8 @@
package cash.z.ecc.android.sdk.sample package cash.z.ecc.android.sdk.sample
import androidx.test.platform.app.InstrumentationRegistry
import cash.z.ecc.android.bip39.Mnemonics
import cash.z.ecc.android.bip39.toSeed
import cash.z.ecc.android.sdk.Initializer
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.Synchronizer.Status.SYNCED
import cash.z.ecc.android.sdk.ext.TroubleshootingTwig
import cash.z.ecc.android.sdk.ext.Twig import cash.z.ecc.android.sdk.ext.Twig
import cash.z.ecc.android.sdk.ext.twig import cash.z.ecc.android.sdk.type.ZcashNetwork
import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.android.sdk.util.TestWallet
import cash.z.ecc.android.sdk.type.ZcashNetwork.Testnet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.newFixedThreadPoolContext
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
@ -27,7 +12,7 @@ import org.junit.Test
*/ */
class ShieldFundsSample { class ShieldFundsSample {
val SEED_PHRASE = "wish puppy smile loan doll curve hole maze file ginger hair nose key relax knife witness cannon grab despair throw review deal slush frame" // \"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread\"//\"deputy visa gentle among clean scout farm drive comfort patch skin salt ranch cool ramp warrior drink narrow normal lunch behind salt deal person"//"deputy visa gentle among clean scout farm drive comfort patch skin salt ranch cool ramp warrior drink narrow normal lunch behind salt deal person" val SEED_PHRASE = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" // \"//\"deputy visa gentle among clean scout farm drive comfort patch skin salt ranch cool ramp warrior drink narrow normal lunch behind salt deal person"//"deputy visa gentle among clean scout farm drive comfort patch skin salt ranch cool ramp warrior drink narrow normal lunch behind salt deal person"
/** /**
* This test will construct a t2z transaction. It is safe to run this repeatedly, because * This test will construct a t2z transaction. It is safe to run this repeatedly, because
@ -40,71 +25,12 @@ class ShieldFundsSample {
fun constructT2Z() = runBlocking { fun constructT2Z() = runBlocking {
Twig.sprout("ShieldFundsSample") Twig.sprout("ShieldFundsSample")
val wallet = SimpleWallet(SEED_PHRASE).sync() val wallet = TestWallet(TestWallet.Backups.DEV_WALLET, ZcashNetwork.Mainnet)
wallet.shieldFunds()
Assert.assertEquals("foo", "${wallet.shieldedAddress} ${wallet.transparentAddress}")
// wallet.shieldFunds()
Twig.clip("ShieldFundsSample") Twig.clip("ShieldFundsSample")
Assert.assertEquals(5, wallet.synchronizer.latestBalance.availableZatoshi) Assert.assertEquals(5, wallet.synchronizer.latestBalance.availableZatoshi)
} }
// when startHeight is null, it will use the latest checkpoint
class SimpleWallet(seedPhrase: String, startHeight: Int? = null) {
// simple flag to turn off actually spending funds
val IS_DRY_RUN = true
val walletScope = CoroutineScope(
SupervisorJob() + newFixedThreadPoolContext(3, this.javaClass.simpleName)
)
private val context = InstrumentationRegistry.getInstrumentation().context
private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
private val shieldedSpendingKey = DerivationTool.deriveSpendingKeys(seed, Testnet)[0]
private val transparentSecretKey = DerivationTool.deriveTransparentSecretKey(seed, Testnet)
private val shieldedAddress = DerivationTool.deriveShieldedAddress(seed, Testnet)
// t1b9Y6PESSGavavgge3ruTtX9X83817V29s
private val transparentAddress = DerivationTool.deriveTransparentAddress(seed, Testnet)
private val host = "lightwalletd.testnet.electriccoin.co"
private val config = Initializer.Config {
it.setSeed(seed, Testnet)
it.setBirthdayHeight(startHeight, false)
it.setNetwork(Testnet, host)
}
val synchronizer = Synchronizer(Initializer(context, config))
suspend fun sync(): SimpleWallet {
twig("Starting sync")
synchronizer.start(walletScope)
// block until synced
synchronizer.status.first { it == SYNCED }
twig("Synced!")
return this
}
suspend fun shieldFunds(): SimpleWallet {
twig("checking $transparentAddress for transactions!")
synchronizer.refreshUtxos(transparentAddress, 935000).let { count ->
twig("FOUND $count new UTXOs")
}
synchronizer.getTransparentBalance(transparentAddress).let { walletBalance ->
twig("FOUND utxo balance of total: ${walletBalance.totalZatoshi} available: ${walletBalance.availableZatoshi}")
if (walletBalance.availableZatoshi > 0L && !IS_DRY_RUN) {
synchronizer.shieldFunds(shieldedSpendingKey, transparentSecretKey)
.onCompletion { twig("done shielding funds") }
.catch { twig("Failed with $it") }
.collect()
}
}
return this
}
companion object {
init {
Twig.plant(TroubleshootingTwig())
}
}
}
} }

View File

@ -44,7 +44,7 @@ class TestWallet(
) : this( ) : this(
backup.seedPhrase, backup.seedPhrase,
network = network, network = network,
startHeight = backup.testnetBirthday, startHeight = if (network == ZcashNetwork.Mainnet) backup.mainnetBirthday else backup.testnetBirthday,
alias = alias alias = alias
) )
@ -106,7 +106,7 @@ class TestWallet(
} }
suspend fun rewindToHeight(height: Int): TestWallet { suspend fun rewindToHeight(height: Int): TestWallet {
synchronizer.rewindToHeight(height, false) synchronizer.rewindToNearestHeight(height, false)
return this return this
} }
@ -151,11 +151,13 @@ class TestWallet(
} }
} }
enum class Backups(val seedPhrase: String, val testnetBirthday: Int) { enum class Backups(val seedPhrase: String, val testnetBirthday: Int, val mainnetBirthday: Int) {
DEFAULT("column rhythm acoustic gym cost fit keen maze fence seed mail medal shrimp tell relief clip cannon foster soldier shallow refuse lunar parrot banana", 1_355_928), // TODO: get the proper birthday values for these wallets
SAMPLE_WALLET("input frown warm senior anxiety abuse yard prefer churn reject people glimpse govern glory crumble swallow verb laptop switch trophy inform friend permit purpose", 1_330_190), DEFAULT("column rhythm acoustic gym cost fit keen maze fence seed mail medal shrimp tell relief clip cannon foster soldier shallow refuse lunar parrot banana", 1_355_928, 1_000_000),
ALICE("quantum whisper lion route fury lunar pelican image job client hundred sauce chimney barely life cliff spirit admit weekend message recipe trumpet impact kitten", 1_330_190), SAMPLE_WALLET("input frown warm senior anxiety abuse yard prefer churn reject people glimpse govern glory crumble swallow verb laptop switch trophy inform friend permit purpose", 1_330_190, 1_000_000),
BOB("canvas wine sugar acquire garment spy tongue odor hole cage year habit bullet make label human unit option top calm neutral try vocal arena", 1_330_190), DEV_WALLET("still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread", 1_000_000, 991645),
ALICE("quantum whisper lion route fury lunar pelican image job client hundred sauce chimney barely life cliff spirit admit weekend message recipe trumpet impact kitten", 1_330_190, 1_000_000),
BOB("canvas wine sugar acquire garment spy tongue odor hole cage year habit bullet make label human unit option top calm neutral try vocal arena", 1_330_190, 1_000_000),
; ;
} }
} }

View File

@ -1,7 +0,0 @@
{
"network": "main",
"height": 1225000,
"hash": "0000000001977934324bddde1888c658b0faf997d91b36125d42b4a394ce94d5",
"time": 1619171235,
"tree": "010b90d9e211f1a12634595a2b7a3899abb0fb46aada6a88a1d5fe4732286cff1c00130000016671cff0e2881f9923d85952f6116d3855918016e8ef2951040a0ace61b8883e0000000000000134ca9a7c4309349dfe003f3b4b95898b4303631e9be3a25b4e917a4f3472b52f00000121c25bceccda091622bfac1b7973ffaa638abe1f334b3b56f48dc93dc549c9070001ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
}

View File

@ -0,0 +1,7 @@
{
"network": "main",
"height": 1230000,
"hash": "0000000001bcfbeb53fd5e9647168265bc5fc8e8622049b9cdd07098f0f51601",
"time": 1619548843,
"tree": "0164566f774ea1f6d7cf21a9fbf9cb3f2e7d1e400097417822a7c233422619c3710013000001bad8de55d9adf4d4ff08f4ad172a5ee80aa0049974c5227d2b07474078f73c2a01e8d5303b72f034efacb9b9aa0697aa5568bf6116f2fdc1e528c03b76ce569c340000000000015334d52667d65b8ff3dcfb3d6ed72c46ad19ea9112813aaf344a3e614eb9012600016cad8c39b711691f2bda74017894c657555a8bf7ef913931ac4f7ba0b48a30120121c25bceccda091622bfac1b7973ffaa638abe1f334b3b56f48dc93dc549c9070001ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
}

View File

@ -17,6 +17,7 @@ import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.EnhanceTr
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.EnhanceTransactionError.EnhanceTxDownloadError import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.EnhanceTransactionError.EnhanceTxDownloadError
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.MismatchedBranch import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.MismatchedBranch
import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.MismatchedNetwork import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException.MismatchedNetwork
import cash.z.ecc.android.sdk.exception.InitializerException
import cash.z.ecc.android.sdk.exception.RustLayerException import cash.z.ecc.android.sdk.exception.RustLayerException
import cash.z.ecc.android.sdk.ext.BatchMetrics import cash.z.ecc.android.sdk.ext.BatchMetrics
import cash.z.ecc.android.sdk.ext.Twig import cash.z.ecc.android.sdk.ext.Twig
@ -383,7 +384,7 @@ class CompactBlockProcessor(
val network = rustBackend.network.networkName val network = rustBackend.network.networkName
when { when {
!info.matchingNetwork(network) -> MismatchedNetwork(clientNetwork = network, serverNetwork = info.chainName) !info.matchingNetwork(network) -> MismatchedNetwork(clientNetwork = network, serverNetwork = info.chainName)
!info.matchingConsensusBranchId(clientBranch) -> MismatchedBranch(clientBranch = clientBranch, serverBranch = info.consensusBranchId) !info.matchingConsensusBranchId(clientBranch) -> MismatchedBranch(clientBranch = clientBranch, serverBranch = info.consensusBranchId, networkName = network)
else -> null else -> null
} }
} }
@ -593,8 +594,10 @@ class CompactBlockProcessor(
} }
suspend fun getNearestRewindHeight(height: Int): Int { suspend fun getNearestRewindHeight(height: Int): Int {
return if (height < lowerBoundHeight) { // TODO: add a concept of original checkpoint height to the processor. For now, derive it
lowerBoundHeight val originalCheckpoint = lowerBoundHeight + MAX_REORG_SIZE + 2 // add one because we already have the checkpoint. Add one again because we delete ABOVE the block
return if (height < originalCheckpoint) {
originalCheckpoint
} else { } else {
// tricky: subtract one because we delete ABOVE this block // tricky: subtract one because we delete ABOVE this block
rustBackend.getNearestRewindHeight(height) - 1 rustBackend.getNearestRewindHeight(height) - 1
@ -745,11 +748,13 @@ class CompactBlockProcessor(
* @return the address of this wallet. * @return the address of this wallet.
*/ */
suspend fun getShieldedAddress(accountId: Int = 0) = withContext(IO) { suspend fun getShieldedAddress(accountId: Int = 0) = withContext(IO) {
repository.getAccount(accountId)!!.rawShieldedAddress repository.getAccount(accountId)?.rawShieldedAddress
?: throw InitializerException.MissingAddressException("shielded")
} }
suspend fun getTransparentAddress(accountId: Int = 0) = withContext(IO) { suspend fun getTransparentAddress(accountId: Int = 0) = withContext(IO) {
repository.getAccount(accountId)!!.rawTransparentAddress repository.getAccount(accountId)?.rawTransparentAddress
?: throw InitializerException.MissingAddressException("transparent")
} }
/** /**

View File

@ -92,8 +92,8 @@ sealed class CompactBlockProcessorException(message: String, cause: Throwable? =
"Incompatible server: this client expects a server using $clientNetwork but it was $serverNetwork! Try updating the client or switching servers." "Incompatible server: this client expects a server using $clientNetwork but it was $serverNetwork! Try updating the client or switching servers."
) )
class MismatchedBranch(clientBranch: String?, serverBranch: String?) : CompactBlockProcessorException( class MismatchedBranch(clientBranch: String?, serverBranch: String?, networkName: String?) : CompactBlockProcessorException(
"Incompatible server: this client expects a server following consensus branch $clientBranch but it was $serverBranch! Try updating the client or switching servers." "Incompatible server: this client expects a server following consensus branch $clientBranch on $networkName but it was $serverBranch! Try updating the client or switching servers."
) )
} }
@ -147,6 +147,14 @@ sealed class InitializerException(message: String, cause: Throwable? = null) : S
" unified viewingKey from the seed or seedPhrase, if they exist, but it is probably" + " unified viewingKey from the seed or seedPhrase, if they exist, but it is probably" +
" better not to mask this error because the root issue should be addressed." " better not to mask this error because the root issue should be addressed."
) )
class MissingAddressException(description: String, cause: Throwable? = null) : InitializerException(
"Expected a $description address for this wallet but failed to find one. This usually" +
" means that wallet setup happened incorrectly. If this problem persists, a" +
" workaround might be to go to settings and WIPE the wallet and rescan. Doing so" +
" will restore any missing address information. Meanwhile, please report that" +
" this happened so that the root issue can be uncovered and corrected." +
if (cause != null) "\nCaused by: $cause" else ""
)
object DatabasePathException : object DatabasePathException :
InitializerException( InitializerException(
"Critical failure to locate path for storing databases. Perhaps this device prevents" + "Critical failure to locate path for storing databases. Perhaps this device prevents" +

View File

@ -1158,13 +1158,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_branchIdFor
_: JClass<'_>, _: JClass<'_>,
height: jint, height: jint,
network_id: jint, network_id: jint,
) -> jint { ) -> jlong {
let res = panic::catch_unwind(|| { let res = panic::catch_unwind(|| {
let network = parse_network(network_id as u32)?; let network = parse_network(network_id as u32)?;
let branch: BranchId = BranchId::for_height(&network, BlockHeight::from(height as u32)); let branch: BranchId = BranchId::for_height(&network, BlockHeight::from(height as u32));
let branch_id: u32 = u32::from(branch); let branch_id: u32 = u32::from(branch);
debug!("For height {} found consensus branch {:?}", height, branch); debug!("For height {} found consensus branch {:?} with id {}", height, branch, branch_id);
Ok(branch_id as i32) Ok(branch_id.into())
}); });
unwrap_exc_or(&env, res, -1) unwrap_exc_or(&env, res, -1)
} }

View File

@ -106,7 +106,7 @@ version.com.google.protobuf..protobuf-gradle-plugin=0.8.16
version.com.nhaarman.mockitokotlin2..mockito-kotlin=2.2.0 version.com.nhaarman.mockitokotlin2..mockito-kotlin=2.2.0
version.com.vanniktech..gradle-maven-publish-plugin=0.14.2 version.com.vanniktech..gradle-maven-publish-plugin=0.15.0
version.io.grpc..grpc-android=1.37.0 version.io.grpc..grpc-android=1.37.0
@ -124,8 +124,12 @@ version.kotlin=1.4.32
## # available=1.5.0-M1 ## # available=1.5.0-M1
## # available=1.5.0-M2 ## # available=1.5.0-M2
## # available=1.5.0-RC ## # available=1.5.0-RC
## # available=1.5.0
version.kotlinx.coroutines=1.4.2 version.kotlinx.coroutines=1.4.2
## # available=1.4.3-native-mt
## # available=1.4.3
## # available=1.5.0-RC
version.org.jetbrains.dokka..dokka-gradle-plugin=1.4.32 version.org.jetbrains.dokka..dokka-gradle-plugin=1.4.32
@ -138,10 +142,10 @@ version.org.junit.jupiter..junit-jupiter-engine=5.7.1
version.org.junit.jupiter..junit-jupiter-migrationsupport=5.7.1 version.org.junit.jupiter..junit-jupiter-migrationsupport=5.7.1
## # available=5.8.0-M1 ## # available=5.8.0-M1
version.org.mockito..mockito-android=3.8.0 version.org.mockito..mockito-android=3.9.0
version.org.mockito..mockito-junit-jupiter=3.8.0 version.org.mockito..mockito-junit-jupiter=3.9.0
version.org.owasp..dependency-check-gradle=6.1.5 version.org.owasp..dependency-check-gradle=6.1.6
version.ru.gildor.coroutines..kotlin-coroutines-okhttp=1.0 version.ru.gildor.coroutines..kotlin-coroutines-okhttp=1.0