Orchard accounts

This commit is contained in:
Hanh 2022-10-29 14:40:05 +08:00
parent 088a4d1ef5
commit f8a692e3e5
9 changed files with 103 additions and 10 deletions

View File

@ -80,9 +80,18 @@ 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 {
if c.chain.has_transparent() {
db.create_taddr(account)?; 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)
} }

View File

@ -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],

View File

@ -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(())
}

View File

@ -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;

View File

@ -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
} }

View File

@ -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};

View File

@ -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;

21
src/orchard/key.rs Normal file
View File

@ -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()
}
}

View File

@ -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,