1use klvmr::allocator::{Allocator, Atom, NodePtr, SExp};
2use klvmr::reduction::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}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
169#[error("validation error: {1:?}")]
170pub struct ValidationErr(pub NodePtr, pub ErrorCode);
171
172impl From<EvalErr> for ValidationErr {
173 fn from(v: EvalErr) -> Self {
174 if v.1 == "cost exceeded" {
175 ValidationErr(v.0, ErrorCode::CostExceeded)
176 } else {
177 ValidationErr(v.0, 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 }
363 }
364}
365
366pub fn rest(a: &Allocator, n: NodePtr) -> Result<NodePtr, ValidationErr> {
367 match a.sexp(n) {
368 SExp::Pair(_, right) => Ok(right),
369 SExp::Atom => Err(ValidationErr(n, ErrorCode::InvalidCondition)),
370 }
371}
372
373pub fn next(a: &Allocator, n: NodePtr) -> Result<Option<(NodePtr, NodePtr)>, ValidationErr> {
374 match a.sexp(n) {
375 SExp::Pair(left, right) => Ok(Some((left, right))),
376 SExp::Atom => {
377 if a.atom_len(n) == 0 {
379 Ok(None)
380 } else {
381 Err(ValidationErr(n, ErrorCode::InvalidCondition))
382 }
383 }
384 }
385}
386
387pub fn atom(a: &Allocator, n: NodePtr, code: ErrorCode) -> Result<Atom<'_>, ValidationErr> {
388 match a.sexp(n) {
389 SExp::Atom => Ok(a.atom(n)),
390 SExp::Pair(..) => Err(ValidationErr(n, code)),
391 }
392}
393
394pub fn check_nil(a: &Allocator, n: NodePtr) -> Result<(), ValidationErr> {
395 if atom(a, n, ErrorCode::InvalidCondition)?.as_ref().is_empty() {
396 Ok(())
397 } else {
398 Err(ValidationErr(n, ErrorCode::InvalidCondition))
399 }
400}