| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954 |
- /* 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 <https://www.gnu.org/licenses/>.
- */
- use std::{
- collections::HashMap,
- time::{Duration, Instant},
- };
- use darkfi::{
- consensus::{
- SlotCheckpoint, 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::{
- merkle_prelude::*, poseidon_hash, Keypair, MerkleNode, MerkleTree, Nullifier, PublicKey,
- SecretKey, CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID, MONEY_CONTRACT_ID,
- },
- pasta::pallas,
- ContractCall,
- };
- use darkfi_serial::{deserialize, serialize, Encodable};
- use log::{info, warn};
- use rand::rngs::OsRng;
- use darkfi_consensus_contract::{
- client::{
- genesis_stake_v1::ConsensusGenesisStakeCallBuilder,
- proposal_v1::ConsensusProposalCallBuilder, stake_v1::ConsensusStakeCallBuilder,
- unstake_request_v1::ConsensusUnstakeRequestCallBuilder,
- unstake_v1::ConsensusUnstakeCallBuilder,
- },
- model::{ConsensusGenesisStakeParamsV1, ConsensusProposalParamsV1},
- ConsensusFunction,
- };
- use darkfi_money_contract::{
- client::{
- stake_v1::MoneyStakeCallBuilder, transfer_v1::TransferCallBuilder,
- unstake_v1::MoneyUnstakeCallBuilder, ConsensusNote, ConsensusOwnCoin, MoneyNote, OwnCoin,
- },
- model::{
- Coin, ConsensusOutput, ConsensusStakeParamsV1, ConsensusUnstakeReqParamsV1,
- MoneyTransferParamsV1, MoneyUnstakeParamsV1, Output,
- },
- MoneyFunction, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
- CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
- MONEY_CONTRACT_ZKAS_MINT_NS_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,
- ) {
- warn!(target: "money_harness", "Logger already initialized");
- }
- }
- /// Enum representing configured wallet holders
- #[derive(Debug, Eq, Hash, PartialEq)]
- pub enum Holder {
- Faucet,
- Alice,
- }
- /// Enum representing transaction actions
- #[derive(Debug, Eq, Hash, PartialEq)]
- pub enum TxAction {
- Airdrop,
- GenesisStake,
- Stake,
- Proposal,
- UnstakeRequest,
- Unstake,
- }
- /// Auxiliary struct to calculate transaction actions benchmarks
- pub struct TxActionBenchmarks {
- /// Vector holding each transaction size in Bytes
- pub sizes: Vec<usize>,
- /// Vector holding each transaction broadcasted size in Bytes
- pub broadcasted_sizes: Vec<usize>,
- /// Vector holding each transaction creation time
- pub creation_times: Vec<Duration>,
- /// Vector holding each transaction verify time
- pub verify_times: Vec<Duration>,
- }
- impl TxActionBenchmarks {
- pub fn new() -> Self {
- Self {
- sizes: vec![],
- broadcasted_sizes: vec![],
- creation_times: vec![],
- verify_times: vec![],
- }
- }
- pub fn statistics(&self, action: &TxAction) {
- if !self.sizes.is_empty() {
- let avg = self.sizes.iter().sum::<usize>();
- let avg = avg / self.sizes.len();
- info!(target: "consensus", "Average {:?} size: {:?} Bytes", action, avg);
- }
- if !self.broadcasted_sizes.is_empty() {
- let avg = self.broadcasted_sizes.iter().sum::<usize>();
- let avg = avg / self.broadcasted_sizes.len();
- info!(target: "consensus", "Average {:?} broadcasted size: {:?} Bytes", action, avg);
- }
- if !self.creation_times.is_empty() {
- let avg = self.creation_times.iter().sum::<Duration>();
- let avg = avg / self.creation_times.len() as u32;
- info!(target: "consensus", "Average {:?} creation time: {:?}", action, avg);
- }
- if !self.verify_times.is_empty() {
- let avg = self.verify_times.iter().sum::<Duration>();
- let avg = avg / self.verify_times.len() as u32;
- info!(target: "consensus", "Average {:?} verification time: {:?}", action, avg);
- }
- }
- }
- pub struct Wallet {
- pub keypair: Keypair,
- pub state: ValidatorStatePtr,
- pub money_merkle_tree: MerkleTree,
- pub consensus_staked_merkle_tree: MerkleTree,
- pub consensus_unstaked_merkle_tree: MerkleTree,
- pub wallet: WalletPtr,
- pub coins: Vec<OwnCoin>,
- pub spent_coins: Vec<OwnCoin>,
- }
- impl Wallet {
- async fn new(keypair: Keypair, faucet_pubkeys: &[PublicKey]) -> Result<Self> {
- 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 money_merkle_tree = MerkleTree::new(100);
- let consensus_staked_merkle_tree = MerkleTree::new(100);
- let consensus_unstaked_merkle_tree = MerkleTree::new(100);
- let coins = vec![];
- let spent_coins = vec![];
- Ok(Self {
- keypair,
- state,
- money_merkle_tree,
- consensus_staked_merkle_tree,
- consensus_unstaked_merkle_tree,
- wallet,
- coins,
- spent_coins,
- })
- }
- }
- pub struct ConsensusTestHarness {
- pub holders: HashMap<Holder, Wallet>,
- pub proving_keys: HashMap<&'static str, (ProvingKey, ZkBinary)>,
- pub tx_action_benchmarks: HashMap<TxAction, TxActionBenchmarks>,
- }
- impl ConsensusTestHarness {
- pub async fn new() -> Result<Self> {
- let mut holders = HashMap::new();
- let faucet_kp = Keypair::random(&mut OsRng);
- let faucet_pubkeys = vec![faucet_kp.public];
- let faucet = Wallet::new(faucet_kp, &faucet_pubkeys).await?;
- holders.insert(Holder::Faucet, faucet);
- 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 mut proving_keys = HashMap::new();
- let alice_sled = alice.state.read().await.blockchain.sled_db.clone();
- let mut db_handle = alice.state.read().await.blockchain.contracts.lookup(
- &alice_sled,
- &MONEY_CONTRACT_ID,
- SMART_CONTRACT_ZKAS_DB_NAME,
- )?;
- macro_rules! mkpk {
- ($ns:expr) => {
- let zkas_bytes = db_handle.get(&serialize(&$ns))?.unwrap();
- let (zkbin, _): (Vec<u8>, Vec<u8>) = 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!(MONEY_CONTRACT_ZKAS_MINT_NS_V1);
- mkpk!(MONEY_CONTRACT_ZKAS_BURN_NS_V1);
- db_handle = alice.state.read().await.blockchain.contracts.lookup(
- &alice_sled,
- &CONSENSUS_CONTRACT_ID,
- SMART_CONTRACT_ZKAS_DB_NAME,
- )?;
- mkpk!(CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1);
- mkpk!(CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1);
- mkpk!(CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1);
- holders.insert(Holder::Alice, alice);
- // Build benchmarks map
- let mut tx_action_benchmarks = HashMap::new();
- tx_action_benchmarks.insert(TxAction::Airdrop, TxActionBenchmarks::new());
- tx_action_benchmarks.insert(TxAction::GenesisStake, TxActionBenchmarks::new());
- tx_action_benchmarks.insert(TxAction::Stake, TxActionBenchmarks::new());
- tx_action_benchmarks.insert(TxAction::Proposal, TxActionBenchmarks::new());
- tx_action_benchmarks.insert(TxAction::UnstakeRequest, TxActionBenchmarks::new());
- tx_action_benchmarks.insert(TxAction::Unstake, TxActionBenchmarks::new());
- Ok(Self { holders, proving_keys, tx_action_benchmarks })
- }
- pub fn airdrop_native(
- &mut self,
- value: u64,
- holder: Holder,
- ) -> Result<(Transaction, MoneyTransferParamsV1)> {
- let recipient = self.holders.get_mut(&holder).unwrap().keypair.public;
- let faucet = self.holders.get_mut(&Holder::Faucet).unwrap();
- let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
- let (burn_pk, burn_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Airdrop).unwrap();
- let timer = Instant::now();
- let builder = TransferCallBuilder {
- keypair: faucet.keypair,
- recipient,
- value,
- token_id: *DARK_TOKEN_ID,
- rcpt_spend_hook: pallas::Base::zero(),
- rcpt_user_data: pallas::Base::zero(),
- rcpt_user_data_blind: pallas::Base::random(&mut OsRng),
- change_spend_hook: pallas::Base::zero(),
- change_user_data: pallas::Base::zero(),
- change_user_data_blind: pallas::Base::random(&mut OsRng),
- coins: vec![],
- tree: faucet.money_merkle_tree.clone(),
- mint_zkbin: mint_zkbin.clone(),
- mint_pk: mint_pk.clone(),
- burn_zkbin: burn_zkbin.clone(),
- burn_pk: burn_pk.clone(),
- clear_input: true,
- };
- let debris = builder.build()?;
- let mut data = vec![MoneyFunction::TransferV1 as u8];
- debris.params.encode(&mut data)?;
- let calls = vec![ContractCall { contract_id: *MONEY_CONTRACT_ID, 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];
- tx_action_benchmark.creation_times.push(timer.elapsed());
- // Calculate transaction sizes
- let encoded: Vec<u8> = serialize(&tx);
- let size = std::mem::size_of_val(&*encoded);
- tx_action_benchmark.sizes.push(size);
- let base58 = bs58::encode(&encoded).into_string();
- let size = std::mem::size_of_val(&*base58);
- tx_action_benchmark.broadcasted_sizes.push(size);
- Ok((tx, debris.params))
- }
- pub async fn execute_airdrop_native_tx(
- &mut self,
- holder: Holder,
- tx: Transaction,
- params: &MoneyTransferParamsV1,
- slot: u64,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Airdrop).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
- assert!(erroneous_txs.is_empty());
- wallet.money_merkle_tree.append(&MerkleNode::from(params.outputs[0].coin.inner()));
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub fn genesis_stake(
- &mut self,
- holder: Holder,
- amount: u64,
- ) -> Result<(Transaction, ConsensusGenesisStakeParamsV1)> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let (mint_pk, mint_zkbin) =
- self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
- let tx_action_benchmark =
- self.tx_action_benchmarks.get_mut(&TxAction::GenesisStake).unwrap();
- let timer = Instant::now();
- // Building Consensus::GenesisStake params
- let genesis_stake_call_debris = ConsensusGenesisStakeCallBuilder {
- keypair: wallet.keypair,
- recipient: wallet.keypair.public,
- amount,
- mint_zkbin: mint_zkbin.clone(),
- mint_pk: mint_pk.clone(),
- }
- .build()?;
- let (genesis_stake_params, genesis_stake_proofs) =
- (genesis_stake_call_debris.params, genesis_stake_call_debris.proofs);
- // Building genesis stake tx
- let mut data = vec![ConsensusFunction::GenesisStakeV1 as u8];
- genesis_stake_params.encode(&mut data)?;
- let contract_call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
- let calls = vec![contract_call];
- let proofs = vec![genesis_stake_proofs];
- let mut genesis_stake_tx = Transaction { calls, proofs, signatures: vec![] };
- let sigs = genesis_stake_tx.create_sigs(&mut OsRng, &[wallet.keypair.secret])?;
- genesis_stake_tx.signatures = vec![sigs];
- tx_action_benchmark.creation_times.push(timer.elapsed());
- // Calculate transaction sizes
- let encoded: Vec<u8> = serialize(&genesis_stake_tx);
- let size = std::mem::size_of_val(&*encoded);
- tx_action_benchmark.sizes.push(size);
- let base58 = bs58::encode(&encoded).into_string();
- let size = std::mem::size_of_val(&*base58);
- tx_action_benchmark.broadcasted_sizes.push(size);
- Ok((genesis_stake_tx, genesis_stake_params))
- }
- pub async fn execute_genesis_stake_tx(
- &mut self,
- holder: Holder,
- tx: Transaction,
- params: &ConsensusGenesisStakeParamsV1,
- slot: u64,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark =
- self.tx_action_benchmarks.get_mut(&TxAction::GenesisStake).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
- assert!(erroneous_txs.is_empty());
- wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub async fn execute_erroneous_genesis_stake_txs(
- &mut self,
- holder: Holder,
- txs: Vec<Transaction>,
- slot: u64,
- erroneous: usize,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark =
- self.tx_action_benchmarks.get_mut(&TxAction::GenesisStake).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&txs, slot, false).await?;
- assert_eq!(erroneous_txs.len(), erroneous);
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub async fn stake(
- &mut self,
- holder: Holder,
- slot: u64,
- owncoin: OwnCoin,
- ) -> Result<(Transaction, ConsensusStakeParamsV1, SecretKey)> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let (mint_pk, mint_zkbin) =
- self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
- let (burn_pk, burn_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Stake).unwrap();
- let epoch = wallet.state.read().await.consensus.time_keeper.slot_epoch(slot);
- let timer = Instant::now();
- // Building Money::Stake params
- let money_stake_call_debris = MoneyStakeCallBuilder {
- coin: owncoin.clone(),
- tree: wallet.money_merkle_tree.clone(),
- burn_zkbin: burn_zkbin.clone(),
- burn_pk: burn_pk.clone(),
- }
- .build()?;
- let (
- money_stake_params,
- money_stake_proofs,
- money_stake_secret_key,
- money_stake_value_blind,
- ) = (
- money_stake_call_debris.params,
- money_stake_call_debris.proofs,
- money_stake_call_debris.signature_secret,
- money_stake_call_debris.value_blind,
- );
- // Building Consensus::Stake params
- let consensus_stake_call_debris = ConsensusStakeCallBuilder {
- coin: owncoin,
- epoch,
- value_blind: money_stake_value_blind,
- money_input: money_stake_params.input.clone(),
- mint_zkbin: mint_zkbin.clone(),
- mint_pk: mint_pk.clone(),
- }
- .build()?;
- let (consensus_stake_params, consensus_stake_proofs, consensus_stake_secret_key) = (
- consensus_stake_call_debris.params,
- consensus_stake_call_debris.proofs,
- consensus_stake_call_debris.signature_secret,
- );
- // Building stake tx
- let mut data = vec![MoneyFunction::StakeV1 as u8];
- money_stake_params.encode(&mut data)?;
- let money_call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
- let mut data = vec![ConsensusFunction::StakeV1 as u8];
- consensus_stake_params.encode(&mut data)?;
- let consensus_call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
- let calls = vec![money_call, consensus_call];
- let proofs = vec![money_stake_proofs, consensus_stake_proofs];
- let mut stake_tx = Transaction { calls, proofs, signatures: vec![] };
- let money_sigs = stake_tx.create_sigs(&mut OsRng, &[money_stake_secret_key])?;
- let consensus_sigs = stake_tx.create_sigs(&mut OsRng, &[consensus_stake_secret_key])?;
- stake_tx.signatures = vec![money_sigs, consensus_sigs];
- tx_action_benchmark.creation_times.push(timer.elapsed());
- // Calculate transaction sizes
- let encoded: Vec<u8> = serialize(&stake_tx);
- let size = std::mem::size_of_val(&*encoded);
- tx_action_benchmark.sizes.push(size);
- let base58 = bs58::encode(&encoded).into_string();
- let size = std::mem::size_of_val(&*base58);
- tx_action_benchmark.broadcasted_sizes.push(size);
- Ok((stake_tx, consensus_stake_params, consensus_stake_secret_key))
- }
- pub async fn execute_stake_tx(
- &mut self,
- holder: Holder,
- tx: Transaction,
- params: &ConsensusStakeParamsV1,
- slot: u64,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Stake).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
- assert!(erroneous_txs.is_empty());
- wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub async fn proposal(
- &mut self,
- holder: Holder,
- slot_checkpoint: SlotCheckpoint,
- staked_oc: ConsensusOwnCoin,
- ) -> Result<(Transaction, ConsensusProposalParamsV1, SecretKey, SecretKey)> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let (proposal_pk, proposal_zkbin) =
- self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Proposal).unwrap();
- let timer = Instant::now();
- // Proposals always extend genesis block
- let fork_hash = wallet.state.read().await.consensus.genesis_block;
- // Building Consensus::Propose params
- let proposal_call_debris = ConsensusProposalCallBuilder {
- owncoin: staked_oc,
- slot_checkpoint,
- fork_hash,
- fork_previous_hash: fork_hash,
- merkle_tree: wallet.consensus_staked_merkle_tree.clone(),
- proposal_zkbin: proposal_zkbin.clone(),
- proposal_pk: proposal_pk.clone(),
- }
- .build()?;
- let (params, proofs, output_keypair, signature_secret_key) = (
- proposal_call_debris.params,
- proposal_call_debris.proofs,
- proposal_call_debris.keypair,
- proposal_call_debris.signature_secret,
- );
- let mut data = vec![ConsensusFunction::ProposalV1 as u8];
- params.encode(&mut data)?;
- let call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
- let calls = vec![call];
- let proofs = vec![proofs];
- let mut tx = Transaction { calls, proofs, signatures: vec![] };
- let sigs = tx.create_sigs(&mut OsRng, &[signature_secret_key])?;
- tx.signatures = vec![sigs];
- tx_action_benchmark.creation_times.push(timer.elapsed());
- // Calculate transaction sizes
- let encoded: Vec<u8> = serialize(&tx);
- let size = std::mem::size_of_val(&*encoded);
- tx_action_benchmark.sizes.push(size);
- let base58 = bs58::encode(&encoded).into_string();
- let size = std::mem::size_of_val(&*base58);
- tx_action_benchmark.broadcasted_sizes.push(size);
- Ok((tx, params, signature_secret_key, output_keypair.secret))
- }
- pub async fn execute_proposal_tx(
- &mut self,
- holder: Holder,
- tx: Transaction,
- params: &ConsensusProposalParamsV1,
- slot: u64,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Proposal).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
- assert!(erroneous_txs.is_empty());
- wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub async fn execute_erroneous_proposal_txs(
- &mut self,
- holder: Holder,
- txs: Vec<Transaction>,
- slot: u64,
- erroneous: usize,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Proposal).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&txs, slot, false).await?;
- assert_eq!(erroneous_txs.len(), erroneous);
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub async fn unstake_request(
- &mut self,
- holder: Holder,
- slot: u64,
- staked_oc: ConsensusOwnCoin,
- ) -> Result<(Transaction, ConsensusUnstakeReqParamsV1, SecretKey, SecretKey)> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let (burn_pk, burn_zkbin) =
- self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
- let (mint_pk, mint_zkbin) =
- self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
- let tx_action_benchmark =
- self.tx_action_benchmarks.get_mut(&TxAction::UnstakeRequest).unwrap();
- let epoch = wallet.state.read().await.consensus.time_keeper.slot_epoch(slot);
- let timer = Instant::now();
- // Building Consensus::Unstake params
- let unstake_request_call_debris = ConsensusUnstakeRequestCallBuilder {
- owncoin: staked_oc.clone(),
- epoch,
- tree: wallet.consensus_staked_merkle_tree.clone(),
- burn_zkbin: burn_zkbin.clone(),
- burn_pk: burn_pk.clone(),
- mint_zkbin: mint_zkbin.clone(),
- mint_pk: mint_pk.clone(),
- }
- .build()?;
- let (
- unstake_request_params,
- unstake_request_proofs,
- unstake_request_output_keypair,
- unstake_request_signature_secret_key,
- ) = (
- unstake_request_call_debris.params,
- unstake_request_call_debris.proofs,
- unstake_request_call_debris.keypair,
- unstake_request_call_debris.signature_secret,
- );
- // Building unstake request tx
- let mut data = vec![ConsensusFunction::UnstakeRequestV1 as u8];
- unstake_request_params.encode(&mut data)?;
- let call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
- let calls = vec![call];
- let proofs = vec![unstake_request_proofs];
- let mut unstake_request_tx = Transaction { calls, proofs, signatures: vec![] };
- let sigs =
- unstake_request_tx.create_sigs(&mut OsRng, &[unstake_request_signature_secret_key])?;
- unstake_request_tx.signatures = vec![sigs];
- tx_action_benchmark.creation_times.push(timer.elapsed());
- // Calculate transaction sizes
- let encoded: Vec<u8> = serialize(&unstake_request_tx);
- let size = std::mem::size_of_val(&*encoded);
- tx_action_benchmark.sizes.push(size);
- let base58 = bs58::encode(&encoded).into_string();
- let size = std::mem::size_of_val(&*base58);
- tx_action_benchmark.broadcasted_sizes.push(size);
- Ok((
- unstake_request_tx,
- unstake_request_params,
- unstake_request_output_keypair.secret,
- unstake_request_signature_secret_key,
- ))
- }
- pub async fn execute_unstake_request_tx(
- &mut self,
- holder: Holder,
- tx: Transaction,
- params: &ConsensusUnstakeReqParamsV1,
- slot: u64,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark =
- self.tx_action_benchmarks.get_mut(&TxAction::UnstakeRequest).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
- assert!(erroneous_txs.is_empty());
- wallet.consensus_unstaked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub async fn execute_erroneous_unstake_request_txs(
- &mut self,
- holder: Holder,
- txs: Vec<Transaction>,
- slot: u64,
- erroneous: usize,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark =
- self.tx_action_benchmarks.get_mut(&TxAction::UnstakeRequest).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&txs, slot, false).await?;
- assert_eq!(erroneous_txs.len(), erroneous);
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub fn unstake(
- &mut self,
- holder: Holder,
- staked_oc: ConsensusOwnCoin,
- ) -> Result<(Transaction, MoneyUnstakeParamsV1, SecretKey)> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let (burn_pk, burn_zkbin) =
- self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
- let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Unstake).unwrap();
- let timer = Instant::now();
- // Building Consensus::Unstake params
- let consensus_unstake_call_debris = ConsensusUnstakeCallBuilder {
- owncoin: staked_oc.clone(),
- tree: wallet.consensus_unstaked_merkle_tree.clone(),
- burn_zkbin: burn_zkbin.clone(),
- burn_pk: burn_pk.clone(),
- }
- .build()?;
- let (
- consensus_unstake_params,
- consensus_unstake_proofs,
- consensus_unstake_secret_key,
- consensus_unstake_value_blind,
- ) = (
- consensus_unstake_call_debris.params,
- consensus_unstake_call_debris.proofs,
- consensus_unstake_call_debris.signature_secret,
- consensus_unstake_call_debris.value_blind,
- );
- // Building Money::Unstake params
- let money_unstake_call_debris = MoneyUnstakeCallBuilder {
- owncoin: staked_oc.into(),
- recipient: self.holders.get_mut(&holder).unwrap().keypair.public,
- value_blind: consensus_unstake_value_blind,
- nullifier: consensus_unstake_params.input.nullifier,
- merkle_root: consensus_unstake_params.input.merkle_root,
- signature_public: consensus_unstake_params.input.signature_public,
- mint_zkbin: mint_zkbin.clone(),
- mint_pk: mint_pk.clone(),
- }
- .build()?;
- let (money_unstake_params, money_unstake_proofs) =
- (money_unstake_call_debris.params, money_unstake_call_debris.proofs);
- // Building unstake tx
- let mut data = vec![ConsensusFunction::UnstakeV1 as u8];
- consensus_unstake_params.encode(&mut data)?;
- let consensus_call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
- let mut data = vec![MoneyFunction::UnstakeV1 as u8];
- money_unstake_params.encode(&mut data)?;
- let money_call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
- let calls = vec![consensus_call, money_call];
- let proofs = vec![consensus_unstake_proofs, money_unstake_proofs];
- let mut unstake_tx = Transaction { calls, proofs, signatures: vec![] };
- let consensus_sigs = unstake_tx.create_sigs(&mut OsRng, &[consensus_unstake_secret_key])?;
- let money_sigs = unstake_tx.create_sigs(&mut OsRng, &[consensus_unstake_secret_key])?;
- unstake_tx.signatures = vec![consensus_sigs, money_sigs];
- tx_action_benchmark.creation_times.push(timer.elapsed());
- // Calculate transaction sizes
- let encoded: Vec<u8> = serialize(&unstake_tx);
- let size = ::std::mem::size_of_val(&*encoded);
- tx_action_benchmark.sizes.push(size);
- let base58 = bs58::encode(&encoded).into_string();
- let size = ::std::mem::size_of_val(&*base58);
- tx_action_benchmark.broadcasted_sizes.push(size);
- Ok((unstake_tx, money_unstake_params, consensus_unstake_secret_key))
- }
- pub async fn execute_unstake_tx(
- &mut self,
- holder: Holder,
- tx: Transaction,
- params: &MoneyUnstakeParamsV1,
- slot: u64,
- ) -> Result<()> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Unstake).unwrap();
- let timer = Instant::now();
- let erroneous_txs =
- wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
- assert!(erroneous_txs.is_empty());
- wallet.money_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
- tx_action_benchmark.verify_times.push(timer.elapsed());
- Ok(())
- }
- pub fn gather_owncoin(
- &mut self,
- holder: Holder,
- output: Output,
- secret_key: Option<SecretKey>,
- ) -> Result<OwnCoin> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let leaf_position = wallet.money_merkle_tree.witness().unwrap();
- let secret_key = match secret_key {
- Some(key) => key,
- None => wallet.keypair.secret,
- };
- let note: MoneyNote = output.note.decrypt(&secret_key)?;
- let oc = OwnCoin {
- coin: Coin::from(output.coin),
- note: note.clone(),
- secret: secret_key,
- nullifier: Nullifier::from(poseidon_hash([wallet.keypair.secret.inner(), note.serial])),
- leaf_position,
- };
- Ok(oc)
- }
- pub fn gather_consensus_staked_owncoin(
- &mut self,
- holder: Holder,
- output: ConsensusOutput,
- secret_key: Option<SecretKey>,
- ) -> Result<ConsensusOwnCoin> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let leaf_position = wallet.consensus_staked_merkle_tree.witness().unwrap();
- let secret_key = match secret_key {
- Some(key) => key,
- None => wallet.keypair.secret,
- };
- let note: ConsensusNote = output.note.decrypt(&secret_key)?;
- let oc = ConsensusOwnCoin {
- coin: Coin::from(output.coin),
- note: note.clone(),
- secret: secret_key,
- nullifier: Nullifier::from(poseidon_hash([wallet.keypair.secret.inner(), note.serial])),
- leaf_position,
- };
- Ok(oc)
- }
- pub fn gather_consensus_unstaked_owncoin(
- &mut self,
- holder: Holder,
- output: ConsensusOutput,
- secret_key: Option<SecretKey>,
- ) -> Result<ConsensusOwnCoin> {
- let wallet = self.holders.get_mut(&holder).unwrap();
- let leaf_position = wallet.consensus_unstaked_merkle_tree.witness().unwrap();
- let secret_key = match secret_key {
- Some(key) => key,
- None => wallet.keypair.secret,
- };
- let note: ConsensusNote = output.note.decrypt(&secret_key)?;
- let oc = ConsensusOwnCoin {
- coin: Coin::from(output.coin),
- note: note.clone(),
- secret: secret_key,
- nullifier: Nullifier::from(poseidon_hash([wallet.keypair.secret.inner(), note.serial])),
- leaf_position,
- };
- Ok(oc)
- }
- pub async fn get_slot_checkpoint_by_slot(&self, slot: u64) -> Result<SlotCheckpoint> {
- let faucet = self.holders.get(&Holder::Faucet).unwrap();
- let slot_checkpoint =
- faucet.state.read().await.blockchain.get_slot_checkpoints_by_slot(&[slot])?[0]
- .clone()
- .unwrap();
- Ok(slot_checkpoint)
- }
- pub async fn generate_slot_checkpoint(&self, slot: u64) -> Result<SlotCheckpoint> {
- // We grab the genesis slot to generate slot checkpoint
- // using same consensus parameters
- let faucet = self.holders.get(&Holder::Faucet).unwrap();
- let genesis_block = faucet.state.read().await.consensus.genesis_block;
- let fork_hashes = vec![genesis_block];
- let fork_previous_hashes = vec![genesis_block];
- let genesis_slot = self.get_slot_checkpoint_by_slot(0).await?;
- let slot_checkpoint = SlotCheckpoint {
- slot,
- previous_eta: genesis_slot.previous_eta,
- fork_hashes,
- fork_previous_hashes,
- sigma1: genesis_slot.sigma1,
- sigma2: genesis_slot.sigma2,
- };
- // Store generated slot checkpoint
- for wallet in self.holders.values() {
- wallet.state.write().await.receive_slot_checkpoints(&[slot_checkpoint.clone()]).await?;
- }
- Ok(slot_checkpoint)
- }
- pub fn assert_trees(&self) {
- let faucet = self.holders.get(&Holder::Faucet).unwrap();
- let money_root = faucet.money_merkle_tree.root(0).unwrap();
- let consensus_stake_root = faucet.consensus_staked_merkle_tree.root(0).unwrap();
- let consensus_unstake_root = faucet.consensus_unstaked_merkle_tree.root(0).unwrap();
- for wallet in self.holders.values() {
- assert!(money_root == wallet.money_merkle_tree.root(0).unwrap());
- assert!(consensus_stake_root == wallet.consensus_staked_merkle_tree.root(0).unwrap());
- assert!(
- consensus_unstake_root == wallet.consensus_unstaked_merkle_tree.root(0).unwrap()
- );
- }
- }
- pub fn statistics(&self) {
- info!(target: "consensus", "==================== Statistics ====================");
- for (action, tx_action_benchmark) in &self.tx_action_benchmarks {
- tx_action_benchmark.statistics(action);
- }
- info!(target: "consensus", "====================================================");
- }
- }
|