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