Skip to main content

tx3_resolver/trp/
errors.rs

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