chia-sdk-test 0.36.0

A wallet simulator and related tooling for testing Chia wallet code.
Documentation
use std::{collections::HashMap, fs::File};

use chia_bls::{SecretKey, Signature};
use chia_consensus::spendbundle_conditions::get_conditions_from_spendbundle;
use chia_protocol::{CoinSpend, SpendBundle};
use chia_sdk_types::TESTNET11_CONSTANTS;
use clvmr::Allocator;
use prettytable::{Table, row};

use crate::Simulator;

#[derive(Debug, Clone)]
pub struct Benchmark {
    pub title: String,
    pub data_keys: Vec<String>,
    pub data: HashMap<String, Vec<u64>>,
}

impl Benchmark {
    pub fn new(title: String) -> Self {
        Self {
            title,
            data_keys: Vec::new(),
            data: HashMap::new(),
        }
    }

    pub fn add_spends(
        &mut self,
        ctx: &mut Allocator,
        sim: &mut Simulator,
        coin_spends: Vec<CoinSpend>,
        key: &str,
        keys: &[SecretKey],
    ) -> anyhow::Result<()> {
        let sb = SpendBundle::new(coin_spends, Signature::default());
        let sb_conds = get_conditions_from_spendbundle(
            ctx,
            &sb,
            u64::MAX,
            sim.height(),
            &TESTNET11_CONSTANTS,
        )?;

        let key = key.to_string();
        if !self.data_keys.contains(&key) {
            self.data_keys.push(key.clone());
        }
        self.data.entry(key).or_default().push(sb_conds.cost);

        sim.spend_coins(sb.coin_spends, keys)?;
        Ok(())
    }

    #[allow(clippy::cast_precision_loss)]
    pub fn print_summary(&self, filename: Option<&str>) {
        let mut table = Table::new();
        table.add_row(row![format!("Cost statistics for {}", self.title)]);
        table.add_row(row!["label", "avg", "n", "min", "max", "median"]);
        for key in &self.data_keys {
            let data = &self.data[key];

            let total = data.iter().sum::<u64>();
            let avg = format!("{:.1}", total as f64 / data.len() as f64);

            let mut sorted = data.clone();
            sorted.sort_unstable();
            let data_min = sorted[0];
            let data_max = sorted[sorted.len() - 1];

            let data_median = if sorted.len().is_multiple_of(2) {
                (sorted[sorted.len() / 2] + sorted[sorted.len() / 2 - 1]) as f64 / 2.0
            } else {
                sorted[sorted.len() / 2] as f64
            };

            table.add_row(row![key, avg, data.len(), data_min, data_max, data_median]);
        }

        table.printstd();
        if let Some(filename) = filename {
            let mut file = File::create(filename).unwrap();
            table.print(&mut file).unwrap();
        }
    }
}