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