rose_grpc_proto/
lib.rs

1#![allow(clippy::doc_overindented_list_items)]
2//! gRPC protobuf definitions and conversions for nockchain-wallet
3//!
4//! This crate provides protobuf type definitions compatible with nockchain's
5//! gRPC API, along with conversion traits to/from nbx-nockchain-types.
6
7// Generated code requires std features from tonic
8// We keep this as a std crate since it's only used in non-WASM contexts
9
10use rose_ztd::Base58Belts;
11
12// Serde helper for serializing u64 as strings (for JavaScript compatibility)
13pub mod serde_u64_as_string {
14    use serde::{Deserialize, Deserializer, Serialize, Serializer};
15
16    pub fn serialize<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
17    where
18        S: Serializer,
19    {
20        value.to_string().serialize(serializer)
21    }
22
23    pub fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
24    where
25        D: Deserializer<'de>,
26    {
27        let s = String::deserialize(deserializer)?;
28        s.parse().map_err(serde::de::Error::custom)
29    }
30}
31
32// Serde helper for serializing u32 as strings (for JavaScript compatibility)
33pub mod serde_u32_as_string {
34    use serde::{Deserialize, Deserializer, Serialize, Serializer};
35
36    pub fn serialize<S>(value: &u32, serializer: S) -> Result<S::Ok, S::Error>
37    where
38        S: Serializer,
39    {
40        value.to_string().serialize(serializer)
41    }
42
43    pub fn deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
44    where
45        D: Deserializer<'de>,
46    {
47        let s = String::deserialize(deserializer)?;
48        s.parse().map_err(serde::de::Error::custom)
49    }
50}
51
52// Serde helper for serializing Hash as base58 string (for JavaScript compatibility)
53//pub struct SerdeBeltsAsBase58<const N: usize>(pub [Belt; N]);
54
55impl TryFrom<pb::common::v1::Hash> for Base58Belts<5> {
56    type Error = ();
57
58    fn try_from(value: pb::common::v1::Hash) -> Result<Self, Self::Error> {
59        Ok(Base58Belts([
60            rose_ztd::Belt(value.belt_1.as_ref().map(|b| b.value).ok_or(())?),
61            rose_ztd::Belt(value.belt_2.as_ref().map(|b| b.value).ok_or(())?),
62            rose_ztd::Belt(value.belt_3.as_ref().map(|b| b.value).ok_or(())?),
63            rose_ztd::Belt(value.belt_4.as_ref().map(|b| b.value).ok_or(())?),
64            rose_ztd::Belt(value.belt_5.as_ref().map(|b| b.value).ok_or(())?),
65        ]))
66    }
67}
68
69impl<'a> TryFrom<&'a pb::common::v1::Hash> for Base58Belts<5> {
70    type Error = ();
71
72    fn try_from(value: &'a pb::common::v1::Hash) -> Result<Self, Self::Error> {
73        (*value).try_into()
74    }
75}
76
77impl TryFrom<pb::common::v1::EightBelt> for Base58Belts<8> {
78    type Error = ();
79
80    fn try_from(value: pb::common::v1::EightBelt) -> Result<Self, Self::Error> {
81        Ok(Base58Belts([
82            rose_ztd::Belt(value.belt_1.as_ref().map(|b| b.value).ok_or(())?),
83            rose_ztd::Belt(value.belt_2.as_ref().map(|b| b.value).ok_or(())?),
84            rose_ztd::Belt(value.belt_3.as_ref().map(|b| b.value).ok_or(())?),
85            rose_ztd::Belt(value.belt_4.as_ref().map(|b| b.value).ok_or(())?),
86            rose_ztd::Belt(value.belt_5.as_ref().map(|b| b.value).ok_or(())?),
87            rose_ztd::Belt(value.belt_6.as_ref().map(|b| b.value).ok_or(())?),
88            rose_ztd::Belt(value.belt_7.as_ref().map(|b| b.value).ok_or(())?),
89            rose_ztd::Belt(value.belt_8.as_ref().map(|b| b.value).ok_or(())?),
90        ]))
91    }
92}
93
94impl<'a> TryFrom<&'a pb::common::v1::EightBelt> for Base58Belts<8> {
95    type Error = ();
96
97    fn try_from(value: &'a pb::common::v1::EightBelt) -> Result<Self, Self::Error> {
98        (*value).try_into()
99    }
100}
101
102impl From<Base58Belts<8>> for pb::common::v1::EightBelt {
103    fn from(value: Base58Belts<8>) -> Self {
104        pb::common::v1::EightBelt {
105            belt_1: Some(pb::common::v1::Belt {
106                value: value.0[0].0,
107            }),
108            belt_2: Some(pb::common::v1::Belt {
109                value: value.0[1].0,
110            }),
111            belt_3: Some(pb::common::v1::Belt {
112                value: value.0[2].0,
113            }),
114            belt_4: Some(pb::common::v1::Belt {
115                value: value.0[3].0,
116            }),
117            belt_5: Some(pb::common::v1::Belt {
118                value: value.0[4].0,
119            }),
120            belt_6: Some(pb::common::v1::Belt {
121                value: value.0[5].0,
122            }),
123            belt_7: Some(pb::common::v1::Belt {
124                value: value.0[6].0,
125            }),
126            belt_8: Some(pb::common::v1::Belt {
127                value: value.0[7].0,
128            }),
129        }
130    }
131}
132
133impl TryFrom<pb::common::v1::SixBelt> for Base58Belts<6> {
134    type Error = ();
135
136    fn try_from(value: pb::common::v1::SixBelt) -> Result<Self, Self::Error> {
137        Ok(Base58Belts([
138            rose_ztd::Belt(value.belt_1.as_ref().map(|b| b.value).ok_or(())?),
139            rose_ztd::Belt(value.belt_2.as_ref().map(|b| b.value).ok_or(())?),
140            rose_ztd::Belt(value.belt_3.as_ref().map(|b| b.value).ok_or(())?),
141            rose_ztd::Belt(value.belt_4.as_ref().map(|b| b.value).ok_or(())?),
142            rose_ztd::Belt(value.belt_5.as_ref().map(|b| b.value).ok_or(())?),
143            rose_ztd::Belt(value.belt_6.as_ref().map(|b| b.value).ok_or(())?),
144        ]))
145    }
146}
147
148impl<'a> TryFrom<&'a pb::common::v1::SixBelt> for Base58Belts<6> {
149    type Error = ();
150
151    fn try_from(value: &'a pb::common::v1::SixBelt) -> Result<Self, Self::Error> {
152        (*value).try_into()
153    }
154}
155
156impl From<Base58Belts<6>> for pb::common::v1::SixBelt {
157    fn from(value: Base58Belts<6>) -> Self {
158        pb::common::v1::SixBelt {
159            belt_1: Some(pb::common::v1::Belt {
160                value: value.0[0].0,
161            }),
162            belt_2: Some(pb::common::v1::Belt {
163                value: value.0[1].0,
164            }),
165            belt_3: Some(pb::common::v1::Belt {
166                value: value.0[2].0,
167            }),
168            belt_4: Some(pb::common::v1::Belt {
169                value: value.0[3].0,
170            }),
171            belt_5: Some(pb::common::v1::Belt {
172                value: value.0[4].0,
173            }),
174            belt_6: Some(pb::common::v1::Belt {
175                value: value.0[5].0,
176            }),
177        }
178    }
179}
180
181pub mod serde_hash_as_base58 {
182    use rose_ztd::Base58Belts;
183    use serde::{
184        de::Error as DeError, ser::Error as SeError, Deserialize, Deserializer, Serialize,
185        Serializer,
186    };
187
188    pub fn serialize<S, T, const N: usize>(
189        hash: &Option<T>,
190        serializer: S,
191    ) -> Result<S::Ok, S::Error>
192    where
193        S: Serializer,
194        for<'a> &'a T: TryInto<Base58Belts<N>>,
195    {
196        match hash {
197            None => serializer.serialize_none(),
198            Some(h) => {
199                // Convert Hash to Digest
200                let belts: Base58Belts<N> = h
201                    .try_into()
202                    .map_err(|_| S::Error::custom("Unable to serialize".to_string()))?;
203                belts.to_string().serialize(serializer)
204            }
205        }
206    }
207
208    pub fn deserialize<'de, D, T, const N: usize>(deserializer: D) -> Result<Option<T>, D::Error>
209    where
210        D: Deserializer<'de>,
211        Base58Belts<N>: Into<T>,
212    {
213        let s = Option::<String>::deserialize(deserializer)?;
214        match s {
215            None => Ok(None),
216            Some(s) => {
217                let belts = Base58Belts::<N>::try_from(s.as_str())
218                    .map_err(|_| DeError::custom("Unable to deserialize".to_string()))?;
219                Ok(Some(belts.into()))
220            }
221        }
222    }
223}
224
225// Serde helper for serializing Vec<Hash> as array of base58 strings
226pub mod serde_hash_vec_as_base58 {
227    use super::pb::common::v1::{Belt, Hash};
228    use rose_ztd::Digest;
229    use serde::{de::Error as DeError, Deserialize, Deserializer, Serializer};
230
231    pub fn serialize<S>(hashes: &Vec<Hash>, serializer: S) -> Result<S::Ok, S::Error>
232    where
233        S: Serializer,
234    {
235        use serde::ser::SerializeSeq;
236        let mut seq = serializer.serialize_seq(Some(hashes.len()))?;
237        for hash in hashes {
238            let digest = Digest([
239                rose_ztd::Belt(hash.belt_1.as_ref().map(|b| b.value).unwrap_or(0)),
240                rose_ztd::Belt(hash.belt_2.as_ref().map(|b| b.value).unwrap_or(0)),
241                rose_ztd::Belt(hash.belt_3.as_ref().map(|b| b.value).unwrap_or(0)),
242                rose_ztd::Belt(hash.belt_4.as_ref().map(|b| b.value).unwrap_or(0)),
243                rose_ztd::Belt(hash.belt_5.as_ref().map(|b| b.value).unwrap_or(0)),
244            ]);
245            seq.serialize_element(&digest.to_string())?;
246        }
247        seq.end()
248    }
249
250    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<Hash>, D::Error>
251    where
252        D: Deserializer<'de>,
253    {
254        let strings = Vec::<String>::deserialize(deserializer)?;
255        strings
256            .into_iter()
257            .map(|s| {
258                let digest = Digest::try_from(s.as_str()).map_err(DeError::custom)?;
259                Ok(Hash {
260                    belt_1: Some(Belt {
261                        value: digest.0[0].0,
262                    }),
263                    belt_2: Some(Belt {
264                        value: digest.0[1].0,
265                    }),
266                    belt_3: Some(Belt {
267                        value: digest.0[2].0,
268                    }),
269                    belt_4: Some(Belt {
270                        value: digest.0[3].0,
271                    }),
272                    belt_5: Some(Belt {
273                        value: digest.0[4].0,
274                    }),
275                })
276            })
277            .collect()
278    }
279}
280
281// Include the generated protobuf code
282pub mod pb {
283    pub mod common {
284        pub mod v1 {
285            include!(concat!(env!("OUT_DIR"), "/nockchain.common.v1.rs"));
286        }
287        pub mod v2 {
288            include!(concat!(env!("OUT_DIR"), "/nockchain.common.v2.rs"));
289        }
290    }
291    pub mod public {
292        pub mod v2 {
293            include!(concat!(env!("OUT_DIR"), "/nockchain.public.v2.rs"));
294        }
295    }
296
297    pub const FILE_DESCRIPTOR_SET: &[u8] =
298        include_bytes!(concat!(env!("OUT_DIR"), "/nockchain_descriptor.bin"));
299}
300
301#[cfg(not(target_arch = "wasm32"))]
302pub mod client;
303pub mod common;
304pub mod convert;