use super::*;
use crate::{
asm,
error::{AccessError, ExecError, OpError},
sync::test_util::*,
types::solution::Solution,
utils::EmptyState,
GasLimit, Op, Vm,
};
macro_rules! check_dec_var {
($d:expr, $s:expr, $f:ident) => {{
$f(&$d, $s)
}};
}
#[test]
fn test_predicate_data() {
let d = vec![vec![42]];
let mut stack = Stack::default();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::MissingArg(MissingAccessArgError::PredDataLen))
));
let mut stack = Stack::default();
stack.push(1).unwrap();
assert!(matches!(
check_dec_var!(d, &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::MissingArg(
MissingAccessArgError::PredDataValueIx
))
));
let d = vec![vec![]];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(1).unwrap();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::PredicateDataValueRangeOutOfBounds(0, 1))
));
let d = vec![vec![42]];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(1).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(stack.pop().unwrap(), 42);
let d = vec![(0..10).collect()];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(1).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(stack.pop().unwrap(), 0);
let d = vec![(0..10).collect(), (10..20).collect()];
let mut stack = Stack::default();
stack.push(1).unwrap();
stack.push(0).unwrap();
stack.push(1).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(stack.pop().unwrap(), 10);
}
#[test]
fn test_predicate_data_at() {
let d = vec![vec![42], vec![9, 20]];
let mut stack = Stack::default();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::MissingArg(MissingAccessArgError::PredDataLen))
));
let mut stack = Stack::default();
stack.push(0).unwrap();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::MissingArg(
MissingAccessArgError::PredDataValueIx
))
));
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::MissingArg(
MissingAccessArgError::PredDataSlotIx
))
));
let mut stack = Stack::default();
stack.push(2).unwrap();
stack.push(0).unwrap();
stack.push(1).unwrap();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::PredicateDataSlotIxOutOfBounds(_))
));
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(1).unwrap();
stack.push(1).unwrap();
assert!(matches!(
check_dec_var!(d, &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::PredicateDataValueRangeOutOfBounds(_, _))
));
let d = vec![vec![]];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(1).unwrap();
assert!(matches!(
check_dec_var!(d, &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::PredicateDataValueRangeOutOfBounds(_, _))
));
let d = vec![vec![]];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(0).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert!(stack.is_empty());
let d = vec![vec![42]];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(1).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(stack.pop().unwrap(), 42);
let d = vec![(0..10).collect()];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(5).unwrap();
stack.push(1).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(stack.pop().unwrap(), 5);
let d = vec![(0..10).collect(), (10..20).collect()];
let mut stack = Stack::default();
stack.push(1).unwrap();
stack.push(5).unwrap();
stack.push(1).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(stack.pop().unwrap(), 15);
}
#[test]
fn test_predicate_data_range() {
let d = vec![vec![42, 43], vec![44, 45, 46]];
let mut stack = Stack::default();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::MissingArg(MissingAccessArgError::PredDataLen))
));
let mut stack = Stack::default();
stack.push(2).unwrap();
stack.push(0).unwrap();
stack.push(0).unwrap();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::PredicateDataSlotIxOutOfBounds(_))
));
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(2).unwrap();
stack.push(1).unwrap();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::PredicateDataValueRangeOutOfBounds(_, _))
));
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(3).unwrap();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::PredicateDataValueRangeOutOfBounds(_, _))
));
let d = vec![vec![]];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(1).unwrap();
assert!(matches!(
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap_err(),
OpError::Access(AccessError::PredicateDataValueRangeOutOfBounds(_, _))
));
let d = vec![vec![42, 43]];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(0).unwrap();
stack.push(2).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(stack.pop().unwrap(), 43);
assert_eq!(stack.pop().unwrap(), 42);
let d = vec![(0..10).collect()];
let mut stack = Stack::default();
stack.push(0).unwrap();
stack.push(5).unwrap();
stack.push(3).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(*stack, vec![5, 6, 7]);
let d = vec![(0..10).collect(), (10..20).collect()];
let mut stack = Stack::default();
stack.push(1).unwrap();
stack.push(5).unwrap();
stack.push(3).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data).unwrap();
assert_eq!(*stack, vec![15, 16, 17]);
}
#[test]
fn test_predicate_data_len() {
let d = vec![vec![42, 43]];
let mut stack = Stack::default();
assert!(matches!(
predicate_data_len(&d.clone(), &mut stack).unwrap_err(),
AccessError::MissingArg(MissingAccessArgError::PredDataSlotIx),
));
let mut stack = Stack::default();
stack.push(1).unwrap();
assert!(matches!(
predicate_data_len(&d.clone(), &mut stack).unwrap_err(),
AccessError::PredicateDataSlotIxOutOfBounds(_)
));
let d = vec![vec![]];
let mut stack = Stack::default();
stack.push(0).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data_len).unwrap();
assert_eq!(stack.pop().unwrap(), 0);
let d = vec![vec![42, 43]];
let mut stack = Stack::default();
stack.push(0).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data_len).unwrap();
assert_eq!(stack.pop().unwrap(), 2);
let d = vec![(0..10).collect(), (10..20).collect()];
let mut stack = Stack::default();
stack.push(1).unwrap();
check_dec_var!(d.clone(), &mut stack, predicate_data_len).unwrap();
assert_eq!(stack.pop().unwrap(), 10);
}
#[test]
fn predicate_data_single_word_ops() {
let access = Access {
solutions: Arc::new(vec![Solution {
predicate_to_solve: TEST_PREDICATE_ADDR,
predicate_data: vec![vec![42]],
state_mutations: Default::default(),
}]),
index: 0,
};
let ops = &[
asm::Stack::Push(0).into(), asm::Stack::Push(0).into(), asm::Stack::Push(1).into(), asm::Access::PredicateData.into(),
];
let op_gas_cost = &|_: &Op| 1;
let mut vm = Vm::default();
vm.exec_ops(ops, access, &EmptyState, op_gas_cost, GasLimit::UNLIMITED)
.unwrap();
assert_eq!(&vm.stack[..], &[42]);
}
#[test]
fn predicate_data_ops() {
let access = Access {
solutions: Arc::new(vec![Solution {
predicate_to_solve: TEST_PREDICATE_ADDR,
predicate_data: vec![vec![7, 8, 9], vec![10, 11, 12]],
state_mutations: Default::default(),
}]),
index: 0,
};
let ops = &[
asm::Stack::Push(0).into(), asm::Stack::Push(0).into(), asm::Stack::Push(3).into(), asm::Access::PredicateData.into(),
];
let op_gas_cost = &|_: &Op| 1;
let mut vm = Vm::default();
vm.exec_ops(ops, access, &EmptyState, op_gas_cost, GasLimit::UNLIMITED)
.unwrap();
assert_eq!(&vm.stack[..], &[7, 8, 9]);
}
#[test]
fn predicate_data_slot_oob_ops() {
let access = Access {
solutions: Arc::new(vec![Solution {
predicate_to_solve: TEST_PREDICATE_ADDR,
predicate_data: vec![vec![42]],
state_mutations: Default::default(),
}]),
index: 0,
};
let ops = &[
asm::Stack::Push(1).into(), asm::Stack::Push(0).into(),
asm::Stack::Push(1).into(),
asm::Access::PredicateData.into(),
];
let op_gas_cost = &|_: &Op| 1;
let res = Vm::default().exec_ops(ops, access, &EmptyState, op_gas_cost, GasLimit::UNLIMITED);
match res {
Err(ExecError(_, OpError::Access(AccessError::PredicateDataSlotIxOutOfBounds(_)))) => {}
_ => panic!("expected predicate data slot out-of-bounds error, got {res:?}"),
}
}
#[test]
fn this_address() {
let ops = &[asm::Access::ThisAddress.into()];
let op_gas_cost = &|_: &Op| 1;
let mut vm = Vm::default();
vm.exec_ops(
ops,
test_access().clone(),
&EmptyState,
op_gas_cost,
GasLimit::UNLIMITED,
)
.unwrap();
let expected_words = word_4_from_u8_32(TEST_PREDICATE_ADDR.predicate.0);
assert_eq!(&vm.stack[..], expected_words);
}
#[test]
fn this_contract_address() {
let ops = &[asm::Access::ThisContractAddress.into()];
let op_gas_cost = &|_: &Op| 1;
let mut vm = Vm::default();
vm.exec_ops(
ops,
test_access().clone(),
&EmptyState,
op_gas_cost,
GasLimit::UNLIMITED,
)
.unwrap();
let expected_words = word_4_from_u8_32(TEST_PREDICATE_ADDR.contract.0);
assert_eq!(&vm.stack[..], expected_words);
}