use std::collections::HashMap;
use std::time::Duration;
use freenet_stdlib::prelude::ContractInstanceId;
use parking_lot::Mutex;
use crate::node::background_task_monitor::BackgroundTaskMonitor;
use crate::ring::interest::SummaryMissingReason;
use crate::tracing::event_kind::{STATE_SIZE_BUCKET_COUNT, state_size_bucket};
const ROLLUP_WINDOW: Duration = Duration::from_secs(60);
const MAX_TRACKED_CONTRACTS: usize = 256;
const TOP_CONTRACTS_REPORTED: usize = 10;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum PayloadArm {
Delta,
FullDeltaSuppressed,
FullNotEfficient,
FullComputeFailed,
FullNoOurSummary,
FullNoTheirSummaryUntracked,
FullNoTheirSummaryTracked,
}
impl PayloadArm {
pub(crate) const ALL: [PayloadArm; 7] = [
PayloadArm::Delta,
PayloadArm::FullDeltaSuppressed,
PayloadArm::FullNotEfficient,
PayloadArm::FullComputeFailed,
PayloadArm::FullNoOurSummary,
PayloadArm::FullNoTheirSummaryUntracked,
PayloadArm::FullNoTheirSummaryTracked,
];
const NO_SUMMARY_SPLIT: [PayloadArm; 3] = [
PayloadArm::FullNoOurSummary,
PayloadArm::FullNoTheirSummaryUntracked,
PayloadArm::FullNoTheirSummaryTracked,
];
const COUNT: usize = Self::ALL.len();
const fn index(self) -> usize {
match self {
PayloadArm::Delta => 0,
PayloadArm::FullDeltaSuppressed => 1,
PayloadArm::FullNotEfficient => 2,
PayloadArm::FullComputeFailed => 3,
PayloadArm::FullNoOurSummary => 4,
PayloadArm::FullNoTheirSummaryUntracked => 5,
PayloadArm::FullNoTheirSummaryTracked => 6,
}
}
pub(crate) const fn label(self) -> &'static str {
match self {
PayloadArm::Delta => "delta",
PayloadArm::FullDeltaSuppressed => "full_delta_suppressed",
PayloadArm::FullNotEfficient => "full_not_efficient",
PayloadArm::FullComputeFailed => "full_compute_failed",
PayloadArm::FullNoOurSummary => "full_no_our_summary",
PayloadArm::FullNoTheirSummaryUntracked => "full_no_their_summary_untracked",
PayloadArm::FullNoTheirSummaryTracked => "full_no_their_summary_tracked",
}
}
pub(crate) const fn is_full_state(self) -> bool {
!matches!(self, PayloadArm::Delta)
}
}
struct Window {
sends: [u64; PayloadArm::COUNT],
bytes: [u64; PayloadArm::COUNT],
contract_full_state_bytes: HashMap<ContractInstanceId, u64>,
contract_total: HashMap<ContractInstanceId, (u64, u64)>,
total_attribution_dropped_sends: u64,
total_attribution_dropped_bytes: u64,
contract_not_efficient_bytes: HashMap<ContractInstanceId, u64>,
attribution_dropped_sends: u64,
attribution_dropped_bytes: u64,
not_efficient_summary_bytes_sum: u64,
not_efficient_state_bytes_sum: u64,
not_efficient_summary_bytes_max: u64,
not_efficient_state_bytes_max: u64,
tracked_missing_sends: [u64; SummaryMissingReason::ALL.len()],
tracked_missing_bytes: [u64; SummaryMissingReason::ALL.len()],
}
impl Default for Window {
fn default() -> Self {
Self {
sends: [0; PayloadArm::COUNT],
bytes: [0; PayloadArm::COUNT],
contract_full_state_bytes: HashMap::new(),
contract_total: HashMap::new(),
total_attribution_dropped_sends: 0,
total_attribution_dropped_bytes: 0,
contract_not_efficient_bytes: HashMap::new(),
attribution_dropped_sends: 0,
attribution_dropped_bytes: 0,
not_efficient_summary_bytes_sum: 0,
not_efficient_state_bytes_sum: 0,
not_efficient_summary_bytes_max: 0,
not_efficient_state_bytes_max: 0,
tracked_missing_sends: [0; SummaryMissingReason::ALL.len()],
tracked_missing_bytes: [0; SummaryMissingReason::ALL.len()],
}
}
}
pub(crate) struct PayloadMix {
window: Mutex<Window>,
receiver_applies: Mutex<ReceiverApplyStats>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ReceiverApplyClass {
DeltaChanged,
DeltaNoOp,
FullChanged,
FullNoOp,
}
impl ReceiverApplyClass {
pub(crate) const ALL: [Self; 4] = [
Self::DeltaChanged,
Self::DeltaNoOp,
Self::FullChanged,
Self::FullNoOp,
];
pub(crate) const COUNT: usize = Self::ALL.len();
pub(crate) const fn index(self) -> usize {
match self {
Self::DeltaChanged => 0,
Self::DeltaNoOp => 1,
Self::FullChanged => 2,
Self::FullNoOp => 3,
}
}
pub(crate) const fn from_apply(is_delta: bool, changed: bool) -> Self {
match (is_delta, changed) {
(true, true) => Self::DeltaChanged,
(true, false) => Self::DeltaNoOp,
(false, true) => Self::FullChanged,
(false, false) => Self::FullNoOp,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub(crate) struct ReceiverApplyStats {
pub(crate) counts: [[u64; STATE_SIZE_BUCKET_COUNT]; ReceiverApplyClass::COUNT],
pub(crate) terminal_counts: [[u64; STATE_SIZE_BUCKET_COUNT]; 10],
pub(crate) terminal_bytes: [[u64; STATE_SIZE_BUCKET_COUNT]; 10],
}
#[derive(Clone, Copy)]
enum ReceiverTerminalOutcome {
Changed,
NoOp,
Dedup,
Backoff,
Failed,
}
impl ReceiverTerminalOutcome {
const fn index(self) -> usize {
self as usize
}
}
pub(crate) struct ReceiverTerminalGuard<'a> {
mix: &'a PayloadMix,
is_delta: bool,
payload_bytes: usize,
outcome: ReceiverTerminalOutcome,
}
impl ReceiverTerminalGuard<'_> {
pub(crate) fn mark_dedup(&mut self) {
self.outcome = ReceiverTerminalOutcome::Dedup;
}
pub(crate) fn mark_backoff(&mut self) {
self.outcome = ReceiverTerminalOutcome::Backoff;
}
pub(crate) fn mark_applied(&mut self, changed: bool, state_size: usize) {
self.mix
.record_receiver_apply(self.is_delta, changed, state_size);
self.outcome = if changed {
ReceiverTerminalOutcome::Changed
} else {
ReceiverTerminalOutcome::NoOp
};
}
}
impl Drop for ReceiverTerminalGuard<'_> {
fn drop(&mut self) {
self.mix
.record_receiver_terminal(self.is_delta, self.outcome, self.payload_bytes);
}
}
impl PayloadMix {
pub(crate) fn new() -> Self {
Self {
window: Mutex::new(Window::default()),
receiver_applies: Mutex::new(ReceiverApplyStats::default()),
}
}
fn record_receiver_apply(&self, is_delta: bool, changed: bool, state_size: usize) {
let class = ReceiverApplyClass::from_apply(is_delta, changed).index();
let bucket = state_size_bucket(state_size as u64);
let mut stats = self.receiver_applies.lock();
stats.counts[class][bucket] = stats.counts[class][bucket].saturating_add(1);
}
pub(crate) fn receiver_terminal_guard(
&self,
is_delta: bool,
payload_bytes: usize,
) -> ReceiverTerminalGuard<'_> {
ReceiverTerminalGuard {
mix: self,
is_delta,
payload_bytes,
outcome: ReceiverTerminalOutcome::Failed,
}
}
fn record_receiver_terminal(
&self,
is_delta: bool,
outcome: ReceiverTerminalOutcome,
payload_bytes: usize,
) {
let outcome_index = outcome.index();
let kind_index = usize::from(!is_delta) * 5 + outcome_index;
let bucket = state_size_bucket(payload_bytes as u64);
let bytes = u64::try_from(payload_bytes).unwrap_or(u64::MAX);
let mut stats = self.receiver_applies.lock();
stats.terminal_counts[kind_index][bucket] =
stats.terminal_counts[kind_index][bucket].saturating_add(1);
stats.terminal_bytes[kind_index][bucket] =
stats.terminal_bytes[kind_index][bucket].saturating_add(bytes);
}
pub(crate) fn receiver_apply_stats(&self) -> ReceiverApplyStats {
*self.receiver_applies.lock()
}
pub(crate) fn record_delivered(
&self,
arm: PayloadArm,
contract: &ContractInstanceId,
payload_bytes: usize,
gate_inputs: Option<(usize, usize)>,
missing_reason: Option<SummaryMissingReason>,
) {
let bytes = payload_bytes as u64;
let idx = arm.index();
let mut w = self.window.lock();
if arm == PayloadArm::FullNoTheirSummaryTracked {
if let Some(reason) = missing_reason {
let r = reason.index();
if r < w.tracked_missing_sends.len() {
w.tracked_missing_sends[r] = w.tracked_missing_sends[r].saturating_add(1);
w.tracked_missing_bytes[r] = w.tracked_missing_bytes[r].saturating_add(bytes);
}
}
}
if arm == PayloadArm::FullNotEfficient {
if let Some((summary_size, state_size)) = gate_inputs {
let (s, st) = (summary_size as u64, state_size as u64);
w.not_efficient_summary_bytes_sum =
w.not_efficient_summary_bytes_sum.saturating_add(s);
w.not_efficient_state_bytes_sum =
w.not_efficient_state_bytes_sum.saturating_add(st);
w.not_efficient_summary_bytes_max = w.not_efficient_summary_bytes_max.max(s);
w.not_efficient_state_bytes_max = w.not_efficient_state_bytes_max.max(st);
}
}
w.sends[idx] = w.sends[idx].saturating_add(1);
w.bytes[idx] = w.bytes[idx].saturating_add(bytes);
if arm == PayloadArm::FullNotEfficient {
if let Some(tally) = w.contract_not_efficient_bytes.get_mut(contract) {
*tally = tally.saturating_add(bytes);
} else if w.contract_not_efficient_bytes.len() < MAX_TRACKED_CONTRACTS {
w.contract_not_efficient_bytes.insert(*contract, bytes);
}
}
if let Some(tally) = w.contract_total.get_mut(contract) {
tally.0 = tally.0.saturating_add(1);
tally.1 = tally.1.saturating_add(bytes);
} else if w.contract_total.len() < MAX_TRACKED_CONTRACTS {
w.contract_total.insert(*contract, (1, bytes));
} else {
w.total_attribution_dropped_sends = w.total_attribution_dropped_sends.saturating_add(1);
w.total_attribution_dropped_bytes =
w.total_attribution_dropped_bytes.saturating_add(bytes);
}
if arm.is_full_state() {
if let Some(tally) = w.contract_full_state_bytes.get_mut(contract) {
*tally = tally.saturating_add(bytes);
} else if w.contract_full_state_bytes.len() < MAX_TRACKED_CONTRACTS {
w.contract_full_state_bytes.insert(*contract, bytes);
} else {
w.attribution_dropped_sends = w.attribution_dropped_sends.saturating_add(1);
w.attribution_dropped_bytes = w.attribution_dropped_bytes.saturating_add(bytes);
}
}
}
fn take_window(&self) -> Window {
std::mem::take(&mut *self.window.lock())
}
}
impl Window {
fn arms(&self) -> Vec<(PayloadArm, u64, u64)> {
PayloadArm::ALL
.iter()
.map(|arm| {
let idx = arm.index();
(*arm, self.sends[idx], self.bytes[idx])
})
.collect()
}
fn gate_stats(&self) -> NotEfficientGateStats {
NotEfficientGateStats {
summary_bytes_sum: self.not_efficient_summary_bytes_sum,
state_bytes_sum: self.not_efficient_state_bytes_sum,
summary_bytes_max: self.not_efficient_summary_bytes_max,
state_bytes_max: self.not_efficient_state_bytes_max,
}
}
fn tracked_missing(&self) -> Vec<(SummaryMissingReason, u64, u64)> {
SummaryMissingReason::ALL
.iter()
.map(|reason| {
let idx = reason.index();
(
*reason,
self.tracked_missing_sends[idx],
self.tracked_missing_bytes[idx],
)
})
.collect()
}
fn top_not_efficient_contracts(&self) -> Vec<(ContractInstanceId, u64)> {
let mut tallies: Vec<(ContractInstanceId, u64)> = self
.contract_not_efficient_bytes
.iter()
.map(|(k, v)| (*k, *v))
.collect();
tallies.sort_by(|a, b| {
b.1.cmp(&a.1)
.then_with(|| a.0.as_bytes().cmp(b.0.as_bytes()))
});
tallies.truncate(TOP_CONTRACTS_REPORTED);
tallies
}
fn top_contracts_total(&self) -> Vec<(ContractInstanceId, u64, u64)> {
let mut tallies: Vec<(ContractInstanceId, u64, u64)> = self
.contract_total
.iter()
.map(|(k, (sends, bytes))| (*k, *sends, *bytes))
.collect();
tallies.sort_by(|a, b| {
b.2.cmp(&a.2)
.then_with(|| a.0.as_bytes().cmp(b.0.as_bytes()))
});
tallies.truncate(TOP_CONTRACTS_REPORTED);
tallies
}
fn total_attribution(&self) -> TotalAttribution {
TotalAttribution {
contracts: self.top_contracts_total(),
contracts_tracked: self.contract_total.len() as u64,
dropped_sends: self.total_attribution_dropped_sends,
dropped_bytes: self.total_attribution_dropped_bytes,
}
}
fn top_contracts(&self) -> Vec<(ContractInstanceId, u64)> {
let mut tallies: Vec<(ContractInstanceId, u64)> = self
.contract_full_state_bytes
.iter()
.map(|(k, v)| (*k, *v))
.collect();
tallies.sort_by(|a, b| {
b.1.cmp(&a.1)
.then_with(|| a.0.as_bytes().cmp(b.0.as_bytes()))
});
tallies.truncate(TOP_CONTRACTS_REPORTED);
tallies
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
struct TotalAttribution {
contracts: Vec<(ContractInstanceId, u64, u64)>,
contracts_tracked: u64,
dropped_sends: u64,
dropped_bytes: u64,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
struct NotEfficientGateStats {
summary_bytes_sum: u64,
state_bytes_sum: u64,
summary_bytes_max: u64,
state_bytes_max: u64,
}
#[allow(clippy::too_many_arguments)]
fn payload_mix_json(
arms: &[(PayloadArm, u64, u64)],
contracts: &[(ContractInstanceId, u64)],
not_efficient_contracts: &[(ContractInstanceId, u64)],
total: &TotalAttribution,
tracked_full_state_bytes: u64,
contracts_tracked: u64,
attribution_dropped_sends: u64,
attribution_dropped_bytes: u64,
gate: NotEfficientGateStats,
tracked_missing: &[(SummaryMissingReason, u64, u64)],
window_secs: u64,
) -> serde_json::Value {
let mut obj = serde_json::Map::new();
let mut total_sends = 0u64;
let mut total_bytes = 0u64;
let mut full_state_bytes = 0u64;
for (arm, sends, bytes) in arms {
obj.insert(format!("{}_sends", arm.label()), (*sends).into());
obj.insert(format!("{}_bytes", arm.label()), (*bytes).into());
total_sends += sends;
total_bytes += bytes;
if arm.is_full_state() {
full_state_bytes += bytes;
}
}
let no_summary_sends: u64 = arms
.iter()
.filter(|(arm, _, _)| PayloadArm::NO_SUMMARY_SPLIT.contains(arm))
.map(|(_, sends, _)| *sends)
.sum();
let no_summary_bytes: u64 = arms
.iter()
.filter(|(arm, _, _)| PayloadArm::NO_SUMMARY_SPLIT.contains(arm))
.map(|(_, _, bytes)| *bytes)
.sum();
obj.insert("full_no_summary_sends".into(), no_summary_sends.into());
obj.insert("full_no_summary_bytes".into(), no_summary_bytes.into());
obj.insert(
"not_efficient_summary_bytes_sum".into(),
gate.summary_bytes_sum.into(),
);
obj.insert(
"not_efficient_state_bytes_sum".into(),
gate.state_bytes_sum.into(),
);
obj.insert(
"not_efficient_summary_bytes_max".into(),
gate.summary_bytes_max.into(),
);
obj.insert(
"not_efficient_state_bytes_max".into(),
gate.state_bytes_max.into(),
);
obj.insert(
"not_efficient_summary_to_state_bytes_ratio".into(),
if gate.state_bytes_sum == 0 {
serde_json::Value::Null
} else {
serde_json::Number::from_f64(
gate.summary_bytes_sum as f64 / gate.state_bytes_sum as f64,
)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null)
},
);
let mut reason_sends = 0u64;
let mut reason_bytes = 0u64;
for (reason, sends, bytes) in tracked_missing {
obj.insert(
format!("tracked_missing_{}_sends", reason.as_str()),
(*sends).into(),
);
obj.insert(
format!("tracked_missing_{}_bytes", reason.as_str()),
(*bytes).into(),
);
reason_sends += sends;
reason_bytes += bytes;
}
let tracked_arm_sends: u64 = arms
.iter()
.filter(|(arm, _, _)| *arm == PayloadArm::FullNoTheirSummaryTracked)
.map(|(_, sends, _)| *sends)
.sum();
let tracked_arm_bytes: u64 = arms
.iter()
.filter(|(arm, _, _)| *arm == PayloadArm::FullNoTheirSummaryTracked)
.map(|(_, _, bytes)| *bytes)
.sum();
obj.insert(
"tracked_missing_unattributed_sends".into(),
tracked_arm_sends.saturating_sub(reason_sends).into(),
);
obj.insert(
"tracked_missing_unattributed_bytes".into(),
tracked_arm_bytes.saturating_sub(reason_bytes).into(),
);
obj.insert("total_sends".into(), total_sends.into());
obj.insert("total_bytes".into(), total_bytes.into());
obj.insert("full_state_bytes".into(), full_state_bytes.into());
let full_state_share = if total_bytes == 0 {
0.0
} else {
full_state_bytes as f64 / total_bytes as f64
};
obj.insert(
"full_state_byte_share".into(),
serde_json::Number::from_f64(full_state_share)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null),
);
obj.insert(
"top_contracts_by_full_state_bytes".into(),
serde_json::Value::Array(
contracts
.iter()
.map(
|(id, bytes)| serde_json::json!({ "contract": id.to_string(), "bytes": bytes }),
)
.collect(),
),
);
obj.insert(
"top_contracts_by_total_bytes".into(),
serde_json::Value::Array(
total
.contracts
.iter()
.map(|(id, sends, bytes)| {
serde_json::json!({
"contract": id.to_string(),
"sends": sends,
"bytes": bytes,
})
})
.collect(),
),
);
obj.insert(
"contracts_tracked_total".into(),
total.contracts_tracked.into(),
);
obj.insert(
"total_attribution_dropped_sends".into(),
total.dropped_sends.into(),
);
obj.insert(
"total_attribution_dropped_bytes".into(),
total.dropped_bytes.into(),
);
obj.insert(
"top_contracts_by_not_efficient_bytes".into(),
serde_json::Value::Array(
not_efficient_contracts
.iter()
.map(
|(id, bytes)| serde_json::json!({ "contract": id.to_string(), "bytes": bytes }),
)
.collect(),
),
);
let top_sum: u64 = contracts.iter().map(|(_, b)| *b).sum();
let other_contracts_bytes = tracked_full_state_bytes.saturating_sub(top_sum);
obj.insert("other_contracts_bytes".into(), other_contracts_bytes.into());
obj.insert("contracts_tracked".into(), contracts_tracked.into());
obj.insert(
"attribution_dropped_sends".into(),
attribution_dropped_sends.into(),
);
obj.insert(
"attribution_dropped_bytes".into(),
attribution_dropped_bytes.into(),
);
obj.insert("window_secs".into(), window_secs.into());
serde_json::Value::Object(obj)
}
pub(crate) fn emit_payload_mix_rollup(
mix: &PayloadMix,
local_peer_id: &str,
window_secs: u64,
) -> serde_json::Value {
let window = mix.take_window();
let payload = payload_mix_json(
&window.arms(),
&window.top_contracts(),
&window.top_not_efficient_contracts(),
&window.total_attribution(),
window.contract_full_state_bytes.values().sum(),
window.contract_full_state_bytes.len() as u64,
window.attribution_dropped_sends,
window.attribution_dropped_bytes,
window.gate_stats(),
&window.tracked_missing(),
window_secs,
);
crate::tracing::telemetry::send_standalone_shadow_event_with_peer_id(
"broadcast_payload_mix",
local_peer_id,
payload.clone(),
);
payload
}
fn rollup_window_secs(elapsed: Duration) -> u64 {
(elapsed.as_secs_f64().round() as u64).max(1)
}
pub(crate) fn spawn_payload_mix_aggregator(
mix: std::sync::Arc<PayloadMix>,
local_peer_id: String,
monitor: &BackgroundTaskMonitor,
) {
let handle = tokio::spawn(async move {
let mut ticker = tokio::time::interval(ROLLUP_WINDOW);
ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
ticker.tick().await; let mut last_rollup = tokio::time::Instant::now();
loop {
ticker.tick().await;
let now = tokio::time::Instant::now();
let elapsed = now.saturating_duration_since(last_rollup);
last_rollup = now;
emit_payload_mix_rollup(&mix, &local_peer_id, rollup_window_secs(elapsed));
}
});
monitor.register("broadcast_payload_mix_aggregator", handle);
}
#[cfg(test)]
mod tests {
use super::*;
fn contract(byte: u8) -> ContractInstanceId {
ContractInstanceId::new([byte; 32])
}
#[test]
fn receiver_applies_classify_all_outcomes_and_state_size_boundaries() {
let mix = PayloadMix::new();
let last_bounded = *crate::tracing::event_kind::STATE_SIZE_BUCKET_UPPER_BOUNDS
.last()
.unwrap() as usize;
for (is_delta, changed, state_size, payload_bytes) in [
(true, true, 64 * 1024, 11),
(true, false, 64 * 1024 + 1, 22),
(false, true, last_bounded, 33),
(false, false, last_bounded + 1, 44),
] {
let mut terminal = mix.receiver_terminal_guard(is_delta, payload_bytes);
terminal.mark_applied(changed, state_size);
}
let stats = mix.receiver_apply_stats();
let delta_changed = ReceiverApplyClass::DeltaChanged.index();
let delta_no_op = ReceiverApplyClass::DeltaNoOp.index();
let full_changed = ReceiverApplyClass::FullChanged.index();
let full_no_op = ReceiverApplyClass::FullNoOp.index();
assert_eq!(stats.counts[delta_changed][0], 1);
assert_eq!(stats.counts[delta_no_op][1], 1);
assert_eq!(stats.counts[full_changed][STATE_SIZE_BUCKET_COUNT - 2], 1);
assert_eq!(stats.counts[full_no_op][STATE_SIZE_BUCKET_COUNT - 1], 1);
let total_count: u64 = stats.counts.iter().flatten().sum();
let total_payload_bytes: u64 = stats.terminal_bytes.iter().flatten().sum();
assert_eq!(total_count, 4);
assert_eq!(total_payload_bytes, 110);
}
#[test]
fn receiver_apply_totals_are_cumulative_across_sender_window_drains() {
let mix = PayloadMix::new();
mix.receiver_terminal_guard(false, 100)
.mark_applied(false, 3 * 1024 * 1024);
let first = mix.receiver_apply_stats();
let _ = mix.take_window();
assert_eq!(mix.receiver_apply_stats(), first);
mix.receiver_terminal_guard(false, 250)
.mark_applied(false, 3 * 1024 * 1024);
let second = mix.receiver_apply_stats();
let class = ReceiverApplyClass::FullNoOp.index();
let terminal_class = 5 + ReceiverTerminalOutcome::NoOp.index();
let result_state_bucket = state_size_bucket(3 * 1024 * 1024);
let incoming_payload_bucket = state_size_bucket(100);
assert_eq!(second.counts[class][result_state_bucket], 2);
assert_eq!(
second.terminal_bytes[terminal_class][incoming_payload_bucket],
350
);
}
#[test]
fn receiver_terminal_guard_accounts_for_dedup_backoff_and_failure_bytes() {
let mix = PayloadMix::new();
let large = 4 * 1024 * 1024;
let mut dedup = mix.receiver_terminal_guard(true, large);
dedup.mark_dedup();
drop(dedup);
let mut backoff = mix.receiver_terminal_guard(false, large + 1);
backoff.mark_backoff();
drop(backoff);
drop(mix.receiver_terminal_guard(false, large + 2));
let stats = mix.receiver_apply_stats();
let bucket = state_size_bucket(large as u64);
assert_eq!(stats.terminal_counts[2][bucket], 1);
assert_eq!(stats.terminal_bytes[2][bucket], large as u64);
assert_eq!(stats.terminal_counts[8][bucket], 1);
assert_eq!(stats.terminal_bytes[8][bucket], (large + 1) as u64);
assert_eq!(stats.terminal_counts[9][bucket], 1);
assert_eq!(stats.terminal_bytes[9][bucket], (large + 2) as u64);
}
#[test]
fn delta_only_contract_is_attributable_in_totals_but_not_full_state() {
let mix = PayloadMix::new();
mix.record_delivered(PayloadArm::Delta, &contract(1), 25_000, None, None);
mix.record_delivered(PayloadArm::Delta, &contract(1), 25_000, None, None);
mix.record_delivered(
PayloadArm::FullNoOurSummary,
&contract(2),
1_000,
None,
None,
);
let w = mix.take_window();
let totals = w.top_contracts_total();
let delta_only = totals.iter().find(|(id, _, _)| *id == contract(1)).expect(
"a delta-only contract MUST appear in the total map — this is \
the #5056 blind spot the map exists to close",
);
assert_eq!(delta_only.1, 2, "both sends must be counted");
assert_eq!(delta_only.2, 50_000, "both sends' bytes must be counted");
assert_eq!(
totals[0].0,
contract(1),
"the total map must rank by TOTAL bytes, so the expensive delta-only \
contract leads — ranking by full-state bytes would hide it entirely"
);
assert!(
!w.top_contracts().iter().any(|(id, _)| *id == contract(1)),
"contract_full_state_bytes must remain full-state-only; if a delta \
contract starts appearing there, the two maps have been conflated \
and the full-state share becomes unreadable"
);
assert!(
w.top_contracts().iter().any(|(id, _)| *id == contract(2)),
"the full-state contract must still be attributed as before"
);
}
#[test]
fn not_efficient_bytes_are_attributed_to_their_contract() {
let mix = PayloadMix::new();
mix.record_delivered(
PayloadArm::FullNotEfficient,
&contract(7),
600,
Some((600, 600)),
None,
);
mix.record_delivered(
PayloadArm::FullNotEfficient,
&contract(7),
400,
Some((400, 400)),
None,
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&contract(8),
999,
None,
None,
);
let w = mix.take_window();
let top = w.top_not_efficient_contracts();
assert_eq!(top.len(), 1, "only the refused arm belongs here: {top:?}");
assert_eq!(top[0].0, contract(7));
assert_eq!(top[0].1, 1000, "per-contract bytes must accumulate");
assert_eq!(w.contract_full_state_bytes[&contract(8)], 999);
}
#[test]
fn take_window_resets_the_window() {
let mix = PayloadMix::new();
mix.record_delivered(PayloadArm::Delta, &contract(1), 100, None, None);
let first = mix.take_window().arms();
assert_eq!(first[PayloadArm::Delta.index()].1, 1);
assert_eq!(first[PayloadArm::Delta.index()].2, 100);
let second = mix.take_window().arms();
assert!(
second
.iter()
.all(|(_, sends, bytes)| *sends == 0 && *bytes == 0),
"second take must be empty, got {second:?}"
);
}
#[test]
fn each_arm_counts_separately() {
let mix = PayloadMix::new();
for (i, arm) in PayloadArm::ALL.iter().enumerate() {
for _ in 0..=i {
mix.record_delivered(*arm, &contract(i as u8), 10, None, None);
}
}
let drained = mix.take_window().arms();
for (i, (arm, sends, bytes)) in drained.iter().enumerate() {
assert_eq!(*arm, PayloadArm::ALL[i]);
assert_eq!(*sends, i as u64 + 1, "wrong send count for {arm:?}");
assert_eq!(*bytes, (i as u64 + 1) * 10, "wrong byte count for {arm:?}");
}
}
#[test]
fn per_contract_tallies_reconcile_with_arm_totals() {
let mix = PayloadMix::new();
mix.record_delivered(PayloadArm::FullNotEfficient, &contract(1), 500, None, None);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&contract(2),
300,
None,
None,
);
mix.record_delivered(
PayloadArm::FullDeltaSuppressed,
&contract(1),
200,
None,
None,
);
mix.record_delivered(PayloadArm::Delta, &contract(3), 50, None, None);
let window = mix.take_window();
let full_state_total: u64 = window
.arms()
.iter()
.filter(|(arm, _, _)| arm.is_full_state())
.map(|(_, _, bytes)| bytes)
.sum();
assert_eq!(
full_state_total, 1000,
"full-state arm bytes should exclude the delta send"
);
assert_eq!(window.contract_full_state_bytes[&contract(1)], 700);
assert_eq!(window.contract_full_state_bytes[&contract(2)], 300);
assert_reconciles(&window);
}
fn assert_reconciles(window: &Window) {
let json = payload_mix_json(
&window.arms(),
&window.top_contracts(),
&window.top_not_efficient_contracts(),
&window.total_attribution(),
window.contract_full_state_bytes.values().sum(),
window.contract_full_state_bytes.len() as u64,
window.attribution_dropped_sends,
window.attribution_dropped_bytes,
window.gate_stats(),
&[],
60,
);
let top_sum: u64 = json["top_contracts_by_full_state_bytes"]
.as_array()
.expect("top contracts must be an array")
.iter()
.map(|e| e["bytes"].as_u64().expect("bytes must be a number"))
.sum();
let other = json["other_contracts_bytes"].as_u64().unwrap();
let dropped = json["attribution_dropped_bytes"].as_u64().unwrap();
let full_state = json["full_state_bytes"].as_u64().unwrap();
assert_eq!(
top_sum + other + dropped,
full_state,
"published schema must add up: sum(top_contracts) + \
other_contracts_bytes + attribution_dropped_bytes == \
full_state_bytes (got {top_sum} + {other} + {dropped} != \
{full_state})"
);
}
#[test]
fn window_with_more_contracts_than_top_n_still_reconciles() {
let mix = PayloadMix::new();
for i in 0..(TOP_CONTRACTS_REPORTED + 1) {
mix.record_delivered(
PayloadArm::FullNotEfficient,
&contract(i as u8),
100,
None,
None,
);
}
let window = mix.take_window();
assert_reconciles(&window);
let json = payload_mix_json(
&window.arms(),
&window.top_contracts(),
&window.top_not_efficient_contracts(),
&window.total_attribution(),
window.contract_full_state_bytes.values().sum(),
window.contract_full_state_bytes.len() as u64,
window.attribution_dropped_sends,
window.attribution_dropped_bytes,
window.gate_stats(),
&[],
60,
);
assert_eq!(json["full_state_bytes"], 1100);
assert_eq!(
json["other_contracts_bytes"], 100,
"the 11th contract's bytes must be reported as the untruncated \
remainder, not silently lost"
);
assert_eq!(
json["attribution_dropped_bytes"], 0,
"nothing was DROPPED here — the cap was never reached; this is \
truncation, which is a different field"
);
assert_eq!(json["contracts_tracked"], 11);
}
#[test]
fn truncation_and_over_cap_drops_reconcile_together() {
let mix = PayloadMix::new();
for i in 0..(MAX_TRACKED_CONTRACTS + 5) {
let mut raw = [0u8; 32];
raw[0] = (i % 256) as u8;
raw[1] = (i / 256) as u8;
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&ContractInstanceId::new(raw),
10,
None,
None,
);
}
let window = mix.take_window();
assert!(
window.attribution_dropped_bytes > 0,
"cap must have been hit"
);
assert_reconciles(&window);
}
#[test]
fn total_map_cap_overflow_is_reported_separately_from_full_state() {
let mix = PayloadMix::new();
let id = |i: usize| {
let mut raw = [0u8; 32];
raw[0] = (i % 256) as u8;
raw[1] = (i / 256) as u8;
ContractInstanceId::new(raw)
};
for i in 0..MAX_TRACKED_CONTRACTS {
mix.record_delivered(PayloadArm::Delta, &id(i), 10, None, None);
}
for i in MAX_TRACKED_CONTRACTS..(MAX_TRACKED_CONTRACTS + 3) {
mix.record_delivered(PayloadArm::Delta, &id(i), 7, None, None);
}
let window = mix.take_window();
let total = window.total_attribution();
assert_eq!(
total.contracts_tracked, MAX_TRACKED_CONTRACTS as u64,
"the total map must be at its cap"
);
assert_eq!(
total.dropped_sends, 3,
"each refused send must be counted — a silently dropped tail is \
what makes the distribution unusable for sizing a budget (#5057)"
);
assert_eq!(
total.dropped_bytes, 21,
"and the bytes behind those refused sends"
);
assert_eq!(
window.attribution_dropped_sends, 0,
"the full-state drop counter must stay zero — no full-state send \
was ever recorded, so a non-zero value means the two overflows \
were conflated"
);
assert_eq!(window.attribution_dropped_bytes, 0);
let json = payload_mix_json(
&window.arms(),
&window.top_contracts(),
&window.top_not_efficient_contracts(),
&total,
window.contract_full_state_bytes.values().sum(),
window.contract_full_state_bytes.len() as u64,
window.attribution_dropped_sends,
window.attribution_dropped_bytes,
window.gate_stats(),
&window.tracked_missing(),
60,
);
assert_eq!(json["total_attribution_dropped_sends"], 3);
assert_eq!(json["total_attribution_dropped_bytes"], 21);
assert_eq!(
json["contracts_tracked_total"], MAX_TRACKED_CONTRACTS as u64,
"the total map's own tracked count, distinct from contracts_tracked \
(which counts the full-state map) — here 256 vs 0"
);
assert_eq!(
json["contracts_tracked"], 0,
"sanity: the two tracked counts really are different maps"
);
}
#[test]
fn total_map_caps_before_full_state_map_and_says_so() {
let mix = PayloadMix::new();
let id = |i: usize| {
let mut raw = [0u8; 32];
raw[0] = (i % 256) as u8;
raw[1] = (i / 256) as u8;
ContractInstanceId::new(raw)
};
for i in 0..MAX_TRACKED_CONTRACTS {
mix.record_delivered(PayloadArm::Delta, &id(i), 10, None, None);
}
let newcomer = id(MAX_TRACKED_CONTRACTS + 1);
mix.record_delivered(PayloadArm::FullNoOurSummary, &newcomer, 5_000, None, None);
let window = mix.take_window();
assert!(
window
.top_contracts()
.iter()
.any(|(cid, bytes)| *cid == newcomer && *bytes == 5_000),
"precondition: the full-state map still had room for the newcomer"
);
assert!(
!window
.total_attribution()
.contracts
.iter()
.any(|(cid, _, _)| *cid == newcomer),
"precondition: the total map was full and refused it"
);
assert_eq!(
window.total_attribution().dropped_bytes,
5_000,
"a contract with full-state bytes and NO total entry must be \
reported as a total-map drop; otherwise the published numerator \
exceeds its own denominator with nothing to explain why"
);
assert_eq!(
window.attribution_dropped_bytes, 0,
"the full-state map did admit it, so nothing was dropped there"
);
}
#[test]
fn concurrent_records_racing_a_rollup_conserve_bytes() {
use std::sync::Arc;
const THREADS: usize = 4;
const PER_THREAD: usize = 500;
let mix = Arc::new(PayloadMix::new());
let stop = Arc::new(std::sync::atomic::AtomicBool::new(false));
let drained_total = Arc::new(Mutex::new(0u64));
let drainer = {
let mix = Arc::clone(&mix);
let stop = Arc::clone(&stop);
let drained_total = Arc::clone(&drained_total);
std::thread::spawn(move || {
while !stop.load(std::sync::atomic::Ordering::Relaxed) {
let w = mix.take_window();
let sum: u64 = w.arms().iter().map(|(_, _, b)| b).sum();
*drained_total.lock() += sum;
std::thread::sleep(Duration::from_micros(50));
}
})
};
let writers: Vec<_> = (0..THREADS)
.map(|t| {
let mix = Arc::clone(&mix);
std::thread::spawn(move || {
for _ in 0..PER_THREAD {
mix.record_delivered(
PayloadArm::FullNotEfficient,
&contract(t as u8),
7,
None,
None,
);
}
})
})
.collect();
for w in writers {
w.join().unwrap();
}
stop.store(true, std::sync::atomic::Ordering::Relaxed);
drainer.join().unwrap();
let leftover: u64 = mix.take_window().arms().iter().map(|(_, _, b)| b).sum();
let total = *drained_total.lock() + leftover;
assert_eq!(
total,
(THREADS * PER_THREAD * 7) as u64,
"bytes were lost or double-counted across a concurrent rollover"
);
}
#[test]
fn full_state_share_excludes_deltas() {
let arms = vec![
(PayloadArm::Delta, 3, 300),
(PayloadArm::FullDeltaSuppressed, 0, 0),
(PayloadArm::FullNotEfficient, 1, 700),
(PayloadArm::FullComputeFailed, 0, 0),
(PayloadArm::FullNoTheirSummaryUntracked, 0, 0),
];
let json = payload_mix_json(
&arms,
&[],
&[],
&TotalAttribution::default(),
0,
0,
0,
0,
NotEfficientGateStats::default(),
&[],
60,
);
assert_eq!(json["total_bytes"], 1000);
assert_eq!(json["full_state_bytes"], 700);
assert_eq!(json["full_state_byte_share"], 0.7);
assert_eq!(json["delta_sends"], 3);
assert_eq!(json["full_not_efficient_bytes"], 700);
}
#[test]
fn no_summary_split_reports_each_cause_and_the_legacy_aggregate() {
let mix = PayloadMix::new();
mix.record_delivered(PayloadArm::FullNoOurSummary, &contract(1), 100, None, None);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&contract(2),
200,
None,
None,
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryTracked,
&contract(3),
300,
None,
None,
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&contract(2),
400,
None,
None,
);
let window = mix.take_window();
let json = payload_mix_json(
&window.arms(),
&window.top_contracts(),
&window.top_not_efficient_contracts(),
&window.total_attribution(),
window.contract_full_state_bytes.values().sum(),
window.contract_full_state_bytes.len() as u64,
window.attribution_dropped_sends,
window.attribution_dropped_bytes,
window.gate_stats(),
&[],
60,
);
assert_eq!(json["full_no_our_summary_bytes"], 100);
assert_eq!(json["full_no_their_summary_untracked_bytes"], 600);
assert_eq!(json["full_no_their_summary_untracked_sends"], 2);
assert_eq!(json["full_no_their_summary_tracked_bytes"], 300);
assert_eq!(
json["full_no_summary_bytes"], 1000,
"the pre-split aggregate must still be published as the sum of the \
three causes, or the split silently zeroes every dashboard and \
analysis script that queries `full_no_summary_bytes` by name"
);
assert_eq!(json["full_no_summary_sends"], 4);
}
fn emit(mix: &PayloadMix) -> serde_json::Value {
let window = mix.take_window();
payload_mix_json(
&window.arms(),
&window.top_contracts(),
&window.top_not_efficient_contracts(),
&window.total_attribution(),
window.contract_full_state_bytes.values().sum(),
window.contract_full_state_bytes.len() as u64,
window.attribution_dropped_sends,
window.attribution_dropped_bytes,
window.gate_stats(),
&window.tracked_missing(),
60,
)
}
#[test]
fn tracked_arm_splits_by_missing_reason_and_reconciles() {
let mix = PayloadMix::new();
mix.record_delivered(
PayloadArm::FullNoTheirSummaryTracked,
&contract(1),
100,
None,
Some(SummaryMissingReason::NeverPopulated),
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryTracked,
&contract(2),
250,
None,
Some(SummaryMissingReason::ClearedByNoneReport),
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryTracked,
&contract(3),
30,
None,
Some(SummaryMissingReason::ClearedByResync),
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryTracked,
&contract(4),
7,
None,
Some(SummaryMissingReason::ClearedByDeltaApplyFailure),
);
let json = emit(&mix);
assert_eq!(json["tracked_missing_never_populated_bytes"], 100);
assert_eq!(json["tracked_missing_never_populated_sends"], 1);
assert_eq!(json["tracked_missing_none_report_bytes"], 250);
assert_eq!(json["tracked_missing_resync_bytes"], 30);
assert_eq!(json["tracked_missing_delta_apply_failed_bytes"], 7);
assert_eq!(
json["full_no_their_summary_tracked_bytes"], 387,
"the arm total must equal the sum of its reasons"
);
assert_eq!(
json["tracked_missing_unattributed_bytes"], 0,
"every tracked send carried a reason, so the residual must be zero"
);
assert_eq!(json["tracked_missing_unattributed_sends"], 0);
}
#[test]
fn tracked_send_without_a_reason_is_reported_as_unattributed() {
let mix = PayloadMix::new();
mix.record_delivered(
PayloadArm::FullNoTheirSummaryTracked,
&contract(1),
100,
None,
Some(SummaryMissingReason::NeverPopulated),
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryTracked,
&contract(2),
900,
None,
None,
);
let json = emit(&mix);
assert_eq!(json["tracked_missing_never_populated_bytes"], 100);
assert_eq!(
json["tracked_missing_unattributed_bytes"], 900,
"an untagged tracked send must be visible as a residual, not \
silently attributed to a reason that did not cause it"
);
assert_eq!(json["tracked_missing_unattributed_sends"], 1);
}
#[test]
fn missing_reason_is_ignored_on_arms_other_than_tracked() {
let mix = PayloadMix::new();
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&contract(1),
500,
None,
Some(SummaryMissingReason::NeverPopulated),
);
mix.record_delivered(
PayloadArm::Delta,
&contract(2),
10,
None,
Some(SummaryMissingReason::ClearedByResync),
);
let json = emit(&mix);
for reason in SummaryMissingReason::ALL {
assert_eq!(
json[format!("tracked_missing_{}_bytes", reason.as_str())],
0,
"a reason paired with a non-tracked arm must not be counted"
);
}
assert_eq!(json["tracked_missing_unattributed_bytes"], 0);
}
#[test]
fn not_efficient_reports_the_gate_inputs_it_refused_on() {
let mix = PayloadMix::new();
mix.record_delivered(
PayloadArm::FullNotEfficient,
&contract(1),
1000,
Some((600, 1000)),
None,
);
mix.record_delivered(
PayloadArm::FullNotEfficient,
&contract(1),
2000,
Some((1400, 2000)),
None,
);
mix.record_delivered(PayloadArm::Delta, &contract(1), 10, Some((99999, 1)), None);
let window = mix.take_window();
assert_eq!(window.gate_stats().summary_bytes_sum, 2000);
assert_eq!(window.gate_stats().state_bytes_sum, 3000);
assert_eq!(window.gate_stats().summary_bytes_max, 1400);
assert_eq!(window.gate_stats().state_bytes_max, 2000);
let json = payload_mix_json(
&window.arms(),
&window.top_contracts(),
&window.top_not_efficient_contracts(),
&window.total_attribution(),
window.contract_full_state_bytes.values().sum(),
window.contract_full_state_bytes.len() as u64,
window.attribution_dropped_sends,
window.attribution_dropped_bytes,
window.gate_stats(),
&[],
60,
);
assert_eq!(json["not_efficient_summary_bytes_sum"], 2000);
assert_eq!(json["not_efficient_state_bytes_sum"], 3000);
assert_eq!(json["not_efficient_summary_bytes_max"], 1400);
assert_eq!(
json["not_efficient_summary_to_state_bytes_ratio"],
2000.0 / 3000.0
);
}
#[test]
fn not_efficient_ratio_is_null_when_the_gate_never_fired() {
let mix = PayloadMix::new();
mix.record_delivered(PayloadArm::Delta, &contract(1), 10, None, None);
let window = mix.take_window();
let json = payload_mix_json(
&window.arms(),
&window.top_contracts(),
&window.top_not_efficient_contracts(),
&window.total_attribution(),
0,
0,
0,
0,
window.gate_stats(),
&[],
60,
);
assert!(json["not_efficient_summary_to_state_bytes_ratio"].is_null());
}
#[test]
fn empty_window_reports_zero_share_not_nan() {
let arms: Vec<_> = PayloadArm::ALL.iter().map(|a| (*a, 0, 0)).collect();
let json = payload_mix_json(
&arms,
&[],
&[],
&TotalAttribution::default(),
0,
0,
0,
0,
NotEfficientGateStats::default(),
&[],
60,
);
assert_eq!(json["full_state_byte_share"], 0.0);
assert_eq!(json["total_bytes"], 0);
}
#[test]
fn contract_attribution_is_bounded_and_reports_overflow() {
let mix = PayloadMix::new();
for i in 0..(MAX_TRACKED_CONTRACTS + 20) {
let mut raw = [0u8; 32];
raw[0] = (i % 256) as u8;
raw[1] = (i / 256) as u8;
mix.record_delivered(
PayloadArm::FullNotEfficient,
&ContractInstanceId::new(raw),
5,
None,
None,
);
}
let window = mix.take_window();
assert!(
window.contract_full_state_bytes.len() <= MAX_TRACKED_CONTRACTS,
"attribution map exceeded its cap: {}",
window.contract_full_state_bytes.len()
);
assert_eq!(
window.attribution_dropped_sends, 20,
"overflow must be reported, not dropped silently"
);
assert_eq!(
window.attribution_dropped_bytes, 100,
"the bytes behind unattributed sends must be reported too"
);
assert!(window.top_contracts().len() <= TOP_CONTRACTS_REPORTED);
let next = mix.take_window();
assert!(next.contract_full_state_bytes.is_empty());
assert_eq!(next.attribution_dropped_sends, 0);
assert_eq!(next.attribution_dropped_bytes, 0);
}
#[test]
fn repeated_sends_from_one_over_cap_contract_count_as_sends() {
let mix = PayloadMix::new();
for i in 0..MAX_TRACKED_CONTRACTS {
let mut raw = [0u8; 32];
raw[0] = (i % 256) as u8;
raw[1] = (i / 256) as u8;
mix.record_delivered(
PayloadArm::FullNotEfficient,
&ContractInstanceId::new(raw),
1,
None,
None,
);
}
let mut raw = [9u8; 32];
raw[31] = 7;
let over_cap = ContractInstanceId::new(raw);
for _ in 0..1000 {
mix.record_delivered(PayloadArm::FullNotEfficient, &over_cap, 3, None, None);
}
let window = mix.take_window();
assert_eq!(window.attribution_dropped_sends, 1000);
assert_eq!(window.attribution_dropped_bytes, 3000);
assert!(!window.contract_full_state_bytes.contains_key(&over_cap));
}
#[test]
fn top_contracts_sort_is_deterministic() {
let mix = PayloadMix::new();
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&contract(9),
100,
None,
None,
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&contract(2),
100,
None,
None,
);
mix.record_delivered(
PayloadArm::FullNoTheirSummaryUntracked,
&contract(5),
500,
None,
None,
);
let top = mix.take_window().top_contracts();
assert_eq!(top[0].0, contract(5), "largest first");
assert_eq!(top[1].0, contract(2), "tie broken by contract id");
assert_eq!(top[2].0, contract(9));
}
#[test]
fn delta_sends_are_not_attributed_as_full_state() {
let mix = PayloadMix::new();
mix.record_delivered(PayloadArm::Delta, &contract(7), 1234, None, None);
let window = mix.take_window();
assert!(
window.contract_full_state_bytes.is_empty(),
"delta bytes leaked into full-state attribution: {:?}",
window.contract_full_state_bytes
);
assert_eq!(window.arms()[PayloadArm::Delta.index()].2, 1234);
}
#[test]
fn reported_window_tracks_actual_elapsed_not_nominal_cadence() {
assert_eq!(rollup_window_secs(ROLLUP_WINDOW), 60);
assert_eq!(rollup_window_secs(Duration::from_secs(150)), 150);
assert_eq!(
rollup_window_secs(Duration::from_millis(90_400)),
90,
"sub-second remainder rounds to nearest"
);
assert_eq!(rollup_window_secs(Duration::ZERO), 1);
assert_eq!(rollup_window_secs(Duration::from_millis(200)), 1);
}
#[test]
fn every_full_state_arm_attributes_to_its_contract() {
for arm in PayloadArm::ALL.iter().filter(|a| a.is_full_state()) {
let mix = PayloadMix::new();
mix.record_delivered(*arm, &contract(3), 99, None, None);
let top = mix.take_window().top_contracts();
assert_eq!(
top,
vec![(contract(3), 99)],
"{arm:?} must attribute its full-state bytes to the contract"
);
}
}
}