use super::*;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
pub struct InMemory {
sparse: bool,
position: StoredPosition,
forgotten: Forgotten,
hashes: BTreeMap<Position, BTreeMap<u8, Hash>>,
commitments: BTreeMap<Position, StateCommitment>,
}
impl InMemory {
pub fn new() -> Self {
Self::default()
}
pub fn new_sparse() -> Self {
let mut new = Self::new();
new.sparse = true;
new
}
pub fn position(&self) -> StoredPosition {
self.position
}
pub fn forgotten(&self) -> Forgotten {
self.forgotten
}
pub fn hashes(&self) -> impl Iterator<Item = (Position, u8, Hash)> + '_ {
self.hashes.iter().flat_map(|(position, hashes)| {
hashes
.iter()
.map(move |(height, hash)| (*position, *height, *hash))
})
}
pub fn commitments(&self) -> impl Iterator<Item = (Position, StateCommitment)> + '_ {
self.commitments
.iter()
.map(|(position, commitment)| (*position, *commitment))
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Error)]
pub enum Error {
#[error("refusing to overwrite existing commitment at position {position:?}")]
DuplicateWriteCommitment {
position: Position,
},
#[error("repeated write of hash at position {position:?}, height {height}")]
RepeatedWriteHash {
position: Position,
height: u8,
},
#[error("hash overwritten with different hash at position {position:?}, height {height}")]
OverwrittenHash {
position: Position,
height: u8,
},
#[error("recalculable hash marked essential at position {position:?}, height {height}")]
EssentialHashHasChildren {
position: Position,
height: u8,
},
#[error("set position did not increase from {previous:?} to {new:?}")]
PositionDidNotIncrease {
previous: StoredPosition,
new: StoredPosition,
},
#[error("set forgotten version did not increase from {previous:?} to {new:?}")]
ForgottenDidNotIncrease {
previous: Forgotten,
new: Forgotten,
},
}
impl Read for InMemory {
type Error = Error;
type HashesIter<'a> =
Box<dyn Iterator<Item = Result<(Position, u8, Hash), Self::Error>> + Send + 'a>;
type CommitmentsIter<'a> =
Box<dyn Iterator<Item = Result<(Position, StateCommitment), Self::Error>> + Send + 'a>;
fn position(&mut self) -> Result<StoredPosition, Self::Error> {
Ok(self.position)
}
fn forgotten(&mut self) -> Result<Forgotten, Self::Error> {
Ok(self.forgotten)
}
fn hash(&mut self, position: Position, height: u8) -> Result<Option<Hash>, Self::Error> {
Ok(self
.hashes
.get(&position)
.and_then(|h| h.get(&height))
.cloned())
}
fn hashes(&mut self) -> Self::HashesIter<'_> {
Box::new(InMemory::hashes(self).map(Ok))
}
fn commitment(&mut self, position: Position) -> Result<Option<StateCommitment>, Self::Error> {
Ok(self.commitments.get(&position).cloned())
}
fn commitments(&mut self) -> Self::CommitmentsIter<'_> {
Box::new(InMemory::commitments(self).map(Ok))
}
}
impl Write for InMemory {
fn add_hash(
&mut self,
position: Position,
height: u8,
hash: Hash,
essential: bool,
) -> Result<(), Self::Error> {
if !essential && self.sparse {
return Ok(());
}
let column = self.hashes.entry(position).or_default();
match column.entry(height) {
Entry::Vacant(e) => {
e.insert(hash);
}
Entry::Occupied(e) => {
if !essential {
return Err(Error::RepeatedWriteHash { position, height });
}
if *e.into_mut() != hash {
return Err(Error::OverwrittenHash { position, height });
}
}
};
Ok(())
}
fn add_commitment(
&mut self,
position: Position,
commitment: StateCommitment,
) -> Result<(), Self::Error> {
match self.commitments.entry(position) {
Entry::Vacant(e) => e.insert(commitment),
Entry::Occupied(_) => return Err(Error::DuplicateWriteCommitment { position }),
};
Ok(())
}
fn delete_range(
&mut self,
below_height: u8,
range: Range<Position>,
) -> Result<(), Self::Error> {
let empty_columns: Vec<Position> = self
.hashes
.range_mut(range.clone())
.filter_map(|(&position, column)| {
*column = column.split_off(&below_height);
if column.is_empty() {
Some(position)
} else {
None
}
})
.collect();
for position in empty_columns {
self.hashes.remove(&position);
}
let commitments_to_delete: Vec<Position> = self
.commitments
.range(range)
.map(|(&position, _)| position)
.collect();
for position in commitments_to_delete {
self.commitments.remove(&position);
}
Ok(())
}
fn set_position(&mut self, position: StoredPosition) -> Result<(), Self::Error> {
if self.position >= position {
return Err(Error::PositionDidNotIncrease {
previous: self.position,
new: position,
});
}
self.position = position;
Ok(())
}
fn set_forgotten(&mut self, forgotten: Forgotten) -> Result<(), Self::Error> {
if self.forgotten >= forgotten {
return Err(Error::ForgottenDidNotIncrease {
previous: self.forgotten,
new: forgotten,
});
}
self.forgotten = forgotten;
Ok(())
}
}