Skip to main content

tidecoin_node_parity/
error.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use core::fmt;
4
5/// Error returned by the shared Tidecoin node parity harness.
6#[derive(Debug, Clone, PartialEq, Eq)]
7#[non_exhaustive]
8pub enum NodeParityError {
9    /// The configured Tidecoin node checkout is missing or malformed.
10    Environment(&'static str),
11    /// A required C-string conversion failed.
12    InvalidCString(&'static str),
13    /// A native bridge call returned an unexpected failure mode.
14    BridgeFailure(&'static str),
15    /// A Tidecoin-node script verification call returned a script error.
16    Script(ScriptError),
17}
18
19impl fmt::Display for NodeParityError {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        match self {
22            Self::Environment(msg) => f.write_str(msg),
23            Self::InvalidCString(name) => write!(f, "failed to build C string for {}", name),
24            Self::BridgeFailure(name) => {
25                write!(f, "tidecoin node parity bridge call failed: {}", name)
26            }
27            Self::Script(err) => write!(f, "script validation failed: {}", err),
28        }
29    }
30}
31
32#[cfg(feature = "std")]
33impl std::error::Error for NodeParityError {}
34
35/// Tidecoin-node script error codes exposed through the node parity bridge.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37#[non_exhaustive]
38pub enum ScriptError {
39    /// `SCRIPT_ERR_OK`
40    Ok,
41    /// `SCRIPT_ERR_UNKNOWN_ERROR`
42    UnknownError,
43    /// `SCRIPT_ERR_EVAL_FALSE`
44    EvalFalse,
45    /// `SCRIPT_ERR_OP_RETURN`
46    OpReturn,
47    /// `SCRIPT_ERR_SCRIPT_SIZE`
48    ScriptSize,
49    /// `SCRIPT_ERR_PUSH_SIZE`
50    PushSize,
51    /// `SCRIPT_ERR_OP_COUNT`
52    OpCount,
53    /// `SCRIPT_ERR_STACK_SIZE`
54    StackSize,
55    /// `SCRIPT_ERR_SIG_COUNT`
56    SigCount,
57    /// `SCRIPT_ERR_PUBKEY_COUNT`
58    PubkeyCount,
59    /// `SCRIPT_ERR_VERIFY`
60    Verify,
61    /// `SCRIPT_ERR_EQUALVERIFY`
62    EqualVerify,
63    /// `SCRIPT_ERR_CHECKMULTISIGVERIFY`
64    CheckMultisigVerify,
65    /// `SCRIPT_ERR_CHECKSIGVERIFY`
66    CheckSigVerify,
67    /// `SCRIPT_ERR_NUMEQUALVERIFY`
68    NumEqualVerify,
69    /// `SCRIPT_ERR_BAD_OPCODE`
70    BadOpcode,
71    /// `SCRIPT_ERR_DISABLED_OPCODE`
72    DisabledOpcode,
73    /// `SCRIPT_ERR_INVALID_STACK_OPERATION`
74    InvalidStackOperation,
75    /// `SCRIPT_ERR_INVALID_ALTSTACK_OPERATION`
76    InvalidAltstackOperation,
77    /// `SCRIPT_ERR_UNBALANCED_CONDITIONAL`
78    UnbalancedConditional,
79    /// `SCRIPT_ERR_NEGATIVE_LOCKTIME`
80    NegativeLocktime,
81    /// `SCRIPT_ERR_UNSATISFIED_LOCKTIME`
82    UnsatisfiedLocktime,
83    /// `SCRIPT_ERR_SIG_HASHTYPE`
84    SigHashType,
85    /// `SCRIPT_ERR_MINIMALDATA`
86    MinimalData,
87    /// `SCRIPT_ERR_SIG_PUSHONLY`
88    SigPushOnly,
89    /// `SCRIPT_ERR_SIG_HIGH_S`
90    SigHighS,
91    /// `SCRIPT_ERR_SIG_NULLDUMMY`
92    SigNullDummy,
93    /// `SCRIPT_ERR_PUBKEYTYPE`
94    PubkeyType,
95    /// `SCRIPT_ERR_CLEANSTACK`
96    Cleanstack,
97    /// `SCRIPT_ERR_MINIMALIF`
98    MinimalIf,
99    /// `SCRIPT_ERR_NULLFAIL`
100    NullFail,
101    /// `SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS`
102    DiscourageUpgradableNops,
103    /// `SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM`
104    DiscourageUpgradableWitnessProgram,
105    /// `SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH`
106    WitnessProgramWrongLength,
107    /// `SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY`
108    WitnessProgramWitnessEmpty,
109    /// `SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH`
110    WitnessProgramMismatch,
111    /// `SCRIPT_ERR_WITNESS_MALLEATED`
112    WitnessMalleated,
113    /// `SCRIPT_ERR_WITNESS_MALLEATED_P2SH`
114    WitnessMalleatedP2sh,
115    /// `SCRIPT_ERR_WITNESS_UNEXPECTED`
116    WitnessUnexpected,
117    /// `SCRIPT_ERR_OP_CODESEPARATOR`
118    OpCodeSeparator,
119    /// `SCRIPT_ERR_SIG_FINDANDDELETE`
120    SigFindAndDelete,
121}
122
123impl ScriptError {
124    /// Maps a raw Tidecoin-node FFI script-error code into the shared enum.
125    pub fn from_ffi(code: i32) -> Self {
126        match code {
127            0 => Self::Ok,
128            1 => Self::UnknownError,
129            2 => Self::EvalFalse,
130            3 => Self::OpReturn,
131            4 => Self::ScriptSize,
132            5 => Self::PushSize,
133            6 => Self::OpCount,
134            7 => Self::StackSize,
135            8 => Self::SigCount,
136            9 => Self::PubkeyCount,
137            10 => Self::Verify,
138            11 => Self::EqualVerify,
139            12 => Self::CheckMultisigVerify,
140            13 => Self::CheckSigVerify,
141            14 => Self::NumEqualVerify,
142            15 => Self::BadOpcode,
143            16 => Self::DisabledOpcode,
144            17 => Self::InvalidStackOperation,
145            18 => Self::InvalidAltstackOperation,
146            19 => Self::UnbalancedConditional,
147            20 => Self::NegativeLocktime,
148            21 => Self::UnsatisfiedLocktime,
149            22 => Self::SigHashType,
150            23 => Self::MinimalData,
151            24 => Self::SigPushOnly,
152            25 => Self::SigHighS,
153            26 => Self::SigNullDummy,
154            27 => Self::PubkeyType,
155            28 => Self::Cleanstack,
156            29 => Self::MinimalIf,
157            30 => Self::NullFail,
158            31 => Self::DiscourageUpgradableNops,
159            32 => Self::DiscourageUpgradableWitnessProgram,
160            33 => Self::WitnessProgramWrongLength,
161            34 => Self::WitnessProgramWitnessEmpty,
162            35 => Self::WitnessProgramMismatch,
163            36 => Self::WitnessMalleated,
164            37 => Self::WitnessMalleatedP2sh,
165            38 => Self::WitnessUnexpected,
166            39 => Self::OpCodeSeparator,
167            40 => Self::SigFindAndDelete,
168            _ => Self::UnknownError,
169        }
170    }
171
172    /// Parses the display-name form used in Tidecoin node JSON fixtures.
173    pub fn from_name(name: &str) -> Option<Self> {
174        Some(match name {
175            "OK" => Self::Ok,
176            "UNKNOWN_ERROR" => Self::UnknownError,
177            "EVAL_FALSE" => Self::EvalFalse,
178            "OP_RETURN" => Self::OpReturn,
179            "SCRIPT_SIZE" => Self::ScriptSize,
180            "PUSH_SIZE" => Self::PushSize,
181            "OP_COUNT" => Self::OpCount,
182            "STACK_SIZE" => Self::StackSize,
183            "SIG_COUNT" => Self::SigCount,
184            "PUBKEY_COUNT" => Self::PubkeyCount,
185            "VERIFY" => Self::Verify,
186            "EQUALVERIFY" => Self::EqualVerify,
187            "CHECKMULTISIGVERIFY" => Self::CheckMultisigVerify,
188            "CHECKSIGVERIFY" => Self::CheckSigVerify,
189            "NUMEQUALVERIFY" => Self::NumEqualVerify,
190            "BAD_OPCODE" => Self::BadOpcode,
191            "DISABLED_OPCODE" => Self::DisabledOpcode,
192            "INVALID_STACK_OPERATION" => Self::InvalidStackOperation,
193            "INVALID_ALTSTACK_OPERATION" => Self::InvalidAltstackOperation,
194            "UNBALANCED_CONDITIONAL" => Self::UnbalancedConditional,
195            "NEGATIVE_LOCKTIME" => Self::NegativeLocktime,
196            "UNSATISFIED_LOCKTIME" => Self::UnsatisfiedLocktime,
197            "SIG_HASHTYPE" => Self::SigHashType,
198            "MINIMALDATA" => Self::MinimalData,
199            "SIG_PUSHONLY" => Self::SigPushOnly,
200            "SIG_HIGH_S" => Self::SigHighS,
201            "SIG_NULLDUMMY" => Self::SigNullDummy,
202            "PUBKEYTYPE" => Self::PubkeyType,
203            "CLEANSTACK" => Self::Cleanstack,
204            "MINIMALIF" => Self::MinimalIf,
205            "NULLFAIL" => Self::NullFail,
206            "DISCOURAGE_UPGRADABLE_NOPS" => Self::DiscourageUpgradableNops,
207            "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM" => Self::DiscourageUpgradableWitnessProgram,
208            "WITNESS_PROGRAM_WRONG_LENGTH" => Self::WitnessProgramWrongLength,
209            "WITNESS_PROGRAM_WITNESS_EMPTY" => Self::WitnessProgramWitnessEmpty,
210            "WITNESS_PROGRAM_MISMATCH" => Self::WitnessProgramMismatch,
211            "WITNESS_MALLEATED" => Self::WitnessMalleated,
212            "WITNESS_MALLEATED_P2SH" => Self::WitnessMalleatedP2sh,
213            "WITNESS_UNEXPECTED" => Self::WitnessUnexpected,
214            "OP_CODESEPARATOR" => Self::OpCodeSeparator,
215            "SIG_FINDANDDELETE" => Self::SigFindAndDelete,
216            _ => return None,
217        })
218    }
219}
220
221impl fmt::Display for ScriptError {
222    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223        f.write_str(match self {
224            Self::Ok => "OK",
225            Self::UnknownError => "UNKNOWN_ERROR",
226            Self::EvalFalse => "EVAL_FALSE",
227            Self::OpReturn => "OP_RETURN",
228            Self::ScriptSize => "SCRIPT_SIZE",
229            Self::PushSize => "PUSH_SIZE",
230            Self::OpCount => "OP_COUNT",
231            Self::StackSize => "STACK_SIZE",
232            Self::SigCount => "SIG_COUNT",
233            Self::PubkeyCount => "PUBKEY_COUNT",
234            Self::Verify => "VERIFY",
235            Self::EqualVerify => "EQUALVERIFY",
236            Self::CheckMultisigVerify => "CHECKMULTISIGVERIFY",
237            Self::CheckSigVerify => "CHECKSIGVERIFY",
238            Self::NumEqualVerify => "NUMEQUALVERIFY",
239            Self::BadOpcode => "BAD_OPCODE",
240            Self::DisabledOpcode => "DISABLED_OPCODE",
241            Self::InvalidStackOperation => "INVALID_STACK_OPERATION",
242            Self::InvalidAltstackOperation => "INVALID_ALTSTACK_OPERATION",
243            Self::UnbalancedConditional => "UNBALANCED_CONDITIONAL",
244            Self::NegativeLocktime => "NEGATIVE_LOCKTIME",
245            Self::UnsatisfiedLocktime => "UNSATISFIED_LOCKTIME",
246            Self::SigHashType => "SIG_HASHTYPE",
247            Self::MinimalData => "MINIMALDATA",
248            Self::SigPushOnly => "SIG_PUSHONLY",
249            Self::SigHighS => "SIG_HIGH_S",
250            Self::SigNullDummy => "SIG_NULLDUMMY",
251            Self::PubkeyType => "PUBKEYTYPE",
252            Self::Cleanstack => "CLEANSTACK",
253            Self::MinimalIf => "MINIMALIF",
254            Self::NullFail => "NULLFAIL",
255            Self::DiscourageUpgradableNops => "DISCOURAGE_UPGRADABLE_NOPS",
256            Self::DiscourageUpgradableWitnessProgram => "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM",
257            Self::WitnessProgramWrongLength => "WITNESS_PROGRAM_WRONG_LENGTH",
258            Self::WitnessProgramWitnessEmpty => "WITNESS_PROGRAM_WITNESS_EMPTY",
259            Self::WitnessProgramMismatch => "WITNESS_PROGRAM_MISMATCH",
260            Self::WitnessMalleated => "WITNESS_MALLEATED",
261            Self::WitnessMalleatedP2sh => "WITNESS_MALLEATED_P2SH",
262            Self::WitnessUnexpected => "WITNESS_UNEXPECTED",
263            Self::OpCodeSeparator => "OP_CODESEPARATOR",
264            Self::SigFindAndDelete => "SIG_FINDANDDELETE",
265        })
266    }
267}