/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2023 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 .
*/
use std::collections::HashMap;
use darkfi::{
consensus::{
ValidatorState, ValidatorStatePtr, TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES,
TESTNET_GENESIS_TIMESTAMP, TESTNET_INITIAL_DISTRIBUTION,
},
runtime::vm_runtime::SMART_CONTRACT_ZKAS_DB_NAME,
tx::Transaction,
wallet::{WalletDb, WalletPtr},
zk::{empty_witnesses, halo2::Field, ProvingKey, ZkCircuit},
zkas::ZkBinary,
Result,
};
use darkfi_sdk::{
crypto::{Keypair, MerkleTree, PublicKey, SecretKey, DARK_TOKEN_ID, MAP_CONTRACT_ID},
pasta::pallas,
ContractCall,
};
use darkfi_serial::{deserialize, serialize, Encodable};
use log::info;
use rand::rngs::OsRng;
use darkfi_map_contract::{client::set_v1::SetCallBuilder, model::SetParamsV1, ContractFunction};
pub const MAP_CONTRACT_ZKAS_SET_NS_V1: &str = "Set_V1";
pub fn init_logger() {
let mut cfg = simplelog::ConfigBuilder::new();
cfg.add_filter_ignore("sled".to_string());
cfg.add_filter_ignore("blockchain::contractstore".to_string());
// We check this error so we can execute same file tests in parallel
// otherwise second one fails to init logger here.
if let Err(_) = simplelog::TermLogger::init(
// simplelog::LevelFilter::Info,
simplelog::LevelFilter::Debug,
//simplelog::LevelFilter::Trace,
cfg.build(),
simplelog::TerminalMode::Mixed,
simplelog::ColorChoice::Auto,
) {
info!(target: "map_harness", "Logger already initialized");
}
}
pub struct Wallet {
pub keypair: Keypair,
pub state: ValidatorStatePtr,
pub merkle_tree: MerkleTree,
pub wallet: WalletPtr,
}
impl Wallet {
async fn new(keypair: Keypair, faucet_pubkeys: &[PublicKey]) -> Result {
let wallet = WalletDb::new("sqlite::memory:", "foo").await?;
let sled_db = sled::Config::new().temporary(true).open()?;
let state = ValidatorState::new(
&sled_db,
*TESTNET_BOOTSTRAP_TIMESTAMP,
*TESTNET_GENESIS_TIMESTAMP,
*TESTNET_GENESIS_HASH_BYTES,
*TESTNET_INITIAL_DISTRIBUTION,
wallet.clone(),
faucet_pubkeys.to_vec(),
false,
false,
)
.await?;
let merkle_tree = MerkleTree::new(100);
Ok(Self {
keypair,
state,
merkle_tree,
wallet,
})
}
}
pub struct MapTestHarness {
pub faucet: Wallet,
pub alice: Wallet,
pub proving_keys: HashMap<&'static str, (ProvingKey, ZkBinary)>,
}
impl MapTestHarness {
pub async fn new() -> Result {
let faucet_kp = Keypair::random(&mut OsRng);
let faucet_pubkeys = vec![faucet_kp.public];
let faucet = Wallet::new(faucet_kp, &faucet_pubkeys).await?;
let alice_kp = Keypair::random(&mut OsRng);
let alice = Wallet::new(alice_kp, &faucet_pubkeys).await?;
// Get the zkas circuits and build proving keys
let alice_sled = alice.state.read().await.blockchain.sled_db.clone();
let db_handle = alice.state.read().await.blockchain.contracts.lookup(
&alice_sled,
&MAP_CONTRACT_ID,
SMART_CONTRACT_ZKAS_DB_NAME,
)?;
// build proving keys
let mut proving_keys = HashMap::new();
macro_rules! mkpk {
($ns:expr) => {
let zkas_bytes = db_handle.get(&serialize(&$ns))?.unwrap();
let (zkbin, _): (Vec, Vec) = deserialize(&zkas_bytes)?;
let zkbin = ZkBinary::decode(&zkbin)?;
let witnesses = empty_witnesses(&zkbin);
let circuit = ZkCircuit::new(witnesses, zkbin.clone());
let pk = ProvingKey::build(13, &circuit);
proving_keys.insert($ns, (pk, zkbin));
};
}
mkpk!(MAP_CONTRACT_ZKAS_SET_NS_V1);
Ok(Self {
faucet,
alice,
proving_keys,
})
}
pub fn set(
&self,
secret: SecretKey,
lock: pallas::Base,
car: pallas::Base,
key: pallas::Base,
value: pallas::Base,
) -> Result<(Transaction, SetParamsV1)> {
let (prove_key, zkbin) = self.proving_keys.get(&MAP_CONTRACT_ZKAS_SET_NS_V1).unwrap();
let debris = SetCallBuilder {
zkbin: zkbin.clone(),
prove_key: prove_key.clone(),
secret: secret.clone(),
lock: lock.clone(),
car: car.clone(),
key: key.clone(),
value: value.clone(),
}
.build()?;
let mut data = vec![ContractFunction::Set as u8];
debris.params.encode(&mut data)?;
let calls = vec![ContractCall {
contract_id: *MAP_CONTRACT_ID,
data: data,
}];
let proofs = vec![debris.proofs];
let mut tx = Transaction {
calls,
proofs,
signatures: vec![],
};
let sigs = tx.create_sigs(&mut OsRng, &debris.signature_secrets)?;
tx.signatures = vec![sigs];
Ok((tx, debris.params))
}
}