1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//! Evidence REMARK wire: encoder + parser.
//!
//! Implements [DSL-102](../../docs/requirements/domains/remark/specs/DSL-102.md).
//! Traces to: [SPEC §16.1](../../docs/resources/SPEC.md).
//!
//! # Wire format
//!
//! ```text
//! payload = SLASH_EVIDENCE_REMARK_MAGIC_V1 || serde_json(SlashingEvidence)
//! ```
//!
//! The magic prefix (`b"DIG_SLASH_EVIDENCE_V1\0"`) namespaces our
//! payloads against foreign REMARK apps. The body is JSON — not
//! bincode — because downstream tooling (block explorers, auditors,
//! cross-client validators) benefits from a human-readable payload
//! that survives casual inspection. On-chain size overhead is
//! bounded by DSL-109's payload cap.
//!
//! # Parser policy
//!
//! Consensus hands us every REMARK payload it saw in a block's
//! spends; most of those payloads belong to unrelated apps. We
//! MUST silently skip (not error) on:
//!
//! - payload shorter than the magic prefix,
//! - payload with the wrong magic,
//! - payload with valid magic but malformed JSON after the prefix,
//! - payload with valid magic + valid JSON but of the wrong type.
//!
//! Returning an error on any of these would make the parser
//! unusable in production: a single foreign REMARK in a block
//! would poison every valid slashing submission alongside it.
use Allocator;
use node_to_bytes;
use Bytes32;
use crateSLASH_EVIDENCE_REMARK_MAGIC_V1;
use crateSlashingError;
use crateSlashingEvidence;
/// Encode a `SlashingEvidence` as a REMARK payload.
///
/// Returns `MAGIC || serde_json(ev)` as a single contiguous
/// byte vector ready to be embedded into a CLVM `REMARK`
/// condition.
///
/// # Errors
///
/// Propagates any `serde_json` serialisation error. In practice
/// `SlashingEvidence` is serde-safe by construction (every field
/// derives `Serialize`), so this only fires if `serde_json`'s own
/// buffer allocation fails — which is a fatal process-level
/// condition, not a recoverable input issue.
/// Extract every valid `SlashingEvidence` from a slice of REMARK
/// payloads.
///
/// The input typically comes from the consensus layer's scan of a
/// block's spends: every REMARK condition's byte payload in input
/// order. This parser is order-preserving and silent-skip: any
/// payload whose prefix does not match `SLASH_EVIDENCE_REMARK_MAGIC_V1`,
/// or whose post-prefix bytes do not deserialise as a
/// `SlashingEvidence`, is dropped on the floor. Foreign REMARK
/// payloads never raise.
///
/// # Complexity
///
/// O(total_bytes) — we iterate each payload once and pass the
/// post-prefix slice directly to `serde_json::from_slice` (no
/// intermediate allocation).
/// CLVM puzzle reveal that, when evaluated with an empty solution,
/// emits exactly one `REMARK` condition carrying the DSL-102
/// encoded wire payload.
///
/// Implements [DSL-103](../../docs/requirements/domains/remark/specs/DSL-103.md).
///
/// # Shape
///
/// The puzzle is a constant-returning quote:
///
/// ```text
/// (q . ((1 . (<wire_bytes> . nil))))
/// ```
///
/// In CLVM the quote opcode is also atom `1`; context disambiguates
/// the outer quote (puzzle head) from the inner REMARK opcode
/// (condition head). Executing the puzzle returns the inner list
/// `((1 <wire>))` — one REMARK condition in canonical proper-list
/// form `(opcode arg)`.
///
/// Why a constant-return puzzle instead of something solution-driven:
/// the reporter MUST commit to the exact payload at coin-creation
/// time so that the `puzzle_hash` (= tree-hash of the reveal) binds
/// the evidence inseparably to the coin. If the solution could
/// influence the emitted payload, an attacker could substitute a
/// different payload after coin creation and break DSL-104
/// admission.
///
/// # Errors
///
/// - `SlashingError::InvalidSlashingEvidence` wrapping the
/// underlying serde / CLVM error, if encoding or serialisation
/// fails. In practice serialisation is infallible; the error
/// path exists only to propagate allocator limits deterministically.
/// `tree_hash` of the evidence REMARK puzzle reveal.
///
/// Implements [DSL-103](../../docs/requirements/domains/remark/specs/DSL-103.md).
/// The returned `Bytes32` is the coin's `puzzle_hash` for the
/// reporter spend admitted on-chain (DSL-104).
///
/// # Determinism
///
/// `clvm_utils::tree_hash_from_bytes` is purely a function of the
/// serialised CLVM bytes, and `slashing_evidence_remark_puzzle_reveal_v1`
/// itself is deterministic (serde_json with no HashMap fields +
/// a fixed CLVM structure), so the returned hash is stable across
/// processes and platforms.