darkfi_contract_test_harness/
money_genesis_mint.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 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
19use darkfi::{
20    tx::{ContractCallLeaf, Transaction, TransactionBuilder},
21    Result,
22};
23use darkfi_money_contract::{
24    client::{genesis_mint_v1::GenesisMintCallBuilder, MoneyNote, OwnCoin},
25    model::MoneyGenesisMintParamsV1,
26    MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
27};
28use darkfi_sdk::{
29    crypto::{contract_id::MONEY_CONTRACT_ID, FuncId, MerkleNode},
30    pasta::pallas,
31    ContractCall,
32};
33use darkfi_serial::AsyncEncodable;
34use log::debug;
35
36use super::{Holder, TestHarness};
37
38impl TestHarness {
39    /// Create a `Money::GenesisMint` transaction for a given [`Holder`].
40    ///
41    /// Returns the created [`Transaction`] and its parameters.
42    pub async fn genesis_mint(
43        &mut self,
44        holder: &Holder,
45        amounts: &[u64],
46        spend_hook: Option<FuncId>,
47        user_data: Option<pallas::Base>,
48    ) -> Result<(Transaction, MoneyGenesisMintParamsV1)> {
49        let wallet = self.holders.get(holder).unwrap();
50
51        let (mint_pk, mint_zkbin) = self.proving_keys.get(MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
52
53        // Build the contract call
54        let builder = GenesisMintCallBuilder {
55            signature_public: wallet.keypair.public,
56            amounts: amounts.to_vec(),
57            recipient: None,
58            spend_hook,
59            user_data,
60            mint_zkbin: mint_zkbin.clone(),
61            mint_pk: mint_pk.clone(),
62        };
63
64        let debris = builder.build()?;
65
66        // Encode and build the transaction
67        let mut data = vec![MoneyFunction::GenesisMintV1 as u8];
68        debris.params.encode_async(&mut data).await?;
69        let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
70        let mut tx_builder =
71            TransactionBuilder::new(ContractCallLeaf { call, proofs: debris.proofs }, vec![])?;
72        let mut tx = tx_builder.build()?;
73        let sigs = tx.create_sigs(&[wallet.keypair.secret])?;
74        tx.signatures = vec![sigs];
75
76        Ok((tx, debris.params))
77    }
78
79    /// Execute the [`Transaction`] created by `genesis_mint()`.
80    ///
81    /// Returns any found [`OwnCoin`]s.
82    pub async fn execute_genesis_mint_tx(
83        &mut self,
84        holder: &Holder,
85        tx: Transaction,
86        params: &MoneyGenesisMintParamsV1,
87        block_height: u32,
88        append: bool,
89    ) -> Result<Vec<OwnCoin>> {
90        let wallet = self.holders.get_mut(holder).unwrap();
91
92        // Execute the transaction
93        wallet.add_transaction("money::genesis_mint", tx, block_height).await?;
94
95        if !append {
96            return Ok(vec![])
97        }
98
99        // Iterate over call outputs to find any new OwnCoins
100        let mut found_owncoins = vec![];
101        for output in &params.outputs {
102            wallet.money_merkle_tree.append(MerkleNode::from(output.coin.inner()));
103
104            // Attempt to decrypt the output note to see if this is a coin for the holder.
105            let Ok(note) = output.note.decrypt::<MoneyNote>(&wallet.keypair.secret) else {
106                continue
107            };
108
109            let owncoin = OwnCoin {
110                coin: output.coin,
111                note: note.clone(),
112                secret: wallet.keypair.secret,
113                leaf_position: wallet.money_merkle_tree.mark().unwrap(),
114            };
115
116            debug!("Found new OwnCoin({}) for {:?}", owncoin.coin, holder);
117            wallet.unspent_money_coins.push(owncoin.clone());
118            found_owncoins.push(owncoin);
119        }
120
121        Ok(found_owncoins)
122    }
123}