use crate::ports::{
DatabaseTransaction,
RelayerDb,
Transactional,
};
use fuel_core_storage::{
blueprint::plain::Plain,
codec::{
postcard::Postcard,
primitive::Primitive,
},
kv_store::StorageColumn,
structured_storage::TableWithBlueprint,
transactional::{
Modifiable,
StorageTransaction,
},
Error as StorageError,
Mappable,
Result as StorageResult,
StorageAsMut,
StorageMutate,
};
use fuel_core_types::{
blockchain::primitives::DaBlockHeight,
services::relayer::Event,
};
#[repr(u32)]
#[derive(
Copy,
Clone,
Debug,
strum_macros::EnumCount,
strum_macros::IntoStaticStr,
PartialEq,
Eq,
enum_iterator::Sequence,
Hash,
)]
pub enum Column {
Metadata = 0,
History = 1,
}
impl Column {
pub const COUNT: usize = <Self as strum::EnumCount>::COUNT;
pub fn as_u32(&self) -> u32 {
*self as u32
}
}
impl StorageColumn for Column {
fn name(&self) -> String {
let str: &str = self.into();
str.to_string()
}
fn id(&self) -> u32 {
self.as_u32()
}
}
pub struct EventsHistory;
impl Mappable for EventsHistory {
type Key = Self::OwnedKey;
type OwnedKey = DaBlockHeight;
type Value = [Event];
type OwnedValue = Vec<Event>;
}
impl TableWithBlueprint for EventsHistory {
type Blueprint = Plain<Primitive<8>, Postcard>;
type Column = Column;
fn column() -> Column {
Column::History
}
}
impl<T> RelayerDb for T
where
T: Send + Sync,
T: Transactional,
for<'a> T::Transaction<'a>: StorageMutate<EventsHistory, Error = StorageError>,
{
fn insert_events(
&mut self,
da_height: &DaBlockHeight,
events: &[Event],
) -> StorageResult<()> {
let before = self.latest_da_height().unwrap_or_default();
let mut db_tx = self.transaction();
for event in events {
if da_height != &event.da_height() {
return Err(anyhow::anyhow!("Invalid da height").into());
}
}
db_tx.storage::<EventsHistory>().insert(da_height, events)?;
db_tx.commit()?;
let after = self
.latest_da_height()
.expect("DA height must be set at this point");
if after < before {
StorageResult::Err(
anyhow::anyhow!("Block height must be monotonically increasing").into(),
)?
}
Ok(())
}
fn get_finalized_da_height(&self) -> Option<DaBlockHeight> {
self.latest_da_height()
}
}
impl<S> DatabaseTransaction for StorageTransaction<S>
where
S: Modifiable,
{
fn commit(self) -> StorageResult<()> {
self.commit()?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fuel_core_storage::basic_storage_tests!(
EventsHistory,
<EventsHistory as Mappable>::Key::default(),
vec![
Event::Message(Default::default()),
Event::Transaction(Default::default())
]
);
}