essential-check 0.15.0

Core logic related to validating Essential state transitions.
Documentation
use essential_check::{
    solution::{self},
    vm::asm,
};
use essential_hash::content_addr;
use essential_types::{
    contract::Contract,
    predicate::{Edge, Node, Predicate, Program},
    solution::{Solution, SolutionSet},
    ContentAddress, PredicateAddress,
};
use std::{collections::HashMap, sync::Arc};
use util::State;

pub mod util;

#[test]
fn test_throughput() {
    use essential_vm::asm::short::*;
    let _ = tracing_subscriber::fmt::try_init();

    let short_n = std::env::var("NUM_SHORT_PROGRAMS")
        .unwrap_or("10".to_string())
        .parse()
        .unwrap();
    let long_n = std::env::var("NUM_LONG_PROGRAMS")
        .unwrap_or("10".to_string())
        .parse()
        .unwrap();

    for name in ["Short", "Long"].iter() {
        let p = match *name {
            "Short" => {
                Program(asm::to_bytes([PUSH(0), PUSH(0), PUSH(1), DATA, PUSH(1), GTE]).collect())
            }
            "Long" => Program(
                asm::to_bytes([
                    PUSH(1),
                    PUSH(5000),
                    PUSH(1),
                    REP,
                    PUSH(0),
                    PUSH(0),
                    PUSH(1),
                    DATA,
                    PUSH(1),
                    GTE,
                    AND,
                    REPE,
                ])
                .collect(),
            ),
            _ => unreachable!(),
        };

        let n = match *name {
            "Short" => short_n,
            "Long" => long_n,
            _ => unreachable!(),
        };

        let p_ca = content_addr(&p);

        let node = |program_address, edge_start| Node {
            program_address,
            edge_start,
        };
        let nodes = vec![node(p_ca.clone(), Edge::MAX)];
        let edges = vec![];
        let predicate_0 = Predicate { nodes, edges };
        let contract_0 = Contract::without_salt(vec![predicate_0]);
        let pred_addr_0 = PredicateAddress {
            contract: content_addr(&contract_0),
            predicate: content_addr(&contract_0.predicates[0]),
        };

        let set = SolutionSet {
            solutions: vec![Solution {
                predicate_to_solve: pred_addr_0.clone(),
                predicate_data: vec![vec![2]],
                state_mutations: vec![],
            }],
        };

        let predicate_0 = Arc::new(contract_0.predicates[0].clone());
        let mut map = HashMap::new();
        map.insert(pred_addr_0.contract.clone(), predicate_0);

        let get_predicate = |addr: &PredicateAddress| map.get(&addr.contract).unwrap().clone();
        let programs: HashMap<ContentAddress, Arc<Program>> =
            vec![(p_ca, Arc::new(p))].into_iter().collect();
        let get_program: Arc<HashMap<_, _>> = Arc::new(programs);

        let set = Arc::new(set);
        let config = Arc::new(solution::CheckPredicateConfig::default());
        let mut gas = 0;
        let s = std::time::Instant::now();
        for _ in 0..n {
            let outputs = solution::check_set_predicates(
                &State::EMPTY,
                set.clone(),
                get_predicate,
                get_program.clone(),
                config.clone(),
                Default::default(),
                &mut Default::default(),
            )
            .unwrap();
            assert!(outputs.gas > 0);
            gas += outputs.gas;
        }
        let elapsed = s.elapsed();

        println!("Gas: {}", gas);
        println!(
            "Check set Elapsed: {:?}, per run: {:?}",
            elapsed,
            elapsed / n
        );

        let mut gas = 0;
        let s = std::time::Instant::now();
        let mut set = Arc::try_unwrap(set).unwrap();
        for _ in 0..n {
            let outputs = solution::check_and_compute_solution_set(
                &State::EMPTY,
                set,
                get_predicate,
                get_program.clone(),
                config.clone(),
                Default::default(),
                &mut Default::default(),
            )
            .unwrap();
            assert!(outputs.0 > 0);
            gas += outputs.0;
            set = outputs.1;
            for s in &mut set.solutions {
                s.state_mutations.clear();
            }
        }
        let elapsed = s.elapsed();

        println!("Gas: {}", gas);
        println!(
            "With compute Elapsed: {:?}, per run: {:?}",
            elapsed,
            elapsed / n
        );

        let mut gas = 0;
        let s = std::time::Instant::now();
        for _ in 0..n {
            let outputs = solution::check_and_compute_solution_set_two_pass(
                &State::EMPTY,
                set,
                get_predicate,
                get_program.clone(),
                config.clone(),
            )
            .unwrap();
            assert!(outputs.0 > 0);
            gas += outputs.0;
            set = outputs.1;
            for s in &mut set.solutions {
                s.state_mutations.clear();
            }
        }
        let elapsed = s.elapsed();

        println!("Gas: {}", gas);
        println!(
            "Two pass Elapsed: {:?}, per run: {:?}",
            elapsed,
            elapsed / n
        );
    }
}