lyquor_primitives/
lib.rs

1pub extern crate serde;
2
3use std::fmt;
4use std::sync::Arc;
5
6pub use alloy_primitives::hex;
7pub use alloy_primitives::{self, Address, B256, U32, U64, U128, U256, address, uint};
8pub use blake3;
9pub use bytes::{self, Bytes};
10pub use cb58;
11pub use serde::{Deserialize, Serialize};
12use typed_builder::TypedBuilder;
13
14mod id;
15pub use id::{LyquidID, LyquidNumber, NodeID, RequiredLyquid};
16
17// Custom serde module for Arc<Option<T>>
18pub mod arc_option_serde {
19    use super::*;
20    use serde::{Deserialize, Deserializer, Serialize, Serializer};
21
22    pub fn serialize<T, S>(value: &Option<Arc<T>>, serializer: S) -> Result<S::Ok, S::Error>
23    where
24        T: Serialize,
25        S: Serializer,
26    {
27        match value {
28            Some(arc) => Some(arc.as_ref()).serialize(serializer),
29            None => Option::<&T>::None.serialize(serializer),
30        }
31    }
32
33    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<Arc<T>>, D::Error>
34    where
35        T: Deserialize<'de>,
36        D: Deserializer<'de>,
37    {
38        let opt = Option::<T>::deserialize(deserializer)?;
39        Ok(opt.map(Arc::new))
40    }
41}
42
43pub type Hash = blake3::Hash;
44
45/// Position of a slot in the sequencer's backend.
46///
47/// Typically, a sequencing backend may be a chain that carries Lyquid slots in some of its blocks.
48/// This means the [SlotNumber]s do not necessarily correspond to continuous [ChainPos] in the sequencing backend.
49#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
50pub struct ChainPos(u128);
51
52impl ChainPos {
53    pub const ZERO: Self = Self(0);
54    pub fn new(block_position: u64, block_index: u32) -> Self {
55        Self((block_position as u128) << 32 | (block_index as u128))
56    }
57
58    #[inline(always)]
59    pub fn block(&self) -> u64 {
60        (self.0 >> 32) as u64
61    }
62
63    #[inline(always)]
64    pub fn next_block(&self) -> Self {
65        Self(((self.0 >> 32) + 1) << 32)
66    }
67}
68
69impl fmt::Display for ChainPos {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
71        write!(f, "(block={}, log={})", self.0 >> 32, self.0 as u32)
72    }
73}
74
75impl fmt::Debug for ChainPos {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
77        fmt::Display::fmt(self, f)
78    }
79}
80
81#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
82pub enum InputABI {
83    Lyquor,
84    Eth,
85}
86
87#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
88pub struct HashBytes(Hash);
89
90impl HashBytes {
91    pub fn new(hash: Hash) -> Self {
92        Self(hash)
93    }
94
95    pub fn into_inner(self) -> Hash {
96        self.0
97    }
98}
99
100impl std::ops::Deref for HashBytes {
101    type Target = Hash;
102    fn deref(&self) -> &Hash {
103        &self.0
104    }
105}
106
107impl From<[u8; 32]> for HashBytes {
108    fn from(hash: [u8; 32]) -> Self {
109        Self(hash.into())
110    }
111}
112
113impl From<Hash> for HashBytes {
114    fn from(hash: Hash) -> Self {
115        Self(hash)
116    }
117}
118
119impl From<HashBytes> for Hash {
120    fn from(hash_bytes: HashBytes) -> Self {
121        hash_bytes.0
122    }
123}
124
125impl Serialize for HashBytes {
126    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
127    where
128        S: serde::Serializer,
129    {
130        let bytes: &[u8; 32] = self.0.as_bytes();
131        serializer.serialize_bytes(bytes)
132    }
133}
134
135impl<'de> Deserialize<'de> for HashBytes {
136    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
137    where
138        D: serde::Deserializer<'de>,
139    {
140        use serde::de::Error;
141        let bytes = <Vec<u8>>::deserialize(deserializer)?;
142        if bytes.len() != 32 {
143            return Err(D::Error::custom(format!(
144                "Expected 32 bytes for HashBytes, got {}",
145                bytes.len()
146            )));
147        }
148        let mut array = [0u8; 32];
149        array.copy_from_slice(&bytes);
150        Ok(HashBytes(blake3::Hash::from(array)))
151    }
152}
153
154#[derive(Serialize, Deserialize, PartialEq, Clone, TypedBuilder)]
155pub struct CallParams {
156    /// The ultimate origin of the call (the transaction signer, for example if the call comes from
157    /// the chain. The default is zero address when unused.
158    #[builder(default = Address::ZERO)]
159    pub origin: Address,
160    /// The direct caller.
161    pub caller: Address,
162    #[builder(default = GROUP_DEFAULT.into())]
163    pub group: String,
164    pub method: String,
165    pub input: Bytes,
166    #[builder(default = InputABI::Lyquor)]
167    pub abi: InputABI,
168}
169
170impl Eq for CallParams {}
171
172impl fmt::Debug for CallParams {
173    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
174        write!(
175            f,
176            "CallParams(caller={}, origin={}, group={}, method={}, input={}, abi={:?})",
177            self.caller,
178            self.origin,
179            self.group,
180            self.method,
181            hex::encode(&self.input),
182            self.abi
183        )
184    }
185}
186
187pub type Signature = (); // TODO
188#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
189pub struct Certificate; // TODO
190pub type PubKey = (); // TODO
191
192#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
193pub enum OracleTarget {
194    // Lyquor network fn
195    Lyquor(LyquidID),
196    // Native contract of the sequence backend (such as EVM)
197    SequenceVM(Address),
198}
199
200/// Contains other fields needed to define a call alongside the standard call parameters.
201#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
202pub struct OracleHeader {
203    /// The node that proposed the call for certification.
204    pub proposer: NodeID,
205    /// The way the call will end (e.g., to be a network fn call, or to call the sequencing chain's
206    /// own VM.)
207    pub target: OracleTarget,
208    /// The hash of the oracle config.
209    pub config_hash: HashBytes,
210}
211
212#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Debug)]
213pub struct OracleSigner {
214    pub id: NodeID,
215    pub key: PubKey,
216}
217
218#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
219pub struct OracleConfig {
220    pub committee: Vec<OracleSigner>,
221    pub threshold: usize,
222}
223
224/// UPC message sent to each signer. The signer will check config hash to see if it's consistent
225/// with its oracle state as of the given network state version, and then run `validate`, a
226/// signature will be automatically signed using the derived key, and respond to the caller if it
227/// `validate()` returns true.
228#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
229pub struct OracleMessage {
230    pub header: OracleHeader,
231    pub params: CallParams,
232}
233
234#[derive(Serialize, Deserialize)]
235pub struct OracleResponse {
236    pub approval: bool,
237    /// Signer signs on hash(<OracleMessage> and <approval bool>)
238    pub sig: Signature,
239}
240
241impl OracleResponse {
242    pub fn sign(msg: OracleMessage, approval: bool) -> Self {
243        // TODO
244        let _ = msg;
245        Self { approval, sig: () }
246    }
247
248    pub fn verify(&self, msg_hash: &Hash) -> bool {
249        // TODO
250        let _ = msg_hash;
251        true
252    }
253}
254
255/// Oracle certificate that could be sequenced.
256#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
257pub struct OracleCert {
258    pub header: OracleHeader,
259    // If Some, a new config is agreed upon for this and following certificates, and becomes
260    // effective until the next update.
261    pub new_config: Option<OracleConfig>,
262    // The certificate that shows a threshold approval (could be implemented by a vector of multi
263    // sigs).
264    pub cert: Certificate,
265}
266
267impl Certificate {
268    pub fn new(sigs: Vec<(OracleSigner, Signature)>) -> Self {
269        // TODO
270        let _ = sigs;
271        Self
272    }
273
274    pub fn verify(&self, input: &CallParams) -> bool {
275        // TODO
276        let _ = input;
277        true
278    }
279}
280
281impl OracleCert {
282    pub fn verify(&self, caller: &Address, input: Bytes) -> bool {
283        // TODO
284        let _ = (caller, input);
285        true
286    }
287}
288
289pub const GROUP_DEFAULT: &str = "main";
290pub const GROUP_NODE: &str = "node";
291pub const GROUP_UPC_CALLEE: &str = "upc::callee";
292pub const GROUP_UPC_REQ: &str = "upc::request";
293pub const GROUP_UPC_RESP: &str = "upc::response";
294
295pub type LyteLogTopic = B256;
296
297#[derive(Serialize, Deserialize, Clone)]
298pub struct LyteLog {
299    pub topics: [Option<Box<LyteLogTopic>>; 4],
300    pub data: Bytes,
301}
302
303impl LyteLog {
304    pub fn new_from_tagged_value<V: Serialize>(tag: &str, value: &V) -> Self {
305        let topic0 = Box::new(Self::tagged_value_topic(tag));
306        Self {
307            topics: [Some(topic0), None, None, None],
308            data: encode_object(value).into(),
309        }
310    }
311
312    pub fn tagged_value_topic(tag: &str) -> LyteLogTopic {
313        let mut hasher = blake3::Hasher::new();
314        hasher.update(tag.as_bytes());
315        let topic: [u8; 32] = hasher.finalize().into();
316        topic.into()
317    }
318}
319
320#[derive(Serialize, Deserialize, Clone, Debug)]
321pub struct RegisterEvent {
322    pub id: LyquidID,
323    pub deps: Vec<LyquidID>,
324}
325
326impl fmt::Debug for LyteLog {
327    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
328        write!(
329            f,
330            "LyteLog(topics={}, data=<{} bytes>)",
331            self.topics
332                .iter()
333                .map(|t| match t {
334                    Some(t) => t.to_string(),
335                    None => "_".into(),
336                })
337                .collect::<Vec<_>>()
338                .join(", "),
339            self.data.len()
340        )
341    }
342}
343
344pub fn decode_object<T: for<'a> Deserialize<'a>>(raw: &[u8]) -> Option<T> {
345    alkahest::deserialize::<alkahest::Bincode, T>(raw).ok()
346}
347
348pub fn encode_object<T: Serialize + ?Sized>(obj: &T) -> Vec<u8> {
349    let mut raw = Vec::new();
350    alkahest::serialize_to_vec::<alkahest::Bincode, &T>(obj, &mut raw);
351    raw
352}
353
354#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
355pub enum StateCategory {
356    Network,
357    Instance,
358}
359
360#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Copy, Clone)]
361#[serde(rename_all = "camelCase")]
362pub enum ConsoleSink {
363    StdOut,
364    StdErr,
365}
366
367pub fn encode_method_name(cat_prefix: &str, group: &str, method: &str) -> String {
368    let mut output = cat_prefix.to_string();
369    output.push('_');
370    cb58::bs58::encode(group.as_bytes()).onto(&mut output).unwrap();
371    output.push('_');
372    output.push_str(method);
373    output
374}
375
376#[doc(hidden)]
377#[macro_export]
378macro_rules! object_by_fields_ {
379    ($serde_crate: tt, $($var:ident: $type:ty = $val:expr),*) => {{
380        #[allow(non_camel_case_types)]
381        #[derive($crate::Serialize, Clone)]
382        #[serde(crate = $serde_crate)]
383        struct parameters { $($var:$type),* }
384        parameters { $($var: $val),* }
385    }};
386}
387
388#[macro_export]
389macro_rules! object_by_fields {
390    ($($token: tt)*) => {{
391        $crate::object_by_fields_!("lyquor_primitives::serde", $($token)*)
392    }};
393}
394
395#[doc(hidden)]
396#[macro_export]
397macro_rules! encode_by_fields_ {
398    ($serde_crate: tt, $($var:ident: $type:ty = $val:expr),*) => {{
399        $crate::encode_object(&$crate::object_by_fields_!($serde_crate, $($var: $type = $val),*))
400    }};
401    ($serde_crate: tt, $($var:ident: $type:ty),*) => {{
402        $crate::encode_object(&$crate::object_by_fields_!($serde_crate, $($var: $type = $var),*))
403    }};
404}
405
406#[macro_export]
407macro_rules! encode_by_fields {
408    ($($token: tt)*) => {{
409        $crate::encode_by_fields_!("lyquor_primitives::serde", $($token)*)
410    }};
411}
412
413#[macro_export]
414macro_rules! decode_by_fields {
415    ($encoded:expr, $($var:ident: $type:ty),*) => {{
416        #[allow(non_camel_case_types)]
417        #[derive($crate::Deserialize)]
418        #[serde(crate = "lyquor_primitives::serde")]
419        struct parameters { $($var:$type),* }
420        $crate::decode_object::<parameters>($encoded)
421    }};
422}
423
424#[derive(Serialize, Deserialize, Debug)]
425pub struct Range<T> {
426    pub start: Option<T>,
427    pub end: Option<T>,
428}
429
430#[macro_export]
431macro_rules! debug_struct_name {
432    ($t:ty) => {
433        impl std::fmt::Debug for $t {
434            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
435                f.write_str(stringify!($t))
436            }
437        }
438    };
439}