walletdb.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. use crate::client::ClientFailed;
  2. use crate::crypto::{
  3. coin::Coin, merkle::IncrementalWitness, merkle_node::MerkleNode, note::Note, OwnCoins,
  4. };
  5. use crate::serial;
  6. use crate::serial::{deserialize, serialize, Decodable, Encodable};
  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::PathBuf;
  14. pub type WalletPtr = Arc<WalletDb>;
  15. pub struct WalletDb {
  16. pub path: PathBuf,
  17. pub witnesses: Mutex<Vec<IncrementalWitness<MerkleNode>>>,
  18. pub password: String,
  19. }
  20. impl WalletDb {
  21. pub fn new(path: &std::path::PathBuf, password: String) -> Result<Self> {
  22. debug!(target: "WALLETDB", "new() Constructor called");
  23. let witnesses = Mutex::new(Vec::new());
  24. Ok(Self {
  25. path: path.to_owned(),
  26. witnesses,
  27. password,
  28. })
  29. }
  30. pub fn init_db(&self) -> Result<()> {
  31. if !self.password.trim().is_empty() {
  32. let contents = include_str!("../../res/schema.sql");
  33. let conn = Connection::open(&self.path)?;
  34. debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", self.path);
  35. conn.pragma_update(None, "key", &self.password)?;
  36. conn.execute_batch(&contents)?;
  37. } else {
  38. debug!(target: "WALLETDB", "Password is empty. You must set a password to use the wallet.");
  39. return Err(Error::from(ClientFailed::EmptyPassword));
  40. }
  41. Ok(())
  42. }
  43. pub fn get_own_coins(&self) -> Result<OwnCoins> {
  44. // open connection
  45. let conn = Connection::open(&self.path)?;
  46. // unlock database
  47. conn.pragma_update(None, "key", &self.password)?;
  48. let mut coins = conn.prepare("SELECT * FROM coins")?;
  49. let rows = coins.query_map([], |row| {
  50. let coin = self.get_value_deserialized(row.get(1)?).unwrap();
  51. // note
  52. let serial = self.get_value_deserialized(row.get(2)?).unwrap();
  53. let coin_blind = self.get_value_deserialized(row.get(3)?).unwrap();
  54. let valcom_blind = self.get_value_deserialized(row.get(4)?).unwrap();
  55. let value: u64 = row.get(5)?;
  56. let asset_id: u64 = row.get(6)?;
  57. let note = Note {
  58. serial,
  59. value,
  60. asset_id,
  61. coin_blind,
  62. valcom_blind,
  63. };
  64. let witness = self.get_value_deserialized(row.get(7)?).unwrap();
  65. let key_id: u64 = row.get(8)?;
  66. // return key_private from key_id
  67. let mut get_private_key =
  68. conn.prepare("SELECT key_private FROM keys WHERE key_id = :key_id")?;
  69. let rows = get_private_key.query_map(&[(":key_id", &key_id)], |row| row.get(0))?;
  70. let mut secret = Vec::new();
  71. for id in rows {
  72. secret.push(id?)
  73. }
  74. let secret: jubjub::Fr = self
  75. .get_value_deserialized(secret.pop().expect("Load public_key from walletdb"))
  76. .unwrap();
  77. Ok((coin, note, secret, witness))
  78. })?;
  79. let mut own_coins = Vec::new();
  80. for id in rows {
  81. own_coins.push(id?)
  82. }
  83. Ok(own_coins)
  84. }
  85. pub fn put_own_coins(
  86. &self,
  87. coin: Coin,
  88. note: Note,
  89. witness: IncrementalWitness<MerkleNode>,
  90. secret: jubjub::Fr,
  91. ) -> Result<()> {
  92. // prepare the values
  93. let coin = self.get_value_serialized(&coin.repr)?;
  94. let serial = self.get_value_serialized(&note.serial)?;
  95. let coin_blind = self.get_value_serialized(&note.coin_blind)?;
  96. let valcom_blind = self.get_value_serialized(&note.valcom_blind)?;
  97. let value: u64 = note.value;
  98. let asset_id: u64 = note.asset_id;
  99. let witness = self.get_value_serialized(&witness)?;
  100. let secret = self.get_value_serialized(&secret)?;
  101. // open connection
  102. let conn = Connection::open(&self.path)?;
  103. // unlock database
  104. conn.pragma_update(None, "key", &self.password)?;
  105. // return key_id from key_private
  106. let mut get_id =
  107. conn.prepare("SELECT key_id FROM keys WHERE key_private = :key_private")?;
  108. let rows = get_id.query_map::<u64, _, _>(&[(":key_private", &secret)], |row| row.get(0))?;
  109. let mut key_id = Vec::new();
  110. for id in rows {
  111. key_id.push(id?)
  112. }
  113. conn.execute(
  114. "INSERT INTO coins(coin, serial, value, asset_id, coin_blind, valcom_blind, witness, key_id)
  115. VALUES (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :key_id)",
  116. named_params! {
  117. ":coin": coin,
  118. ":serial": serial,
  119. ":value": value,
  120. ":asset_id": asset_id,
  121. ":coin_blind": coin_blind,
  122. ":valcom_blind": valcom_blind,
  123. ":witness": witness,
  124. ":key_id": key_id.pop().expect("Get key_id"),
  125. },
  126. )?;
  127. Ok(())
  128. }
  129. pub fn key_gen(&self) -> (Vec<u8>, Vec<u8>) {
  130. debug!(target: "WALLETDB", "Attempting to generate keys...");
  131. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  132. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  133. let pubkey = serial::serialize(&public);
  134. let privkey = serial::serialize(&secret);
  135. (pubkey, privkey)
  136. }
  137. pub fn put_keypair(&self, key_public: Vec<u8>, key_private: Vec<u8>) -> Result<()> {
  138. let conn = Connection::open(&self.path)?;
  139. conn.pragma_update(None, "key", &self.password)?;
  140. conn.execute(
  141. "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  142. params![key_public, key_private],
  143. )?;
  144. Ok(())
  145. }
  146. pub fn put_cashier_pub(&self, key_public: Vec<u8>) -> Result<()> {
  147. debug!(target: "WALLETDB", "Save cashier keys...");
  148. let conn = Connection::open(&self.path)?;
  149. conn.pragma_update(None, "key", &self.password)?;
  150. conn.execute(
  151. "INSERT INTO cashier(key_public) VALUES (?1)",
  152. params![key_public],
  153. )?;
  154. Ok(())
  155. }
  156. pub fn get_public(&self) -> Result<jubjub::SubgroupPoint> {
  157. debug!(target: "WALLETDB", "Returning keys...");
  158. let conn = Connection::open(&self.path)?;
  159. conn.pragma_update(None, "key", &self.password)?;
  160. let mut stmt = conn.prepare("SELECT key_public FROM keys")?;
  161. // this just gets the first key. maybe we should randomize this
  162. let key_iter = stmt.query_map([], |row| row.get(0))?;
  163. let mut pub_keys = Vec::new();
  164. for key in key_iter {
  165. pub_keys.push(key?);
  166. }
  167. let public: jubjub::SubgroupPoint =
  168. self.get_value_deserialized(pub_keys.pop().expect("Load public_key from walletdb"))?;
  169. Ok(public)
  170. }
  171. pub fn get_cashier_public(&self) -> Result<jubjub::SubgroupPoint> {
  172. debug!(target: "WALLETDB", "Returning keys...");
  173. let conn = Connection::open(&self.path)?;
  174. conn.pragma_update(None, "key", &self.password)?;
  175. let mut stmt = conn.prepare("SELECT key_public FROM cashier")?;
  176. let key_iter = stmt.query_map([], |row| row.get(0))?;
  177. let mut pub_keys = Vec::new();
  178. for key in key_iter {
  179. pub_keys.push(key?);
  180. }
  181. let public: jubjub::SubgroupPoint = self.get_value_deserialized(
  182. pub_keys
  183. .pop()
  184. .expect("Load cashier public_key from walletdb"),
  185. )?;
  186. Ok(public)
  187. }
  188. pub fn get_private(&self) -> Result<jubjub::Fr> {
  189. debug!(target: "WALLETDB", "Returning keys...");
  190. let conn = Connection::open(&self.path)?;
  191. conn.pragma_update(None, "key", &self.password)?;
  192. let mut stmt = conn.prepare("SELECT key_private FROM keys")?;
  193. let key_iter = stmt.query_map([], |row| row.get(0))?;
  194. let mut keys = Vec::new();
  195. for key in key_iter {
  196. keys.push(key?);
  197. }
  198. let private: jubjub::Fr =
  199. self.get_value_deserialized(keys.pop().expect("Load private key from walletdb"))?;
  200. Ok(private)
  201. }
  202. pub fn test_wallet(&self) -> Result<()> {
  203. let conn = Connection::open(&self.path)?;
  204. conn.pragma_update(None, "key", &self.password)?;
  205. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  206. let _rows = stmt.query([])?;
  207. Ok(())
  208. }
  209. fn get_tables_name(&self) -> Result<Vec<String>> {
  210. let conn = Connection::open(&self.path)?;
  211. conn.pragma_update(None, "key", &self.password)?;
  212. let mut stmt = conn.prepare("SELECT name FROM sqlite_master WHERE type='table'")?;
  213. let table_iter = stmt.query_map::<String, _, _>([], |row| row.get(0))?;
  214. let mut tables = Vec::new();
  215. for table in table_iter {
  216. tables.push(table?);
  217. }
  218. Ok(tables)
  219. }
  220. pub fn destory(&self) -> Result<()> {
  221. let conn = Connection::open(&self.path)?;
  222. conn.pragma_update(None, "key", &self.password)?;
  223. for table in self.get_tables_name()?.iter() {
  224. let drop_stmt = format!("DROP TABLE IF EXISTS {}", table);
  225. let drop_stmt = drop_stmt.as_str();
  226. conn.execute(drop_stmt, [])?;
  227. }
  228. Ok(())
  229. }
  230. pub fn get_value_serialized<T: Encodable>(&self, data: &T) -> Result<Vec<u8>> {
  231. let v = serialize(data);
  232. Ok(v)
  233. }
  234. pub fn get_value_deserialized<D: Decodable>(&self, key: Vec<u8>) -> Result<D> {
  235. let v: D = deserialize(&key)?;
  236. Ok(v)
  237. }
  238. }
  239. #[cfg(test)]
  240. mod tests {
  241. use super::*;
  242. use crate::util::join_config_path;
  243. use ff::PrimeField;
  244. #[test]
  245. pub fn test_save_and_load_keypair() -> Result<()> {
  246. let walletdb_path = join_config_path(&PathBuf::from("test_wallet.db"))?;
  247. let wallet = WalletDb::new(&walletdb_path, "darkfi".into())?;
  248. wallet.init_db()?;
  249. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  250. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  251. let key_public = serial::serialize(&public);
  252. let key_private = serial::serialize(&secret);
  253. wallet.put_keypair(key_public, key_private)?;
  254. let public2 = wallet.get_public()?;
  255. let secret2 = wallet.get_private()?;
  256. assert_eq!(public, public2);
  257. assert_eq!(secret, secret2);
  258. wallet.destory()?;
  259. Ok(())
  260. }
  261. #[test]
  262. pub fn test_put_and_get_own_coins() -> Result<()> {
  263. let walletdb_path = join_config_path(&PathBuf::from("test2_wallet.db"))?;
  264. let wallet = WalletDb::new(&walletdb_path, "darkfi".into())?;
  265. wallet.init_db()?;
  266. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  267. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  268. let key_public = serial::serialize(&public);
  269. let key_private = serial::serialize(&secret);
  270. wallet.put_keypair(key_public, key_private)?;
  271. let note = Note {
  272. serial: jubjub::Fr::random(&mut OsRng),
  273. value: 110,
  274. asset_id: 1,
  275. coin_blind: jubjub::Fr::random(&mut OsRng),
  276. valcom_blind: jubjub::Fr::random(&mut OsRng),
  277. };
  278. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  279. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  280. tree.append(MerkleNode::from_coin(&coin))?;
  281. let witness = IncrementalWitness::from_tree(&tree);
  282. wallet.put_own_coins(coin.clone(), note.clone(), witness.clone(), secret)?;
  283. let own_coin = wallet.get_own_coins()?[0].clone();
  284. assert_eq!(&own_coin.1.valcom_blind, &note.valcom_blind);
  285. assert_eq!(&own_coin.1.coin_blind, &note.coin_blind);
  286. assert_eq!(own_coin.2, secret);
  287. assert_eq!(own_coin.3.root(), witness.root());
  288. assert_eq!(own_coin.3.path(), witness.path());
  289. wallet.destory()?;
  290. Ok(())
  291. }
  292. }