money.rs 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{
  19. collections::{BTreeMap, HashMap},
  20. str::FromStr,
  21. };
  22. use lazy_static::lazy_static;
  23. use rand::rngs::OsRng;
  24. use darkfi::{
  25. tx::Transaction,
  26. util::encoding::base64,
  27. zk::{halo2::Field, proof::ProvingKey, vm::ZkCircuit, vm_heap::empty_witnesses, Proof},
  28. zkas::ZkBinary,
  29. Error, Result,
  30. };
  31. use darkfi_money_contract::{
  32. client::{
  33. compute_remainder_blind,
  34. fee_v1::{create_fee_proof, FeeCallInput, FeeCallOutput, FEE_CALL_GAS},
  35. MoneyNote, OwnCoin,
  36. },
  37. model::{
  38. Coin, Input, MoneyAuthTokenFreezeParamsV1, MoneyBurnParamsV1, MoneyFeeParamsV1,
  39. MoneyGenesisMintParamsV1, MoneyPoWRewardParamsV1, MoneyTokenMintParamsV1,
  40. MoneyTransferParamsV1, Nullifier, Output, TokenId, DARK_TOKEN_ID,
  41. },
  42. MoneyFunction, MONEY_CONTRACT_ZKAS_FEE_NS_V1,
  43. };
  44. use darkfi_sdk::{
  45. blockchain::compute_fee,
  46. bridgetree::Position,
  47. crypto::{
  48. keypair::{Address, Keypair, PublicKey, SecretKey, StandardAddress},
  49. note::AeadEncryptedNote,
  50. pasta_prelude::PrimeField,
  51. BaseBlind, FuncId, MerkleNode, MerkleTree, ScalarBlind, MONEY_CONTRACT_ID,
  52. },
  53. dark_tree::DarkLeaf,
  54. pasta::pallas,
  55. ContractCall,
  56. };
  57. use darkfi_serial::{deserialize, deserialize_async, serialize, serialize_async, AsyncEncodable};
  58. use crate::{
  59. cache::CacheSmt,
  60. cli_util::kaching,
  61. convert_named_params,
  62. error::{WalletDbError, WalletDbResult},
  63. params,
  64. rpc::ScanCache,
  65. walletdb::Value,
  66. Drk,
  67. };
  68. // Money Merkle tree Sled key
  69. pub const SLED_MERKLE_TREES_MONEY: &[u8] = b"_money_tree";
  70. // Wallet SQL table constant names. These have to represent the `money.sql`
  71. // SQL schema. Table names are prefixed with the contract ID to avoid collisions.
  72. lazy_static! {
  73. pub static ref MONEY_KEYS_TABLE: String =
  74. format!("{}_money_keys", MONEY_CONTRACT_ID.to_string());
  75. pub static ref MONEY_COINS_TABLE: String =
  76. format!("{}_money_coins", MONEY_CONTRACT_ID.to_string());
  77. pub static ref MONEY_TOKENS_TABLE: String =
  78. format!("{}_money_tokens", MONEY_CONTRACT_ID.to_string());
  79. pub static ref MONEY_ALIASES_TABLE: String =
  80. format!("{}_money_aliases", MONEY_CONTRACT_ID.to_string());
  81. }
  82. // MONEY_KEYS_TABLE
  83. pub const MONEY_KEYS_COL_KEY_ID: &str = "key_id";
  84. pub const MONEY_KEYS_COL_IS_DEFAULT: &str = "is_default";
  85. pub const MONEY_KEYS_COL_PUBLIC: &str = "public";
  86. pub const MONEY_KEYS_COL_SECRET: &str = "secret";
  87. // MONEY_COINS_TABLE
  88. pub const MONEY_COINS_COL_COIN: &str = "coin";
  89. pub const MONEY_COINS_COL_VALUE: &str = "value";
  90. pub const MONEY_COINS_COL_TOKEN_ID: &str = "token_id";
  91. pub const MONEY_COINS_COL_SPEND_HOOK: &str = "spend_hook";
  92. pub const MONEY_COINS_COL_USER_DATA: &str = "user_data";
  93. pub const MONEY_COINS_COL_COIN_BLIND: &str = "coin_blind";
  94. pub const MONEY_COINS_COL_VALUE_BLIND: &str = "value_blind";
  95. pub const MONEY_COINS_COL_TOKEN_BLIND: &str = "token_blind";
  96. pub const MONEY_COINS_COL_SECRET: &str = "secret";
  97. pub const MONEY_COINS_COL_LEAF_POSITION: &str = "leaf_position";
  98. pub const MONEY_COINS_COL_MEMO: &str = "memo";
  99. pub const MONEY_COINS_COL_CREATION_HEIGHT: &str = "creation_height";
  100. pub const MONEY_COINS_COL_IS_SPENT: &str = "is_spent";
  101. pub const MONEY_COINS_COL_SPENT_HEIGHT: &str = "spent_height";
  102. pub const MONEY_COINS_COL_SPENT_TX_HASH: &str = "spent_tx_hash";
  103. // MONEY_TOKENS_TABLE
  104. pub const MONEY_TOKENS_COL_TOKEN_ID: &str = "token_id";
  105. pub const MONEY_TOKENS_COL_MINT_AUTHORITY: &str = "mint_authority";
  106. pub const MONEY_TOKENS_COL_TOKEN_BLIND: &str = "token_blind";
  107. pub const MONEY_TOKENS_COL_IS_FROZEN: &str = "is_frozen";
  108. pub const MONEY_TOKENS_COL_FREEZE_HEIGHT: &str = "freeze_height";
  109. // MONEY_ALIASES_TABLE
  110. pub const MONEY_ALIASES_COL_ALIAS: &str = "alias";
  111. pub const MONEY_ALIASES_COL_TOKEN_ID: &str = "token_id";
  112. pub const BALANCE_BASE10_DECIMALS: usize = 8;
  113. impl Drk {
  114. /// Initialize wallet with tables for the Money contract.
  115. pub async fn initialize_money(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
  116. // Initialize Money wallet schema
  117. let wallet_schema = include_str!("../money.sql");
  118. self.wallet.exec_batch_sql(wallet_schema).await?;
  119. // Insert DRK alias
  120. self.add_alias("DRK".to_string(), *DARK_TOKEN_ID, output).await?;
  121. Ok(())
  122. }
  123. /// Generate a new keypair and place it into the wallet.
  124. pub async fn money_keygen(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
  125. output.push(String::from("Generating a new keypair"));
  126. // TODO: We might want to have hierarchical deterministic key derivation.
  127. let keypair = Keypair::random(&mut OsRng);
  128. let is_default = 0;
  129. let query = format!(
  130. "INSERT INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
  131. *MONEY_KEYS_TABLE,
  132. MONEY_KEYS_COL_IS_DEFAULT,
  133. MONEY_KEYS_COL_PUBLIC,
  134. MONEY_KEYS_COL_SECRET
  135. );
  136. self.wallet
  137. .exec_sql(
  138. &query,
  139. params![
  140. is_default,
  141. serialize_async(&keypair.public).await,
  142. serialize_async(&keypair.secret).await
  143. ],
  144. )
  145. .await?;
  146. output.push(String::from("New address:"));
  147. let address: Address = StandardAddress::from_public(self.network, keypair.public).into();
  148. output.push(format!("{address}"));
  149. Ok(())
  150. }
  151. /// Fetch default secret key from the wallet.
  152. pub async fn default_secret(&self) -> Result<SecretKey> {
  153. let row = match self
  154. .wallet
  155. .query_single(
  156. &MONEY_KEYS_TABLE,
  157. &[MONEY_KEYS_COL_SECRET],
  158. convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
  159. )
  160. .await
  161. {
  162. Ok(r) => r,
  163. Err(e) => {
  164. return Err(Error::DatabaseError(format!(
  165. "[default_secret] Default secret key retrieval failed: {e}"
  166. )))
  167. }
  168. };
  169. let Value::Blob(ref key_bytes) = row[0] else {
  170. return Err(Error::ParseFailed("[default_secret] Key bytes parsing failed"))
  171. };
  172. let secret_key: SecretKey = deserialize_async(key_bytes).await?;
  173. Ok(secret_key)
  174. }
  175. /// Fetch default pubkey from the wallet.
  176. pub async fn default_address(&self) -> Result<PublicKey> {
  177. let row = match self
  178. .wallet
  179. .query_single(
  180. &MONEY_KEYS_TABLE,
  181. &[MONEY_KEYS_COL_PUBLIC],
  182. convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
  183. )
  184. .await
  185. {
  186. Ok(r) => r,
  187. Err(e) => {
  188. return Err(Error::DatabaseError(format!(
  189. "[default_address] Default address retrieval failed: {e}"
  190. )))
  191. }
  192. };
  193. let Value::Blob(ref key_bytes) = row[0] else {
  194. return Err(Error::ParseFailed("[default_address] Key bytes parsing failed"))
  195. };
  196. let public_key: PublicKey = deserialize_async(key_bytes).await?;
  197. Ok(public_key)
  198. }
  199. /// Set provided index address as default in the wallet.
  200. pub async fn set_default_address(&self, idx: u16) -> WalletDbResult<()> {
  201. // First we update previous default record
  202. let is_default = 0;
  203. let query = format!("UPDATE {} SET {} = ?1", *MONEY_KEYS_TABLE, MONEY_KEYS_COL_IS_DEFAULT,);
  204. self.wallet.exec_sql(&query, params![is_default]).await?;
  205. // and then we set the new one
  206. let is_default = 1;
  207. let query = format!(
  208. "UPDATE {} SET {} = ?1 WHERE {} = ?2",
  209. *MONEY_KEYS_TABLE, MONEY_KEYS_COL_IS_DEFAULT, MONEY_KEYS_COL_KEY_ID,
  210. );
  211. self.wallet.exec_sql(&query, params![is_default, idx]).await
  212. }
  213. /// Fetch all pukeys from the wallet.
  214. pub async fn addresses(&self) -> Result<Vec<(u64, PublicKey, SecretKey, u64)>> {
  215. let rows = match self.wallet.query_multiple(&MONEY_KEYS_TABLE, &[], vec![]).await {
  216. Ok(r) => r,
  217. Err(e) => {
  218. return Err(Error::DatabaseError(format!(
  219. "[addresses] Addresses retrieval failed: {e}"
  220. )))
  221. }
  222. };
  223. let mut vec = Vec::with_capacity(rows.len());
  224. for row in rows {
  225. let Value::Integer(key_id) = row[0] else {
  226. return Err(Error::ParseFailed("[addresses] Key ID parsing failed"))
  227. };
  228. let Ok(key_id) = u64::try_from(key_id) else {
  229. return Err(Error::ParseFailed("[addresses] Key ID parsing failed"))
  230. };
  231. let Value::Integer(is_default) = row[1] else {
  232. return Err(Error::ParseFailed("[addresses] Is default parsing failed"))
  233. };
  234. let Ok(is_default) = u64::try_from(is_default) else {
  235. return Err(Error::ParseFailed("[addresses] Is default parsing failed"))
  236. };
  237. let Value::Blob(ref key_bytes) = row[2] else {
  238. return Err(Error::ParseFailed("[addresses] Public key bytes parsing failed"))
  239. };
  240. let public_key: PublicKey = deserialize_async(key_bytes).await?;
  241. let Value::Blob(ref key_bytes) = row[3] else {
  242. return Err(Error::ParseFailed("[addresses] Secret key bytes parsing failed"))
  243. };
  244. let secret_key: SecretKey = deserialize_async(key_bytes).await?;
  245. vec.push((key_id, public_key, secret_key, is_default));
  246. }
  247. Ok(vec)
  248. }
  249. /// Fetch provided index address from the wallet and generate its
  250. /// mining configuration.
  251. pub async fn mining_config(
  252. &self,
  253. idx: u16,
  254. spend_hook: Option<FuncId>,
  255. user_data: Option<pallas::Base>,
  256. output: &mut Vec<String>,
  257. ) -> Result<()> {
  258. let row = match self
  259. .wallet
  260. .query_single(
  261. &MONEY_KEYS_TABLE,
  262. &[MONEY_KEYS_COL_PUBLIC],
  263. convert_named_params! {(MONEY_KEYS_COL_KEY_ID, idx)},
  264. )
  265. .await
  266. {
  267. Ok(r) => r,
  268. Err(e) => {
  269. return Err(Error::DatabaseError(format!(
  270. "[mining_address] Address retrieval failed: {e}"
  271. )))
  272. }
  273. };
  274. let Value::Blob(ref key_bytes) = row[0] else {
  275. return Err(Error::ParseFailed("[mining_address] Key bytes parsing failed"))
  276. };
  277. let public_key: PublicKey = deserialize_async(key_bytes).await?;
  278. let address: Address = StandardAddress::from_public(self.network, public_key).into();
  279. let recipient = address.to_string();
  280. let spend_hook = spend_hook.as_ref().map(|spend_hook| spend_hook.to_string());
  281. let user_data =
  282. user_data.as_ref().map(|user_data| bs58::encode(user_data.to_repr()).into_string());
  283. output.push(String::from("DarkFi mining configuration address:"));
  284. output.push(base64::encode(&serialize(&(recipient, spend_hook, user_data))).to_string());
  285. Ok(())
  286. }
  287. /// Fetch all secret keys from the wallet.
  288. pub async fn get_money_secrets(&self) -> Result<Vec<SecretKey>> {
  289. let rows = match self
  290. .wallet
  291. .query_multiple(&MONEY_KEYS_TABLE, &[MONEY_KEYS_COL_SECRET], vec![])
  292. .await
  293. {
  294. Ok(r) => r,
  295. Err(e) => {
  296. return Err(Error::DatabaseError(format!(
  297. "[get_money_secrets] Secret keys retrieval failed: {e}"
  298. )))
  299. }
  300. };
  301. let mut secrets = Vec::with_capacity(rows.len());
  302. // Let's scan through the rows and see if we got anything.
  303. for row in rows {
  304. let Value::Blob(ref key_bytes) = row[0] else {
  305. return Err(Error::ParseFailed(
  306. "[get_money_secrets] Secret key bytes parsing failed",
  307. ))
  308. };
  309. let secret_key: SecretKey = deserialize_async(key_bytes).await?;
  310. secrets.push(secret_key);
  311. }
  312. Ok(secrets)
  313. }
  314. /// Import given secret keys into the wallet.
  315. /// If the key already exists, it will be skipped.
  316. /// Returns the respective PublicKey objects for the imported keys.
  317. pub async fn import_money_secrets(
  318. &self,
  319. secrets: Vec<SecretKey>,
  320. output: &mut Vec<String>,
  321. ) -> Result<Vec<PublicKey>> {
  322. let existing_secrets = self.get_money_secrets().await?;
  323. let mut ret = Vec::with_capacity(secrets.len());
  324. for secret in secrets {
  325. // Check if secret already exists
  326. if existing_secrets.contains(&secret) {
  327. output.push(format!("Existing key found: {secret}"));
  328. continue
  329. }
  330. ret.push(PublicKey::from_secret(secret));
  331. let is_default = 0;
  332. let public = serialize_async(&PublicKey::from_secret(secret)).await;
  333. let secret = serialize_async(&secret).await;
  334. let query = format!(
  335. "INSERT INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
  336. *MONEY_KEYS_TABLE,
  337. MONEY_KEYS_COL_IS_DEFAULT,
  338. MONEY_KEYS_COL_PUBLIC,
  339. MONEY_KEYS_COL_SECRET
  340. );
  341. if let Err(e) = self.wallet.exec_sql(&query, params![is_default, public, secret]).await
  342. {
  343. return Err(Error::DatabaseError(format!(
  344. "[import_money_secrets] Inserting new address failed: {e}"
  345. )))
  346. }
  347. }
  348. Ok(ret)
  349. }
  350. /// Fetch known unspent balances from the wallet and return them as a hashmap.
  351. pub async fn money_balance(&self) -> Result<HashMap<String, u64>> {
  352. let mut coins = self.get_coins(false).await?;
  353. coins.retain(|x| x.0.note.spend_hook == FuncId::none());
  354. // Fill this map with balances
  355. let mut balmap: HashMap<String, u64> = HashMap::new();
  356. for coin in coins {
  357. let mut value = coin.0.note.value;
  358. if let Some(prev) = balmap.get(&coin.0.note.token_id.to_string()) {
  359. value += prev;
  360. }
  361. balmap.insert(coin.0.note.token_id.to_string(), value);
  362. }
  363. Ok(balmap)
  364. }
  365. /// Fetch all coins and their metadata related to the Money contract from the wallet.
  366. /// Optionally also fetch spent ones.
  367. /// The boolean in the returned tuple notes if the coin was marked
  368. /// as spent, along with the height and tx it was spent in.
  369. pub async fn get_coins(
  370. &self,
  371. fetch_spent: bool,
  372. ) -> Result<Vec<(OwnCoin, u32, bool, Option<u32>, String)>> {
  373. let query = if fetch_spent {
  374. self.wallet.query_multiple(&MONEY_COINS_TABLE, &[], vec![]).await
  375. } else {
  376. self.wallet
  377. .query_multiple(
  378. &MONEY_COINS_TABLE,
  379. &[],
  380. convert_named_params! {(MONEY_COINS_COL_IS_SPENT, false)},
  381. )
  382. .await
  383. };
  384. let rows = match query {
  385. Ok(r) => r,
  386. Err(e) => {
  387. return Err(Error::DatabaseError(format!("[get_coins] Coins retrieval failed: {e}")))
  388. }
  389. };
  390. let mut owncoins = Vec::with_capacity(rows.len());
  391. for row in rows {
  392. owncoins.push(self.parse_coin_record(&row).await?)
  393. }
  394. Ok(owncoins)
  395. }
  396. /// Fetch provided token unspend balances from the wallet.
  397. pub async fn get_token_coins(&self, token_id: &TokenId) -> Result<Vec<OwnCoin>> {
  398. let query = self
  399. .wallet
  400. .query_multiple(
  401. &MONEY_COINS_TABLE,
  402. &[],
  403. convert_named_params! {
  404. (MONEY_COINS_COL_TOKEN_ID, serialize_async(token_id).await),
  405. (MONEY_COINS_COL_SPEND_HOOK, serialize_async(&FuncId::none()).await),
  406. (MONEY_COINS_COL_IS_SPENT, false),
  407. },
  408. )
  409. .await;
  410. let rows = match query {
  411. Ok(r) => r,
  412. Err(e) => {
  413. return Err(Error::DatabaseError(format!(
  414. "[get_token_coins] Coins retrieval failed: {e}"
  415. )))
  416. }
  417. };
  418. let mut owncoins = Vec::with_capacity(rows.len());
  419. for row in rows {
  420. owncoins.push(self.parse_coin_record(&row).await?.0)
  421. }
  422. Ok(owncoins)
  423. }
  424. /// Fetch provided contract specified token unspend balances from the wallet.
  425. pub async fn get_contract_token_coins(
  426. &self,
  427. token_id: &TokenId,
  428. spend_hook: &FuncId,
  429. user_data: &pallas::Base,
  430. ) -> Result<Vec<OwnCoin>> {
  431. let query = self
  432. .wallet
  433. .query_multiple(
  434. &MONEY_COINS_TABLE,
  435. &[],
  436. convert_named_params! {
  437. (MONEY_COINS_COL_TOKEN_ID, serialize_async(token_id).await),
  438. (MONEY_COINS_COL_SPEND_HOOK, serialize_async(spend_hook).await),
  439. (MONEY_COINS_COL_USER_DATA, serialize_async(user_data).await),
  440. (MONEY_COINS_COL_IS_SPENT, false),
  441. },
  442. )
  443. .await;
  444. let rows = match query {
  445. Ok(r) => r,
  446. Err(e) => {
  447. return Err(Error::DatabaseError(format!(
  448. "[get_contract_token_coins] Coins retrieval failed: {e}"
  449. )))
  450. }
  451. };
  452. let mut owncoins = Vec::with_capacity(rows.len());
  453. for row in rows {
  454. owncoins.push(self.parse_coin_record(&row).await?.0)
  455. }
  456. Ok(owncoins)
  457. }
  458. /// Auxiliary function to parse a `MONEY_COINS_TABLE` record.
  459. /// The boolean in the returned tuple notes if the coin was marked
  460. /// as spent, along with the height and tx it was spent in.
  461. async fn parse_coin_record(
  462. &self,
  463. row: &[Value],
  464. ) -> Result<(OwnCoin, u32, bool, Option<u32>, String)> {
  465. let Value::Blob(ref coin_bytes) = row[0] else {
  466. return Err(Error::ParseFailed("[parse_coin_record] Coin bytes parsing failed"))
  467. };
  468. let coin: Coin = deserialize_async(coin_bytes).await?;
  469. let Value::Blob(ref value_bytes) = row[1] else {
  470. return Err(Error::ParseFailed("[parse_coin_record] Value bytes parsing failed"))
  471. };
  472. let value: u64 = deserialize_async(value_bytes).await?;
  473. let Value::Blob(ref token_id_bytes) = row[2] else {
  474. return Err(Error::ParseFailed("[parse_coin_record] Token ID bytes parsing failed"))
  475. };
  476. let token_id: TokenId = deserialize_async(token_id_bytes).await?;
  477. let Value::Blob(ref spend_hook_bytes) = row[3] else {
  478. return Err(Error::ParseFailed("[parse_coin_record] Spend hook bytes parsing failed"))
  479. };
  480. let spend_hook: pallas::Base = deserialize_async(spend_hook_bytes).await?;
  481. let Value::Blob(ref user_data_bytes) = row[4] else {
  482. return Err(Error::ParseFailed("[parse_coin_record] User data bytes parsing failed"))
  483. };
  484. let user_data: pallas::Base = deserialize_async(user_data_bytes).await?;
  485. let Value::Blob(ref coin_blind_bytes) = row[5] else {
  486. return Err(Error::ParseFailed("[parse_coin_record] Coin blind bytes parsing failed"))
  487. };
  488. let coin_blind: BaseBlind = deserialize_async(coin_blind_bytes).await?;
  489. let Value::Blob(ref value_blind_bytes) = row[6] else {
  490. return Err(Error::ParseFailed("[parse_coin_record] Value blind bytes parsing failed"))
  491. };
  492. let value_blind: ScalarBlind = deserialize_async(value_blind_bytes).await?;
  493. let Value::Blob(ref token_blind_bytes) = row[7] else {
  494. return Err(Error::ParseFailed("[parse_coin_record] Token blind bytes parsing failed"))
  495. };
  496. let token_blind: BaseBlind = deserialize_async(token_blind_bytes).await?;
  497. let Value::Blob(ref secret_bytes) = row[8] else {
  498. return Err(Error::ParseFailed("[parse_coin_record] Secret bytes parsing failed"))
  499. };
  500. let secret: SecretKey = deserialize_async(secret_bytes).await?;
  501. let Value::Blob(ref leaf_position_bytes) = row[9] else {
  502. return Err(Error::ParseFailed("[parse_coin_record] Leaf position bytes parsing failed"))
  503. };
  504. let leaf_position: Position = deserialize_async(leaf_position_bytes).await?;
  505. let Value::Blob(ref memo) = row[10] else {
  506. return Err(Error::ParseFailed("[parse_coin_record] Memo parsing failed"))
  507. };
  508. let Value::Integer(creation_height) = row[11] else {
  509. return Err(Error::ParseFailed("[parse_coin_record] Creation height parsing failed"))
  510. };
  511. let Ok(creation_height) = u32::try_from(creation_height) else {
  512. return Err(Error::ParseFailed("[parse_coin_record] Creation height parsing failed"))
  513. };
  514. let Value::Integer(is_spent) = row[12] else {
  515. return Err(Error::ParseFailed("[parse_coin_record] Is spent parsing failed"))
  516. };
  517. let Ok(is_spent) = u64::try_from(is_spent) else {
  518. return Err(Error::ParseFailed("[parse_coin_record] Is spent parsing failed"))
  519. };
  520. let is_spent = is_spent > 0;
  521. let spent_height = match row[13] {
  522. Value::Integer(spent_height) => {
  523. let Ok(spent_height) = u32::try_from(spent_height) else {
  524. return Err(Error::ParseFailed(
  525. "[parse_coin_record] Spent height parsing failed",
  526. ))
  527. };
  528. Some(spent_height)
  529. }
  530. Value::Null => None,
  531. _ => return Err(Error::ParseFailed("[parse_coin_record] Spent height parsing failed")),
  532. };
  533. let Value::Text(ref spent_tx_hash) = row[14] else {
  534. return Err(Error::ParseFailed(
  535. "[parse_coin_record] Spent transaction hash parsing failed",
  536. ))
  537. };
  538. let note = MoneyNote {
  539. value,
  540. token_id,
  541. spend_hook: spend_hook.into(),
  542. user_data,
  543. coin_blind,
  544. value_blind,
  545. token_blind,
  546. memo: memo.clone(),
  547. };
  548. Ok((
  549. OwnCoin { coin, note, secret, leaf_position },
  550. creation_height,
  551. is_spent,
  552. spent_height,
  553. spent_tx_hash.clone(),
  554. ))
  555. }
  556. /// Create an alias record for provided Token ID.
  557. pub async fn add_alias(
  558. &self,
  559. alias: String,
  560. token_id: TokenId,
  561. output: &mut Vec<String>,
  562. ) -> WalletDbResult<()> {
  563. output.push(format!("Generating alias {alias} for Token: {token_id}"));
  564. let query = format!(
  565. "INSERT OR REPLACE INTO {} ({}, {}) VALUES (?1, ?2);",
  566. *MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS, MONEY_ALIASES_COL_TOKEN_ID,
  567. );
  568. self.wallet
  569. .exec_sql(
  570. &query,
  571. params![serialize_async(&alias).await, serialize_async(&token_id).await],
  572. )
  573. .await
  574. }
  575. /// Fetch all aliases from the wallet.
  576. /// Optionally filter using alias name and/or token id.
  577. pub async fn get_aliases(
  578. &self,
  579. alias_filter: Option<String>,
  580. token_id_filter: Option<TokenId>,
  581. ) -> Result<HashMap<String, TokenId>> {
  582. let rows = match self.wallet.query_multiple(&MONEY_ALIASES_TABLE, &[], vec![]).await {
  583. Ok(r) => r,
  584. Err(e) => {
  585. return Err(Error::DatabaseError(format!(
  586. "[get_aliases] Aliases retrieval failed: {e}"
  587. )))
  588. }
  589. };
  590. // Fill this map with aliases
  591. let mut map: HashMap<String, TokenId> = HashMap::new();
  592. for row in rows {
  593. let Value::Blob(ref alias_bytes) = row[0] else {
  594. return Err(Error::ParseFailed("[get_aliases] Alias bytes parsing failed"))
  595. };
  596. let alias: String = deserialize_async(alias_bytes).await?;
  597. if alias_filter.is_some() && alias_filter.as_ref().unwrap() != &alias {
  598. continue
  599. }
  600. let Value::Blob(ref token_id_bytes) = row[1] else {
  601. return Err(Error::ParseFailed("[get_aliases] TokenId bytes parsing failed"))
  602. };
  603. let token_id: TokenId = deserialize_async(token_id_bytes).await?;
  604. if token_id_filter.is_some() && token_id_filter.as_ref().unwrap() != &token_id {
  605. continue
  606. }
  607. map.insert(alias, token_id);
  608. }
  609. Ok(map)
  610. }
  611. /// Fetch all aliases from the wallet, mapped by token id.
  612. pub async fn get_aliases_mapped_by_token(&self) -> Result<HashMap<String, String>> {
  613. let aliases = self.get_aliases(None, None).await?;
  614. let mut map: HashMap<String, String> = HashMap::new();
  615. for (alias, token_id) in aliases {
  616. let aliases_string = if let Some(prev) = map.get(&token_id.to_string()) {
  617. format!("{prev}, {alias}")
  618. } else {
  619. alias
  620. };
  621. map.insert(token_id.to_string(), aliases_string);
  622. }
  623. Ok(map)
  624. }
  625. /// Remove provided alias record from the wallet database.
  626. pub async fn remove_alias(
  627. &self,
  628. alias: String,
  629. output: &mut Vec<String>,
  630. ) -> WalletDbResult<()> {
  631. output.push(format!("Removing alias: {alias}"));
  632. let query = format!(
  633. "DELETE FROM {} WHERE {} = ?1;",
  634. *MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS,
  635. );
  636. self.wallet.exec_sql(&query, params![serialize_async(&alias).await]).await
  637. }
  638. /// Mark a given coin in the wallet as unspent.
  639. pub async fn unspend_coin(&self, coin: &Coin) -> WalletDbResult<()> {
  640. let query = format!(
  641. "UPDATE {} SET {} = 0, {} = NULL, {} = '-' WHERE {} = ?1;",
  642. *MONEY_COINS_TABLE,
  643. MONEY_COINS_COL_IS_SPENT,
  644. MONEY_COINS_COL_SPENT_HEIGHT,
  645. MONEY_COINS_COL_SPENT_TX_HASH,
  646. MONEY_COINS_COL_COIN
  647. );
  648. self.wallet.exec_sql(&query, params![serialize_async(&coin.inner()).await]).await
  649. }
  650. /// Fetch the Money Merkle tree from the cache.
  651. /// If it doesn't exists a new Merkle Tree is returned.
  652. pub async fn get_money_tree(&self) -> Result<MerkleTree> {
  653. match self.cache.merkle_trees.get(SLED_MERKLE_TREES_MONEY)? {
  654. Some(tree_bytes) => Ok(deserialize_async(&tree_bytes).await?),
  655. None => {
  656. let mut tree = MerkleTree::new(u32::MAX as usize);
  657. tree.append(MerkleNode::from(pallas::Base::ZERO));
  658. let _ = tree.mark().unwrap();
  659. Ok(tree)
  660. }
  661. }
  662. }
  663. /// Auxiliary function to grab all the nullifiers, coins with their
  664. /// notes and a flag indicating if its a block reward, and freezes
  665. /// from a transaction money call.
  666. async fn parse_money_call(
  667. &self,
  668. scan_cache: &mut ScanCache,
  669. call_idx: &usize,
  670. calls: &[DarkLeaf<ContractCall>],
  671. ) -> Result<(Vec<Nullifier>, Vec<(Coin, AeadEncryptedNote, bool)>, Vec<TokenId>)> {
  672. let mut nullifiers: Vec<Nullifier> = vec![];
  673. let mut coins: Vec<(Coin, AeadEncryptedNote, bool)> = vec![];
  674. let mut freezes: Vec<TokenId> = vec![];
  675. let call = &calls[*call_idx];
  676. let data = &call.data.data;
  677. match MoneyFunction::try_from(data[0])? {
  678. MoneyFunction::FeeV1 => {
  679. scan_cache.log(String::from("[parse_money_call] Found Money::FeeV1 call"));
  680. let params: MoneyFeeParamsV1 = deserialize_async(&data[9..]).await?;
  681. nullifiers.push(params.input.nullifier);
  682. if !params.output.tx_local {
  683. coins.push((params.output.coin, params.output.note, false));
  684. }
  685. }
  686. MoneyFunction::GenesisMintV1 => {
  687. scan_cache.log(String::from("[parse_money_call] Found Money::GenesisMintV1 call"));
  688. let params: MoneyGenesisMintParamsV1 = deserialize_async(&data[1..]).await?;
  689. for output in params.outputs {
  690. if !output.tx_local {
  691. coins.push((output.coin, output.note, false));
  692. }
  693. }
  694. }
  695. MoneyFunction::PoWRewardV1 => {
  696. scan_cache.log(String::from("[parse_money_call] Found Money::PoWRewardV1 call"));
  697. let params: MoneyPoWRewardParamsV1 = deserialize_async(&data[1..]).await?;
  698. if !params.output.tx_local {
  699. coins.push((params.output.coin, params.output.note, true));
  700. }
  701. }
  702. MoneyFunction::TransferV1 => {
  703. scan_cache.log(String::from("[parse_money_call] Found Money::TransferV1 call"));
  704. let params: MoneyTransferParamsV1 = deserialize_async(&data[1..]).await?;
  705. for input in params.inputs {
  706. nullifiers.push(input.nullifier);
  707. }
  708. for output in params.outputs {
  709. if !output.tx_local {
  710. coins.push((output.coin, output.note, false));
  711. }
  712. }
  713. }
  714. MoneyFunction::AuthTokenMintV1 => {
  715. scan_cache
  716. .log(String::from("[parse_money_call] Found Money::AuthTokenMintV1 call"));
  717. // Handled in TokenMint
  718. }
  719. MoneyFunction::AuthTokenFreezeV1 => {
  720. scan_cache
  721. .log(String::from("[parse_money_call] Found Money::AuthTokenFreezeV1 call"));
  722. let params: MoneyAuthTokenFreezeParamsV1 = deserialize_async(&data[1..]).await?;
  723. freezes.push(params.token_id);
  724. }
  725. MoneyFunction::TokenMintV1 => {
  726. scan_cache.log(String::from("[parse_money_call] Found Money::TokenMintV1 call"));
  727. let params: MoneyTokenMintParamsV1 = deserialize_async(&data[1..]).await?;
  728. coins.push((params.coin, params.enc_note, false))
  729. }
  730. MoneyFunction::BurnV1 => {
  731. scan_cache.log(String::from("[parse_money_call] Found Money::BurnV1 call"));
  732. let params: MoneyBurnParamsV1 = deserialize_async(&data[1..]).await?;
  733. for input in params.inputs {
  734. nullifiers.push(input.nullifier);
  735. }
  736. }
  737. }
  738. Ok((nullifiers, coins, freezes))
  739. }
  740. /// Auxiliary function to handle coins with their notes and flag
  741. /// indicating if its a block reward from a transaction money call.
  742. /// Returns our found own coins along with the block signing key,
  743. /// if found.
  744. fn handle_money_call_coins(
  745. &self,
  746. tree: &mut MerkleTree,
  747. secrets: &[SecretKey],
  748. messages_buffer: &mut Vec<String>,
  749. coins: &[(Coin, AeadEncryptedNote, bool)],
  750. ) -> Result<(Vec<OwnCoin>, Option<SecretKey>)> {
  751. // Keep track of our own coins found in the vec
  752. let mut owncoins = vec![];
  753. // Check if provided coins vec is empty
  754. if coins.is_empty() {
  755. return Ok((owncoins, None))
  756. }
  757. // Handle provided coins vector and grab our own,
  758. // along with the block signing key if its a block
  759. // reward coin. Only one reward call and coin exists
  760. // in each block.
  761. let mut block_signing_key = None;
  762. for (coin, note, is_block_reward) in coins {
  763. // Append the new coin to the Merkle tree.
  764. // Every coin has to be added.
  765. tree.append(MerkleNode::from(coin.inner()));
  766. // Attempt to decrypt the note
  767. for secret in secrets {
  768. let Ok(note) = note.decrypt::<MoneyNote>(secret) else { continue };
  769. messages_buffer.push(String::from(
  770. "[handle_money_call_coins] Successfully decrypted a Money Note",
  771. ));
  772. messages_buffer
  773. .push(String::from("[handle_money_call_coins] Witnessing coin in Merkle tree"));
  774. let leaf_position = tree.mark().unwrap();
  775. if *is_block_reward {
  776. messages_buffer
  777. .push(String::from("[handle_money_call_coins] Grabing block signing key"));
  778. block_signing_key = Some(deserialize(&note.memo)?);
  779. }
  780. let owncoin = OwnCoin { coin: *coin, note, secret: *secret, leaf_position };
  781. owncoins.push(owncoin);
  782. break
  783. }
  784. }
  785. Ok((owncoins, block_signing_key))
  786. }
  787. /// Auxiliary function to handle own coins from a transaction money
  788. /// call.
  789. async fn handle_money_call_owncoins(
  790. &self,
  791. scan_cache: &mut ScanCache,
  792. coins: &[OwnCoin],
  793. creation_height: &u32,
  794. ) -> Result<()> {
  795. scan_cache.log(format!("Found {} OwnCoin(s) in transaction", coins.len()));
  796. // Check if we have any owncoins to process
  797. if coins.is_empty() {
  798. return Ok(())
  799. }
  800. // This is the SQL query we'll be executing to insert new coins into the wallet
  801. let query = format!(
  802. "INSERT INTO {} ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14);",
  803. *MONEY_COINS_TABLE,
  804. MONEY_COINS_COL_COIN,
  805. MONEY_COINS_COL_VALUE,
  806. MONEY_COINS_COL_TOKEN_ID,
  807. MONEY_COINS_COL_SPEND_HOOK,
  808. MONEY_COINS_COL_USER_DATA,
  809. MONEY_COINS_COL_COIN_BLIND,
  810. MONEY_COINS_COL_VALUE_BLIND,
  811. MONEY_COINS_COL_TOKEN_BLIND,
  812. MONEY_COINS_COL_SECRET,
  813. MONEY_COINS_COL_LEAF_POSITION,
  814. MONEY_COINS_COL_MEMO,
  815. MONEY_COINS_COL_CREATION_HEIGHT,
  816. MONEY_COINS_COL_IS_SPENT,
  817. MONEY_COINS_COL_SPENT_HEIGHT,
  818. );
  819. // Handle our own coins
  820. let spent_height: Option<u32> = None;
  821. for coin in coins {
  822. scan_cache.log(format!("OwnCoin: {:?}", coin.coin));
  823. // Grab coin record key
  824. let key = coin.coin.to_bytes();
  825. // Push to our own coins nullifiers cache
  826. scan_cache
  827. .owncoins_nullifiers
  828. .insert(coin.nullifier().to_bytes(), (key, coin.leaf_position));
  829. // Execute the query
  830. let params = params![
  831. key.to_vec(),
  832. serialize(&coin.note.value),
  833. serialize(&coin.note.token_id),
  834. serialize(&coin.note.spend_hook),
  835. serialize(&coin.note.user_data),
  836. serialize(&coin.note.coin_blind),
  837. serialize(&coin.note.value_blind),
  838. serialize(&coin.note.token_blind),
  839. serialize(&coin.secret),
  840. serialize(&coin.leaf_position),
  841. serialize(&coin.note.memo),
  842. *creation_height,
  843. 0, // <-- is_spent
  844. spent_height,
  845. ];
  846. if let Err(e) = self.wallet.exec_sql(&query, params).await {
  847. return Err(Error::DatabaseError(format!(
  848. "[handle_money_call_owncoins] Inserting Money coin failed: {e}"
  849. )))
  850. }
  851. }
  852. Ok(())
  853. }
  854. /// Auxiliary function to handle freezes from a transaction money
  855. /// call.
  856. /// Returns a flag indicating if provided freezes refer to our own
  857. /// wallet.
  858. async fn handle_money_call_freezes(
  859. &self,
  860. own_tokens: &[TokenId],
  861. freezes: &[TokenId],
  862. freeze_height: &u32,
  863. ) -> Result<bool> {
  864. // Check if we have any freezes to process
  865. if freezes.is_empty() {
  866. return Ok(false)
  867. }
  868. // Find our own tokens that got frozen
  869. let mut own_freezes = Vec::with_capacity(freezes.len());
  870. for freeze in freezes {
  871. if own_tokens.contains(freeze) {
  872. own_freezes.push(freeze);
  873. }
  874. }
  875. // Check if we need to freeze anything
  876. if own_freezes.is_empty() {
  877. return Ok(false)
  878. }
  879. // This is the SQL query we'll be executing to update frozen tokens into the wallet
  880. let query = format!(
  881. "UPDATE {} SET {} = 1, {} = ?1 WHERE {} = ?2;",
  882. *MONEY_TOKENS_TABLE,
  883. MONEY_TOKENS_COL_IS_FROZEN,
  884. MONEY_TOKENS_COL_FREEZE_HEIGHT,
  885. MONEY_TOKENS_COL_TOKEN_ID,
  886. );
  887. for token_id in own_freezes {
  888. // Grab token record key
  889. let key = serialize_async(token_id).await;
  890. // Execute the query
  891. if let Err(e) = self.wallet.exec_sql(&query, params![Some(*freeze_height), key]).await {
  892. return Err(Error::DatabaseError(format!(
  893. "[handle_money_call_freezes] Update Money token freeze failed: {e}"
  894. )))
  895. }
  896. }
  897. Ok(true)
  898. }
  899. /// Append data related to Money contract transactions into the
  900. /// wallet database and update the provided scan cache.
  901. /// Returns a flag indicating if provided data refer to our own
  902. /// wallet along with the block signing key, if found.
  903. pub async fn apply_tx_money_data(
  904. &self,
  905. scan_cache: &mut ScanCache,
  906. call_idx: &usize,
  907. calls: &[DarkLeaf<ContractCall>],
  908. tx_hash: &str,
  909. block_height: &u32,
  910. ) -> Result<(bool, Option<SecretKey>)> {
  911. // Parse the call
  912. let (nullifiers, coins, freezes) =
  913. self.parse_money_call(scan_cache, call_idx, calls).await?;
  914. // Parse call coins and grab our own
  915. let (owncoins, block_signing_key) = self.handle_money_call_coins(
  916. &mut scan_cache.money_tree,
  917. &scan_cache.notes_secrets,
  918. &mut scan_cache.messages_buffer,
  919. &coins,
  920. )?;
  921. // Update nullifiers smt
  922. self.smt_insert(&mut scan_cache.money_smt, &nullifiers)?;
  923. // Check if we have any spent coins
  924. let wallet_spent_coins = self
  925. .mark_spent_coins(
  926. Some(&mut scan_cache.money_tree),
  927. &scan_cache.owncoins_nullifiers,
  928. &nullifiers,
  929. &Some(*block_height),
  930. tx_hash,
  931. )
  932. .await?;
  933. // Handle our own coins
  934. self.handle_money_call_owncoins(scan_cache, &owncoins, block_height).await?;
  935. // Handle freezes
  936. let wallet_freezes =
  937. self.handle_money_call_freezes(&scan_cache.own_tokens, &freezes, block_height).await?;
  938. if self.fun && !owncoins.is_empty() {
  939. kaching().await;
  940. }
  941. Ok((wallet_spent_coins || !owncoins.is_empty() || wallet_freezes, block_signing_key))
  942. }
  943. /// Auxiliary function to grab all the nullifiers from a transaction money call.
  944. async fn money_call_nullifiers(&self, call: &DarkLeaf<ContractCall>) -> Result<Vec<Nullifier>> {
  945. let mut nullifiers: Vec<Nullifier> = vec![];
  946. let data = &call.data.data;
  947. match MoneyFunction::try_from(data[0])? {
  948. MoneyFunction::FeeV1 => {
  949. let params: MoneyFeeParamsV1 = deserialize_async(&data[9..]).await?;
  950. nullifiers.push(params.input.nullifier);
  951. }
  952. MoneyFunction::TransferV1 => {
  953. let params: MoneyTransferParamsV1 = deserialize_async(&data[1..]).await?;
  954. for input in params.inputs {
  955. nullifiers.push(input.nullifier);
  956. }
  957. }
  958. _ => { /* Do nothing */ }
  959. }
  960. Ok(nullifiers)
  961. }
  962. /// Mark provided transaction input coins as spent.
  963. pub async fn mark_tx_spend(&self, tx: &Transaction, output: &mut Vec<String>) -> Result<()> {
  964. // Create a cache of all our own nullifiers
  965. let mut owncoins_nullifiers = BTreeMap::new();
  966. for coin in self.get_coins(true).await? {
  967. owncoins_nullifiers.insert(
  968. coin.0.nullifier().to_bytes(),
  969. (coin.0.coin.to_bytes(), coin.0.leaf_position),
  970. );
  971. }
  972. let tx_hash = tx.hash().to_string();
  973. output.push(format!("[mark_tx_spend] Processing transaction: {tx_hash}"));
  974. for (i, call) in tx.calls.iter().enumerate() {
  975. if call.data.contract_id != *MONEY_CONTRACT_ID {
  976. continue
  977. }
  978. output.push(format!("[mark_tx_spend] Found Money contract in call {i}"));
  979. let nullifiers = self.money_call_nullifiers(call).await?;
  980. self.mark_spent_coins(None, &owncoins_nullifiers, &nullifiers, &None, &tx_hash).await?;
  981. }
  982. Ok(())
  983. }
  984. /// Marks all coins in the wallet as spent, if their nullifier is in the given set.
  985. /// Returns a flag indicating if any of the provided nullifiers refer to our own wallet.
  986. pub async fn mark_spent_coins(
  987. &self,
  988. mut tree: Option<&mut MerkleTree>,
  989. owncoins_nullifiers: &BTreeMap<[u8; 32], ([u8; 32], Position)>,
  990. nullifiers: &[Nullifier],
  991. spent_height: &Option<u32>,
  992. spent_tx_hash: &str,
  993. ) -> Result<bool> {
  994. if nullifiers.is_empty() {
  995. return Ok(false)
  996. }
  997. // Find our owncoins that where spent
  998. let mut spent_owncoins = Vec::new();
  999. for nullifier in nullifiers {
  1000. if let Some(coin) = owncoins_nullifiers.get(&nullifier.to_bytes()) {
  1001. spent_owncoins.push(coin);
  1002. }
  1003. }
  1004. if spent_owncoins.is_empty() {
  1005. return Ok(false)
  1006. }
  1007. // Create an SQL `UPDATE` query to mark rows as spent(1)
  1008. let query = format!(
  1009. "UPDATE {} SET {} = 1, {} = ?1, {} = ?2 WHERE {} = ?3;",
  1010. *MONEY_COINS_TABLE,
  1011. MONEY_COINS_COL_IS_SPENT,
  1012. MONEY_COINS_COL_SPENT_HEIGHT,
  1013. MONEY_COINS_COL_SPENT_TX_HASH,
  1014. MONEY_COINS_COL_COIN
  1015. );
  1016. // Mark spent own coins
  1017. for (ownoin, leaf_position) in spent_owncoins {
  1018. // Execute the query
  1019. if let Err(e) = self
  1020. .wallet
  1021. .exec_sql(&query, params![*spent_height, spent_tx_hash, ownoin.to_vec()])
  1022. .await
  1023. {
  1024. return Err(Error::DatabaseError(format!(
  1025. "[mark_spent_coins] Marking spent coin failed: {e}"
  1026. )))
  1027. }
  1028. // Remove the coin mark from the Merkle tree
  1029. if let Some(ref mut tree) = tree {
  1030. tree.remove_mark(*leaf_position);
  1031. }
  1032. }
  1033. Ok(true)
  1034. }
  1035. /// Inserts given slice to the wallets nullifiers Sparse Merkle Tree.
  1036. pub fn smt_insert(&self, smt: &mut CacheSmt, nullifiers: &[Nullifier]) -> Result<()> {
  1037. let leaves: Vec<_> = nullifiers.iter().map(|x| (x.inner(), x.inner())).collect();
  1038. Ok(smt.insert_batch(leaves)?)
  1039. }
  1040. /// Reset the Money Merkle tree in the cache.
  1041. pub fn reset_money_tree(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
  1042. output.push(String::from("Resetting Money Merkle tree"));
  1043. if let Err(e) = self.cache.merkle_trees.remove(SLED_MERKLE_TREES_MONEY) {
  1044. output.push(format!("[reset_money_tree] Resetting Money Merkle tree failed: {e}"));
  1045. return Err(WalletDbError::GenericError)
  1046. }
  1047. output.push(String::from("Successfully reset Money Merkle tree"));
  1048. Ok(())
  1049. }
  1050. /// Reset the Money nullifiers Sparse Merkle Tree in the cache.
  1051. pub fn reset_money_smt(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
  1052. output.push(String::from("Resetting Money Sparse Merkle tree"));
  1053. if let Err(e) = self.cache.money_smt.clear() {
  1054. output
  1055. .push(format!("[reset_money_smt] Resetting Money Sparse Merkle tree failed: {e}"));
  1056. return Err(WalletDbError::GenericError)
  1057. }
  1058. output.push(String::from("Successfully reset Money Sparse Merkle tree"));
  1059. Ok(())
  1060. }
  1061. /// Reset the Money coins in the wallet.
  1062. pub async fn reset_money_coins(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
  1063. output.push(String::from("Resetting coins"));
  1064. let query = format!("DELETE FROM {};", *MONEY_COINS_TABLE);
  1065. self.wallet.exec_sql(&query, vec![]).await?;
  1066. output.push(String::from("Successfully reset coins"));
  1067. Ok(())
  1068. }
  1069. /// Remove the Money coins in the wallet that were created after
  1070. /// provided height.
  1071. pub async fn remove_money_coins_after(
  1072. &self,
  1073. height: &u32,
  1074. output: &mut Vec<String>,
  1075. ) -> WalletDbResult<()> {
  1076. output.push(format!("Removing coins after: {height}"));
  1077. let query = format!(
  1078. "DELETE FROM {} WHERE {} > ?1;",
  1079. *MONEY_COINS_TABLE, MONEY_COINS_COL_CREATION_HEIGHT
  1080. );
  1081. self.wallet.exec_sql(&query, params![*height]).await?;
  1082. output.push(String::from("Successfully removed coins"));
  1083. Ok(())
  1084. }
  1085. /// Mark the Money coins in the wallet that were spent after
  1086. /// provided height as unspent.
  1087. pub async fn unspent_money_coins_after(
  1088. &self,
  1089. height: &u32,
  1090. output: &mut Vec<String>,
  1091. ) -> WalletDbResult<()> {
  1092. output.push(format!("Unspenting coins after: {height}"));
  1093. let query = format!(
  1094. "UPDATE {} SET {} = 0, {} = NULL, {} = '=' WHERE {} > ?1;",
  1095. *MONEY_COINS_TABLE,
  1096. MONEY_COINS_COL_IS_SPENT,
  1097. MONEY_COINS_COL_SPENT_HEIGHT,
  1098. MONEY_COINS_COL_SPENT_TX_HASH,
  1099. MONEY_COINS_COL_SPENT_HEIGHT
  1100. );
  1101. self.wallet.exec_sql(&query, params![Some(*height)]).await?;
  1102. output.push(String::from("Successfully unspent coins"));
  1103. Ok(())
  1104. }
  1105. /// Retrieve token by provided string.
  1106. /// Input string represents either an alias or a token id.
  1107. pub async fn get_token(&self, input: String) -> Result<TokenId> {
  1108. // Check if input is an alias(max 5 characters)
  1109. if input.chars().count() <= 5 {
  1110. let aliases = self.get_aliases(Some(input.clone()), None).await?;
  1111. if let Some(token_id) = aliases.get(&input) {
  1112. return Ok(*token_id)
  1113. }
  1114. }
  1115. // Else parse input
  1116. Ok(TokenId::from_str(input.as_str())?)
  1117. }
  1118. /// Create and append a `Money::Fee` call to a given [`Transaction`].
  1119. ///
  1120. /// Optionally takes a set of spent coins in order not to reuse them here.
  1121. ///
  1122. /// Returns the `Fee` call, and all necessary data and parameters related.
  1123. pub async fn append_fee_call(
  1124. &self,
  1125. tx: &Transaction,
  1126. money_merkle_tree: &MerkleTree,
  1127. fee_pk: &ProvingKey,
  1128. fee_zkbin: &ZkBinary,
  1129. spent_coins: Option<&[OwnCoin]>,
  1130. ) -> Result<(ContractCall, Vec<Proof>, Vec<SecretKey>)> {
  1131. // First we verify the fee-less transaction to see how much fee it requires for execution
  1132. // and verification.
  1133. let required_fee = compute_fee(&FEE_CALL_GAS) + self.get_tx_fee(tx, false).await?;
  1134. // Knowing the total gas, we can now find an OwnCoin of enough value
  1135. // so that we can create a valid Money::Fee call.
  1136. let mut available_coins = self.get_token_coins(&DARK_TOKEN_ID).await?;
  1137. available_coins.retain(|x| x.note.value > required_fee);
  1138. if let Some(spent_coins) = spent_coins {
  1139. available_coins.retain(|x| !spent_coins.contains(x));
  1140. }
  1141. if available_coins.is_empty() {
  1142. return Err(Error::Custom("Not enough native tokens to pay for fees".to_string()))
  1143. }
  1144. let coin = &available_coins[0];
  1145. let change_value = coin.note.value - required_fee;
  1146. // Input and output setup
  1147. let input = FeeCallInput {
  1148. coin: coin.clone(),
  1149. merkle_path: money_merkle_tree.witness(coin.leaf_position, 0).unwrap(),
  1150. user_data_blind: BaseBlind::random(&mut OsRng),
  1151. };
  1152. let output = FeeCallOutput {
  1153. public_key: PublicKey::from_secret(coin.secret),
  1154. value: change_value,
  1155. token_id: coin.note.token_id,
  1156. blind: BaseBlind::random(&mut OsRng),
  1157. spend_hook: FuncId::none(),
  1158. user_data: pallas::Base::ZERO,
  1159. };
  1160. // Create blinding factors
  1161. let token_blind = BaseBlind::random(&mut OsRng);
  1162. let input_value_blind = ScalarBlind::random(&mut OsRng);
  1163. let fee_value_blind = ScalarBlind::random(&mut OsRng);
  1164. let output_value_blind = compute_remainder_blind(&[input_value_blind], &[fee_value_blind]);
  1165. // Create an ephemeral signing key
  1166. let signature_secret = SecretKey::random(&mut OsRng);
  1167. // Create the actual fee proof
  1168. let (proof, public_inputs) = create_fee_proof(
  1169. fee_zkbin,
  1170. fee_pk,
  1171. &input,
  1172. input_value_blind,
  1173. &output,
  1174. output_value_blind,
  1175. output.spend_hook,
  1176. output.user_data,
  1177. output.blind,
  1178. token_blind,
  1179. signature_secret,
  1180. )?;
  1181. // Encrypted note for the output
  1182. let note = MoneyNote {
  1183. coin_blind: output.blind,
  1184. value: output.value,
  1185. token_id: output.token_id,
  1186. spend_hook: output.spend_hook,
  1187. user_data: output.user_data,
  1188. value_blind: output_value_blind,
  1189. token_blind,
  1190. memo: vec![],
  1191. };
  1192. let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
  1193. let params = MoneyFeeParamsV1 {
  1194. input: Input {
  1195. value_commit: public_inputs.input_value_commit,
  1196. token_commit: public_inputs.token_commit,
  1197. nullifier: public_inputs.nullifier,
  1198. merkle_root: public_inputs.merkle_root,
  1199. user_data_enc: public_inputs.input_user_data_enc,
  1200. signature_public: public_inputs.signature_public,
  1201. tx_local: false,
  1202. },
  1203. output: Output {
  1204. value_commit: public_inputs.output_value_commit,
  1205. token_commit: public_inputs.token_commit,
  1206. coin: public_inputs.output_coin,
  1207. note: encrypted_note,
  1208. tx_local: false,
  1209. },
  1210. fee_value_blind,
  1211. token_blind,
  1212. };
  1213. // Encode the contract call
  1214. let mut data = vec![MoneyFunction::FeeV1 as u8];
  1215. required_fee.encode_async(&mut data).await?;
  1216. params.encode_async(&mut data).await?;
  1217. let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
  1218. Ok((call, vec![proof], vec![signature_secret]))
  1219. }
  1220. /// Create and attach the fee call to given transaction.
  1221. pub async fn attach_fee(&self, tx: &mut Transaction) -> Result<()> {
  1222. // Grab spent coins nullifiers of the transactions and check no other fee call exists
  1223. let mut tx_nullifiers = vec![];
  1224. for call in &tx.calls {
  1225. if call.data.contract_id != *MONEY_CONTRACT_ID {
  1226. continue
  1227. }
  1228. match MoneyFunction::try_from(call.data.data[0])? {
  1229. MoneyFunction::FeeV1 => {
  1230. return Err(Error::Custom("Fee call already exists".to_string()))
  1231. }
  1232. _ => { /* Do nothing */ }
  1233. }
  1234. let nullifiers = self.money_call_nullifiers(call).await?;
  1235. tx_nullifiers.extend_from_slice(&nullifiers);
  1236. }
  1237. // Grab all native owncoins to check if any is spent
  1238. let mut spent_coins = vec![];
  1239. let available_coins = self.get_token_coins(&DARK_TOKEN_ID).await?;
  1240. for coin in available_coins {
  1241. if tx_nullifiers.contains(&coin.nullifier()) {
  1242. spent_coins.push(coin);
  1243. }
  1244. }
  1245. // Now we need to do a lookup for the zkas proof bincodes, and create
  1246. // the circuit objects and proving keys so we can build the transaction.
  1247. // We also do this through the RPC.
  1248. let zkas_bins = self.lookup_zkas(&MONEY_CONTRACT_ID).await?;
  1249. let Some(fee_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_FEE_NS_V1)
  1250. else {
  1251. return Err(Error::Custom("Fee circuit not found".to_string()))
  1252. };
  1253. let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
  1254. let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
  1255. // Creating Fee circuits proving keys
  1256. let fee_pk = ProvingKey::build(fee_zkbin.k, &fee_circuit);
  1257. // We first have to execute the fee-less tx to gather its used gas, and then we feed
  1258. // it into the fee-creating function.
  1259. let tree = self.get_money_tree().await?;
  1260. let (fee_call, fee_proofs, fee_secrets) =
  1261. self.append_fee_call(tx, &tree, &fee_pk, &fee_zkbin, Some(&spent_coins)).await?;
  1262. // Append the fee call to the transaction
  1263. tx.calls.push(DarkLeaf { data: fee_call, parent_index: None, children_indexes: vec![] });
  1264. tx.proofs.push(fee_proofs);
  1265. let sigs = tx.create_sigs(&fee_secrets)?;
  1266. tx.signatures.push(sigs);
  1267. Ok(())
  1268. }
  1269. }