|
@@ -0,0 +1,136 @@
|
|
|
|
|
+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, expand_path},
|
|
|
|
|
+ wallet::walletdb::init_wallet,
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// Auxiliary struct to Serialize BridgeTree
|
|
|
|
|
+struct BridgeTreeWrapper {
|
|
|
|
|
+ tree: BridgeTree<MerkleNode, MERKLE_DEPTH>,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl Serialize for BridgeTreeWrapper {
|
|
|
|
|
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
|
+ 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<MerkleNode, MERKLE_DEPTH>) {
|
|
|
|
|
+ let wrapper = BridgeTreeWrapper { tree };
|
|
|
|
|
+ let encoded: Vec<u8> = bincode::serialize(&wrapper).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<SecretKey> =
|
|
|
|
|
+ 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(())
|
|
|
|
|
+}
|