@@ -48,7 +48,8 @@ impl error::Error for Error {
4848/// 1. Provide structured error responses for protocol-level failures
4949/// 2. Hide implementation details of external errors for security
5050/// 3. Support proper error propagation through the receiver stack
51- /// 4. Provide errors according to BIP-78 JSON error specifications for return using [`JsonError::to_json`]
51+ /// 4. Provide errors according to BIP-78 JSON error specifications for return
52+ /// after conversion into [`JsonReply`]
5253#[ derive( Debug ) ]
5354pub enum ReplyableError {
5455 /// Error arising from validation of the original PSBT payload
@@ -62,41 +63,54 @@ pub enum ReplyableError {
6263 Implementation ( ImplementationError ) ,
6364}
6465
65- /// A trait for errors that can be serialized to JSON in a standardized format .
66+ /// The standard format for errors that can be replied as JSON.
6667///
67- /// The JSON output follows the structure :
68+ /// The JSON output includes the following fields :
6869/// ```json
6970/// {
7071/// "errorCode": "specific-error-code",
7172/// "message": "Human readable error message"
7273/// }
7374/// ```
74- pub trait JsonError {
75- /// Converts the error into a JSON string representation.
76- fn to_json ( & self ) -> String ;
75+ pub struct JsonReply {
76+ /// The error code
77+ error_code : ErrorCode ,
78+ /// The error message to be displayed only in debug logs
79+ message : String ,
80+ /// Additional fields to be added to the JSON
81+ additional_fields : Vec < String > ,
7782}
7883
79- impl JsonError for ReplyableError {
80- fn to_json ( & self ) -> String {
81- match self {
82- Self :: Payload ( e) => e. to_json ( ) ,
83- #[ cfg( feature = "v1" ) ]
84- Self :: V1 ( e) => e. to_json ( ) ,
85- Self :: Implementation ( _) => serialize_json_error ( Unavailable , "Receiver error" ) ,
86- }
84+ impl JsonReply {
85+ /// Create a new Reply
86+ pub fn new ( error_code : ErrorCode , message : impl fmt:: Display ) -> Self {
87+ Self { error_code, message : message. to_string ( ) , additional_fields : vec ! [ ] }
8788 }
88- }
8989
90- pub ( crate ) fn serialize_json_error ( code : ErrorCode , message : impl fmt:: Display ) -> String {
91- format ! ( r#"{{ "errorCode": "{}", "message": "{}" }}"# , code, message)
90+ /// Serialize the Reply to a JSON string
91+ pub fn to_json ( & self ) -> String {
92+ if self . additional_fields . is_empty ( ) {
93+ format ! ( r#"{{ "errorCode": "{}", "message": "{}" }}"# , self . error_code, self . message)
94+ } else {
95+ format ! (
96+ r#"{{ "errorCode": "{}", "message": "{}", {} }}"# ,
97+ self . error_code,
98+ self . message,
99+ self . additional_fields. join( ", " )
100+ )
101+ }
102+ }
92103}
93104
94- pub ( crate ) fn serialize_json_plus_fields (
95- code : ErrorCode ,
96- message : impl fmt:: Display ,
97- additional_fields : & str ,
98- ) -> String {
99- format ! ( r#"{{ "errorCode": "{}", "message": "{}", {} }}"# , code, message, additional_fields)
105+ impl From < & ReplyableError > for JsonReply {
106+ fn from ( e : & ReplyableError ) -> Self {
107+ match e {
108+ ReplyableError :: Payload ( e) => e. into ( ) ,
109+ #[ cfg( feature = "v1" ) ]
110+ ReplyableError :: V1 ( e) => e. into ( ) ,
111+ ReplyableError :: Implementation ( _) => JsonReply :: new ( Unavailable , "Receiver error" ) ,
112+ }
113+ }
100114}
101115
102116impl fmt:: Display for ReplyableError {
@@ -180,34 +194,37 @@ pub(crate) enum InternalPayloadError {
180194 FeeTooHigh ( bitcoin:: FeeRate , bitcoin:: FeeRate ) ,
181195}
182196
183- impl JsonError for PayloadError {
184- fn to_json ( & self ) -> String {
197+ impl From < & PayloadError > for JsonReply {
198+ fn from ( e : & PayloadError ) -> Self {
185199 use InternalPayloadError :: * ;
186200
187- match & self . 0 {
188- Utf8 ( _) => serialize_json_error ( OriginalPsbtRejected , self ) ,
189- ParsePsbt ( _) => serialize_json_error ( OriginalPsbtRejected , self ) ,
201+ match & e . 0 {
202+ Utf8 ( _) => JsonReply :: new ( OriginalPsbtRejected , e ) ,
203+ ParsePsbt ( _) => JsonReply :: new ( OriginalPsbtRejected , e ) ,
190204 SenderParams ( e) => match e {
191205 super :: optional_parameters:: Error :: UnknownVersion { supported_versions } => {
192206 let supported_versions_json =
193207 serde_json:: to_string ( supported_versions) . unwrap_or_default ( ) ;
194- serialize_json_plus_fields (
195- VersionUnsupported ,
196- "This version of payjoin is not supported." ,
197- & format ! ( r#""supported": {}"# , supported_versions_json) ,
198- )
208+ JsonReply {
209+ error_code : VersionUnsupported ,
210+ message : "This version of payjoin is not supported." . to_string ( ) ,
211+ additional_fields : vec ! [ format!(
212+ r#""supported": {}"# ,
213+ supported_versions_json
214+ ) ] ,
215+ }
199216 }
200- _ => serialize_json_error ( OriginalPsbtRejected , self ) ,
217+ _ => JsonReply :: new ( OriginalPsbtRejected , e ) ,
201218 } ,
202- InconsistentPsbt ( _) => serialize_json_error ( OriginalPsbtRejected , self ) ,
203- PrevTxOut ( _) => serialize_json_error ( OriginalPsbtRejected , self ) ,
204- MissingPayment => serialize_json_error ( OriginalPsbtRejected , self ) ,
205- OriginalPsbtNotBroadcastable => serialize_json_error ( OriginalPsbtRejected , self ) ,
206- InputOwned ( _) => serialize_json_error ( OriginalPsbtRejected , self ) ,
207- InputWeight ( _) => serialize_json_error ( OriginalPsbtRejected , self ) ,
208- InputSeen ( _) => serialize_json_error ( OriginalPsbtRejected , self ) ,
209- PsbtBelowFeeRate ( _, _) => serialize_json_error ( OriginalPsbtRejected , self ) ,
210- FeeTooHigh ( _, _) => serialize_json_error ( NotEnoughMoney , self ) ,
219+ InconsistentPsbt ( _) => JsonReply :: new ( OriginalPsbtRejected , e ) ,
220+ PrevTxOut ( _) => JsonReply :: new ( OriginalPsbtRejected , e ) ,
221+ MissingPayment => JsonReply :: new ( OriginalPsbtRejected , e ) ,
222+ OriginalPsbtNotBroadcastable => JsonReply :: new ( OriginalPsbtRejected , e ) ,
223+ InputOwned ( _) => JsonReply :: new ( OriginalPsbtRejected , e ) ,
224+ InputWeight ( _) => JsonReply :: new ( OriginalPsbtRejected , e ) ,
225+ InputSeen ( _) => JsonReply :: new ( OriginalPsbtRejected , e ) ,
226+ PsbtBelowFeeRate ( _, _) => JsonReply :: new ( OriginalPsbtRejected , e ) ,
227+ FeeTooHigh ( _, _) => JsonReply :: new ( NotEnoughMoney , e ) ,
211228 }
212229 }
213230}
0 commit comments