essential-constraint-vm 0.6.0

The Essential constraint checking VM
Documentation
use super::test_utils::ops;
use super::*;
use crate::error::OpError;
use crate::error::StackError;
use crate::exec_ops;
use crate::test_util::test_empty_keys;
use asm::Op;
use essential_constraint_asm as asm;
use essential_types::ContentAddress;
use essential_types::PredicateAddress;
use test_case::test_case;
use test_utils::assert_err;
use test_utils::assert_stack_ok;

#[test_case(
    &[0, 0, 2], &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[3, 99])
    ; "Sanity"
)]
#[test_case(
    &[1, 0, 2], &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[4, 61])
    ; "slot_ix 1"
)]
#[test_case(
    &[1, 1, 1], &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[61])
    ; "slot_ix 1 index 1 len 1"
)]
#[test_case(
    &[1, 1, 0], &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[])
    ; "empty"
)]
#[test_case(
    &[], &[&[3, 99], &[4, 61, 100]] =>
    using assert_err!(OpError::Access(AccessError::MissingArg(MissingAccessArgError::DecVarLen)))
    ; "missing len"
)]
#[test_case(
    &[1], &[&[3, 99], &[4, 61, 100]] =>
    using assert_err!(OpError::Access(AccessError::MissingArg(MissingAccessArgError::DecVarValueIx)))
    ; "missing value_ix"
)]
#[test_case(
    &[0, 1], &[&[3, 99], &[4, 61, 100]] =>
    using assert_err!(OpError::Access(AccessError::MissingArg(MissingAccessArgError::DecVarSlotIx)))
    ; "missing slot_ix"
)]
#[test_case(
    &{
        let mut v = vec![1; Stack::SIZE_LIMIT];
        *v.get_mut(Stack::SIZE_LIMIT - 1).unwrap() = 5;
        v
    },  &[&[], &[3; 6]] =>
    using assert_err!(OpError::Stack(StackError::Overflow))
    ; "values over flow the stack"
)]
#[test_case(
    &[-1, 0, 1], &[&[3]] =>
    using assert_err!(OpError::Access(AccessError::DecisionSlotIxOutOfBounds(-1)))
    ; "negative slot_ix"
)]
#[test_case(
    &[1, -1, 1], &[&[3]] =>
    using assert_err!(OpError::Access(AccessError::InvalidAccessRange))
    ; "negative value_ix"
)]
#[test_case(
    &[0, 0, -1], &[&[3]] =>
    using assert_err!(OpError::Access(AccessError::InvalidAccessRange))
    ; "negative len"
)]
#[test_case(
    &[1, 0, 1], &[&[3]] =>
    using assert_err!(OpError::Access(AccessError::DecisionSlotIxOutOfBounds(1)))
    ; "slot_ix out of bounds"
)]
#[test_case(
    &[0, 1, 1], &[&[3]] =>
    using assert_err!(OpError::Access(AccessError::DecisionValueRangeOutOfBounds(1, 2)))
    ; "value ix out of bounds"
)]
#[test_case(
    &[0, 0, 2], &[&[3]] =>
    using assert_err!(OpError::Access(AccessError::DecisionValueRangeOutOfBounds(0, 2)))
    ; "len out of bounds"
)]
fn test_dec_var(stack: &[Word], dec_vars: &[&[Word]]) -> OpResult<Vec<Word>> {
    let mut s = Stack::default();
    s.extend(stack.to_vec()).unwrap();

    let dec_vars = dec_vars.iter().map(|v| v.to_vec()).collect::<Vec<_>>();
    decision_var(&dec_vars, &mut s).map(|_| s.into())
}

#[test_case(
    &[0], &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[2])
    ; "Sanity"
)]
#[test_case(
    &[1], &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[3])
    ; "slot_ix 1"
)]
#[test_case(
    &[1], &[&[3, 99], &[]] => using assert_stack_ok(&[0])
    ; "empty"
)]
#[test_case(
    &[], &[&[3, 99], &[4, 61, 100]] =>
    using assert_err!(OpError::Access(AccessError::MissingArg(MissingAccessArgError::DecVarSlotIx)))
    ; "missing slot_ix"
)]
#[test_case(
    &[-1], &[&[3]] =>
    using assert_err!(OpError::Access(AccessError::DecisionSlotIxOutOfBounds(-1)))
    ; "negative slot_ix"
)]
#[test_case(
    &[1], &[&[3]] =>
    using assert_err!(OpError::Access(AccessError::DecisionSlotIxOutOfBounds(1)))
    ; "slot_ix out of bounds"
)]
fn test_dec_var_len(stack: &[Word], dec_vars: &[&[Word]]) -> OpResult<Vec<Word>> {
    let mut s = Stack::default();
    s.extend(stack.to_vec()).unwrap();

    let dec_vars = dec_vars.iter().map(|v| v.to_vec()).collect::<Vec<_>>();
    decision_var_len(&dec_vars, &mut s).map(|_| s.into())
}

#[test_case(
    ops![
        asm::Stack::Push(0),
        asm::Stack::Push(0),
        asm::Stack::Push(2),
        asm::Access::DecisionVar,
    ],
    &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[3, 99])
    ; "sanity dec var"
)]
#[test_case(
    ops![
        asm::Stack::Push(1),
        asm::Stack::Push(1),
        asm::Stack::Push(1),
        asm::Access::DecisionVar,
    ],
    &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[61])
    ; "slot_ix 1, value_ix 1, len 1"
)]
#[test_case(
    ops![
        asm::Stack::Push(1),
        asm::Access::DecisionVarLen,
    ],
    &[&[3, 99], &[4, 61, 100]] => using assert_stack_ok(&[3])
    ; "sanity dec var len"
)]
fn test_dec_var_ops(ops: Vec<Op>, dec_vars: &[&[Word]]) -> OpResult<Vec<Word>> {
    let dec_vars = dec_vars.iter().map(|v| v.to_vec()).collect::<Vec<_>>();
    let data = [SolutionData {
        predicate_to_solve: PredicateAddress {
            contract: ContentAddress([0; 32]),
            predicate: ContentAddress([0; 32]),
        },
        decision_variables: dec_vars,
        state_mutations: vec![],
    }];
    let access = Access {
        solution: SolutionAccess {
            data: &data,
            index: 0,
            mutable_keys: test_empty_keys(),
        },
        state_slots: StateSlots::EMPTY,
    };
    exec_ops(&ops, access)
        .map_err(|e| match e {
            crate::error::ConstraintError::InvalidEvaluation(_) => unreachable!(),
            crate::error::ConstraintError::Op(_, e) => e,
        })
        .map(|stack| stack.into())
}