New: Explicitly declare network when needed.
It is important to be very explicit about the network and not make any assumptions for ease of use because that resulted in numerous bugs while transitioning away from the old two library setup. squash explicit network
This commit is contained in:
parent
9dd9eef9ee
commit
af190e786b
|
@ -27,12 +27,14 @@ import org.mockito.Spy
|
|||
@RunWith(AndroidJUnit4::class)
|
||||
class ChangeServiceTest : ScopedTest() {
|
||||
|
||||
val network = ZcashNetwork.Mainnet
|
||||
|
||||
@Mock
|
||||
lateinit var mockBlockStore: CompactBlockStore
|
||||
var mockCloseable: AutoCloseable? = null
|
||||
|
||||
@Spy
|
||||
val service = LightWalletGrpcService(context, ZcashSdk.DEFAULT_LIGHTWALLETD_HOST)
|
||||
val service = LightWalletGrpcService(context, network)
|
||||
|
||||
lateinit var downloader: CompactBlockDownloader
|
||||
lateinit var otherService: LightWalletService
|
||||
|
@ -105,7 +107,7 @@ class ChangeServiceTest : ScopedTest() {
|
|||
@Test
|
||||
fun testSwitchToTestnetFails() = runBlocking {
|
||||
var caughtException: Throwable? = null
|
||||
downloader.changeService(LightWalletGrpcService(context, "testnet.lightwalletd.com", 9067)) {
|
||||
downloader.changeService(LightWalletGrpcService(context, ZcashNetwork.Testnet)) {
|
||||
caughtException = it
|
||||
}
|
||||
assertNotNull("Using an invalid host should generate an exception.", caughtException)
|
||||
|
|
|
@ -17,34 +17,41 @@ import org.junit.runner.RunWith
|
|||
class TransparentTest {
|
||||
|
||||
lateinit var expected: Expected
|
||||
lateinit var network: ZcashNetwork
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
expected = if (BuildConfig.FLAVOR == "zcashtestnet") ExpectedTestnet else ExpectedMainnet
|
||||
if (BuildConfig.FLAVOR == "zcashtestnet") {
|
||||
expected = ExpectedTestnet
|
||||
network = ZcashNetwork.Testnet
|
||||
} else {
|
||||
expected = ExpectedMainnet
|
||||
network = ZcashNetwork.Mainnet
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deriveTransparentSecretKeyTest() {
|
||||
assertEquals(expected.tskCompressed, DerivationTool.deriveTransparentSecretKey(SEED))
|
||||
assertEquals(expected.tskCompressed, DerivationTool.deriveTransparentSecretKey(SEED, network = network))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deriveTransparentAddressTest() {
|
||||
assertEquals(expected.tAddr, DerivationTool.deriveTransparentAddress(SEED))
|
||||
assertEquals(expected.tAddr, DerivationTool.deriveTransparentAddress(SEED, network = network))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deriveTransparentAddressFromSecretKeyTest() {
|
||||
assertEquals(expected.tAddr, DerivationTool.deriveTransparentAddressFromPrivateKey(expected.tskCompressed))
|
||||
assertEquals(expected.tAddr, DerivationTool.deriveTransparentAddressFromPrivateKey(expected.tskCompressed, network = network))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deriveUnifiedViewingKeysFromSeedTest() {
|
||||
val uvks = DerivationTool.deriveUnifiedViewingKeys(SEED)
|
||||
val uvks = DerivationTool.deriveUnifiedViewingKeys(SEED, network = network)
|
||||
assertEquals(1, uvks.size)
|
||||
val uvk = uvks.first()
|
||||
assertEquals(expected.zAddr, DerivationTool.deriveShieldedAddress(uvk.extfvk))
|
||||
assertEquals(expected.tAddr, DerivationTool.deriveTransparentAddressFromPublicKey(uvk.extpub))
|
||||
assertEquals(expected.zAddr, DerivationTool.deriveShieldedAddress(uvk.extfvk, network = network))
|
||||
assertEquals(expected.tAddr, DerivationTool.deriveTransparentAddressFromPublicKey(uvk.extpub, network = network))
|
||||
}
|
||||
|
||||
// @Test
|
||||
|
|
|
@ -56,17 +56,17 @@ class ShieldFundsSample {
|
|||
)
|
||||
private val context = InstrumentationRegistry.getInstrumentation().context
|
||||
private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
||||
private val shieldedSpendingKey = DerivationTool.deriveSpendingKeys(seed)[0]
|
||||
private val transparentSecretKey = DerivationTool.deriveTransparentSecretKey(seed)
|
||||
private val shieldedAddress = DerivationTool.deriveShieldedAddress(seed)
|
||||
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)
|
||||
private val transparentAddress = DerivationTool.deriveTransparentAddress(seed, Testnet)
|
||||
|
||||
private val config = Initializer.Config {
|
||||
it.setSeed(seed)
|
||||
it.setSeed(seed, Testnet)
|
||||
it.setBirthdayHeight(startHeight, false)
|
||||
it.server("lightwalletd.electriccoin.co", 9067)
|
||||
it.setNetwork(Testnet, host)
|
||||
}
|
||||
|
||||
val synchronizer = Synchronizer(Initializer(context, config))
|
||||
|
|
|
@ -2,6 +2,7 @@ package cash.z.ecc.android.sdk.util
|
|||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
@ -35,7 +36,7 @@ class AddressGeneratorUtil {
|
|||
.map { seedPhrase ->
|
||||
mnemonics.toSeed(seedPhrase.toCharArray())
|
||||
}.map { seed ->
|
||||
DerivationTool.deriveShieldedAddress(seed)
|
||||
DerivationTool.deriveShieldedAddress(seed, ZcashNetwork.Mainnet)
|
||||
}.collect { address ->
|
||||
println("xrxrx2\t$address")
|
||||
assertTrue(address.startsWith("zs1"))
|
||||
|
|
|
@ -8,6 +8,7 @@ import cash.z.ecc.android.sdk.ext.Twig
|
|||
import cash.z.ecc.android.sdk.ext.twig
|
||||
import cash.z.ecc.android.sdk.tool.WalletBirthdayTool
|
||||
import cash.z.ecc.android.sdk.type.WalletBirthday
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
@ -26,8 +27,7 @@ import java.io.IOException
|
|||
@ExperimentalCoroutinesApi
|
||||
class BalancePrinterUtil {
|
||||
|
||||
private val host = "lightd-main.zecwallet.co"
|
||||
private val port = 443
|
||||
private val network = ZcashNetwork.Mainnet
|
||||
private val downloadBatchSize = 9_000
|
||||
private val birthdayHeight = 523240
|
||||
|
||||
|
@ -52,7 +52,7 @@ class BalancePrinterUtil {
|
|||
fun setup() {
|
||||
Twig.plant(TroubleshootingTwig())
|
||||
cacheBlocks()
|
||||
birthday = WalletBirthdayTool.loadNearest(context, birthdayHeight)
|
||||
birthday = WalletBirthdayTool.loadNearest(context, network, birthdayHeight)
|
||||
}
|
||||
|
||||
private fun cacheBlocks() = runBlocking {
|
||||
|
@ -80,7 +80,7 @@ class BalancePrinterUtil {
|
|||
// TODO: clear the dataDb but leave the cacheDb
|
||||
val initializer = Initializer(context) { config ->
|
||||
config.importWallet(seed, birthdayHeight)
|
||||
config.server(host, port)
|
||||
config.setNetwork(network)
|
||||
config.alias = alias
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -2,9 +2,9 @@ package cash.z.ecc.android.sdk.util
|
|||
|
||||
import android.content.Context
|
||||
import cash.z.ecc.android.sdk.R
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||
import cash.z.ecc.android.sdk.ext.twig
|
||||
import cash.z.ecc.android.sdk.service.LightWalletGrpcService
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import cash.z.wallet.sdk.rpc.Darkside
|
||||
import cash.z.wallet.sdk.rpc.Darkside.DarksideTransactionsURL
|
||||
import cash.z.wallet.sdk.rpc.DarksideStreamerGrpc
|
||||
|
@ -23,7 +23,7 @@ class DarksideApi(
|
|||
constructor(
|
||||
appContext: Context,
|
||||
host: String,
|
||||
port: Int = ZcashSdk.DEFAULT_LIGHTWALLETD_PORT,
|
||||
port: Int = ZcashNetwork.Mainnet.defaultPort,
|
||||
usePlainText: Boolean = appContext.resources.getBoolean(
|
||||
R.bool.lightwalletd_allow_very_insecure_connections
|
||||
)
|
||||
|
@ -42,8 +42,8 @@ class DarksideApi(
|
|||
|
||||
fun reset(
|
||||
saplingActivationHeight: Int = 419200,
|
||||
branchId: String = "2bb40e60", // Blossom,
|
||||
chainName: String = "darkside"
|
||||
branchId: String = "e9ff75a6", // Canopy,
|
||||
chainName: String = "darkside${ZcashNetwork.Mainnet.networkName}"
|
||||
) = apply {
|
||||
twig("resetting darksidewalletd with saplingActivation=$saplingActivationHeight branchId=$branchId chainName=$chainName")
|
||||
Darkside.DarksideMetaState.newBuilder()
|
||||
|
|
|
@ -8,6 +8,7 @@ import cash.z.ecc.android.sdk.ext.Twig
|
|||
import cash.z.ecc.android.sdk.ext.seedPhrase
|
||||
import cash.z.ecc.android.sdk.ext.twig
|
||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import io.grpc.StatusRuntimeException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
|
@ -21,8 +22,7 @@ import org.junit.Assert
|
|||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
|
||||
class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: String = "DarksideTestCoordinator") {
|
||||
private val port = 9067
|
||||
class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: String = "DarksideTestCoordinator", val network: ZcashNetwork = ZcashNetwork.Mainnet, val port: Int = 9067) {
|
||||
private val birthdayHeight = 663150
|
||||
private val targetHeight = 663250
|
||||
private val seedPhrase =
|
||||
|
@ -38,7 +38,7 @@ class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: Stri
|
|||
// var initializer = Initializer(context, Initializer.Builder(host, port, testName))
|
||||
lateinit var synchronizer: SdkSynchronizer
|
||||
|
||||
val spendingKey: String get() = DerivationTool.deriveSpendingKeys(SimpleMnemonics().toSeed(seedPhrase.toCharArray()))[0]
|
||||
val spendingKey: String get() = DerivationTool.deriveSpendingKeys(SimpleMnemonics().toSeed(seedPhrase.toCharArray()), network)[0]
|
||||
|
||||
//
|
||||
// High-level APIs
|
||||
|
@ -75,7 +75,8 @@ class DarksideTestCoordinator(val host: String = "127.0.0.1", val testName: Stri
|
|||
fun initiate() {
|
||||
twig("*************** INITIALIZING TEST COORDINATOR (ONLY ONCE) ***********************")
|
||||
val initializer = Initializer(context) { config ->
|
||||
config.seedPhrase(seedPhrase)
|
||||
config.setNetwork(network, host, port)
|
||||
config.seedPhrase(seedPhrase, network)
|
||||
config.setBirthdayHeight(birthdayHeight)
|
||||
config.alias = testName
|
||||
}
|
||||
|
|
|
@ -3,16 +3,17 @@ package cash.z.ecc.android.sdk.util
|
|||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import cash.z.ecc.android.sdk.ext.TroubleshootingTwig
|
||||
import cash.z.ecc.android.sdk.ext.Twig
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||
import cash.z.ecc.android.sdk.ext.twig
|
||||
import cash.z.ecc.android.sdk.service.LightWalletGrpcService
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
|
||||
class TransactionCounterUtil {
|
||||
|
||||
private val network = ZcashNetwork.Mainnet
|
||||
private val context = InstrumentationRegistry.getInstrumentation().context
|
||||
private val service = LightWalletGrpcService(context, ZcashSdk.DEFAULT_LIGHTWALLETD_HOST, ZcashSdk.DEFAULT_LIGHTWALLETD_PORT)
|
||||
private val service = LightWalletGrpcService(context, network)
|
||||
|
||||
init {
|
||||
Twig.plant(TroubleshootingTwig())
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.io.File
|
|||
class Initializer constructor(appContext: Context, config: Config) : SdkSynchronizer.SdkInitializer {
|
||||
override val context = appContext.applicationContext
|
||||
override val rustBackend: RustBackend
|
||||
override val network: ZcashNetwork
|
||||
override val alias: String
|
||||
override val host: String
|
||||
override val port: Int
|
||||
|
@ -35,28 +36,30 @@ class Initializer constructor(appContext: Context, config: Config) : SdkSynchron
|
|||
|
||||
init {
|
||||
config.validate()
|
||||
network = config.network
|
||||
val heightToUse = config.birthdayHeight
|
||||
?: (if (config.defaultToOldestHeight == true) SAPLING_ACTIVATION_HEIGHT else null)
|
||||
val loadedBirthday = WalletBirthdayTool.loadNearest(context, heightToUse)
|
||||
val loadedBirthday = WalletBirthdayTool.loadNearest(context, network, heightToUse)
|
||||
birthday = loadedBirthday
|
||||
viewingKeys = config.viewingKeys
|
||||
alias = config.alias
|
||||
host = config.host
|
||||
port = config.port
|
||||
rustBackend = initRustBackend(birthday)
|
||||
rustBackend = initRustBackend(network, birthday)
|
||||
// TODO: get rid of this by first answering the question: why is this necessary?
|
||||
initMissingDatabases(birthday, *viewingKeys.toTypedArray())
|
||||
}
|
||||
|
||||
constructor(appContext: Context, block: (Config) -> Unit) : this(appContext, Config(block))
|
||||
|
||||
fun erase() = erase(context, alias)
|
||||
fun erase() = erase(context, network, alias)
|
||||
|
||||
private fun initRustBackend(birthday: WalletBirthday): RustBackend {
|
||||
private fun initRustBackend(network: ZcashNetwork, birthday: WalletBirthday): RustBackend {
|
||||
return RustBackend.init(
|
||||
cacheDbPath(context, alias),
|
||||
dataDbPath(context, alias),
|
||||
cacheDbPath(context, network, alias),
|
||||
dataDbPath(context, network, alias),
|
||||
"${context.cacheDir.absolutePath}/params",
|
||||
network,
|
||||
birthday.height
|
||||
)
|
||||
}
|
||||
|
@ -137,12 +140,19 @@ class Initializer constructor(appContext: Context, config: Config) : SdkSynchron
|
|||
class Config private constructor (
|
||||
val viewingKeys: MutableList<UnifiedViewingKey> = mutableListOf(),
|
||||
var alias: String = ZcashSdk.DEFAULT_ALIAS,
|
||||
var host: String = ZcashSdk.DEFAULT_LIGHTWALLETD_HOST,
|
||||
var port: Int = ZcashSdk.DEFAULT_LIGHTWALLETD_PORT,
|
||||
) {
|
||||
var birthdayHeight: Int? = null
|
||||
private set
|
||||
|
||||
lateinit var network: ZcashNetwork
|
||||
private set
|
||||
|
||||
lateinit var host: String
|
||||
private set
|
||||
|
||||
var port: Int = ZcashNetwork.Mainnet.defaultPort
|
||||
private set
|
||||
|
||||
/**
|
||||
* Determines the default behavior for null birthdays. When null, nothing has been specified
|
||||
* so a null birthdayHeight value is an error. When false, null birthdays will be replaced
|
||||
|
@ -229,53 +239,112 @@ class Initializer constructor(appContext: Context, config: Config) : SdkSynchron
|
|||
// Convenience functions
|
||||
//
|
||||
|
||||
fun server(host: String, port: Int): Config = apply {
|
||||
/**
|
||||
* Set the server and the network property at the same time to prevent them from getting out
|
||||
* of sync. Ultimately, this determines which host a synchronizer will use in order to
|
||||
* connect to lightwalletd. In most cases, the default host is sufficient but an override
|
||||
* can be provided. The host cannot be changed without explicitly setting the network.
|
||||
*
|
||||
* @param network the Zcash network to use. Either testnet or mainnet.
|
||||
* @param host the lightwalletd host to use.
|
||||
* @param port the lightwalletd port to use.
|
||||
*/
|
||||
fun setNetwork(
|
||||
network: ZcashNetwork,
|
||||
host: String = network.defaultHost,
|
||||
port: Int = network.defaultPort
|
||||
): Config = apply {
|
||||
this.network = network
|
||||
this.host = host
|
||||
this.port = port
|
||||
}
|
||||
|
||||
fun importWallet(seed: ByteArray, birthdayHeight: Int? = null): Config = apply {
|
||||
setSeed(seed)
|
||||
importedWalletBirthday(birthdayHeight)
|
||||
}
|
||||
/**
|
||||
* Import a wallet using the first viewing key derived from the given seed.
|
||||
*/
|
||||
fun importWallet(
|
||||
seed: ByteArray,
|
||||
birthdayHeight: Int? = null,
|
||||
network: ZcashNetwork,
|
||||
host: String = network.defaultHost,
|
||||
port: Int = network.defaultPort,
|
||||
alias: String = ZcashSdk.DEFAULT_ALIAS
|
||||
): Config =
|
||||
importWallet(
|
||||
DerivationTool.deriveUnifiedViewingKeys(seed, network = network)[0],
|
||||
birthdayHeight,
|
||||
network,
|
||||
host,
|
||||
port,
|
||||
alias
|
||||
)
|
||||
|
||||
/**
|
||||
* Default function for importing a wallet.
|
||||
*/
|
||||
fun importWallet(
|
||||
viewingKey: UnifiedViewingKey,
|
||||
birthdayHeight: Int? = null,
|
||||
host: String = ZcashSdk.DEFAULT_LIGHTWALLETD_HOST,
|
||||
port: Int = ZcashSdk.DEFAULT_LIGHTWALLETD_PORT
|
||||
network: ZcashNetwork,
|
||||
host: String = network.defaultHost,
|
||||
port: Int = network.defaultPort,
|
||||
alias: String = ZcashSdk.DEFAULT_ALIAS
|
||||
): Config = apply {
|
||||
setViewingKeys(viewingKey)
|
||||
server(host, port)
|
||||
setNetwork(network, host, port)
|
||||
importedWalletBirthday(birthdayHeight)
|
||||
this.alias = alias
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new wallet using the first viewing key derived from the given seed.
|
||||
*/
|
||||
fun newWallet(
|
||||
seed: ByteArray,
|
||||
host: String = ZcashSdk.DEFAULT_LIGHTWALLETD_HOST,
|
||||
port: Int = ZcashSdk.DEFAULT_LIGHTWALLETD_PORT
|
||||
): Config = apply {
|
||||
setSeed(seed)
|
||||
server(host, port)
|
||||
newWalletBirthday()
|
||||
}
|
||||
network: ZcashNetwork,
|
||||
host: String = network.defaultHost,
|
||||
port: Int = network.defaultPort,
|
||||
alias: String = ZcashSdk.DEFAULT_ALIAS
|
||||
): Config = newWallet(
|
||||
DerivationTool.deriveUnifiedViewingKeys(seed, network)[0],
|
||||
network,
|
||||
host,
|
||||
port,
|
||||
alias
|
||||
)
|
||||
|
||||
/**
|
||||
* Default function for creating a new wallet.
|
||||
*/
|
||||
fun newWallet(
|
||||
viewingKey: UnifiedViewingKey,
|
||||
host: String = ZcashSdk.DEFAULT_LIGHTWALLETD_HOST,
|
||||
port: Int = ZcashSdk.DEFAULT_LIGHTWALLETD_PORT
|
||||
network: ZcashNetwork,
|
||||
host: String = network.defaultHost,
|
||||
port: Int = network.defaultPort,
|
||||
alias: String = ZcashSdk.DEFAULT_ALIAS
|
||||
): Config = apply {
|
||||
setViewingKeys(viewingKey)
|
||||
server(host, port)
|
||||
setNetwork(network, host, port)
|
||||
newWalletBirthday()
|
||||
this.alias = alias
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for setting thew viewingKeys from a given seed. This is the same as
|
||||
* calling `setViewingKeys` with the keys that match this seed.
|
||||
*/
|
||||
fun setSeed(seed: ByteArray, numberOfAccounts: Int = 1): Config = apply {
|
||||
setViewingKeys(*DerivationTool.deriveUnifiedViewingKeys(seed, numberOfAccounts))
|
||||
fun setSeed(seed: ByteArray, network: ZcashNetwork, numberOfAccounts: Int = 1): Config = apply {
|
||||
setViewingKeys(*DerivationTool.deriveUnifiedViewingKeys(seed, network, numberOfAccounts))
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the network from a network id, throwing an exception if the id is not recognized.
|
||||
*
|
||||
* @param networkId the ID of the network corresponding to the [ZcashNetwork] enum.
|
||||
* Typically, it is 0 for testnet and 1 for mainnet.
|
||||
*/
|
||||
fun setNetworkId(networkId: Int): Config = apply {
|
||||
network = ZcashNetwork.from(networkId)
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -299,7 +368,7 @@ class Initializer constructor(appContext: Context, config: Config) : SdkSynchron
|
|||
(birthdayHeight ?: SAPLING_ACTIVATION_HEIGHT)
|
||||
< SAPLING_ACTIVATION_HEIGHT
|
||||
) {
|
||||
throw InitializerException.InvalidBirthdayHeightException(birthdayHeight)
|
||||
throw InitializerException.InvalidBirthdayHeightException(birthdayHeight, network)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,13 +393,17 @@ class Initializer constructor(appContext: Context, config: Config) : SdkSynchron
|
|||
* managed separately by the wallet.
|
||||
*
|
||||
* @param appContext the application context.
|
||||
* @param network the network associated with the data to be erased.
|
||||
* @param alias the alias used to create the local data.
|
||||
*
|
||||
* @return true when associated files were found. False most likely indicates that the wrong
|
||||
* alias was provided.
|
||||
* @return true when one of the associated files was found. False most likely indicates
|
||||
* that the wrong alias was provided.
|
||||
*/
|
||||
override fun erase(appContext: Context, alias: String) =
|
||||
delete(cacheDbPath(appContext, alias)) || delete(dataDbPath(appContext, alias))
|
||||
override fun erase(appContext: Context, network: ZcashNetwork, alias: String): Boolean {
|
||||
val cacheDeleted = deleteDb(cacheDbPath(appContext, network, alias))
|
||||
val dataDeleted = deleteDb(dataDbPath(appContext, network, alias))
|
||||
return dataDeleted || cacheDeleted
|
||||
}
|
||||
|
||||
//
|
||||
// Path Helpers
|
||||
|
@ -340,25 +413,29 @@ class Initializer constructor(appContext: Context, config: Config) : SdkSynchron
|
|||
* Returns the path to the cache database that would correspond to the given alias.
|
||||
*
|
||||
* @param appContext the application context
|
||||
* @param network the network associated with the data in the cache database.
|
||||
* @param alias the alias to convert into a database path
|
||||
*/
|
||||
internal fun cacheDbPath(appContext: Context, alias: String): String =
|
||||
aliasToPath(appContext, alias, ZcashSdk.DB_CACHE_NAME)
|
||||
internal fun cacheDbPath(appContext: Context, network: ZcashNetwork, alias: String): String =
|
||||
aliasToPath(appContext, network, alias, ZcashSdk.DB_CACHE_NAME)
|
||||
|
||||
/**
|
||||
* Returns the path to the data database that would correspond to the given alias.
|
||||
* @param appContext the application context
|
||||
* * @param network the network associated with the data in the database.
|
||||
* @param alias the alias to convert into a database path
|
||||
*/
|
||||
internal fun dataDbPath(appContext: Context, alias: String): String =
|
||||
aliasToPath(appContext, alias, ZcashSdk.DB_DATA_NAME)
|
||||
internal fun dataDbPath(appContext: Context, network: ZcashNetwork, alias: String): String =
|
||||
aliasToPath(appContext, network, alias, ZcashSdk.DB_DATA_NAME)
|
||||
|
||||
private fun aliasToPath(appContext: Context, alias: String, dbFileName: String): String {
|
||||
private fun aliasToPath(appContext: Context, network: ZcashNetwork, alias: String, dbFileName: String): String {
|
||||
val parentDir: String =
|
||||
appContext.getDatabasePath("unused.db").parentFile?.absolutePath
|
||||
?: throw InitializerException.DatabasePathException
|
||||
val prefix = if (alias.endsWith('_')) alias else "${alias}_"
|
||||
return File(parentDir, "$prefix$dbFileName").absolutePath
|
||||
return File(parentDir, "$prefix${network.networkName}_$dbFileName").absolutePath
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -398,16 +475,6 @@ internal fun validateAlias(alias: String) {
|
|||
alias.all { it.isLetterOrDigit() || it == '_' }
|
||||
) {
|
||||
"ERROR: Invalid alias ($alias). For security, the alias must be shorter than 100 " +
|
||||
"characters and only contain letters, digits or underscores and start with a letter; " +
|
||||
"ideally, it would also differentiate across mainnet and testnet but that is not " +
|
||||
"enforced."
|
||||
}
|
||||
|
||||
// TODO: consider exposing this as a proper warning that can be received by apps, since most apps won't use logging
|
||||
if (alias.toLowerCase().contains(BuildConfig.FLAVOR.toLowerCase())) {
|
||||
twig(
|
||||
"WARNING: alias does not contain the build flavor but it probably should to help" +
|
||||
" prevent testnet data from contaminating mainnet data."
|
||||
)
|
||||
"characters and only contain letters, digits or underscores and start with a letter."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import cash.z.ecc.android.sdk.type.AddressType.Shielded
|
|||
import cash.z.ecc.android.sdk.type.AddressType.Transparent
|
||||
import cash.z.ecc.android.sdk.type.ConsensusMatchType
|
||||
import cash.z.ecc.android.sdk.type.WalletBalance
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import cash.z.wallet.sdk.rpc.Service
|
||||
import io.grpc.ManagedChannel
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
|
@ -146,6 +147,8 @@ class SdkSynchronizer internal constructor(
|
|||
// Status
|
||||
//
|
||||
|
||||
override val network: ZcashNetwork get() = processor.network
|
||||
|
||||
/**
|
||||
* Indicates the status of this Synchronizer. This implementation basically simplifies the
|
||||
* status of the processor to focus only on the high level states that matter most. Whenever the
|
||||
|
@ -608,7 +611,7 @@ class SdkSynchronizer internal constructor(
|
|||
memo: String
|
||||
): Flow<PendingTransaction> = flow {
|
||||
twig("Initializing shielding transaction")
|
||||
val tAddr = DerivationTool.deriveTransparentAddressFromPrivateKey(transparentSecretKey)
|
||||
val tAddr = DerivationTool.deriveTransparentAddressFromPrivateKey(transparentSecretKey, network)
|
||||
val tBalance = processor.getUtxoCacheBalance(tAddr)
|
||||
val zAddr = getAddress(0)
|
||||
|
||||
|
@ -677,6 +680,7 @@ class SdkSynchronizer internal constructor(
|
|||
interface SdkInitializer {
|
||||
val context: Context
|
||||
val rustBackend: RustBackend
|
||||
val network: ZcashNetwork
|
||||
val host: String
|
||||
val port: Int
|
||||
val alias: String
|
||||
|
@ -687,12 +691,14 @@ class SdkSynchronizer internal constructor(
|
|||
* Erase content related to this SDK.
|
||||
*
|
||||
* @param appContext the application context.
|
||||
* @param network the network corresponding to the data being erased. Data is segmented by
|
||||
* network in order to prevent contamination.
|
||||
* @param alias identifier for SDK content. It is possible for multiple synchronizers to
|
||||
* exist with different aliases.
|
||||
*
|
||||
* @return true when content was found for the given alias. False otherwise.
|
||||
*/
|
||||
fun erase(appContext: Context, alias: String = ZcashSdk.DEFAULT_ALIAS): Boolean
|
||||
fun erase(appContext: Context, network: ZcashNetwork, alias: String = ZcashSdk.DEFAULT_ALIAS): Boolean
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import cash.z.ecc.android.sdk.ext.ZcashSdk
|
|||
import cash.z.ecc.android.sdk.type.AddressType
|
||||
import cash.z.ecc.android.sdk.type.ConsensusMatchType
|
||||
import cash.z.ecc.android.sdk.type.WalletBalance
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import cash.z.wallet.sdk.rpc.Service
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -58,6 +59,11 @@ interface Synchronizer {
|
|||
|
||||
/* Status */
|
||||
|
||||
/**
|
||||
* The network to which this synchronizer is connected and from which it is processing blocks.
|
||||
*/
|
||||
val network: ZcashNetwork
|
||||
|
||||
/**
|
||||
* A flow of values representing the [Status] of this Synchronizer. As the status changes, a new
|
||||
* value will be emitted by this flow.
|
||||
|
@ -264,7 +270,7 @@ interface Synchronizer {
|
|||
*/
|
||||
suspend fun changeServer(
|
||||
host: String,
|
||||
port: Int = ZcashSdk.DEFAULT_LIGHTWALLETD_PORT,
|
||||
port: Int = network.defaultPort,
|
||||
errorHandler: (Throwable) -> Unit = { throw it }
|
||||
)
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import cash.z.ecc.android.sdk.ext.twig
|
|||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||
import cash.z.ecc.android.sdk.type.UnifiedViewingKey
|
||||
import cash.z.ecc.android.sdk.type.WalletBalance
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
|
@ -28,6 +29,8 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
lateinit var pathParamsDir: String
|
||||
internal set
|
||||
|
||||
override lateinit var network: ZcashNetwork
|
||||
|
||||
internal var birthdayHeight: Int = -1
|
||||
get() = if (field != -1) field else throw BirthdayException.UninitializedBirthdayException
|
||||
private set
|
||||
|
@ -47,7 +50,7 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
// Wrapper Functions
|
||||
//
|
||||
|
||||
override fun initDataDb() = initDataDb(pathDataDb)
|
||||
override fun initDataDb() = initDataDb(pathDataDb, networkId = network.id)
|
||||
|
||||
override fun initAccountsTable(vararg keys: UnifiedViewingKey): Boolean {
|
||||
val extfvks = Array(keys.size) { "" }
|
||||
|
@ -56,14 +59,14 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
extfvks[i] = key.extfvk
|
||||
extpubs[i] = key.extpub
|
||||
}
|
||||
return initAccountsTableWithKeys(pathDataDb, extfvks, extpubs)
|
||||
return initAccountsTableWithKeys(pathDataDb, extfvks, extpubs, networkId = network.id)
|
||||
}
|
||||
|
||||
override fun initAccountsTable(
|
||||
seed: ByteArray,
|
||||
numberOfAccounts: Int
|
||||
): Array<UnifiedViewingKey> {
|
||||
return DerivationTool.deriveUnifiedViewingKeys(seed, numberOfAccounts).apply {
|
||||
return DerivationTool.deriveUnifiedViewingKeys(seed, network, numberOfAccounts).apply {
|
||||
initAccountsTable(*this)
|
||||
}
|
||||
}
|
||||
|
@ -74,37 +77,38 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
time: Long,
|
||||
saplingTree: String
|
||||
): Boolean {
|
||||
return initBlocksTable(pathDataDb, height, hash, time, saplingTree)
|
||||
return initBlocksTable(pathDataDb, height, hash, time, saplingTree, networkId = network.id)
|
||||
}
|
||||
|
||||
override fun getShieldedAddress(account: Int) = getShieldedAddress(pathDataDb, account)
|
||||
override fun getShieldedAddress(account: Int) = getShieldedAddress(pathDataDb, account, networkId = network.id)
|
||||
|
||||
override fun getTransparentAddress(account: Int, index: Int): String {
|
||||
throw NotImplementedError("TODO: implement this at the zcash_client_sqlite level. But for now, use DerivationTool, instead to derive addresses from seeds")
|
||||
}
|
||||
|
||||
override fun getBalance(account: Int) = getBalance(pathDataDb, account)
|
||||
override fun getBalance(account: Int) = getBalance(pathDataDb, account, networkId = network.id)
|
||||
|
||||
override fun getVerifiedBalance(account: Int) = getVerifiedBalance(pathDataDb, account)
|
||||
override fun getVerifiedBalance(account: Int) = getVerifiedBalance(pathDataDb, account, networkId = network.id)
|
||||
|
||||
override fun getReceivedMemoAsUtf8(idNote: Long) =
|
||||
getReceivedMemoAsUtf8(pathDataDb, idNote)
|
||||
getReceivedMemoAsUtf8(pathDataDb, idNote, networkId = network.id)
|
||||
|
||||
override fun getSentMemoAsUtf8(idNote: Long) = getSentMemoAsUtf8(pathDataDb, idNote)
|
||||
override fun getSentMemoAsUtf8(idNote: Long) = getSentMemoAsUtf8(pathDataDb, idNote, networkId = network.id)
|
||||
|
||||
override fun validateCombinedChain() = validateCombinedChain(pathCacheDb, pathDataDb)
|
||||
override fun validateCombinedChain() = validateCombinedChain(pathCacheDb, pathDataDb, networkId = network.id,)
|
||||
|
||||
override fun rewindToHeight(height: Int) = rewindToHeight(pathDataDb, height)
|
||||
override fun rewindToHeight(height: Int) = rewindToHeight(pathDataDb, height, networkId = network.id)
|
||||
|
||||
override fun scanBlocks(limit: Int): Boolean {
|
||||
return if (limit > 0) {
|
||||
scanBlockBatch(pathCacheDb, pathDataDb, limit)
|
||||
scanBlockBatch(pathCacheDb, pathDataDb, limit, networkId = network.id)
|
||||
} else {
|
||||
scanBlocks(pathCacheDb, pathDataDb)
|
||||
scanBlocks(pathCacheDb, pathDataDb, networkId = network.id)
|
||||
}
|
||||
}
|
||||
|
||||
override fun decryptAndStoreTransaction(tx: ByteArray) = decryptAndStoreTransaction(pathDataDb, tx)
|
||||
override fun decryptAndStoreTransaction(tx: ByteArray) = decryptAndStoreTransaction(pathDataDb, tx, networkId = network.id)
|
||||
|
||||
override fun createToAddress(
|
||||
consensusBranchId: Long,
|
||||
|
@ -122,7 +126,8 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
value,
|
||||
memo ?: ByteArray(0),
|
||||
"$pathParamsDir/$SPEND_PARAM_FILE_NAME",
|
||||
"$pathParamsDir/$OUTPUT_PARAM_FILE_NAME"
|
||||
"$pathParamsDir/$OUTPUT_PARAM_FILE_NAME",
|
||||
networkId = network.id,
|
||||
)
|
||||
|
||||
override fun shieldToAddress(
|
||||
|
@ -138,7 +143,8 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
tsk,
|
||||
memo ?: ByteArray(0),
|
||||
"$pathParamsDir/$SPEND_PARAM_FILE_NAME",
|
||||
"$pathParamsDir/$OUTPUT_PARAM_FILE_NAME"
|
||||
"$pathParamsDir/$OUTPUT_PARAM_FILE_NAME",
|
||||
networkId = network.id,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -149,24 +155,24 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
script: ByteArray,
|
||||
value: Long,
|
||||
height: Int
|
||||
): Boolean = putUtxo(pathDataDb, tAddress, txId, index, script, value, height)
|
||||
): Boolean = putUtxo(pathDataDb, tAddress, txId, index, script, value, height, networkId = network.id)
|
||||
|
||||
override fun clearUtxos(
|
||||
tAddress: String,
|
||||
aboveHeight: Int,
|
||||
): Boolean = clearUtxos(pathDataDb, tAddress, aboveHeight)
|
||||
): Boolean = clearUtxos(pathDataDb, tAddress, aboveHeight, networkId = network.id)
|
||||
|
||||
override fun getDownloadedUtxoBalance(address: String): WalletBalance {
|
||||
val verified = getVerifiedTransparentBalance(pathDataDb, address)
|
||||
val total = getTotalTransparentBalance(pathDataDb, address)
|
||||
val verified = getVerifiedTransparentBalance(pathDataDb, address, networkId = network.id)
|
||||
val total = getTotalTransparentBalance(pathDataDb, address, networkId = network.id)
|
||||
return WalletBalance(total, verified)
|
||||
}
|
||||
|
||||
override fun isValidShieldedAddr(addr: String) = isValidShieldedAddress(addr)
|
||||
override fun isValidShieldedAddr(addr: String) = isValidShieldedAddress(addr, networkId = network.id)
|
||||
|
||||
override fun isValidTransparentAddr(addr: String) = isValidTransparentAddress(addr)
|
||||
override fun isValidTransparentAddr(addr: String) = isValidTransparentAddress(addr, networkId = network.id)
|
||||
|
||||
override fun getBranchIdForHeight(height: Int): Long = branchIdForHeight(height)
|
||||
override fun getBranchIdForHeight(height: Int): Long = branchIdForHeight(height, networkId = network.id)
|
||||
|
||||
// /**
|
||||
// * This is a proof-of-concept for doing Local RPC, where we are effectively using the JNI
|
||||
|
@ -201,12 +207,14 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
cacheDbPath: String,
|
||||
dataDbPath: String,
|
||||
paramsPath: String,
|
||||
zcashNetwork: ZcashNetwork,
|
||||
birthdayHeight: Int? = null
|
||||
): RustBackend {
|
||||
return RustBackend().apply {
|
||||
pathCacheDb = cacheDbPath
|
||||
pathDataDb = dataDbPath
|
||||
pathParamsDir = paramsPath
|
||||
network = zcashNetwork
|
||||
if (birthdayHeight != null) {
|
||||
this.birthdayHeight = birthdayHeight
|
||||
}
|
||||
|
@ -241,12 +249,13 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
// External Functions
|
||||
//
|
||||
|
||||
@JvmStatic private external fun initDataDb(dbDataPath: String): Boolean
|
||||
@JvmStatic private external fun initDataDb(dbDataPath: String, networkId: Int): Boolean
|
||||
|
||||
@JvmStatic private external fun initAccountsTableWithKeys(
|
||||
dbDataPath: String,
|
||||
extfvk: Array<out String>,
|
||||
extpub: Array<out String>,
|
||||
networkId: Int,
|
||||
): Boolean
|
||||
|
||||
@JvmStatic private external fun initBlocksTable(
|
||||
|
@ -254,34 +263,82 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
height: Int,
|
||||
hash: String,
|
||||
time: Long,
|
||||
saplingTree: String
|
||||
saplingTree: String,
|
||||
networkId: Int,
|
||||
): Boolean
|
||||
|
||||
@JvmStatic private external fun getShieldedAddress(dbDataPath: String, account: Int): String
|
||||
// TODO: implement this in the zcash_client_sqlite layer. For now, use DerivationTool, instead.
|
||||
// @JvmStatic private external fun getTransparentAddress(dbDataPath: String, account: Int): String
|
||||
@JvmStatic
|
||||
private external fun getShieldedAddress(
|
||||
dbDataPath: String,
|
||||
account: Int,
|
||||
networkId: Int,
|
||||
): String
|
||||
|
||||
@JvmStatic private external fun isValidShieldedAddress(addr: String): Boolean
|
||||
@JvmStatic
|
||||
private external fun isValidShieldedAddress(addr: String, networkId: Int): Boolean
|
||||
|
||||
@JvmStatic private external fun isValidTransparentAddress(addr: String): Boolean
|
||||
@JvmStatic
|
||||
private external fun isValidTransparentAddress(addr: String, networkId: Int): Boolean
|
||||
|
||||
@JvmStatic private external fun getBalance(dbDataPath: String, account: Int): Long
|
||||
@JvmStatic
|
||||
private external fun getBalance(dbDataPath: String, account: Int, networkId: Int): Long
|
||||
|
||||
@JvmStatic private external fun getVerifiedBalance(dbDataPath: String, account: Int): Long
|
||||
@JvmStatic
|
||||
private external fun getVerifiedBalance(
|
||||
dbDataPath: String,
|
||||
account: Int,
|
||||
networkId: Int,
|
||||
): Long
|
||||
|
||||
@JvmStatic private external fun getReceivedMemoAsUtf8(dbDataPath: String, idNote: Long): String
|
||||
@JvmStatic
|
||||
private external fun getReceivedMemoAsUtf8(
|
||||
dbDataPath: String,
|
||||
idNote: Long,
|
||||
networkId: Int,
|
||||
): String
|
||||
|
||||
@JvmStatic private external fun getSentMemoAsUtf8(dbDataPath: String, idNote: Long): String
|
||||
@JvmStatic
|
||||
private external fun getSentMemoAsUtf8(
|
||||
dbDataPath: String,
|
||||
dNote: Long,
|
||||
networkId: Int,
|
||||
): String
|
||||
|
||||
@JvmStatic private external fun validateCombinedChain(dbCachePath: String, dbDataPath: String): Int
|
||||
@JvmStatic
|
||||
private external fun validateCombinedChain(
|
||||
dbCachePath: String,
|
||||
dbDataPath: String,
|
||||
networkId: Int,
|
||||
): Int
|
||||
|
||||
@JvmStatic private external fun rewindToHeight(dbDataPath: String, height: Int): Boolean
|
||||
@JvmStatic
|
||||
private external fun rewindToHeight(
|
||||
dbDataPath: String,
|
||||
height: Int,
|
||||
networkId: Int,
|
||||
): Boolean
|
||||
|
||||
@JvmStatic private external fun scanBlocks(dbCachePath: String, dbDataPath: String): Boolean
|
||||
@JvmStatic
|
||||
private external fun scanBlocks(
|
||||
dbCachePath: String,
|
||||
dbDataPath: String,
|
||||
networkId: Int,
|
||||
): Boolean
|
||||
|
||||
@JvmStatic private external fun scanBlockBatch(dbCachePath: String, dbDataPath: String, limit: Int): Boolean
|
||||
@JvmStatic
|
||||
private external fun scanBlockBatch(
|
||||
dbCachePath: String,
|
||||
dbDataPath: String,
|
||||
limit: Int,
|
||||
networkId: Int,
|
||||
): Boolean
|
||||
|
||||
@JvmStatic private external fun decryptAndStoreTransaction(dbDataPath: String, tx: ByteArray)
|
||||
@JvmStatic
|
||||
private external fun decryptAndStoreTransaction(
|
||||
dbDataPath: String,
|
||||
tx: ByteArray,
|
||||
networkId: Int,
|
||||
)
|
||||
|
||||
@JvmStatic private external fun createToAddress(
|
||||
dbDataPath: String,
|
||||
|
@ -292,7 +349,8 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
value: Long,
|
||||
memo: ByteArray,
|
||||
spendParamsPath: String,
|
||||
outputParamsPath: String
|
||||
outputParamsPath: String,
|
||||
networkId: Int,
|
||||
): Long
|
||||
|
||||
@JvmStatic private external fun shieldToAddress(
|
||||
|
@ -302,12 +360,13 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
tsk: String,
|
||||
memo: ByteArray,
|
||||
spendParamsPath: String,
|
||||
outputParamsPath: String
|
||||
outputParamsPath: String,
|
||||
networkId: Int,
|
||||
): Long
|
||||
|
||||
@JvmStatic private external fun initLogs()
|
||||
|
||||
@JvmStatic private external fun branchIdForHeight(height: Int): Long
|
||||
@JvmStatic private external fun branchIdForHeight(height: Int, networkId: Int): Long
|
||||
|
||||
@JvmStatic private external fun putUtxo(
|
||||
dbDataPath: String,
|
||||
|
@ -316,23 +375,27 @@ class RustBackend private constructor() : RustBackendWelding {
|
|||
index: Int,
|
||||
script: ByteArray,
|
||||
value: Long,
|
||||
height: Int
|
||||
height: Int,
|
||||
networkId: Int,
|
||||
): Boolean
|
||||
|
||||
@JvmStatic private external fun clearUtxos(
|
||||
dbDataPath: String,
|
||||
tAddress: String,
|
||||
aboveHeight: Int,
|
||||
networkId: Int,
|
||||
): Boolean
|
||||
|
||||
@JvmStatic private external fun getVerifiedTransparentBalance(
|
||||
pathDataDb: String,
|
||||
taddr: String
|
||||
taddr: String,
|
||||
networkId: Int,
|
||||
): Long
|
||||
|
||||
@JvmStatic private external fun getTotalTransparentBalance(
|
||||
pathDataDb: String,
|
||||
taddr: String
|
||||
taddr: String,
|
||||
networkId: Int,
|
||||
): Long
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package cash.z.ecc.android.sdk.jni
|
||||
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||
import cash.z.ecc.android.sdk.type.UnifiedViewingKey
|
||||
import cash.z.ecc.android.sdk.type.WalletBalance
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
|
||||
/**
|
||||
* Contract defining the exposed capabilities of the Rust backend.
|
||||
|
@ -12,6 +12,8 @@ import cash.z.ecc.android.sdk.type.WalletBalance
|
|||
*/
|
||||
interface RustBackendWelding {
|
||||
|
||||
val network: ZcashNetwork
|
||||
|
||||
fun createToAddress(
|
||||
consensusBranchId: Long,
|
||||
account: Int,
|
||||
|
@ -78,22 +80,56 @@ interface RustBackendWelding {
|
|||
|
||||
// Implemented by `DerivationTool`
|
||||
interface Derivation {
|
||||
fun deriveShieldedAddress(viewingKey: String): String
|
||||
fun deriveShieldedAddress(
|
||||
viewingKey: String,
|
||||
network: ZcashNetwork
|
||||
): String
|
||||
|
||||
fun deriveShieldedAddress(seed: ByteArray, accountIndex: Int = 0): String
|
||||
fun deriveShieldedAddress(
|
||||
seed: ByteArray,
|
||||
network: ZcashNetwork,
|
||||
accountIndex: Int = 0,
|
||||
): String
|
||||
|
||||
fun deriveSpendingKeys(seed: ByteArray, numberOfAccounts: Int = 1): Array<String>
|
||||
fun deriveSpendingKeys(
|
||||
seed: ByteArray,
|
||||
network: ZcashNetwork,
|
||||
numberOfAccounts: Int = 1,
|
||||
): Array<String>
|
||||
|
||||
fun deriveTransparentAddress(seed: ByteArray, account: Int = 0, index: Int = 0): String
|
||||
fun deriveTransparentAddress(
|
||||
seed: ByteArray,
|
||||
network: ZcashNetwork,
|
||||
account: Int = 0,
|
||||
index: Int = 0,
|
||||
): String
|
||||
|
||||
fun deriveTransparentAddressFromPublicKey(publicKey: String): String
|
||||
fun deriveTransparentAddressFromPublicKey(
|
||||
publicKey: String,
|
||||
network: ZcashNetwork
|
||||
): String
|
||||
|
||||
fun deriveTransparentAddressFromPrivateKey(privateKey: String): String
|
||||
fun deriveTransparentAddressFromPrivateKey(
|
||||
privateKey: String,
|
||||
network: ZcashNetwork
|
||||
): String
|
||||
|
||||
fun deriveTransparentSecretKey(seed: ByteArray, account: Int = 0, index: Int = 0): String
|
||||
fun deriveTransparentSecretKey(
|
||||
seed: ByteArray,
|
||||
network: ZcashNetwork,
|
||||
account: Int = 0,
|
||||
index: Int = 0,
|
||||
): String
|
||||
|
||||
fun deriveViewingKey(spendingKey: String): String
|
||||
fun deriveViewingKey(
|
||||
spendingKey: String,
|
||||
network: ZcashNetwork
|
||||
): String
|
||||
|
||||
fun deriveUnifiedViewingKeys(seed: ByteArray, numberOfAccounts: Int = 1): Array<UnifiedViewingKey>
|
||||
fun deriveUnifiedViewingKeys(
|
||||
seed: ByteArray,
|
||||
network: ZcashNetwork,
|
||||
numberOfAccounts: Int = 1,
|
||||
): Array<UnifiedViewingKey>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import android.content.Context
|
|||
import cash.z.ecc.android.sdk.R
|
||||
import cash.z.ecc.android.sdk.annotation.OpenForTesting
|
||||
import cash.z.ecc.android.sdk.exception.LightWalletException
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk.DEFAULT_LIGHTWALLETD_PORT
|
||||
import cash.z.ecc.android.sdk.ext.twig
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import cash.z.wallet.sdk.rpc.CompactFormats
|
||||
import cash.z.wallet.sdk.rpc.CompactTxStreamerGrpc
|
||||
import cash.z.wallet.sdk.rpc.Service
|
||||
|
@ -34,6 +34,13 @@ class LightWalletGrpcService private constructor(
|
|||
|
||||
lateinit var connectionInfo: ConnectionInfo
|
||||
|
||||
constructor(
|
||||
appContext: Context,
|
||||
network: ZcashNetwork,
|
||||
usePlaintext: Boolean =
|
||||
appContext.resources.getBoolean(R.bool.lightwalletd_allow_very_insecure_connections)
|
||||
) : this(appContext, network.defaultHost, network.defaultPort, usePlaintext)
|
||||
|
||||
/**
|
||||
* Construct an instance that corresponds to the given host and port.
|
||||
*
|
||||
|
@ -47,7 +54,7 @@ class LightWalletGrpcService private constructor(
|
|||
constructor(
|
||||
appContext: Context,
|
||||
host: String,
|
||||
port: Int = DEFAULT_LIGHTWALLETD_PORT,
|
||||
port: Int = ZcashNetwork.Mainnet.defaultPort,
|
||||
usePlaintext: Boolean =
|
||||
appContext.resources.getBoolean(R.bool.lightwalletd_allow_very_insecure_connections)
|
||||
) : this(createDefaultChannel(appContext, host, port, usePlaintext)) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package cash.z.ecc.android.sdk.tool
|
|||
import cash.z.ecc.android.sdk.jni.RustBackend
|
||||
import cash.z.ecc.android.sdk.jni.RustBackendWelding
|
||||
import cash.z.ecc.android.sdk.type.UnifiedViewingKey
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
|
||||
class DerivationTool {
|
||||
|
||||
|
@ -17,9 +18,9 @@ class DerivationTool {
|
|||
*
|
||||
* @return the viewing keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
override fun deriveUnifiedViewingKeys(seed: ByteArray, numberOfAccounts: Int): Array<UnifiedViewingKey> =
|
||||
override fun deriveUnifiedViewingKeys(seed: ByteArray, network: ZcashNetwork, numberOfAccounts: Int): Array<UnifiedViewingKey> =
|
||||
withRustBackendLoaded {
|
||||
deriveUnifiedViewingKeysFromSeed(seed, numberOfAccounts).map {
|
||||
deriveUnifiedViewingKeysFromSeed(seed, numberOfAccounts, networkId = network.id).map {
|
||||
UnifiedViewingKey(it[0], it[1])
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
@ -31,8 +32,8 @@ class DerivationTool {
|
|||
*
|
||||
* @return the viewing key that corresponds to the spending key.
|
||||
*/
|
||||
override fun deriveViewingKey(spendingKey: String): String = withRustBackendLoaded {
|
||||
deriveExtendedFullViewingKey(spendingKey)
|
||||
override fun deriveViewingKey(spendingKey: String, network: ZcashNetwork): String = withRustBackendLoaded {
|
||||
deriveExtendedFullViewingKey(spendingKey, networkId = network.id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,9 +45,9 @@ class DerivationTool {
|
|||
*
|
||||
* @return the spending keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
override fun deriveSpendingKeys(seed: ByteArray, numberOfAccounts: Int): Array<String> =
|
||||
override fun deriveSpendingKeys(seed: ByteArray, network: ZcashNetwork, numberOfAccounts: Int): Array<String> =
|
||||
withRustBackendLoaded {
|
||||
deriveExtendedSpendingKeys(seed, numberOfAccounts)
|
||||
deriveExtendedSpendingKeys(seed, numberOfAccounts, networkId = network.id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,9 +59,9 @@ class DerivationTool {
|
|||
*
|
||||
* @return the address that corresponds to the seed and account index.
|
||||
*/
|
||||
override fun deriveShieldedAddress(seed: ByteArray, accountIndex: Int): String =
|
||||
override fun deriveShieldedAddress(seed: ByteArray, network: ZcashNetwork, accountIndex: Int): String =
|
||||
withRustBackendLoaded {
|
||||
deriveShieldedAddressFromSeed(seed, accountIndex)
|
||||
deriveShieldedAddressFromSeed(seed, accountIndex, networkId = network.id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,30 +72,30 @@ class DerivationTool {
|
|||
*
|
||||
* @return the address that corresponds to the viewing key.
|
||||
*/
|
||||
override fun deriveShieldedAddress(viewingKey: String): String = withRustBackendLoaded {
|
||||
deriveShieldedAddressFromViewingKey(viewingKey)
|
||||
override fun deriveShieldedAddress(viewingKey: String, network: ZcashNetwork): String = withRustBackendLoaded {
|
||||
deriveShieldedAddressFromViewingKey(viewingKey, networkId = network.id)
|
||||
}
|
||||
|
||||
// WIP probably shouldn't be used just yet. Why?
|
||||
// - because we need the private key associated with this seed and this function doesn't return it.
|
||||
// - the underlying implementation needs to be split out into a few lower-level calls
|
||||
override fun deriveTransparentAddress(seed: ByteArray, account: Int, index: Int): String = withRustBackendLoaded {
|
||||
deriveTransparentAddressFromSeed(seed, account, index)
|
||||
override fun deriveTransparentAddress(seed: ByteArray, network: ZcashNetwork, account: Int, index: Int): String = withRustBackendLoaded {
|
||||
deriveTransparentAddressFromSeed(seed, account, index, networkId = network.id)
|
||||
}
|
||||
|
||||
override fun deriveTransparentAddressFromPublicKey(transparentPublicKey: String): String = withRustBackendLoaded {
|
||||
deriveTransparentAddressFromPubKey(transparentPublicKey)
|
||||
override fun deriveTransparentAddressFromPublicKey(transparentPublicKey: String, network: ZcashNetwork): String = withRustBackendLoaded {
|
||||
deriveTransparentAddressFromPubKey(transparentPublicKey, networkId = network.id)
|
||||
}
|
||||
|
||||
override fun deriveTransparentAddressFromPrivateKey(transparentPrivateKey: String): String = withRustBackendLoaded {
|
||||
deriveTransparentAddressFromPrivKey(transparentPrivateKey)
|
||||
override fun deriveTransparentAddressFromPrivateKey(transparentPrivateKey: String, network: ZcashNetwork): String = withRustBackendLoaded {
|
||||
deriveTransparentAddressFromPrivKey(transparentPrivateKey, networkId = network.id)
|
||||
}
|
||||
|
||||
override fun deriveTransparentSecretKey(seed: ByteArray, account: Int, index: Int): String = withRustBackendLoaded {
|
||||
deriveTransparentSecretKeyFromSeed(seed, account, index)
|
||||
override fun deriveTransparentSecretKey(seed: ByteArray, network: ZcashNetwork, account: Int, index: Int): String = withRustBackendLoaded {
|
||||
deriveTransparentSecretKeyFromSeed(seed, account, index, networkId = network.id)
|
||||
}
|
||||
|
||||
fun validateUnifiedViewingKey(viewingKey: UnifiedViewingKey) {
|
||||
fun validateUnifiedViewingKey(viewingKey: UnifiedViewingKey, networkId: Int = ZcashNetwork.Mainnet.id) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
@ -115,37 +116,40 @@ class DerivationTool {
|
|||
@JvmStatic
|
||||
private external fun deriveExtendedSpendingKeys(
|
||||
seed: ByteArray,
|
||||
numberOfAccounts: Int
|
||||
numberOfAccounts: Int,
|
||||
networkId: Int,
|
||||
): Array<String>
|
||||
|
||||
@JvmStatic
|
||||
private external fun deriveUnifiedViewingKeysFromSeed(
|
||||
seed: ByteArray,
|
||||
numberOfAccounts: Int
|
||||
numberOfAccounts: Int,
|
||||
networkId: Int,
|
||||
): Array<Array<String>>
|
||||
|
||||
@JvmStatic
|
||||
private external fun deriveExtendedFullViewingKey(spendingKey: String): String
|
||||
private external fun deriveExtendedFullViewingKey(spendingKey: String, networkId: Int): String
|
||||
|
||||
@JvmStatic
|
||||
private external fun deriveShieldedAddressFromSeed(
|
||||
seed: ByteArray,
|
||||
accountIndex: Int
|
||||
accountIndex: Int,
|
||||
networkId: Int,
|
||||
): String
|
||||
|
||||
@JvmStatic
|
||||
private external fun deriveShieldedAddressFromViewingKey(key: String): String
|
||||
private external fun deriveShieldedAddressFromViewingKey(key: String, networkId: Int): String
|
||||
|
||||
@JvmStatic
|
||||
private external fun deriveTransparentAddressFromSeed(seed: ByteArray, account: Int, index: Int): String
|
||||
private external fun deriveTransparentAddressFromSeed(seed: ByteArray, account: Int, index: Int, networkId: Int): String
|
||||
|
||||
@JvmStatic
|
||||
private external fun deriveTransparentAddressFromPubKey(pk: String): String
|
||||
private external fun deriveTransparentAddressFromPubKey(pk: String, networkId: Int): String
|
||||
|
||||
@JvmStatic
|
||||
private external fun deriveTransparentAddressFromPrivKey(sk: String): String
|
||||
private external fun deriveTransparentAddressFromPrivKey(sk: String, networkId: Int): String
|
||||
|
||||
@JvmStatic
|
||||
private external fun deriveTransparentSecretKeyFromSeed(seed: ByteArray, account: Int, index: Int): String
|
||||
private external fun deriveTransparentSecretKeyFromSeed(seed: ByteArray, account: Int, index: Int, networkId: Int): String
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,14 @@ package cash.z.ecc.android.sdk.tool
|
|||
|
||||
import android.content.Context
|
||||
import cash.z.ecc.android.sdk.exception.BirthdayException
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||
import cash.z.ecc.android.sdk.ext.twig
|
||||
import cash.z.ecc.android.sdk.type.WalletBirthday
|
||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.stream.JsonReader
|
||||
import java.io.InputStreamReader
|
||||
import java.util.Arrays
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Tool for loading checkpoints for the wallet, based on the height at which the wallet was born.
|
||||
|
@ -22,33 +23,27 @@ class WalletBirthdayTool(appContext: Context) {
|
|||
* Load the nearest checkpoint to the given birthday height. If null is given, then this
|
||||
* will load the most recent checkpoint available.
|
||||
*/
|
||||
fun loadNearest(birthdayHeight: Int? = null): WalletBirthday {
|
||||
return loadBirthdayFromAssets(context, birthdayHeight)
|
||||
fun loadNearest(network: ZcashNetwork, birthdayHeight: Int? = null): WalletBirthday {
|
||||
return loadBirthdayFromAssets(context, network, birthdayHeight)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Directory within the assets folder where birthday data
|
||||
* (i.e. sapling trees for a given height) can be found.
|
||||
*/
|
||||
private const val BIRTHDAY_DIRECTORY = "zcash/saplingtree"
|
||||
|
||||
/**
|
||||
* Load the nearest checkpoint to the given birthday height. If null is given, then this
|
||||
* will load the most recent checkpoint available.
|
||||
*/
|
||||
fun loadNearest(context: Context, birthdayHeight: Int? = null): WalletBirthday {
|
||||
fun loadNearest(context: Context, network: ZcashNetwork, birthdayHeight: Int? = null): WalletBirthday {
|
||||
// TODO: potentially pull from shared preferences first
|
||||
return loadBirthdayFromAssets(context, birthdayHeight)
|
||||
return loadBirthdayFromAssets(context, network, birthdayHeight)
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for when an exact checkpoint is needed, like for SAPLING_ACTIVATION_HEIGHT. In
|
||||
* most cases, loading the nearest checkpoint is preferred for privacy reasons.
|
||||
*/
|
||||
fun loadExact(context: Context, birthdayHeight: Int) =
|
||||
loadNearest(context, birthdayHeight).also {
|
||||
fun loadExact(context: Context, network: ZcashNetwork, birthdayHeight: Int) =
|
||||
loadNearest(context, network, birthdayHeight).also {
|
||||
if (it.height != birthdayHeight)
|
||||
throw BirthdayException.ExactBirthdayNotFoundException(
|
||||
birthdayHeight,
|
||||
|
@ -56,6 +51,14 @@ class WalletBirthdayTool(appContext: Context) {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory within the assets folder where birthday data
|
||||
* (i.e. sapling trees for a given height) can be found.
|
||||
*/
|
||||
private fun birthdayDirectory(network: ZcashNetwork): String {
|
||||
return "saplingtree/${network.networkName.toLowerCase(Locale.US)}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the given birthday file from the assets of the given context. When no height is
|
||||
* specified, we default to the file with the greatest name.
|
||||
|
@ -68,21 +71,23 @@ class WalletBirthdayTool(appContext: Context) {
|
|||
*/
|
||||
private fun loadBirthdayFromAssets(
|
||||
context: Context,
|
||||
network: ZcashNetwork,
|
||||
birthdayHeight: Int? = null
|
||||
): WalletBirthday {
|
||||
twig("loading birthday from assets: $birthdayHeight")
|
||||
val directory = birthdayDirectory(network)
|
||||
val treeFiles =
|
||||
context.assets.list(BIRTHDAY_DIRECTORY)?.apply {
|
||||
context.assets.list(directory)?.apply {
|
||||
sortByDescending { fileName ->
|
||||
try {
|
||||
fileName.split('.').first().toInt()
|
||||
} catch (t: Throwable) {
|
||||
ZcashSdk.SAPLING_ACTIVATION_HEIGHT
|
||||
network.saplingActivationHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
if (treeFiles.isNullOrEmpty()) throw BirthdayException.MissingBirthdayFilesException(
|
||||
BIRTHDAY_DIRECTORY
|
||||
directory
|
||||
)
|
||||
twig("found ${treeFiles.size} sapling tree checkpoints: ${Arrays.toString(treeFiles)}")
|
||||
val file: String
|
||||
|
@ -94,18 +99,18 @@ class WalletBirthdayTool(appContext: Context) {
|
|||
}
|
||||
} catch (t: Throwable) {
|
||||
throw BirthdayException.BirthdayFileNotFoundException(
|
||||
BIRTHDAY_DIRECTORY,
|
||||
directory,
|
||||
birthdayHeight
|
||||
)
|
||||
}
|
||||
try {
|
||||
val reader = JsonReader(
|
||||
InputStreamReader(context.assets.open("$BIRTHDAY_DIRECTORY/$file"))
|
||||
InputStreamReader(context.assets.open("$directory/$file"))
|
||||
)
|
||||
return Gson().fromJson(reader, WalletBirthday::class.java)
|
||||
} catch (t: Throwable) {
|
||||
throw BirthdayException.MalformattedBirthdayFilesException(
|
||||
BIRTHDAY_DIRECTORY,
|
||||
directory,
|
||||
treeFiles[0]
|
||||
)
|
||||
}
|
||||
|
|
|
@ -53,3 +53,12 @@ interface UnifiedAddress {
|
|||
val rawShieldedAddress: String
|
||||
val rawTransparentAddress: String
|
||||
}
|
||||
|
||||
enum class ZcashNetwork(val id: Int, val networkName: String, val saplingActivationHeight: Int, val defaultHost: String, val defaultPort: Int) {
|
||||
Testnet(0, "testnet", 280_000, "testnet.lightwalletd.com", 9067),
|
||||
Mainnet(1, "mainnet", 419_200, "mainnet.lightwalletd.com", 9067);
|
||||
|
||||
companion object {
|
||||
fun from(id: Int) = values().first { it.id == id }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ use jni::{
|
|||
sys::{jboolean, jbyteArray, jint, jlong, JNI_FALSE, JNI_TRUE, jobjectArray, jstring},
|
||||
};
|
||||
use log::Level;
|
||||
use secp256k1::key::{PublicKey, SecretKey};
|
||||
use zcash_client_backend::{
|
||||
address::RecipientAddress,
|
||||
data_api::{
|
||||
|
@ -29,41 +30,37 @@ use zcash_client_backend::{
|
|||
encode_payment_address,
|
||||
},
|
||||
keys::{
|
||||
derive_secret_key_from_seed, derive_public_key_from_seed,
|
||||
derive_public_key_from_seed, derive_secret_key_from_seed,
|
||||
derive_transparent_address_from_public_key, derive_transparent_address_from_secret_key,
|
||||
spending_key, Wif,
|
||||
},
|
||||
wallet::{AccountId, OvkPolicy, WalletTransparentOutput},
|
||||
};
|
||||
use zcash_client_backend::data_api::wallet::{shield_funds, ANCHOR_OFFSET};
|
||||
use zcash_client_backend::data_api::wallet::{ANCHOR_OFFSET, shield_funds};
|
||||
use zcash_client_sqlite::{
|
||||
BlockDB,
|
||||
error::SqliteClientError,
|
||||
NoteId,
|
||||
wallet::{delete_utxos_above, put_received_transparent_utxo},
|
||||
wallet::init::{init_accounts_table, init_blocks_table, init_wallet_db},
|
||||
wallet::{put_received_transparent_utxo, delete_utxos_above},
|
||||
wallet::rewind_to_height,
|
||||
WalletDB,
|
||||
};
|
||||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::{BlockHeight, BranchId, Parameters},
|
||||
consensus::{BlockHeight, BranchId, Network, Parameters},
|
||||
legacy::TransparentAddress,
|
||||
memo::{
|
||||
Memo, MemoBytes
|
||||
},
|
||||
transaction::{
|
||||
components::{Amount, OutPoint},
|
||||
Transaction
|
||||
},
|
||||
zip32::ExtendedFullViewingKey,
|
||||
memo::{
|
||||
Memo, MemoBytes
|
||||
}
|
||||
zip32::ExtendedFullViewingKey
|
||||
};
|
||||
#[cfg(feature = "mainnet")]
|
||||
use zcash_primitives::consensus::{MAIN_NETWORK, MainNetwork};
|
||||
#[cfg(not(feature = "mainnet"))]
|
||||
use zcash_primitives::consensus::{TEST_NETWORK, TestNetwork};
|
||||
use zcash_primitives::consensus::Network::{MainNetwork, TestNetwork};
|
||||
use zcash_proofs::prover::LocalTxProver;
|
||||
use secp256k1::key::{SecretKey, PublicKey};
|
||||
|
||||
use crate::utils::exception::unwrap_exc_or;
|
||||
|
||||
|
@ -79,12 +76,6 @@ fn print_debug_state() {
|
|||
debug!("Release enabled (congrats, this is NOT a debug build).");
|
||||
}
|
||||
|
||||
#[cfg(feature = "mainnet")]
|
||||
pub const NETWORK: MainNetwork = MAIN_NETWORK;
|
||||
|
||||
#[cfg(not(feature = "mainnet"))]
|
||||
pub const NETWORK: TestNetwork = TEST_NETWORK;
|
||||
|
||||
fn wallet_db<P: Parameters>(env: &JNIEnv<'_>, params: P, db_data: JString<'_>) -> Result<WalletDB<P>, failure::Error> {
|
||||
WalletDB::for_path(utils::java_string_to_rust(&env, db_data), params)
|
||||
.map_err(|e| format_err!("Error opening wallet database connection: {}", e))
|
||||
|
@ -117,10 +108,12 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initDataDb(
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_path = utils::java_string_to_rust(&env, db_data);
|
||||
WalletDB::for_path(db_path, NETWORK)
|
||||
WalletDB::for_path(db_path, network)
|
||||
.and_then(|db| init_wallet_db(&db))
|
||||
.map(|()| JNI_TRUE)
|
||||
.map_err(|e| format_err!("Error while initializing data DB: {}", e))
|
||||
|
@ -135,9 +128,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccount
|
|||
db_data: JString<'_>,
|
||||
extfvks_arr: jobjectArray,
|
||||
extpubs_arr: jobjectArray,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
// TODO: avoid all this unwrapping and also surface errors, better
|
||||
let count = env.get_array_length(extfvks_arr).unwrap();
|
||||
let extfvks = (0..count)
|
||||
|
@ -145,13 +140,21 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccount
|
|||
.map(|jstr| utils::java_string_to_rust(&env, jstr.unwrap().into()))
|
||||
.map(|vkstr| {
|
||||
decode_extended_full_viewing_key(
|
||||
NETWORK.hrp_sapling_extended_full_viewing_key(),
|
||||
network.hrp_sapling_extended_full_viewing_key(),
|
||||
&vkstr,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.map_err(|err| format_err!("Invalid bech32: {}", err))
|
||||
.and_then(|extfvk|
|
||||
extfvk.ok_or_else(|| {
|
||||
let (network_name, other) = if network == TestNetwork {
|
||||
("testnet", "mainnet")
|
||||
} else {
|
||||
("mainnet", "testnet")
|
||||
};
|
||||
format_err!("Error: Wrong network! Unable to decode viewing key for {}. Check whether this is a key for {}.", network_name, other)
|
||||
}))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let taddrs:Vec<_> = (0..count)
|
||||
.map(|i| env.get_object_array_element(extpubs_arr, i))
|
||||
|
@ -174,8 +177,10 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
|
|||
_: JClass<'_>,
|
||||
seed: jbyteArray,
|
||||
accounts: jint,
|
||||
network_id: jint,
|
||||
) -> jobjectArray {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let seed = env.convert_byte_array(seed).unwrap();
|
||||
let accounts = if accounts > 0 {
|
||||
accounts as u32
|
||||
|
@ -184,7 +189,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
|
|||
};
|
||||
|
||||
let extsks: Vec<_> = (0..accounts)
|
||||
.map(|account| spending_key(&seed, NETWORK.coin_type(), AccountId(account)))
|
||||
.map(|account| spending_key(&seed, network.coin_type(), AccountId(account)))
|
||||
.collect();
|
||||
|
||||
Ok(utils::rust_vec_to_java(
|
||||
|
@ -193,7 +198,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
|
|||
"java/lang/String",
|
||||
|env, extsk| {
|
||||
env.new_string(encode_extended_spending_key(
|
||||
NETWORK.hrp_sapling_extended_spending_key(),
|
||||
network.hrp_sapling_extended_spending_key(),
|
||||
&extsk,
|
||||
))
|
||||
},
|
||||
|
@ -209,8 +214,10 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveU
|
|||
_: JClass<'_>,
|
||||
seed: jbyteArray,
|
||||
accounts: jint,
|
||||
network_id: jint,
|
||||
) -> jobjectArray {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let seed = env.convert_byte_array(seed).unwrap();
|
||||
let accounts = if accounts > 0 {
|
||||
accounts as u32
|
||||
|
@ -221,15 +228,15 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveU
|
|||
let extfvks: Vec<_> = (0..accounts)
|
||||
.map(|account| {
|
||||
encode_extended_full_viewing_key(
|
||||
NETWORK.hrp_sapling_extended_full_viewing_key(),
|
||||
&ExtendedFullViewingKey::from(&spending_key(&seed, NETWORK.coin_type(), AccountId(account)))
|
||||
network.hrp_sapling_extended_full_viewing_key(),
|
||||
&ExtendedFullViewingKey::from(&spending_key(&seed, network.coin_type(), AccountId(account)))
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let extpubs: Vec<_> = (0..accounts)
|
||||
.map(|account| {
|
||||
let pk = derive_public_key_from_seed(&NETWORK, &seed, AccountId(account), 0).unwrap();
|
||||
let pk = derive_public_key_from_seed(&network, &seed, AccountId(account), 0).unwrap();
|
||||
hex::encode(&pk.serialize())
|
||||
})
|
||||
.collect();
|
||||
|
@ -253,8 +260,10 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveS
|
|||
_: JClass<'_>,
|
||||
seed: jbyteArray,
|
||||
account_index: jint,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let seed = env.convert_byte_array(seed).unwrap();
|
||||
let account_index = if account_index >= 0 {
|
||||
account_index as u32
|
||||
|
@ -262,11 +271,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveS
|
|||
return Err(format_err!("accountIndex argument must be positive"));
|
||||
};
|
||||
|
||||
let address = spending_key(&seed, NETWORK.coin_type(), AccountId(account_index))
|
||||
let address = spending_key(&seed, network.coin_type(), AccountId(account_index))
|
||||
.default_address()
|
||||
.unwrap()
|
||||
.1;
|
||||
let address_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &address);
|
||||
let address_str = encode_payment_address(network.hrp_sapling_payment_address(), &address);
|
||||
let output = env
|
||||
.new_string(address_str)
|
||||
.expect("Couldn't create Java string!");
|
||||
|
@ -280,11 +289,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveS
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
extfvk_string: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let extfvk_string = utils::java_string_to_rust(&env, extfvk_string);
|
||||
let extfvk = match decode_extended_full_viewing_key(
|
||||
NETWORK.hrp_sapling_extended_full_viewing_key(),
|
||||
network.hrp_sapling_extended_full_viewing_key(),
|
||||
&extfvk_string,
|
||||
) {
|
||||
Ok(Some(extfvk)) => extfvk,
|
||||
|
@ -300,7 +311,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveS
|
|||
};
|
||||
|
||||
let address = extfvk.default_address().unwrap().1;
|
||||
let address_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &address);
|
||||
let address_str = encode_payment_address(network.hrp_sapling_payment_address(), &address);
|
||||
let output = env
|
||||
.new_string(address_str)
|
||||
.expect("Couldn't create Java string!");
|
||||
|
@ -314,11 +325,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
extsk_string: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jobjectArray {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let extsk_string = utils::java_string_to_rust(&env, extsk_string);
|
||||
let extfvk = match decode_extended_spending_key(
|
||||
NETWORK.hrp_sapling_extended_spending_key(),
|
||||
network.hrp_sapling_extended_spending_key(),
|
||||
&extsk_string,
|
||||
) {
|
||||
Ok(Some(extsk)) => ExtendedFullViewingKey::from(&extsk),
|
||||
|
@ -335,7 +348,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveE
|
|||
|
||||
let output = env
|
||||
.new_string(encode_extended_full_viewing_key(
|
||||
NETWORK.hrp_sapling_extended_full_viewing_key(),
|
||||
network.hrp_sapling_extended_full_viewing_key(),
|
||||
&extfvk,
|
||||
))
|
||||
.expect("Couldn't create Java string!");
|
||||
|
@ -354,9 +367,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initBlocksT
|
|||
hash_string: JString<'_>,
|
||||
time: jlong,
|
||||
sapling_tree_string: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let hash = {
|
||||
let mut hash = hex::decode(utils::java_string_to_rust(&env, hash_string)).unwrap();
|
||||
hash.reverse();
|
||||
|
@ -385,14 +400,16 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getShielded
|
|||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
account: jint,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let account = AccountId(account.try_into()?);
|
||||
|
||||
match (&db_data).get_address(account) {
|
||||
Ok(Some(addr)) => {
|
||||
let addr_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &addr);
|
||||
let addr_str = encode_payment_address(network.hrp_sapling_payment_address(), &addr);
|
||||
let output = env
|
||||
.new_string(addr_str)
|
||||
.expect("Couldn't create Java string!");
|
||||
|
@ -414,11 +431,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidShie
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
addr: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let addr = utils::java_string_to_rust(&env, addr);
|
||||
|
||||
match RecipientAddress::decode(&NETWORK, &addr) {
|
||||
match RecipientAddress::decode(&network, &addr) {
|
||||
Some(addr) => match addr {
|
||||
RecipientAddress::Shielded(_) => Ok(JNI_TRUE),
|
||||
RecipientAddress::Transparent(_) => Ok(JNI_FALSE),
|
||||
|
@ -434,11 +453,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidTran
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
addr: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let addr = utils::java_string_to_rust(&env, addr);
|
||||
|
||||
match RecipientAddress::decode(&NETWORK, &addr) {
|
||||
match RecipientAddress::decode(&network, &addr) {
|
||||
Some(addr) => match addr {
|
||||
RecipientAddress::Shielded(_) => Ok(JNI_FALSE),
|
||||
RecipientAddress::Transparent(_) => Ok(JNI_TRUE),
|
||||
|
@ -454,11 +475,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getBalance(
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
account: jint,
|
||||
accountj: jint,
|
||||
network_id: jint,
|
||||
) -> jlong {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let account = AccountId(account.try_into()?);
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let account = AccountId(accountj.try_into()?);
|
||||
|
||||
(&db_data)
|
||||
.get_target_and_anchor_heights()
|
||||
|
@ -484,11 +507,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerified
|
|||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
address: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jlong {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let addr = utils::java_string_to_rust(&env, address);
|
||||
let taddr = TransparentAddress::decode(&NETWORK, &addr).unwrap();
|
||||
let taddr = TransparentAddress::decode(&network, &addr).unwrap();
|
||||
|
||||
let amount = (&db_data)
|
||||
.get_target_and_anchor_heights()
|
||||
|
@ -519,11 +544,13 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getTotalTra
|
|||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
address: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jlong {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let addr = utils::java_string_to_rust(&env, address);
|
||||
let taddr = TransparentAddress::decode(&NETWORK, &addr).unwrap();
|
||||
let taddr = TransparentAddress::decode(&network, &addr).unwrap();
|
||||
|
||||
let amount = (&db_data)
|
||||
.get_target_and_anchor_heights()
|
||||
|
@ -554,9 +581,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getVerified
|
|||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
account: jint,
|
||||
network_id: jint,
|
||||
) -> jlong {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let account = AccountId(account.try_into()?);
|
||||
|
||||
(&db_data)
|
||||
|
@ -584,9 +613,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getReceived
|
|||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
id_note: jlong,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
|
||||
let memo = (&db_data)
|
||||
.get_memo(NoteId::ReceivedNoteId(id_note))
|
||||
|
@ -611,9 +642,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getSentMemo
|
|||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
id_note: jlong,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
|
||||
let memo = (&db_data)
|
||||
.get_memo(NoteId::SentNoteId(id_note))
|
||||
|
@ -639,16 +672,18 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_validateCom
|
|||
_: JClass<'_>,
|
||||
db_cache: JString<'_>,
|
||||
db_data: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jint {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let block_db = block_db(&env, db_cache)?;
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
|
||||
let validate_from = (&db_data)
|
||||
.get_max_height_hash()
|
||||
.map_err(|e| format_err!("Error while validating chain: {}", e))?;
|
||||
|
||||
let val_res = validate_chain(&NETWORK, &block_db, validate_from);
|
||||
let val_res = validate_chain(&network, &block_db, validate_from);
|
||||
|
||||
if let Err(e) = val_res {
|
||||
match e {
|
||||
|
@ -673,9 +708,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_rewindToHei
|
|||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
height: jint,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
|
||||
let height = BlockHeight::try_from(height)?;
|
||||
rewind_to_height(&db_data, height)
|
||||
|
@ -692,13 +729,15 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_scanBlocks(
|
|||
_: JClass<'_>,
|
||||
db_cache: JString<'_>,
|
||||
db_data: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_cache = block_db(&env, db_cache)?;
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let mut db_data = db_data.get_update_ops()?;
|
||||
|
||||
match scan_cached_blocks(&NETWORK, &db_cache, &mut db_data, None) {
|
||||
match scan_cached_blocks(&network, &db_cache, &mut db_data, None) {
|
||||
Ok(()) => Ok(JNI_TRUE),
|
||||
Err(e) => Err(format_err!("Error while scanning blocks: {}", e)),
|
||||
}
|
||||
|
@ -717,19 +756,21 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_putUtxo(
|
|||
script: jbyteArray,
|
||||
value: jlong,
|
||||
height: jint,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
// debug!("For height {} found consensus branch {:?}", height, branch);
|
||||
debug!("preparing to store UTXO in db_data");
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let txid_bytes = env.convert_byte_array(txid_bytes).unwrap();
|
||||
let mut txid = [0u8; 32];
|
||||
txid.copy_from_slice(&txid_bytes);
|
||||
|
||||
let script = env.convert_byte_array(script).unwrap();
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let mut db_data = db_data.get_update_ops()?;
|
||||
let addr = utils::java_string_to_rust(&env, address);
|
||||
let address = TransparentAddress::decode(&NETWORK, &addr).unwrap();
|
||||
let address = TransparentAddress::decode(&network, &addr).unwrap();
|
||||
|
||||
let output = WalletTransparentOutput {
|
||||
address: address,
|
||||
|
@ -756,19 +797,21 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_clearUtxos(
|
|||
db_data: JString<'_>,
|
||||
taddress: JString<'_>,
|
||||
above_height: jint,
|
||||
network_id: jint,
|
||||
) -> jint {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let mut db_data = db_data.get_update_ops()?;
|
||||
let addr = utils::java_string_to_rust(&env, taddress);
|
||||
let taddress = TransparentAddress::decode(&NETWORK, &addr).unwrap();
|
||||
let height = BlockHeight::from(above_height as u32);
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let mut db_data = db_data.get_update_ops()?;
|
||||
let addr = utils::java_string_to_rust(&env, taddress);
|
||||
let taddress = TransparentAddress::decode(&network, &addr).unwrap();
|
||||
let height = BlockHeight::from(above_height as u32);
|
||||
|
||||
debug!("clearing UTXOs that were found above height: {}", above_height);
|
||||
match delete_utxos_above(&mut db_data, &taddress, height) {
|
||||
Ok(rows) => Ok(rows as i32),
|
||||
Err(e) => Err(format_err!("Error while clearing UTXOs: {}", e)),
|
||||
}
|
||||
debug!("clearing UTXOs that were found above height: {}", above_height);
|
||||
match delete_utxos_above(&mut db_data, &taddress, height) {
|
||||
Ok(rows) => Ok(rows as i32),
|
||||
Err(e) => Err(format_err!("Error while clearing UTXOs: {}", e)),
|
||||
}
|
||||
});
|
||||
unwrap_exc_or(&env, res, -1)
|
||||
}
|
||||
|
@ -781,13 +824,15 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_scanBlockBa
|
|||
db_cache: JString<'_>,
|
||||
db_data: JString<'_>,
|
||||
limit: jint,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_cache = block_db(&env, db_cache)?;
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let mut db_data = db_data.get_update_ops()?;
|
||||
|
||||
match scan_cached_blocks(&NETWORK, &db_cache, &mut db_data, Some(limit as u32)) {
|
||||
match scan_cached_blocks(&network, &db_cache, &mut db_data, Some(limit as u32)) {
|
||||
Ok(()) => Ok(JNI_TRUE),
|
||||
Err(e) => Err(format_err!("Error while scanning blocks: {}", e)),
|
||||
}
|
||||
|
@ -802,8 +847,10 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveT
|
|||
seed: jbyteArray,
|
||||
account: jint,
|
||||
index: jint,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let seed = env.convert_byte_array(seed).unwrap();
|
||||
let account = if account >= 0 {
|
||||
account as u32
|
||||
|
@ -815,7 +862,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveT
|
|||
} else {
|
||||
return Err(format_err!("index argument must be positive"));
|
||||
};
|
||||
let sk = derive_secret_key_from_seed(&NETWORK, &seed, AccountId(account), index).unwrap();
|
||||
let sk = derive_secret_key_from_seed(&network, &seed, AccountId(account), index).unwrap();
|
||||
let sk_wif = Wif::from_secret_key(&sk, true);
|
||||
let output = env
|
||||
.new_string(sk_wif.0)
|
||||
|
@ -832,8 +879,10 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveT
|
|||
seed: jbyteArray,
|
||||
account: jint,
|
||||
index: jint,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let seed = env.convert_byte_array(seed).unwrap();
|
||||
let account = if account >= 0 {
|
||||
account as u32
|
||||
|
@ -845,9 +894,9 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveT
|
|||
} else {
|
||||
return Err(format_err!("index argument must be positive"));
|
||||
};
|
||||
let sk = derive_secret_key_from_seed(&NETWORK, &seed, AccountId(account), index);
|
||||
let sk = derive_secret_key_from_seed(&network, &seed, AccountId(account), index);
|
||||
let taddr = derive_transparent_address_from_secret_key(&sk.unwrap())
|
||||
.encode(&NETWORK);
|
||||
.encode(&network);
|
||||
|
||||
let output = env
|
||||
.new_string(taddr)
|
||||
|
@ -862,13 +911,15 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveT
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
secret_key: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let tsk_wif = utils::java_string_to_rust(&env, secret_key);
|
||||
let sk:SecretKey = (&Wif(tsk_wif)).try_into().expect("invalid private key WIF");
|
||||
let taddr =
|
||||
derive_transparent_address_from_secret_key(&sk)
|
||||
.encode(&NETWORK);
|
||||
.encode(&network);
|
||||
|
||||
let output = env
|
||||
.new_string(taddr)
|
||||
|
@ -885,13 +936,15 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_tool_DerivationTool_deriveT
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
public_key: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jstring {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let public_key_str = utils::java_string_to_rust(&env, public_key);
|
||||
let pk = PublicKey::from_str(&public_key_str)?;
|
||||
let taddr =
|
||||
derive_transparent_address_from_public_key(&pk)
|
||||
.encode(&NETWORK);
|
||||
.encode(&network);
|
||||
|
||||
let output = env
|
||||
.new_string(taddr)
|
||||
|
@ -908,14 +961,16 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_decryptAndS
|
|||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
tx: jbyteArray,
|
||||
network_id: jint,
|
||||
) -> jboolean {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let mut db_data = db_data.get_update_ops()?;
|
||||
let tx_bytes = env.convert_byte_array(tx).unwrap();
|
||||
let tx = Transaction::read(&tx_bytes[..])?;
|
||||
|
||||
match decrypt_and_store_transaction(&NETWORK, &mut db_data, &tx) {
|
||||
match decrypt_and_store_transaction(&network, &mut db_data, &tx) {
|
||||
Ok(()) => Ok(JNI_TRUE),
|
||||
Err(e) => Err(format_err!("Error while decrypting transaction: {}", e)),
|
||||
}
|
||||
|
@ -937,9 +992,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
|
|||
memo: jbyteArray,
|
||||
spend_params: JString<'_>,
|
||||
output_params: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jlong {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let mut db_data = db_data.get_update_ops()?;
|
||||
let account = if account >= 0 {
|
||||
account as u32
|
||||
|
@ -958,7 +1015,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
|
|||
let output_params = utils::java_string_to_rust(&env, output_params);
|
||||
|
||||
let extsk =
|
||||
match decode_extended_spending_key(NETWORK.hrp_sapling_extended_spending_key(), &extsk)
|
||||
match decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk)
|
||||
{
|
||||
Ok(Some(extsk)) => extsk,
|
||||
Ok(None) => {
|
||||
|
@ -969,7 +1026,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
|
|||
}
|
||||
};
|
||||
|
||||
let to = match RecipientAddress::decode(&NETWORK, &to) {
|
||||
let to = match RecipientAddress::decode(&network, &to) {
|
||||
Some(to) => to,
|
||||
None => {
|
||||
return Err(format_err!("Address is for the wrong network"));
|
||||
|
@ -990,7 +1047,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createToAdd
|
|||
// let branch = if
|
||||
create_spend_to_address(
|
||||
&mut db_data,
|
||||
&NETWORK,
|
||||
&network,
|
||||
prover,
|
||||
AccountId(account),
|
||||
&extsk,
|
||||
|
@ -1015,9 +1072,11 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_shieldToAdd
|
|||
memo: jbyteArray,
|
||||
spend_params: JString<'_>,
|
||||
output_params: JString<'_>,
|
||||
network_id: jint,
|
||||
) -> jlong {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let db_data = wallet_db(&env, NETWORK, db_data)?;
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let mut db_data = db_data.get_update_ops()?;
|
||||
let account = if account == 0 {
|
||||
account as u32
|
||||
|
@ -1030,7 +1089,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_shieldToAdd
|
|||
let spend_params = utils::java_string_to_rust(&env, spend_params);
|
||||
let output_params = utils::java_string_to_rust(&env, output_params);
|
||||
let extsk =
|
||||
match decode_extended_spending_key(NETWORK.hrp_sapling_extended_spending_key(), &extsk)
|
||||
match decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk)
|
||||
{
|
||||
Ok(Some(extsk)) => extsk,
|
||||
Ok(None) => {
|
||||
|
@ -1049,7 +1108,7 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_shieldToAdd
|
|||
|
||||
shield_funds(
|
||||
&mut db_data,
|
||||
&NETWORK,
|
||||
&network,
|
||||
prover,
|
||||
AccountId(account),
|
||||
&sk,
|
||||
|
@ -1067,12 +1126,29 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_branchIdFor
|
|||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
height: jint,
|
||||
network_id: jint,
|
||||
) -> jint {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let branch: BranchId = BranchId::for_height(&NETWORK, BlockHeight::from(height as u32));
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let branch: BranchId = BranchId::for_height(&network, BlockHeight::from(height as u32));
|
||||
let branch_id: u32 = u32::from(branch);
|
||||
debug!("For height {} found consensus branch {:?}", height, branch);
|
||||
Ok(branch_id as i32)
|
||||
});
|
||||
unwrap_exc_or(&env, res, -1)
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Utility functions
|
||||
//
|
||||
|
||||
fn parse_network(value: u32) -> Result<Network, failure::Error> {
|
||||
match value {
|
||||
0 => Ok(TestNetwork),
|
||||
1 => Ok(MainNetwork),
|
||||
_ => Err(format_err!("Invalid network type: {}. Expected either 0 or 1 for Testnet or Mainnet, respectively.", value))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue