#![forbid(unsafe_code)]
use core::fmt;
use hop_actions::Action;
use hop_channels::{Channel, ChannelError};
#[cfg(feature = "net")]
pub mod net;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BundleReceipt {
pub start_height: u64,
pub end_height: u64,
pub committed: usize,
}
#[derive(Debug)]
pub struct BundleError {
pub action_index: usize,
pub committed: usize,
pub source: ChannelError,
}
impl fmt::Display for BundleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"bundle action {} failed after {} commits: {}",
self.action_index, self.committed, self.source
)
}
}
impl std::error::Error for BundleError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
}
}
pub fn apply_bundle(
channel: &mut Channel,
actions: &[Action],
) -> Result<BundleReceipt, BundleError> {
for (index, action) in actions.iter().enumerate() {
if let Err(source) = action
.validate_for_dimension(channel.dimension())
.map_err(ChannelError::from)
{
return Err(BundleError {
action_index: index,
committed: 0,
source,
});
}
}
let start_height = channel.height();
for (index, action) in actions.iter().enumerate() {
if let Err(source) = channel.apply(action) {
return Err(BundleError {
action_index: index,
committed: index,
source,
});
}
}
Ok(BundleReceipt {
start_height,
end_height: channel.height(),
committed: actions.len(),
})
}