Skip to content

Commit

Permalink
WIP: StateMachine tests for lazy_vec validation
Browse files Browse the repository at this point in the history
  • Loading branch information
brentstone committed Sep 14, 2022
1 parent 5396df9 commit f3e9984
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 11 deletions.
1 change: 1 addition & 0 deletions shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ pretty_assertions = "0.7.2"
proptest = {git = "https://github.com/heliaxdev/proptest", branch = "tomas/sm"}
test-log = {version = "0.2.7", default-features = false, features = ["trace"]}
tracing-subscriber = {version = "0.3.7", default-features = false, features = ["env-filter", "fmt"]}
namada_tests = {path = "../tests/" }

[build-dependencies]
tonic-build = "0.6.0"
68 changes: 57 additions & 11 deletions shared/src/ledger/storage_api/collections/lazy_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ mod test {

use super::*;
use crate::ledger::storage::testing::TestStorage;
use namada_tests::tx::{tx_host_env, TestTxEnv};

#[test]
fn test_lazy_vec_basics() -> storage_api::Result<()> {
Expand Down Expand Up @@ -602,17 +603,23 @@ mod test {
// `fn apply_transition_on_eager_vec`)
eager_vec: Vec<TestVecItem>,
lazy_vec: LazyVec<TestVecItem>,
storage: TestStorage,
}

#[derive(Clone, Debug)]
struct AbstractLazyVecState(Vec<TestVecItem>);
struct AbstractLazyVecState {
/// Valid LazyVec changes in the current transaction
valid_transitions: Vec<Transition<TestVecItem>>,
/// Valid LazyVec changes committed to storage
committed_transitions: Vec<Transition<TestVecItem>>,
}

/// Possible transitions that can modify a [`LazyVec`]. This roughly
/// corresponds to the methods that have `StorageWrite` access and is very
/// similar to [`Action`]
#[derive(Clone, Debug)]
pub enum Transition<T> {
/// Commit all valid transition in the current transaction
CommitTx,
/// Push a value `T` into a [`LazyVec<T>`]
Push(T),
/// Pop a value from a [`LazyVec<T>`]
Expand All @@ -625,26 +632,35 @@ mod test {
/// value to update the element to
value: T,
},

}

impl AbstractStateMachine for AbstractLazyVecState {
type State = Self;
type Transition = Transition<TestVecItem>;

fn init_state() -> BoxedStrategy<Self::State> {
Just(Self(vec![])).boxed()
Just(Self {
valid_transitions: vec![],
committed_transitions: vec![],
})
.boxed()
}

//

// Apply a random transition to the state
fn transitions(state: &Self::State) -> BoxedStrategy<Self::Transition> {
if state.0.is_empty() {
prop_oneof![arb_test_vec_item().prop_map(Transition::Push)]
let length = state.len();
if length == 0 {
prop_oneof![Just(Transition::CommitTx), arb_test_vec_item().prop_map(Transition::Push)]
.boxed()
} else {
let indices: Vec<Index> =
(0_usize..state.0.len()).map(|ix| ix as Index).collect();
(0..length).collect();
let arb_index = proptest::sample::select(indices);
prop_oneof![
Just(Transition::CommitTx),
Just(Transition::Pop),
arb_test_vec_item().prop_map(Transition::Push),
(arb_index, arb_test_vec_item()).prop_map(
Expand All @@ -659,15 +675,22 @@ mod test {
mut state: Self::State,
transition: &Self::Transition,
) -> Self::State {
apply_transition_on_eager_vec(&mut state.0, transition);
match transition {
Transition::CommitTx => {
let valid_actions_to_commit = std::mem::take(&mut state.valid_transitions);
state.committed_transitions.extend(valid_actions_to_commit.into_iter());
},
_ => state.valid_transitions.push(transition.clone())
}
state
}

fn preconditions(
state: &Self::State,
transition: &Self::Transition,
) -> bool {
if state.0.is_empty() {
let length = state.len();
if length == 0 {
// Ensure that the pop or update transitions are not applied to
// an empty state
!matches!(
Expand All @@ -676,7 +699,7 @@ mod test {
)
} else if let Transition::Update { index, .. } = transition {
// Ensure that the update index is a valid one
*index < (state.0.len() - 1) as Index
*index < (length - 1)
} else {
true
}
Expand All @@ -690,12 +713,12 @@ mod test {
fn init_test(
_initial_state: <Self::Abstract as AbstractStateMachine>::State,
) -> Self::ConcreteState {
tx_host_env::init();
Self {
eager_vec: vec![],
lazy_vec: LazyVec::open(
storage::Key::parse("key_path/arbitrary").unwrap(),
),
storage: TestStorage::default(),
}
}

Expand All @@ -705,8 +728,12 @@ mod test {
) -> Self::ConcreteState {
// Transition application on lazy vec and post-conditions:
match dbg!(&transition) {
Transition::CommitTx => {
// commit the tx without committing the block
tx_host_env::with(|env| env.write_log.commit_tx());
}
Transition::Push(value) => {
let old_len = state.lazy_vec.len(&state.storage).unwrap();
let old_len = state.lazy_vec.len(&tx_host_env::Ctx::new()).unwrap();

state
.lazy_vec
Expand Down Expand Up @@ -811,6 +838,24 @@ mod test {
}
}

/// impl
impl AbstractLazyVecState {
fn len(&self) -> u64 {
let all_transitions = [self.committed_transitions.clone(), self.valid_transitions.clone()].concat();
let mut push_count = 0;
let mut pop_count = 0;

for trans in all_transitions {
match trans {
Transition::CommitTx | Transition::Update{..} => {},
Transition::Push(_) => push_count += 1,
Transition::Pop => pop_count += 1,
}
}
push_count - pop_count
}
}

/// Generate an arbitrary `TestVecItem`
fn arb_test_vec_item() -> impl Strategy<Value = TestVecItem> {
(any::<u64>(), any::<bool>()).prop_map(|(x, y)| TestVecItem { x, y })
Expand All @@ -822,6 +867,7 @@ mod test {
transition: &Transition<TestVecItem>,
) {
match transition {
Transition::CommitTx => {}
Transition::Push(value) => vec.push(value.clone()),
Transition::Pop => {
let _popped = vec.pop();
Expand Down

0 comments on commit f3e9984

Please sign in to comment.