use crate::{error::Error, index::PadStatus};
use crate::index::error::IndexError;
use crate::index::pad_info::PadInfo;
use crate::storage::ScratchpadAddress;
use mutant_protocol::StorageMode;
use std::ops::Range;
use super::{IndexEntry, MasterIndex};
impl MasterIndex {
pub fn chunk_data(&self, data_bytes: &[u8], mode: StorageMode) -> Vec<Range<usize>> {
let pad_size = mode.scratchpad_size();
let mut ranges = Vec::new();
let mut current_pos = 0;
while current_pos < data_bytes.len() {
let end = std::cmp::min(current_pos + pad_size, data_bytes.len());
ranges.push(current_pos..end);
current_pos = end;
}
ranges
}
pub fn acquire_pads(
&mut self,
data_bytes: &[u8],
chunk_ranges: &[Range<usize>],
) -> Result<Vec<PadInfo>, Error> {
self.generate_pads(data_bytes, chunk_ranges.iter())
}
pub fn generate_pads<'a>(
&mut self,
data_bytes: &'a [u8],
chunk_ranges: impl Iterator<Item = &'a Range<usize>>,
) -> Result<Vec<PadInfo>, Error> {
let ranges: Vec<_> = chunk_ranges.cloned().collect();
let num_pads_needed = ranges.len();
let mut available_pads = self._acquire_pads_internal(num_pads_needed)?;
let mut generated_pads = Vec::with_capacity(num_pads_needed);
for (i, range) in ranges.iter().enumerate() {
let chunk_data_slice = &data_bytes[range.clone()];
let mut pad_info = available_pads.remove(0);
pad_info = pad_info.update_data(chunk_data_slice, i);
generated_pads.push(pad_info);
}
if !available_pads.is_empty() {
return Err(Error::Internal("Unexpected remaining pads detected. This indicates a bug.".to_string()));
}
Ok(generated_pads)
}
pub(crate) fn _acquire_pads_internal(&mut self, num_pads_needed: usize) -> Result<Vec<PadInfo>, Error> {
let free_pads_count = self.free_pads.len();
let pads_to_generate = num_pads_needed.saturating_sub(free_pads_count);
let pads_to_take_from_free = num_pads_needed - pads_to_generate;
if self.free_pads.len() < pads_to_take_from_free {
return Err(Error::Internal(format!(
"Insufficient free pads available. Needed {}, have {}",
pads_to_take_from_free,
self.free_pads.len()
)));
}
let taken_free_pads: Vec<_> = self.free_pads.drain(..pads_to_take_from_free).collect();
let mut generated_new_pads = Vec::with_capacity(pads_to_generate);
for _ in 0..pads_to_generate {
generated_new_pads.push(PadInfo::new(&[], 0));
}
let mut available_pads = taken_free_pads;
available_pads.append(&mut generated_new_pads);
if available_pads.len() < num_pads_needed {
return Err(Error::Internal(format!(
"Failed to acquire enough pads. Needed {}, got {}",
num_pads_needed,
available_pads.len()
)));
}
available_pads.iter_mut().for_each(|p| {
p.last_known_counter += 1;
});
Ok(available_pads)
}
pub fn update_key_with_pads(
&mut self,
key_name: &str,
pads: Vec<PadInfo>,
index_pad: Option<PadInfo>,
) -> Result<(), Error> {
if !self.index.contains_key(key_name) {
return Err(Error::Index(IndexError::KeyNotFound(key_name.to_string())));
}
if let Some(index_pad) = index_pad {
self.index.insert(
key_name.to_string(),
IndexEntry::PublicUpload(index_pad, pads),
);
} else {
self.index.insert(key_name.to_string(), IndexEntry::PrivateKey(pads));
}
self.save(self.network_choice)?;
Ok(())
}
pub async fn recycle_errored_pad(
&mut self,
key_name: &str,
pad_address: &ScratchpadAddress,
) -> Result<PadInfo, Error> {
let mut new_pad = if self.free_pads.is_empty() {
PadInfo::new(&[0u8; 1], 0)
} else {
self.free_pads.pop().unwrap()
};
if let Some(entry) = self.index.get_mut(key_name) {
let result = match entry {
super::IndexEntry::PrivateKey(pads) => {
if let Some(pad_index) = pads.iter().position(|p| p.address == *pad_address) {
let old_pad = pads[pad_index].clone();
Self::update_pad_properties(&mut new_pad, &old_pad);
pads[pad_index] = new_pad.clone();
self.pending_verification_pads.push(old_pad);
Ok(new_pad)
} else {
Err(IndexError::KeyNotFound(format!(
"Pad address {} not found in key {}",
pad_address, key_name
)))
}
}
super::IndexEntry::PublicUpload(index_pad, pads) => {
if *pad_address == index_pad.address {
let old_pad = index_pad.clone();
Self::update_pad_properties(&mut new_pad, &old_pad);
*index_pad = new_pad.clone();
self.pending_verification_pads.push(old_pad);
Ok(new_pad)
} else {
if let Some(data_pad_index) =
pads.iter().position(|p| p.address == *pad_address)
{
let old_pad = pads[data_pad_index].clone();
Self::update_pad_properties(&mut new_pad, &old_pad);
pads[data_pad_index] = new_pad.clone();
self.pending_verification_pads.push(old_pad);
Ok(new_pad)
} else {
Err(IndexError::KeyNotFound(format!(
"Pad address {} not found in key {}",
pad_address, key_name
)))
}
}
}
};
match result {
Ok(ref pad_info) => {
self.save(self.network_choice)?;
Ok(pad_info.clone()) }
Err(e) => Err(e.into()), }
} else {
Err(IndexError::KeyNotFound(key_name.to_string()).into())
}
}
pub fn pad_exists(&self, pad_address: &ScratchpadAddress) -> bool {
let address_exists = self
.free_pads
.iter()
.chain(self.pending_verification_pads.iter())
.any(|p| p.address == *pad_address);
let index_exists = self.index.iter().any(|(_, entry)| match entry {
super::IndexEntry::PrivateKey(pads) => pads.iter().any(|p| p.address == *pad_address),
super::IndexEntry::PublicUpload(index_pad, pads) => {
index_pad.address == *pad_address || pads.iter().any(|p| p.address == *pad_address)
}
});
address_exists || index_exists
}
pub(crate) fn update_pad_properties(target_pad: &mut PadInfo, source_pad: &PadInfo) {
target_pad.checksum = source_pad.checksum;
target_pad.size = source_pad.size;
target_pad.chunk_index = source_pad.chunk_index;
}
pub(crate) fn free_pads(&mut self, pads: Vec<PadInfo>) -> Result<(), Error> {
for mut pad in pads{
if pad.status == PadStatus::Generated {
self.pending_verification_pads.push(pad);
} else {
pad.status = PadStatus::Free;
self.free_pads.push(pad);
}
}
self.save(self.network_choice)?;
Ok(())
}
}