use clvmr::allocator::{Allocator, Atom, NodePtr, SExp};
use clvmr::error::EvalErr;
use thiserror::Error;
#[cfg(feature = "py-bindings")]
use pyo3::PyErr;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ErrorCode {
#[default]
Unknown,
InvalidBlockSolution,
InvalidCoinSolution,
DuplicateOutput,
DoubleSpend,
UnknownUnspent,
BadAggregateSignature,
WrongPuzzleHash,
BadFarmerCoinAmount,
InvalidCondition,
InvalidConditionOpcode,
InvalidParentId,
InvalidPuzzleHash,
InvalidPublicKey,
InvalidMessage,
InvalidCoinAmount,
InvalidCoinAnnouncement,
InvalidPuzzleAnnouncement,
AssertMyCoinIdFailed,
AssertPuzzleAnnouncementFailed,
AssertCoinAnnouncementFailed,
AssertHeightRelativeFailed,
AssertHeightAbsoluteFailed,
AssertSecondsAbsoluteFailed,
CoinAmountExceedsMaximum,
SexpError,
InvalidFeeLowFee,
MempoolConflict,
MintingCoin,
ExtendsUnknownBlock,
CoinbaseNotYetSpendable,
CostExceeded,
BadAdditionRoot,
BadRemovalRoot,
InvalidPospaceHash,
InvalidCoinbaseSignature,
InvalidPlotSignature,
TimestampTooFarInPast,
TimestampTooFarInFuture,
InvalidTransactionsFilterHash,
InvalidPospaceChallenge,
InvalidPospace,
InvalidHeight,
InvalidCoinbaseAmount,
InvalidMerkleRoot,
InvalidBlockFeeAmount,
InvalidWeight,
InvalidTotalIters,
BlockIsNotFinished,
InvalidNumIterations,
InvalidPot,
InvalidPotChallenge,
InvalidTransactionsGeneratorHash,
InvalidPoolTarget,
InvalidCoinbaseParent,
InvalidFeesCoinParent,
ReserveFeeConditionFailed,
NotBlockButHasData,
IsTransactionBlockButNoData,
InvalidPrevBlockHash,
InvalidTransactionsInfoHash,
InvalidFoliageBlockHash,
InvalidRewardCoins,
InvalidBlockCost,
NoEndOfSlotInfo,
InvalidPrevChallengeSlotHash,
InvalidSubEpochSummaryHash,
NoSubEpochSummaryHash,
ShouldNotMakeChallengeBlock,
ShouldMakeChallengeBlock,
InvalidChallengeChainData,
InvalidCcEosVdf,
InvalidRcEosVdf,
InvalidChallengeSlotHashRc,
InvalidPriorPointRc,
InvalidDeficit,
InvalidSubEpochSummary,
InvalidPrevSubEpochSummaryHash,
InvalidRewardChainHash,
InvalidSubEpochOverflow,
InvalidNewDifficulty,
InvalidNewSubSlotIters,
InvalidCcSpVdf,
InvalidRcSpVdf,
InvalidCcSignature,
InvalidRcSignature,
CannotMakeCcBlock,
InvalidRcSpPrevIp,
InvalidRcIpPrevIp,
InvalidIsTransactionBlock,
InvalidUrsbHash,
OldPoolTarget,
InvalidPoolSignature,
InvalidFoliageBlockPresence,
InvalidCcIpVdf,
InvalidRcIpVdf,
IpShouldBeNone,
InvalidRewardBlockHash,
InvalidMadeNonOverflowInfusions,
NoOverflowsInFirstSubSlotNewEpoch,
MempoolNotInitialized,
ShouldNotHaveIcc,
ShouldHaveIcc,
InvalidIccVdf,
InvalidIccHashCc,
InvalidIccHashRc,
InvalidIccEosVdf,
InvalidSpIndex,
TooManyBlocks,
InvalidCcChallenge,
InvalidPrefarm,
AssertSecondsRelativeFailed,
BadCoinbaseSignature,
NoTransactionsWhileSyncing,
AlreadyIncludingTransaction,
IncompatibleNetworkId,
PreSoftForkMaxGeneratorSize,
InvalidRequiredIters,
TooManyGeneratorRefs,
AssertMyParentIdFailed,
AssertMyPuzzleHashFailed,
AssertMyAmountFailed,
GeneratorRuntimeError,
InvalidCostResult,
InvalidTransactionsGeneratorRefsRoot,
FutureGeneratorRefs,
GeneratorRefHasNoGenerator,
DoubleSpendInFork,
InvalidFeeTooCloseToZero,
CoinAmountNegative,
InternalProtocolError,
InvalidSpendBundle,
FailedGettingGeneratorMultiprocessing,
AssertBeforeSecondsAbsoluteFailed,
AssertBeforeSecondsRelativeFailed,
AssertBeforeHeightAbsoluteFailed,
AssertBeforeHeightRelativeFailed,
AssertConcurrentSpendFailed,
AssertConcurrentPuzzleFailed,
ImpossibleSecondsRelativeConstraints,
ImpossibleSecondsAbsoluteConstraints,
ImpossibleHeightRelativeConstraints,
ImpossibleHeightAbsoluteConstraints,
AssertMyBirthSecondsFailed,
AssertMyBirthHeightFailed,
AssertEphemeralFailed,
EphemeralRelativeCondition,
InvalidSoftforkCondition,
InvalidSoftforkCost,
TooManyAnnouncements,
InvalidMessageMode,
InvalidCoinId,
MessageNotSentOrReceived,
ComplexGeneratorReceived,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
#[error("validation error: {1:?}")]
pub struct ValidationErr(pub NodePtr, pub ErrorCode);
impl From<EvalErr> for ValidationErr {
fn from(v: EvalErr) -> Self {
match v {
EvalErr::CostExceeded => ValidationErr(v.node_ptr(), ErrorCode::CostExceeded),
_ => ValidationErr(v.node_ptr(), ErrorCode::GeneratorRuntimeError),
}
}
}
impl From<std::io::Error> for ValidationErr {
fn from(_: std::io::Error) -> Self {
ValidationErr(NodePtr::NIL, ErrorCode::GeneratorRuntimeError)
}
}
#[cfg(feature = "py-bindings")]
impl From<ValidationErr> for PyErr {
fn from(err: ValidationErr) -> PyErr {
pyo3::exceptions::PyValueError::new_err(("ValidationError", u32::from(err.1)))
}
}
pub fn first(a: &Allocator, n: NodePtr) -> Result<NodePtr, ValidationErr> {
match a.sexp(n) {
SExp::Pair(left, _) => Ok(left),
SExp::Atom => Err(ValidationErr(n, ErrorCode::InvalidCondition)),
}
}
impl From<ErrorCode> for u32 {
fn from(err: ErrorCode) -> u32 {
match err {
ErrorCode::Unknown => 1,
ErrorCode::InvalidBlockSolution => 2,
ErrorCode::InvalidCoinSolution => 3,
ErrorCode::DuplicateOutput => 4,
ErrorCode::DoubleSpend => 5,
ErrorCode::UnknownUnspent => 6,
ErrorCode::BadAggregateSignature => 7,
ErrorCode::WrongPuzzleHash => 8,
ErrorCode::BadFarmerCoinAmount => 9,
ErrorCode::InvalidCondition
| ErrorCode::InvalidConditionOpcode
| ErrorCode::InvalidParentId
| ErrorCode::InvalidPuzzleHash
| ErrorCode::InvalidPublicKey
| ErrorCode::InvalidMessage
| ErrorCode::InvalidCoinAmount
| ErrorCode::InvalidCoinAnnouncement
| ErrorCode::InvalidPuzzleAnnouncement => 10,
ErrorCode::AssertMyCoinIdFailed => 11,
ErrorCode::AssertPuzzleAnnouncementFailed | ErrorCode::AssertCoinAnnouncementFailed => {
12
}
ErrorCode::AssertHeightRelativeFailed => 13,
ErrorCode::AssertHeightAbsoluteFailed => 14,
ErrorCode::AssertSecondsAbsoluteFailed => 15,
ErrorCode::CoinAmountExceedsMaximum => 16,
ErrorCode::SexpError => 17,
ErrorCode::InvalidFeeLowFee => 18,
ErrorCode::MempoolConflict => 19,
ErrorCode::MintingCoin => 20,
ErrorCode::ExtendsUnknownBlock => 21,
ErrorCode::CoinbaseNotYetSpendable => 22,
ErrorCode::CostExceeded => 23,
ErrorCode::BadAdditionRoot => 24,
ErrorCode::BadRemovalRoot => 25,
ErrorCode::InvalidPospaceHash => 26,
ErrorCode::InvalidCoinbaseSignature => 27,
ErrorCode::InvalidPlotSignature => 28,
ErrorCode::TimestampTooFarInPast => 29,
ErrorCode::TimestampTooFarInFuture => 30,
ErrorCode::InvalidTransactionsFilterHash => 31,
ErrorCode::InvalidPospaceChallenge => 32,
ErrorCode::InvalidPospace => 33,
ErrorCode::InvalidHeight => 34,
ErrorCode::InvalidCoinbaseAmount => 35,
ErrorCode::InvalidMerkleRoot => 36,
ErrorCode::InvalidBlockFeeAmount => 37,
ErrorCode::InvalidWeight => 38,
ErrorCode::InvalidTotalIters => 39,
ErrorCode::BlockIsNotFinished => 40,
ErrorCode::InvalidNumIterations => 41,
ErrorCode::InvalidPot => 42,
ErrorCode::InvalidPotChallenge => 43,
ErrorCode::InvalidTransactionsGeneratorHash => 44,
ErrorCode::InvalidPoolTarget => 45,
ErrorCode::InvalidCoinbaseParent => 46,
ErrorCode::InvalidFeesCoinParent => 47,
ErrorCode::ReserveFeeConditionFailed => 48,
ErrorCode::NotBlockButHasData => 49,
ErrorCode::IsTransactionBlockButNoData => 50,
ErrorCode::InvalidPrevBlockHash => 51,
ErrorCode::InvalidTransactionsInfoHash => 52,
ErrorCode::InvalidFoliageBlockHash => 53,
ErrorCode::InvalidRewardCoins => 54,
ErrorCode::InvalidBlockCost => 55,
ErrorCode::NoEndOfSlotInfo => 56,
ErrorCode::InvalidPrevChallengeSlotHash => 57,
ErrorCode::InvalidSubEpochSummaryHash => 58,
ErrorCode::NoSubEpochSummaryHash => 59,
ErrorCode::ShouldNotMakeChallengeBlock => 60,
ErrorCode::ShouldMakeChallengeBlock => 61,
ErrorCode::InvalidChallengeChainData => 62,
ErrorCode::InvalidCcEosVdf => 65,
ErrorCode::InvalidRcEosVdf => 66,
ErrorCode::InvalidChallengeSlotHashRc => 67,
ErrorCode::InvalidPriorPointRc => 68,
ErrorCode::InvalidDeficit => 69,
ErrorCode::InvalidSubEpochSummary => 70,
ErrorCode::InvalidPrevSubEpochSummaryHash => 71,
ErrorCode::InvalidRewardChainHash => 72,
ErrorCode::InvalidSubEpochOverflow => 73,
ErrorCode::InvalidNewDifficulty => 74,
ErrorCode::InvalidNewSubSlotIters => 75,
ErrorCode::InvalidCcSpVdf => 76,
ErrorCode::InvalidRcSpVdf => 77,
ErrorCode::InvalidCcSignature => 78,
ErrorCode::InvalidRcSignature => 79,
ErrorCode::CannotMakeCcBlock => 80,
ErrorCode::InvalidRcSpPrevIp => 81,
ErrorCode::InvalidRcIpPrevIp => 82,
ErrorCode::InvalidIsTransactionBlock => 83,
ErrorCode::InvalidUrsbHash => 84,
ErrorCode::OldPoolTarget => 85,
ErrorCode::InvalidPoolSignature => 86,
ErrorCode::InvalidFoliageBlockPresence => 87,
ErrorCode::InvalidCcIpVdf => 88,
ErrorCode::InvalidRcIpVdf => 89,
ErrorCode::IpShouldBeNone => 90,
ErrorCode::InvalidRewardBlockHash => 91,
ErrorCode::InvalidMadeNonOverflowInfusions => 92,
ErrorCode::NoOverflowsInFirstSubSlotNewEpoch => 93,
ErrorCode::MempoolNotInitialized => 94,
ErrorCode::ShouldNotHaveIcc => 95,
ErrorCode::ShouldHaveIcc => 96,
ErrorCode::InvalidIccVdf => 97,
ErrorCode::InvalidIccHashCc => 98,
ErrorCode::InvalidIccHashRc => 99,
ErrorCode::InvalidIccEosVdf => 100,
ErrorCode::InvalidSpIndex => 101,
ErrorCode::TooManyBlocks => 102,
ErrorCode::InvalidCcChallenge => 103,
ErrorCode::InvalidPrefarm => 104,
ErrorCode::AssertSecondsRelativeFailed => 105,
ErrorCode::BadCoinbaseSignature => 106,
ErrorCode::NoTransactionsWhileSyncing => 108,
ErrorCode::AlreadyIncludingTransaction => 109,
ErrorCode::IncompatibleNetworkId => 110,
ErrorCode::PreSoftForkMaxGeneratorSize => 111,
ErrorCode::InvalidRequiredIters => 112,
ErrorCode::TooManyGeneratorRefs => 113,
ErrorCode::AssertMyParentIdFailed => 114,
ErrorCode::AssertMyPuzzleHashFailed => 115,
ErrorCode::AssertMyAmountFailed => 116,
ErrorCode::GeneratorRuntimeError => 117,
ErrorCode::InvalidCostResult => 118,
ErrorCode::InvalidTransactionsGeneratorRefsRoot => 119,
ErrorCode::FutureGeneratorRefs => 120,
ErrorCode::GeneratorRefHasNoGenerator => 121,
ErrorCode::DoubleSpendInFork => 122,
ErrorCode::InvalidFeeTooCloseToZero => 123,
ErrorCode::CoinAmountNegative => 124,
ErrorCode::InternalProtocolError => 125,
ErrorCode::InvalidSpendBundle => 126,
ErrorCode::FailedGettingGeneratorMultiprocessing => 127,
ErrorCode::AssertBeforeSecondsAbsoluteFailed => 128,
ErrorCode::AssertBeforeSecondsRelativeFailed => 129,
ErrorCode::AssertBeforeHeightAbsoluteFailed => 130,
ErrorCode::AssertBeforeHeightRelativeFailed => 131,
ErrorCode::AssertConcurrentSpendFailed => 132,
ErrorCode::AssertConcurrentPuzzleFailed => 133,
ErrorCode::ImpossibleSecondsRelativeConstraints => 134,
ErrorCode::ImpossibleSecondsAbsoluteConstraints => 135,
ErrorCode::ImpossibleHeightRelativeConstraints => 136,
ErrorCode::ImpossibleHeightAbsoluteConstraints => 137,
ErrorCode::AssertMyBirthSecondsFailed => 138,
ErrorCode::AssertMyBirthHeightFailed => 139,
ErrorCode::AssertEphemeralFailed => 140,
ErrorCode::EphemeralRelativeCondition => 141,
ErrorCode::InvalidSoftforkCondition => 142,
ErrorCode::InvalidSoftforkCost => 143,
ErrorCode::TooManyAnnouncements => 144,
ErrorCode::InvalidMessageMode => 145,
ErrorCode::InvalidCoinId => 146,
ErrorCode::MessageNotSentOrReceived => 147,
ErrorCode::ComplexGeneratorReceived => 148,
}
}
}
pub fn rest(a: &Allocator, n: NodePtr) -> Result<NodePtr, ValidationErr> {
match a.sexp(n) {
SExp::Pair(_, right) => Ok(right),
SExp::Atom => Err(ValidationErr(n, ErrorCode::InvalidCondition)),
}
}
pub fn next(a: &Allocator, n: NodePtr) -> Result<Option<(NodePtr, NodePtr)>, ValidationErr> {
match a.sexp(n) {
SExp::Pair(left, right) => Ok(Some((left, right))),
SExp::Atom => {
if a.atom_len(n) == 0 {
Ok(None)
} else {
Err(ValidationErr(n, ErrorCode::InvalidCondition))
}
}
}
}
pub fn atom(a: &Allocator, n: NodePtr, code: ErrorCode) -> Result<Atom<'_>, ValidationErr> {
match a.sexp(n) {
SExp::Atom => Ok(a.atom(n)),
SExp::Pair(..) => Err(ValidationErr(n, code)),
}
}
pub fn check_nil(a: &Allocator, n: NodePtr) -> Result<(), ValidationErr> {
if atom(a, n, ErrorCode::InvalidCondition)?.as_ref().is_empty() {
Ok(())
} else {
Err(ValidationErr(n, ErrorCode::InvalidCondition))
}
}