walletdb.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  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 > :id")?;
  76. let key_check = stmt.exists(&[(":id", &"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 =
  111. self.get_value_deserialized::<jubjub::SubgroupPoint>(public)?;
  112. let private: jubjub::Fr = self.get_value_deserialized::<jubjub::Fr>(private)?;
  113. keypairs.push(Keypair { public, private });
  114. }
  115. Ok(keypairs)
  116. }
  117. pub fn get_own_coins(&self) -> Result<OwnCoins> {
  118. debug!(target: "WALLETDB", "Get own coins");
  119. let conn = Connection::open(&self.path)?;
  120. // unlock database
  121. conn.pragma_update(None, "key", &self.password)?;
  122. let mut coins = conn.prepare("SELECT * FROM coins")?;
  123. let rows = coins.query_map([], |row| {
  124. Ok((
  125. row.get(1)?,
  126. row.get(2)?,
  127. row.get(3)?,
  128. row.get(4)?,
  129. row.get(5)?,
  130. row.get(6)?,
  131. row.get(7)?,
  132. row.get(8)?,
  133. ))
  134. })?;
  135. let mut own_coins = Vec::new();
  136. for row in rows {
  137. let row = row?;
  138. let coin = self.get_value_deserialized(row.0)?;
  139. // note
  140. let serial = self.get_value_deserialized(row.1)?;
  141. let coin_blind = self.get_value_deserialized(row.2)?;
  142. let valcom_blind = self.get_value_deserialized(row.3)?;
  143. let value: u64 = row.4;
  144. let asset_id = self.get_value_deserialized(row.5)?;
  145. let note = Note {
  146. serial,
  147. value,
  148. asset_id,
  149. coin_blind,
  150. valcom_blind,
  151. };
  152. let witness = self.get_value_deserialized(row.6)?;
  153. let key_id: u64 = row.7;
  154. // return key_private from key_id
  155. let mut get_private_key =
  156. conn.prepare("SELECT key_private FROM keys WHERE key_id = :key_id")?;
  157. let rows = get_private_key.query_map(&[(":key_id", &key_id)], |row| row.get(0))?;
  158. let mut secret = Vec::new();
  159. for id in rows {
  160. secret.push(id?)
  161. }
  162. let secret: jubjub::Fr =
  163. self.get_value_deserialized(secret.pop().expect("Load public_key from walletdb"))?;
  164. let oc = OwnCoin {
  165. coin,
  166. note,
  167. secret,
  168. witness,
  169. };
  170. own_coins.push(oc)
  171. }
  172. Ok(own_coins)
  173. }
  174. pub fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
  175. // prepare the values
  176. debug!(target: "WALLETDB", "Put own coins");
  177. let coin = self.get_value_serialized(&own_coin.coin.repr)?;
  178. let serial = self.get_value_serialized(&own_coin.note.serial)?;
  179. let coin_blind = self.get_value_serialized(&own_coin.note.coin_blind)?;
  180. let valcom_blind = self.get_value_serialized(&own_coin.note.valcom_blind)?;
  181. let value: u64 = own_coin.note.value;
  182. let asset_id = self.get_value_serialized(&own_coin.note.asset_id)?;
  183. let witness = self.get_value_serialized(&own_coin.witness)?;
  184. let secret = self.get_value_serialized(&own_coin.secret)?;
  185. // open connection
  186. let conn = Connection::open(&self.path)?;
  187. // unlock database
  188. conn.pragma_update(None, "key", &self.password)?;
  189. // return key_id from key_private
  190. let mut get_id =
  191. conn.prepare("SELECT key_id FROM keys WHERE key_private = :key_private")?;
  192. let rows = get_id.query_map::<u64, _, _>(&[(":key_private", &secret)], |row| row.get(0))?;
  193. let mut key_id = Vec::new();
  194. for id in rows {
  195. key_id.push(id?)
  196. }
  197. conn.execute(
  198. "INSERT INTO coins
  199. (coin, serial, value, asset_id, coin_blind, valcom_blind, witness, key_id)
  200. VALUES
  201. (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :key_id);",
  202. named_params! {
  203. ":coin": coin,
  204. ":serial": serial,
  205. ":value": value,
  206. ":asset_id": asset_id,
  207. ":coin_blind": coin_blind,
  208. ":valcom_blind": valcom_blind,
  209. ":witness": witness,
  210. ":key_id": key_id.pop().expect("Get key_id"),
  211. },
  212. )?;
  213. Ok(())
  214. }
  215. pub fn get_witnesses(&self) -> Result<Vec<(u64, IncrementalWitness<MerkleNode>)>> {
  216. let conn = Connection::open(&self.path)?;
  217. conn.pragma_update(None, "key", &self.password)?;
  218. let mut witnesses = conn.prepare("SELECT coin_id, witness FROM coins;")?;
  219. let rows = witnesses.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?;
  220. let mut witnesses = Vec::new();
  221. for i in rows {
  222. let i = i?;
  223. let coin_id: u64 = i.0;
  224. let witness: IncrementalWitness<MerkleNode> = self.get_value_deserialized(i.1)?;
  225. witnesses.push((coin_id, witness))
  226. }
  227. Ok(witnesses)
  228. }
  229. pub fn update_witness(
  230. &self,
  231. coin_id: u64,
  232. witness: IncrementalWitness<MerkleNode>,
  233. ) -> Result<()> {
  234. debug!(target: "WALLETDB", "Updating witness");
  235. let conn = Connection::open(&self.path)?;
  236. conn.pragma_update(None, "key", &self.password)?;
  237. let witness = self.get_value_serialized(&witness)?;
  238. conn.execute(
  239. "UPDATE coins SET witness = ?1 WHERE coin_id = ?2;",
  240. params![witness, coin_id],
  241. )?;
  242. Ok(())
  243. }
  244. pub fn put_cashier_pub(&self, key_public: &jubjub::SubgroupPoint) -> Result<()> {
  245. debug!(target: "WALLETDB", "Save cashier keys...");
  246. let conn = Connection::open(&self.path)?;
  247. conn.pragma_update(None, "key", &self.password)?;
  248. let key_public = self.get_value_serialized(key_public)?;
  249. conn.execute(
  250. "INSERT INTO cashier(key_public) VALUES (?1)",
  251. params![key_public],
  252. )?;
  253. Ok(())
  254. }
  255. pub fn get_cashier_public_keys(&self) -> Result<Vec<jubjub::SubgroupPoint>> {
  256. debug!(target: "WALLETDB", "Returning Cashier Public key...");
  257. let conn = Connection::open(&self.path)?;
  258. conn.pragma_update(None, "key", &self.password)?;
  259. let mut stmt = conn.prepare("SELECT key_public FROM cashier")?;
  260. let key_iter = stmt.query_map([], |row| row.get(0))?;
  261. let mut pub_keys = Vec::new();
  262. for key in key_iter {
  263. let public: jubjub::SubgroupPoint = self.get_value_deserialized(key?)?;
  264. pub_keys.push(public);
  265. }
  266. Ok(pub_keys)
  267. }
  268. pub fn get_token_table(&self) -> Result<Vec<TokenTable>> {
  269. debug!(target: "WALLETDB", "Get token and balances...");
  270. let conn = Connection::open(&self.path)?;
  271. conn.pragma_update(None, "key", &self.password)?;
  272. let mut stmt = conn.prepare("SELECT coin_id, value, asset_id FROM coins ;")?;
  273. let rows = stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)))?;
  274. let mut token_table = Vec::new();
  275. for row in rows {
  276. let row = row?;
  277. let coin_id: u64 = row.0;
  278. let value: u64 = row.1;
  279. let token_id: jubjub::Fr = self.get_value_deserialized(row.2)?;
  280. token_table.push(TokenTable {
  281. coin_id,
  282. value,
  283. token_id,
  284. });
  285. }
  286. Ok(token_table)
  287. }
  288. pub fn get_token_id(&self) -> Result<Vec<jubjub::Fr>> {
  289. debug!(target: "WALLETDB", "Get token and balances...");
  290. let conn = Connection::open(&self.path)?;
  291. conn.pragma_update(None, "key", &self.password)?;
  292. let mut stmt = conn.prepare("SELECT asset_id FROM coins")?;
  293. let rows = stmt.query_map([], |row| row.get(0))?;
  294. let mut token_ids = Vec::new();
  295. for row in rows {
  296. let row = row?;
  297. let token_id = self.get_value_deserialized(row).unwrap();
  298. token_ids.push(token_id);
  299. }
  300. Ok(token_ids)
  301. }
  302. pub fn token_id_exists(&self, token_id: &jubjub::Fr) -> Result<bool> {
  303. debug!(target: "WALLETDB", "Check tokenID exists");
  304. let conn = Connection::open(&self.path)?;
  305. conn.pragma_update(None, "key", &self.password)?;
  306. let id = self.get_value_serialized(token_id)?;
  307. let mut stmt = conn.prepare("SELECT * FROM coins WHERE asset_id > :id")?;
  308. let id_check = stmt.exists([id])?;
  309. Ok(id_check)
  310. }
  311. pub fn test_wallet(&self) -> Result<()> {
  312. let conn = Connection::open(&self.path)?;
  313. conn.pragma_update(None, "key", &self.password)?;
  314. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  315. let _rows = stmt.query([])?;
  316. Ok(())
  317. }
  318. }
  319. #[cfg(test)]
  320. mod tests {
  321. use super::*;
  322. use crate::crypto::{coin::Coin, OwnCoin};
  323. use crate::util::join_config_path;
  324. use ff::PrimeField;
  325. pub fn init_db(path: &PathBuf, password: String) -> Result<()> {
  326. if !password.trim().is_empty() {
  327. let contents = include_str!("../../sql/schema.sql");
  328. let conn = Connection::open(&path)?;
  329. debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", path);
  330. conn.pragma_update(None, "key", &password)?;
  331. conn.execute_batch(&contents)?;
  332. } else {
  333. debug!(
  334. target: "WALLETDB", "Password is empty. You must set a password to use the wallet."
  335. );
  336. return Err(Error::from(ClientFailed::EmptyPassword));
  337. }
  338. Ok(())
  339. }
  340. #[test]
  341. pub fn test_get_token_id() -> Result<()> {
  342. let walletdb_path = join_config_path(&PathBuf::from("test_wallet.db"))?;
  343. let password: String = "darkfi".into();
  344. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  345. init_db(&walletdb_path, password)?;
  346. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  347. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  348. let key_public = serial::serialize(&public);
  349. let key_private = serial::serialize(&secret);
  350. wallet.put_keypair(key_public, key_private)?;
  351. let asset_id = jubjub::Fr::random(&mut OsRng);
  352. let note = Note {
  353. serial: jubjub::Fr::random(&mut OsRng),
  354. value: 110,
  355. asset_id,
  356. coin_blind: jubjub::Fr::random(&mut OsRng),
  357. valcom_blind: jubjub::Fr::random(&mut OsRng),
  358. };
  359. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  360. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  361. tree.append(MerkleNode::from_coin(&coin))?;
  362. let witness = IncrementalWitness::from_tree(&tree);
  363. let own_coin = OwnCoin {
  364. coin,
  365. note: note.clone(),
  366. secret,
  367. witness: witness.clone(),
  368. };
  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. wallet.put_own_coins(own_coin.clone())?;
  373. let token_id = wallet.get_token_id()?;
  374. assert_eq!(token_id.len(), 4);
  375. assert_eq!(token_id[0], asset_id);
  376. assert_eq!(token_id[2], 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. std::fs::remove_file(walletdb_path)?;
  538. Ok(())
  539. }
  540. }