1#![deny(clippy::pedantic)]
2#![allow(clippy::missing_errors_doc)]
3#![allow(clippy::module_name_repetitions)]
4#![allow(clippy::must_use_candidate)]
5#![allow(clippy::needless_lifetimes)]
6
7pub mod endpoint;
8
9use std::fmt;
10use std::str::FromStr;
11
12use config::MetaClientConfig;
13use fedimint_core::core::{Decoder, ModuleInstanceId, ModuleKind};
14use fedimint_core::encoding::{Decodable, DecodeError, Encodable};
15use fedimint_core::module::{CommonModuleInit, ModuleCommon, ModuleConsensusVersion};
16use fedimint_core::plugin_types_trait_impl_common;
17use fedimint_logging::LOG_MODULE_META;
18use serde::de::{self, Visitor};
19use serde::{Deserialize, Deserializer, Serialize, Serializer};
20use thiserror::Error;
21use tracing::warn;
22pub mod config;
26
27pub const KIND: ModuleKind = ModuleKind::from_static_str("meta");
29
30pub const MODULE_CONSENSUS_VERSION: ModuleConsensusVersion = ModuleConsensusVersion::new(0, 0);
32
33pub const DEFAULT_META_KEY: MetaKey = MetaKey(0);
36
37#[derive(
44 Debug,
45 Copy,
46 Clone,
47 Encodable,
48 Decodable,
49 PartialEq,
50 Eq,
51 PartialOrd,
52 Ord,
53 Hash,
54 Serialize,
55 Deserialize,
56)]
57pub struct MetaKey(pub u8);
58
59impl fmt::Display for MetaKey {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 self.0.fmt(f)
62 }
63}
64
65impl FromStr for MetaKey {
66 type Err = <u8 as FromStr>::Err;
67
68 fn from_str(s: &str) -> Result<Self, Self::Err> {
69 Ok(Self(FromStr::from_str(s)?))
70 }
71}
72#[derive(Debug, Clone, Encodable, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub struct MetaValue(Vec<u8>);
79
80impl FromStr for MetaValue {
81 type Err = hex::FromHexError;
82
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 Ok(Self(hex::decode(s)?))
85 }
86}
87
88impl fmt::Display for MetaValue {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 f.write_str(&hex::encode(&self.0))
91 }
92}
93impl From<&[u8]> for MetaValue {
94 fn from(value: &[u8]) -> Self {
95 Self(value.to_vec())
96 }
97}
98
99impl MetaValue {
100 pub const MAX_LEN_BYTES: usize = 1024 * 1024 * 1024;
103
104 pub fn as_slice(&self) -> &[u8] {
105 &self.0
106 }
107
108 pub fn to_json(&self) -> Result<serde_json::Value, serde_json::Error> {
115 serde_json::from_slice(&self.0)
116 }
117
118 pub fn to_json_lossy(&self) -> Result<serde_json::Value, serde_json::Error> {
125 let maybe_lossy_str = String::from_utf8_lossy(self.as_slice());
126
127 if maybe_lossy_str.as_bytes() != self.as_slice() {
128 warn!(target: LOG_MODULE_META, "Value contains invalid utf-8, converting to lossy string");
129 }
130
131 serde_json::from_str(&maybe_lossy_str)
132 }
133}
134
135impl Decodable for MetaValue {
136 fn consensus_decode_partial<R: std::io::Read>(
137 r: &mut R,
138 modules: &fedimint_core::module::registry::ModuleDecoderRegistry,
139 ) -> Result<Self, fedimint_core::encoding::DecodeError> {
140 let bytes = Vec::consensus_decode_partial(r, modules)?;
141
142 if Self::MAX_LEN_BYTES < bytes.len() {
143 return Err(DecodeError::from_str("Too long"));
144 }
145
146 Ok(Self(bytes))
147 }
148}
149impl Serialize for MetaValue {
150 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
151 where
152 S: Serializer,
153 {
154 assert!(self.0.len() <= Self::MAX_LEN_BYTES);
155 serializer.serialize_str(&hex::encode(&self.0))
156 }
157}
158
159impl<'de> Deserialize<'de> for MetaValue {
161 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
162 where
163 D: Deserializer<'de>,
164 {
165 struct MetaValueVisitor;
166
167 impl Visitor<'_> for MetaValueVisitor {
168 type Value = MetaValue;
169
170 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
171 formatter.write_str("a hex string")
172 }
173
174 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
175 where
176 E: de::Error,
177 {
178 let val = hex::decode(value).map_err(de::Error::custom)?;
179
180 if MetaValue::MAX_LEN_BYTES < val.len() {
181 return Err(de::Error::custom("Too long"));
182 }
183
184 Ok(MetaValue(val))
185 }
186 }
187
188 deserializer.deserialize_str(MetaValueVisitor)
189 }
190}
191
192#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
193pub struct MetaConsensusItem {
194 pub salt: u64,
198 pub key: MetaKey,
199 pub value: MetaValue,
200}
201
202#[derive(Debug, Clone, Encodable, Decodable, Serialize, Deserialize, PartialEq, Eq)]
204pub struct MetaConsensusValue {
205 pub revision: u64,
206 pub value: MetaValue,
207}
208
209#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
211pub struct MetaInput;
212
213#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
215pub struct MetaOutput;
216
217#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
219pub struct MetaOutputOutcome;
220
221#[derive(Debug, Clone, Eq, PartialEq, Hash, Error, Encodable, Decodable)]
223pub enum MetaInputError {
224 #[error("This module does not support inputs")]
225 NotSupported,
226}
227
228#[derive(Debug, Clone, Eq, PartialEq, Hash, Error, Encodable, Decodable)]
230pub enum MetaOutputError {
231 #[error("This module does not support outputs")]
232 NotSupported,
233}
234
235pub struct MetaModuleTypes;
237
238plugin_types_trait_impl_common!(
240 KIND,
241 MetaModuleTypes,
242 MetaClientConfig,
243 MetaInput,
244 MetaOutput,
245 MetaOutputOutcome,
246 MetaConsensusItem,
247 MetaInputError,
248 MetaOutputError
249);
250
251#[derive(Debug)]
252pub struct MetaCommonInit;
253
254impl CommonModuleInit for MetaCommonInit {
255 const CONSENSUS_VERSION: ModuleConsensusVersion = MODULE_CONSENSUS_VERSION;
256 const KIND: ModuleKind = KIND;
257
258 type ClientConfig = MetaClientConfig;
259
260 fn decoder() -> Decoder {
261 MetaModuleTypes::decoder_builder().build()
262 }
263}
264
265impl fmt::Display for MetaClientConfig {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 write!(f, "MetaClientConfig")
268 }
269}
270impl fmt::Display for MetaInput {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 write!(f, "MetaInput")
273 }
274}
275
276impl fmt::Display for MetaOutput {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 write!(f, "MetaOutput")
279 }
280}
281
282impl fmt::Display for MetaOutputOutcome {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 write!(f, "MetaOutputOutcome")
285 }
286}
287
288impl fmt::Display for MetaConsensusItem {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 write!(f, "Meta - len: {}", self.value.0.len())
291 }
292}
293
294#[cfg(test)]
295mod tests;