Skip to main content

tx3_resolver/trp/
errors.rs

1use serde_json::json;
2use tx3_tir::encoding;
3
4use crate::{
5    inputs::{CanonicalQuery, SearchSpace},
6    trp::spec,
7    Error,
8};
9
10pub const CODE_UNSUPPORTED_TIR: i32 = -32000;
11pub const CODE_MISSING_TX_ARG: i32 = -32001;
12pub const CODE_INPUT_NOT_RESOLVED: i32 = -32002;
13pub const CODE_TX_SCRIPT_FAILURE: i32 = -32003;
14pub const CODE_TX_NOT_ACCEPTED: i32 = -32004;
15pub const CODE_INTEROP_ERROR: i32 = -32005;
16pub const CODE_COMPILE_ERROR: i32 = -32006;
17pub const CODE_INPUT_QUERY_TOO_BROAD: i32 = -32007;
18pub const CODE_UTXO_STORE_ERROR: i32 = -32008;
19pub const CODE_TRANSIENT_ERROR: i32 = -32009;
20
21// JSON-RPC error codes.
22// pub const INVALID_REQUEST_CODE: i32 = -32600;
23// pub const INVALID_PARAMS_CODE: i32 = -32602;
24// pub const INTERNAL_ERROR_CODE: i32 = -32603;
25
26pub trait TrpError {
27    fn code(&self) -> i32;
28    fn data(&self) -> Option<serde_json::Value>;
29}
30
31pub trait IntoErrorData {
32    type Output;
33    fn into_error_data(self) -> Self::Output;
34}
35
36impl IntoErrorData for CanonicalQuery {
37    type Output = spec::InputQueryDiagnostic;
38
39    fn into_error_data(self) -> Self::Output {
40        spec::InputQueryDiagnostic {
41            address: self.address.as_ref().map(hex::encode),
42            min_amount: self
43                .min_amount
44                .iter()
45                .flat_map(|x| x.iter())
46                .map(|(k, v)| (k.to_string(), v.to_string()))
47                .collect(),
48            refs: self
49                .refs
50                .iter()
51                .map(ToString::to_string)
52                .collect::<Vec<_>>(),
53            support_many: self.support_many,
54            collateral: self.collateral,
55        }
56    }
57}
58
59impl IntoErrorData for SearchSpace {
60    type Output = spec::SearchSpaceDiagnostic;
61
62    fn into_error_data(self) -> Self::Output {
63        spec::SearchSpaceDiagnostic {
64            matched: self
65                .take(Some(10))
66                .iter()
67                .map(ToString::to_string)
68                .collect::<Vec<_>>(),
69            by_address_count: self.by_address_count,
70            by_asset_class_count: self.by_asset_class_count,
71            by_ref_count: self.by_ref_count,
72        }
73    }
74}
75
76impl TrpError for encoding::Error {
77    fn code(&self) -> i32 {
78        match self {
79            encoding::Error::DeprecatedTirVersion(_) => CODE_UNSUPPORTED_TIR,
80            encoding::Error::UnknownTirVersion(_) => CODE_UNSUPPORTED_TIR,
81            encoding::Error::TirDeserializeError(_) => CODE_UNSUPPORTED_TIR,
82        }
83    }
84
85    fn data(&self) -> Option<serde_json::Value> {
86        match self {
87            encoding::Error::DeprecatedTirVersion(version) => {
88                let data = spec::UnsupportedTirDiagnostic {
89                    provided: version.to_string(),
90                    expected: tx3_tir::encoding::MIN_SUPPORTED_VERSION.to_string(),
91                };
92
93                Some(json!(data))
94            }
95            encoding::Error::UnknownTirVersion(version) => {
96                let data = spec::UnsupportedTirDiagnostic {
97                    provided: version.to_string(),
98                    expected: tx3_tir::encoding::MIN_SUPPORTED_VERSION.to_string(),
99                };
100
101                Some(json!(data))
102            }
103            encoding::Error::TirDeserializeError(_) => None,
104        }
105    }
106}
107
108impl TrpError for crate::Error {
109    fn code(&self) -> i32 {
110        match self {
111            Error::InputQueryTooBroad => CODE_INPUT_QUERY_TOO_BROAD,
112            Error::InputNotResolved(..) => CODE_INPUT_NOT_RESOLVED,
113            Error::MissingTxArg { .. } => CODE_MISSING_TX_ARG,
114            Error::CompileError(..) => CODE_COMPILE_ERROR,
115            Error::CantCompileNonConstantTir => CODE_COMPILE_ERROR,
116            Error::ExpectedData(..) => CODE_COMPILE_ERROR,
117            Error::TransientError(_) => CODE_TRANSIENT_ERROR,
118            Error::StoreError(_) => CODE_UTXO_STORE_ERROR,
119            Error::InteropError(_) => CODE_INTEROP_ERROR,
120            Error::ReduceError(_) => CODE_COMPILE_ERROR,
121            Error::TxScriptFailure(_) => CODE_TX_SCRIPT_FAILURE,
122            Error::TxNotAccepted(_) => CODE_TX_NOT_ACCEPTED,
123            Error::TirEncodingError(x) => x.code(),
124        }
125    }
126
127    fn data(&self) -> Option<serde_json::Value> {
128        match self {
129            Error::TirEncodingError(x) => x.data(),
130
131            Error::MissingTxArg { key, ty } => {
132                let data = spec::MissingTxArgDiagnostic {
133                    key: key.to_string(),
134                    ty: format!("{ty:?}"),
135                };
136
137                Some(json!(data))
138            }
139            Error::InputNotResolved(name, q, ss) => {
140                let data = spec::InputNotResolvedDiagnostic {
141                    name: name.to_string(),
142                    query: q.clone().into_error_data(),
143                    search_space: ss.clone().into_error_data(),
144                };
145
146                Some(json!(data))
147            }
148
149            Error::TxScriptFailure(x) => {
150                let data = spec::TxScriptFailureDiagnostic { logs: x.clone() };
151                Some(json!(data))
152            }
153            _ => None,
154        }
155    }
156}