/* 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 .
*/
use async_std::sync::{Arc, Mutex};
use incrementalmerkletree::bridgetree::BridgeTree;
use lazy_init::Lazy;
use pasta_curves::{group::ff::Field, pallas::Base};
use rand::rngs::OsRng;
use serde::ser::{Serialize, SerializeStruct, Serializer};
use darkfi::{
blockchain::Blockchain,
consensus::{TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP},
crypto::{
constants::MERKLE_DEPTH,
keypair::{PublicKey, SecretKey},
merkle_node::MerkleNode,
},
node::{
state::{state_transition, ProgramState},
Client, MemoryState, State,
},
util::{cli::progress_bar, path::expand_path},
wallet::walletdb::init_wallet,
};
// Auxiliary struct to Serialize BridgeTree
struct BridgeTreeWrapper {
tree: BridgeTree,
}
impl Serialize for BridgeTreeWrapper {
fn serialize(&self, serializer: S) -> Result
where
S: Serializer,
{
let mut state = serializer.serialize_struct("BridgeTreeWrapper", 1)?;
state.serialize_field("tree", &self.tree)?;
state.end()
}
}
pub fn bridge_tree_usage(prefix: &str, tree: BridgeTree) {
let wrapper = BridgeTreeWrapper { tree };
let encoded: Vec =
bincode::serde::encode_to_vec(&wrapper, bincode::config::legacy()).unwrap();
let size = ::std::mem::size_of_val(&*encoded);
println!(" {} size: {:?} Bytes", prefix, size);
}
#[async_std::main]
async fn main() -> darkfi::Result<()> {
// Config
let folder = "~/.config/darkfi/merkle_testing";
let genesis_ts = *TESTNET_GENESIS_TIMESTAMP;
let genesis_data = *TESTNET_GENESIS_HASH_BYTES;
let pass = "changeme";
// Initialize
let pb = progress_bar("Initializing wallet...");
let path = folder.to_owned() + "/wallet.db";
let wallet = init_wallet(&path, &pass).await?;
let client = Arc::new(Client::new(wallet.clone()).await?);
let address = wallet.get_default_address().await?;
let pubkey = PublicKey::try_from(address)?;
pb.finish();
let pb = progress_bar("Initializing sled database...");
let path = folder.to_owned() + "/blockchain/testnet";
let db_path = expand_path(&path).unwrap();
let sled_db = sled::open(&db_path)?;
pb.finish();
let pb = progress_bar("Generating state machine...");
let blockchain = Blockchain::new(&sled_db, genesis_ts, genesis_data)?;
let state_machine = State {
tree: client.get_tree().await?,
merkle_roots: blockchain.merkle_roots.clone(),
nullifiers: blockchain.nullifiers.clone(),
cashier_pubkeys: vec![],
faucet_pubkeys: vec![pubkey.clone()],
mint_vk: Lazy::new(),
burn_vk: Lazy::new(),
};
pb.finish();
let pb = progress_bar("Creating zk proof verification keys...");
let _ = state_machine.mint_vk();
let _ = state_machine.burn_vk();
pb.finish();
let pb = progress_bar("Generating memory state and secret keys...");
let canon_state_clone = state_machine.clone();
let mut state = state_machine;
let mut mem_state = MemoryState::new(canon_state_clone);
let state_arc = Arc::new(Mutex::new(state.clone()));
let secret_keys: Vec =
client.get_keypairs().await?.iter().map(|x| x.secret).collect();
pb.finish();
// Initial size
bridge_tree_usage("Original state", state.tree.clone());
// Create txs token
let token_id = Base::random(&mut OsRng);
let amount = 1;
// Generating and applying transactions
let txs = 5;
println!(" Applying {} transactions...", txs);
for i in 0..txs {
println!(" tx {}", i);
let tx =
match client.build_transaction(pubkey, amount, token_id, true, state_arc.clone()).await
{
Ok(v) => v,
Err(e) => {
println!("Failed building transaction: {}", e);
return Err(e.into())
}
};
let update = match state_transition(&mem_state, tx.clone()) {
Ok(v) => v,
Err(e) => {
println!("validate_state_transition(): Failed for tx {}: {}", i, e);
return Err(e.into())
}
};
mem_state.apply(update.clone());
state.apply(update, secret_keys.clone(), None, client.wallet.clone()).await?;
}
// Final size
bridge_tree_usage("Final state", state.tree);
Ok(())
}