walletdb.rs 22 KB

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