2021-06-29 00:04:12 -07:00
use crate ::chain ::{ Nf , NfRef } ;
2021-11-11 17:39:50 -08:00
use crate ::contact ::Contact ;
2021-08-16 06:07:04 -07:00
use crate ::prices ::Quote ;
2022-06-07 09:58:24 -07:00
use crate ::taddr ::{ derive_tkeys , TBalance } ;
2021-09-08 07:10:22 -07:00
use crate ::transaction ::TransactionInfo ;
2022-03-07 06:47:06 -08:00
use crate ::{ CTree , Witness } ;
2022-05-19 09:19:04 -07:00
use rusqlite ::{ params , Connection , OptionalExtension , Transaction } ;
2022-06-07 09:58:24 -07:00
use serde ::{ Deserialize , Serialize } ;
2021-06-26 02:52:03 -07:00
use std ::collections ::HashMap ;
2021-07-30 01:11:44 -07:00
use zcash_client_backend ::encoding ::decode_extended_full_viewing_key ;
2022-06-07 09:58:24 -07:00
use zcash_params ::coin ::{ get_coin_chain , get_coin_id , CoinType } ;
2022-03-07 06:47:06 -08:00
use zcash_primitives ::consensus ::{ Network , NetworkUpgrade , Parameters } ;
2021-06-26 02:52:03 -07:00
use zcash_primitives ::merkle_tree ::IncrementalWitness ;
2021-07-27 22:07:20 -07:00
use zcash_primitives ::sapling ::{ Diversifier , Node , Note , Rseed , SaplingIvk } ;
2021-07-16 01:42:29 -07:00
use zcash_primitives ::zip32 ::{ DiversifierIndex , ExtendedFullViewingKey } ;
2021-07-09 22:44:13 -07:00
mod migration ;
2021-06-26 02:52:03 -07:00
#[ allow(dead_code) ]
pub const DEFAULT_DB_PATH : & str = " zec.db " ;
2021-06-21 17:33:13 -07:00
pub struct DbAdapter {
2022-03-07 06:47:06 -08:00
pub coin_type : CoinType ,
2021-06-28 21:49:00 -07:00
pub connection : Connection ,
2021-06-21 17:33:13 -07:00
}
pub struct ReceivedNote {
2021-06-29 00:04:12 -07:00
pub account : u32 ,
2021-06-21 17:33:13 -07:00
pub height : u32 ,
pub output_index : u32 ,
pub diversifier : Vec < u8 > ,
pub value : u64 ,
pub rcm : Vec < u8 > ,
pub nf : Vec < u8 > ,
2021-06-24 05:08:20 -07:00
pub spent : Option < u32 > ,
}
2021-11-11 17:39:50 -08:00
#[ derive(Clone) ]
2021-06-24 05:08:20 -07:00
pub struct SpendableNote {
2021-06-28 21:49:00 -07:00
pub id : u32 ,
2021-06-24 05:08:20 -07:00
pub note : Note ,
pub diversifier : Diversifier ,
pub witness : IncrementalWitness < Node > ,
2021-06-21 17:33:13 -07:00
}
2021-07-27 22:07:20 -07:00
pub struct AccountViewKey {
pub fvk : ExtendedFullViewingKey ,
pub ivk : SaplingIvk ,
pub viewonly : bool ,
}
impl AccountViewKey {
pub fn from_fvk ( fvk : & ExtendedFullViewingKey ) -> AccountViewKey {
AccountViewKey {
fvk : fvk . clone ( ) ,
ivk : fvk . fvk . vk . ivk ( ) ,
viewonly : false ,
}
}
}
2022-02-28 07:35:29 -08:00
#[ derive(Serialize, Deserialize) ]
pub struct AccountBackup {
2022-03-07 06:47:06 -08:00
pub coin : u8 ,
2022-02-28 07:35:29 -08:00
pub name : String ,
pub seed : Option < String > ,
2022-03-07 06:47:06 -08:00
pub index : u32 ,
2022-02-28 07:35:29 -08:00
pub z_sk : Option < String > ,
pub ivk : String ,
pub z_addr : String ,
pub t_sk : Option < String > ,
pub t_addr : Option < String > ,
}
2021-06-21 17:33:13 -07:00
impl DbAdapter {
2022-04-19 09:47:08 -07:00
pub fn new ( coin_type : CoinType , db_path : & str ) -> anyhow ::Result < DbAdapter > {
2021-06-21 17:33:13 -07:00
let connection = Connection ::open ( db_path ) ? ;
2022-06-07 09:58:24 -07:00
connection . query_row ( " PRAGMA journal_mode = WAL " , [ ] , | _ | Ok ( ( ) ) ) ? ;
2022-05-19 09:19:04 -07:00
connection . execute ( " PRAGMA synchronous = NORMAL " , [ ] ) ? ;
2022-06-07 09:58:24 -07:00
Ok ( DbAdapter {
coin_type ,
connection ,
} )
2021-06-21 17:33:13 -07:00
}
2021-09-02 19:56:10 -07:00
pub fn begin_transaction ( & mut self ) -> anyhow ::Result < Transaction > {
let tx = self . connection . transaction ( ) ? ;
Ok ( tx )
}
//
// pub fn commit(&self) -> anyhow::Result<()> {
2022-05-19 09:19:04 -07:00
// self.connection.execute("COMMIT", [])?;
2021-09-02 19:56:10 -07:00
// Ok(())
// }
//
2021-06-21 17:33:13 -07:00
pub fn init_db ( & self ) -> anyhow ::Result < ( ) > {
2021-08-09 07:13:10 -07:00
migration ::init_db ( & self . connection ) ? ;
2021-06-24 05:08:20 -07:00
Ok ( ( ) )
}
2021-06-21 17:33:13 -07:00
2021-11-26 19:34:26 -08:00
pub fn reset_db ( & self ) -> anyhow ::Result < ( ) > {
migration ::reset_db ( & self . connection ) ? ;
Ok ( ( ) )
}
2021-07-16 01:42:29 -07:00
pub fn store_account (
& self ,
name : & str ,
seed : Option < & str > ,
2022-03-07 06:47:06 -08:00
index : u32 ,
2021-07-16 01:42:29 -07:00
sk : Option < & str > ,
ivk : & str ,
address : & str ,
2022-06-08 05:48:16 -07:00
) -> anyhow ::Result < ( u32 , bool ) > {
2021-11-11 17:39:50 -08:00
let mut statement = self
. connection
. prepare ( " SELECT id_account FROM accounts WHERE ivk = ?1 " ) ? ;
2022-06-08 05:48:16 -07:00
let exists = statement . exists ( params! [ ivk ] ) ? ;
2021-06-26 02:52:03 -07:00
self . connection . execute (
2022-03-07 06:47:06 -08:00
" INSERT INTO accounts(name, seed, aindex, sk, ivk, address) VALUES (?1, ?2, ?3, ?4, ?5, ?6)
2021-06-26 02:52:03 -07:00
ON CONFLICT DO NOTHING " ,
2022-03-07 06:47:06 -08:00
params! [ name , seed , index , sk , ivk , address ] ,
2021-06-26 02:52:03 -07:00
) ? ;
2022-06-08 05:48:16 -07:00
let id_account : u32 = self . connection . query_row (
2021-07-27 22:07:20 -07:00
" SELECT id_account FROM accounts WHERE ivk = ?1 " ,
params! [ ivk ] ,
2021-06-29 00:04:12 -07:00
| row | row . get ( 0 ) ,
) ? ;
2022-06-08 05:48:16 -07:00
Ok ( ( id_account , exists ) )
2021-06-21 17:33:13 -07:00
}
2022-06-08 05:48:16 -07:00
pub fn next_account_id ( & self , seed : & str ) -> anyhow ::Result < u32 > {
2022-06-07 09:58:24 -07:00
let index = self . connection . query_row (
" SELECT MAX(aindex) FROM accounts WHERE seed = ?1 " ,
[ seed ] ,
| row | {
2022-03-07 06:47:06 -08:00
let aindex : Option < i32 > = row . get ( 0 ) ? ;
Ok ( aindex . unwrap_or ( - 1 ) )
2022-06-07 09:58:24 -07:00
} ,
) ? + 1 ;
2022-06-08 05:48:16 -07:00
Ok ( index as u32 )
2022-03-07 06:47:06 -08:00
}
2022-07-16 20:23:56 -07:00
pub fn store_transparent_key (
& self ,
id_account : u32 ,
sk : & str ,
addr : & str ,
) -> anyhow ::Result < ( ) > {
self . connection . execute (
" UPDATE taddrs SET sk = ?1, address = ?2 WHERE account = ?3 " ,
params! [ sk , addr , id_account ] ,
) ? ;
Ok ( ( ) )
}
2021-07-27 22:07:20 -07:00
pub fn get_fvks ( & self ) -> anyhow ::Result < HashMap < u32 , AccountViewKey > > {
2021-07-16 01:42:29 -07:00
let mut statement = self
. connection
2021-07-27 22:07:20 -07:00
. prepare ( " SELECT id_account, ivk, sk FROM accounts " ) ? ;
2022-05-19 09:19:04 -07:00
let rows = statement . query_map ( [ ] , | row | {
2021-06-29 00:04:12 -07:00
let account : u32 = row . get ( 0 ) ? ;
let ivk : String = row . get ( 1 ) ? ;
2021-07-27 22:07:20 -07:00
let sk : Option < String > = row . get ( 2 ) ? ;
2021-07-30 01:11:44 -07:00
let fvk = decode_extended_full_viewing_key (
2022-03-07 06:47:06 -08:00
self . network ( ) . hrp_sapling_extended_full_viewing_key ( ) ,
2021-07-30 01:11:44 -07:00
& ivk ,
)
. unwrap ( )
. unwrap ( ) ;
2021-07-27 22:07:20 -07:00
let ivk = fvk . fvk . vk . ivk ( ) ;
2021-07-30 01:11:44 -07:00
Ok ( (
account ,
AccountViewKey {
fvk ,
ivk ,
viewonly : sk . is_none ( ) ,
} ,
) )
2021-06-29 00:04:12 -07:00
} ) ? ;
2021-07-27 22:07:20 -07:00
let mut fvks : HashMap < u32 , AccountViewKey > = HashMap ::new ( ) ;
2021-06-29 00:04:12 -07:00
for r in rows {
let row = r ? ;
fvks . insert ( row . 0 , row . 1 ) ;
}
Ok ( fvks )
2021-06-26 02:52:03 -07:00
}
2021-06-21 17:33:13 -07:00
pub fn trim_to_height ( & mut self , height : u32 ) -> anyhow ::Result < ( ) > {
let tx = self . connection . transaction ( ) ? ;
tx . execute ( " DELETE FROM blocks WHERE height >= ?1 " , params! [ height ] ) ? ;
2021-06-26 02:52:03 -07:00
tx . execute (
" DELETE FROM sapling_witnesses WHERE height >= ?1 " ,
params! [ height ] ,
) ? ;
tx . execute (
" DELETE FROM received_notes WHERE height >= ?1 " ,
params! [ height ] ,
) ? ;
2021-12-11 22:19:58 -08:00
tx . execute (
" UPDATE received_notes SET spent = NULL WHERE spent >= ?1 " ,
params! [ height ] ,
) ? ;
2021-06-26 02:52:03 -07:00
tx . execute (
" DELETE FROM transactions WHERE height >= ?1 " ,
params! [ height ] ,
) ? ;
2022-06-07 09:58:24 -07:00
tx . execute ( " DELETE FROM messages WHERE height >= ?1 " , params! [ height ] ) ? ;
2021-06-21 17:33:13 -07:00
tx . commit ( ) ? ;
Ok ( ( ) )
}
2022-04-15 23:23:50 -07:00
pub fn get_txhash ( & self , id_tx : u32 ) -> anyhow ::Result < ( u32 , u32 , u32 , Vec < u8 > , String ) > {
let ( account , height , timestamp , tx_hash , ivk ) = self . connection . query_row (
" SELECT account, height, timestamp, txid, ivk FROM transactions t, accounts a WHERE id_tx = ?1 AND t.account = a.id_account " ,
2021-07-16 01:42:29 -07:00
params! [ id_tx ] ,
2021-07-09 22:44:13 -07:00
| row | {
let account : u32 = row . get ( 0 ) ? ;
let height : u32 = row . get ( 1 ) ? ;
2022-04-15 23:23:50 -07:00
let timestamp : u32 = row . get ( 2 ) ? ;
let tx_hash : Vec < u8 > = row . get ( 3 ) ? ;
let ivk : String = row . get ( 4 ) ? ;
Ok ( ( account , height , timestamp , tx_hash , ivk ) )
2021-07-16 01:42:29 -07:00
} ,
) ? ;
2022-04-15 23:23:50 -07:00
Ok ( ( account , height , timestamp , tx_hash , ivk ) )
2021-07-09 22:44:13 -07:00
}
2021-06-26 02:52:03 -07:00
pub fn store_block (
2022-07-12 00:28:58 -07:00
connection : & Connection ,
2021-06-26 02:52:03 -07:00
height : u32 ,
hash : & [ u8 ] ,
timestamp : u32 ,
tree : & CTree ,
) -> anyhow ::Result < ( ) > {
log ::debug! ( " +block " ) ;
2021-06-21 17:33:13 -07:00
let mut bb : Vec < u8 > = vec! [ ] ;
tree . write ( & mut bb ) ? ;
2022-07-12 00:28:58 -07:00
connection . execute (
2021-06-26 02:52:03 -07:00
" INSERT INTO blocks(height, hash, timestamp, sapling_tree)
VALUES ( ? 1 , ? 2 , ? 3 , ? 4 )
ON CONFLICT DO NOTHING " ,
params! [ height , hash , timestamp , & bb ] ,
) ? ;
log ::debug! ( " -block " ) ;
2021-06-21 17:33:13 -07:00
Ok ( ( ) )
}
2021-06-26 02:52:03 -07:00
pub fn store_transaction (
txid : & [ u8 ] ,
2021-06-29 00:04:12 -07:00
account : u32 ,
2021-06-26 02:52:03 -07:00
height : u32 ,
timestamp : u32 ,
tx_index : u32 ,
2021-11-11 17:39:50 -08:00
db_tx : & Transaction ,
2021-06-26 02:52:03 -07:00
) -> anyhow ::Result < u32 > {
log ::debug! ( " +transaction " ) ;
2021-09-02 19:56:10 -07:00
db_tx . execute (
2021-06-29 00:04:12 -07:00
" INSERT INTO transactions(account, txid, height, timestamp, tx_index, value)
VALUES ( ? 1 , ? 2 , ? 3 , ? 4 , ? 5 , 0 )
2021-06-26 02:52:03 -07:00
ON CONFLICT DO NOTHING " ,
2021-06-29 00:04:12 -07:00
params! [ account , txid , height , timestamp , tx_index ] ,
2021-06-26 02:52:03 -07:00
) ? ;
2021-09-02 19:56:10 -07:00
let id_tx : u32 = db_tx . query_row (
2021-07-11 08:42:52 -07:00
" SELECT id_tx FROM transactions WHERE account = ?1 AND txid = ?2 " ,
params! [ account , txid ] ,
2021-06-26 02:52:03 -07:00
| row | row . get ( 0 ) ,
) ? ;
log ::debug! ( " -transaction {} " , id_tx ) ;
2021-06-21 17:33:13 -07:00
Ok ( id_tx )
}
2021-06-26 02:52:03 -07:00
pub fn store_received_note (
note : & ReceivedNote ,
id_tx : u32 ,
position : usize ,
2021-11-11 17:39:50 -08:00
db_tx : & Transaction ,
2021-06-26 02:52:03 -07:00
) -> anyhow ::Result < u32 > {
log ::debug! ( " +received_note {} " , id_tx ) ;
2021-09-02 19:56:10 -07:00
db_tx . execute ( " INSERT INTO received_notes(account, tx, height, position, output_index, diversifier, value, rcm, nf, spent)
2021-06-29 00:04:12 -07:00
VALUES ( ? 1 , ? 2 , ? 3 , ? 4 , ? 5 , ? 6 , ? 7 , ? 8 , ? 9 , ? 10 )
ON CONFLICT DO NOTHING " , params![note.account, id_tx, note.height, position as u32, note.output_index, note.diversifier, note.value as i64, note.rcm, note.nf, note.spent])?;
2021-09-02 19:56:10 -07:00
let id_note : u32 = db_tx . query_row (
2021-06-26 02:52:03 -07:00
" SELECT id_note FROM received_notes WHERE tx = ?1 AND output_index = ?2 " ,
params! [ id_tx , note . output_index ] ,
| row | row . get ( 0 ) ,
) ? ;
log ::debug! ( " -received_note " ) ;
2021-06-21 17:33:13 -07:00
Ok ( id_note )
}
2021-06-26 02:52:03 -07:00
pub fn store_witnesses (
2022-07-12 00:28:58 -07:00
connection : & Connection ,
2021-06-26 02:52:03 -07:00
witness : & Witness ,
height : u32 ,
id_note : u32 ,
) -> anyhow ::Result < ( ) > {
log ::debug! ( " +witnesses " ) ;
2021-06-21 17:33:13 -07:00
let mut bb : Vec < u8 > = vec! [ ] ;
witness . write ( & mut bb ) ? ;
2022-07-12 00:28:58 -07:00
connection . execute (
2021-06-26 02:52:03 -07:00
" INSERT INTO sapling_witnesses(note, height, witness) VALUES (?1, ?2, ?3)
ON CONFLICT DO NOTHING " ,
params! [ id_note , height , bb ] ,
) ? ;
log ::debug! ( " -witnesses " ) ;
Ok ( ( ) )
}
2021-07-09 22:44:13 -07:00
pub fn store_tx_metadata ( & self , id_tx : u32 , tx_info : & TransactionInfo ) -> anyhow ::Result < ( ) > {
self . connection . execute (
2021-07-16 01:42:29 -07:00
" UPDATE transactions SET address = ?1, memo = ?2 WHERE id_tx = ?3 " ,
2021-07-18 08:57:43 -07:00
params! [ tx_info . address , & tx_info . memo , id_tx ] ,
2021-07-09 22:44:13 -07:00
) ? ;
Ok ( ( ) )
}
2021-09-02 19:56:10 -07:00
pub fn add_value ( id_tx : u32 , value : i64 , db_tx : & Transaction ) -> anyhow ::Result < ( ) > {
db_tx . execute (
2021-06-26 02:52:03 -07:00
" UPDATE transactions SET value = value + ?2 WHERE id_tx = ?1 " ,
params! [ id_tx , value ] ,
) ? ;
2021-06-21 17:33:13 -07:00
Ok ( ( ) )
}
2021-09-02 19:56:10 -07:00
pub fn get_received_note_value ( nf : & Nf , db_tx : & Transaction ) -> anyhow ::Result < ( u32 , i64 ) > {
let ( account , value ) = db_tx . query_row (
2021-06-29 00:04:12 -07:00
" SELECT account, value FROM received_notes WHERE nf = ?1 " ,
2021-06-26 02:52:03 -07:00
params! [ nf . 0. to_vec ( ) ] ,
2021-06-29 00:04:12 -07:00
| row | {
let account : u32 = row . get ( 0 ) ? ;
let value : i64 = row . get ( 1 ) ? ;
Ok ( ( account , value ) )
} ,
2021-06-26 02:52:03 -07:00
) ? ;
2021-06-29 00:04:12 -07:00
Ok ( ( account , value ) )
2021-06-26 02:52:03 -07:00
}
2021-06-29 00:04:12 -07:00
pub fn get_balance ( & self , account : u32 ) -> anyhow ::Result < u64 > {
2021-06-26 02:52:03 -07:00
let balance : Option < i64 > = self . connection . query_row (
2021-06-29 00:04:12 -07:00
" SELECT SUM(value) FROM received_notes WHERE (spent IS NULL OR spent = 0) AND account = ?1 " ,
params! [ account ] ,
2021-06-26 02:52:03 -07:00
| row | row . get ( 0 ) ,
) ? ;
Ok ( balance . unwrap_or ( 0 ) as u64 )
}
2021-06-24 05:08:20 -07:00
pub fn get_last_sync_height ( & self ) -> anyhow ::Result < Option < u32 > > {
2021-06-26 02:52:03 -07:00
let height : Option < u32 > =
self . connection
2022-06-07 09:58:24 -07:00
. query_row ( " SELECT MAX(height) FROM blocks " , [ ] , | row | row . get ( 0 ) ) ? ;
2021-06-24 05:08:20 -07:00
Ok ( height )
}
pub fn get_db_height ( & self ) -> anyhow ::Result < u32 > {
let height : u32 = self . get_last_sync_height ( ) ? . unwrap_or_else ( | | {
2022-03-07 06:47:06 -08:00
self . network ( )
2021-06-24 05:08:20 -07:00
. activation_height ( NetworkUpgrade ::Sapling )
. unwrap ( )
. into ( )
} ) ;
2021-06-21 17:33:13 -07:00
Ok ( height )
}
2021-06-26 02:52:03 -07:00
pub fn get_db_hash ( & self , height : u32 ) -> anyhow ::Result < Option < [ u8 ; 32 ] > > {
2021-07-16 01:42:29 -07:00
let hash : Option < Vec < u8 > > = self
. connection
. query_row (
" SELECT hash FROM blocks WHERE height = ?1 " ,
params! [ height ] ,
| row | row . get ( 0 ) ,
)
. optional ( ) ? ;
2021-06-26 02:52:03 -07:00
Ok ( hash . map ( | h | {
let mut hash = [ 0 u8 ; 32 ] ;
hash . copy_from_slice ( & h ) ;
hash
} ) )
}
2021-06-21 17:33:13 -07:00
pub fn get_tree ( & self ) -> anyhow ::Result < ( CTree , Vec < Witness > ) > {
let res = self . connection . query_row (
" SELECT height, sapling_tree FROM blocks WHERE height = (SELECT MAX(height) FROM blocks) " ,
2022-05-19 09:19:04 -07:00
[ ] , | row | {
2021-06-21 17:33:13 -07:00
let height : u32 = row . get ( 0 ) ? ;
let tree : Vec < u8 > = row . get ( 1 ) ? ;
Ok ( ( height , tree ) )
} ) . optional ( ) ? ;
Ok ( match res {
Some ( ( height , tree ) ) = > {
let tree = CTree ::read ( & * tree ) ? ;
let mut statement = self . connection . prepare (
2021-06-29 00:04:12 -07:00
" SELECT id_note, witness FROM sapling_witnesses w, received_notes n WHERE w.height = ?1 AND w.note = n.id_note AND (n.spent IS NULL OR n.spent = 0) " ) ? ;
2021-06-21 17:33:13 -07:00
let ws = statement . query_map ( params! [ height ] , | row | {
let id_note : u32 = row . get ( 0 ) ? ;
2021-06-28 21:49:00 -07:00
let witness : Vec < u8 > = row . get ( 1 ) ? ;
Ok ( Witness ::read ( id_note , & * witness ) . unwrap ( ) )
2021-06-21 17:33:13 -07:00
} ) ? ;
let mut witnesses : Vec < Witness > = vec! [ ] ;
for w in ws {
witnesses . push ( w ? ) ;
}
( tree , witnesses )
2021-06-26 02:52:03 -07:00
}
None = > ( CTree ::new ( ) , vec! [ ] ) ,
2021-06-21 17:33:13 -07:00
} )
}
2021-06-24 05:08:20 -07:00
2021-06-29 00:04:12 -07:00
pub fn get_nullifiers ( & self ) -> anyhow ::Result < HashMap < Nf , NfRef > > {
2021-07-16 01:42:29 -07:00
let mut statement = self . connection . prepare (
" SELECT id_note, account, nf FROM received_notes WHERE spent IS NULL OR spent = 0 " ,
) ? ;
2022-05-19 09:19:04 -07:00
let nfs_res = statement . query_map ( [ ] , | row | {
2021-06-24 05:08:20 -07:00
let id_note : u32 = row . get ( 0 ) ? ;
2021-06-29 00:04:12 -07:00
let account : u32 = row . get ( 1 ) ? ;
let nf_vec : Vec < u8 > = row . get ( 2 ) ? ;
2021-06-24 05:08:20 -07:00
let mut nf = [ 0 u8 ; 32 ] ;
nf . clone_from_slice ( & nf_vec ) ;
2021-07-16 01:42:29 -07:00
let nf_ref = NfRef { id_note , account } ;
2021-06-29 00:04:12 -07:00
Ok ( ( nf_ref , nf ) )
2021-06-24 05:08:20 -07:00
} ) ? ;
2021-06-29 00:04:12 -07:00
let mut nfs : HashMap < Nf , NfRef > = HashMap ::new ( ) ;
2021-06-24 05:08:20 -07:00
for n in nfs_res {
let n = n ? ;
nfs . insert ( Nf ( n . 1 ) , n . 0 ) ;
}
Ok ( nfs )
}
2021-07-16 01:42:29 -07:00
pub fn get_nullifier_amounts (
& self ,
account : u32 ,
unspent_only : bool ,
) -> anyhow ::Result < HashMap < Vec < u8 > , u64 > > {
2021-07-09 22:44:13 -07:00
let mut sql = " SELECT value, nf FROM received_notes WHERE account = ?1 " . to_string ( ) ;
if unspent_only {
sql + = " AND (spent IS NULL OR spent = 0) " ;
}
2021-07-16 01:42:29 -07:00
let mut statement = self . connection . prepare ( & sql ) ? ;
2021-06-29 00:04:12 -07:00
let nfs_res = statement . query_map ( params! [ account ] , | row | {
2021-06-26 02:52:03 -07:00
let amount : i64 = row . get ( 0 ) ? ;
let nf : Vec < u8 > = row . get ( 1 ) ? ;
Ok ( ( amount , nf ) )
} ) ? ;
let mut nfs : HashMap < Vec < u8 > , u64 > = HashMap ::new ( ) ;
for n in nfs_res {
let n = n ? ;
nfs . insert ( n . 1 , n . 0 as u64 ) ;
}
Ok ( nfs )
}
2021-07-11 08:42:52 -07:00
pub fn get_nullifiers_raw ( & self ) -> anyhow ::Result < Vec < ( u32 , u64 , Vec < u8 > ) > > {
2021-07-16 01:42:29 -07:00
let mut statement = self
. connection
. prepare ( " SELECT account, value, nf FROM received_notes " ) ? ;
2022-05-19 09:19:04 -07:00
let res = statement . query_map ( [ ] , | row | {
2021-07-11 08:42:52 -07:00
let account : u32 = row . get ( 0 ) ? ;
let amount : i64 = row . get ( 1 ) ? ;
let nf : Vec < u8 > = row . get ( 2 ) ? ;
Ok ( ( account , amount as u64 , nf ) )
} ) ? ;
let mut v : Vec < ( u32 , u64 , Vec < u8 > ) > = vec! [ ] ;
for r in res {
v . push ( r ? ) ;
}
Ok ( v )
}
2021-06-26 02:52:03 -07:00
pub fn get_spendable_notes (
& self ,
2021-06-29 00:04:12 -07:00
account : u32 ,
2021-06-26 02:52:03 -07:00
anchor_height : u32 ,
fvk : & ExtendedFullViewingKey ,
) -> anyhow ::Result < Vec < SpendableNote > > {
2021-06-24 05:08:20 -07:00
let mut statement = self . connection . prepare (
2021-06-29 00:04:12 -07:00
" SELECT id_note, diversifier, value, rcm, witness FROM received_notes r, sapling_witnesses w WHERE spent IS NULL AND account = ?2
2021-07-16 01:42:29 -07:00
AND ( r . excluded IS NULL OR NOT r . excluded ) AND w . height = (
2021-06-24 05:08:20 -07:00
SELECT MAX ( height ) FROM sapling_witnesses WHERE height < = ? 1
) AND r . id_note = w . note " )?;
2021-06-29 00:04:12 -07:00
let notes = statement . query_map ( params! [ anchor_height , account ] , | row | {
2021-06-28 21:49:00 -07:00
let id_note : u32 = row . get ( 0 ) ? ;
let diversifier : Vec < u8 > = row . get ( 1 ) ? ;
let value : i64 = row . get ( 2 ) ? ;
let rcm : Vec < u8 > = row . get ( 3 ) ? ;
let witness : Vec < u8 > = row . get ( 4 ) ? ;
2021-06-24 05:08:20 -07:00
let mut diversifer_bytes = [ 0 u8 ; 11 ] ;
diversifer_bytes . copy_from_slice ( & diversifier ) ;
let diversifier = Diversifier ( diversifer_bytes ) ;
let mut rcm_bytes = [ 0 u8 ; 32 ] ;
rcm_bytes . copy_from_slice ( & rcm ) ;
let rcm = jubjub ::Fr ::from_bytes ( & rcm_bytes ) . unwrap ( ) ;
let rseed = Rseed ::BeforeZip212 ( rcm ) ;
let witness = IncrementalWitness ::< Node > ::read ( & * witness ) . unwrap ( ) ;
let pa = fvk . fvk . vk . to_payment_address ( diversifier ) . unwrap ( ) ;
let note = pa . create_note ( value as u64 , rseed ) . unwrap ( ) ;
Ok ( SpendableNote {
2021-06-28 21:49:00 -07:00
id : id_note ,
2021-06-24 05:08:20 -07:00
note ,
diversifier ,
2021-06-26 02:52:03 -07:00
witness ,
2021-06-24 05:08:20 -07:00
} )
} ) ? ;
let mut spendable_notes : Vec < SpendableNote > = vec! [ ] ;
for n in notes {
spendable_notes . push ( n ? ) ;
}
Ok ( spendable_notes )
}
2022-06-08 05:48:16 -07:00
pub fn tx_mark_spend ( & mut self , selected_notes : & [ u32 ] ) -> anyhow ::Result < ( ) > {
let db_tx = self . begin_transaction ( ) ? ;
for id_note in selected_notes . iter ( ) {
DbAdapter ::mark_spent ( * id_note , 0 , & db_tx ) ? ;
}
db_tx . commit ( ) ? ;
Ok ( ( ) )
}
2021-09-02 19:56:10 -07:00
pub fn mark_spent ( id : u32 , height : u32 , tx : & Transaction ) -> anyhow ::Result < ( ) > {
2021-06-26 02:52:03 -07:00
log ::debug! ( " +mark_spent " ) ;
2021-09-02 19:56:10 -07:00
tx . execute (
2021-06-26 02:52:03 -07:00
" UPDATE received_notes SET spent = ?1 WHERE id_note = ?2 " ,
params! [ height , id ] ,
) ? ;
log ::debug! ( " -mark_spent " ) ;
2021-06-24 05:08:20 -07:00
Ok ( ( ) )
}
2021-07-16 01:42:29 -07:00
pub fn purge_old_witnesses ( & self , height : u32 ) -> anyhow ::Result < ( ) > {
log ::debug! ( " +purge_old_witnesses " ) ;
2021-10-20 18:42:10 -07:00
let min_height : Option < u32 > = self . connection . query_row (
" SELECT MAX(height) FROM sapling_witnesses WHERE height <= ?1 " ,
2021-11-11 17:39:50 -08:00
params! [ height ] ,
| row | row . get ( 0 ) ,
) ? ;
2021-10-20 18:42:10 -07:00
// Leave at least one sapling witness
if let Some ( min_height ) = min_height {
log ::debug! ( " Purging witnesses older than {} " , min_height ) ;
self . connection . execute (
" DELETE FROM sapling_witnesses WHERE height < ?1 " ,
params! [ min_height ] ,
) ? ;
self . connection
. execute ( " DELETE FROM blocks WHERE height < ?1 " , params! [ min_height ] ) ? ;
}
2021-07-16 01:42:29 -07:00
log ::debug! ( " -purge_old_witnesses " ) ;
Ok ( ( ) )
}
2021-09-08 07:10:22 -07:00
pub fn store_contact ( & self , contact : & Contact , dirty : bool ) -> anyhow ::Result < ( ) > {
if contact . id = = 0 {
2021-07-30 01:11:44 -07:00
self . connection . execute (
2021-09-08 07:10:22 -07:00
" INSERT INTO contacts(name, address, dirty)
VALUES ( ? 1 , ? 2 , ? 3 ) " ,
params! [ & contact . name , & contact . address , dirty ] ,
2021-07-30 01:11:44 -07:00
) ? ;
2021-11-11 17:39:50 -08:00
} else {
2021-07-30 01:11:44 -07:00
self . connection . execute (
2021-09-08 07:10:22 -07:00
" INSERT INTO contacts(id, name, address, dirty)
VALUES ( ? 1 , ? 2 , ? 3 , ? 4 ) ON CONFLICT ( id ) DO UPDATE SET
name = excluded . name , address = excluded . address , dirty = excluded . dirty " ,
params! [ contact . id , & contact . name , & contact . address , dirty ] ,
2021-07-30 01:11:44 -07:00
) ? ;
2021-07-19 01:17:05 -07:00
}
2021-07-18 08:57:43 -07:00
Ok ( ( ) )
}
2021-09-08 07:10:22 -07:00
pub fn get_unsaved_contacts ( & self ) -> anyhow ::Result < Vec < Contact > > {
2021-11-11 17:39:50 -08:00
let mut statement = self
. connection
. prepare ( " SELECT id, name, address FROM contacts WHERE dirty = TRUE " ) ? ;
2022-05-19 09:19:04 -07:00
let rows = statement . query_map ( [ ] , | row | {
2021-09-08 07:10:22 -07:00
let id : u32 = row . get ( 0 ) ? ;
let name : String = row . get ( 1 ) ? ;
let address : String = row . get ( 2 ) ? ;
2021-11-11 17:39:50 -08:00
let contact = Contact { id , name , address } ;
2021-09-08 07:10:22 -07:00
Ok ( contact )
} ) ? ;
let mut contacts : Vec < Contact > = vec! [ ] ;
for r in rows {
contacts . push ( r ? ) ;
}
Ok ( contacts )
}
2021-07-16 01:42:29 -07:00
pub fn get_backup (
& self ,
account : u32 ,
) -> anyhow ::Result < ( Option < String > , Option < String > , String ) > {
2021-06-29 00:04:12 -07:00
log ::debug! ( " +get_backup " ) ;
let ( seed , sk , ivk ) = self . connection . query_row (
" SELECT seed, sk, ivk FROM accounts WHERE id_account = ?1 " ,
2021-06-28 21:49:00 -07:00
params! [ account ] ,
| row | {
2021-06-29 00:04:12 -07:00
let seed : Option < String > = row . get ( 0 ) ? ;
2022-06-10 02:16:00 -07:00
let sk : Option < String > = row . get ( 1 ) ? ;
let ivk : String = row . get ( 2 ) ? ;
2021-06-29 00:04:12 -07:00
Ok ( ( seed , sk , ivk ) )
2021-06-28 21:49:00 -07:00
} ,
) ? ;
2021-06-29 00:04:12 -07:00
log ::debug! ( " -get_backup " ) ;
Ok ( ( seed , sk , ivk ) )
2021-06-28 21:49:00 -07:00
}
2022-03-11 02:11:44 -08:00
pub fn get_seed ( & self , account : u32 ) -> anyhow ::Result < ( Option < String > , u32 ) > {
2021-07-09 06:33:05 -07:00
log ::info! ( " +get_seed " ) ;
2022-03-11 02:11:44 -08:00
let ( seed , index ) = self . connection . query_row (
" SELECT seed, aindex FROM accounts WHERE id_account = ?1 " ,
2021-07-30 01:11:44 -07:00
params! [ account ] ,
| row | {
let sk : Option < String > = row . get ( 0 ) ? ;
2022-03-11 02:11:44 -08:00
let index : u32 = row . get ( 1 ) ? ;
Ok ( ( sk , index ) )
2021-07-30 01:11:44 -07:00
} ,
) ? ;
2021-07-09 06:33:05 -07:00
log ::info! ( " -get_seed " ) ;
2022-03-11 02:11:44 -08:00
Ok ( ( seed , index ) )
2021-07-09 06:33:05 -07:00
}
2021-06-24 05:08:20 -07:00
pub fn get_sk ( & self , account : u32 ) -> anyhow ::Result < String > {
2021-06-29 00:04:12 -07:00
log ::info! ( " +get_sk " ) ;
let sk = self . connection . query_row (
2021-06-26 02:52:03 -07:00
" SELECT sk FROM accounts WHERE id_account = ?1 " ,
params! [ account ] ,
| row | {
2021-06-29 00:04:12 -07:00
let sk : String = row . get ( 0 ) ? ;
Ok ( sk )
2021-06-26 02:52:03 -07:00
} ,
) ? ;
2021-06-29 00:04:12 -07:00
log ::info! ( " -get_sk " ) ;
Ok ( sk )
2021-06-24 05:08:20 -07:00
}
pub fn get_ivk ( & self , account : u32 ) -> anyhow ::Result < String > {
2021-06-26 02:52:03 -07:00
log ::debug! ( " +get_ivk " ) ;
let ivk = self . connection . query_row (
" SELECT ivk FROM accounts WHERE id_account = ?1 " ,
params! [ account ] ,
| row | {
let ivk : String = row . get ( 0 ) ? ;
Ok ( ivk )
} ,
) ? ;
log ::debug! ( " -get_ivk " ) ;
2021-06-24 05:08:20 -07:00
Ok ( ivk )
}
2021-07-07 21:22:34 -07:00
2021-07-09 06:33:05 -07:00
pub fn get_address ( & self , account : u32 ) -> anyhow ::Result < String > {
log ::debug! ( " +get_address " ) ;
let address = self . connection . query_row (
" SELECT address FROM accounts WHERE id_account = ?1 " ,
params! [ account ] ,
| row | {
let address : String = row . get ( 0 ) ? ;
Ok ( address )
} ,
) ? ;
log ::debug! ( " -get_address " ) ;
Ok ( address )
}
2021-07-07 21:22:34 -07:00
pub fn get_diversifier ( & self , account : u32 ) -> anyhow ::Result < DiversifierIndex > {
2021-07-16 01:42:29 -07:00
let diversifier_index = self
. connection
. query_row (
" SELECT diversifier_index FROM diversifiers WHERE account = ?1 " ,
params! [ account ] ,
| row | {
let d : Vec < u8 > = row . get ( 0 ) ? ;
let mut div = [ 0 u8 ; 11 ] ;
div . copy_from_slice ( & d ) ;
Ok ( div )
} ,
)
. optional ( ) ?
2022-06-08 05:48:16 -07:00
. unwrap_or ( [ 0 u8 ; 11 ] ) ;
2021-07-07 21:22:34 -07:00
Ok ( DiversifierIndex ( diversifier_index ) )
}
2021-07-16 01:42:29 -07:00
pub fn store_diversifier (
& self ,
account : u32 ,
diversifier_index : & DiversifierIndex ,
) -> anyhow ::Result < ( ) > {
2021-07-07 21:22:34 -07:00
let diversifier_bytes = diversifier_index . 0. to_vec ( ) ;
self . connection . execute (
" INSERT INTO diversifiers(account, diversifier_index) VALUES (?1, ?2) ON CONFLICT \
( account ) DO UPDATE SET diversifier_index = excluded . diversifier_index " ,
2021-07-16 01:42:29 -07:00
params! [ account , diversifier_bytes ] ,
) ? ;
2021-07-07 21:22:34 -07:00
Ok ( ( ) )
}
2021-07-09 06:33:05 -07:00
pub fn get_taddr ( & self , account : u32 ) -> anyhow ::Result < Option < String > > {
2021-07-16 01:42:29 -07:00
let address = self
. connection
. query_row (
" SELECT address FROM taddrs WHERE account = ?1 " ,
params! [ account ] ,
| row | {
let address : String = row . get ( 0 ) ? ;
Ok ( address )
} ,
)
. optional ( ) ? ;
2021-07-09 06:33:05 -07:00
Ok ( address )
}
2021-11-11 17:39:50 -08:00
pub fn get_tsk ( & self , account : u32 ) -> anyhow ::Result < Option < String > > {
let sk = self
. connection
. query_row (
" SELECT sk FROM taddrs WHERE account = ?1 " ,
params! [ account ] ,
| row | {
let address : String = row . get ( 0 ) ? ;
Ok ( address )
} ,
)
. optional ( ) ? ;
2021-07-09 06:33:05 -07:00
Ok ( sk )
}
pub fn create_taddr ( & self , account : u32 ) -> anyhow ::Result < ( ) > {
2022-03-11 02:11:44 -08:00
let ( seed , index ) = self . get_seed ( account ) ? ;
2021-07-09 06:33:05 -07:00
if let Some ( seed ) = seed {
2022-03-11 02:11:44 -08:00
let bip44_path = format! ( " m/44'/ {} '/0'/0/ {} " , self . network ( ) . coin_type ( ) , index ) ;
2022-03-07 06:47:06 -08:00
let ( sk , address ) = derive_tkeys ( self . network ( ) , & seed , & bip44_path ) ? ;
2021-07-16 01:42:29 -07:00
self . connection . execute (
" INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3) \
ON CONFLICT DO NOTHING " ,
params! [ account , & sk , & address ] ,
) ? ;
2021-07-09 06:33:05 -07:00
}
Ok ( ( ) )
}
2021-08-09 07:13:10 -07:00
2021-08-16 06:07:04 -07:00
pub fn store_historical_prices (
& mut self ,
prices : & [ Quote ] ,
currency : & str ,
) -> anyhow ::Result < ( ) > {
2021-08-09 07:13:10 -07:00
let db_transaction = self . connection . transaction ( ) ? ;
{
2021-08-16 06:07:04 -07:00
let mut statement = db_transaction . prepare (
" INSERT INTO historical_prices(timestamp, price, currency) VALUES (?1, ?2, ?3) " ,
) ? ;
for q in prices {
statement . execute ( params! [ q . timestamp , q . price , currency ] ) ? ;
2021-08-09 07:13:10 -07:00
}
}
db_transaction . commit ( ) ? ;
Ok ( ( ) )
}
2021-08-16 06:07:04 -07:00
pub fn get_latest_quote ( & self , currency : & str ) -> anyhow ::Result < Option < Quote > > {
let quote = self . connection . query_row (
" SELECT timestamp, price FROM historical_prices WHERE currency = ?1 ORDER BY timestamp DESC " ,
params! [ currency ] ,
| row | {
let timestamp : i64 = row . get ( 0 ) ? ;
let price : f64 = row . get ( 1 ) ? ;
Ok ( Quote { timestamp , price } )
} ) . optional ( ) ? ;
Ok ( quote )
}
2021-09-08 07:10:22 -07:00
2021-11-11 17:39:50 -08:00
pub fn store_share_secret (
& self ,
account : u32 ,
secret : & str ,
index : usize ,
threshold : usize ,
participants : usize ,
) -> anyhow ::Result < ( ) > {
self . connection . execute (
" INSERT INTO secret_shares(account, secret, idx, threshold, participants) VALUES (?1, ?2, ?3, ?4, ?5) \
ON CONFLICT ( account ) DO UPDATE SET secret = excluded . secret , threshold = excluded . threshold , participants = excluded . participants " ,
params! [ account , & secret , index as u32 , threshold as u32 , participants as u32 ] ,
) ? ;
Ok ( ( ) )
}
pub fn get_share_secret ( & self , account : u32 ) -> anyhow ::Result < String > {
let secret = self
. connection
. query_row (
" SELECT secret FROM secret_shares WHERE account = ?1 " ,
params! [ account ] ,
| row | {
let secret : String = row . get ( 0 ) ? ;
Ok ( secret )
} ,
)
. optional ( ) ? ;
Ok ( secret . unwrap_or ( " " . to_string ( ) ) )
}
2021-09-08 07:10:22 -07:00
pub fn truncate_data ( & self ) -> anyhow ::Result < ( ) > {
2022-05-19 09:19:04 -07:00
self . connection . execute ( " DELETE FROM blocks " , [ ] ) ? ;
self . connection . execute ( " DELETE FROM contacts " , [ ] ) ? ;
2022-06-07 09:58:24 -07:00
self . connection . execute ( " DELETE FROM diversifiers " , [ ] ) ? ;
2021-11-11 17:39:50 -08:00
self . connection
2022-05-19 09:19:04 -07:00
. execute ( " DELETE FROM historical_prices " , [ ] ) ? ;
2022-06-07 09:58:24 -07:00
self . connection . execute ( " DELETE FROM received_notes " , [ ] ) ? ;
2021-11-11 17:39:50 -08:00
self . connection
2022-05-19 09:19:04 -07:00
. execute ( " DELETE FROM sapling_witnesses " , [ ] ) ? ;
2022-06-07 09:58:24 -07:00
self . connection . execute ( " DELETE FROM transactions " , [ ] ) ? ;
self . connection . execute ( " DELETE FROM messages " , [ ] ) ? ;
2021-09-08 07:10:22 -07:00
Ok ( ( ) )
}
2021-09-10 02:54:55 -07:00
pub fn delete_account ( & self , account : u32 ) -> anyhow ::Result < ( ) > {
2021-11-11 17:39:50 -08:00
self . connection . execute (
" DELETE FROM received_notes WHERE account = ?1 " ,
params! [ account ] ,
) ? ;
2021-12-15 03:09:53 -08:00
self . connection . execute (
" DELETE FROM transactions WHERE account = ?1 " ,
params! [ account ] ,
) ? ;
self . connection . execute (
" DELETE FROM diversifiers WHERE account = ?1 " ,
params! [ account ] ,
) ? ;
2021-11-11 17:39:50 -08:00
self . connection . execute (
" DELETE FROM accounts WHERE id_account = ?1 " ,
params! [ account ] ,
) ? ;
self . connection
. execute ( " DELETE FROM taddrs WHERE account = ?1 " , params! [ account ] ) ? ;
2022-04-17 01:09:25 -07:00
self . connection
. execute ( " DELETE FROM messages WHERE account = ?1 " , params! [ account ] ) ? ;
2021-11-11 17:39:50 -08:00
self . connection . execute (
" DELETE FROM secret_shares WHERE account = ?1 " ,
params! [ account ] ,
) ? ;
2021-09-10 02:54:55 -07:00
Ok ( ( ) )
}
2022-02-28 07:35:29 -08:00
2022-03-07 06:47:06 -08:00
pub fn get_full_backup ( & self ) -> anyhow ::Result < Vec < AccountBackup > > {
2022-06-07 09:58:24 -07:00
let _ = self . connection . execute (
" ALTER TABLE accounts ADD COLUMN aindex INT NOT NULL DEFAULT 0 " ,
[ ] ,
) ; // ignore error
2022-04-11 07:50:11 -07:00
2022-02-28 07:35:29 -08:00
let mut statement = self . connection . prepare (
2022-03-07 06:47:06 -08:00
" SELECT name, seed, aindex, a.sk AS z_sk, ivk, a.address AS z_addr, t.sk as t_sk, t.address AS t_addr FROM accounts a LEFT JOIN taddrs t ON a.id_account = t.account " ) ? ;
2022-05-19 09:19:04 -07:00
let rows = statement . query_map ( [ ] , | r | {
2022-02-28 07:35:29 -08:00
let name : String = r . get ( 0 ) ? ;
let seed : Option < String > = r . get ( 1 ) ? ;
2022-03-07 06:47:06 -08:00
let index : u32 = r . get ( 2 ) ? ;
let z_sk : Option < String > = r . get ( 3 ) ? ;
let ivk : String = r . get ( 4 ) ? ;
let z_addr : String = r . get ( 5 ) ? ;
let t_sk : Option < String > = r . get ( 6 ) ? ;
let t_addr : Option < String > = r . get ( 7 ) ? ;
2022-04-11 07:30:41 -07:00
let coin = get_coin_id_by_address ( & z_addr ) ;
2022-02-28 07:35:29 -08:00
Ok ( AccountBackup {
2022-03-07 06:47:06 -08:00
coin ,
2022-02-28 07:35:29 -08:00
name ,
seed ,
2022-03-07 06:47:06 -08:00
index ,
2022-02-28 07:35:29 -08:00
z_sk ,
ivk ,
z_addr ,
t_sk ,
t_addr ,
} )
} ) ? ;
let mut accounts : Vec < AccountBackup > = vec! [ ] ;
for r in rows {
accounts . push ( r ? ) ;
}
2022-03-07 06:47:06 -08:00
Ok ( accounts )
2022-02-28 07:35:29 -08:00
}
2022-03-07 06:47:06 -08:00
pub fn restore_full_backup ( & self , accounts : & [ AccountBackup ] ) -> anyhow ::Result < ( ) > {
let coin = get_coin_id ( self . coin_type ) ;
2022-02-28 07:35:29 -08:00
for a in accounts {
2022-03-07 06:47:06 -08:00
log ::info! ( " {} {} {} " , a . name , a . coin , coin ) ;
if a . coin = = coin {
let do_insert = | | {
self . connection . execute ( " INSERT INTO accounts(name, seed, aindex, sk, ivk, address) VALUES (?1,?2,?3,?4,?5,?6) " ,
params! [ a . name , a . seed , a . index , a . z_sk , a . ivk , a . z_addr ] ) ? ;
let id_account = self . connection . last_insert_rowid ( ) as u32 ;
if let Some ( t_addr ) = & a . t_addr {
2022-06-07 09:58:24 -07:00
self . connection . execute (
" INSERT INTO taddrs(account, sk, address) VALUES (?1,?2,?3) " ,
params! [ id_account , a . t_sk , t_addr ] ,
) ? ;
2022-03-07 06:47:06 -08:00
}
Ok ::< _ , anyhow ::Error > ( ( ) )
} ;
if let Err ( e ) = do_insert ( ) {
log ::info! ( " {:?} " , e ) ;
2022-02-28 07:35:29 -08:00
}
2022-03-07 06:47:06 -08:00
}
2022-02-28 07:35:29 -08:00
}
Ok ( ( ) )
}
2022-03-07 06:47:06 -08:00
2022-04-15 23:23:50 -07:00
pub fn store_message ( & self , account : u32 , message : & ZMessage ) -> anyhow ::Result < ( ) > {
self . connection . execute ( " INSERT INTO messages(account, sender, recipient, subject, body, timestamp, height, read) VALUES (?1,?2,?3,?4,?5,?6,?7,?8) " ,
params! [ account , message . sender , message . recipient , message . subject , message . body , message . timestamp , message . height , false ] ) ? ;
Ok ( ( ) )
}
pub fn mark_message_read ( & self , message_id : u32 , read : bool ) -> anyhow ::Result < ( ) > {
2022-06-07 09:58:24 -07:00
self . connection . execute (
" UPDATE messages SET read = ?1 WHERE id = ?2 " ,
params! [ read , message_id ] ,
) ? ;
2022-04-15 23:23:50 -07:00
Ok ( ( ) )
}
2022-04-16 20:15:59 -07:00
pub fn mark_all_messages_read ( & self , account : u32 , read : bool ) -> anyhow ::Result < ( ) > {
2022-06-07 09:58:24 -07:00
self . connection . execute (
" UPDATE messages SET read = ?1 WHERE account = ?2 " ,
params! [ read , account ] ,
) ? ;
Ok ( ( ) )
}
pub fn store_t_scan ( & self , addresses : & [ TBalance ] ) -> anyhow ::Result < ( ) > {
self . connection . execute (
" CREATE TABLE IF NOT EXISTS taddr_scan( \
id INTEGER NOT NULL PRIMARY KEY ,
address TEXT NOT NULL ,
value INTEGER NOT NULL ,
aindex INTEGER NOT NULL ) " ,
[ ] ,
) ? ;
for addr in addresses . iter ( ) {
self . connection . execute (
" INSERT INTO taddr_scan(address, value, aindex) VALUES (?1, ?2, ?3) " ,
params! [ addr . address , addr . balance , addr . index ] ,
) ? ;
}
2022-04-15 23:23:50 -07:00
Ok ( ( ) )
}
2022-06-10 03:41:03 -07:00
pub fn get_accounts ( & self ) -> anyhow ::Result < Vec < AccountRec > > {
2022-06-10 11:41:05 -07:00
let mut s = self
. connection
. prepare ( " SELECT id_account, name, address FROM accounts " ) ? ;
2022-06-10 03:41:03 -07:00
let accounts = s . query_map ( [ ] , | row | {
let id_account : u32 = row . get ( 0 ) ? ;
let name : String = row . get ( 1 ) ? ;
let address : String = row . get ( 2 ) ? ;
Ok ( AccountRec {
2022-06-10 11:41:05 -07:00
id_account ,
name ,
address ,
2022-06-10 03:41:03 -07:00
} )
} ) ? ;
let mut account_recs = vec! [ ] ;
for row in accounts {
account_recs . push ( row ? ) ;
}
Ok ( account_recs )
}
2022-06-10 02:16:00 -07:00
pub fn get_txs ( & self , account : u32 ) -> anyhow ::Result < Vec < TxRec > > {
let mut s = self . connection . prepare ( " SELECT txid, height, timestamp, value, address, memo FROM transactions WHERE account = ?1 " ) ? ;
let tx_rec = s . query_map ( params! [ account ] , | row | {
let mut txid : Vec < u8 > = row . get ( 0 ) ? ;
txid . reverse ( ) ;
let txid = hex ::encode ( txid ) ;
let height : u32 = row . get ( 1 ) ? ;
let timestamp : u32 = row . get ( 2 ) ? ;
let value : i64 = row . get ( 3 ) ? ;
let address : String = row . get ( 4 ) ? ;
let memo : String = row . get ( 5 ) ? ;
Ok ( TxRec {
2022-06-10 03:09:37 -07:00
txid ,
height ,
timestamp ,
value ,
address ,
memo ,
2022-06-10 02:16:00 -07:00
} )
} ) ? ;
let mut txs = vec! [ ] ;
for row in tx_rec {
txs . push ( row ? ) ;
}
Ok ( txs )
}
2022-03-07 06:47:06 -08:00
fn network ( & self ) -> & 'static Network {
let chain = get_coin_chain ( self . coin_type ) ;
chain . network ( )
}
2021-06-21 17:33:13 -07:00
}
2022-04-11 07:30:41 -07:00
fn get_coin_id_by_address ( address : & str ) -> u8 {
2022-06-07 09:58:24 -07:00
if address . starts_with ( " ys " ) {
1
} else {
0
}
2022-04-11 07:30:41 -07:00
}
2022-04-15 23:23:50 -07:00
pub struct ZMessage {
pub sender : Option < String > ,
pub recipient : String ,
pub subject : String ,
pub body : String ,
pub timestamp : u32 ,
pub height : u32 ,
}
2022-04-17 01:09:25 -07:00
impl ZMessage {
pub fn is_empty ( & self ) -> bool {
self . sender . is_none ( ) & & self . subject . is_empty ( ) & & self . body . is_empty ( )
}
}
2022-06-10 02:16:00 -07:00
#[ derive(Serialize) ]
pub struct TxRec {
txid : String ,
height : u32 ,
timestamp : u32 ,
value : i64 ,
address : String ,
memo : String ,
}
2022-06-10 03:41:03 -07:00
#[ derive(Serialize) ]
pub struct AccountRec {
id_account : u32 ,
name : String ,
address : String ,
}
2021-06-21 17:33:13 -07:00
#[ cfg(test) ]
mod tests {
2021-06-26 02:52:03 -07:00
use crate ::db ::{ DbAdapter , ReceivedNote , DEFAULT_DB_PATH } ;
use crate ::{ CTree , Witness } ;
2022-06-07 09:58:24 -07:00
use zcash_params ::coin ::CoinType ;
2021-06-21 17:33:13 -07:00
#[ test ]
fn test_db ( ) {
2022-04-19 09:47:08 -07:00
let mut db = DbAdapter ::new ( CoinType ::Zcash , DEFAULT_DB_PATH ) . unwrap ( ) ;
2021-06-21 17:33:13 -07:00
db . init_db ( ) . unwrap ( ) ;
db . trim_to_height ( 0 ) . unwrap ( ) ;
2021-06-26 02:52:03 -07:00
db . store_block ( 1 , & [ 0 u8 ; 32 ] , 0 , & CTree ::new ( ) ) . unwrap ( ) ;
2021-09-02 19:56:10 -07:00
let db_tx = db . begin_transaction ( ) . unwrap ( ) ;
let id_tx = DbAdapter ::store_transaction ( & [ 0 ; 32 ] , 1 , 1 , 0 , 20 , & db_tx ) . unwrap ( ) ;
DbAdapter ::store_received_note (
2021-06-26 02:52:03 -07:00
& ReceivedNote {
2021-06-29 00:04:12 -07:00
account : 1 ,
2021-06-26 02:52:03 -07:00
height : 1 ,
output_index : 0 ,
diversifier : vec ! [ ] ,
value : 0 ,
rcm : vec ! [ ] ,
nf : vec ! [ ] ,
spent : None ,
} ,
id_tx ,
5 ,
2021-11-11 17:39:50 -08:00
& db_tx ,
2021-06-26 02:52:03 -07:00
)
2021-07-16 01:42:29 -07:00
. unwrap ( ) ;
2021-06-21 17:33:13 -07:00
let witness = Witness {
position : 10 ,
id_note : 0 ,
note : None ,
tree : CTree ::new ( ) ,
filled : vec ! [ ] ,
cursor : CTree ::new ( ) ,
} ;
2021-09-02 19:56:10 -07:00
db_tx . commit ( ) . unwrap ( ) ;
2022-07-12 00:28:58 -07:00
Db ::store_witnesses ( & witness , 1000 , 1 ) . unwrap ( ) ;
2021-06-21 17:33:13 -07:00
}
#[ test ]
fn test_balance ( ) {
2022-04-19 09:47:08 -07:00
let db = DbAdapter ::new ( CoinType ::Zcash , DEFAULT_DB_PATH ) . unwrap ( ) ;
2021-06-29 00:04:12 -07:00
let balance = db . get_balance ( 1 ) . unwrap ( ) ;
2021-06-21 17:33:13 -07:00
println! ( " {} " , balance ) ;
}
}