Orchard accounts
This commit is contained in:
parent
088a4d1ef5
commit
f8a692e3e5
|
@ -80,8 +80,17 @@ fn new_account_with_key(coin: u8, name: &str, key: &str, index: u32) -> anyhow::
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let (account, exists) =
|
let (account, exists) =
|
||||||
db.store_account(name, seed.as_deref(), index, sk.as_deref(), &ivk, &pa)?;
|
db.store_account(name, seed.as_deref(), index, sk.as_deref(), &ivk, &pa)?;
|
||||||
if !exists && c.chain.has_transparent() {
|
if !exists {
|
||||||
db.create_taddr(account)?;
|
if c.chain.has_transparent() {
|
||||||
|
db.create_taddr(account)?;
|
||||||
|
}
|
||||||
|
if c.chain.has_unified() {
|
||||||
|
db.create_orchard(account)?;
|
||||||
|
}
|
||||||
|
db.store_ua_settings(account, true, true, true)?;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
db.store_ua_settings(account, false, true, false)?;
|
||||||
}
|
}
|
||||||
Ok(account)
|
Ok(account)
|
||||||
}
|
}
|
||||||
|
|
26
src/db.rs
26
src/db.rs
|
@ -16,6 +16,7 @@ use zcash_primitives::consensus::{Network, NetworkUpgrade, Parameters};
|
||||||
use zcash_primitives::merkle_tree::IncrementalWitness;
|
use zcash_primitives::merkle_tree::IncrementalWitness;
|
||||||
use zcash_primitives::sapling::{Diversifier, Node, Note, Rseed, SaplingIvk};
|
use zcash_primitives::sapling::{Diversifier, Node, Note, Rseed, SaplingIvk};
|
||||||
use zcash_primitives::zip32::{DiversifierIndex, ExtendedFullViewingKey};
|
use zcash_primitives::zip32::{DiversifierIndex, ExtendedFullViewingKey};
|
||||||
|
use crate::orchard::derive_orchard_keys;
|
||||||
use crate::sync;
|
use crate::sync;
|
||||||
|
|
||||||
mod migration;
|
mod migration;
|
||||||
|
@ -142,7 +143,7 @@ impl DbAdapter {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
pub fn init_db(&mut self) -> anyhow::Result<()> {
|
pub fn init_db(&mut self) -> anyhow::Result<()> {
|
||||||
migration::init_db(&self.connection)?;
|
migration::init_db(&self.connection, self.network())?;
|
||||||
self.delete_incomplete_scan()?;
|
self.delete_incomplete_scan()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -893,14 +894,33 @@ impl DbAdapter {
|
||||||
let bip44_path = format!("m/44'/{}'/0'/0/{}", self.network().coin_type(), aindex);
|
let bip44_path = format!("m/44'/{}'/0'/0/{}", self.network().coin_type(), aindex);
|
||||||
let (sk, address) = derive_tkeys(self.network(), &seed, &bip44_path)?;
|
let (sk, address) = derive_tkeys(self.network(), &seed, &bip44_path)?;
|
||||||
self.connection.execute(
|
self.connection.execute(
|
||||||
"INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3) \
|
"INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING",
|
||||||
ON CONFLICT DO NOTHING",
|
|
||||||
params![account, &sk, &address],
|
params![account, &sk, &address],
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_orchard(&self, account: u32) -> anyhow::Result<()> {
|
||||||
|
let AccountData { seed, aindex, .. } = self.get_account_info(account)?;
|
||||||
|
if let Some(seed) = seed {
|
||||||
|
let keys = derive_orchard_keys(self.network().coin_type(), &seed, aindex);
|
||||||
|
self.connection.execute(
|
||||||
|
"INSERT INTO orchard_addrs(account, sk, fvk) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING",
|
||||||
|
params![account, &keys.sk, &keys.fvk],
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store_ua_settings(&self, account: u32, transparent: bool, sapling: bool, orchard: bool) -> anyhow::Result<()> {
|
||||||
|
self.connection.execute(
|
||||||
|
"INSERT INTO ua_settings(account, transparent, sapling, orchard) VALUES (?1, ?2, ?3, ?4) ON CONFLICT DO NOTHING",
|
||||||
|
params![account, transparent, sapling, orchard],
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn store_historical_prices(
|
pub fn store_historical_prices(
|
||||||
&mut self,
|
&mut self,
|
||||||
prices: &[Quote],
|
prices: &[Quote],
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use rusqlite::{params, Connection, OptionalExtension};
|
use rusqlite::{params, Connection, OptionalExtension};
|
||||||
|
use zcash_primitives::consensus::{Network, Parameters};
|
||||||
|
use crate::orchard::derive_orchard_keys;
|
||||||
|
|
||||||
pub fn get_schema_version(connection: &Connection) -> anyhow::Result<u32> {
|
pub fn get_schema_version(connection: &Connection) -> anyhow::Result<u32> {
|
||||||
let version: Option<u32> = connection
|
let version: Option<u32> = connection
|
||||||
|
@ -32,7 +34,7 @@ pub fn reset_db(connection: &Connection) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_db(connection: &Connection) -> anyhow::Result<()> {
|
pub fn init_db(connection: &Connection, network: &Network) -> anyhow::Result<()> {
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"CREATE TABLE IF NOT EXISTS schema_version (
|
"CREATE TABLE IF NOT EXISTS schema_version (
|
||||||
id INTEGER PRIMARY KEY NOT NULL,
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
@ -178,6 +180,16 @@ pub fn init_db(connection: &Connection) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if version < 5 {
|
if version < 5 {
|
||||||
|
connection.execute("CREATE TABLE orchard_addrs(
|
||||||
|
account INTEGER PRIMARY KEY,
|
||||||
|
sk BLOB,
|
||||||
|
fvk BLOB NOT NULL)", [])?;
|
||||||
|
connection.execute("CREATE TABLE ua_settings(
|
||||||
|
account INTEGER PRIMARY KEY,
|
||||||
|
transparent BOOL NOT NULL,
|
||||||
|
sapling BOOL NOT NULL,
|
||||||
|
orchard BOOL NOT NULL)", [])?;
|
||||||
|
upgrade_accounts(&connection, network)?;
|
||||||
connection.execute("CREATE TABLE sapling_tree(
|
connection.execute("CREATE TABLE sapling_tree(
|
||||||
height INTEGER PRIMARY KEY,
|
height INTEGER PRIMARY KEY,
|
||||||
tree BLOB NOT NULL)", [])?;
|
tree BLOB NOT NULL)", [])?;
|
||||||
|
@ -227,3 +239,29 @@ pub fn init_db(connection: &Connection) -> anyhow::Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn upgrade_accounts(connection: &Connection, network: &Network) -> anyhow::Result<()> {
|
||||||
|
let mut statement = connection.prepare("SELECT a.id_account, a.seed, a.aindex, t.address FROM accounts a LEFT JOIN taddrs t ON a.id_account = t.account")?;
|
||||||
|
let rows = statement.query_map([], |row| {
|
||||||
|
let id_account: u32 = row.get(0)?;
|
||||||
|
let seed: Option<String> = row.get(1)?;
|
||||||
|
let aindex: u32 = row.get(2)?;
|
||||||
|
let transparent_address: Option<String> = row.get(3)?;
|
||||||
|
Ok((id_account, seed, aindex, transparent_address.is_some()))
|
||||||
|
})?;
|
||||||
|
let mut res = vec![];
|
||||||
|
for row in rows {
|
||||||
|
res.push(row?);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id_account, seed, aindex, has_transparent) in res {
|
||||||
|
let has_orchard = seed.is_some();
|
||||||
|
if let Some(seed) = seed {
|
||||||
|
let orchard_keys = derive_orchard_keys(network.coin_type(), &seed, aindex);
|
||||||
|
connection.execute("INSERT INTO orchard_addrs(account, sk, fvk) VALUES (?1,?2,?3)", params![id_account, &orchard_keys.sk, &orchard_keys.fvk])?;
|
||||||
|
}
|
||||||
|
connection.execute("INSERT INTO ua_settings(account, transparent, sapling, orchard) VALUES (?1,?2,?3,?4)",
|
||||||
|
params![id_account, has_transparent, true, has_orchard])?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
//! DEAD CODE - Candidate for deletion
|
||||||
|
//!
|
||||||
|
|
||||||
use bech32::{ToBase32, Variant};
|
use bech32::{ToBase32, Variant};
|
||||||
use bip39::{Language, Mnemonic, Seed};
|
use bip39::{Language, Mnemonic, Seed};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub fn decode_key(
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::anyhow!("Not a valid key"))
|
Err(anyhow::anyhow!("Not a valid key"))
|
||||||
};
|
};
|
||||||
|
// TODO: Accept UA viewing key
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ pub fn is_valid_key(coin: u8, key: &str) -> i8 {
|
||||||
{
|
{
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
// TODO: Accept UA viewing key
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ mod hash;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod sapling;
|
mod sapling;
|
||||||
mod orchard;
|
mod orchard;
|
||||||
mod key;
|
// mod key;
|
||||||
mod key2;
|
mod key2;
|
||||||
mod mempool;
|
mod mempool;
|
||||||
mod misc;
|
mod misc;
|
||||||
|
@ -125,7 +125,7 @@ pub use crate::coinconfig::{
|
||||||
};
|
};
|
||||||
pub use crate::db::{AccountData, AccountInfo, AccountRec, DbAdapter, TxRec, DbAdapterBuilder};
|
pub use crate::db::{AccountData, AccountInfo, AccountRec, DbAdapter, TxRec, DbAdapterBuilder};
|
||||||
pub use crate::fountain::{FountainCodes, RaptorQDrops};
|
pub use crate::fountain::{FountainCodes, RaptorQDrops};
|
||||||
pub use crate::key::KeyHelpers;
|
// pub use crate::key::KeyHelpers;
|
||||||
pub use crate::lw_rpc::compact_tx_streamer_client::CompactTxStreamerClient;
|
pub use crate::lw_rpc::compact_tx_streamer_client::CompactTxStreamerClient;
|
||||||
pub use crate::lw_rpc::*;
|
pub use crate::lw_rpc::*;
|
||||||
pub use crate::pay::{broadcast_tx, Tx, TxIn, TxOut};
|
pub use crate::pay::{broadcast_tx, Tx, TxIn, TxOut};
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
mod hash;
|
mod hash;
|
||||||
mod note;
|
mod note;
|
||||||
|
mod key;
|
||||||
|
|
||||||
pub use note::{OrchardDecrypter, OrchardViewKey, DecryptedOrchardNote};
|
pub use note::{OrchardDecrypter, OrchardViewKey, DecryptedOrchardNote};
|
||||||
pub use hash::OrchardHasher;
|
pub use hash::OrchardHasher;
|
||||||
|
pub use key::derive_orchard_keys;
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
use bip39::{Language, Mnemonic};
|
||||||
|
use orchard::keys::{FullViewingKey, SpendingKey};
|
||||||
|
|
||||||
|
pub struct OrchardKeyBytes {
|
||||||
|
pub sk: [u8; 32],
|
||||||
|
pub fvk: [u8; 96],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn derive_orchard_keys(coin_type: u32, seed: &str, account_index: u32) -> OrchardKeyBytes {
|
||||||
|
let mnemonic = Mnemonic::from_phrase(seed, Language::English).unwrap();
|
||||||
|
let sk = SpendingKey::from_zip32_seed(
|
||||||
|
mnemonic.entropy(),
|
||||||
|
coin_type,
|
||||||
|
account_index,
|
||||||
|
).unwrap();
|
||||||
|
let fvk = FullViewingKey::from(&sk);
|
||||||
|
OrchardKeyBytes {
|
||||||
|
sk: sk.to_bytes().clone(),
|
||||||
|
fvk: fvk.to_bytes()
|
||||||
|
}
|
||||||
|
}
|
|
@ -174,8 +174,6 @@ pub async fn sync_async<'a>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn sync_async_old(
|
fn sync_async_old(
|
||||||
coin_type: CoinType,
|
coin_type: CoinType,
|
||||||
_chunk_size: u32,
|
_chunk_size: u32,
|
||||||
|
|
Loading…
Reference in New Issue