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 (account, exists) =
|
||||
db.store_account(name, seed.as_deref(), index, sk.as_deref(), &ivk, &pa)?;
|
||||
if !exists && c.chain.has_transparent() {
|
||||
db.create_taddr(account)?;
|
||||
if !exists {
|
||||
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)
|
||||
}
|
||||
|
|
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::sapling::{Diversifier, Node, Note, Rseed, SaplingIvk};
|
||||
use zcash_primitives::zip32::{DiversifierIndex, ExtendedFullViewingKey};
|
||||
use crate::orchard::derive_orchard_keys;
|
||||
use crate::sync;
|
||||
|
||||
mod migration;
|
||||
|
@ -142,7 +143,7 @@ impl DbAdapter {
|
|||
// }
|
||||
//
|
||||
pub fn init_db(&mut self) -> anyhow::Result<()> {
|
||||
migration::init_db(&self.connection)?;
|
||||
migration::init_db(&self.connection, self.network())?;
|
||||
self.delete_incomplete_scan()?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -893,14 +894,33 @@ impl DbAdapter {
|
|||
let bip44_path = format!("m/44'/{}'/0'/0/{}", self.network().coin_type(), aindex);
|
||||
let (sk, address) = derive_tkeys(self.network(), &seed, &bip44_path)?;
|
||||
self.connection.execute(
|
||||
"INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3) \
|
||||
ON CONFLICT DO NOTHING",
|
||||
"INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING",
|
||||
params![account, &sk, &address],
|
||||
)?;
|
||||
}
|
||||
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(
|
||||
&mut self,
|
||||
prices: &[Quote],
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
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> {
|
||||
let version: Option<u32> = connection
|
||||
|
@ -32,7 +34,7 @@ pub fn reset_db(connection: &Connection) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init_db(connection: &Connection) -> anyhow::Result<()> {
|
||||
pub fn init_db(connection: &Connection, network: &Network) -> anyhow::Result<()> {
|
||||
connection.execute(
|
||||
"CREATE TABLE IF NOT EXISTS schema_version (
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
|
@ -178,6 +180,16 @@ pub fn init_db(connection: &Connection) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
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(
|
||||
height INTEGER PRIMARY KEY,
|
||||
tree BLOB NOT NULL)", [])?;
|
||||
|
@ -227,3 +239,29 @@ pub fn init_db(connection: &Connection) -> anyhow::Result<()> {
|
|||
|
||||
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 bip39::{Language, Mnemonic, Seed};
|
||||
use rand::rngs::OsRng;
|
||||
|
|
|
@ -31,6 +31,7 @@ pub fn decode_key(
|
|||
} else {
|
||||
Err(anyhow::anyhow!("Not a valid key"))
|
||||
};
|
||||
// TODO: Accept UA viewing key
|
||||
res
|
||||
}
|
||||
|
||||
|
@ -48,6 +49,7 @@ pub fn is_valid_key(coin: u8, key: &str) -> i8 {
|
|||
{
|
||||
return 2;
|
||||
}
|
||||
// TODO: Accept UA viewing key
|
||||
-1
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ mod hash;
|
|||
mod sync;
|
||||
mod sapling;
|
||||
mod orchard;
|
||||
mod key;
|
||||
// mod key;
|
||||
mod key2;
|
||||
mod mempool;
|
||||
mod misc;
|
||||
|
@ -125,7 +125,7 @@ pub use crate::coinconfig::{
|
|||
};
|
||||
pub use crate::db::{AccountData, AccountInfo, AccountRec, DbAdapter, TxRec, DbAdapterBuilder};
|
||||
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::*;
|
||||
pub use crate::pay::{broadcast_tx, Tx, TxIn, TxOut};
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
mod hash;
|
||||
mod note;
|
||||
mod key;
|
||||
|
||||
pub use note::{OrchardDecrypter, OrchardViewKey, DecryptedOrchardNote};
|
||||
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(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn sync_async_old(
|
||||
coin_type: CoinType,
|
||||
_chunk_size: u32,
|
||||
|
|
Loading…
Reference in New Issue