mod util;
use essential_vm::{
asm::{self, short::*, Op},
types::solution::{Mutation, Solution},
Access, BytecodeMapped, Gas, GasLimit, Vm,
};
use std::sync::Arc;
use util::*;
#[test]
fn no_yield() {
let mut vm = Vm::default();
let ops = &[
asm::Stack::Push(6).into(),
asm::Stack::Push(7).into(),
asm::Alu::Mul.into(),
asm::TotalControlFlow::Halt.into(),
];
let op_gas_cost = &|_: &Op| 1;
let spent = vm
.exec_ops(
ops,
test_access().clone(),
&State::EMPTY,
op_gas_cost,
GasLimit::UNLIMITED,
)
.unwrap();
assert_eq!(spent, ops.iter().map(op_gas_cost).sum::<Gas>());
assert_eq!(vm.pc, ops.len() - 1);
assert_eq!(&vm.stack[..], &[42]);
}
#[test]
fn continue_execution() {
let mut vm = Vm::default();
let ops = &[
asm::Stack::Push(6).into(),
asm::Stack::Push(7).into(),
asm::Alu::Mul.into(),
asm::TotalControlFlow::Halt.into(),
];
let op_gas_cost = &|_: &Op| 1;
let spent = vm
.exec_ops(
ops,
test_access().clone(),
&State::EMPTY,
op_gas_cost,
GasLimit::UNLIMITED,
)
.unwrap();
assert_eq!(spent, ops.iter().map(op_gas_cost).sum::<Gas>());
assert_eq!(vm.pc, ops.len() - 1);
assert_eq!(&vm.stack[..], &[42]);
vm.pc = 0;
let ops = &[
asm::Stack::Push(6).into(),
asm::Alu::Div.into(),
asm::TotalControlFlow::Halt.into(),
];
let spent = vm
.exec_ops(
ops,
test_access().clone(),
&State::EMPTY,
&op_gas_cost,
GasLimit::UNLIMITED,
)
.unwrap();
assert_eq!(spent, ops.iter().map(op_gas_cost).sum::<Gas>());
assert_eq!(vm.pc, ops.len() - 1);
assert_eq!(&vm.stack[..], &[7]);
}
#[test]
fn exec_method_behaviours_match() {
let ops: &[Op] = &[
asm::Stack::Push(6).into(),
asm::Stack::Push(7).into(),
asm::Alu::Mul.into(),
asm::TotalControlFlow::Halt.into(),
];
let mut vm_ops = Vm::default();
let spent_ops = vm_ops
.exec_ops(
ops,
test_access().clone(),
&State::EMPTY,
&|_: &Op| 1,
GasLimit::UNLIMITED,
)
.unwrap();
let mut vm_sync_ops = Vm::default();
let spent_sync_ops = vm_sync_ops
.exec_ops(
ops,
test_access().clone(),
&State::EMPTY,
&|_: &Op| 1,
GasLimit::UNLIMITED,
)
.unwrap();
assert_eq!(spent_ops, spent_sync_ops);
assert_eq!(vm_ops, vm_sync_ops);
let mapped: BytecodeMapped = ops.iter().copied().collect();
let mut vm_bc = Vm::default();
let spent_bc = vm_bc
.exec_bytecode(
&mapped,
test_access().clone(),
&State::EMPTY,
&|_: &Op| 1,
GasLimit::UNLIMITED,
)
.unwrap();
assert_eq!(spent_sync_ops, spent_bc);
assert_eq!(vm_sync_ops, vm_bc);
}
#[test]
fn read_pre_post_state() {
let predicate_addr = TEST_PREDICATE_ADDR;
let pre_state = State::new(vec![(
predicate_addr.contract.clone(),
vec![(vec![0, 0, 0, 0], vec![40]), (vec![0, 0, 0, 2], vec![42])],
)]);
let solutions = Arc::new(vec![Solution {
predicate_to_solve: predicate_addr.clone(),
predicate_data: vec![],
state_mutations: vec![Mutation {
key: vec![0, 0, 0, 1],
value: vec![41],
}],
}]);
let solution_index = 0;
let access = Access::new(solutions.clone(), solution_index);
let ops = &[
PUSH(9), ALOC,
PUSH(0), PUSH(0), PUSH(0), PUSH(0), PUSH(4), PUSH(3), PUSH(0), KRNG,
];
let mut vm = Vm::default();
vm.exec_ops(
ops,
access.clone(),
&pre_state,
&|_: &Op| 1,
GasLimit::UNLIMITED,
)
.unwrap();
let pre_state_mem: Vec<_> = vm.memory.into();
let mut post_state = pre_state.clone();
for solution in solutions.iter() {
let contract_addr = &solution.predicate_to_solve.contract;
for Mutation { key, value } in &solution.state_mutations {
post_state.set(contract_addr.clone(), key, value.clone());
}
}
let mut vm = Vm::default();
vm.exec_ops(ops, access, &post_state, &|_: &Op| 1, GasLimit::UNLIMITED)
.unwrap();
let post_state_mem: Vec<_> = vm.memory.into();
assert_eq!(pre_state_mem, vec![6, 1, 7, 0, 7, 1, 40, 42, 0]);
assert_eq!(post_state_mem, vec![6, 1, 7, 1, 8, 1, 40, 41, 42]);
}
#[test]
fn read_sync_state() {
let predicate_addr = TEST_PREDICATE_ADDR;
let pre_state = State::new(vec![(
predicate_addr.contract.clone(),
vec![(vec![0, 0, 0, 0], vec![40]), (vec![0, 0, 0, 2], vec![42])],
)]);
let solutions = Arc::new(vec![Solution {
predicate_to_solve: predicate_addr.clone(),
predicate_data: vec![],
state_mutations: vec![Mutation {
key: vec![0, 0, 0, 1],
value: vec![41],
}],
}]);
let solution_index = 0;
let access = Access::new(solutions.clone(), solution_index);
let ops = &[
PUSH(9), ALOC,
PUSH(0), PUSH(0), PUSH(0), PUSH(0), PUSH(4), PUSH(3), PUSH(0), KRNG,
];
let mut vm = Vm::default();
vm.exec_ops(
ops,
access.clone(),
&pre_state,
&|_: &Op| 1,
GasLimit::UNLIMITED,
)
.unwrap();
let pre_state_mem: Vec<_> = vm.memory.into();
let mut post_state = pre_state.clone();
for solution in solutions.iter() {
let contract_addr = &solution.predicate_to_solve.contract;
for Mutation { key, value } in &solution.state_mutations {
post_state.set(contract_addr.clone(), key, value.clone());
}
}
let mut vm = Vm::default();
vm.exec_ops(ops, access, &post_state, &|_: &Op| 1, GasLimit::UNLIMITED)
.unwrap();
let post_state_mem: Vec<_> = vm.memory.into();
assert_eq!(pre_state_mem, vec![6, 1, 7, 0, 7, 1, 40, 42, 0]);
assert_eq!(post_state_mem, vec![6, 1, 7, 1, 8, 1, 40, 41, 42]);
}
#[test]
fn test_halt() {
let mut vm = Vm::default();
let ops = &[
asm::Stack::Push(6).into(),
asm::Stack::Push(7).into(),
asm::Alu::Mul.into(),
];
let op_gas_cost = &|_: &Op| 1;
vm.exec_ops(
ops,
test_access().clone(),
&State::EMPTY,
op_gas_cost,
GasLimit::UNLIMITED,
)
.unwrap();
assert_eq!(&vm.stack[..], &[42]);
}