bsv_script/interpreter/error.rs
1//! Interpreter error types matching the Go SDK's errs package.
2
3use std::fmt;
4
5/// Error codes for the script interpreter.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum InterpreterErrorCode {
8 /// An internal interpreter error occurred.
9 Internal,
10 /// No error; used as a sentinel for early successful return.
11 Ok,
12 /// The combination of script flags is invalid.
13 InvalidFlags,
14 /// An index is out of range for the operation.
15 InvalidIndex,
16 /// The address type is not supported.
17 UnsupportedAddress,
18 /// The script is not a valid multisig script.
19 NotMultisigScript,
20 /// The number of required signatures exceeds the allowed maximum.
21 TooManyRequiredSigs,
22 /// The OP_RETURN data payload exceeds the allowed size.
23 TooMuchNullData,
24 /// Invalid parameters were supplied to the interpreter.
25 InvalidParams,
26 /// Script execution returned early (post-genesis OP_RETURN).
27 EarlyReturn,
28 /// The stack is empty when an operand was expected.
29 EmptyStack,
30 /// The top stack value is false at the end of script execution.
31 EvalFalse,
32 /// Script execution ended before all opcodes were processed.
33 ScriptUnfinished,
34 /// The program counter points to an invalid script position.
35 InvalidProgramCounter,
36 /// The script exceeds the maximum allowed size.
37 ScriptTooBig,
38 /// A data element exceeds the maximum allowed element size.
39 ElementTooBig,
40 /// The number of non-push opcodes exceeds the allowed maximum.
41 TooManyOperations,
42 /// The combined data and alt stack size exceeds the allowed maximum.
43 StackOverflow,
44 /// The public key count in a multisig is out of range.
45 InvalidPubKeyCount,
46 /// The signature count in a multisig is out of range.
47 InvalidSignatureCount,
48 /// A numeric operand exceeds the maximum allowed byte length.
49 NumberTooBig,
50 /// A numeric operand is below the minimum allowed value.
51 NumberTooSmall,
52 /// Division or modulo by zero was attempted.
53 DivideByZero,
54 /// OP_VERIFY failed because the top stack value is false.
55 Verify,
56 /// OP_EQUALVERIFY failed because the top two values are not equal.
57 EqualVerify,
58 /// OP_NUMEQUALVERIFY failed because the top two numeric values differ.
59 NumEqualVerify,
60 /// OP_CHECKSIGVERIFY failed because signature verification failed.
61 CheckSigVerify,
62 /// OP_CHECKMULTISIGVERIFY failed because multisig verification failed.
63 CheckMultiSigVerify,
64 /// A disabled opcode was encountered during execution.
65 DisabledOpcode,
66 /// A reserved opcode was encountered during execution.
67 ReservedOpcode,
68 /// A push opcode has a malformed or truncated data payload.
69 MalformedPush,
70 /// A stack operation references an invalid stack index.
71 InvalidStackOperation,
72 /// An IF/ELSE/ENDIF block is not properly balanced.
73 UnbalancedConditional,
74 /// An input length is invalid for the operation.
75 InvalidInputLength,
76 /// A data push does not use the minimal encoding required by policy.
77 MinimalData,
78 /// An OP_IF/OP_NOTIF argument is not minimally encoded (must be empty or 0x01).
79 MinimalIf,
80 /// The sighash type byte in a signature is invalid.
81 InvalidSigHashType,
82 /// The DER-encoded signature is shorter than the minimum valid length.
83 SigTooShort,
84 /// The DER-encoded signature is longer than the maximum valid length.
85 SigTooLong,
86 /// The DER sequence identifier byte is missing or invalid.
87 SigInvalidSeqID,
88 /// The DER data length field does not match the actual signature length.
89 SigInvalidDataLen,
90 /// The DER S-type identifier byte (0x02) is missing.
91 SigMissingSTypeID,
92 /// The DER S-length field is missing.
93 SigMissingSLen,
94 /// The DER S-length value is invalid.
95 SigInvalidSLen,
96 /// The DER R integer type identifier byte (0x02) is invalid.
97 SigInvalidRIntID,
98 /// The DER R value has zero length.
99 SigZeroRLen,
100 /// The DER R value is negative (leading byte has high bit set without padding).
101 SigNegativeR,
102 /// The DER R value has excessive zero-byte padding.
103 SigTooMuchRPadding,
104 /// The DER S integer type identifier byte (0x02) is invalid.
105 SigInvalidSIntID,
106 /// The DER S value has zero length.
107 SigZeroSLen,
108 /// The DER S value is negative (leading byte has high bit set without padding).
109 SigNegativeS,
110 /// The DER S value has excessive zero-byte padding.
111 SigTooMuchSPadding,
112 /// The S value in the signature is not in the low-S canonical form.
113 SigHighS,
114 /// The unlocking script contains non-push opcodes when push-only is required.
115 NotPushOnly,
116 /// The dummy element for OP_CHECKMULTISIG is not empty (null dummy rule).
117 SigNullDummy,
118 /// A public key does not conform to the required encoding format.
119 PubKeyType,
120 /// The stack contains extra items after execution when clean stack is enforced.
121 CleanStack,
122 /// A failed signature check did not have an empty signature (NULLFAIL rule).
123 NullFail,
124 /// An upgradable NOP opcode was encountered and the discourage flag is set.
125 DiscourageUpgradableNOPs,
126 /// The lock time value is negative.
127 NegativeLockTime,
128 /// The transaction lock time does not satisfy OP_CHECKLOCKTIMEVERIFY.
129 UnsatisfiedLockTime,
130 /// The SIGHASH_FORKID flag is missing or incorrectly set.
131 IllegalForkID,
132}
133
134impl fmt::Display for InterpreterErrorCode {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 write!(f, "{:?}", self)
137 }
138}
139
140/// A script interpreter error with an error code and description.
141#[derive(Debug, Clone)]
142pub struct InterpreterError {
143 /// The error code identifying the class of error.
144 pub code: InterpreterErrorCode,
145 /// A human-readable description of the error.
146 pub description: String,
147}
148
149impl InterpreterError {
150 /// Create a new interpreter error from an error code and description string.
151 pub fn new(code: InterpreterErrorCode, description: String) -> Self {
152 InterpreterError { code, description }
153 }
154}
155
156impl fmt::Display for InterpreterError {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 write!(f, "{}", self.description)
159 }
160}
161
162impl std::error::Error for InterpreterError {}
163
164/// Check if an error has a specific error code.
165pub fn is_error_code(err: &InterpreterError, code: InterpreterErrorCode) -> bool {
166 err.code == code
167}