walletdb.rs 22 KB

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