walletdb.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. use crate::crypto::{
  2. coin::Coin, merkle::IncrementalWitness, merkle_node::MerkleNode, note::Note, OwnCoins,
  3. };
  4. use crate::serial;
  5. use crate::serial::{deserialize, serialize, Decodable, Encodable};
  6. use crate::{Error, Result};
  7. use crate::client::ClientFailed;
  8. use async_std::sync::{Arc, Mutex};
  9. use ff::Field;
  10. use log::*;
  11. use rand::rngs::OsRng;
  12. use rusqlite::{named_params, params, Connection};
  13. use std::path::PathBuf;
  14. pub type WalletPtr = Arc<WalletDb>;
  15. pub struct WalletDb {
  16. pub path: PathBuf,
  17. pub secrets: Vec<jubjub::Fr>,
  18. pub cashier_secrets: Vec<jubjub::Fr>,
  19. pub coins: Mutex<Vec<Coin>>,
  20. pub notes: Mutex<Vec<Note>>,
  21. pub witnesses: Mutex<Vec<IncrementalWitness<MerkleNode>>>,
  22. pub cashier_public: jubjub::SubgroupPoint,
  23. pub public: jubjub::SubgroupPoint,
  24. pub password: String,
  25. }
  26. impl WalletDb {
  27. pub fn new(path: &std::path::PathBuf, password: String) -> Result<Self> {
  28. debug!(target: "walletdb", "new() Constructor called");
  29. let cashier_secret = jubjub::Fr::random(&mut OsRng);
  30. let secret = jubjub::Fr::random(&mut OsRng);
  31. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  32. let cashier_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret;
  33. let coins = Mutex::new(Vec::new());
  34. let notes = Mutex::new(Vec::new());
  35. let witnesses = Mutex::new(Vec::new());
  36. Ok(Self {
  37. path: path.to_owned(),
  38. cashier_secrets: vec![cashier_secret.clone()],
  39. secrets: vec![secret.clone()],
  40. cashier_public,
  41. public,
  42. coins,
  43. notes,
  44. witnesses,
  45. password,
  46. //conn,
  47. })
  48. }
  49. pub fn init_db(&self) -> Result<()> {
  50. if !self.password.trim().is_empty() {
  51. let contents = include_str!("../../res/schema.sql");
  52. let conn = Connection::open(&self.path)?;
  53. debug!(target: "walletdb", "OPENED CONNECTION AT PATH {:?}", self.path);
  54. conn.pragma_update(None, "key", &self.password)?;
  55. conn.execute_batch(&contents)?;
  56. } else {
  57. info!("Password is empty. You must set a password to use the wallet.");
  58. info!("Current password: {}", self.password);
  59. return Err(Error::from(ClientFailed::EmptyPassword));
  60. }
  61. Ok(())
  62. }
  63. pub fn init_cashier_db(&self) -> Result<()> {
  64. let conn = Connection::open(&self.path)?;
  65. debug!(target: "cashierdb", "OPENED CONNECTION AT PATH {:?}", self.path);
  66. let contents = include_str!("../../res/schema.sql");
  67. conn.execute_batch(&contents)?;
  68. Ok(())
  69. }
  70. pub fn get_own_coins(&self) -> Result<OwnCoins> {
  71. // open connection
  72. let conn = Connection::open(&self.path)?;
  73. // unlock database
  74. conn.pragma_update(None, "key", &self.password)?;
  75. let mut coins = conn.prepare("SELECT * FROM coins")?;
  76. let rows = coins.query_map([], |row| {
  77. let coin = self.get_value_deserialized(row.get(1)?).unwrap();
  78. // note
  79. let serial = self.get_value_deserialized(row.get(2)?).unwrap();
  80. let coin_blind = self.get_value_deserialized(row.get(3)?).unwrap();
  81. let valcom_blind = self.get_value_deserialized(row.get(4)?).unwrap();
  82. let value: u64 = row.get(5)?;
  83. let asset_id: u64 = row.get(6)?;
  84. let note = Note {
  85. serial,
  86. value,
  87. asset_id,
  88. coin_blind,
  89. valcom_blind,
  90. };
  91. let witness = self.get_value_deserialized(row.get(7)?).unwrap();
  92. let key_id: u64 = row.get(8)?;
  93. // return key_private from key_id
  94. let mut get_private_key =
  95. conn.prepare("SELECT key_private FROM keys WHERE key_id = :key_id")?;
  96. let rows = get_private_key.query_map(&[(":key_id", &key_id)], |row| row.get(0))?;
  97. let mut secret = Vec::new();
  98. for id in rows {
  99. secret.push(id?)
  100. }
  101. let secret: jubjub::Fr = self
  102. .get_value_deserialized(
  103. secret
  104. .pop()
  105. .expect("unable to load public_key from walletdb"),
  106. )
  107. .unwrap();
  108. Ok((coin, note, secret, witness))
  109. })?;
  110. let mut own_coins = Vec::new();
  111. for id in rows {
  112. own_coins.push(id?)
  113. }
  114. Ok(own_coins)
  115. }
  116. pub fn put_own_coins(
  117. &self,
  118. coin: Coin,
  119. note: Note,
  120. witness: IncrementalWitness<MerkleNode>,
  121. secret: jubjub::Fr,
  122. ) -> Result<()> {
  123. // prepare the values
  124. let coin = self.get_value_serialized(&coin.repr)?;
  125. let serial = self.get_value_serialized(&note.serial)?;
  126. let coin_blind = self.get_value_serialized(&note.coin_blind)?;
  127. let valcom_blind = self.get_value_serialized(&note.valcom_blind)?;
  128. let value: u64 = note.value;
  129. let asset_id: u64 = note.asset_id;
  130. let witness = self.get_value_serialized(&witness)?;
  131. let secret = self.get_value_serialized(&secret)?;
  132. // open connection
  133. let conn = Connection::open(&self.path)?;
  134. // unlock database
  135. conn.pragma_update(None, "key", &self.password)?;
  136. // return key_id from key_private
  137. let mut get_id =
  138. conn.prepare("SELECT key_id FROM keys WHERE key_private = :key_private")?;
  139. let rows = get_id.query_map::<u64, _, _>(&[(":key_private", &secret)], |row| row.get(0))?;
  140. let mut key_id = Vec::new();
  141. for id in rows {
  142. key_id.push(id?)
  143. }
  144. conn.execute(
  145. "INSERT INTO coins(coin, serial, value, asset_id, coin_blind, valcom_blind, witness, key_id)
  146. VALUES (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :key_id)",
  147. named_params! {
  148. ":coin": coin,
  149. ":serial": serial,
  150. ":value": value,
  151. ":asset_id": asset_id,
  152. ":coin_blind": coin_blind,
  153. ":valcom_blind": valcom_blind,
  154. ":witness": witness,
  155. ":key_id": key_id.pop().expect("key_id not found!"),
  156. },
  157. )?;
  158. Ok(())
  159. }
  160. pub fn key_gen(&self) -> (Vec<u8>, Vec<u8>) {
  161. debug!(target: "key_gen", "Attempting to generate keys...");
  162. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  163. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  164. let pubkey = serial::serialize(&public);
  165. let privkey = serial::serialize(&secret);
  166. (pubkey, privkey)
  167. }
  168. pub fn cash_key_gen(&self) -> (Vec<u8>, Vec<u8>) {
  169. debug!(target: "cash key_gen", "Generating cashier keys...");
  170. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  171. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  172. let pubkey = serial::serialize(&public);
  173. let privkey = serial::serialize(&secret);
  174. (pubkey, privkey)
  175. }
  176. pub fn put_keypair(&self, key_public: Vec<u8>, key_private: Vec<u8>) -> Result<()> {
  177. let conn = Connection::open(&self.path)?;
  178. conn.pragma_update(None, "key", &self.password)?;
  179. conn.execute(
  180. "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  181. params![key_public, key_private],
  182. )?;
  183. Ok(())
  184. }
  185. pub fn put_cashier_pub(&self, key_public: Vec<u8>) -> Result<()> {
  186. debug!(target: "save_cash_key", "Save cashier keys...");
  187. let conn = Connection::open(&self.path)?;
  188. conn.pragma_update(None, "key", &self.password)?;
  189. conn.execute(
  190. "INSERT INTO cashier(key_public) VALUES (?1)",
  191. params![key_public],
  192. )?;
  193. Ok(())
  194. }
  195. pub fn get_public(&self) -> Result<jubjub::SubgroupPoint> {
  196. debug!(target: "get", "Returning keys...");
  197. let conn = Connection::open(&self.path)?;
  198. conn.pragma_update(None, "key", &self.password)?;
  199. let mut stmt = conn.prepare("SELECT key_public FROM keys")?;
  200. // this just gets the first key. maybe we should randomize this
  201. let key_iter = stmt.query_map([], |row| row.get(0))?;
  202. let mut pub_keys = Vec::new();
  203. for key in key_iter {
  204. pub_keys.push(key?);
  205. }
  206. let public: jubjub::SubgroupPoint = self.get_value_deserialized(
  207. pub_keys
  208. .pop()
  209. .expect("unable to load public_key from walletdb"),
  210. )?;
  211. Ok(public)
  212. }
  213. pub fn get_cashier_public(&self) -> Result<jubjub::SubgroupPoint> {
  214. debug!(target: "get_cashier_public", "Returning keys...");
  215. let conn = Connection::open(&self.path)?;
  216. conn.pragma_update(None, "key", &self.password)?;
  217. let mut stmt = conn.prepare("SELECT key_public FROM cashier")?;
  218. let key_iter = stmt.query_map([], |row| row.get(0))?;
  219. let mut pub_keys = Vec::new();
  220. for key in key_iter {
  221. pub_keys.push(key?);
  222. }
  223. let public: jubjub::SubgroupPoint = self.get_value_deserialized(
  224. pub_keys
  225. .pop()
  226. .expect("unable to load cashier public_key from walletdb"),
  227. )?;
  228. Ok(public)
  229. }
  230. pub fn get_private(&self) -> Result<jubjub::Fr> {
  231. debug!(target: "get", "Returning keys...");
  232. let conn = Connection::open(&self.path)?;
  233. conn.pragma_update(None, "key", &self.password)?;
  234. let mut stmt = conn.prepare("SELECT key_private FROM keys")?;
  235. let key_iter = stmt.query_map([], |row| row.get(0))?;
  236. let mut keys = Vec::new();
  237. for key in key_iter {
  238. keys.push(key?);
  239. }
  240. let private: jubjub::Fr = self.get_value_deserialized(
  241. keys.pop()
  242. .expect("unable to load private key from walletdb"),
  243. )?;
  244. Ok(private)
  245. }
  246. pub fn test_wallet(&self) -> Result<()> {
  247. let conn = Connection::open(&self.path)?;
  248. conn.pragma_update(None, "key", &self.password)?;
  249. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  250. let _rows = stmt.query([])?;
  251. Ok(())
  252. }
  253. fn get_tables_name(&self) -> Result<Vec<String>> {
  254. let conn = Connection::open(&self.path)?;
  255. conn.pragma_update(None, "key", &self.password)?;
  256. let mut stmt = conn.prepare("SELECT name FROM sqlite_master WHERE type='table'")?;
  257. let table_iter = stmt.query_map::<String, _, _>([], |row| row.get(0))?;
  258. let mut tables = Vec::new();
  259. for table in table_iter {
  260. tables.push(table?);
  261. }
  262. Ok(tables)
  263. }
  264. pub fn destory(&self) -> Result<()> {
  265. let conn = Connection::open(&self.path)?;
  266. conn.pragma_update(None, "key", &self.password)?;
  267. for table in self.get_tables_name()?.iter() {
  268. let drop_stmt = format!("DROP TABLE IF EXISTS {}", table);
  269. let drop_stmt = drop_stmt.as_str();
  270. conn.execute(drop_stmt, [])?;
  271. }
  272. Ok(())
  273. }
  274. pub fn get_value_serialized<T: Encodable>(&self, data: &T) -> Result<Vec<u8>> {
  275. let v = serialize(data);
  276. Ok(v)
  277. }
  278. pub fn get_value_deserialized<D: Decodable>(&self, key: Vec<u8>) -> Result<D> {
  279. let v: D = deserialize(&key)?;
  280. Ok(v)
  281. }
  282. }
  283. #[cfg(test)]
  284. mod tests {
  285. use super::*;
  286. use crate::util::join_config_path;
  287. use ff::PrimeField;
  288. #[test]
  289. pub fn test_save_and_load_keypair() -> Result<()> {
  290. let walletdb_path = join_config_path(&PathBuf::from("test_wallet.db"))?;
  291. let wallet = WalletDb::new(&walletdb_path, "darkfi".into())?;
  292. wallet.init_db()?;
  293. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  294. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  295. let key_public = serial::serialize(&public);
  296. let key_private = serial::serialize(&secret);
  297. wallet.put_keypair(key_public, key_private)?;
  298. let public2 = wallet.get_public()?;
  299. let secret2 = wallet.get_private()?;
  300. assert_eq!(public, public2);
  301. assert_eq!(secret, secret2);
  302. wallet.destory()?;
  303. Ok(())
  304. }
  305. #[test]
  306. pub fn test_put_and_get_own_coins() -> Result<()> {
  307. let walletdb_path = join_config_path(&PathBuf::from("test_wallet.db"))?;
  308. let wallet = WalletDb::new(&walletdb_path, "darkfi".into())?;
  309. wallet.init_db()?;
  310. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  311. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  312. let key_public = serial::serialize(&public);
  313. let key_private = serial::serialize(&secret);
  314. wallet.put_keypair(key_public, key_private)?;
  315. let note = Note {
  316. serial: jubjub::Fr::random(&mut OsRng),
  317. value: 110,
  318. asset_id: 1,
  319. coin_blind: jubjub::Fr::random(&mut OsRng),
  320. valcom_blind: jubjub::Fr::random(&mut OsRng),
  321. };
  322. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  323. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  324. tree.append(MerkleNode::from_coin(&coin))?;
  325. let witness = IncrementalWitness::from_tree(&tree);
  326. wallet.put_own_coins(coin.clone(), note.clone(), witness.clone(), secret)?;
  327. let own_coin = wallet.get_own_coins()?[0].clone();
  328. assert_eq!(&own_coin.1.valcom_blind, &note.valcom_blind);
  329. assert_eq!(&own_coin.1.coin_blind, &note.coin_blind);
  330. assert_eq!(own_coin.2, secret);
  331. assert_eq!(own_coin.3.root(), witness.root());
  332. assert_eq!(own_coin.3.path(), witness.path());
  333. wallet.destory()?;
  334. Ok(())
  335. }
  336. //#[test]
  337. // let password = "roseiscool2021";
  338. // let path = join_config_path(&PathBuf::from("wallet.db"))?;
  339. // let contents = include_str!("../../res/schema.sql");
  340. // let conn = Connection::open(&path)?;
  341. // debug!(target: "walletdb", "OPENED CONNECTION AT PATH {:?}", path);
  342. // conn.pragma_update(None, "key", &password)?;
  343. // conn.execute_batch(&contents)?;
  344. // Ok(())
  345. //}
  346. //#[test]
  347. //pub fn test_keypair() -> Result<()> {
  348. // let path = join_config_path(&PathBuf::from("wallet.db"))?;
  349. // let conn = Connection::open(path)?;
  350. // let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  351. // let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  352. // let key_public = serial::serialize(&public);
  353. // let key_private = serial::serialize(&secret);
  354. // let mut stmt = conn.prepare("PRAGMA key = 'testkey'")?;
  355. // let _rows = stmt.query([])?;
  356. // conn.execute(
  357. // "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  358. // params![key_public, key_private],
  359. // )?;
  360. // Ok(())
  361. //}
  362. //#[test]
  363. //pub fn test_get_id() -> Result<()> {
  364. // let path = join_config_path(&PathBuf::from("wallet.db"))?;
  365. // let conn = Connection::open(path)?;
  366. // let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  367. // let key_private = serial::serialize(&secret);
  368. // let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  369. // let key_public = serial::serialize(&public);
  370. // let mut stmt = conn.prepare("PRAGMA key = 'testkey'")?;
  371. // let _rows = stmt.query([])?;
  372. // conn.execute(
  373. // "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  374. // params![key_public, key_private],
  375. // )?;
  376. // let mut get_id =
  377. // conn.prepare("SELECT key_id FROM keys WHERE key_private = :key_private")?;
  378. // let rows =
  379. // get_id.query_map::<u8, _, _>(&[(":key_private", &key_private)], |row| row.get(0))?;
  380. // let mut key_id = Vec::new();
  381. // for id in rows {
  382. // key_id.push(id?)
  383. // }
  384. // println!("FOUND ID: {:?}", key_id.pop().unwrap());
  385. // Ok(())
  386. //}
  387. //#[test]
  388. //pub fn test_own_coins() -> Result<()> {
  389. // let key_private = Vec::new();
  390. // let coin = Vec::new();
  391. // let serial = Vec::new();
  392. // let coin_blind = Vec::new();
  393. // let valcom_blind = Vec::new();
  394. // let value = Vec::new();
  395. // let asset_id = Vec::new();
  396. // let witness = Vec::new();
  397. // let path = join_config_path(&PathBuf::from("wallet.db"))?;
  398. // let conn = Connection::open(path)?;
  399. // let contents = include_str!("../../res/schema.sql");
  400. // match conn.execute_batch(&contents) {
  401. // Ok(v) => println!("Database initalized successfully {:?}", v),
  402. // Err(err) => println!("Error: {}", err),
  403. // };
  404. // //let mut unlock = conn.prepare("PRAGMA key = 'testkey'")?;
  405. // //let _rows = unlock.query([])?;
  406. // let mut get_id =
  407. // conn.prepare("SELECT key_id FROM keys WHERE key_private = :key_private")?;
  408. // let rows =
  409. // get_id.query_map::<u8, _, _>(&[(":key_private", &key_private)], |row| row.get(0))?;
  410. // let mut key_id = Vec::new();
  411. // for id in rows {
  412. // key_id.push(id?)
  413. // }
  414. // conn.execute(
  415. // "INSERT INTO coins(coin, serial, value, asset_id, coin_blind, valcom_blind, witness, key_id)
  416. // VALUES (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :key_id)",
  417. // named_params! {
  418. // ":coin": coin,
  419. // ":serial": serial,
  420. // ":value": value,
  421. // ":asset_id": asset_id,
  422. // ":coin_blind": coin_blind,
  423. // ":valcom_blind": valcom_blind,
  424. // ":witness": witness,
  425. // ":key_id": key_id.pop().expect("key_id not found!"),
  426. // },
  427. // )?;
  428. // Ok(())
  429. //}
  430. }