walletdb.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. use async_std::sync::Arc;
  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,
  12. merkle::IncrementalWitness,
  13. merkle_node::MerkleNode,
  14. note::Note,
  15. nullifier::Nullifier,
  16. types::{PublicKey, SecretKey, TokenId},
  17. OwnCoin, OwnCoins,
  18. };
  19. use crate::serial;
  20. use crate::{Error, Result};
  21. pub type WalletPtr = Arc<WalletDb>;
  22. #[derive(Debug, Clone)]
  23. pub struct Keypair {
  24. pub public: PublicKey,
  25. pub private: SecretKey,
  26. }
  27. #[derive(Debug, Clone)]
  28. pub struct Balance {
  29. pub token_id: TokenId,
  30. pub value: u64,
  31. pub nullifier: Nullifier,
  32. }
  33. #[derive(Debug, Clone)]
  34. pub struct Balances {
  35. pub list: Vec<Balance>,
  36. }
  37. impl Balances {
  38. pub fn add(&mut self, balance: &Balance) {
  39. if let Some(mut saved_balance) = self
  40. .list
  41. .iter_mut()
  42. .find(|b| b.token_id == balance.token_id)
  43. {
  44. saved_balance.value += balance.value;
  45. } else {
  46. self.list.push(balance.clone());
  47. }
  48. }
  49. }
  50. //#[derive(Clone)]
  51. pub struct WalletDb {
  52. pub path: PathBuf,
  53. pub password: String,
  54. }
  55. impl WalletApi for WalletDb {
  56. fn get_password(&self) -> String {
  57. self.password.to_owned()
  58. }
  59. fn get_path(&self) -> PathBuf {
  60. self.path.to_owned()
  61. }
  62. }
  63. impl WalletDb {
  64. pub fn new(path: &Path, password: String) -> Result<WalletPtr> {
  65. debug!(target: "WALLETDB", "new() Constructor called");
  66. Ok(Arc::new(Self {
  67. path: path.to_owned(),
  68. password,
  69. }))
  70. }
  71. pub fn init_db(&self) -> Result<()> {
  72. debug!(target: "WALLETDB", "Initialize...");
  73. if !self.password.trim().is_empty() {
  74. let contents = include_str!("../../sql/schema.sql");
  75. let conn = Connection::open(&self.path)?;
  76. debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", self.path);
  77. conn.pragma_update(None, "key", &self.password)?;
  78. conn.execute_batch(contents)?;
  79. } else {
  80. debug!(
  81. target: "WALLETDB",
  82. "Password is empty. You must set a password to use the wallet."
  83. );
  84. return Err(Error::from(ClientFailed::EmptyPassword));
  85. }
  86. Ok(())
  87. }
  88. pub fn key_gen(&self) -> Result<()> {
  89. debug!(target: "WALLETDB", "Attempting to generate keys...");
  90. let conn = Connection::open(&self.path)?;
  91. conn.pragma_update(None, "key", &self.password)?;
  92. let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > ?")?;
  93. let key_check = stmt.exists(params!["0"])?;
  94. if !key_check {
  95. let secret: SecretKey = SecretKey::random(&mut OsRng);
  96. let public: PublicKey = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  97. self.put_keypair(&public, &secret)?;
  98. } else {
  99. debug!(target: "WALLETDB", "Keys already exist.");
  100. return Err(Error::from(ClientFailed::KeyExists));
  101. }
  102. Ok(())
  103. }
  104. pub fn put_keypair(&self, key_public: &PublicKey, key_private: &SecretKey) -> Result<()> {
  105. let conn = Connection::open(&self.path)?;
  106. conn.pragma_update(None, "key", &self.password)?;
  107. let key_public = serial::serialize(key_public);
  108. let key_private = serial::serialize(key_private);
  109. conn.execute(
  110. "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  111. params![key_public, key_private],
  112. )?;
  113. Ok(())
  114. }
  115. pub fn get_keypairs(&self) -> Result<Vec<Keypair>> {
  116. debug!(target: "WALLETDB", "Returning keypairs...");
  117. let conn = Connection::open(&self.path)?;
  118. conn.pragma_update(None, "key", &self.password)?;
  119. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  120. // this just gets the first key. maybe we should randomize this
  121. let key_iter = stmt.query_map([], |row| Ok((row.get(1)?, row.get(2)?)))?;
  122. let mut keypairs = Vec::new();
  123. for key in key_iter {
  124. let key = key?;
  125. let public = key.0;
  126. let private = key.1;
  127. let public: PublicKey = self.get_value_deserialized(public)?;
  128. let private: SecretKey = self.get_value_deserialized(private)?;
  129. keypairs.push(Keypair { public, private });
  130. }
  131. Ok(keypairs)
  132. }
  133. pub fn get_own_coins(&self) -> Result<OwnCoins> {
  134. debug!(target: "WALLETDB", "Get own coins");
  135. let is_spent = 0;
  136. let conn = Connection::open(&self.path)?;
  137. // unlock database
  138. conn.pragma_update(None, "key", &self.password)?;
  139. let mut coins = conn.prepare("SELECT * FROM coins WHERE is_spent = :is_spent ;")?;
  140. let rows = coins.query_map(&[(":is_spent", &is_spent)], |row| {
  141. Ok((
  142. row.get(0)?,
  143. row.get(1)?,
  144. row.get(2)?,
  145. row.get(3)?,
  146. row.get(4)?,
  147. row.get(5)?,
  148. row.get(6)?,
  149. row.get(7)?,
  150. row.get(9)?,
  151. ))
  152. })?;
  153. let mut own_coins = Vec::new();
  154. for row in rows {
  155. let row = row?;
  156. let coin = self.get_value_deserialized(row.0)?;
  157. // note
  158. let serial = self.get_value_deserialized(row.1)?;
  159. let coin_blind = self.get_value_deserialized(row.2)?;
  160. let valcom_blind = self.get_value_deserialized(row.3)?;
  161. let value: u64 = row.4;
  162. let token_id = self.get_value_deserialized(row.5)?;
  163. let note = Note {
  164. serial,
  165. value,
  166. token_id,
  167. coin_blind,
  168. valcom_blind,
  169. };
  170. let witness = self.get_value_deserialized(row.6)?;
  171. let secret: SecretKey = self.get_value_deserialized(row.7)?;
  172. let nullifier: Nullifier = self.get_value_deserialized(row.8)?;
  173. let oc = OwnCoin {
  174. coin,
  175. note,
  176. secret,
  177. witness,
  178. nullifier,
  179. };
  180. own_coins.push(oc)
  181. }
  182. Ok(own_coins)
  183. }
  184. pub fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
  185. debug!(target: "WALLETDB", "Put own coins");
  186. // open connection
  187. let conn = Connection::open(&self.path)?;
  188. // unlock database
  189. conn.pragma_update(None, "key", &self.password)?;
  190. let coin = self.get_value_serialized(&own_coin.coin.repr)?;
  191. let serial = self.get_value_serialized(&own_coin.note.serial)?;
  192. let coin_blind = self.get_value_serialized(&own_coin.note.coin_blind)?;
  193. let valcom_blind = self.get_value_serialized(&own_coin.note.valcom_blind)?;
  194. let value: u64 = own_coin.note.value;
  195. let token_id = self.get_value_serialized(&own_coin.note.token_id)?;
  196. let witness = self.get_value_serialized(&own_coin.witness)?;
  197. let secret = self.get_value_serialized(&own_coin.secret)?;
  198. let is_spent = 0;
  199. let nullifier = self.get_value_serialized(&own_coin.nullifier)?;
  200. conn.execute(
  201. "INSERT OR REPLACE INTO coins
  202. (coin, serial, value, token_id, coin_blind,
  203. valcom_blind, witness, secret, is_spent, nullifier)
  204. VALUES
  205. (:coin, :serial, :value, :token_id, :coin_blind,
  206. :valcom_blind, :witness, :secret, :is_spent, :nullifier);",
  207. named_params! {
  208. ":coin": coin,
  209. ":serial": serial,
  210. ":value": value,
  211. ":token_id": token_id,
  212. ":coin_blind": coin_blind,
  213. ":valcom_blind": valcom_blind,
  214. ":witness": witness,
  215. ":secret": secret,
  216. ":is_spent": is_spent,
  217. ":nullifier": nullifier,
  218. },
  219. )?;
  220. Ok(())
  221. }
  222. pub fn remove_own_coins(&self) -> Result<()> {
  223. debug!(target: "WALLETDB", "Remove own coins");
  224. // open connection
  225. let conn = Connection::open(&self.path)?;
  226. // unlock database
  227. conn.pragma_update(None, "key", &self.password)?;
  228. conn.execute("DROP TABLE coins;", [])?;
  229. Ok(())
  230. }
  231. pub fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
  232. debug!(target: "WALLETDB", "Confirm spend coin");
  233. let coin = self.get_value_serialized(coin)?;
  234. // open connection
  235. let conn = Connection::open(&self.path)?;
  236. // unlock database
  237. conn.pragma_update(None, "key", &self.password)?;
  238. let is_spent = 1;
  239. conn.execute(
  240. "UPDATE coins
  241. SET is_spent = ?1
  242. WHERE coin = ?2 ;",
  243. params![is_spent, coin],
  244. )?;
  245. Ok(())
  246. }
  247. pub fn get_witnesses(&self) -> Result<HashMap<Vec<u8>, IncrementalWitness<MerkleNode>>> {
  248. let conn = Connection::open(&self.path)?;
  249. conn.pragma_update(None, "key", &self.password)?;
  250. let is_spent = 0;
  251. let mut witnesses =
  252. conn.prepare("SELECT coin, witness FROM coins WHERE is_spent = :is_spent;")?;
  253. let rows = witnesses.query_map(&[(":is_spent", &is_spent)], |row| {
  254. Ok((row.get(0)?, row.get(1)?))
  255. })?;
  256. let mut witnesses = HashMap::new();
  257. for i in rows {
  258. let i = i?;
  259. let coin: Vec<u8> = i.0;
  260. let witness: IncrementalWitness<MerkleNode> = self.get_value_deserialized(i.1)?;
  261. witnesses.insert(coin, witness);
  262. }
  263. Ok(witnesses)
  264. }
  265. pub fn update_witnesses(
  266. &self,
  267. witnesses: HashMap<Vec<u8>, IncrementalWitness<MerkleNode>>,
  268. ) -> Result<()> {
  269. debug!(target: "WALLETDB", "Updating witness");
  270. let conn = Connection::open(&self.path)?;
  271. conn.pragma_update(None, "key", &self.password)?;
  272. for (coin, witness) in witnesses.iter() {
  273. let witness = self.get_value_serialized(witness)?;
  274. let is_spent = 0;
  275. conn.execute(
  276. "UPDATE coins SET witness = ?1 WHERE coin = ?2 AND is_spent = ?3",
  277. params![witness, coin, is_spent],
  278. )?;
  279. }
  280. Ok(())
  281. }
  282. pub fn get_balances(&self) -> Result<Balances> {
  283. debug!(target: "WALLETDB", "Get token and balances...");
  284. let conn = Connection::open(&self.path)?;
  285. conn.pragma_update(None, "key", &self.password)?;
  286. let is_spent = 0;
  287. let mut stmt = conn.prepare(
  288. "SELECT value, token_id, nullifier FROM coins WHERE is_spent = :is_spent ;",
  289. )?;
  290. let rows = stmt.query_map(&[(":is_spent", &is_spent)], |row| {
  291. Ok((row.get(0)?, row.get(1)?, row.get(2)?))
  292. })?;
  293. let mut balances = Balances { list: Vec::new() };
  294. for row in rows {
  295. let row = row?;
  296. let value: u64 = row.0;
  297. let token_id: TokenId = self.get_value_deserialized(row.1)?;
  298. let nullifier: Nullifier = self.get_value_deserialized(row.2)?;
  299. balances.add(&Balance {
  300. token_id,
  301. value,
  302. nullifier,
  303. });
  304. }
  305. Ok(balances)
  306. }
  307. pub fn get_token_id(&self) -> Result<Vec<TokenId>> {
  308. debug!(target: "WALLETDB", "Get token ID...");
  309. let conn = Connection::open(&self.path)?;
  310. conn.pragma_update(None, "key", &self.password)?;
  311. let is_spent = 0;
  312. let mut stmt = conn.prepare("SELECT token_id FROM coins WHERE is_spent = :is_spent ;")?;
  313. let rows = stmt.query_map(&[(":is_spent", &is_spent)], |row| row.get(0))?;
  314. let mut token_ids = Vec::new();
  315. for row in rows {
  316. let row = row?;
  317. let token_id = self.get_value_deserialized(row).unwrap();
  318. token_ids.push(token_id);
  319. }
  320. Ok(token_ids)
  321. }
  322. pub fn token_id_exists(&self, token_id: &TokenId) -> Result<bool> {
  323. debug!(target: "WALLETDB", "Check tokenID exists");
  324. let conn = Connection::open(&self.path)?;
  325. conn.pragma_update(None, "key", &self.password)?;
  326. let id = self.get_value_serialized(token_id)?;
  327. let is_spent = 0;
  328. let mut stmt = conn.prepare("SELECT * FROM coins WHERE token_id = ? AND is_spent = ? ;")?;
  329. let id_check = stmt.exists(params![id, is_spent])?;
  330. Ok(id_check)
  331. }
  332. pub fn test_wallet(&self) -> Result<()> {
  333. let conn = Connection::open(&self.path)?;
  334. conn.pragma_update(None, "key", &self.password)?;
  335. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  336. let _rows = stmt.query([])?;
  337. Ok(())
  338. }
  339. }
  340. #[cfg(test)]
  341. mod tests {
  342. // TODO: Clean up, there's a lot of duplicated code here.
  343. use super::*;
  344. use crate::crypto::{
  345. coin::Coin,
  346. types::{derive_publickey, CoinBlind, NullifierSerial, ValueCommitBlind},
  347. OwnCoin,
  348. };
  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 = SecretKey::random(&mut OsRng);
  373. let public = derive_publickey(secret);
  374. wallet.put_keypair(&public, &secret)?;
  375. let token_id = TokenId::random(&mut OsRng);
  376. let note = Note {
  377. serial: NullifierSerial::random(&mut OsRng),
  378. value: 110,
  379. token_id,
  380. coin_blind: CoinBlind::random(&mut OsRng),
  381. valcom_blind: ValueCommitBlind::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 = SecretKey::random(&mut OsRng);
  415. let public = derive_publickey(secret);
  416. wallet.put_keypair(&public, &secret)?;
  417. let token_id = TokenId::random(&mut OsRng);
  418. let note = Note {
  419. serial: NullifierSerial::random(&mut OsRng),
  420. value: 110,
  421. token_id,
  422. coin_blind: CoinBlind::random(&mut OsRng),
  423. valcom_blind: ValueCommitBlind::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 = SecretKey::random(&mut OsRng);
  455. let public = derive_publickey(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 = SecretKey::random(&mut OsRng);
  470. let public = derive_publickey(secret);
  471. wallet.put_keypair(&public, &secret)?;
  472. let note = Note {
  473. serial: NullifierSerial::random(&mut OsRng),
  474. value: 110,
  475. token_id: TokenId::random(&mut OsRng),
  476. coin_blind: CoinBlind::random(&mut OsRng),
  477. valcom_blind: ValueCommitBlind::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. std::fs::remove_file(walletdb_path)?;
  509. Ok(())
  510. }
  511. #[test]
  512. pub fn test_get_witnesses_and_update_them() -> Result<()> {
  513. let walletdb_path = join_config_path(&PathBuf::from("test5_wallet.db"))?;
  514. let password: String = "darkfi".into();
  515. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  516. init_db(&walletdb_path, password)?;
  517. let secret = SecretKey::random(&mut OsRng);
  518. let public = derive_publickey(secret);
  519. wallet.put_keypair(&public, &secret)?;
  520. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  521. let note = Note {
  522. serial: NullifierSerial::random(&mut OsRng),
  523. value: 110,
  524. token_id: TokenId::random(&mut OsRng),
  525. coin_blind: CoinBlind::random(&mut OsRng),
  526. valcom_blind: ValueCommitBlind::random(&mut OsRng),
  527. };
  528. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  529. let node = MerkleNode::from_coin(&coin);
  530. tree.append(node)?;
  531. tree.append(node)?;
  532. tree.append(node)?;
  533. tree.append(node)?;
  534. let witness = IncrementalWitness::from_tree(&tree);
  535. // for testing
  536. let nullifier = Nullifier::new(coin.repr);
  537. let own_coin = OwnCoin {
  538. coin,
  539. note,
  540. secret,
  541. witness,
  542. nullifier,
  543. };
  544. wallet.put_own_coins(own_coin.clone())?;
  545. wallet.put_own_coins(own_coin.clone())?;
  546. wallet.put_own_coins(own_coin.clone())?;
  547. wallet.put_own_coins(own_coin)?;
  548. let coin2 = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  549. let node2 = MerkleNode::from_coin(&coin2);
  550. tree.append(node2)?;
  551. let mut updated_witnesses = wallet.get_witnesses()?;
  552. updated_witnesses.iter_mut().for_each(|(_, witness)| {
  553. witness.append(node2).expect("Append to witness");
  554. });
  555. wallet.update_witnesses(updated_witnesses)?;
  556. for (_, witness) in wallet.get_witnesses()?.iter() {
  557. assert_eq!(tree.root(), witness.root());
  558. }
  559. std::fs::remove_file(walletdb_path)?;
  560. Ok(())
  561. }
  562. }