use crate::{
deploy::deploy,
solution::submit_solution,
test_utils::{counter_predicate, counter_solution, deploy_predicate, test_solution},
};
use essential_memory_storage::MemoryStorage;
use essential_state_read_vm::StateRead;
use essential_storage::{QueryState, Storage};
use essential_types::{predicate::Predicate, ContentAddress, PredicateAddress, Word};
use std::time::Duration;
use test_utils::{empty::Empty, sign_contract_with_random_keypair};
use super::RUN_LOOP_FREQUENCY;
async fn run<S>(storage: &S) -> anyhow::Result<()>
where
S: Storage + StateRead + Clone + Send + Sync + 'static,
<S as StateRead>::Future: Send,
<S as StateRead>::Error: Send,
{
let (tx, rx) = tokio::sync::oneshot::channel();
let shutdown = super::Shutdown(rx);
let s = storage.clone();
let jh = tokio::spawn(async move {
super::run(&s, shutdown, RUN_LOOP_FREQUENCY, &Default::default()).await
});
tokio::time::sleep(Duration::from_millis(100)).await;
tx.send(()).unwrap();
jh.await?
}
#[tokio::test]
async fn test_run() {
let (solution, storage) = test_solution(None, 1).await;
let first_state_mutation = &solution.data[0].state_mutations[0];
let mutation_key = first_state_mutation.key.clone();
let mutation_address = solution.data[0].predicate_to_solve.contract.clone();
submit_solution(&storage, solution.clone()).await.unwrap();
let pre_state = storage
.query_state(&mutation_address, &mutation_key)
.await
.unwrap();
assert!(pre_state.is_empty());
run(&storage).await.unwrap();
let post_state = storage
.query_state(&mutation_address, &mutation_key)
.await
.unwrap();
assert_eq!(post_state, vec![42]);
let blocks = storage.list_blocks(None, None, None).await.unwrap();
assert_eq!(blocks.len(), 1);
assert_eq!(blocks[0].solutions.len(), 1);
assert_eq!(blocks[0].solutions[0], solution);
let solution2 = solution; let (solution3, _) = test_solution(Some(storage.clone()), 2).await;
submit_solution(&storage, solution2).await.unwrap();
submit_solution(&storage, solution3.clone()).await.unwrap();
run(&storage).await.unwrap();
let blocks = storage.list_blocks(None, None, None).await.unwrap();
assert_eq!(blocks.len(), 2);
assert_eq!(blocks[1].solutions.len(), 1);
assert!(blocks[1].solutions.iter().any(|s| s == &solution3));
}
#[tokio::test]
async fn test_counter() {
let predicate = counter_predicate(1);
let (predicate_address, storage) = deploy_predicate(predicate.clone()).await;
let solution = counter_solution(predicate_address.clone(), 1).await;
let solution2 = counter_solution(predicate_address.clone(), 2).await;
let solution3 = counter_solution(predicate_address.clone(), 3).await;
let solution4 = counter_solution(predicate_address.clone(), 4).await;
let mutation_key = solution.data[0].state_mutations[0].key.clone();
let solution_clone = solution.clone();
submit_solution(&storage, solution.clone()).await.unwrap();
submit_solution(&storage, solution_clone.clone())
.await
.unwrap();
submit_solution(&storage, solution2.clone()).await.unwrap();
submit_solution(&storage, solution4.clone()).await.unwrap();
let pre_state = storage
.query_state(&predicate_address.contract, &mutation_key)
.await
.unwrap();
assert!(pre_state.is_empty());
run(&storage).await.unwrap();
let post_state = storage
.query_state(&predicate_address.contract, &mutation_key)
.await
.unwrap();
assert_eq!(post_state, vec![2]);
let blocks = storage.list_blocks(None, None, None).await.unwrap();
assert_eq!(blocks.len(), 1);
assert_eq!(blocks[0].solutions.len(), 2);
let solutions = &blocks[0].solutions;
assert!(solutions.contains(&solution));
assert!(solutions.contains(&solution2));
submit_solution(&storage, solution3.clone()).await.unwrap();
submit_solution(&storage, solution4.clone()).await.unwrap();
run(&storage).await.unwrap();
let post_state = storage
.query_state(&predicate_address.contract, &mutation_key)
.await
.unwrap();
assert_eq!(post_state, vec![4]);
let blocks = storage.list_blocks(None, None, None).await.unwrap();
assert_eq!(blocks.len(), 2);
assert_eq!(blocks[1].solutions.len(), 2);
let solutions = &blocks[1].solutions;
assert!(solutions.contains(&solution3));
assert!(solutions.contains(&solution4));
}
fn state_read_error_predicate(salt: Word) -> Predicate {
let mut predicate = Predicate::empty();
predicate.state_read = vec![essential_state_read_vm::asm::to_bytes(vec![
essential_state_read_vm::asm::Stack::Push(1).into(),
essential_state_read_vm::asm::StateSlots::AllocSlots.into(),
essential_state_read_vm::asm::Stack::Push(0).into(),
essential_state_read_vm::asm::Stack::Push(0).into(),
essential_state_read_vm::asm::Stack::Push(0).into(),
essential_state_read_vm::asm::Stack::Push(0).into(),
essential_state_read_vm::asm::Stack::Push(4).into(),
essential_state_read_vm::asm::Stack::Push(1).into(),
essential_state_read_vm::asm::Stack::Push(0).into(),
essential_state_read_vm::asm::StateRead::KeyRange,
essential_state_read_vm::asm::TotalControlFlow::Halt.into(),
])
.collect()];
predicate.constraints = vec![essential_constraint_vm::asm::to_bytes(vec![
essential_constraint_vm::asm::Stack::Push(salt).into(),
essential_constraint_vm::asm::Stack::Pop.into(),
essential_constraint_vm::asm::Stack::Push(2).into(),
essential_constraint_vm::asm::Stack::Push(0).into(),
essential_constraint_vm::asm::Stack::Push(0).into(),
essential_constraint_vm::asm::Access::StateLen.into(),
essential_constraint_vm::asm::Stack::Push(0).into(),
essential_constraint_vm::asm::Pred::Eq.into(),
essential_constraint_vm::asm::Pred::Not.into(),
essential_constraint_vm::asm::TotalControlFlow::JumpForwardIf.into(),
essential_constraint_vm::asm::Stack::Push(0).into(),
essential_constraint_vm::asm::Stack::Push(0).into(),
essential_constraint_vm::asm::Stack::Push(0).into(),
essential_constraint_vm::asm::Access::State.into(),
essential_constraint_vm::asm::Stack::Push(1).into(),
essential_constraint_vm::asm::Alu::Add.into(),
essential_constraint_vm::asm::Stack::Push(0).into(),
essential_constraint_vm::asm::Stack::Push(1).into(),
essential_constraint_vm::asm::Access::State.into(),
essential_constraint_vm::asm::Pred::Eq.into(),
])
.collect()];
predicate
}
#[tokio::test]
async fn test_tracing() {
std::env::set_var("RUST_LOG", "trace");
#[cfg(feature = "tracing")]
let _ = tracing_subscriber::fmt::try_init();
let predicate: Predicate = state_read_error_predicate(1);
let storage = MemoryStorage::default();
let predicate_hash = ContentAddress(essential_hash::hash(&predicate));
let contract = sign_contract_with_random_keypair(vec![predicate]);
let result = deploy(&storage, contract).await.unwrap();
let predicate_address = PredicateAddress {
contract: result,
predicate: predicate_hash,
};
let solution = counter_solution(predicate_address.clone(), 1).await;
submit_solution(&storage, solution.clone()).await.unwrap();
run(&storage).await.unwrap();
}