walletdb.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. use std::{fs::create_dir_all, path::Path, str::FromStr};
  2. use async_std::sync::Arc;
  3. use log::{trace, error, info};
  4. use rand::rngs::OsRng;
  5. use sqlx::{
  6. sqlite::{SqliteConnectOptions, SqliteJournalMode},
  7. Row, SqlitePool,
  8. };
  9. use crate::{
  10. client::ClientFailed,
  11. crypto::{
  12. coin::Coin,
  13. keypair::{Keypair, PublicKey, SecretKey},
  14. note::Note,
  15. nullifier::Nullifier,
  16. OwnCoin, OwnCoins,
  17. },
  18. serial::serialize,
  19. types::DrkTokenId,
  20. wallet::wallet_api::WalletApi,
  21. Error, Result,
  22. };
  23. pub type WalletPtr = Arc<WalletDb>;
  24. #[derive(Clone, Debug)]
  25. pub struct Balance {
  26. pub token_id: DrkTokenId,
  27. pub value: u64,
  28. pub nullifier: Nullifier,
  29. }
  30. #[derive(Clone, Debug)]
  31. pub struct Balances {
  32. pub list: Vec<Balance>,
  33. }
  34. pub struct WalletDb {
  35. pub conn: SqlitePool,
  36. }
  37. impl WalletApi for WalletDb {}
  38. impl WalletDb {
  39. pub async fn new(path: &str, password: String) -> Result<WalletPtr> {
  40. if password.trim().is_empty() {
  41. error!("Password is empty. You must set a password to use the wallet.");
  42. return Err(Error::from(ClientFailed::EmptyPassword))
  43. }
  44. if path != "sqlite::memory:" {
  45. let p = Path::new(path.strip_prefix("sqlite://").unwrap());
  46. if let Some(dirname) = p.parent() {
  47. info!("Creating path to database: {}", dirname.display());
  48. create_dir_all(&dirname)?;
  49. }
  50. }
  51. let connect_opts = SqliteConnectOptions::from_str(path)?
  52. .pragma("key", password)
  53. .create_if_missing(true)
  54. .journal_mode(SqliteJournalMode::Off);
  55. let conn = SqlitePool::connect_with(connect_opts).await?;
  56. info!("Opened connection at path {}", path);
  57. Ok(Arc::new(WalletDb { conn }))
  58. }
  59. pub async fn init_db(&self) -> Result<()> {
  60. info!("Initializing wallet database");
  61. let keys = include_str!("../../sql/keys.sql");
  62. let coins = include_str!("../../sql/coins.sql");
  63. let mut conn = self.conn.acquire().await?;
  64. trace!("Initializing keys table");
  65. sqlx::query(keys).execute(&mut conn).await?;
  66. trace!("Initializing coins table");
  67. sqlx::query(coins).execute(&mut conn).await?;
  68. Ok(())
  69. }
  70. pub async fn key_gen(&self) -> Result<()> {
  71. trace!("Attempting to generate keypairs");
  72. let mut conn = self.conn.acquire().await?;
  73. // TODO: Think about multiple keys
  74. match sqlx::query("SELECT * FROM keys WHERE key_id > ?").fetch_one(&mut conn).await {
  75. Ok(_) => {
  76. error!("Keys already exist");
  77. Err(Error::from(ClientFailed::KeyExists))
  78. }
  79. Err(_) => {
  80. let keypair = Keypair::random(&mut OsRng);
  81. self.put_keypair(&keypair.public, &keypair.secret).await?;
  82. Ok(())
  83. }
  84. }
  85. }
  86. pub async fn put_keypair(&self, public: &PublicKey, secret: &SecretKey) -> Result<()> {
  87. trace!("Writing keypair into the wallet database");
  88. let pubkey = serialize(&public.0);
  89. let secret = serialize(&secret.0);
  90. let mut conn = self.conn.acquire().await?;
  91. sqlx::query("INSERT INTO keys(public, secret) VALUES (?1, ?2)")
  92. .bind(pubkey)
  93. .bind(secret)
  94. .execute(&mut conn)
  95. .await?;
  96. Ok(())
  97. }
  98. pub async fn get_keypairs(&self) -> Result<Vec<Keypair>> {
  99. trace!("Returning keypairs");
  100. let mut conn = self.conn.acquire().await?;
  101. // TODO: Think about multiple keys
  102. let row = sqlx::query("SELECT * FROM keys").fetch_one(&mut conn).await?;
  103. let public: PublicKey = self.get_value_deserialized(row.get("public"))?;
  104. let secret: SecretKey = self.get_value_deserialized(row.get("secret"))?;
  105. Ok(vec![Keypair { public, secret }])
  106. }
  107. pub async fn get_own_coins(&self) -> Result<OwnCoins> {
  108. trace!("Finding own coins");
  109. let is_spent = 0;
  110. let mut conn = self.conn.acquire().await?;
  111. let rows = sqlx::query("SELECT * FROM coins WHERE is_spent = ?1;")
  112. .bind(is_spent)
  113. .fetch_all(&mut conn)
  114. .await?;
  115. let mut own_coins = vec![];
  116. for row in rows {
  117. let coin = self.get_value_deserialized(row.get("coin"))?;
  118. // Note
  119. let serial = self.get_value_deserialized(row.get("serial"))?;
  120. let coin_blind = self.get_value_deserialized(row.get("coin_blind"))?;
  121. let value_blind = self.get_value_deserialized(row.get("valcom_blind"))?;
  122. // TODO: FIXME:
  123. let value_bytes: Vec<u8> = row.get("value");
  124. let value = u64::from_le_bytes(value_bytes.try_into().unwrap());
  125. let token_id = self.get_value_deserialized(row.get("token_id"))?;
  126. let note = Note { serial, value, token_id, coin_blind, value_blind };
  127. // TODO:
  128. // let witness = deserialized(row.6)
  129. let secret = self.get_value_deserialized(row.get("secret"))?;
  130. let nullifier = self.get_value_deserialized(row.get("nullifier"))?;
  131. let oc = OwnCoin {
  132. coin,
  133. note,
  134. secret,
  135. // witness,
  136. nullifier,
  137. };
  138. own_coins.push(oc);
  139. }
  140. Ok(own_coins)
  141. }
  142. pub async fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
  143. trace!("Putting own coin into wallet database");
  144. let coin = self.get_value_serialized(&own_coin.coin.to_bytes())?;
  145. let serial = self.get_value_serialized(&own_coin.note.serial)?;
  146. let coin_blind = self.get_value_serialized(&own_coin.note.coin_blind)?;
  147. let value_blind = self.get_value_serialized(&own_coin.note.value_blind)?;
  148. let value = own_coin.note.value.to_le_bytes();
  149. let token_id = self.get_value_serialized(&own_coin.note.token_id)?;
  150. // TODO: let witness
  151. let secret = self.get_value_serialized(&own_coin.secret)?;
  152. let is_spent = 0;
  153. let nullifier = self.get_value_serialized(&own_coin.nullifier)?;
  154. let mut conn = self.conn.acquire().await?;
  155. sqlx::query(
  156. "INSERT OR REPLACE INTO coins
  157. (coin, serial, value, token_id, coin_blind,
  158. valcom_blind, secret, is_spent, nullifier)
  159. VALUES
  160. (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9);",
  161. )
  162. .bind(coin)
  163. .bind(serial)
  164. .bind(value.to_vec())
  165. .bind(token_id)
  166. .bind(coin_blind)
  167. .bind(value_blind)
  168. .bind(secret)
  169. .bind(is_spent)
  170. .bind(nullifier)
  171. .execute(&mut conn)
  172. .await?;
  173. Ok(())
  174. }
  175. pub async fn remove_own_coins(&self) -> Result<()> {
  176. trace!("Removing own coins from wallet database");
  177. let mut conn = self.conn.acquire().await?;
  178. sqlx::query("DROP TABLE coins;").execute(&mut conn).await?;
  179. Ok(())
  180. }
  181. pub async fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
  182. trace!("Confirm spend coin");
  183. let is_spent = 1;
  184. let coin = self.get_value_serialized(coin)?;
  185. let mut conn = self.conn.acquire().await?;
  186. sqlx::query("UPDATE coins SET is_spent = ?1 WHERE coin = ?2;")
  187. .bind(is_spent)
  188. .bind(coin)
  189. .execute(&mut conn)
  190. .await?;
  191. Ok(())
  192. }
  193. pub async fn get_balances(&self) -> Result<Balances> {
  194. trace!("Getting tokens and balances");
  195. let is_spent = 0;
  196. let mut conn = self.conn.acquire().await?;
  197. let rows = sqlx::query("SELECT value, token_id, nullifier FROM coins WHERE is_spent = ?1;")
  198. .bind(is_spent)
  199. .fetch_all(&mut conn)
  200. .await?;
  201. let mut list = vec![];
  202. for row in rows {
  203. // TODO: FIXME:
  204. let value_bytes: Vec<u8> = row.get("value");
  205. let value = u64::from_le_bytes(value_bytes.try_into().unwrap());
  206. let token_id = self.get_value_deserialized(row.get("token_id"))?;
  207. let nullifier = self.get_value_deserialized(row.get("nullifier"))?;
  208. list.push(Balance { token_id, value, nullifier });
  209. }
  210. if list.is_empty() {
  211. trace!("Did not find any unspent coins");
  212. }
  213. Ok(Balances { list })
  214. }
  215. pub async fn get_token_id(&self) -> Result<Vec<DrkTokenId>> {
  216. trace!("Getting token ID");
  217. let is_spent = 0;
  218. let mut conn = self.conn.acquire().await?;
  219. let rows = sqlx::query("SELECT token_id FROM coins WHERE is_spent = ?1;")
  220. .bind(is_spent)
  221. .fetch_all(&mut conn)
  222. .await?;
  223. let mut token_ids = vec![];
  224. for row in rows {
  225. let token_id = self.get_value_deserialized(row.get("token_id"))?;
  226. token_ids.push(token_id);
  227. }
  228. Ok(token_ids)
  229. }
  230. pub async fn token_id_exists(&self, token_id: DrkTokenId) -> Result<bool> {
  231. trace!("Checking if token ID exists");
  232. let is_spent = 0;
  233. let id = self.get_value_serialized(&token_id)?;
  234. let mut conn = self.conn.acquire().await?;
  235. let id_check = sqlx::query("SELECT * FROM coins WHERE token_id = ?1 AND is_spent = ?2;")
  236. .bind(id)
  237. .bind(is_spent)
  238. .fetch_optional(&mut conn)
  239. .await?;
  240. Ok(id_check.is_some())
  241. }
  242. pub async fn test_wallet(&self) -> Result<()> {
  243. trace!("Testing wallet");
  244. let mut conn = self.conn.acquire().await?;
  245. let _row = sqlx::query("SELECT * FROM keys").fetch_one(&mut conn).await?;
  246. Ok(())
  247. }
  248. }
  249. #[cfg(test)]
  250. mod tests {
  251. use super::*;
  252. use crate::types::{DrkCoinBlind, DrkSerial, DrkValueBlind};
  253. use pasta_curves::{arithmetic::Field, pallas};
  254. use rand::rngs::OsRng;
  255. const WPASS: &str = "darkfi";
  256. fn dummy_coin(s: &SecretKey, v: u64, t: &DrkTokenId) -> OwnCoin {
  257. let serial = DrkSerial::random(&mut OsRng);
  258. let note = Note {
  259. serial,
  260. value: v,
  261. token_id: *t,
  262. coin_blind: DrkCoinBlind::random(&mut OsRng),
  263. value_blind: DrkValueBlind::random(&mut OsRng),
  264. };
  265. let coin = Coin(pallas::Base::random(&mut OsRng));
  266. let nullifier = Nullifier::new(*s, serial);
  267. OwnCoin { coin, note, secret: *s, nullifier }
  268. }
  269. #[async_std::test]
  270. async fn test_walletdb() -> Result<()> {
  271. let wallet = WalletDb::new("sqlite::memory:", WPASS.to_string()).await?;
  272. let keypair = Keypair::random(&mut OsRng);
  273. // init_db()
  274. wallet.init_db().await?;
  275. // put_keypair()
  276. wallet.put_keypair(&keypair.public, &keypair.secret).await?;
  277. let token_id = DrkTokenId::random(&mut OsRng);
  278. let c0 = dummy_coin(&keypair.secret, 69, &token_id);
  279. let c1 = dummy_coin(&keypair.secret, 420, &token_id);
  280. let c2 = dummy_coin(&keypair.secret, 42, &token_id);
  281. let c3 = dummy_coin(&keypair.secret, 11, &token_id);
  282. // put_own_coins()
  283. wallet.put_own_coins(c0).await?;
  284. wallet.put_own_coins(c1).await?;
  285. wallet.put_own_coins(c2).await?;
  286. wallet.put_own_coins(c3).await?;
  287. // get_token_id()
  288. let id = wallet.get_token_id().await?;
  289. assert_eq!(id.len(), 4);
  290. for i in id {
  291. assert_eq!(i, token_id);
  292. assert!(wallet.token_id_exists(i).await?);
  293. }
  294. // get_balances()
  295. let balances = wallet.get_balances().await?;
  296. assert_eq!(balances.list.len(), 4);
  297. assert_eq!(balances.list[1].value, 420);
  298. assert_eq!(balances.list[2].value, 42);
  299. assert_eq!(balances.list[3].token_id, token_id);
  300. // get_keypairs()
  301. let keypair_r = wallet.get_keypairs().await?[0];
  302. assert_eq!(keypair, keypair_r);
  303. // get_own_coins()
  304. let own_coins = wallet.get_own_coins().await?;
  305. assert_eq!(own_coins.len(), 4);
  306. assert_eq!(own_coins[0], c0);
  307. assert_eq!(own_coins[1], c1);
  308. assert_eq!(own_coins[2], c2);
  309. assert_eq!(own_coins[3], c3);
  310. Ok(())
  311. }
  312. }