contract/consensus: migrated tests to new contract/test-harness

This commit is contained in:
aggstam
2023-06-14 19:02:28 +03:00
parent 33c286f19f
commit 410ab42b54
11 changed files with 851 additions and 1005 deletions

1
Cargo.lock generated
View File

@@ -1343,6 +1343,7 @@ dependencies = [
"bs58",
"chacha20poly1305",
"darkfi",
"darkfi-contract-test-harness",
"darkfi-money-contract",
"darkfi-sdk",
"darkfi-serial",

View File

@@ -29,6 +29,7 @@ async-std = {version = "1.12.0", features = ["attributes"]}
bs58 = "0.5.0"
darkfi = {path = "../../../", features = ["tx", "blockchain"]}
darkfi-money-contract = { path = "../money", features = ["client", "no-entrypoint"] }
darkfi-contract-test-harness = {path = "../test-harness"}
simplelog = "0.12.1"
sled = "0.34.7"

View File

@@ -28,14 +28,15 @@ use darkfi::Result;
use log::info;
use darkfi_consensus_contract::model::{calculate_grace_period, EPOCH_LENGTH, REWARD};
mod harness;
use harness::{init_logger, ConsensusTestHarness, Holder};
use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
#[async_std::test]
async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
init_logger();
// Holders this test will use
const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
// Some numbers we want to assert
const ALICE_INITIAL: u64 = 1000;
@@ -43,7 +44,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
let mut current_slot = 0;
// Initialize harness
let mut th = ConsensusTestHarness::new().await?;
let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
// Now Alice can craate a genesis stake transaction to mint
// some staked coins
@@ -85,7 +86,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ================================");
th.execute_genesis_stake_tx(
Holder::Faucet,
genesis_stake_tx.clone(),
&genesis_stake_tx,
&genesis_stake_params,
current_slot,
)
@@ -96,13 +97,13 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Alice] ================================");
th.execute_genesis_stake_tx(
Holder::Alice,
genesis_stake_tx,
&genesis_stake_tx,
&genesis_stake_params,
current_slot,
)
.await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new staked owncoin
let alice_staked_oc =
@@ -128,15 +129,14 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ===========================");
info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
info!(target: "consensus", "[Faucet] ===========================");
th.execute_proposal_tx(Holder::Faucet, proposal_tx.clone(), &proposal_params, current_slot)
.await?;
th.execute_proposal_tx(Holder::Faucet, &proposal_tx, &proposal_params, current_slot).await?;
info!(target: "consensus", "[Alice] ===========================");
info!(target: "consensus", "[Alice] Executing Alice proposal tx");
info!(target: "consensus", "[Alice] ===========================");
th.execute_proposal_tx(Holder::Alice, proposal_tx, &proposal_params, current_slot).await?;
th.execute_proposal_tx(Holder::Alice, &proposal_tx, &proposal_params, current_slot).await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new staked owncoin which includes the reward
let alice_rewarded_staked_oc = th.gather_consensus_staked_owncoin(
@@ -168,7 +168,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ==================================");
th.execute_unstake_request_tx(
Holder::Faucet,
unstake_request_tx.clone(),
&unstake_request_tx,
&unstake_request_params,
current_slot,
)
@@ -179,13 +179,13 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Alice] ==================================");
th.execute_unstake_request_tx(
Holder::Alice,
unstake_request_tx,
&unstake_request_tx,
&unstake_request_params,
current_slot,
)
.await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new unstake request owncoin
let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
@@ -210,15 +210,14 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ==========================");
info!(target: "consensus", "[Faucet] Executing Alice unstake tx");
info!(target: "consensus", "[Faucet] ==========================");
th.execute_unstake_tx(Holder::Faucet, unstake_tx.clone(), &unstake_params, current_slot)
.await?;
th.execute_unstake_tx(Holder::Faucet, &unstake_tx, &unstake_params, current_slot).await?;
info!(target: "consensus", "[Alice] ==========================");
info!(target: "consensus", "[Alice] Executing Alice unstake tx");
info!(target: "consensus", "[Alice] ==========================");
th.execute_unstake_tx(Holder::Alice, unstake_tx, &unstake_params, current_slot).await?;
th.execute_unstake_tx(Holder::Alice, &unstake_tx, &unstake_params, current_slot).await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new unstaked owncoin
let alice_unstaked_oc = th.gather_owncoin(Holder::Alice, unstake_params.output, None)?;

View File

@@ -1,954 +0,0 @@
/* 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::{
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.mark().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.mark().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.mark().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", "====================================================");
}
}

View File

@@ -30,14 +30,15 @@ use darkfi::Result;
use log::info;
use darkfi_consensus_contract::model::{calculate_grace_period, EPOCH_LENGTH, REWARD};
mod harness;
use harness::{init_logger, ConsensusTestHarness, Holder};
use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
#[async_std::test]
async fn consensus_contract_stake_unstake() -> Result<()> {
init_logger();
// Holders this test will use
const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
// Some numbers we want to assert
const ALICE_AIRDROP: u64 = 1000;
@@ -45,7 +46,9 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
let mut current_slot = 1;
// Initialize harness
let mut th = ConsensusTestHarness::new().await?;
let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
// Now Alice can airdrop some native tokens to herself
info!(target: "consensus", "[Faucet] =========================");
info!(target: "consensus", "[Faucet] Building Alice airdrop tx");
info!(target: "consensus", "[Faucet] =========================");
@@ -54,15 +57,15 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ==========================");
info!(target: "consensus", "[Faucet] Executing Alice airdrop tx");
info!(target: "consensus", "[Faucet] ==========================");
th.execute_airdrop_native_tx(Holder::Faucet, airdrop_tx.clone(), &airdrop_params, current_slot)
th.execute_airdrop_native_tx(Holder::Faucet, &airdrop_tx, &airdrop_params, current_slot)
.await?;
info!(target: "consensus", "[Alice] ==========================");
info!(target: "consensus", "[Alice] Executing Alice airdrop tx");
info!(target: "consensus", "[Alice] ==========================");
th.execute_airdrop_native_tx(Holder::Alice, airdrop_tx, &airdrop_params, current_slot).await?;
th.execute_airdrop_native_tx(Holder::Alice, &airdrop_tx, &airdrop_params, current_slot).await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new owncoin
let alice_oc = th.gather_owncoin(Holder::Alice, airdrop_params.outputs[0].clone(), None)?;
@@ -77,14 +80,14 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ========================");
info!(target: "consensus", "[Faucet] Executing Alice stake tx");
info!(target: "consensus", "[Faucet] ========================");
th.execute_stake_tx(Holder::Faucet, stake_tx.clone(), &stake_params, current_slot).await?;
th.execute_stake_tx(Holder::Faucet, &stake_tx, &stake_params, current_slot).await?;
info!(target: "consensus", "[Alice] ========================");
info!(target: "consensus", "[Alice] Executing Alice stake tx");
info!(target: "consensus", "[Alice] ========================");
th.execute_stake_tx(Holder::Alice, stake_tx, &stake_params, current_slot).await?;
th.execute_stake_tx(Holder::Alice, &stake_tx, &stake_params, current_slot).await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new staked owncoin
let alice_staked_oc = th.gather_consensus_staked_owncoin(
@@ -128,15 +131,14 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ===========================");
info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
info!(target: "consensus", "[Faucet] ===========================");
th.execute_proposal_tx(Holder::Faucet, proposal_tx.clone(), &proposal_params, current_slot)
.await?;
th.execute_proposal_tx(Holder::Faucet, &proposal_tx, &proposal_params, current_slot).await?;
info!(target: "consensus", "[Alice] ===========================");
info!(target: "consensus", "[Alice] Executing Alice proposal tx");
info!(target: "consensus", "[Alice] ===========================");
th.execute_proposal_tx(Holder::Alice, proposal_tx, &proposal_params, current_slot).await?;
th.execute_proposal_tx(Holder::Alice, &proposal_tx, &proposal_params, current_slot).await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new staked owncoin which includes the reward
let alice_rewarded_staked_oc = th.gather_consensus_staked_owncoin(
@@ -168,7 +170,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ==================================");
th.execute_unstake_request_tx(
Holder::Faucet,
unstake_request_tx.clone(),
&unstake_request_tx,
&unstake_request_params,
current_slot,
)
@@ -179,13 +181,13 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Alice] ==================================");
th.execute_unstake_request_tx(
Holder::Alice,
unstake_request_tx,
&unstake_request_tx,
&unstake_request_params,
current_slot,
)
.await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new unstake request owncoin
let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
@@ -234,15 +236,14 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Faucet] ==========================");
info!(target: "consensus", "[Faucet] Executing Alice unstake tx");
info!(target: "consensus", "[Faucet] ==========================");
th.execute_unstake_tx(Holder::Faucet, unstake_tx.clone(), &unstake_params, current_slot)
.await?;
th.execute_unstake_tx(Holder::Faucet, &unstake_tx, &unstake_params, current_slot).await?;
info!(target: "consensus", "[Alice] ==========================");
info!(target: "consensus", "[Alice] Executing Alice unstake tx");
info!(target: "consensus", "[Alice] ==========================");
th.execute_unstake_tx(Holder::Alice, unstake_tx, &unstake_params, current_slot).await?;
th.execute_unstake_tx(Holder::Alice, &unstake_tx, &unstake_params, current_slot).await?;
th.assert_trees();
th.assert_trees(&HOLDERS);
// Gather new unstaked owncoin
let alice_unstaked_oc = th.gather_owncoin(Holder::Alice, unstake_params.output, None)?;

View File

@@ -0,0 +1,123 @@
/* 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::time::Instant;
use darkfi::{tx::Transaction, Result};
use darkfi_consensus_contract::{
client::genesis_stake_v1::ConsensusGenesisStakeCallBuilder,
model::ConsensusGenesisStakeParamsV1, ConsensusFunction,
};
use darkfi_money_contract::CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1;
use darkfi_sdk::{
crypto::{MerkleNode, CONSENSUS_CONTRACT_ID},
ContractCall,
};
use darkfi_serial::{serialize, Encodable};
use rand::rngs::OsRng;
use super::{Holder, TestHarness, TxAction};
impl TestHarness {
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::ConsensusGenesisStake).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::ConsensusGenesisStake).unwrap();
let timer = Instant::now();
let erroneous_txs =
wallet.state.read().await.verify_transactions(&[tx.clone()], 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::ConsensusGenesisStake).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(())
}
}

View File

@@ -0,0 +1,134 @@
/* 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::time::Instant;
use darkfi::{consensus::SlotCheckpoint, tx::Transaction, Result};
use darkfi_consensus_contract::{
client::proposal_v1::ConsensusProposalCallBuilder, model::ConsensusProposalParamsV1,
ConsensusFunction,
};
use darkfi_money_contract::{client::ConsensusOwnCoin, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1};
use darkfi_sdk::{
crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID},
ContractCall,
};
use darkfi_serial::{serialize, Encodable};
use rand::rngs::OsRng;
use super::{Holder, TestHarness, TxAction};
impl TestHarness {
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::ConsensusProposal).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::ConsensusProposal).unwrap();
let timer = Instant::now();
let erroneous_txs =
wallet.state.read().await.verify_transactions(&[tx.clone()], 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::ConsensusProposal).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(())
}
}

View File

@@ -0,0 +1,139 @@
/* 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::time::Instant;
use darkfi::{tx::Transaction, Result};
use darkfi_consensus_contract::{client::stake_v1::ConsensusStakeCallBuilder, ConsensusFunction};
use darkfi_money_contract::{
client::{stake_v1::MoneyStakeCallBuilder, OwnCoin},
model::ConsensusStakeParamsV1,
MoneyFunction, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
};
use darkfi_sdk::{
crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID, MONEY_CONTRACT_ID},
ContractCall,
};
use darkfi_serial::{serialize, Encodable};
use rand::rngs::OsRng;
use super::{Holder, TestHarness, TxAction};
impl TestHarness {
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::ConsensusStake).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::ConsensusStake).unwrap();
let timer = Instant::now();
let erroneous_txs =
wallet.state.read().await.verify_transactions(&[tx.clone()], 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(())
}
}

View File

@@ -0,0 +1,136 @@
/* 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::time::Instant;
use darkfi::{tx::Transaction, Result};
use darkfi_consensus_contract::{
client::unstake_v1::ConsensusUnstakeCallBuilder, ConsensusFunction,
};
use darkfi_money_contract::{
client::{unstake_v1::MoneyUnstakeCallBuilder, ConsensusOwnCoin},
model::MoneyUnstakeParamsV1,
MoneyFunction, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
};
use darkfi_sdk::{
crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID, MONEY_CONTRACT_ID},
ContractCall,
};
use darkfi_serial::{serialize, Encodable};
use rand::rngs::OsRng;
use super::{Holder, TestHarness, TxAction};
impl TestHarness {
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::ConsensusUnstake).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::ConsensusUnstake).unwrap();
let timer = Instant::now();
let erroneous_txs =
wallet.state.read().await.verify_transactions(&[tx.clone()], 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(())
}
}

View File

@@ -0,0 +1,147 @@
/* 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::time::Instant;
use darkfi::{tx::Transaction, Result};
use darkfi_consensus_contract::{
client::unstake_request_v1::ConsensusUnstakeRequestCallBuilder, ConsensusFunction,
};
use darkfi_money_contract::{
client::ConsensusOwnCoin, model::ConsensusUnstakeReqParamsV1,
CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
};
use darkfi_sdk::{
crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID},
ContractCall,
};
use darkfi_serial::{serialize, Encodable};
use rand::rngs::OsRng;
use super::{Holder, TestHarness, TxAction};
impl TestHarness {
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::ConsensusUnstakeRequest).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::ConsensusUnstakeRequest).unwrap();
let timer = Instant::now();
let erroneous_txs =
wallet.state.read().await.verify_transactions(&[tx.clone()], 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::ConsensusUnstakeRequest).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(())
}
}

View File

@@ -20,8 +20,8 @@ use std::collections::HashMap;
use darkfi::{
consensus::{
ValidatorState, ValidatorStatePtr, TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES,
TESTNET_GENESIS_TIMESTAMP, TESTNET_INITIAL_DISTRIBUTION,
SlotCheckpoint, ValidatorState, ValidatorStatePtr, TESTNET_BOOTSTRAP_TIMESTAMP,
TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP, TESTNET_INITIAL_DISTRIBUTION,
},
runtime::vm_runtime::SMART_CONTRACT_ZKAS_DB_NAME,
wallet::{WalletDb, WalletPtr},
@@ -35,8 +35,8 @@ use darkfi_dao_contract::{
DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS,
};
use darkfi_money_contract::{
client::{MoneyNote, OwnCoin},
model::Output,
client::{ConsensusNote, ConsensusOwnCoin, MoneyNote, OwnCoin},
model::{Coin, ConsensusOutput, Output},
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, MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1,
@@ -54,6 +54,11 @@ mod benchmarks;
use benchmarks::TxActionBenchmarks;
mod vks;
mod consensus_genesis_stake;
mod consensus_proposal;
mod consensus_stake;
mod consensus_unstake;
mod consensus_unstake_request;
mod money_airdrop;
mod money_token;
@@ -92,6 +97,11 @@ pub enum TxAction {
MoneyGenesisMint,
MoneyTransfer,
MoneyOtcSwap,
ConsensusGenesisStake,
ConsensusStake,
ConsensusProposal,
ConsensusUnstakeRequest,
ConsensusUnstake,
}
pub struct Wallet {
@@ -244,6 +254,11 @@ impl TestHarness {
tx_action_benchmarks.insert(TxAction::MoneyGenesisMint, TxActionBenchmarks::new());
tx_action_benchmarks.insert(TxAction::MoneyOtcSwap, TxActionBenchmarks::new());
tx_action_benchmarks.insert(TxAction::MoneyTransfer, TxActionBenchmarks::new());
tx_action_benchmarks.insert(TxAction::ConsensusGenesisStake, TxActionBenchmarks::new());
tx_action_benchmarks.insert(TxAction::ConsensusStake, TxActionBenchmarks::new());
tx_action_benchmarks.insert(TxAction::ConsensusProposal, TxActionBenchmarks::new());
tx_action_benchmarks.insert(TxAction::ConsensusUnstakeRequest, TxActionBenchmarks::new());
tx_action_benchmarks.insert(TxAction::ConsensusUnstake, TxActionBenchmarks::new());
// Alice jumps down the rabbit hole
holders.insert(Holder::Alice, alice);
@@ -251,14 +266,6 @@ impl TestHarness {
Ok(Self { holders, proving_keys, tx_action_benchmarks })
}
pub fn statistics(&self) {
info!("==================== Statistics ====================");
for (action, tx_action_benchmark) in &self.tx_action_benchmarks {
tx_action_benchmark.statistics(action);
}
info!("====================================================");
}
pub fn gather_owncoin(
&mut self,
holder: Holder,
@@ -285,4 +292,116 @@ impl TestHarness {
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.mark().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.mark().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, holders: &[Holder]) {
assert!(holders.len() > 1);
// Gather wallets
let mut wallets = vec![];
for holder in holders {
wallets.push(self.holders.get(holder).unwrap());
}
// Compare trees
let wallet = wallets[0];
let money_root = wallet.money_merkle_tree.root(0).unwrap();
let consensus_stake_root = wallet.consensus_staked_merkle_tree.root(0).unwrap();
let consensus_unstake_root = wallet.consensus_unstaked_merkle_tree.root(0).unwrap();
for wallet in &wallets[1..] {
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!("==================== Statistics ====================");
for (action, tx_action_benchmark) in &self.tx_action_benchmarks {
tx_action_benchmark.statistics(action);
}
info!("====================================================");
}
}