#![no_main]
use arbitrary::{Arbitrary, Unstructured};
use commonware_runtime::{deterministic, Metrics, Runner, Storage};
use commonware_storage::ordinal::{Config, Ordinal};
use commonware_utils::sequence::FixedBytes;
use core::num::{NonZeroU64, NonZeroUsize};
use libfuzzer_sys::fuzz_target;
#[derive(Arbitrary, Clone)]
struct Entry {
index: u64,
value: [u8; 32],
}
#[derive(Arbitrary, Clone)]
struct FuzzInput {
partition_seed: u64,
items_per_blob_hint: u16,
write_buffer_hint: u16,
replay_buffer_hint: u16,
prune_offset: u64,
selection_hint: u16,
entries: Vec<Entry>,
}
async fn run_case(context: deterministic::Context, input: FuzzInput) {
let FuzzInput {
partition_seed,
items_per_blob_hint,
write_buffer_hint,
replay_buffer_hint,
prune_offset,
selection_hint,
entries,
} = input;
let items_per_blob_raw = u64::from(items_per_blob_hint % 64).saturating_add(1);
let Some(items_per_blob) = NonZeroU64::new(items_per_blob_raw) else {
return;
};
let write_buffer_raw = usize::from(write_buffer_hint % 4095).saturating_add(1);
let Some(write_buffer) = NonZeroUsize::new(write_buffer_raw) else {
return;
};
let replay_buffer_raw = usize::from(replay_buffer_hint % 4095).saturating_add(1);
let Some(replay_buffer) = NonZeroUsize::new(replay_buffer_raw) else {
return;
};
let partition = format!("generated_25_prune_fuzz_{partition_seed}");
let config = Config {
partition: partition.clone(),
items_per_blob,
write_buffer,
replay_buffer,
};
let ordinal_context: deterministic::Context = context.with_label("ordinal");
let mut store: Ordinal<deterministic::Context, FixedBytes<32>> =
match Ordinal::init(ordinal_context, config).await {
Ok(store) => store,
Err(_) => return,
};
let mut indices = Vec::new();
for entry in entries.into_iter().take(32) {
let index = entry.index % 4096;
if store
.put(index, FixedBytes::new(entry.value))
.await
.is_err()
{
return;
}
indices.push(index);
}
if indices.is_empty() {
return;
}
if store.sync().await.is_err() {
return;
}
let choice = usize::from(selection_hint) % indices.len();
let target_index = indices[choice];
let items_per_blob_value = items_per_blob.get();
let target_section = target_index / items_per_blob_value;
let section_name = target_section.to_be_bytes();
if context
.remove(&partition, Some(§ion_name))
.await
.is_err()
{
return;
}
let prune_min_base = target_section
.saturating_add(1)
.saturating_mul(items_per_blob_value);
let prune_min = prune_min_base.saturating_add(prune_offset % items_per_blob_value);
let _ = store.prune(prune_min).await;
let _ = store.get(target_index).await;
}
fuzz_target!(|data: &[u8]| {
let mut unstructured = Unstructured::new(data);
let Ok(input) = FuzzInput::arbitrary(&mut unstructured) else {
return;
};
let runner = deterministic::Runner::default();
runner.start(move |context| {
let params = input.clone();
async move {
run_case(context, params).await;
}
});
});
thread panicked at storage/src/ordinal/storage.rs:281
called
Option::unwrap()on aNonevaluePoC: