walletdb.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. use super::WalletApi;
  2. use crate::client::ClientFailed;
  3. use crate::crypto::{
  4. merkle::IncrementalWitness, merkle_node::MerkleNode, note::Note, OwnCoin, OwnCoins,
  5. };
  6. use crate::serial;
  7. use crate::{Error, Result};
  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::{Path, PathBuf};
  14. pub type WalletPtr = Arc<WalletDb>;
  15. #[derive(Debug, Clone)]
  16. pub struct Keypair {
  17. pub public: jubjub::SubgroupPoint,
  18. pub private: jubjub::Fr,
  19. }
  20. #[derive(Debug, Clone)]
  21. pub struct TokenTable {
  22. pub coin_id: u64,
  23. pub token_id: jubjub::Fr,
  24. pub value: u64,
  25. }
  26. //#[derive(Clone)]
  27. pub struct WalletDb {
  28. pub path: PathBuf,
  29. pub password: String,
  30. pub initialized: Mutex<bool>,
  31. }
  32. impl WalletApi for WalletDb {
  33. fn get_password(&self) -> String {
  34. self.password.to_owned()
  35. }
  36. fn get_path(&self) -> PathBuf {
  37. self.path.to_owned()
  38. }
  39. }
  40. impl WalletDb {
  41. pub fn new(path: &Path, password: String) -> Result<WalletPtr> {
  42. debug!(target: "WALLETDB", "new() Constructor called");
  43. Ok(Arc::new(Self {
  44. path: path.to_owned(),
  45. password,
  46. initialized: Mutex::new(false),
  47. }))
  48. }
  49. pub async fn init_db(&self) -> Result<()> {
  50. if !*self.initialized.lock().await {
  51. if !self.password.trim().is_empty() {
  52. let contents = include_str!("../../sql/schema.sql");
  53. let conn = Connection::open(&self.path)?;
  54. debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", self.path);
  55. conn.pragma_update(None, "key", &self.password)?;
  56. conn.execute_batch(&contents)?;
  57. *self.initialized.lock().await = true;
  58. } else {
  59. debug!(
  60. target: "WALLETDB",
  61. "Password is empty. You must set a password to use the wallet."
  62. );
  63. return Err(Error::from(ClientFailed::EmptyPassword));
  64. }
  65. } else {
  66. debug!(target: "WALLETDB", "Wallet already initialized.");
  67. return Err(Error::from(ClientFailed::WalletInitialized));
  68. }
  69. Ok(())
  70. }
  71. pub fn key_gen(&self) -> Result<()> {
  72. debug!(target: "WALLETDB", "Attempting to generate keys...");
  73. let conn = Connection::open(&self.path)?;
  74. conn.pragma_update(None, "key", &self.password)?;
  75. let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > ?")?;
  76. let key_check = stmt.exists(params!["0"])?;
  77. if !key_check {
  78. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  79. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  80. let pubkey = serial::serialize(&public);
  81. let privkey = serial::serialize(&secret);
  82. self.put_keypair(pubkey, privkey)?;
  83. } else {
  84. debug!(target: "WALLETDB", "Keys already exist.");
  85. return Err(Error::from(ClientFailed::KeyExists));
  86. }
  87. Ok(())
  88. }
  89. pub fn put_keypair(&self, key_public: Vec<u8>, key_private: Vec<u8>) -> Result<()> {
  90. let conn = Connection::open(&self.path)?;
  91. conn.pragma_update(None, "key", &self.password)?;
  92. conn.execute(
  93. "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  94. params![key_public, key_private],
  95. )?;
  96. Ok(())
  97. }
  98. pub fn get_keypairs(&self) -> Result<Vec<Keypair>> {
  99. debug!(target: "WALLETDB", "Returning keypairs...");
  100. let conn = Connection::open(&self.path)?;
  101. conn.pragma_update(None, "key", &self.password)?;
  102. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  103. // this just gets the first key. maybe we should randomize this
  104. let key_iter = stmt.query_map([], |row| Ok((row.get(1)?, row.get(2)?)))?;
  105. let mut keypairs = Vec::new();
  106. for key in key_iter {
  107. let key = key?;
  108. let public = key.0;
  109. let private = key.1;
  110. let public: jubjub::SubgroupPoint = self.get_value_deserialized(&public)?;
  111. let private: jubjub::Fr = self.get_value_deserialized(&private)?;
  112. keypairs.push(Keypair { public, private });
  113. }
  114. Ok(keypairs)
  115. }
  116. pub fn get_own_coins(&self) -> Result<OwnCoins> {
  117. debug!(target: "WALLETDB", "Get own coins");
  118. let conn = Connection::open(&self.path)?;
  119. // unlock database
  120. conn.pragma_update(None, "key", &self.password)?;
  121. let mut coins = conn.prepare("SELECT * FROM coins")?;
  122. let rows = coins.query_map([], |row| {
  123. Ok((
  124. row.get(1)?,
  125. row.get(2)?,
  126. row.get(3)?,
  127. row.get(4)?,
  128. row.get(5)?,
  129. row.get(6)?,
  130. row.get(7)?,
  131. row.get(8)?,
  132. ))
  133. })?;
  134. let mut own_coins = Vec::new();
  135. for row in rows {
  136. let row = row?;
  137. let coin = self.get_value_deserialized(&row.0)?;
  138. // note
  139. let serial = self.get_value_deserialized(&row.1)?;
  140. let coin_blind = self.get_value_deserialized(&row.2)?;
  141. let valcom_blind = self.get_value_deserialized(&row.3)?;
  142. let value: u64 = row.4;
  143. let asset_id = self.get_value_deserialized(&row.5)?;
  144. let note = Note {
  145. serial,
  146. value,
  147. asset_id,
  148. coin_blind,
  149. valcom_blind,
  150. };
  151. let witness = self.get_value_deserialized(&row.6)?;
  152. let key_id: u64 = row.7;
  153. // return key_private from key_id
  154. let mut get_private_key =
  155. conn.prepare("SELECT key_private FROM keys WHERE key_id = :key_id")?;
  156. let rows = get_private_key.query_map(&[(":key_id", &key_id)], |row| row.get(0))?;
  157. let mut secret = Vec::new();
  158. for id in rows {
  159. secret.push(id?)
  160. }
  161. let secret: jubjub::Fr =
  162. self.get_value_deserialized(&secret.pop().expect("Load public_key from walletdb"))?;
  163. let oc = OwnCoin {
  164. coin,
  165. note,
  166. secret,
  167. witness,
  168. };
  169. own_coins.push(oc)
  170. }
  171. Ok(own_coins)
  172. }
  173. pub fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
  174. // prepare the values
  175. debug!(target: "WALLETDB", "Put own coins");
  176. let coin = self.get_value_serialized(&own_coin.coin.repr)?;
  177. let serial = self.get_value_serialized(&own_coin.note.serial)?;
  178. let coin_blind = self.get_value_serialized(&own_coin.note.coin_blind)?;
  179. let valcom_blind = self.get_value_serialized(&own_coin.note.valcom_blind)?;
  180. let value: u64 = own_coin.note.value;
  181. let asset_id = self.get_value_serialized(&own_coin.note.asset_id)?;
  182. let witness = self.get_value_serialized(&own_coin.witness)?;
  183. let secret = self.get_value_serialized(&own_coin.secret)?;
  184. // open connection
  185. let conn = Connection::open(&self.path)?;
  186. // unlock database
  187. conn.pragma_update(None, "key", &self.password)?;
  188. // return key_id from key_private
  189. let mut get_id =
  190. conn.prepare("SELECT key_id FROM keys WHERE key_private = :key_private")?;
  191. let rows = get_id.query_map::<u64, _, _>(&[(":key_private", &secret)], |row| row.get(0))?;
  192. let mut key_id = Vec::new();
  193. for id in rows {
  194. key_id.push(id?)
  195. }
  196. conn.execute(
  197. "INSERT INTO coins
  198. (coin, serial, value, asset_id, coin_blind, valcom_blind, witness, key_id)
  199. VALUES
  200. (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :key_id);",
  201. named_params! {
  202. ":coin": coin,
  203. ":serial": serial,
  204. ":value": value,
  205. ":asset_id": asset_id,
  206. ":coin_blind": coin_blind,
  207. ":valcom_blind": valcom_blind,
  208. ":witness": witness,
  209. ":key_id": key_id.pop().expect("Get key_id"),
  210. },
  211. )?;
  212. Ok(())
  213. }
  214. pub fn get_witnesses(&self) -> Result<Vec<(u64, IncrementalWitness<MerkleNode>)>> {
  215. let conn = Connection::open(&self.path)?;
  216. conn.pragma_update(None, "key", &self.password)?;
  217. let mut witnesses = conn.prepare("SELECT coin_id, witness FROM coins;")?;
  218. let rows = witnesses.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?;
  219. let mut witnesses = Vec::new();
  220. for i in rows {
  221. let i = i?;
  222. let coin_id: u64 = i.0;
  223. let witness: IncrementalWitness<MerkleNode> = self.get_value_deserialized(&i.1)?;
  224. witnesses.push((coin_id, witness))
  225. }
  226. Ok(witnesses)
  227. }
  228. pub fn update_witness(
  229. &self,
  230. coin_id: u64,
  231. witness: IncrementalWitness<MerkleNode>,
  232. ) -> Result<()> {
  233. debug!(target: "WALLETDB", "Updating witness");
  234. let conn = Connection::open(&self.path)?;
  235. conn.pragma_update(None, "key", &self.password)?;
  236. let witness = self.get_value_serialized(&witness)?;
  237. conn.execute(
  238. "UPDATE coins SET witness = ?1 WHERE coin_id = ?2;",
  239. params![witness, coin_id],
  240. )?;
  241. Ok(())
  242. }
  243. pub fn put_cashier_pub(&self, key_public: &jubjub::SubgroupPoint) -> Result<()> {
  244. debug!(target: "WALLETDB", "Save cashier keys...");
  245. let conn = Connection::open(&self.path)?;
  246. conn.pragma_update(None, "key", &self.password)?;
  247. let key_public = self.get_value_serialized(key_public)?;
  248. conn.execute(
  249. "INSERT INTO cashier(key_public) VALUES (?1)",
  250. params![key_public],
  251. )?;
  252. Ok(())
  253. }
  254. pub fn get_cashier_public_keys(&self) -> Result<Vec<jubjub::SubgroupPoint>> {
  255. debug!(target: "WALLETDB", "Returning Cashier Public key...");
  256. let conn = Connection::open(&self.path)?;
  257. conn.pragma_update(None, "key", &self.password)?;
  258. let mut stmt = conn.prepare("SELECT key_public FROM cashier")?;
  259. let key_iter = stmt.query_map([], |row| row.get(0))?;
  260. let mut pub_keys = Vec::new();
  261. for key in key_iter {
  262. let public: jubjub::SubgroupPoint = self.get_value_deserialized(&key?)?;
  263. pub_keys.push(public);
  264. }
  265. Ok(pub_keys)
  266. }
  267. pub fn get_token_table(&self) -> Result<Vec<TokenTable>> {
  268. debug!(target: "WALLETDB", "Get token and balances...");
  269. let conn = Connection::open(&self.path)?;
  270. conn.pragma_update(None, "key", &self.password)?;
  271. let mut stmt = conn.prepare("SELECT coin_id, value, asset_id FROM coins ;")?;
  272. let rows = stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)))?;
  273. let mut token_table = Vec::new();
  274. for row in rows {
  275. let row = row?;
  276. let coin_id: u64 = row.0;
  277. let value: u64 = row.1;
  278. let token_id: jubjub::Fr = self.get_value_deserialized(&row.2)?;
  279. token_table.push(TokenTable {
  280. coin_id,
  281. value,
  282. token_id,
  283. });
  284. }
  285. Ok(token_table)
  286. }
  287. pub fn get_token_id(&self) -> Result<Vec<jubjub::Fr>> {
  288. debug!(target: "WALLETDB", "Get token and balances...");
  289. let conn = Connection::open(&self.path)?;
  290. conn.pragma_update(None, "key", &self.password)?;
  291. let mut stmt = conn.prepare("SELECT asset_id FROM coins")?;
  292. let rows = stmt.query_map([], |row| row.get(0))?;
  293. let mut token_ids = Vec::new();
  294. for row in rows {
  295. let row = row?;
  296. let token_id = self.get_value_deserialized(&row).unwrap();
  297. token_ids.push(token_id);
  298. }
  299. Ok(token_ids)
  300. }
  301. pub fn token_id_exists(&self, token_id: &jubjub::Fr) -> Result<bool> {
  302. debug!(target: "WALLETDB", "Check tokenID exists");
  303. let conn = Connection::open(&self.path)?;
  304. conn.pragma_update(None, "key", &self.password)?;
  305. let id = self.get_value_serialized(token_id)?;
  306. let mut stmt = conn.prepare("SELECT * FROM coins WHERE asset_id = ?")?;
  307. let id_check = stmt.exists(params![id])?;
  308. Ok(id_check)
  309. }
  310. pub fn test_wallet(&self) -> Result<()> {
  311. let conn = Connection::open(&self.path)?;
  312. conn.pragma_update(None, "key", &self.password)?;
  313. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  314. let _rows = stmt.query([])?;
  315. Ok(())
  316. }
  317. }
  318. #[cfg(test)]
  319. mod tests {
  320. use super::*;
  321. use crate::crypto::{coin::Coin, OwnCoin};
  322. use crate::util::join_config_path;
  323. use ff::PrimeField;
  324. pub fn init_db(path: &PathBuf, password: String) -> Result<()> {
  325. if !password.trim().is_empty() {
  326. let contents = include_str!("../../sql/schema.sql");
  327. let conn = Connection::open(&path)?;
  328. debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", path);
  329. conn.pragma_update(None, "key", &password)?;
  330. conn.execute_batch(&contents)?;
  331. } else {
  332. debug!(
  333. target: "WALLETDB", "Password is empty. You must set a password to use the wallet."
  334. );
  335. return Err(Error::from(ClientFailed::EmptyPassword));
  336. }
  337. Ok(())
  338. }
  339. #[test]
  340. pub fn test_get_token_id() -> Result<()> {
  341. let walletdb_path = join_config_path(&PathBuf::from("test_wallet.db"))?;
  342. let password: String = "darkfi".into();
  343. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  344. init_db(&walletdb_path, password)?;
  345. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  346. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  347. let key_public = serial::serialize(&public);
  348. let key_private = serial::serialize(&secret);
  349. wallet.put_keypair(key_public, key_private)?;
  350. let asset_id = jubjub::Fr::random(&mut OsRng);
  351. let note = Note {
  352. serial: jubjub::Fr::random(&mut OsRng),
  353. value: 110,
  354. asset_id,
  355. coin_blind: jubjub::Fr::random(&mut OsRng),
  356. valcom_blind: jubjub::Fr::random(&mut OsRng),
  357. };
  358. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  359. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  360. tree.append(MerkleNode::from_coin(&coin))?;
  361. let witness = IncrementalWitness::from_tree(&tree);
  362. let own_coin = OwnCoin {
  363. coin,
  364. note: note.clone(),
  365. secret,
  366. witness: witness.clone(),
  367. };
  368. wallet.put_own_coins(own_coin.clone())?;
  369. wallet.put_own_coins(own_coin.clone())?;
  370. wallet.put_own_coins(own_coin.clone())?;
  371. wallet.put_own_coins(own_coin.clone())?;
  372. let token_id = wallet.get_token_id()?;
  373. assert_eq!(token_id.len(), 4);
  374. assert_eq!(token_id[0], asset_id);
  375. assert_eq!(token_id[2], asset_id);
  376. assert!(wallet.token_id_exists(&asset_id)?);
  377. std::fs::remove_file(walletdb_path)?;
  378. Ok(())
  379. }
  380. #[test]
  381. pub fn test_get_token_table() -> Result<()> {
  382. let walletdb_path = join_config_path(&PathBuf::from("test2_wallet.db"))?;
  383. let password: String = "darkfi".into();
  384. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  385. init_db(&walletdb_path, password)?;
  386. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  387. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  388. let key_public = serial::serialize(&public);
  389. let key_private = serial::serialize(&secret);
  390. wallet.put_keypair(key_public, key_private)?;
  391. let asset_id = jubjub::Fr::random(&mut OsRng);
  392. let note = Note {
  393. serial: jubjub::Fr::random(&mut OsRng),
  394. value: 110,
  395. asset_id,
  396. coin_blind: jubjub::Fr::random(&mut OsRng),
  397. valcom_blind: jubjub::Fr::random(&mut OsRng),
  398. };
  399. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  400. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  401. tree.append(MerkleNode::from_coin(&coin))?;
  402. let witness = IncrementalWitness::from_tree(&tree);
  403. let own_coin = OwnCoin {
  404. coin,
  405. note: note.clone(),
  406. secret,
  407. witness: witness.clone(),
  408. };
  409. wallet.put_own_coins(own_coin.clone())?;
  410. wallet.put_own_coins(own_coin.clone())?;
  411. wallet.put_own_coins(own_coin.clone())?;
  412. wallet.put_own_coins(own_coin.clone())?;
  413. let table_vec = wallet.get_token_table()?;
  414. assert_eq!(table_vec.len(), 4);
  415. assert_eq!(table_vec[0].value, 110);
  416. assert_eq!(table_vec[0].token_id, asset_id);
  417. assert_eq!(table_vec[2].value, 110);
  418. assert_eq!(table_vec[2].token_id, asset_id);
  419. std::fs::remove_file(walletdb_path)?;
  420. Ok(())
  421. }
  422. #[test]
  423. pub fn test_save_and_load_keypair() -> Result<()> {
  424. let walletdb_path = join_config_path(&PathBuf::from("test3_wallet.db"))?;
  425. let password: String = "darkfi".into();
  426. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  427. init_db(&walletdb_path, password)?;
  428. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  429. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  430. let key_public = serial::serialize(&public);
  431. let key_private = serial::serialize(&secret);
  432. wallet.put_keypair(key_public, key_private)?;
  433. let keypair = wallet.get_keypairs()?[0].clone();
  434. assert_eq!(public, keypair.public);
  435. assert_eq!(secret, keypair.private);
  436. std::fs::remove_file(walletdb_path)?;
  437. Ok(())
  438. }
  439. #[test]
  440. pub fn test_put_and_get_own_coins() -> Result<()> {
  441. let walletdb_path = join_config_path(&PathBuf::from("test4_wallet.db"))?;
  442. let password: String = "darkfi".into();
  443. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  444. init_db(&walletdb_path, password)?;
  445. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  446. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  447. let key_public = serial::serialize(&public);
  448. let key_private = serial::serialize(&secret);
  449. wallet.put_keypair(key_public, key_private)?;
  450. let note = Note {
  451. serial: jubjub::Fr::random(&mut OsRng),
  452. value: 110,
  453. asset_id: jubjub::Fr::random(&mut OsRng),
  454. coin_blind: jubjub::Fr::random(&mut OsRng),
  455. valcom_blind: jubjub::Fr::random(&mut OsRng),
  456. };
  457. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  458. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  459. tree.append(MerkleNode::from_coin(&coin))?;
  460. let witness = IncrementalWitness::from_tree(&tree);
  461. let own_coin = OwnCoin {
  462. coin,
  463. note: note.clone(),
  464. secret,
  465. witness: witness.clone(),
  466. };
  467. wallet.put_own_coins(own_coin.clone())?;
  468. let own_coin = wallet.get_own_coins()?[0].clone();
  469. assert_eq!(&own_coin.note.valcom_blind, &note.valcom_blind);
  470. assert_eq!(&own_coin.note.coin_blind, &note.coin_blind);
  471. assert_eq!(own_coin.secret, secret);
  472. assert_eq!(own_coin.witness.root(), witness.root());
  473. assert_eq!(own_coin.witness.path(), witness.path());
  474. std::fs::remove_file(walletdb_path)?;
  475. Ok(())
  476. }
  477. #[test]
  478. pub fn test_get_witnesses_and_update_them() -> Result<()> {
  479. let walletdb_path = join_config_path(&PathBuf::from("test5_wallet.db"))?;
  480. let password: String = "darkfi".into();
  481. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  482. init_db(&walletdb_path, password)?;
  483. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  484. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  485. let key_public = serial::serialize(&public);
  486. let key_private = serial::serialize(&secret);
  487. wallet.put_keypair(key_public, key_private)?;
  488. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  489. let note = Note {
  490. serial: jubjub::Fr::random(&mut OsRng),
  491. value: 110,
  492. asset_id: jubjub::Fr::random(&mut OsRng),
  493. coin_blind: jubjub::Fr::random(&mut OsRng),
  494. valcom_blind: jubjub::Fr::random(&mut OsRng),
  495. };
  496. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  497. let node = MerkleNode::from_coin(&coin);
  498. tree.append(node)?;
  499. tree.append(node)?;
  500. tree.append(node)?;
  501. tree.append(node)?;
  502. let witness = IncrementalWitness::from_tree(&tree);
  503. let own_coin = OwnCoin {
  504. coin,
  505. note,
  506. secret,
  507. witness,
  508. };
  509. wallet.put_own_coins(own_coin.clone())?;
  510. wallet.put_own_coins(own_coin.clone())?;
  511. wallet.put_own_coins(own_coin.clone())?;
  512. wallet.put_own_coins(own_coin.clone())?;
  513. let coin2 = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  514. let node2 = MerkleNode::from_coin(&coin2);
  515. tree.append(node2)?;
  516. for (coin_id, witness) in wallet.get_witnesses()?.iter_mut() {
  517. witness.append(node2).expect("Append to witness");
  518. wallet.update_witness(coin_id.clone(), witness.clone())?;
  519. }
  520. for (_, witness) in wallet.get_witnesses()?.iter() {
  521. assert_eq!(tree.root(), witness.root());
  522. }
  523. std::fs::remove_file(walletdb_path)?;
  524. Ok(())
  525. }
  526. #[test]
  527. pub fn test_put_and_get_cashier_public_key() -> Result<()> {
  528. let walletdb_path = join_config_path(&PathBuf::from("test6_wallet.db"))?;
  529. let password: String = "darkfi".into();
  530. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  531. init_db(&walletdb_path, password)?;
  532. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  533. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  534. wallet.put_cashier_pub(&public)?;
  535. let cashier_public = wallet.get_cashier_public_keys()?[0];
  536. assert_eq!(cashier_public, public);
  537. assert_eq!(wallet.get_cashier_public_keys()?.contains(&public), true);
  538. std::fs::remove_file(walletdb_path)?;
  539. Ok(())
  540. }
  541. }