locutus_stdlib/
contract_interface.rs

1//! Interface and related utilities for interaction with the compiled WASM contracts.
2//! Contracts have an isomorphic interface which partially maps to this interface,
3//! allowing interaction between the runtime and the contracts themselves.
4//!
5//! This abstraction layer shouldn't leak beyond the contract handler.
6
7use std::{
8    borrow::{Borrow, Cow},
9    collections::HashMap,
10    fmt::Display,
11    fs::File,
12    hash::{Hash, Hasher},
13    io::{Cursor, Read},
14    ops::{Deref, DerefMut},
15    path::Path,
16    str::FromStr,
17    sync::Arc,
18};
19
20use blake2::{Blake2s256, Digest};
21use byteorder::LittleEndian;
22use serde::{Deserialize, Deserializer, Serialize, Serializer};
23use serde_with::serde_as;
24
25const CONTRACT_KEY_SIZE: usize = 32;
26
27/// Type of errors during interaction with a contract.
28#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
29pub enum ContractError {
30    #[error("de/serialization error: {0}")]
31    Deser(String),
32    #[error("invalid contract update")]
33    InvalidUpdate,
34    #[error("trying to read an invalid state")]
35    InvalidState,
36    #[error("trying to read an invalid delta")]
37    InvalidDelta,
38    #[error("{0}")]
39    Other(String),
40}
41
42pub trait TryFromTsStd<T>: Sized {
43    fn try_decode(value: T) -> Result<Self, WsApiError>;
44}
45
46#[derive(thiserror::Error, Debug)]
47pub enum WsApiError {
48    #[error("Failed decoding msgpack message from client request: {cause}")]
49    MsgpackDecodeError { cause: String },
50    #[error("Unsupported contract version")]
51    UnsupportedContractVersion,
52    #[error("Failed unpacking contract container")]
53    UnpackingContractContainerError(Box<dyn std::error::Error + Send + Sync + 'static>),
54}
55
56impl WsApiError {
57    pub fn deserialization(cause: String) -> Self {
58        Self::MsgpackDecodeError { cause }
59    }
60}
61
62/// An update to a contract state or any required related contracts to update that state.
63#[non_exhaustive]
64#[derive(Debug, Serialize, Deserialize)]
65pub struct UpdateModification<'a> {
66    #[serde(borrow)]
67    pub new_state: Option<State<'a>>,
68    pub related: Vec<RelatedContract>,
69}
70
71impl<'a> UpdateModification<'a> {
72    /// Constructor for self when the state is valid.
73    pub fn valid(new_state: State<'a>) -> Self {
74        Self {
75            new_state: Some(new_state),
76            related: vec![],
77        }
78    }
79
80    /// Constructor for self when this contract still is missing some [`RelatedContract`]
81    /// to proceed with any verification or updates.
82    pub fn requires(related: Vec<RelatedContract>) -> Self {
83        Self {
84            new_state: None,
85            related,
86        }
87    }
88
89    /// Unwraps self returning a [`State`].
90    ///
91    /// Panics if self does not contain a state.
92    pub fn unwrap_valid(self) -> State<'a> {
93        match self.new_state {
94            Some(s) => s,
95            _ => panic!("failed unwrapping state in modification"),
96        }
97    }
98
99    /// Gets the pending related contracts.
100    pub fn get_related(&self) -> &[RelatedContract] {
101        &self.related
102    }
103
104    /// Copies the data if not owned and returns an owned version of self.
105    pub fn into_owned(self) -> UpdateModification<'static> {
106        let Self { new_state, related } = self;
107        UpdateModification {
108            new_state: new_state.map(|s| State::from(s.into_bytes())),
109            related,
110        }
111    }
112}
113
114/// The contracts related to a parent or root contract. Tipically this means
115/// contracts which state requires to be verified or integrated in some way with
116/// the parent contract.
117#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
118pub struct RelatedContracts<'a> {
119    #[serde(borrow)]
120    map: HashMap<ContractInstanceId, Option<State<'a>>>,
121}
122
123impl RelatedContracts<'_> {
124    pub fn new() -> Self {
125        Self {
126            map: HashMap::new(),
127        }
128    }
129
130    /// Copies the data if not owned and returns an owned version of self.
131    pub fn into_owned(self) -> RelatedContracts<'static> {
132        let mut map = HashMap::with_capacity(self.map.len());
133        for (k, v) in self.map {
134            map.insert(k, v.map(|s| s.into_owned()));
135        }
136        RelatedContracts { map }
137    }
138}
139
140impl<'a> TryFrom<&'a rmpv::Value> for RelatedContracts<'a> {
141    type Error = String;
142
143    fn try_from(value: &'a rmpv::Value) -> Result<Self, Self::Error> {
144        let related_contracts: HashMap<ContractInstanceId, Option<State<'a>>> =
145            HashMap::from_iter(value.as_map().unwrap().iter().map(|(key, val)| {
146                let id = ContractInstanceId::from_bytes(key.as_slice().unwrap()).unwrap();
147                let state = State::from(val.as_slice().unwrap());
148                (id, Some(state))
149            }));
150        Ok(RelatedContracts::from(related_contracts))
151    }
152}
153
154impl<'a> TryFromTsStd<&'a rmpv::Value> for RelatedContracts<'a> {
155    fn try_decode(value: &'a rmpv::Value) -> Result<Self, WsApiError> {
156        let related_contracts: HashMap<ContractInstanceId, Option<State<'a>>> =
157            HashMap::from_iter(value.as_map().unwrap().iter().map(|(key, val)| {
158                let id = ContractInstanceId::from_bytes(key.as_slice().unwrap()).unwrap();
159                let state = State::from(val.as_slice().unwrap());
160                (id, Some(state))
161            }));
162        Ok(RelatedContracts::from(related_contracts))
163    }
164}
165
166impl<'a> From<HashMap<ContractInstanceId, Option<State<'a>>>> for RelatedContracts<'a> {
167    fn from(related_contracts: HashMap<ContractInstanceId, Option<State<'a>>>) -> Self {
168        Self {
169            map: related_contracts,
170        }
171    }
172}
173
174/// A contract related to an other contract and the specification
175/// of the kind of update notifications that should be received by this contract.
176#[derive(Debug, Serialize, Deserialize)]
177pub struct RelatedContract {
178    pub contract_instance_id: ContractInstanceId,
179    pub mode: RelatedMode,
180}
181
182/// Specification of the notifications of interest from a related contract.
183#[derive(Debug, Serialize, Deserialize)]
184pub enum RelatedMode {
185    /// Retrieve the state once, not concerned with subsequent changes.
186    StateOnce,
187    /// Retrieve the state once, and then supply deltas from then on.
188    StateOnceThenDeltas,
189    /// Retrieve the state and then provide new states every time it updates.
190    StateEvery,
191    /// Retrieve the state and then provide new states and deltas every time it updates.
192    StateThenStateAndDeltas,
193}
194
195/// The result of calling the [`ContractInterface::validate_state`] function.
196#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
197pub enum ValidateResult {
198    Valid,
199    Invalid,
200    /// The peer will attempt to retrieve the requested contract states
201    /// and will call validate_state() again when it retrieves them.
202    RequestRelated(Vec<ContractInstanceId>),
203}
204
205/// Update notifications for a contract or a related contract.
206#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
207pub enum UpdateData<'a> {
208    State(#[serde(borrow)] State<'a>),
209    Delta(#[serde(borrow)] StateDelta<'a>),
210    StateAndDelta {
211        #[serde(borrow)]
212        state: State<'a>,
213        #[serde(borrow)]
214        delta: StateDelta<'a>,
215    },
216    RelatedState {
217        related_to: ContractInstanceId,
218        #[serde(borrow)]
219        state: State<'a>,
220    },
221    RelatedDelta {
222        related_to: ContractInstanceId,
223        #[serde(borrow)]
224        delta: StateDelta<'a>,
225    },
226    RelatedStateAndDelta {
227        related_to: ContractInstanceId,
228        #[serde(borrow)]
229        state: State<'a>,
230        #[serde(borrow)]
231        delta: StateDelta<'a>,
232    },
233}
234
235impl UpdateData<'_> {
236    pub fn size(&self) -> usize {
237        match self {
238            UpdateData::State(state) => state.size(),
239            UpdateData::Delta(delta) => delta.size(),
240            UpdateData::StateAndDelta { state, delta } => state.size() + delta.size(),
241            UpdateData::RelatedState { state, .. } => state.size() + CONTRACT_KEY_SIZE,
242            UpdateData::RelatedDelta { delta, .. } => delta.size() + CONTRACT_KEY_SIZE,
243            UpdateData::RelatedStateAndDelta { state, delta, .. } => {
244                state.size() + delta.size() + CONTRACT_KEY_SIZE
245            }
246        }
247    }
248
249    pub fn unwrap_delta(&self) -> &StateDelta<'_> {
250        match self {
251            UpdateData::Delta(delta) => delta,
252            _ => panic!(),
253        }
254    }
255
256    /// Copies the data if not owned and returns an owned version of self.
257    pub fn into_owned(self) -> UpdateData<'static> {
258        match self {
259            UpdateData::State(s) => UpdateData::State(State::from(s.into_bytes())),
260            UpdateData::Delta(d) => UpdateData::Delta(StateDelta::from(d.into_bytes())),
261            UpdateData::StateAndDelta { state, delta } => UpdateData::StateAndDelta {
262                delta: StateDelta::from(delta.into_bytes()),
263                state: State::from(state.into_bytes()),
264            },
265            UpdateData::RelatedState { related_to, state } => UpdateData::RelatedState {
266                related_to,
267                state: State::from(state.into_bytes()),
268            },
269            UpdateData::RelatedDelta { related_to, delta } => UpdateData::RelatedDelta {
270                related_to,
271                delta: StateDelta::from(delta.into_bytes()),
272            },
273            UpdateData::RelatedStateAndDelta {
274                related_to,
275                state,
276                delta,
277            } => UpdateData::RelatedStateAndDelta {
278                related_to,
279                state: State::from(state.into_bytes()),
280                delta: StateDelta::from(delta.into_bytes()),
281            },
282        }
283    }
284}
285
286impl<'a> From<StateDelta<'a>> for UpdateData<'a> {
287    fn from(delta: StateDelta<'a>) -> Self {
288        UpdateData::Delta(delta)
289    }
290}
291
292impl<'a> TryFromTsStd<&'a rmpv::Value> for UpdateData<'a> {
293    fn try_decode(value: &'a rmpv::Value) -> Result<Self, WsApiError> {
294        let value_map: HashMap<_, _> = HashMap::from_iter(
295            value
296                .as_map()
297                .unwrap()
298                .iter()
299                .map(|(key, val)| (key.as_str().unwrap(), val)),
300        );
301        let mut map_keys = Vec::from_iter(value_map.keys().copied());
302        map_keys.sort();
303        match map_keys.as_slice() {
304            ["delta"] => {
305                let delta = value_map.get("delta").unwrap();
306                Ok(UpdateData::Delta(StateDelta::from(
307                    delta.as_slice().unwrap(),
308                )))
309            }
310            ["state"] => {
311                let state = value_map.get("state").unwrap();
312                Ok(UpdateData::Delta(StateDelta::from(
313                    state.as_slice().unwrap(),
314                )))
315            }
316            ["delta", "state"] => {
317                let state = value_map.get("state").unwrap();
318                let delta = value_map.get("delta").unwrap();
319                Ok(UpdateData::StateAndDelta {
320                    state: State::from(state.as_slice().unwrap()),
321                    delta: StateDelta::from(delta.as_slice().unwrap()),
322                })
323            }
324            ["delta", "relatedTo"] => {
325                let delta = value_map.get("delta").unwrap();
326                let related_to = value_map.get("relatedTo").unwrap();
327                Ok(UpdateData::RelatedDelta {
328                    delta: StateDelta::from(delta.as_slice().unwrap()),
329                    related_to: ContractInstanceId::from_bytes(related_to.as_slice().unwrap())
330                        .unwrap(),
331                })
332            }
333            ["state", "relatedTo"] => {
334                let state = value_map.get("state").unwrap();
335                let related_to = value_map.get("relatedTo").unwrap();
336                Ok(UpdateData::RelatedState {
337                    state: State::from(state.as_slice().unwrap()),
338                    related_to: ContractInstanceId::from_bytes(related_to.as_slice().unwrap())
339                        .unwrap(),
340                })
341            }
342            ["delta", "state", "relatedTo"] => {
343                let state = value_map.get("state").unwrap();
344                let delta = value_map.get("delta").unwrap();
345                let related_to = value_map.get("relatedTo").unwrap();
346                Ok(UpdateData::RelatedStateAndDelta {
347                    state: State::from(state.as_slice().unwrap()),
348                    delta: StateDelta::from(delta.as_slice().unwrap()),
349                    related_to: ContractInstanceId::from_bytes(related_to.as_slice().unwrap())
350                        .unwrap(),
351                })
352            }
353            _ => unreachable!(),
354        }
355    }
356}
357
358/// Trait to implement for the contract building.
359///
360/// Contains all necessary methods to interact with the contract.
361///
362/// # Examples
363///
364/// Implementing `ContractInterface` on a type:
365///
366/// ```
367/// # use locutus_stdlib::prelude::*;
368/// struct Contract;
369///
370/// #[contract]
371/// impl ContractInterface for Contract {
372///     fn validate_state(
373///         _parameters: Parameters<'static>,
374///         _state: State<'static>,
375///         _related: RelatedContracts
376///     ) -> Result<ValidateResult, ContractError> {
377///         Ok(ValidateResult::Valid)
378///     }
379///
380///     fn validate_delta(
381///         _parameters: Parameters<'static>,
382///         _delta: StateDelta<'static>
383///     ) -> Result<bool, ContractError> {
384///         Ok(true)
385///     }
386///
387///     fn update_state(
388///         _parameters: Parameters<'static>,
389///         state: State<'static>,
390///         _data: Vec<UpdateData>,
391///     ) -> Result<UpdateModification<'static>, ContractError> {
392///         Ok(UpdateModification::valid(state))
393///     }
394///
395///     fn summarize_state(
396///         _parameters: Parameters<'static>,
397///         _state: State<'static>,
398///     ) -> Result<StateSummary<'static>, ContractError> {
399///         Ok(StateSummary::from(vec![]))
400///     }
401///
402///     fn get_state_delta(
403///         _parameters: Parameters<'static>,
404///         _state: State<'static>,
405///         _summary: StateSummary<'static>,
406///     ) -> Result<StateDelta<'static>, ContractError> {
407///         Ok(StateDelta::from(vec![]))
408///     }
409/// }
410/// ```
411// ANCHOR: contractifce
412pub trait ContractInterface {
413    /// Verify that the state is valid, given the parameters.
414    fn validate_state(
415        parameters: Parameters<'static>,
416        state: State<'static>,
417        related: RelatedContracts<'static>,
418    ) -> Result<ValidateResult, ContractError>;
419
420    /// Verify that a delta is valid if possible, returns false if and only delta is
421    /// definitely invalid, true otherwise.
422    fn validate_delta(
423        parameters: Parameters<'static>,
424        delta: StateDelta<'static>,
425    ) -> Result<bool, ContractError>;
426
427    /// Update the state to account for the new data
428    fn update_state(
429        parameters: Parameters<'static>,
430        state: State<'static>,
431        data: Vec<UpdateData<'static>>,
432    ) -> Result<UpdateModification<'static>, ContractError>;
433
434    /// Generate a concise summary of a state that can be used to create deltas
435    /// relative to this state.
436    fn summarize_state(
437        parameters: Parameters<'static>,
438        state: State<'static>,
439    ) -> Result<StateSummary<'static>, ContractError>;
440
441    /// Generate a state delta using a summary from the current state.
442    /// This along with [`Self::summarize_state`] allows flexible and efficient
443    /// state synchronization between peers.
444    fn get_state_delta(
445        parameters: Parameters<'static>,
446        state: State<'static>,
447        summary: StateSummary<'static>,
448    ) -> Result<StateDelta<'static>, ContractError>;
449}
450// ANCHOR_END: contractifce
451
452/// A complete contract specification requires a `parameters` section
453/// and a `contract` section.
454#[derive(Debug, Serialize, Deserialize, Clone)]
455pub struct Contract<'a> {
456    #[serde(borrow)]
457    pub parameters: Parameters<'a>,
458    #[serde(borrow)]
459    pub data: ContractCode<'a>,
460    key: ContractKey,
461}
462
463impl<'a> Contract<'a> {
464    /// Returns a contract from [contract code](ContractCode) and given [parameters](Parameters).
465    pub fn new(contract: ContractCode<'a>, parameters: Parameters<'a>) -> Contract<'a> {
466        let key = ContractKey::from((&parameters, &contract));
467        Contract {
468            parameters,
469            data: contract,
470            key,
471        }
472    }
473
474    /// Key portion of the specification.
475    pub fn key(&self) -> &ContractKey {
476        &self.key
477    }
478
479    /// Code portion of the specification.
480    pub fn into_code(self) -> ContractCode<'a> {
481        self.data
482    }
483}
484
485impl TryFrom<Vec<u8>> for Contract<'static> {
486    type Error = std::io::Error;
487
488    fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
489        use byteorder::ReadBytesExt;
490        let mut reader = Cursor::new(data);
491
492        let params_len = reader.read_u64::<LittleEndian>()?;
493        let mut params_buf = vec![0; params_len as usize];
494        reader.read_exact(&mut params_buf)?;
495        let parameters = Parameters::from(params_buf);
496
497        let contract_len = reader.read_u64::<LittleEndian>()?;
498        let mut contract_buf = vec![0; contract_len as usize];
499        reader.read_exact(&mut contract_buf)?;
500        let contract = ContractCode::from(contract_buf);
501
502        let key = ContractKey::from((&parameters, &contract));
503
504        Ok(Contract {
505            parameters,
506            data: contract,
507            key,
508        })
509    }
510}
511
512impl PartialEq for Contract<'_> {
513    fn eq(&self, other: &Self) -> bool {
514        self.key == other.key
515    }
516}
517
518impl Eq for Contract<'_> {}
519
520impl std::fmt::Display for Contract<'_> {
521    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522        write!(f, "ContractSpec( key: ")?;
523        internal_fmt_key(&self.key.instance.0, f)?;
524        let data: String = if self.data.data.len() > 8 {
525            self.data.data[..4]
526                .iter()
527                .map(|b| char::from(*b))
528                .chain("...".chars())
529                .chain(self.data.data[4..].iter().map(|b| char::from(*b)))
530                .collect()
531        } else {
532            self.data.data.iter().copied().map(char::from).collect()
533        };
534        write!(f, ", data: [{data}])")
535    }
536}
537
538#[cfg(all(any(test, feature = "testing"), target_family = "unix"))]
539impl<'a> arbitrary::Arbitrary<'a> for Contract<'static> {
540    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
541        let contract: ContractCode = u.arbitrary()?;
542        let parameters: Vec<u8> = u.arbitrary()?;
543        let parameters = Parameters::from(parameters);
544
545        let key = ContractKey::from((&parameters, &contract));
546
547        Ok(Contract {
548            data: contract,
549            parameters,
550            key,
551        })
552    }
553}
554
555/// Data that forms part of a contract along with the WebAssembly code.
556///
557/// This is supplied to the contract as a parameter to the contract's functions. Parameters are
558/// typically be used to configure a contract, much like the parameters of a constructor function.
559#[derive(Debug, Clone, Serialize, Deserialize)]
560#[serde_as]
561#[cfg_attr(feature = "testing", derive(arbitrary::Arbitrary))]
562pub struct Parameters<'a>(
563    #[serde_as(as = "serde_with::Bytes")]
564    #[serde(borrow)]
565    Cow<'a, [u8]>,
566);
567
568impl<'a> Parameters<'a> {
569    /// Gets the number of bytes of data stored in the `Parameters`.
570    pub fn size(&self) -> usize {
571        self.0.len()
572    }
573
574    /// Returns the bytes of parameters.
575    pub fn into_bytes(self) -> Vec<u8> {
576        self.0.into_owned()
577    }
578
579    /// Copies the data if not owned and returns an owned version of self.
580    pub fn into_owned(self) -> Parameters<'static> {
581        let data: Cow<'static, _> = Cow::from(self.0.into_owned());
582        Parameters(data)
583    }
584}
585
586impl<'a> From<Vec<u8>> for Parameters<'a> {
587    fn from(data: Vec<u8>) -> Self {
588        Parameters(Cow::from(data))
589    }
590}
591
592impl<'a> From<&'a [u8]> for Parameters<'a> {
593    fn from(s: &'a [u8]) -> Self {
594        Parameters(Cow::from(s))
595    }
596}
597
598impl<'a> TryFromTsStd<&'a rmpv::Value> for Parameters<'a> {
599    fn try_decode(value: &'a rmpv::Value) -> Result<Self, WsApiError> {
600        let params = value.as_slice().unwrap();
601        Ok(Parameters::from(params))
602    }
603}
604
605impl<'a> AsRef<[u8]> for Parameters<'a> {
606    fn as_ref(&self) -> &[u8] {
607        match &self.0 {
608            Cow::Borrowed(arr) => arr,
609            Cow::Owned(arr) => arr.as_ref(),
610        }
611    }
612}
613
614/// Data associated with a contract that can be retrieved by Applications and Components.
615///
616/// For efficiency and flexibility, contract state is represented as a simple [u8] byte array.
617#[serde_as]
618#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
619#[cfg_attr(feature = "testing", derive(arbitrary::Arbitrary))]
620pub struct State<'a>(
621    #[serde_as(as = "serde_with::Bytes")]
622    #[serde(borrow)]
623    Cow<'a, [u8]>,
624);
625
626impl State<'_> {
627    /// Gets the number of bytes of data stored in the `State`.
628    pub fn size(&self) -> usize {
629        self.0.len()
630    }
631
632    pub fn into_owned(self) -> State<'static> {
633        State(self.0.into_owned().into())
634    }
635
636    /// Extracts the owned data as a `Vec<u8>`.
637    pub fn into_bytes(self) -> Vec<u8> {
638        self.0.into_owned()
639    }
640
641    /// Acquires a mutable reference to the owned form of the `State` data.
642    pub fn to_mut(&mut self) -> &mut Vec<u8> {
643        self.0.to_mut()
644    }
645}
646
647impl<'a> From<Vec<u8>> for State<'a> {
648    fn from(state: Vec<u8>) -> Self {
649        State(Cow::from(state))
650    }
651}
652
653impl<'a> From<&'a [u8]> for State<'a> {
654    fn from(state: &'a [u8]) -> Self {
655        State(Cow::from(state))
656    }
657}
658
659impl<'a> AsRef<[u8]> for State<'a> {
660    fn as_ref(&self) -> &[u8] {
661        match &self.0 {
662            Cow::Borrowed(arr) => arr,
663            Cow::Owned(arr) => arr.as_ref(),
664        }
665    }
666}
667
668impl<'a> Deref for State<'a> {
669    type Target = Cow<'a, [u8]>;
670
671    fn deref(&self) -> &Self::Target {
672        &self.0
673    }
674}
675
676impl<'a> DerefMut for State<'a> {
677    fn deref_mut(&mut self) -> &mut Self::Target {
678        &mut self.0
679    }
680}
681
682impl<'a> std::io::Read for State<'a> {
683    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
684        self.as_ref().read(buf)
685    }
686}
687
688/// Represents a modification to some state - similar to a diff in source code.
689///
690/// The exact format of a delta is determined by the contract. A [contract](Contract) implementation will determine whether
691/// a delta is valid - perhaps by verifying it is signed by someone authorized to modify the
692/// contract state. A delta may be created in response to a [State Summary](StateSummary) as part of the State
693/// Synchronization mechanism.
694#[serde_as]
695#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
696#[cfg_attr(feature = "testing", derive(arbitrary::Arbitrary))]
697pub struct StateDelta<'a>(
698    #[serde_as(as = "serde_with::Bytes")]
699    #[serde(borrow)]
700    Cow<'a, [u8]>,
701);
702
703impl<'a> StateDelta<'a> {
704    /// Gets the number of bytes of data stored in the `StateDelta`.
705    pub fn size(&self) -> usize {
706        self.0.len()
707    }
708
709    /// Extracts the owned data as a `Vec<u8>`.
710    pub fn into_bytes(self) -> Vec<u8> {
711        self.0.into_owned()
712    }
713
714    pub fn into_owned(self) -> StateDelta<'static> {
715        StateDelta(self.0.into_owned().into())
716    }
717}
718
719impl<'a> From<Vec<u8>> for StateDelta<'a> {
720    fn from(delta: Vec<u8>) -> Self {
721        StateDelta(Cow::from(delta))
722    }
723}
724
725impl<'a> From<&'a [u8]> for StateDelta<'a> {
726    fn from(delta: &'a [u8]) -> Self {
727        StateDelta(Cow::from(delta))
728    }
729}
730
731impl<'a> AsRef<[u8]> for StateDelta<'a> {
732    fn as_ref(&self) -> &[u8] {
733        match &self.0 {
734            Cow::Borrowed(arr) => arr,
735            Cow::Owned(arr) => arr.as_ref(),
736        }
737    }
738}
739
740impl<'a> Deref for StateDelta<'a> {
741    type Target = Cow<'a, [u8]>;
742
743    fn deref(&self) -> &Self::Target {
744        &self.0
745    }
746}
747
748impl<'a> DerefMut for StateDelta<'a> {
749    fn deref_mut(&mut self) -> &mut Self::Target {
750        &mut self.0
751    }
752}
753
754/// Summary of `State` changes.
755///
756/// Given a contract state, this is a small piece of data that can be used to determine a delta
757/// between two contracts as part of the state synchronization mechanism. The format of a state
758/// summary is determined by the state's contract.
759#[serde_as]
760#[derive(Clone, Serialize, Deserialize, Debug)]
761pub struct StateSummary<'a>(
762    #[serde_as(as = "serde_with::Bytes")]
763    #[serde(borrow)]
764    Cow<'a, [u8]>,
765);
766
767impl StateSummary<'_> {
768    /// Extracts the owned data as a `Vec<u8>`.
769    pub fn into_bytes(self) -> Vec<u8> {
770        self.0.into_owned()
771    }
772
773    /// Gets the number of bytes of data stored in the `StateSummary`.
774    pub fn size(&self) -> usize {
775        self.0.len()
776    }
777
778    pub fn into_owned(self) -> StateSummary<'static> {
779        StateSummary(self.0.into_owned().into())
780    }
781}
782
783impl<'a> From<Vec<u8>> for StateSummary<'a> {
784    fn from(state: Vec<u8>) -> Self {
785        StateSummary(Cow::from(state))
786    }
787}
788
789impl<'a> From<&'a [u8]> for StateSummary<'a> {
790    fn from(state: &'a [u8]) -> Self {
791        StateSummary(Cow::from(state))
792    }
793}
794
795impl<'a> AsRef<[u8]> for StateSummary<'a> {
796    fn as_ref(&self) -> &[u8] {
797        match &self.0 {
798            Cow::Borrowed(arr) => arr,
799            Cow::Owned(arr) => arr.as_ref(),
800        }
801    }
802}
803
804impl<'a> Deref for StateSummary<'a> {
805    type Target = Cow<'a, [u8]>;
806
807    fn deref(&self) -> &Self::Target {
808        &self.0
809    }
810}
811
812impl<'a> DerefMut for StateSummary<'a> {
813    fn deref_mut(&mut self) -> &mut Self::Target {
814        &mut self.0
815    }
816}
817
818#[cfg(all(any(test, feature = "testing"), target_family = "unix"))]
819impl<'a> arbitrary::Arbitrary<'a> for StateSummary<'static> {
820    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
821        let data: Vec<u8> = u.arbitrary()?;
822        Ok(StateSummary::from(data))
823    }
824}
825
826/// The executable contract.
827///
828/// It is the part of the executable belonging to the full specification
829/// and does not include any other metadata (like the parameters).
830#[serde_as]
831#[derive(Debug, Serialize, Deserialize, Clone)]
832pub struct ContractCode<'a> {
833    #[serde_as(as = "serde_with::Bytes")]
834    #[serde(borrow)]
835    data: Cow<'a, [u8]>,
836    #[serde_as(as = "[_; CONTRACT_KEY_SIZE]")]
837    key: [u8; CONTRACT_KEY_SIZE],
838}
839
840impl ContractCode<'_> {
841    /// Contract key hash.
842    pub fn hash(&self) -> &[u8; CONTRACT_KEY_SIZE] {
843        &self.key
844    }
845
846    /// Returns the `Base58` string representation of the contract key.
847    pub fn hash_str(&self) -> String {
848        Self::encode_hash(&self.key)
849    }
850
851    /// Reference to contract code.
852    pub fn data(&self) -> &[u8] {
853        &self.data
854    }
855
856    /// Extracts the owned contract code data as a `Vec<u8>`.
857    pub fn into_bytes(self) -> Vec<u8> {
858        self.data.to_vec()
859    }
860
861    /// Returns the `Base58` string representation of a hash.
862    pub fn encode_hash(hash: &[u8; CONTRACT_KEY_SIZE]) -> String {
863        bs58::encode(hash)
864            .with_alphabet(bs58::Alphabet::BITCOIN)
865            .into_string()
866    }
867
868    /// Copies the data if not owned and returns an owned version of self.
869    pub fn into_owned(self) -> ContractCode<'static> {
870        ContractCode {
871            data: self.data.into_owned().into(),
872            key: self.key,
873        }
874    }
875
876    fn gen_key(data: &[u8]) -> [u8; CONTRACT_KEY_SIZE] {
877        let mut hasher = Blake2s256::new();
878        hasher.update(data);
879        let key_arr = hasher.finalize();
880        debug_assert_eq!(key_arr[..].len(), CONTRACT_KEY_SIZE);
881        let mut key = [0; CONTRACT_KEY_SIZE];
882        key.copy_from_slice(&key_arr);
883        key
884    }
885}
886
887impl From<Vec<u8>> for ContractCode<'static> {
888    fn from(data: Vec<u8>) -> Self {
889        let key = ContractCode::gen_key(&data);
890        ContractCode {
891            data: Cow::from(data),
892            key,
893        }
894    }
895}
896
897impl<'a> From<&'a [u8]> for ContractCode<'a> {
898    fn from(data: &'a [u8]) -> ContractCode {
899        let key = ContractCode::gen_key(data);
900        ContractCode {
901            data: Cow::from(data),
902            key,
903        }
904    }
905}
906
907impl<'a> TryFromTsStd<&'a rmpv::Value> for ContractCode<'a> {
908    fn try_decode(value: &'a rmpv::Value) -> Result<Self, WsApiError> {
909        let data = value.as_slice().unwrap();
910        Ok(ContractCode::from(data))
911    }
912}
913
914impl PartialEq for ContractCode<'_> {
915    fn eq(&self, other: &Self) -> bool {
916        self.key == other.key
917    }
918}
919
920impl Eq for ContractCode<'_> {}
921
922#[cfg(all(any(test, feature = "testing"), target_family = "unix"))]
923impl<'a> arbitrary::Arbitrary<'a> for ContractCode<'static> {
924    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
925        let data: Vec<u8> = u.arbitrary()?;
926        Ok(ContractCode::from(data))
927    }
928}
929
930impl std::fmt::Display for ContractCode<'_> {
931    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
932        write!(f, "Contract( key: ")?;
933        internal_fmt_key(&self.key, f)?;
934        let data: String = if self.data.len() > 8 {
935            self.data[..4]
936                .iter()
937                .map(|b| char::from(*b))
938                .chain("...".chars())
939                .chain(self.data[4..].iter().map(|b| char::from(*b)))
940                .collect()
941        } else {
942            self.data.iter().copied().map(char::from).collect()
943        };
944        write!(f, ", data: [{data}])")
945    }
946}
947
948/// The key representing the hash of the contract executable code hash and a set of `parameters`.
949#[serde_as]
950#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Hash)]
951#[cfg_attr(
952    all(any(test, feature = "testing"), target_family = "unix"),
953    derive(arbitrary::Arbitrary)
954)]
955#[repr(transparent)]
956pub struct ContractInstanceId(#[serde_as(as = "[_; CONTRACT_KEY_SIZE]")] [u8; CONTRACT_KEY_SIZE]);
957
958impl ContractInstanceId {
959    /// `Base58` string representation of the `contract id`.
960    pub fn encode(&self) -> String {
961        bs58::encode(self.0)
962            .with_alphabet(bs58::Alphabet::BITCOIN)
963            .into_string()
964    }
965
966    /// Build `ContractId` from the binary representation.
967    fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, bs58::decode::Error> {
968        let mut spec = [0; CONTRACT_KEY_SIZE];
969        bs58::decode(bytes)
970            .with_alphabet(bs58::Alphabet::BITCOIN)
971            .into(&mut spec)?;
972        Ok(Self(spec))
973    }
974}
975
976impl FromStr for ContractInstanceId {
977    type Err = bs58::decode::Error;
978
979    fn from_str(s: &str) -> Result<Self, Self::Err> {
980        ContractInstanceId::from_bytes(s)
981    }
982}
983
984impl TryFrom<String> for ContractInstanceId {
985    type Error = bs58::decode::Error;
986
987    fn try_from(s: String) -> Result<Self, Self::Error> {
988        ContractInstanceId::from_bytes(s)
989    }
990}
991
992impl<'a, T, U> From<(T, U)> for ContractInstanceId
993where
994    T: Borrow<Parameters<'a>>,
995    U: Borrow<ContractCode<'a>>,
996{
997    fn from(val: (T, U)) -> Self {
998        let (parameters, code_data) = (val.0.borrow(), val.1.borrow());
999        generate_id(parameters, code_data)
1000    }
1001}
1002
1003impl Display for ContractInstanceId {
1004    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1005        write!(f, "{}", self.encode())
1006    }
1007}
1008
1009/// A complete key specification, that represents a cryptographic hash that identifies the contract.
1010#[serde_as]
1011#[derive(Debug, Eq, Clone, Serialize, Deserialize)]
1012#[cfg_attr(
1013    all(any(test, feature = "testing"), target_family = "unix"),
1014    derive(arbitrary::Arbitrary)
1015)]
1016pub struct ContractKey {
1017    instance: ContractInstanceId,
1018    #[serde_as(as = "Option<[_; CONTRACT_KEY_SIZE]>")]
1019    code: Option<[u8; CONTRACT_KEY_SIZE]>,
1020}
1021
1022impl PartialEq for ContractKey {
1023    fn eq(&self, other: &Self) -> bool {
1024        self.instance == other.instance
1025    }
1026}
1027
1028impl std::hash::Hash for ContractKey {
1029    fn hash<H: Hasher>(&self, state: &mut H) {
1030        self.instance.0.hash(state);
1031    }
1032}
1033
1034impl From<ContractInstanceId> for ContractKey {
1035    fn from(instance: ContractInstanceId) -> Self {
1036        Self {
1037            instance,
1038            code: None,
1039        }
1040    }
1041}
1042
1043impl<'a, T, U> From<(T, U)> for ContractKey
1044where
1045    T: Borrow<Parameters<'a>>,
1046    U: Borrow<ContractCode<'a>>,
1047{
1048    fn from(val: (T, U)) -> Self {
1049        let (parameters, code_data) = (val.0.borrow(), val.1.borrow());
1050        let id = generate_id(parameters, code_data);
1051        let contract_hash = code_data.hash();
1052        Self {
1053            instance: id,
1054            code: Some(*contract_hash),
1055        }
1056    }
1057}
1058
1059impl ContractKey {
1060    /// Builds a partial [`ContractKey`](ContractKey), the contract code part is unspecified.
1061    pub fn from_id(instance: impl Into<String>) -> Result<Self, bs58::decode::Error> {
1062        let instance = ContractInstanceId::try_from(instance.into())?;
1063        Ok(Self {
1064            instance,
1065            code: None,
1066        })
1067    }
1068
1069    /// Gets the whole spec key hash.
1070    pub fn bytes(&self) -> &[u8] {
1071        self.instance.0.as_ref()
1072    }
1073
1074    /// Returns the hash of the contract code only, if the key is fully specified.
1075    pub fn code_hash(&self) -> Option<&[u8; CONTRACT_KEY_SIZE]> {
1076        self.code.as_ref()
1077    }
1078
1079    /// Returns the encoded hash of the contract code, if the key is fully specified.
1080    pub fn encoded_code_hash(&self) -> Option<String> {
1081        self.code.as_ref().map(|c| {
1082            bs58::encode(c)
1083                .with_alphabet(bs58::Alphabet::BITCOIN)
1084                .into_string()
1085        })
1086    }
1087
1088    /// Returns the decoded contract key from encoded hash of the contract key and the given
1089    /// parameters.
1090    pub fn decode(
1091        contract_key: impl Into<String>,
1092        parameters: Parameters,
1093    ) -> Result<Self, bs58::decode::Error> {
1094        let mut contract = [0; CONTRACT_KEY_SIZE];
1095        bs58::decode(contract_key.into())
1096            .with_alphabet(bs58::Alphabet::BITCOIN)
1097            .into(&mut contract)?;
1098
1099        let mut hasher = Blake2s256::new();
1100        hasher.update(contract);
1101        hasher.update(parameters.as_ref());
1102        let full_key_arr = hasher.finalize();
1103
1104        let mut spec = [0; CONTRACT_KEY_SIZE];
1105        spec.copy_from_slice(&full_key_arr);
1106        Ok(Self {
1107            instance: ContractInstanceId(spec),
1108            code: Some(contract),
1109        })
1110    }
1111
1112    /// Returns the `Base58` encoded string of the [`ContractInstanceId`](ContractInstanceId).
1113    pub fn encoded_contract_id(&self) -> String {
1114        self.instance.encode()
1115    }
1116}
1117
1118impl Deref for ContractKey {
1119    type Target = [u8];
1120
1121    fn deref(&self) -> &Self::Target {
1122        &self.instance.0
1123    }
1124}
1125
1126impl std::fmt::Display for ContractKey {
1127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1128        self.instance.fmt(f)
1129    }
1130}
1131
1132impl TryFromTsStd<&rmpv::Value> for ContractKey {
1133    fn try_decode(value: &rmpv::Value) -> Result<Self, WsApiError> {
1134        let key_map: HashMap<&str, &rmpv::Value> = match value.as_map() {
1135            Some(map_value) => HashMap::from_iter(
1136                map_value
1137                    .iter()
1138                    .map(|(key, val)| (key.as_str().unwrap(), val)),
1139            ),
1140            _ => {
1141                return Err(WsApiError::MsgpackDecodeError {
1142                    cause: "Failed decoding ContractKey, input value is not a map".to_string(),
1143                })
1144            }
1145        };
1146
1147        let instance_id = match key_map.get("instance") {
1148            Some(instance_value) => bs58::encode(&instance_value.as_slice().unwrap()).into_string(),
1149            _ => {
1150                return Err(WsApiError::MsgpackDecodeError {
1151                    cause: "Failed decoding WrappedContract, instance not found".to_string(),
1152                })
1153            }
1154        };
1155
1156        Ok(ContractKey::from_id(instance_id).unwrap())
1157    }
1158}
1159
1160fn generate_id<'a>(
1161    parameters: &Parameters<'a>,
1162    code_data: &ContractCode<'a>,
1163) -> ContractInstanceId {
1164    let contract_hash = code_data.hash();
1165
1166    let mut hasher = Blake2s256::new();
1167    hasher.update(contract_hash);
1168    hasher.update(parameters.as_ref());
1169    let full_key_arr = hasher.finalize();
1170
1171    debug_assert_eq!(full_key_arr[..].len(), CONTRACT_KEY_SIZE);
1172    let mut spec = [0; CONTRACT_KEY_SIZE];
1173    spec.copy_from_slice(&full_key_arr);
1174    ContractInstanceId(spec)
1175}
1176
1177#[inline]
1178fn internal_fmt_key(
1179    key: &[u8; CONTRACT_KEY_SIZE],
1180    f: &mut std::fmt::Formatter<'_>,
1181) -> std::fmt::Result {
1182    let r = bs58::encode(key)
1183        .with_alphabet(bs58::Alphabet::BITCOIN)
1184        .into_string();
1185    write!(f, "{}", &r[..8])
1186}
1187
1188/// The state for a contract.
1189#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
1190#[cfg_attr(feature = "testing", derive(arbitrary::Arbitrary))]
1191pub struct WrappedState(
1192    #[serde(
1193        serialize_with = "WrappedState::ser_state",
1194        deserialize_with = "WrappedState::deser_state"
1195    )]
1196    Arc<Vec<u8>>,
1197);
1198
1199impl WrappedState {
1200    pub fn new(bytes: Vec<u8>) -> Self {
1201        WrappedState(Arc::new(bytes))
1202    }
1203
1204    pub fn size(&self) -> usize {
1205        self.0.len()
1206    }
1207
1208    fn ser_state<S>(data: &Arc<Vec<u8>>, ser: S) -> Result<S::Ok, S::Error>
1209    where
1210        S: Serializer,
1211    {
1212        serde_bytes::serialize(&**data, ser)
1213    }
1214
1215    fn deser_state<'de, D>(deser: D) -> Result<Arc<Vec<u8>>, D::Error>
1216    where
1217        D: Deserializer<'de>,
1218    {
1219        let data: Vec<u8> = serde_bytes::deserialize(deser)?;
1220        Ok(Arc::new(data))
1221    }
1222}
1223
1224impl From<Vec<u8>> for WrappedState {
1225    fn from(bytes: Vec<u8>) -> Self {
1226        Self::new(bytes)
1227    }
1228}
1229
1230impl TryFromTsStd<&rmpv::Value> for WrappedState {
1231    fn try_decode(value: &rmpv::Value) -> Result<Self, WsApiError> {
1232        let state = value.as_slice().unwrap().to_vec();
1233        Ok(WrappedState::from(state))
1234    }
1235}
1236
1237impl AsRef<[u8]> for WrappedState {
1238    fn as_ref(&self) -> &[u8] {
1239        self.0.as_ref()
1240    }
1241}
1242
1243impl Deref for WrappedState {
1244    type Target = [u8];
1245
1246    fn deref(&self) -> &Self::Target {
1247        &self.0
1248    }
1249}
1250
1251impl Borrow<[u8]> for WrappedState {
1252    fn borrow(&self) -> &[u8] {
1253        &self.0
1254    }
1255}
1256
1257impl std::fmt::Display for WrappedState {
1258    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1259        let data: String = if self.0.len() > 8 {
1260            let last_4 = self.0.len() - 4;
1261            self.0[..4]
1262                .iter()
1263                .map(|b| char::from(*b))
1264                .chain("...".chars())
1265                .chain(self.0[last_4..].iter().map(|b| char::from(*b)))
1266                .collect()
1267        } else {
1268            self.0.iter().copied().map(char::from).collect()
1269        };
1270        write!(f, "ContractState(data: [{data}])")
1271    }
1272}
1273
1274/// Just as `locutus_stdlib::Contract` but with some convenience impl.
1275#[non_exhaustive]
1276#[derive(Clone, Debug, Serialize, Deserialize)]
1277pub struct WrappedContract {
1278    #[serde(
1279        serialize_with = "WrappedContract::ser_contract_data",
1280        deserialize_with = "WrappedContract::deser_contract_data"
1281    )]
1282    pub data: Arc<ContractCode<'static>>,
1283    #[serde(
1284        serialize_with = "WrappedContract::ser_params",
1285        deserialize_with = "WrappedContract::deser_params"
1286    )]
1287    pub params: Parameters<'static>,
1288    pub key: ContractKey,
1289}
1290
1291impl PartialEq for WrappedContract {
1292    fn eq(&self, other: &Self) -> bool {
1293        self.key == other.key
1294    }
1295}
1296
1297impl Eq for WrappedContract {}
1298
1299impl WrappedContract {
1300    pub fn new(data: Arc<ContractCode<'static>>, params: Parameters<'static>) -> WrappedContract {
1301        let key = ContractKey::from((&params, &*data));
1302        WrappedContract { data, params, key }
1303    }
1304
1305    #[inline]
1306    pub fn key(&self) -> &ContractKey {
1307        &self.key
1308    }
1309
1310    #[inline]
1311    pub fn code(&self) -> &Arc<ContractCode<'static>> {
1312        &self.data
1313    }
1314
1315    #[inline]
1316    pub fn params(&self) -> &Parameters<'static> {
1317        &self.params
1318    }
1319
1320    pub fn get_data_from_fs(path: &Path) -> Result<ContractCode<'static>, std::io::Error> {
1321        let mut contract_file = File::open(path)?;
1322        let mut contract_data = if let Ok(md) = contract_file.metadata() {
1323            Vec::with_capacity(md.len() as usize)
1324        } else {
1325            Vec::new()
1326        };
1327        contract_file.read_to_end(&mut contract_data)?;
1328        Ok(ContractCode::from(contract_data))
1329    }
1330
1331    fn ser_contract_data<S>(data: &Arc<ContractCode<'_>>, ser: S) -> Result<S::Ok, S::Error>
1332    where
1333        S: Serializer,
1334    {
1335        data.serialize(ser)
1336    }
1337
1338    fn deser_contract_data<'de, D>(_deser: D) -> Result<Arc<ContractCode<'static>>, D::Error>
1339    where
1340        D: Deserializer<'de>,
1341    {
1342        // let data: ContractCode<'de> = Deserialize::deserialize(deser)?;
1343        // Ok(Arc::new(data))
1344        todo!()
1345    }
1346
1347    fn ser_params<S>(data: &Parameters<'_>, ser: S) -> Result<S::Ok, S::Error>
1348    where
1349        S: Serializer,
1350    {
1351        data.serialize(ser)
1352    }
1353
1354    fn deser_params<'de, D>(_deser: D) -> Result<Parameters<'static>, D::Error>
1355    where
1356        D: Deserializer<'de>,
1357    {
1358        // let data: ContractCode<'de> = Deserialize::deserialize(deser)?;
1359        // Ok(Arc::new(data))
1360        todo!()
1361    }
1362}
1363
1364impl<'a> TryFrom<(&'a Path, Parameters<'static>)> for WrappedContract {
1365    type Error = std::io::Error;
1366    fn try_from(data: (&'a Path, Parameters<'static>)) -> Result<Self, Self::Error> {
1367        let (path, params) = data;
1368        let data = Arc::new(Self::get_data_from_fs(path)?);
1369        Ok(WrappedContract::new(data, params))
1370    }
1371}
1372
1373impl TryFromTsStd<&rmpv::Value> for WrappedContract {
1374    fn try_decode(value: &rmpv::Value) -> Result<Self, WsApiError> {
1375        let contract_map: HashMap<&str, &rmpv::Value> = match value.as_map() {
1376            Some(map_value) => HashMap::from_iter(
1377                map_value
1378                    .iter()
1379                    .map(|(key, val)| (key.as_str().unwrap(), val)),
1380            ),
1381            _ => {
1382                return Err(WsApiError::MsgpackDecodeError {
1383                    cause: "Failed decoding WrappedContract, input value is not a map".to_string(),
1384                })
1385            }
1386        };
1387
1388        let key = match contract_map.get("key") {
1389            Some(key_value) => ContractKey::try_decode(*key_value).unwrap(),
1390            _ => {
1391                return Err(WsApiError::MsgpackDecodeError {
1392                    cause: "Failed decoding WrappedContract, key not found".to_string(),
1393                })
1394            }
1395        };
1396
1397        let data = match contract_map.get("data") {
1398            Some(contract_data_value) => Arc::new(
1399                ContractCode::try_decode(*contract_data_value)
1400                    .unwrap()
1401                    .into_owned(),
1402            ),
1403            _ => {
1404                return Err(WsApiError::MsgpackDecodeError {
1405                    cause: "Failed decoding WrappedContract, data not found".to_string(),
1406                })
1407            }
1408        };
1409
1410        let params = match contract_map.get("parameters") {
1411            Some(params_value) => Parameters::try_decode(*params_value).unwrap().into_owned(),
1412            _ => {
1413                return Err(WsApiError::MsgpackDecodeError {
1414                    cause: "Failed decoding WrappedContract, parameters not found".to_string(),
1415                })
1416            }
1417        };
1418
1419        Ok(Self { data, params, key })
1420    }
1421}
1422
1423impl TryInto<Vec<u8>> for WrappedContract {
1424    type Error = ();
1425    fn try_into(self) -> Result<Vec<u8>, Self::Error> {
1426        Arc::try_unwrap(self.data)
1427            .map(|r| r.into_bytes())
1428            .map_err(|_| ())
1429    }
1430}
1431
1432impl Display for WrappedContract {
1433    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1434        write!(f, "Contract(")?;
1435        self.key.fmt(f)?;
1436        write!(f, ")")
1437    }
1438}
1439
1440#[cfg(feature = "testing")]
1441impl<'a> arbitrary::Arbitrary<'a> for WrappedContract {
1442    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1443        use arbitrary::Arbitrary;
1444        let data: ContractCode = Arbitrary::arbitrary(u)?;
1445        let param_bytes: Vec<u8> = Arbitrary::arbitrary(u)?;
1446        let params = Parameters::from(param_bytes);
1447        let key = ContractKey::from((&params, &data));
1448        Ok(Self {
1449            data: Arc::new(data),
1450            params,
1451            key,
1452        })
1453    }
1454}
1455
1456#[doc(hidden)]
1457pub(crate) mod wasm_interface {
1458    //! Contains all the types to interface between the host environment and
1459    //! the wasm module execution.
1460    use super::*;
1461    use crate::WasmLinearMem;
1462
1463    #[repr(i32)]
1464    enum ResultKind {
1465        ValidateState = 0,
1466        ValidateDelta = 1,
1467        UpdateState = 2,
1468        SummarizeState = 3,
1469        StateDelta = 4,
1470    }
1471
1472    impl From<i32> for ResultKind {
1473        fn from(v: i32) -> Self {
1474            match v {
1475                0 => ResultKind::ValidateState,
1476                1 => ResultKind::ValidateDelta,
1477                2 => ResultKind::UpdateState,
1478                3 => ResultKind::SummarizeState,
1479                4 => ResultKind::StateDelta,
1480                _ => panic!(),
1481            }
1482        }
1483    }
1484
1485    #[doc(hidden)]
1486    #[repr(C)]
1487    #[derive(Debug, Clone, Copy)]
1488    pub struct ContractInterfaceResult {
1489        ptr: i64,
1490        kind: i32,
1491        size: u32,
1492    }
1493
1494    impl ContractInterfaceResult {
1495        pub unsafe fn unwrap_validate_state_res(
1496            self,
1497            mem: WasmLinearMem,
1498        ) -> Result<ValidateResult, ContractError> {
1499            #![allow(clippy::let_and_return)]
1500            let kind = ResultKind::from(self.kind);
1501            match kind {
1502                ResultKind::ValidateState => {
1503                    let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1504                    let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1505                    let value = bincode::deserialize(serialized)
1506                        .map_err(|e| ContractError::Other(format!("{e}")))?;
1507                    #[cfg(feature = "trace")]
1508                    self.log_input(serialized, &value, ptr);
1509                    value
1510                }
1511                _ => unreachable!(),
1512            }
1513        }
1514
1515        pub unsafe fn unwrap_validate_delta_res(
1516            self,
1517            mem: WasmLinearMem,
1518        ) -> Result<bool, ContractError> {
1519            #![allow(clippy::let_and_return)]
1520            let kind = ResultKind::from(self.kind);
1521            match kind {
1522                ResultKind::ValidateDelta => {
1523                    let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1524                    let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1525                    let value = bincode::deserialize(serialized)
1526                        .map_err(|e| ContractError::Other(format!("{e}")))?;
1527                    #[cfg(feature = "trace")]
1528                    self.log_input(serialized, &value, ptr);
1529                    value
1530                }
1531                _ => unreachable!(),
1532            }
1533        }
1534
1535        pub unsafe fn unwrap_update_state(
1536            self,
1537            mem: WasmLinearMem,
1538        ) -> Result<UpdateModification<'static>, ContractError> {
1539            let kind = ResultKind::from(self.kind);
1540            match kind {
1541                ResultKind::UpdateState => {
1542                    let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1543                    let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1544                    let value: Result<UpdateModification<'_>, ContractError> =
1545                        bincode::deserialize(serialized)
1546                            .map_err(|e| ContractError::Other(format!("{e}")))?;
1547                    #[cfg(feature = "trace")]
1548                    self.log_input(serialized, &value, ptr);
1549                    // TODO: it may be possible to not own this value while deserializing
1550                    //       under certain circumstances (e.g. when the cotnract mem is kept alive)
1551                    value.map(|r| r.into_owned())
1552                }
1553                _ => unreachable!(),
1554            }
1555        }
1556
1557        pub unsafe fn unwrap_summarize_state(
1558            self,
1559            mem: WasmLinearMem,
1560        ) -> Result<StateSummary<'static>, ContractError> {
1561            let kind = ResultKind::from(self.kind);
1562            match kind {
1563                ResultKind::SummarizeState => {
1564                    let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1565                    let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1566                    let value: Result<StateSummary<'static>, ContractError> =
1567                        bincode::deserialize(serialized)
1568                            .map_err(|e| ContractError::Other(format!("{e}")))?;
1569                    #[cfg(feature = "trace")]
1570                    self.log_input(serialized, &value, ptr);
1571                    // TODO: it may be possible to not own this value while deserializing
1572                    //       under certain circumstances (e.g. when the contract mem is kept alive)
1573                    value.map(|s| StateSummary::from(s.into_bytes()))
1574                }
1575                _ => unreachable!(),
1576            }
1577        }
1578
1579        pub unsafe fn unwrap_get_state_delta(
1580            self,
1581            mem: WasmLinearMem,
1582        ) -> Result<StateDelta<'static>, ContractError> {
1583            let kind = ResultKind::from(self.kind);
1584            match kind {
1585                ResultKind::StateDelta => {
1586                    let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1587                    let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1588                    let value: Result<StateDelta<'static>, ContractError> =
1589                        bincode::deserialize(serialized)
1590                            .map_err(|e| ContractError::Other(format!("{e}")))?;
1591                    #[cfg(feature = "trace")]
1592                    self.log_input(serialized, &value, ptr);
1593                    // TODO: it may be possible to not own this value while deserializing
1594                    //       under certain circumstances (e.g. when the contract mem is kept alive)
1595                    value.map(|d| StateDelta::from(d.into_bytes()))
1596                }
1597                _ => unreachable!(),
1598            }
1599        }
1600
1601        pub fn into_raw(self) -> i64 {
1602            #[cfg(feature = "trace")]
1603            {
1604                tracing::trace!("returning FFI -> {self:?}");
1605            }
1606            let ptr = Box::into_raw(Box::new(self));
1607            #[cfg(feature = "trace")]
1608            {
1609                tracing::trace!("FFI result ptr: {ptr:p} ({}i64)", ptr as i64);
1610            }
1611            ptr as _
1612        }
1613
1614        pub unsafe fn from_raw(ptr: i64, mem: &WasmLinearMem) -> Self {
1615            let result = Box::leak(Box::from_raw(crate::buf::compute_ptr(
1616                ptr as *mut Self,
1617                mem,
1618            )));
1619            #[cfg(feature = "trace")]
1620            {
1621                tracing::trace!(
1622                    "got FFI result @ {ptr} ({:p}) -> {result:?}",
1623                    ptr as *mut Self
1624                );
1625            }
1626            *result
1627        }
1628
1629        #[cfg(feature = "trace")]
1630        fn log_input<T: std::fmt::Debug>(&self, serialized: &[u8], value: &T, ptr: *mut u8) {
1631            tracing::trace!(
1632                "got result through FFI; addr: {:p} ({}i64, mapped: {ptr:p})
1633                 serialized: {serialized:?}
1634                 value: {value:?}",
1635                self.ptr as *mut u8,
1636                self.ptr
1637            );
1638        }
1639    }
1640
1641    macro_rules! conversion {
1642        ($value:ty: $kind:expr) => {
1643            impl From<$value> for ContractInterfaceResult {
1644                fn from(value: $value) -> Self {
1645                    let kind = $kind as i32;
1646                    // TODO: research if there is a safe way to just transmute the pointer in memory
1647                    //       independently of the architecture when stored in WASM and accessed from
1648                    //       the host, maybe even if is just for some architectures
1649                    let serialized = bincode::serialize(&value).unwrap();
1650                    let size = serialized.len() as _;
1651                    let ptr = serialized.as_ptr();
1652                    #[cfg(feature = "trace")] {
1653                        tracing::trace!(
1654                            "sending result through FFI; addr: {ptr:p} ({}),\n  serialized: {serialized:?}\n  value: {value:?}",
1655                            ptr as i64
1656                        );
1657                    }
1658                    std::mem::forget(serialized);
1659                    Self { kind, ptr: ptr as i64, size }
1660                }
1661            }
1662        };
1663    }
1664
1665    conversion!(Result<ValidateResult, ContractError>: ResultKind::ValidateState);
1666    conversion!(Result<bool, ContractError>: ResultKind::ValidateDelta);
1667    conversion!(Result<UpdateModification<'static>, ContractError>: ResultKind::UpdateState);
1668    conversion!(Result<StateSummary<'static>, ContractError>: ResultKind::SummarizeState);
1669    conversion!(Result<StateDelta<'static>, ContractError>: ResultKind::StateDelta);
1670}
1671
1672#[cfg(all(test, target_family = "unix"))]
1673mod test {
1674    use super::*;
1675    use once_cell::sync::Lazy;
1676    use rand::{rngs::SmallRng, Rng, SeedableRng};
1677
1678    static RND_BYTES: Lazy<[u8; 1024]> = Lazy::new(|| {
1679        let mut bytes = [0; 1024];
1680        let mut rng = SmallRng::from_entropy();
1681        rng.fill(&mut bytes);
1682        bytes
1683    });
1684
1685    #[test]
1686    fn key_encoding() -> Result<(), Box<dyn std::error::Error>> {
1687        let code = ContractCode::from(vec![1, 2, 3]);
1688        let expected = ContractKey::from((Parameters::from(vec![]), &code));
1689        // let encoded_key = expected.encode();
1690        // println!("encoded key: {encoded_key}");
1691        // let encoded_code = expected.contract_part_as_str();
1692        // println!("encoded key: {encoded_code}");
1693
1694        let decoded = ContractKey::decode(code.hash_str(), [].as_ref().into())?;
1695        assert_eq!(expected, decoded);
1696        assert_eq!(expected.code_hash(), decoded.code_hash());
1697        Ok(())
1698    }
1699
1700    #[test]
1701    fn key_ser() -> Result<(), Box<dyn std::error::Error>> {
1702        let mut gen = arbitrary::Unstructured::new(&*RND_BYTES);
1703        let expected: ContractKey = gen.arbitrary()?;
1704        let encoded = bs58::encode(expected.bytes()).into_string();
1705        // println!("encoded key: {encoded}");
1706
1707        let serialized = bincode::serialize(&expected)?;
1708        let deserialized: ContractKey = bincode::deserialize(&serialized)?;
1709        let decoded = bs58::encode(deserialized.bytes()).into_string();
1710        assert_eq!(encoded, decoded);
1711        assert_eq!(deserialized, expected);
1712        Ok(())
1713    }
1714
1715    #[test]
1716    fn contract_ser() -> Result<(), Box<dyn std::error::Error>> {
1717        let mut gen = arbitrary::Unstructured::new(&*RND_BYTES);
1718        let expected: Contract = gen.arbitrary()?;
1719
1720        let serialized = bincode::serialize(&expected)?;
1721        let deserialized: Contract = bincode::deserialize(&serialized)?;
1722        assert_eq!(deserialized, expected);
1723        Ok(())
1724    }
1725}