mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-10 15:17:57 -05:00
contract/consensus: migrated tests to new contract/test-harness
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1343,6 +1343,7 @@ dependencies = [
|
||||
"bs58",
|
||||
"chacha20poly1305",
|
||||
"darkfi",
|
||||
"darkfi-contract-test-harness",
|
||||
"darkfi-money-contract",
|
||||
"darkfi-sdk",
|
||||
"darkfi-serial",
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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", "====================================================");
|
||||
}
|
||||
}
|
||||
@@ -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)?;
|
||||
|
||||
123
src/contract/test-harness/src/consensus_genesis_stake.rs
Normal file
123
src/contract/test-harness/src/consensus_genesis_stake.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
134
src/contract/test-harness/src/consensus_proposal.rs
Normal file
134
src/contract/test-harness/src/consensus_proposal.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
139
src/contract/test-harness/src/consensus_stake.rs
Normal file
139
src/contract/test-harness/src/consensus_stake.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
136
src/contract/test-harness/src/consensus_unstake.rs
Normal file
136
src/contract/test-harness/src/consensus_unstake.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
147
src/contract/test-harness/src/consensus_unstake_request.rs
Normal file
147
src/contract/test-harness/src/consensus_unstake_request.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
@@ -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!("====================================================");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user