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 = anyhow::Error;
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) -> anyhow::Result<serde_json::Value> {
109 Ok(serde_json::from_slice(&self.0)?)
110 }
111
112 pub fn to_json_lossy(&self) -> anyhow::Result<serde_json::Value> {
114 let maybe_lossy_str = String::from_utf8_lossy(self.as_slice());
115
116 if maybe_lossy_str.as_bytes() != self.as_slice() {
117 warn!(target: LOG_MODULE_META, "Value contains invalid utf-8, converting to lossy string");
118 }
119
120 Ok(serde_json::from_str(&maybe_lossy_str)?)
121 }
122}
123
124impl Decodable for MetaValue {
125 fn consensus_decode_partial<R: std::io::Read>(
126 r: &mut R,
127 modules: &fedimint_core::module::registry::ModuleDecoderRegistry,
128 ) -> Result<Self, fedimint_core::encoding::DecodeError> {
129 let bytes = Vec::consensus_decode_partial(r, modules)?;
130
131 if Self::MAX_LEN_BYTES < bytes.len() {
132 return Err(DecodeError::new_custom(anyhow::format_err!("Too long")));
133 }
134
135 Ok(Self(bytes))
136 }
137}
138impl Serialize for MetaValue {
139 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
140 where
141 S: Serializer,
142 {
143 assert!(self.0.len() <= Self::MAX_LEN_BYTES);
144 serializer.serialize_str(&hex::encode(&self.0))
145 }
146}
147
148impl<'de> Deserialize<'de> for MetaValue {
150 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
151 where
152 D: Deserializer<'de>,
153 {
154 struct MetaValueVisitor;
155
156 impl<'de> Visitor<'de> for MetaValueVisitor {
157 type Value = MetaValue;
158
159 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
160 formatter.write_str("a hex string")
161 }
162
163 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
164 where
165 E: de::Error,
166 {
167 let val = hex::decode(value).map_err(de::Error::custom)?;
168
169 if MetaValue::MAX_LEN_BYTES < val.len() {
170 return Err(de::Error::custom("Too long"));
171 }
172
173 Ok(MetaValue(val))
174 }
175 }
176
177 deserializer.deserialize_str(MetaValueVisitor)
178 }
179}
180
181#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
182pub struct MetaConsensusItem {
183 pub salt: u64,
187 pub key: MetaKey,
188 pub value: MetaValue,
189}
190
191#[derive(Debug, Clone, Encodable, Decodable, Serialize, Deserialize, PartialEq, Eq)]
193pub struct MetaConsensusValue {
194 pub revision: u64,
195 pub value: MetaValue,
196}
197
198#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
200pub struct MetaInput;
201
202#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
204pub struct MetaOutput;
205
206#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Encodable, Decodable)]
208pub struct MetaOutputOutcome;
209
210#[derive(Debug, Clone, Eq, PartialEq, Hash, Error, Encodable, Decodable)]
212pub enum MetaInputError {
213 #[error("This module does not support inputs")]
214 NotSupported,
215}
216
217#[derive(Debug, Clone, Eq, PartialEq, Hash, Error, Encodable, Decodable)]
219pub enum MetaOutputError {
220 #[error("This module does not support outputs")]
221 NotSupported,
222}
223
224pub struct MetaModuleTypes;
226
227plugin_types_trait_impl_common!(
229 KIND,
230 MetaModuleTypes,
231 MetaClientConfig,
232 MetaInput,
233 MetaOutput,
234 MetaOutputOutcome,
235 MetaConsensusItem,
236 MetaInputError,
237 MetaOutputError
238);
239
240#[derive(Debug)]
241pub struct MetaCommonInit;
242
243impl CommonModuleInit for MetaCommonInit {
244 const CONSENSUS_VERSION: ModuleConsensusVersion = MODULE_CONSENSUS_VERSION;
245 const KIND: ModuleKind = KIND;
246
247 type ClientConfig = MetaClientConfig;
248
249 fn decoder() -> Decoder {
250 MetaModuleTypes::decoder_builder().build()
251 }
252}
253
254impl fmt::Display for MetaClientConfig {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 write!(f, "MetaClientConfig")
257 }
258}
259impl fmt::Display for MetaInput {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 write!(f, "MetaInput")
262 }
263}
264
265impl fmt::Display for MetaOutput {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 write!(f, "MetaOutput")
268 }
269}
270
271impl fmt::Display for MetaOutputOutcome {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 write!(f, "MetaOutputOutcome")
274 }
275}
276
277impl fmt::Display for MetaConsensusItem {
278 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279 write!(f, "MetaConsensusItem")
280 }
281}