From c34d07c7af2db014ffdb426463195b974852b99a Mon Sep 17 00:00:00 2001 From: antiochp <30642645+antiochp@users.noreply.github.com> Date: Fri, 20 Mar 2020 21:53:00 +0000 Subject: [PATCH] some test coverage for output_pos_list --- chain/src/store.rs | 37 +++++++--- chain/src/types.rs | 2 +- chain/tests/store_output_pos_list.rs | 104 +++++++++++++++++++++++++++ store/src/lmdb.rs | 3 + 4 files changed, 137 insertions(+), 9 deletions(-) create mode 100644 chain/tests/store_output_pos_list.rs diff --git a/chain/src/store.rs b/chain/src/store.rs index 4d2abfd364..f72fd27fcf 100644 --- a/chain/src/store.rs +++ b/chain/src/store.rs @@ -64,9 +64,7 @@ impl ChainStore { db: db_with_version, } } -} -impl ChainStore { /// The current chain head. pub fn head(&self) -> Result { option_to_not_found(self.db.get_ser(&[HEAD_PREFIX]), || "HEAD".to_owned()) @@ -437,6 +435,7 @@ impl Readable for OutputPosEntryVariant { } } +#[derive(Copy, Clone, Debug, PartialEq)] pub enum OutputPosList { Unique { pos: OutputPos }, Multi { head: u64, tail: u64 }, @@ -553,12 +552,34 @@ impl OutputPosList { batch.db.put_ser(&Self::list_key(commit), &list)?; } Some(OutputPosList::Multi { head, tail }) => { - // lookup entry for current head - // create new middle based on current head - // save new middle to db - // create new head based on new_pos - // save updated head to db - // save list itself with head and tail references + if let Some(OutputPosEntry::Head { + pos: current_pos, + next: current_next, + }) = Self::get_entry(batch, commit, head)? + { + let head = OutputPosEntry::Head { + pos: new_pos, + next: current_pos.pos, + }; + let middle = OutputPosEntry::Middle { + pos: current_pos, + next: current_next, + prev: new_pos.pos, + }; + let list = OutputPosList::Multi { + head: new_pos.pos, + tail, + }; + batch + .db + .put_ser(&Self::entry_key(commit, new_pos.pos), &head)?; + batch + .db + .put_ser(&Self::entry_key(commit, current_pos.pos), &middle)?; + batch.db.put_ser(&Self::list_key(commit), &list)?; + } else { + return Err(Error::OtherErr("expected head to be head variant".into())); + } } } Ok(()) diff --git a/chain/src/types.rs b/chain/src/types.rs index 5dc47564cb..ffc9a614f8 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -283,7 +283,7 @@ impl Writeable for CommitPos { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct OutputPos { /// MMR position pub pos: u64, diff --git a/chain/tests/store_output_pos_list.rs b/chain/tests/store_output_pos_list.rs new file mode 100644 index 0000000000..7c1c6cb817 --- /dev/null +++ b/chain/tests/store_output_pos_list.rs @@ -0,0 +1,104 @@ +// Copyright 2020 The Grin Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use grin_chain as chain; +use grin_core as core; +use grin_util as util; + +use crate::chain::store::{ChainStore, OutputPosList}; +use crate::chain::types::OutputPos; +use crate::core::core::OutputFeatures; +use crate::util::secp::pedersen::Commitment; +mod chain_test_helper; + +use self::chain_test_helper::clean_output_dir; + +#[test] +fn test_store_output_pos_list() { + util::init_test_logger(); + + let chain_dir = ".grin_idx_1"; + clean_output_dir(chain_dir); + + let store = ChainStore::new(chain_dir).unwrap(); + + let batch = store.batch().unwrap(); + + let commit = Commitment::from_vec(vec![]); + + assert_eq!(OutputPosList::get_list(&batch, commit), Ok(None)); + + assert_eq!( + OutputPosList::push_entry( + &batch, + commit, + OutputPos { + pos: 1, + height: 1, + features: OutputFeatures::Plain, + }, + ), + Ok(()), + ); + + assert_eq!( + OutputPosList::get_list(&batch, commit), + Ok(Some(OutputPosList::Unique { + pos: OutputPos { + pos: 1, + height: 1, + features: OutputFeatures::Plain + } + })), + ); + + assert_eq!( + OutputPosList::push_entry( + &batch, + commit, + OutputPos { + pos: 2, + height: 2, + features: OutputFeatures::Plain, + }, + ), + Ok(()), + ); + + assert_eq!( + OutputPosList::get_list(&batch, commit), + Ok(Some(OutputPosList::Multi { head: 2, tail: 1 })), + ); + + assert_eq!( + OutputPosList::push_entry( + &batch, + commit, + OutputPos { + pos: 3, + height: 3, + features: OutputFeatures::Plain, + }, + ), + Ok(()), + ); + + assert_eq!( + OutputPosList::get_list(&batch, commit), + Ok(Some(OutputPosList::Multi { head: 3, tail: 1 })), + ); + + // Cleanup chain directory + clean_output_dir(chain_dir); +} diff --git a/store/src/lmdb.rs b/store/src/lmdb.rs index 1419fc7ae5..7dd9a62615 100644 --- a/store/src/lmdb.rs +++ b/store/src/lmdb.rs @@ -47,6 +47,9 @@ pub enum Error { /// Wraps a serialization error for Writeable or Readable #[fail(display = "Serialization Error")] SerErr(String), + /// Other error + #[fail(display = "Other Error")] + OtherErr(String), } impl From for Error {