Jelajahi Sumber

src/contract/money: new tx verification benchmark added

aggstam 3 tahun lalu
induk
melakukan
5d9f67b5cd
2 mengubah file dengan 196 tambahan dan 1 penghapusan
  1. 4 1
      src/contract/money/Makefile
  2. 192 0
      src/contract/money/tests/tx_verification.rs

+ 4 - 1
src/contract/money/Makefile

@@ -33,8 +33,11 @@ test-otc: all
 
 test-transfer: all
 	$(CARGO) test --release --features=no-entrypoint,client --package darkfi-money-contract --test transfer
+	
+test-tx-verification: all
+	$(CARGO) test --release --features=no-entrypoint,client --package darkfi-money-contract --test tx_verification
 
-test: test-otc test-transfer
+test: test-otc test-transfer test-tx-verification
 
 clean:
 	rm -f $(ZKAS_BIN) $(WASM_BIN)

+ 192 - 0
src/contract/money/tests/tx_verification.rs

@@ -0,0 +1,192 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2022 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use std::collections::HashMap;
+
+use darkfi::{
+    consensus::{
+        constants::{TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP},
+        ValidatorState,
+    },
+    tx::Transaction,
+    util::{parse::decode_base10, time::Timestamp},
+    wallet::WalletDb,
+    zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses},
+    zkas::ZkBinary,
+    Result,
+};
+use darkfi_sdk::{
+    crypto::{constants::MERKLE_DEPTH, ContractId, Keypair, MerkleNode, TokenId},
+    db::ZKAS_DB_NAME,
+    incrementalmerkletree::bridgetree::BridgeTree,
+    pasta::{
+        group::ff::{Field, PrimeField},
+        pallas,
+    },
+    tx::ContractCall,
+};
+use darkfi_serial::{serialize, Encodable};
+use log::info;
+use rand::rngs::OsRng;
+
+use darkfi_money_contract::{client::build_transfer_tx, MoneyFunction, ZKAS_BURN_NS, ZKAS_MINT_NS};
+
+/// Initialize log configuration
+fn logger_init() -> Result<()> {
+    let mut cfg = simplelog::ConfigBuilder::new();
+    cfg.add_filter_ignore("sled".to_string());
+    simplelog::TermLogger::init(
+        simplelog::LevelFilter::Info,
+        cfg.build(),
+        simplelog::TerminalMode::Mixed,
+        simplelog::ColorChoice::Auto,
+    )?;
+
+    Ok(())
+}
+
+/// Generate N transactions
+fn generate_txs(
+    n: u64,
+    faucet_kp: &Keypair,
+    faucet_merkle_tree: &BridgeTree<MerkleNode, MERKLE_DEPTH>,
+    contract_id: ContractId,
+    mint_zkbin: &ZkBinary,
+    mint_pk: &ProvingKey,
+    burn_zkbin: &ZkBinary,
+    burn_pk: &ProvingKey,
+) -> Result<Vec<Transaction>> {
+    let mut txs = vec![];
+    for i in 0..n {
+        // Generating dummy transaction
+        info!("Generating transaction {}", i);
+        let alice_kp = Keypair::random(&mut OsRng);
+        let token_id = TokenId::from(pallas::Base::random(&mut OsRng));
+        let amount = decode_base10("42.69", 8, true)?;
+
+        let (params, proofs, secret_keys, _spent_coins) = build_transfer_tx(
+            faucet_kp,
+            &alice_kp.public,
+            amount,
+            token_id,
+            &[],
+            faucet_merkle_tree,
+            mint_zkbin,
+            mint_pk,
+            burn_zkbin,
+            burn_pk,
+            true,
+        )?;
+
+        // Build transaction
+        let mut data = vec![MoneyFunction::Transfer as u8];
+        params.encode(&mut data)?;
+        let calls = vec![ContractCall { contract_id, data }];
+        let proofs = vec![proofs];
+        let mut tx = Transaction { calls, proofs, signatures: vec![] };
+        let sigs = tx.create_sigs(&mut OsRng, &secret_keys)?;
+        tx.signatures = vec![sigs];
+
+        txs.push(tx);
+    }
+
+    Ok(txs)
+}
+
+/// Check N faucet transactions verification performance
+#[async_std::test]
+async fn tx_faucet_verification() -> Result<()> {
+    logger_init()?;
+
+    // Test configuration
+    let n = 10;
+
+    // We initialize the faucet that will generate the transactions
+    info!("Initializing faucet");
+    let faucet_kp = Keypair::random(&mut OsRng);
+    let faucet_pubkeys = vec![faucet_kp.public];
+    let faucet_wallet = WalletDb::new("sqlite::memory:", "foo").await?;
+    let faucet_sled_db = sled::Config::new().temporary(true).open()?;
+    let faucet_state = ValidatorState::new(
+        &faucet_sled_db,
+        *TESTNET_GENESIS_TIMESTAMP,
+        *TESTNET_GENESIS_HASH_BYTES,
+        faucet_wallet,
+        faucet_pubkeys.clone(),
+        false,
+    )
+    .await?;
+
+    info!("Looking up zkas circuits from DB");
+    let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+    let faucet_sled = &faucet_state.read().await.blockchain.sled_db;
+    let db_handle = faucet_state.read().await.blockchain.contracts.lookup(
+        faucet_sled,
+        &contract_id,
+        ZKAS_DB_NAME,
+    )?;
+
+    let mint_zkbin = db_handle.get(&serialize(&ZKAS_MINT_NS))?.unwrap();
+    let burn_zkbin = db_handle.get(&serialize(&ZKAS_BURN_NS))?.unwrap();
+    info!("Decoding bincode");
+    let mint_zkbin = ZkBinary::decode(&mint_zkbin.clone())?;
+    let burn_zkbin = ZkBinary::decode(&burn_zkbin.clone())?;
+    let mint_witnesses = empty_witnesses(&mint_zkbin);
+    let burn_witnesses = empty_witnesses(&burn_zkbin);
+    let mint_circuit = ZkCircuit::new(mint_witnesses, mint_zkbin.clone());
+    let burn_circuit = ZkCircuit::new(burn_witnesses, burn_zkbin.clone());
+
+    info!("Creating zk proving keys");
+    let k = 13;
+    let mut proving_keys = HashMap::<[u8; 32], Vec<(&str, ProvingKey)>>::new();
+    let mint_pk = ProvingKey::build(k, &mint_circuit);
+    let burn_pk = ProvingKey::build(k, &burn_circuit);
+    let pks = vec![(ZKAS_MINT_NS, mint_pk.clone()), (ZKAS_BURN_NS, burn_pk.clone())];
+    proving_keys.insert(contract_id.inner().to_repr(), pks);
+
+    info!("Initializing Merkle tree");
+    let faucet_merkle_tree = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(100);
+
+    // Generating transactions
+    info!("Generating {} transactions", n);
+    let init = Timestamp::current_time();
+    let txs = generate_txs(
+        n,
+        &faucet_kp,
+        &faucet_merkle_tree,
+        contract_id,
+        &mint_zkbin,
+        &mint_pk,
+        &burn_zkbin,
+        &burn_pk,
+    )?;
+    let generation_elapsed_time = init.elapsed();
+    assert_eq!(txs.len(), n as usize);
+
+    // Verifying transactions
+    info!("Verifying transactions...");
+    let init = Timestamp::current_time();
+    faucet_state.read().await.verify_transactions(&txs, true).await?;
+    let verification_elapsed_time = init.elapsed();
+
+    info!("Processing time of {} transactions(in sec):", n);
+    info!("\tGeneration -> {}", generation_elapsed_time);
+    info!("\tVerification -> {}", verification_elapsed_time);
+
+    Ok(())
+}