walletdb.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. use super::WalletApi;
  2. use crate::client::ClientFailed;
  3. use crate::crypto::{
  4. merkle::IncrementalWitness, merkle_node::MerkleNode, note::Note, OwnCoin, OwnCoins,
  5. };
  6. use crate::serial;
  7. use crate::{Error, Result};
  8. use async_std::sync::{Arc, Mutex};
  9. use ff::Field;
  10. use log::*;
  11. use rand::rngs::OsRng;
  12. use rusqlite::{named_params, params, Connection};
  13. use std::path::{Path, PathBuf};
  14. pub type WalletPtr = Arc<WalletDb>;
  15. #[derive(Debug, Clone)]
  16. pub struct Keypair {
  17. pub public: jubjub::SubgroupPoint,
  18. pub private: jubjub::Fr,
  19. }
  20. //#[derive(Clone)]
  21. pub struct WalletDb {
  22. pub path: PathBuf,
  23. pub password: String,
  24. pub initialized: Mutex<bool>,
  25. }
  26. impl WalletApi for WalletDb {
  27. fn get_password(&self) -> String {
  28. self.password.to_owned()
  29. }
  30. fn get_path(&self) -> PathBuf {
  31. self.path.to_owned()
  32. }
  33. }
  34. impl WalletDb {
  35. pub fn new(path: &Path, password: String) -> Result<WalletPtr> {
  36. debug!(target: "WALLETDB", "new() Constructor called");
  37. Ok(Arc::new(Self {
  38. path: path.to_owned(),
  39. password,
  40. initialized: Mutex::new(false),
  41. }))
  42. }
  43. pub async fn init_db(&self) -> Result<()> {
  44. if !*self.initialized.lock().await {
  45. if !self.password.trim().is_empty() {
  46. let contents = include_str!("../../sql/schema.sql");
  47. let conn = Connection::open(&self.path)?;
  48. debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", self.path);
  49. conn.pragma_update(None, "key", &self.password)?;
  50. conn.execute_batch(&contents)?;
  51. *self.initialized.lock().await = true;
  52. } else {
  53. debug!(
  54. target: "WALLETDB",
  55. "Password is empty. You must set a password to use the wallet."
  56. );
  57. return Err(Error::from(ClientFailed::EmptyPassword));
  58. }
  59. } else {
  60. debug!(target: "WALLETDB", "Wallet already initialized.");
  61. return Err(Error::from(ClientFailed::WalletInitialized));
  62. }
  63. Ok(())
  64. }
  65. pub fn key_gen(&self) -> Result<()> {
  66. debug!(target: "WALLETDB", "Attempting to generate keys...");
  67. let conn = Connection::open(&self.path)?;
  68. conn.pragma_update(None, "key", &self.password)?;
  69. let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > :id")?;
  70. let key_check = stmt.exists(&[(":id", &"0")])?;
  71. if !key_check {
  72. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  73. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  74. let pubkey = serial::serialize(&public);
  75. let privkey = serial::serialize(&secret);
  76. self.put_keypair(pubkey, privkey)?;
  77. } else {
  78. debug!(target: "WALLETDB", "Keys already exist.");
  79. return Err(Error::from(ClientFailed::KeyExists));
  80. }
  81. Ok(())
  82. }
  83. pub fn put_keypair(&self, key_public: Vec<u8>, key_private: Vec<u8>) -> Result<()> {
  84. let conn = Connection::open(&self.path)?;
  85. conn.pragma_update(None, "key", &self.password)?;
  86. conn.execute(
  87. "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  88. params![key_public, key_private],
  89. )?;
  90. Ok(())
  91. }
  92. pub fn get_keypairs(&self) -> Result<Vec<Keypair>> {
  93. debug!(target: "WALLETDB", "Returning keys...");
  94. let conn = Connection::open(&self.path)?;
  95. conn.pragma_update(None, "key", &self.password)?;
  96. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  97. // this just gets the first key. maybe we should randomize this
  98. let key_iter = stmt.query_map([], |row| Ok((row.get(1)?, row.get(2)?)))?;
  99. let mut keypairs = Vec::new();
  100. for key in key_iter {
  101. let key = key?;
  102. let public = key.0;
  103. let private = key.1;
  104. let public: jubjub::SubgroupPoint =
  105. self.get_value_deserialized::<jubjub::SubgroupPoint>(public)?;
  106. let private: jubjub::Fr = self.get_value_deserialized::<jubjub::Fr>(private)?;
  107. keypairs.push(Keypair { public, private });
  108. }
  109. Ok(keypairs)
  110. }
  111. pub fn get_own_coins(&self) -> Result<OwnCoins> {
  112. // open connection
  113. let conn = Connection::open(&self.path)?;
  114. // unlock database
  115. conn.pragma_update(None, "key", &self.password)?;
  116. let mut coins = conn.prepare("SELECT * FROM coins")?;
  117. let rows = coins.query_map([], |row| {
  118. let coin = self.get_value_deserialized(row.get(1)?).unwrap();
  119. // note
  120. let serial = self.get_value_deserialized(row.get(2)?).unwrap();
  121. let coin_blind = self.get_value_deserialized(row.get(3)?).unwrap();
  122. let valcom_blind = self.get_value_deserialized(row.get(4)?).unwrap();
  123. let value: u64 = row.get(5)?;
  124. let asset_id = self.get_value_deserialized(row.get(6)?).unwrap();
  125. let note = Note {
  126. serial,
  127. value,
  128. asset_id,
  129. coin_blind,
  130. valcom_blind,
  131. };
  132. let witness = self.get_value_deserialized(row.get(7)?).unwrap();
  133. let key_id: u64 = row.get(8)?;
  134. // return key_private from key_id
  135. let mut get_private_key =
  136. conn.prepare("SELECT key_private FROM keys WHERE key_id = :key_id")?;
  137. let rows = get_private_key.query_map(&[(":key_id", &key_id)], |row| row.get(0))?;
  138. let mut secret = Vec::new();
  139. for id in rows {
  140. secret.push(id?)
  141. }
  142. let secret: jubjub::Fr = self
  143. .get_value_deserialized(secret.pop().expect("Load public_key from walletdb"))
  144. .unwrap();
  145. Ok(OwnCoin {
  146. coin,
  147. note,
  148. secret,
  149. witness,
  150. })
  151. })?;
  152. let mut own_coins = Vec::new();
  153. for id in rows {
  154. own_coins.push(id?)
  155. }
  156. Ok(own_coins)
  157. }
  158. pub fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
  159. // prepare the values
  160. let coin = self.get_value_serialized(&own_coin.coin.repr)?;
  161. let serial = self.get_value_serialized(&own_coin.note.serial)?;
  162. let coin_blind = self.get_value_serialized(&own_coin.note.coin_blind)?;
  163. let valcom_blind = self.get_value_serialized(&own_coin.note.valcom_blind)?;
  164. let value: u64 = own_coin.note.value;
  165. let asset_id = self.get_value_serialized(&own_coin.note.asset_id)?;
  166. let witness = self.get_value_serialized(&own_coin.witness)?;
  167. let secret = self.get_value_serialized(&own_coin.secret)?;
  168. // open connection
  169. let conn = Connection::open(&self.path)?;
  170. // unlock database
  171. conn.pragma_update(None, "key", &self.password)?;
  172. // return key_id from key_private
  173. let mut get_id =
  174. conn.prepare("SELECT key_id FROM keys WHERE key_private = :key_private")?;
  175. let rows = get_id.query_map::<u64, _, _>(&[(":key_private", &secret)], |row| row.get(0))?;
  176. let mut key_id = Vec::new();
  177. for id in rows {
  178. key_id.push(id?)
  179. }
  180. conn.execute(
  181. "INSERT INTO coins
  182. (coin, serial, value, asset_id, coin_blind, valcom_blind, witness, key_id)
  183. VALUES
  184. (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :key_id);",
  185. named_params! {
  186. ":coin": coin,
  187. ":serial": serial,
  188. ":value": value,
  189. ":asset_id": asset_id,
  190. ":coin_blind": coin_blind,
  191. ":valcom_blind": valcom_blind,
  192. ":witness": witness,
  193. ":key_id": key_id.pop().expect("Get key_id"),
  194. },
  195. )?;
  196. Ok(())
  197. }
  198. pub fn get_witnesses(&self) -> Result<Vec<(u64, IncrementalWitness<MerkleNode>)>> {
  199. let conn = Connection::open(&self.path)?;
  200. conn.pragma_update(None, "key", &self.password)?;
  201. let mut witnesses = conn.prepare("SELECT coin_id, witness FROM coins;")?;
  202. let rows = witnesses.query_map([], |row| {
  203. let coin_id: u64 = row.get(0)?;
  204. let witness: IncrementalWitness<MerkleNode> =
  205. self.get_value_deserialized(row.get(1)?).unwrap();
  206. Ok((coin_id, witness))
  207. })?;
  208. let mut witnesses = Vec::new();
  209. for i in rows {
  210. witnesses.push(i?)
  211. }
  212. Ok(witnesses)
  213. }
  214. pub fn update_witness(
  215. &self,
  216. coin_id: u64,
  217. witness: IncrementalWitness<MerkleNode>,
  218. ) -> Result<()> {
  219. let conn = Connection::open(&self.path)?;
  220. conn.pragma_update(None, "key", &self.password)?;
  221. let witness = self.get_value_serialized(&witness)?;
  222. conn.execute(
  223. "UPDATE coins SET witness = ?1 WHERE coin_id = ?2;",
  224. params![witness, coin_id],
  225. )?;
  226. Ok(())
  227. }
  228. pub fn put_cashier_pub(&self, key_public: Vec<u8>) -> Result<()> {
  229. debug!(target: "WALLETDB", "Save cashier keys...");
  230. let conn = Connection::open(&self.path)?;
  231. conn.pragma_update(None, "key", &self.password)?;
  232. conn.execute(
  233. "INSERT INTO cashier(key_public) VALUES (?1)",
  234. params![key_public],
  235. )?;
  236. Ok(())
  237. }
  238. pub fn get_cashier_public_keys(&self) -> Result<Vec<jubjub::SubgroupPoint>> {
  239. debug!(target: "WALLETDB", "Returning keys...");
  240. let conn = Connection::open(&self.path)?;
  241. conn.pragma_update(None, "key", &self.password)?;
  242. let mut stmt = conn.prepare("SELECT key_public FROM cashier")?;
  243. let key_iter = stmt.query_map([], |row| row.get(0))?;
  244. let mut pub_keys = Vec::new();
  245. for key in key_iter {
  246. let public: jubjub::SubgroupPoint = self.get_value_deserialized(key?)?;
  247. pub_keys.push(public);
  248. }
  249. if pub_keys.is_empty() {
  250. return Err(Error::from(ClientFailed::DoesNotHaveCashierPublicKey));
  251. }
  252. Ok(pub_keys)
  253. }
  254. pub fn test_wallet(&self) -> Result<()> {
  255. let conn = Connection::open(&self.path)?;
  256. conn.pragma_update(None, "key", &self.password)?;
  257. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  258. let _rows = stmt.query([])?;
  259. Ok(())
  260. }
  261. }
  262. #[cfg(test)]
  263. mod tests {
  264. use super::*;
  265. use crate::crypto::{coin::Coin, OwnCoin};
  266. use crate::util::join_config_path;
  267. use ff::PrimeField;
  268. #[test]
  269. fn test_key_exist() -> Result<()> {
  270. let path = join_config_path(&PathBuf::from("test_wallet.db"))?;
  271. let password: String = "darkfi".into();
  272. let contents = include_str!("../../sql/schema.sql");
  273. let conn = Connection::open(&path)?;
  274. conn.pragma_update(None, "key", &password)?;
  275. conn.execute_batch(&contents)?;
  276. let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > :id")?;
  277. let boolean = stmt.exists(&[(":id", &"0")])?;
  278. println!("Attempt 1. Result is the following: {}", boolean);
  279. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  280. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  281. let key_public = serial::serialize(&public);
  282. let key_private = serial::serialize(&secret);
  283. conn.execute(
  284. "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  285. params![key_public, key_private],
  286. )?;
  287. let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > :id")?;
  288. let boolean = stmt.exists(&[(":id", &"0")])?;
  289. println!("Wrote keys, result is the following: {}", boolean);
  290. conn.execute(
  291. "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  292. params![key_public, key_private],
  293. )?;
  294. let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > :id")?;
  295. let boolean = stmt.exists(&[(":id", &"0")])?;
  296. println!("Third time, result is the following: {}", boolean);
  297. std::fs::remove_file(path)?;
  298. Ok(())
  299. }
  300. pub fn init_db(path: &PathBuf, password: String) -> Result<()> {
  301. if !password.trim().is_empty() {
  302. let contents = include_str!("../../sql/schema.sql");
  303. let conn = Connection::open(&path)?;
  304. debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", path);
  305. conn.pragma_update(None, "key", &password)?;
  306. conn.execute_batch(&contents)?;
  307. } else {
  308. debug!(
  309. target: "WALLETDB", "Password is empty. You must set a password to use the wallet."
  310. );
  311. return Err(Error::from(ClientFailed::EmptyPassword));
  312. }
  313. Ok(())
  314. }
  315. #[test]
  316. pub fn test_save_and_load_keypair() -> Result<()> {
  317. let walletdb_path = join_config_path(&PathBuf::from("test4_wallet.db"))?;
  318. let password: String = "darkfi".into();
  319. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  320. init_db(&walletdb_path, password)?;
  321. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  322. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  323. let key_public = serial::serialize(&public);
  324. let key_private = serial::serialize(&secret);
  325. wallet.put_keypair(key_public, key_private)?;
  326. let keypair = wallet.get_keypairs()?[0].clone();
  327. assert_eq!(public, keypair.public);
  328. assert_eq!(secret, keypair.private);
  329. std::fs::remove_file(walletdb_path)?;
  330. Ok(())
  331. }
  332. #[test]
  333. pub fn test_put_and_get_own_coins() -> Result<()> {
  334. let walletdb_path = join_config_path(&PathBuf::from("test2_wallet.db"))?;
  335. let password: String = "darkfi".into();
  336. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  337. init_db(&walletdb_path, password)?;
  338. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  339. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  340. let key_public = serial::serialize(&public);
  341. let key_private = serial::serialize(&secret);
  342. wallet.put_keypair(key_public, key_private)?;
  343. let note = Note {
  344. serial: jubjub::Fr::random(&mut OsRng),
  345. value: 110,
  346. asset_id: jubjub::Fr::random(&mut OsRng),
  347. coin_blind: jubjub::Fr::random(&mut OsRng),
  348. valcom_blind: jubjub::Fr::random(&mut OsRng),
  349. };
  350. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  351. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  352. tree.append(MerkleNode::from_coin(&coin))?;
  353. let witness = IncrementalWitness::from_tree(&tree);
  354. let own_coin = OwnCoin {
  355. coin,
  356. note: note.clone(),
  357. secret,
  358. witness: witness.clone(),
  359. };
  360. wallet.put_own_coins(own_coin.clone())?;
  361. let own_coin = wallet.get_own_coins()?[0].clone();
  362. assert_eq!(&own_coin.note.valcom_blind, &note.valcom_blind);
  363. assert_eq!(&own_coin.note.coin_blind, &note.coin_blind);
  364. assert_eq!(own_coin.secret, secret);
  365. assert_eq!(own_coin.witness.root(), witness.root());
  366. assert_eq!(own_coin.witness.path(), witness.path());
  367. std::fs::remove_file(walletdb_path)?;
  368. Ok(())
  369. }
  370. #[test]
  371. pub fn test_get_witnesses_and_update_them() -> Result<()> {
  372. let walletdb_path = join_config_path(&PathBuf::from("test3_wallet.db"))?;
  373. let password: String = "darkfi".into();
  374. let wallet = WalletDb::new(&walletdb_path, password.clone())?;
  375. init_db(&walletdb_path, password)?;
  376. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  377. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  378. let key_public = serial::serialize(&public);
  379. let key_private = serial::serialize(&secret);
  380. wallet.put_keypair(key_public, key_private)?;
  381. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  382. let note = Note {
  383. serial: jubjub::Fr::random(&mut OsRng),
  384. value: 110,
  385. asset_id: jubjub::Fr::random(&mut OsRng),
  386. coin_blind: jubjub::Fr::random(&mut OsRng),
  387. valcom_blind: jubjub::Fr::random(&mut OsRng),
  388. };
  389. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  390. let node = MerkleNode::from_coin(&coin);
  391. tree.append(node)?;
  392. tree.append(node)?;
  393. tree.append(node)?;
  394. tree.append(node)?;
  395. let witness = IncrementalWitness::from_tree(&tree);
  396. let own_coin = OwnCoin {
  397. coin,
  398. note,
  399. secret,
  400. witness,
  401. };
  402. wallet.put_own_coins(own_coin.clone())?;
  403. wallet.put_own_coins(own_coin.clone())?;
  404. wallet.put_own_coins(own_coin.clone())?;
  405. wallet.put_own_coins(own_coin.clone())?;
  406. let coin2 = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  407. let node2 = MerkleNode::from_coin(&coin2);
  408. tree.append(node2)?;
  409. for (coin_id, witness) in wallet.get_witnesses()?.iter_mut() {
  410. witness.append(node2).expect("Append to witness");
  411. wallet.update_witness(coin_id.clone(), witness.clone())?;
  412. }
  413. for (_, witness) in wallet.get_witnesses()?.iter() {
  414. assert_eq!(tree.root(), witness.root());
  415. }
  416. std::fs::remove_file(walletdb_path)?;
  417. Ok(())
  418. }
  419. }