use std::sync::Arc;
use freenet_stdlib::prelude::ContractInstanceId;
use super::focus::FocusSelector;
use super::sampler::{Admission, ContractSampler, SamplerConfig, Stratum};
fn config() -> SamplerConfig {
SamplerConfig {
earliest: 2,
recent: 3,
reservoir: 3,
largest: 2,
smallest: 2,
transitions: 3,
max_bytes: 4096,
max_state_bytes: 512,
seed: 42,
}
}
fn state(tag: u8, len: usize) -> Vec<u8> {
let mut out = vec![tag];
out.resize(len.max(1), tag);
out
}
#[test]
fn the_in_memory_corpus_carries_transition_provenance() {
let mut sampler = ContractSampler::new(config());
let base = state(1, 32);
let result = state(2, 48);
assert_eq!(
sampler.observe_transition(&base, None, Some(&[9]), None, &result),
Admission::Stored
);
let corpus = sampler.corpus();
assert_eq!(
corpus.transitions.len(),
1,
"the ordered base -> result step is what the transition law needs, and a \
corpus without it checks that law on nothing"
);
assert_eq!(corpus.transitions[0].0.as_ref(), base.as_slice());
assert_eq!(corpus.transitions[0].1.as_ref(), result.as_slice());
let bundle = sampler.to_bundle(None, Some([0u8; 32]), Vec::new());
assert_eq!(bundle.transitions.len(), 1);
let replayed = bundle.to_corpus();
assert_eq!(replayed.transitions, corpus.transitions);
assert_eq!(
corpus.delta_bases,
vec![Some(Arc::from(base.as_slice()))],
"the observed delta must be recorded against the state it was applied to"
);
assert_eq!(replayed.delta_bases, corpus.delta_bases);
assert_eq!(replayed.deltas, corpus.deltas);
assert!(
bundle.deltas.is_empty(),
"a delta carried by a transition must not also be emitted loose: {:?}",
bundle.deltas
);
assert_eq!(
bundle.transitions[0].delta.as_deref(),
Some(&[9u8][..]),
"...and it must actually be on the transition, or the assertion above \
passes because the delta was dropped entirely"
);
}
#[test]
fn identical_states_are_stored_once() {
let mut sampler = ContractSampler::new(config());
assert_eq!(sampler.observe_state(&state(1, 10)), Admission::Stored);
assert_eq!(sampler.observe_state(&state(1, 10)), Admission::Duplicate);
assert_eq!(sampler.distinct_states(), 1);
assert_eq!(sampler.total_seen(), 2);
assert_eq!(sampler.distinct_seen(), 1);
}
#[test]
fn oscillation_does_not_consume_sample_budget() {
let mut sampler = ContractSampler::new(config());
let (a, b) = (state(1, 32), state(2, 32));
for _ in 0..500 {
sampler.observe_state(&a);
sampler.observe_state(&b);
}
assert_eq!(sampler.distinct_states(), 2);
assert_eq!(sampler.distinct_seen(), 2);
assert_eq!(sampler.total_seen(), 1000);
assert!(sampler.stored_bytes() <= 64 + 8);
}
#[test]
fn earliest_keeps_the_first_states_and_recent_keeps_the_last() {
let mut sampler = ContractSampler::new(config());
for tag in 1u8..=8 {
sampler.observe_state(&state(tag, 16));
}
let earliest = sampler.members(Stratum::Earliest).to_vec();
assert_eq!(
earliest.len(),
2,
"earliest is capped at its configured size"
);
let corpus = sampler.corpus();
assert!(
corpus.states.iter().any(|s| s.as_ref()[0] == 8),
"the most recently observed state was not retained"
);
}
#[test]
fn largest_and_smallest_track_size_not_arrival_order() {
let mut sampler = ContractSampler::new(config());
for (tag, len) in [(1u8, 400), (2, 8), (3, 200), (4, 4), (5, 100)] {
sampler.observe_state(&state(tag, len));
}
let corpus = sampler.corpus();
let sizes: Vec<usize> = corpus.states.iter().map(|s| s.len()).collect();
assert!(
sizes.contains(&400),
"the largest observed state must be retained: {sizes:?}"
);
assert!(
sizes.contains(&4),
"the smallest observed state must be retained: {sizes:?}"
);
}
#[test]
fn a_state_in_several_strata_is_stored_once() {
let mut sampler = ContractSampler::new(config());
sampler.observe_state(&state(1, 100));
assert_eq!(sampler.distinct_states(), 1);
assert_eq!(sampler.stored_bytes(), 100);
}
#[test]
fn the_reservoir_is_deterministic_for_a_given_seed() {
let run = || {
let mut sampler = ContractSampler::new(config());
for tag in 1u8..=40 {
sampler.observe_state(&state(tag, 16));
}
sampler.members(Stratum::Reservoir).to_vec()
};
assert_eq!(run(), run());
}
#[test]
fn a_different_seed_samples_differently() {
let sample_with = |seed: u64| {
let mut sampler = ContractSampler::new(SamplerConfig { seed, ..config() });
for tag in 1u8..=40 {
sampler.observe_state(&state(tag, 16));
}
sampler.members(Stratum::Reservoir).to_vec()
};
assert_ne!(sample_with(1), sample_with(999));
}
#[test]
fn a_state_larger_than_the_per_state_ceiling_is_refused() {
let mut sampler = ContractSampler::new(config());
assert_eq!(sampler.observe_state(&state(1, 5000)), Admission::TooLarge);
assert_eq!(sampler.distinct_states(), 0);
assert_eq!(sampler.stored_bytes(), 0);
}
#[test]
fn the_byte_budget_is_never_exceeded() {
let mut sampler = ContractSampler::new(config());
for tag in 1u8..=200 {
sampler.observe_state(&state(tag, 500));
}
assert!(
sampler.stored_bytes() <= config().max_bytes,
"stored {} bytes over a {} budget",
sampler.stored_bytes(),
config().max_bytes
);
assert!(
sampler.distinct_states() > 0,
"budget enforcement emptied the store instead of bounding it"
);
}
#[test]
fn the_store_stays_useful_under_a_flood_of_large_states() {
let mut sampler = ContractSampler::new(config());
for tag in 1u8..=100 {
sampler.observe_state(&state(tag, 500));
}
let corpus = sampler.corpus();
assert!(
corpus.states.len() >= 2,
"a flood of large states left too little to check anything with"
);
}
#[test]
fn transitions_carry_replay_context() {
let mut sampler = ContractSampler::new(config());
let base = state(1, 16);
let result = state(2, 16);
assert_eq!(
sampler.observe_transition(&base, None, Some(&[9, 9]), Some(&[1]), &result),
Admission::Stored
);
let corpus = sampler.corpus();
assert!(corpus.deltas.iter().any(|d| d.as_ref() == [9, 9]));
let bundle = sampler.to_bundle(None, Some([7u8; 32]), vec![]);
assert_eq!(bundle.transitions.len(), 1);
assert_eq!(bundle.transitions[0].base_state, base);
assert_eq!(bundle.transitions[0].result_state, result);
}
#[test]
fn transitions_are_bounded() {
let mut sampler = ContractSampler::new(config());
for tag in 1u8..=20 {
sampler.observe_transition(
&state(tag, 16),
None,
Some(&[tag]),
None,
&state(tag + 1, 16),
);
}
let bundle = sampler.to_bundle(None, Some([7u8; 32]), vec![]);
assert!(bundle.transitions.len() <= config().transitions);
}
#[test]
fn a_transition_whose_endpoints_were_refused_is_not_recorded() {
let mut sampler = ContractSampler::new(config());
let huge = state(1, 5000);
assert_eq!(
sampler.observe_transition(&huge, None, None, None, &state(2, 16)),
Admission::TooLarge
);
let bundle = sampler.to_bundle(None, Some([7u8; 32]), vec![]);
assert!(bundle.transitions.is_empty());
}
#[test]
fn transition_payloads_count_against_the_byte_budget() {
let cfg = SamplerConfig {
transitions: 24,
max_bytes: 4096,
..config()
};
let mut sampler = ContractSampler::new(cfg.clone());
let payload = vec![7u8; 200];
let mut admitted = 0;
for tag in 1u8..=60 {
if sampler.observe_transition(
&state(tag, 16),
None,
Some(&payload),
Some(&payload),
&state(tag + 1, 16),
) == Admission::Stored
{
admitted += 1;
}
}
assert!(
admitted > cfg.transitions,
"fixture failed: only {admitted} transitions were admitted, so nothing \
accumulated and the assertions below prove nothing"
);
let actually_held = bincode::serialize(&sampler).expect("serialize").len();
assert!(
actually_held <= cfg.max_bytes + cfg.max_bytes / 2,
"the store really holds {actually_held} bytes against a {} byte budget; \
transition payloads are escaping the accounting",
cfg.max_bytes
);
assert!(
sampler.stored_bytes() <= cfg.max_bytes,
"reported {} bytes over a {} budget",
sampler.stored_bytes(),
cfg.max_bytes
);
}
#[test]
fn a_run_of_large_early_states_does_not_wedge_the_store() {
let cfg = SamplerConfig {
earliest: 4,
recent: 8,
reservoir: 8,
largest: 4,
smallest: 4,
transitions: 8,
max_bytes: 4096,
max_state_bytes: 1024,
seed: 7,
};
let mut sampler = ContractSampler::new(cfg.clone());
for tag in 1u8..=8 {
sampler.observe_state(&state(tag, 1000));
}
let mut admitted_after = 0;
for tag in 100u8..=140 {
if sampler.observe_state(&state(tag, 8)) == Admission::Stored {
admitted_after += 1;
}
}
assert!(
admitted_after > 0,
"the store wedged: {} large states filled it and nothing could be admitted \
afterwards, so it stops learning for the life of the contract",
8
);
assert!(
sampler.stored_bytes() <= cfg.max_bytes,
"budget exceeded while unwedging: {} > {}",
sampler.stored_bytes(),
cfg.max_bytes
);
let corpus = sampler.corpus();
assert!(
corpus.states.iter().any(|s| s.as_ref()[0] == 140),
"the newest observation never made it into the corpus"
);
}
#[test]
fn an_oversized_transition_payload_is_refused() {
let mut sampler = ContractSampler::new(config());
let huge = vec![7u8; config().max_state_bytes + 1];
assert_eq!(
sampler.observe_transition(&state(1, 16), None, Some(&huge), None, &state(2, 16)),
Admission::TooLarge
);
}
#[test]
fn the_recent_stratum_survives_many_rotations() {
let mut sampler = ContractSampler::new(config());
for tag in 1u8..=200 {
sampler.observe_state(&state(tag, 16));
}
let recent = sampler.members(Stratum::Recent);
assert_eq!(
recent.len(),
config().recent,
"recent stratum lost members to deque slicing"
);
let corpus = sampler.corpus();
assert!(
corpus.states.iter().any(|s| s.as_ref()[0] == 200),
"the newest observation is missing from the corpus"
);
}
#[test]
fn reobserving_an_aged_out_state_makes_it_recent_again() {
let mut sampler = ContractSampler::new(config());
let first = state(1, 16);
sampler.observe_state(&first);
for tag in 2u8..=10 {
sampler.observe_state(&state(tag, 16));
}
let hash = *blake3::hash(&first).as_bytes();
assert!(
!sampler.members(Stratum::Recent).contains(&hash),
"fixture failed: the state never aged out, so the assertion below is vacuous"
);
assert_eq!(sampler.observe_state(&first), Admission::Duplicate);
assert!(
sampler.members(Stratum::Recent).contains(&hash),
"a re-observed state did not return to the recent stratum"
);
assert!(
sampler.members(Stratum::Recent).len() <= config().recent,
"reinsertion broke the recent cap"
);
}
#[test]
fn the_store_survives_a_restart() {
let mut sampler = ContractSampler::new(config());
for tag in 1u8..=12 {
sampler.observe_state(&state(tag, 24));
}
sampler.observe_transition(&state(1, 24), None, Some(&[7]), None, &state(2, 24));
let encoded = bincode::serialize(&sampler).expect("serialize");
let restored: ContractSampler = bincode::deserialize(&encoded).expect("deserialize");
assert_eq!(restored, sampler);
assert_eq!(restored.distinct_seen(), sampler.distinct_seen());
let mut a = sampler;
let mut b = restored;
for tag in 13u8..=30 {
a.observe_state(&state(tag, 24));
b.observe_state(&state(tag, 24));
}
assert_eq!(a.members(Stratum::Reservoir), b.members(Stratum::Reservoir));
}
fn instance(seed: u8) -> ContractInstanceId {
ContractInstanceId::new([seed; 32])
}
#[test]
fn focus_is_bounded_and_stable_within_a_period() {
let selector = FocusSelector::new([7; 32], 2);
let candidates: Vec<_> = (1u8..=20).map(instance).collect();
let first = selector.select(&candidates);
assert_eq!(first.len(), 2);
assert_eq!(
first,
selector.select(&candidates),
"focus churned mid-period"
);
}
#[test]
fn rotation_redraws_the_focus_set() {
let mut selector = FocusSelector::new([7; 32], 2);
let candidates: Vec<_> = (1u8..=20).map(instance).collect();
let before = selector.select(&candidates);
let mut changed = false;
for _ in 0..8 {
selector.rotate();
if selector.select(&candidates) != before {
changed = true;
break;
}
}
assert!(changed, "rotation never changed the focus set");
}
#[test]
fn peers_with_different_salts_watch_different_contracts() {
let candidates: Vec<_> = (1u8..=40).map(instance).collect();
let mut distinct = std::collections::HashSet::new();
for salt in 0u8..12 {
distinct.insert(FocusSelector::new([salt; 32], 2).select(&candidates));
}
assert!(
distinct.len() > 6,
"focus barely varied across peers ({} distinct sets of 12): selection is \
not effectively keyed on the per-peer salt",
distinct.len()
);
}
#[test]
fn focus_handles_having_fewer_contracts_than_slots() {
let selector = FocusSelector::new([1; 32], 4);
assert!(selector.select(&[]).is_empty());
assert_eq!(selector.select(&[instance(1)]).len(), 1);
}
#[test]
fn duplicate_candidates_do_not_waste_focus_slots() {
let selector = FocusSelector::new([1; 32], 2);
let selected = selector.select(&[instance(1), instance(1), instance(2)]);
assert_eq!(selected.len(), 2);
assert_ne!(selected[0], selected[1]);
}