Skip to main content

ic_query/sns/report/model/reports/neurons/
diff.rs

1//! Module: sns::report::model::reports::neurons::diff
2//!
3//! Responsibility: local SNS reward-checkpoint reconciliation DTOs.
4//! Does not own: checkpoint collection, filesystem loading, or live source calls.
5//! Boundary: preserves joined raw maturity deltas, typed invalid reasons, and allocations.
6
7use super::SnsPolicyObservationStatus;
8use crate::sns::report::MainnetSnsCanisters;
9use serde::{Deserialize, Serialize};
10
11///
12/// SnsRewardAllocationStatus
13///
14/// Reconciliation outcome for one pair of SNS reward checkpoints.
15///
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
18#[serde(rename_all = "snake_case")]
19pub enum SnsRewardAllocationStatus {
20    /// Every invariant reconciled to one positive native reward distribution.
21    Valid,
22    /// Every invariant reconciled to a native distribution of zero.
23    NoAllocation,
24    /// At least one checkpoint, continuity, policy, or reconciliation invariant failed.
25    Invalid,
26}
27
28impl SnsRewardAllocationStatus {
29    /// Return the stable report label for this allocation status.
30    #[must_use]
31    pub const fn as_str(self) -> &'static str {
32        match self {
33            Self::Valid => "valid",
34            Self::NoAllocation => "no_allocation",
35            Self::Invalid => "invalid",
36        }
37    }
38}
39
40///
41/// SnsRewardDiffInvalidReasonKind
42///
43/// Stable category for one failed reward-diff invariant.
44///
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
47#[serde(rename_all = "snake_case")]
48pub enum SnsRewardDiffInvalidReasonKind {
49    /// The earlier checkpoint failed pure raw-evidence validation.
50    BeforeCheckpointInvalid,
51    /// The later checkpoint failed pure raw-evidence validation.
52    AfterCheckpointInvalid,
53    /// A stable network or canister identity differs between checkpoints.
54    TargetMismatch,
55    /// The later collection started before the earlier collection completed.
56    CheckpointOrder,
57    /// A recomputed checkpoint policy is not observed satisfied.
58    PolicyNotObservedSatisfied,
59    /// Canonical reward-event timestamps are missing or not strictly increasing.
60    RewardEventOrder,
61    /// The later distribution did not occur after the earlier collection completed.
62    RewardEventCoverage,
63    /// Native reward round continuity does not describe the immediate next event.
64    RewardEventContinuity,
65    /// A neuron present before is absent after.
66    NeuronMissingAfter,
67    /// A later-only neuron cannot truthfully receive a synthetic zero before value.
68    NewNeuronCreationUnexplained,
69    /// A matched neuron changed its reported creation timestamp.
70    NeuronCreationTimestampChanged,
71    /// A neuron's combined maturity decreased.
72    NegativeMaturityDelta,
73    /// Aggregate before/after maturity does not reconcile to the native distribution.
74    AggregateReconciliation,
75    /// The sum of joined neuron deltas does not reconcile to the native distribution.
76    PerNeuronReconciliation,
77    /// Checked arithmetic could not represent a required value.
78    Arithmetic,
79}
80
81impl SnsRewardDiffInvalidReasonKind {
82    /// Return the stable report label for this invalid-reason category.
83    #[must_use]
84    pub const fn as_str(self) -> &'static str {
85        match self {
86            Self::BeforeCheckpointInvalid => "before_checkpoint_invalid",
87            Self::AfterCheckpointInvalid => "after_checkpoint_invalid",
88            Self::TargetMismatch => "target_mismatch",
89            Self::CheckpointOrder => "checkpoint_order",
90            Self::PolicyNotObservedSatisfied => "policy_not_observed_satisfied",
91            Self::RewardEventOrder => "reward_event_order",
92            Self::RewardEventCoverage => "reward_event_coverage",
93            Self::RewardEventContinuity => "reward_event_continuity",
94            Self::NeuronMissingAfter => "neuron_missing_after",
95            Self::NewNeuronCreationUnexplained => "new_neuron_creation_unexplained",
96            Self::NeuronCreationTimestampChanged => "neuron_creation_timestamp_changed",
97            Self::NegativeMaturityDelta => "negative_maturity_delta",
98            Self::AggregateReconciliation => "aggregate_reconciliation",
99            Self::PerNeuronReconciliation => "per_neuron_reconciliation",
100            Self::Arithmetic => "arithmetic",
101        }
102    }
103}
104
105///
106/// SnsRewardDiffInvalidReason
107///
108/// One typed failed invariant retained in an invalid reward diff.
109///
110
111#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
112#[serde(deny_unknown_fields)]
113pub struct SnsRewardDiffInvalidReason {
114    /// Stable machine-readable reason category.
115    pub kind: SnsRewardDiffInvalidReasonKind,
116    /// Full neuron identifier when the failure belongs to one joined row.
117    pub neuron_id: Option<String>,
118    /// Deterministic human-readable detail retaining compared raw values.
119    pub detail: String,
120}
121
122///
123/// SnsRewardDiffCheckpointRef
124///
125/// Stable identity and event position retained for one compared checkpoint.
126///
127
128#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
129#[serde(deny_unknown_fields)]
130pub struct SnsRewardDiffCheckpointRef {
131    /// Requested network identity.
132    pub network: String,
133    /// Stable SNS-W canister principal.
134    pub sns_wasm_canister_id: String,
135    /// Mutable SNS-W list position retained only as display metadata.
136    pub id: usize,
137    /// Mutable SNS name retained only as display metadata.
138    pub name: String,
139    /// Complete deployed-SNS canister identity, serialized as flat fields.
140    #[serde(flatten)]
141    pub canisters: MainnetSnsCanisters,
142    /// Explicit source endpoint retained as provenance, not target identity.
143    pub source_endpoint: String,
144    /// Collection completion timestamp from the checkpoint.
145    pub collection_completed_at_unix_secs: u64,
146    /// Canonical reward-event position.
147    pub reward_event_end_timestamp_seconds: Option<u64>,
148    /// Native timestamp at which the represented reward distribution actually ran.
149    pub reward_event_actual_timestamp_seconds: u64,
150    /// Deprecated native round retained as continuity evidence.
151    pub reward_event_round: u64,
152    /// Native number of rounds covered by the event when supplied.
153    pub rounds_since_last_distribution: Option<u64>,
154    /// Exact maturity distributed by this checkpoint's native reward event.
155    pub distributed_e8s_equivalent: u64,
156}
157
158///
159/// SnsRewardDiffRow
160///
161/// Joined raw maturity and policy evidence for one full SNS neuron identifier.
162///
163
164#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
165#[serde(deny_unknown_fields)]
166pub struct SnsRewardDiffRow {
167    /// Exact 32-byte neuron identifier as lowercase hexadecimal text.
168    pub neuron_id: String,
169    /// Earlier combined maturity, or no value for a supported new neuron.
170    pub before_combined_maturity_e8s_equivalent: Option<u64>,
171    /// Later combined maturity, or no value when the neuron disappeared.
172    pub after_combined_maturity_e8s_equivalent: Option<u64>,
173    /// Raw signed later-minus-earlier combined maturity delta.
174    pub maturity_delta_e8s_equivalent: i128,
175    /// Whether the neuron was first observed after the earlier checkpoint.
176    pub new_neuron: bool,
177    /// Whether an earlier neuron was absent from the later checkpoint.
178    pub missing_after: bool,
179    /// Earlier creation timestamp when the neuron existed.
180    pub before_created_timestamp_seconds: Option<u64>,
181    /// Later creation timestamp when the neuron existed.
182    pub after_created_timestamp_seconds: Option<u64>,
183    /// Earlier neuron-local mint-conversion observation when present.
184    pub before_maturity_mint_conversion_observed_disabled: Option<SnsPolicyObservationStatus>,
185    /// Later neuron-local mint-conversion observation when present.
186    pub after_maturity_mint_conversion_observed_disabled: Option<SnsPolicyObservationStatus>,
187    /// Earlier neuron-local manual-staking observation when present.
188    pub before_manual_maturity_staking_observed_disabled: Option<SnsPolicyObservationStatus>,
189    /// Later neuron-local manual-staking observation when present.
190    pub after_manual_maturity_staking_observed_disabled: Option<SnsPolicyObservationStatus>,
191    /// Earlier pending maturity-disbursement count.
192    pub before_pending_maturity_disbursement_count: Option<usize>,
193    /// Later pending maturity-disbursement count.
194    pub after_pending_maturity_disbursement_count: Option<usize>,
195    /// Whether raw permission, pending-disbursement, or auto-stake evidence changed.
196    pub policy_evidence_changed: bool,
197    /// Allocation numerator, populated only for a valid positive distribution.
198    pub allocation_numerator_e8s_equivalent: Option<u64>,
199    /// Shared allocation denominator, populated only for a valid positive distribution.
200    pub allocation_denominator_e8s_equivalent: Option<u64>,
201}
202
203///
204/// SnsRewardDiffReport
205///
206/// Pure local reconciliation of two untrusted SNS reward checkpoints.
207///
208
209#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
210#[serde(deny_unknown_fields)]
211pub struct SnsRewardDiffReport {
212    /// Reward-diff report schema version.
213    pub schema_version: u32,
214    /// Earlier checkpoint identity and event position.
215    pub before: SnsRewardDiffCheckpointRef,
216    /// Later checkpoint identity and event position.
217    pub after: SnsRewardDiffCheckpointRef,
218    /// Recomputed earlier aggregate combined maturity when representable.
219    pub aggregate_before_combined_maturity_e8s_equivalent: Option<u64>,
220    /// Recomputed later aggregate combined maturity when representable.
221    pub aggregate_after_combined_maturity_e8s_equivalent: Option<u64>,
222    /// Raw signed later-minus-earlier aggregate maturity delta when representable.
223    pub aggregate_maturity_delta_e8s_equivalent: Option<i128>,
224    /// Checked sum of every joined raw signed neuron delta when representable.
225    pub summed_neuron_maturity_delta_e8s_equivalent: Option<i128>,
226    /// Native distributed value against which both delta paths reconcile.
227    pub distributed_e8s_equivalent: u64,
228    /// Whether aggregate before/after maturity exactly matches the native distribution.
229    pub aggregate_reconciled: bool,
230    /// Whether the sum of joined neuron deltas exactly matches the native distribution.
231    pub per_neuron_reconciled: bool,
232    /// Recomputed earlier global maturity-conversion policy status when available.
233    pub before_policy_status: Option<SnsPolicyObservationStatus>,
234    /// Recomputed later global maturity-conversion policy status when available.
235    pub after_policy_status: Option<SnsPolicyObservationStatus>,
236    /// Typed allocation outcome.
237    pub allocation_status: SnsRewardAllocationStatus,
238    /// Every failed comparison and reconciliation invariant.
239    pub invalid_reasons: Vec<SnsRewardDiffInvalidReason>,
240    /// Canonically neuron-id-ordered joined rows.
241    pub rows: Vec<SnsRewardDiffRow>,
242    /// Always false because local JSON evidence has no content-authenticity proof.
243    pub checkpoint_content_authenticated: bool,
244}