Merge pull request #225 from zcash/hotfix/1.3.0-beta06
Hotfix/1.3.0 beta06
This commit is contained in:
commit
fb2e9cff51
|
@ -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.
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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'
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 ->
|
||||||
|
|
|
@ -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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"network": "main",
|
|
||||||
"height": 1225000,
|
|
||||||
"hash": "0000000001977934324bddde1888c658b0faf997d91b36125d42b4a394ce94d5",
|
|
||||||
"time": 1619171235,
|
|
||||||
"tree": "010b90d9e211f1a12634595a2b7a3899abb0fb46aada6a88a1d5fe4732286cff1c00130000016671cff0e2881f9923d85952f6116d3855918016e8ef2951040a0ace61b8883e0000000000000134ca9a7c4309349dfe003f3b4b95898b4303631e9be3a25b4e917a4f3472b52f00000121c25bceccda091622bfac1b7973ffaa638abe1f334b3b56f48dc93dc549c9070001ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"network": "main",
|
||||||
|
"height": 1230000,
|
||||||
|
"hash": "0000000001bcfbeb53fd5e9647168265bc5fc8e8622049b9cdd07098f0f51601",
|
||||||
|
"time": 1619548843,
|
||||||
|
"tree": "0164566f774ea1f6d7cf21a9fbf9cb3f2e7d1e400097417822a7c233422619c3710013000001bad8de55d9adf4d4ff08f4ad172a5ee80aa0049974c5227d2b07474078f73c2a01e8d5303b72f034efacb9b9aa0697aa5568bf6116f2fdc1e528c03b76ce569c340000000000015334d52667d65b8ff3dcfb3d6ed72c46ad19ea9112813aaf344a3e614eb9012600016cad8c39b711691f2bda74017894c657555a8bf7ef913931ac4f7ba0b48a30120121c25bceccda091622bfac1b7973ffaa638abe1f334b3b56f48dc93dc549c9070001ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
|
||||||
|
}
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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" +
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue