walletdb.rs 16 KB

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