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