1use clvmr::allocator::{Allocator, Atom, NodePtr, SExp};
2use clvmr::error::EvalErr;
3use thiserror::Error;
4
5#[cfg(feature = "py-bindings")]
6use pyo3::PyErr;
7
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub enum ErrorCode {
10 #[default]
11 Unknown,
12 InvalidBlockSolution,
13 InvalidCoinSolution,
14 DuplicateOutput,
15 DoubleSpend,
16 UnknownUnspent,
17 BadAggregateSignature,
18 WrongPuzzleHash,
19 BadFarmerCoinAmount,
20 InvalidCondition,
21 InvalidConditionOpcode,
22 InvalidParentId,
23 InvalidPuzzleHash,
24 InvalidPublicKey,
25 InvalidMessage,
26 InvalidCoinAmount,
27 InvalidCoinAnnouncement,
28 InvalidPuzzleAnnouncement,
29 AssertMyCoinIdFailed,
30 AssertPuzzleAnnouncementFailed,
31 AssertCoinAnnouncementFailed,
32 AssertHeightRelativeFailed,
33 AssertHeightAbsoluteFailed,
34 AssertSecondsAbsoluteFailed,
35 CoinAmountExceedsMaximum,
36 SexpError,
37 InvalidFeeLowFee,
38 MempoolConflict,
39 MintingCoin,
40 ExtendsUnknownBlock,
41 CoinbaseNotYetSpendable,
42 CostExceeded,
44 BadAdditionRoot,
45 BadRemovalRoot,
46 InvalidPospaceHash,
47 InvalidCoinbaseSignature,
48 InvalidPlotSignature,
49 TimestampTooFarInPast,
50 TimestampTooFarInFuture,
51 InvalidTransactionsFilterHash,
52 InvalidPospaceChallenge,
53 InvalidPospace,
54 InvalidHeight,
55 InvalidCoinbaseAmount,
56 InvalidMerkleRoot,
57 InvalidBlockFeeAmount,
58 InvalidWeight,
59 InvalidTotalIters,
60 BlockIsNotFinished,
61 InvalidNumIterations,
62 InvalidPot,
63 InvalidPotChallenge,
64 InvalidTransactionsGeneratorHash,
65 InvalidPoolTarget,
66 InvalidCoinbaseParent,
67 InvalidFeesCoinParent,
68 ReserveFeeConditionFailed,
69 NotBlockButHasData,
70 IsTransactionBlockButNoData,
71 InvalidPrevBlockHash,
72 InvalidTransactionsInfoHash,
73 InvalidFoliageBlockHash,
74 InvalidRewardCoins,
75 InvalidBlockCost,
76 NoEndOfSlotInfo,
77 InvalidPrevChallengeSlotHash,
78 InvalidSubEpochSummaryHash,
79 NoSubEpochSummaryHash,
80 ShouldNotMakeChallengeBlock,
81 ShouldMakeChallengeBlock,
82 InvalidChallengeChainData,
83 InvalidCcEosVdf,
84 InvalidRcEosVdf,
85 InvalidChallengeSlotHashRc,
86 InvalidPriorPointRc,
87 InvalidDeficit,
88 InvalidSubEpochSummary,
89 InvalidPrevSubEpochSummaryHash,
90 InvalidRewardChainHash,
91 InvalidSubEpochOverflow,
92 InvalidNewDifficulty,
93 InvalidNewSubSlotIters,
94 InvalidCcSpVdf,
95 InvalidRcSpVdf,
96 InvalidCcSignature,
97 InvalidRcSignature,
98 CannotMakeCcBlock,
99 InvalidRcSpPrevIp,
100 InvalidRcIpPrevIp,
101 InvalidIsTransactionBlock,
102 InvalidUrsbHash,
103 OldPoolTarget,
104 InvalidPoolSignature,
105 InvalidFoliageBlockPresence,
106 InvalidCcIpVdf,
107 InvalidRcIpVdf,
108 IpShouldBeNone,
109 InvalidRewardBlockHash,
110 InvalidMadeNonOverflowInfusions,
111 NoOverflowsInFirstSubSlotNewEpoch,
112 MempoolNotInitialized,
113 ShouldNotHaveIcc,
114 ShouldHaveIcc,
115 InvalidIccVdf,
116 InvalidIccHashCc,
117 InvalidIccHashRc,
118 InvalidIccEosVdf,
119 InvalidSpIndex,
120 TooManyBlocks,
121 InvalidCcChallenge,
122 InvalidPrefarm,
123 AssertSecondsRelativeFailed,
124 BadCoinbaseSignature,
125 NoTransactionsWhileSyncing,
127 AlreadyIncludingTransaction,
128 IncompatibleNetworkId,
129 PreSoftForkMaxGeneratorSize,
130 InvalidRequiredIters,
131 TooManyGeneratorRefs,
132 AssertMyParentIdFailed,
133 AssertMyPuzzleHashFailed,
134 AssertMyAmountFailed,
135 GeneratorRuntimeError,
136 InvalidCostResult,
137 InvalidTransactionsGeneratorRefsRoot,
138 FutureGeneratorRefs,
139 GeneratorRefHasNoGenerator,
140 DoubleSpendInFork,
141 InvalidFeeTooCloseToZero,
142 CoinAmountNegative,
143 InternalProtocolError,
144 InvalidSpendBundle,
145 FailedGettingGeneratorMultiprocessing,
146 AssertBeforeSecondsAbsoluteFailed,
147 AssertBeforeSecondsRelativeFailed,
148 AssertBeforeHeightAbsoluteFailed,
149 AssertBeforeHeightRelativeFailed,
150 AssertConcurrentSpendFailed,
151 AssertConcurrentPuzzleFailed,
152 ImpossibleSecondsRelativeConstraints,
153 ImpossibleSecondsAbsoluteConstraints,
154 ImpossibleHeightRelativeConstraints,
155 ImpossibleHeightAbsoluteConstraints,
156 AssertMyBirthSecondsFailed,
157 AssertMyBirthHeightFailed,
158 AssertEphemeralFailed,
159 EphemeralRelativeCondition,
160 InvalidSoftforkCondition,
161 InvalidSoftforkCost,
162 TooManyAnnouncements,
163 InvalidMessageMode,
164 InvalidCoinId,
165 MessageNotSentOrReceived,
166 ComplexGeneratorReceived,
167}
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
170#[error("validation error: {1:?}")]
171pub struct ValidationErr(pub NodePtr, pub ErrorCode);
172
173impl From<EvalErr> for ValidationErr {
174 fn from(v: EvalErr) -> Self {
175 match v {
176 EvalErr::CostExceeded => ValidationErr(v.node_ptr(), ErrorCode::CostExceeded),
177 _ => ValidationErr(v.node_ptr(), ErrorCode::GeneratorRuntimeError),
178 }
179 }
180}
181
182impl From<std::io::Error> for ValidationErr {
183 fn from(_: std::io::Error) -> Self {
184 ValidationErr(NodePtr::NIL, ErrorCode::GeneratorRuntimeError)
185 }
186}
187
188#[cfg(feature = "py-bindings")]
189impl From<ValidationErr> for PyErr {
190 fn from(err: ValidationErr) -> PyErr {
191 pyo3::exceptions::PyValueError::new_err(("ValidationError", u32::from(err.1)))
192 }
193}
194
195pub fn first(a: &Allocator, n: NodePtr) -> Result<NodePtr, ValidationErr> {
197 match a.sexp(n) {
198 SExp::Pair(left, _) => Ok(left),
199 SExp::Atom => Err(ValidationErr(n, ErrorCode::InvalidCondition)),
200 }
201}
202
203impl From<ErrorCode> for u32 {
205 fn from(err: ErrorCode) -> u32 {
206 match err {
207 ErrorCode::Unknown => 1,
208 ErrorCode::InvalidBlockSolution => 2,
209 ErrorCode::InvalidCoinSolution => 3,
210 ErrorCode::DuplicateOutput => 4,
211 ErrorCode::DoubleSpend => 5,
212 ErrorCode::UnknownUnspent => 6,
213 ErrorCode::BadAggregateSignature => 7,
214 ErrorCode::WrongPuzzleHash => 8,
215 ErrorCode::BadFarmerCoinAmount => 9,
216 ErrorCode::InvalidCondition
217 | ErrorCode::InvalidConditionOpcode
218 | ErrorCode::InvalidParentId
219 | ErrorCode::InvalidPuzzleHash
220 | ErrorCode::InvalidPublicKey
221 | ErrorCode::InvalidMessage
222 | ErrorCode::InvalidCoinAmount
223 | ErrorCode::InvalidCoinAnnouncement
224 | ErrorCode::InvalidPuzzleAnnouncement => 10,
225 ErrorCode::AssertMyCoinIdFailed => 11,
226 ErrorCode::AssertPuzzleAnnouncementFailed | ErrorCode::AssertCoinAnnouncementFailed => {
227 12
228 }
229 ErrorCode::AssertHeightRelativeFailed => 13,
230 ErrorCode::AssertHeightAbsoluteFailed => 14,
231 ErrorCode::AssertSecondsAbsoluteFailed => 15,
232 ErrorCode::CoinAmountExceedsMaximum => 16,
233 ErrorCode::SexpError => 17,
234 ErrorCode::InvalidFeeLowFee => 18,
235 ErrorCode::MempoolConflict => 19,
236 ErrorCode::MintingCoin => 20,
237 ErrorCode::ExtendsUnknownBlock => 21,
238 ErrorCode::CoinbaseNotYetSpendable => 22,
239 ErrorCode::CostExceeded => 23,
240 ErrorCode::BadAdditionRoot => 24,
241 ErrorCode::BadRemovalRoot => 25,
242 ErrorCode::InvalidPospaceHash => 26,
243 ErrorCode::InvalidCoinbaseSignature => 27,
244 ErrorCode::InvalidPlotSignature => 28,
245 ErrorCode::TimestampTooFarInPast => 29,
246 ErrorCode::TimestampTooFarInFuture => 30,
247 ErrorCode::InvalidTransactionsFilterHash => 31,
248 ErrorCode::InvalidPospaceChallenge => 32,
249 ErrorCode::InvalidPospace => 33,
250 ErrorCode::InvalidHeight => 34,
251 ErrorCode::InvalidCoinbaseAmount => 35,
252 ErrorCode::InvalidMerkleRoot => 36,
253 ErrorCode::InvalidBlockFeeAmount => 37,
254 ErrorCode::InvalidWeight => 38,
255 ErrorCode::InvalidTotalIters => 39,
256 ErrorCode::BlockIsNotFinished => 40,
257 ErrorCode::InvalidNumIterations => 41,
258 ErrorCode::InvalidPot => 42,
259 ErrorCode::InvalidPotChallenge => 43,
260 ErrorCode::InvalidTransactionsGeneratorHash => 44,
261 ErrorCode::InvalidPoolTarget => 45,
262 ErrorCode::InvalidCoinbaseParent => 46,
263 ErrorCode::InvalidFeesCoinParent => 47,
264 ErrorCode::ReserveFeeConditionFailed => 48,
265 ErrorCode::NotBlockButHasData => 49,
266 ErrorCode::IsTransactionBlockButNoData => 50,
267 ErrorCode::InvalidPrevBlockHash => 51,
268 ErrorCode::InvalidTransactionsInfoHash => 52,
269 ErrorCode::InvalidFoliageBlockHash => 53,
270 ErrorCode::InvalidRewardCoins => 54,
271 ErrorCode::InvalidBlockCost => 55,
272 ErrorCode::NoEndOfSlotInfo => 56,
273 ErrorCode::InvalidPrevChallengeSlotHash => 57,
274 ErrorCode::InvalidSubEpochSummaryHash => 58,
275 ErrorCode::NoSubEpochSummaryHash => 59,
276 ErrorCode::ShouldNotMakeChallengeBlock => 60,
277 ErrorCode::ShouldMakeChallengeBlock => 61,
278 ErrorCode::InvalidChallengeChainData => 62,
279 ErrorCode::InvalidCcEosVdf => 65,
280 ErrorCode::InvalidRcEosVdf => 66,
281 ErrorCode::InvalidChallengeSlotHashRc => 67,
282 ErrorCode::InvalidPriorPointRc => 68,
283 ErrorCode::InvalidDeficit => 69,
284 ErrorCode::InvalidSubEpochSummary => 70,
285 ErrorCode::InvalidPrevSubEpochSummaryHash => 71,
286 ErrorCode::InvalidRewardChainHash => 72,
287 ErrorCode::InvalidSubEpochOverflow => 73,
288 ErrorCode::InvalidNewDifficulty => 74,
289 ErrorCode::InvalidNewSubSlotIters => 75,
290 ErrorCode::InvalidCcSpVdf => 76,
291 ErrorCode::InvalidRcSpVdf => 77,
292 ErrorCode::InvalidCcSignature => 78,
293 ErrorCode::InvalidRcSignature => 79,
294 ErrorCode::CannotMakeCcBlock => 80,
295 ErrorCode::InvalidRcSpPrevIp => 81,
296 ErrorCode::InvalidRcIpPrevIp => 82,
297 ErrorCode::InvalidIsTransactionBlock => 83,
298 ErrorCode::InvalidUrsbHash => 84,
299 ErrorCode::OldPoolTarget => 85,
300 ErrorCode::InvalidPoolSignature => 86,
301 ErrorCode::InvalidFoliageBlockPresence => 87,
302 ErrorCode::InvalidCcIpVdf => 88,
303 ErrorCode::InvalidRcIpVdf => 89,
304 ErrorCode::IpShouldBeNone => 90,
305 ErrorCode::InvalidRewardBlockHash => 91,
306 ErrorCode::InvalidMadeNonOverflowInfusions => 92,
307 ErrorCode::NoOverflowsInFirstSubSlotNewEpoch => 93,
308 ErrorCode::MempoolNotInitialized => 94,
309 ErrorCode::ShouldNotHaveIcc => 95,
310 ErrorCode::ShouldHaveIcc => 96,
311 ErrorCode::InvalidIccVdf => 97,
312 ErrorCode::InvalidIccHashCc => 98,
313 ErrorCode::InvalidIccHashRc => 99,
314 ErrorCode::InvalidIccEosVdf => 100,
315 ErrorCode::InvalidSpIndex => 101,
316 ErrorCode::TooManyBlocks => 102,
317 ErrorCode::InvalidCcChallenge => 103,
318 ErrorCode::InvalidPrefarm => 104,
319 ErrorCode::AssertSecondsRelativeFailed => 105,
320 ErrorCode::BadCoinbaseSignature => 106,
321 ErrorCode::NoTransactionsWhileSyncing => 108,
323 ErrorCode::AlreadyIncludingTransaction => 109,
324 ErrorCode::IncompatibleNetworkId => 110,
325 ErrorCode::PreSoftForkMaxGeneratorSize => 111,
326 ErrorCode::InvalidRequiredIters => 112,
327 ErrorCode::TooManyGeneratorRefs => 113,
328 ErrorCode::AssertMyParentIdFailed => 114,
329 ErrorCode::AssertMyPuzzleHashFailed => 115,
330 ErrorCode::AssertMyAmountFailed => 116,
331 ErrorCode::GeneratorRuntimeError => 117,
332 ErrorCode::InvalidCostResult => 118,
333 ErrorCode::InvalidTransactionsGeneratorRefsRoot => 119,
334 ErrorCode::FutureGeneratorRefs => 120,
335 ErrorCode::GeneratorRefHasNoGenerator => 121,
336 ErrorCode::DoubleSpendInFork => 122,
337 ErrorCode::InvalidFeeTooCloseToZero => 123,
338 ErrorCode::CoinAmountNegative => 124,
339 ErrorCode::InternalProtocolError => 125,
340 ErrorCode::InvalidSpendBundle => 126,
341 ErrorCode::FailedGettingGeneratorMultiprocessing => 127,
342 ErrorCode::AssertBeforeSecondsAbsoluteFailed => 128,
343 ErrorCode::AssertBeforeSecondsRelativeFailed => 129,
344 ErrorCode::AssertBeforeHeightAbsoluteFailed => 130,
345 ErrorCode::AssertBeforeHeightRelativeFailed => 131,
346 ErrorCode::AssertConcurrentSpendFailed => 132,
347 ErrorCode::AssertConcurrentPuzzleFailed => 133,
348 ErrorCode::ImpossibleSecondsRelativeConstraints => 134,
349 ErrorCode::ImpossibleSecondsAbsoluteConstraints => 135,
350 ErrorCode::ImpossibleHeightRelativeConstraints => 136,
351 ErrorCode::ImpossibleHeightAbsoluteConstraints => 137,
352 ErrorCode::AssertMyBirthSecondsFailed => 138,
353 ErrorCode::AssertMyBirthHeightFailed => 139,
354 ErrorCode::AssertEphemeralFailed => 140,
355 ErrorCode::EphemeralRelativeCondition => 141,
356 ErrorCode::InvalidSoftforkCondition => 142,
357 ErrorCode::InvalidSoftforkCost => 143,
358 ErrorCode::TooManyAnnouncements => 144,
359 ErrorCode::InvalidMessageMode => 145,
360 ErrorCode::InvalidCoinId => 146,
361 ErrorCode::MessageNotSentOrReceived => 147,
362 ErrorCode::ComplexGeneratorReceived => 148,
363 }
364 }
365}
366
367pub fn rest(a: &Allocator, n: NodePtr) -> Result<NodePtr, ValidationErr> {
368 match a.sexp(n) {
369 SExp::Pair(_, right) => Ok(right),
370 SExp::Atom => Err(ValidationErr(n, ErrorCode::InvalidCondition)),
371 }
372}
373
374pub fn next(a: &Allocator, n: NodePtr) -> Result<Option<(NodePtr, NodePtr)>, ValidationErr> {
375 match a.sexp(n) {
376 SExp::Pair(left, right) => Ok(Some((left, right))),
377 SExp::Atom => {
378 if a.atom_len(n) == 0 {
380 Ok(None)
381 } else {
382 Err(ValidationErr(n, ErrorCode::InvalidCondition))
383 }
384 }
385 }
386}
387
388pub fn atom(a: &Allocator, n: NodePtr, code: ErrorCode) -> Result<Atom<'_>, ValidationErr> {
389 match a.sexp(n) {
390 SExp::Atom => Ok(a.atom(n)),
391 SExp::Pair(..) => Err(ValidationErr(n, code)),
392 }
393}
394
395pub fn check_nil(a: &Allocator, n: NodePtr) -> Result<(), ValidationErr> {
396 if atom(a, n, ErrorCode::InvalidCondition)?.as_ref().is_empty() {
397 Ok(())
398 } else {
399 Err(ValidationErr(n, ErrorCode::InvalidCondition))
400 }
401}