Add `SdkSynchronizer.createAccount()` method
It is currently hidden from the public API, implemented for testing purposes.
This commit is contained in:
parent
c6fd783317
commit
f69cacb9e6
|
@ -6,6 +6,9 @@ Change Log
|
|||
### Added
|
||||
- `cash.z.ecc.android.sdk`:
|
||||
- `Synchronizer.isValidUnifiedAddr`
|
||||
- `cash.z.ecc.android.sdk.model`:
|
||||
- `FirstClassByteArray`
|
||||
- `UnifiedSpendingKey`
|
||||
- `cash.z.ecc.android.sdk.tool`:
|
||||
- `DerivationTool.deriveTransparentAccountPrivateKey`
|
||||
- `DerivationTool.deriveTransparentAddressFromAccountPrivateKey`
|
||||
|
|
|
@ -591,7 +591,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "equihash"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
|
@ -609,7 +609,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "f4jumble"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
]
|
||||
|
@ -2037,7 +2037,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_address"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bs58",
|
||||
|
@ -2048,12 +2048,13 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_client_backend"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bech32",
|
||||
"bls12_381",
|
||||
"bs58",
|
||||
"byteorder",
|
||||
"crossbeam-channel",
|
||||
"ff",
|
||||
"group",
|
||||
|
@ -2061,6 +2062,7 @@ dependencies = [
|
|||
"hex",
|
||||
"jubjub",
|
||||
"log",
|
||||
"memuse",
|
||||
"nom",
|
||||
"orchard",
|
||||
"percent-encoding",
|
||||
|
@ -2084,7 +2086,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_client_sqlite"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bs58",
|
||||
|
@ -2108,7 +2110,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_encoding"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"nonempty",
|
||||
|
@ -2117,7 +2119,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_note_encryption"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"chacha20 0.9.0",
|
||||
"chacha20poly1305 0.10.1",
|
||||
|
@ -2130,7 +2132,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
version = "0.7.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bip0039",
|
||||
|
@ -2167,7 +2169,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_proofs"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=6cb0d212195a32b7456c866bcd367fc98967b668#6cb0d212195a32b7456c866bcd367fc98967b668"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=774ffadf5a0120a74d70d281974d079ccd58c600#774ffadf5a0120a74d70d281974d079ccd58c600"
|
||||
dependencies = [
|
||||
"bellman",
|
||||
"blake2b_simd",
|
||||
|
|
|
@ -21,8 +21,8 @@ log-panics = "2.0.0"
|
|||
schemer = "0.2"
|
||||
secp256k1 = "0.21"
|
||||
secrecy = "0.8"
|
||||
zcash_client_backend = { version = "0.5", features = ["transparent-inputs"] }
|
||||
zcash_client_sqlite = { version = "0.3", features = ["transparent-inputs"] }
|
||||
zcash_client_backend = { version = "0.5", features = ["transparent-inputs", "unstable"] }
|
||||
zcash_client_sqlite = { version = "0.3", features = ["transparent-inputs", "unstable"] }
|
||||
zcash_primitives = "0.7"
|
||||
zcash_proofs = "0.7"
|
||||
|
||||
|
@ -30,11 +30,11 @@ zcash_proofs = "0.7"
|
|||
[patch.crates-io]
|
||||
group = { git = "https://github.com/zkcrypto/group.git", rev = "a7f3ceb2373e9fe536996f7b4d55c797f3e667f0" }
|
||||
orchard = { git = 'https://github.com/zcash/orchard.git', rev='f206b3f5d4e31bba75d03d9d03d5fa25825a9384' }
|
||||
zcash_client_backend = { git = 'https://github.com/zcash/librustzcash.git', rev='6cb0d212195a32b7456c866bcd367fc98967b668' }
|
||||
zcash_client_sqlite = { git = 'https://github.com/zcash/librustzcash.git', rev='6cb0d212195a32b7456c866bcd367fc98967b668' }
|
||||
zcash_note_encryption = { git = 'https://github.com/zcash/librustzcash.git', rev='6cb0d212195a32b7456c866bcd367fc98967b668' }
|
||||
zcash_primitives = { git = 'https://github.com/zcash/librustzcash.git', rev='6cb0d212195a32b7456c866bcd367fc98967b668' }
|
||||
zcash_proofs = { git = 'https://github.com/zcash/librustzcash.git', rev='6cb0d212195a32b7456c866bcd367fc98967b668' }
|
||||
zcash_client_backend = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||
zcash_client_sqlite = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||
zcash_note_encryption = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||
zcash_primitives = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||
zcash_proofs = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||
|
||||
## Uncomment this to test librustzcash changes locally
|
||||
#[patch.crates-io]
|
||||
|
|
|
@ -49,6 +49,7 @@ import cash.z.ecc.android.sdk.internal.transaction.WalletTransactionEncoder
|
|||
import cash.z.ecc.android.sdk.internal.twig
|
||||
import cash.z.ecc.android.sdk.internal.twigTask
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
|
@ -622,6 +623,14 @@ class SdkSynchronizer internal constructor(
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Account management
|
||||
//
|
||||
|
||||
// Not ready to be a public API; internal for testing only
|
||||
internal suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey =
|
||||
processor.createAccount(seed)
|
||||
|
||||
//
|
||||
// Send / Receive
|
||||
//
|
||||
|
|
|
@ -5,6 +5,7 @@ import cash.z.ecc.android.sdk.db.entity.ConfirmedTransaction
|
|||
import cash.z.ecc.android.sdk.db.entity.PendingTransaction
|
||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
|
@ -159,6 +160,33 @@ interface Synchronizer {
|
|||
// Operations
|
||||
//
|
||||
|
||||
/**
|
||||
* Adds the next available account-level spend authority, given the current set of
|
||||
* [ZIP 316](https://zips.z.cash/zip-0316) account identifiers known, to the wallet
|
||||
* database.
|
||||
*
|
||||
* The caller should store the byte encoding of the returned spending key in a secure
|
||||
* fashion. This encoding **MUST NOT** be exposed to users. It is an internal encoding
|
||||
* that is inherently unstable, and only intended to be passed between the SDK and the
|
||||
* storage backend. The caller **MUST NOT** allow this encoding to be exported or
|
||||
* imported.
|
||||
*
|
||||
* If `seed` was imported from a backup and this method is being used to restore a
|
||||
* previous wallet state, you should use this method to add all of the desired
|
||||
* accounts before scanning the chain from the seed's birthday height.
|
||||
*
|
||||
* By convention, wallets should only allow a new account to be generated after funds
|
||||
* have been received by the currently-available account (in order to enable
|
||||
* automated account recovery).
|
||||
*
|
||||
* @param seed the wallet's seed phrase.
|
||||
*
|
||||
* @return the newly created ZIP 316 account identifier, along with the binary
|
||||
* encoding of the `UnifiedSpendingKey` for the newly created account.
|
||||
*/
|
||||
// This is not yet ready to be a public API
|
||||
// suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey
|
||||
|
||||
/**
|
||||
* Gets the shielded address for the given account. This is syntactic sugar for
|
||||
* [getShieldedAddress] because we use z-addrs by default.
|
||||
|
|
|
@ -41,6 +41,7 @@ import cash.z.ecc.android.sdk.internal.twigTask
|
|||
import cash.z.ecc.android.sdk.jni.RustBackend
|
||||
import cash.z.ecc.android.sdk.jni.RustBackendWelding
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.wallet.sdk.rpc.Service
|
||||
import io.grpc.StatusRuntimeException
|
||||
|
@ -1016,6 +1017,11 @@ class CompactBlockProcessor internal constructor(
|
|||
suspend fun getLastScannedHeight() =
|
||||
repository.lastScannedHeight()
|
||||
|
||||
// TODO(str4d): CompactBlockProcessor is the wrong place for this, but it's where all the other APIs that need
|
||||
// access to the RustBackend live. This should be refactored.
|
||||
internal suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey =
|
||||
rustBackend.createAccount(seed)
|
||||
|
||||
/**
|
||||
* Get address corresponding to the given account for this wallet.
|
||||
*
|
||||
|
|
|
@ -7,6 +7,7 @@ import cash.z.ecc.android.sdk.internal.ext.deleteSuspend
|
|||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||
import cash.z.ecc.android.sdk.internal.twig
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
|
@ -52,6 +53,16 @@ internal class RustBackend private constructor(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey {
|
||||
return withContext(SdkDispatchers.DATABASE_IO) {
|
||||
createAccount(
|
||||
dataDbFile.absolutePath,
|
||||
seed,
|
||||
networkId = network.id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun initAccountsTable(vararg keys: UnifiedFullViewingKey): Boolean {
|
||||
val ufvks = Array(keys.size) { keys[it].encoding }
|
||||
|
||||
|
@ -405,6 +416,9 @@ internal class RustBackend private constructor(
|
|||
networkId: Int
|
||||
): Boolean
|
||||
|
||||
@JvmStatic
|
||||
private external fun createAccount(dbDataPath: String, seed: ByteArray, networkId: Int): UnifiedSpendingKey
|
||||
|
||||
@JvmStatic
|
||||
private external fun getCurrentAddress(
|
||||
dbDataPath: String,
|
||||
|
|
|
@ -2,6 +2,7 @@ package cash.z.ecc.android.sdk.jni
|
|||
|
||||
import cash.z.ecc.android.sdk.internal.model.Checkpoint
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
|
@ -42,6 +43,8 @@ internal interface RustBackendWelding {
|
|||
|
||||
suspend fun initDataDb(seed: ByteArray?): Int
|
||||
|
||||
suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey
|
||||
|
||||
fun isValidShieldedAddr(addr: String): Boolean
|
||||
|
||||
fun isValidTransparentAddr(addr: String): Boolean
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package cash.z.ecc.android.sdk.model
|
||||
|
||||
class FirstClassByteArray(val byteArray: ByteArray) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as FirstClassByteArray
|
||||
|
||||
if (!byteArray.contentEquals(other.byteArray)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode() = byteArray.contentHashCode()
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package cash.z.ecc.android.sdk.model
|
||||
|
||||
/**
|
||||
* A [ZIP 316](https://zips.z.cash/zip-0316) Unified Spending Key.
|
||||
*
|
||||
* This is the spend authority for an account under the wallet's seed.
|
||||
*
|
||||
* An instance of this class contains all of the per-pool spending keys that could be
|
||||
* derived at the time of its creation. As such, it is not suitable for long-term storage,
|
||||
* export/import, or backup purposes.
|
||||
*/
|
||||
data class UnifiedSpendingKey internal constructor(
|
||||
/**
|
||||
* A [ZIP 316](https://zips.z.cash/zip-0316) account identifier.
|
||||
*/
|
||||
val account: Int,
|
||||
|
||||
/**
|
||||
* The binary encoding of the [ZIP 316](https://zips.z.cash/zip-0316) Unified Spending
|
||||
* Key for [account].
|
||||
*
|
||||
* This encoding **MUST NOT** be exposed to users. It is an internal encoding that is
|
||||
* inherently unstable, and only intended to be passed between the SDK and the storage
|
||||
* backend. Wallets **MUST NOT** allow this encoding to be exported or imported.
|
||||
*/
|
||||
internal val bytes: FirstClassByteArray
|
||||
) {
|
||||
// Override to prevent leaking key to logs
|
||||
override fun toString() = "UnifiedSpendingKey(account=$account)"
|
||||
|
||||
fun copyBytes() = bytes.byteArray.copyOf()
|
||||
}
|
|
@ -11,9 +11,10 @@ use std::str::FromStr;
|
|||
use android_logger::Config;
|
||||
use failure::format_err;
|
||||
use hdwallet::traits::{Deserialize, Serialize};
|
||||
use jni::objects::JValue;
|
||||
use jni::{
|
||||
objects::{JClass, JString},
|
||||
sys::{jboolean, jbyteArray, jint, jlong, jobjectArray, jstring, JNI_FALSE, JNI_TRUE},
|
||||
sys::{jboolean, jbyteArray, jint, jlong, jobject, jobjectArray, jstring, JNI_FALSE, JNI_TRUE},
|
||||
JNIEnv,
|
||||
};
|
||||
use log::Level;
|
||||
|
@ -35,7 +36,7 @@ use zcash_client_backend::{
|
|||
decode_extended_spending_key, encode_extended_full_viewing_key,
|
||||
encode_extended_spending_key, AddressCodec,
|
||||
},
|
||||
keys::{sapling, UnifiedFullViewingKey},
|
||||
keys::{sapling, Era, UnifiedFullViewingKey},
|
||||
wallet::{OvkPolicy, WalletTransparentOutput},
|
||||
};
|
||||
use zcash_client_sqlite::wallet::init::WalletMigrationError;
|
||||
|
@ -145,6 +146,58 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initDataDb(
|
|||
unwrap_exc_or(&env, res, -1)
|
||||
}
|
||||
|
||||
/// Adds the next available account-level spend authority, given the current set of
|
||||
/// [ZIP 316] account identifiers known, to the wallet database.
|
||||
///
|
||||
/// Returns the newly created [ZIP 316] account identifier, along with the binary encoding
|
||||
/// of the [`UnifiedSpendingKey`] for the newly created account. The caller should store
|
||||
/// the returned spending key in a secure fashion.
|
||||
///
|
||||
/// If `seed` was imported from a backup and this method is being used to restore a
|
||||
/// previous wallet state, you should use this method to add all of the desired
|
||||
/// accounts before scanning the chain from the seed's birthday height.
|
||||
///
|
||||
/// By convention, wallets should only allow a new account to be generated after funds
|
||||
/// have been received by the currently-available account (in order to enable
|
||||
/// automated account recovery).
|
||||
///
|
||||
/// [ZIP 316]: https://zips.z.cash/zip-0316
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_createAccount(
|
||||
env: JNIEnv<'_>,
|
||||
_: JClass<'_>,
|
||||
db_data: JString<'_>,
|
||||
seed: jbyteArray,
|
||||
network_id: jint,
|
||||
) -> jobject {
|
||||
let res = panic::catch_unwind(|| {
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(&env, network, db_data)?;
|
||||
let seed = SecretVec::new(env.convert_byte_array(seed).unwrap());
|
||||
|
||||
let mut db_ops = db_data.get_update_ops()?;
|
||||
let (account, usk) = db_ops
|
||||
.create_account(&seed)
|
||||
.map_err(|e| format_err!("Error while initializing accounts: {}", e))?;
|
||||
|
||||
let encoded = usk.to_bytes(Era::Orchard);
|
||||
let output = env.new_object(
|
||||
"cash/z/ecc/android/sdk/model/UnifiedSpendingKey",
|
||||
"(I[B)V",
|
||||
&[
|
||||
JValue::Int(u32::from(account) as i32),
|
||||
JValue::Object(env.byte_array_from_slice(&encoded)?.into()),
|
||||
],
|
||||
)?;
|
||||
Ok(output.into_inner())
|
||||
});
|
||||
unwrap_exc_or(&env, res, ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Initialises the data database with the given set of unified full viewing keys.
|
||||
///
|
||||
/// This should only be used in special cases for implementing wallet recovery; prefer
|
||||
/// `RustBackend.createAccount` for normal account creation purposes.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_initAccountsTableWithKeys(
|
||||
env: JNIEnv<'_>,
|
||||
|
|
Loading…
Reference in New Issue