#[cfg(feature = "bincode")]
use bincode::{Decode, Encode};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub trait OutputKeyStorage: Send + Sync {
type Error: std::error::Error + Send + 'static;
fn insert(&mut self, key: OutputPubKey, output_id: OutputId) -> Result<(), Self::Error>;
fn get(&self, key: OutputPubKey) -> Result<Option<OutputId>, Self::Error>;
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
pub struct OutputPubKey(pub [u8; 32]);
impl AsRef<[u8]> for OutputPubKey {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
pub struct OutputId {
pub tx_hash: [u8; 32],
pub index: u8,
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod test {
use std::fmt::{Debug, Display};
use test_case::test_case;
use testing_utils::new_temp_dir;
use crate::storage::{
stores::{InMemory, Sled, Sqlite},
OutputId, OutputKeyStorage, OutputPubKey,
};
fn dummy_key() -> OutputPubKey {
OutputPubKey([0; 32])
}
fn dummy_id() -> OutputId {
OutputId {
tx_hash: [0; 32],
index: 13,
}
}
#[test_case(Sled::new(&new_temp_dir(), "invoices", "output keys", "height").unwrap(); "sled")]
#[test_case(InMemory::new(); "in-memory")]
#[test_case(Sqlite::new(":memory:", "invoices", "output keys", "height").unwrap(); "sqlite")]
fn insert_and_check<S, E>(mut store: S)
where
S: OutputKeyStorage<Error = E> + 'static,
E: Debug + Display + Send,
{
let key = dummy_key();
let output_id = dummy_id();
store.insert(key, output_id).unwrap();
assert_eq!(store.get(key).unwrap(), Some(output_id));
}
#[test_case(Sled::new(&new_temp_dir(), "invoices", "output keys", "height").unwrap(); "sled")]
#[test_case(InMemory::new(); "in-memory")]
#[test_case(Sqlite::new(":memory:", "invoices", "output keys", "height").unwrap(); "sqlite")]
fn insert_existing<S, E>(mut store: S)
where
S: OutputKeyStorage<Error = E> + 'static,
E: Debug + Display + Send,
{
let key = dummy_key();
let output_id = dummy_id();
store.insert(key, output_id).unwrap();
assert_eq!(store.get(key).unwrap(), Some(output_id));
store
.insert(key, output_id)
.expect_err("inserting existing key should fail");
assert_eq!(store.get(key).unwrap(), Some(output_id));
}
#[test_case(Sled::new(&new_temp_dir(), "invoices", "output keys", "height").unwrap(); "sled")]
#[test_case(InMemory::new(); "in-memory")]
#[test_case(Sqlite::new(":memory:", "invoices", "output keys", "height").unwrap(); "sqlite")]
fn doesnt_contain_key<S, E>(mut store: S)
where
S: OutputKeyStorage<Error = E> + 'static,
E: Debug + Display + Send,
{
let key = OutputPubKey([1; 32]);
let output_id = dummy_id();
store.insert(key, output_id).unwrap();
assert!(store.get(dummy_key()).unwrap().is_none());
}
}