freenet_stdlib/contract_interface/
contract.rs

1//! Complete contract specification combining code and parameters.
2//!
3//! This module provides the `Contract` type which represents a complete
4//! contract with both executable code and runtime parameters.
5
6use std::io::{Cursor, Read};
7
8use byteorder::{LittleEndian, ReadBytesExt};
9use serde::{Deserialize, Serialize};
10
11use crate::parameters::Parameters;
12
13use super::code::ContractCode;
14use super::key::{internal_fmt_key, ContractKey};
15
16/// A complete contract specification requires a `parameters` section
17/// and a `contract` section.
18#[derive(Debug, Serialize, Deserialize, Clone)]
19#[cfg_attr(
20    any(feature = "testing", all(test, any(unix, windows))),
21    derive(arbitrary::Arbitrary)
22)]
23pub struct Contract<'a> {
24    #[serde(borrow)]
25    pub parameters: Parameters<'a>,
26    #[serde(borrow)]
27    pub data: ContractCode<'a>,
28    // todo: skip serializing and instead compute it
29    key: ContractKey,
30}
31
32impl<'a> Contract<'a> {
33    /// Returns a contract from [contract code](ContractCode) and given [parameters](Parameters).
34    pub fn new(contract: ContractCode<'a>, parameters: Parameters<'a>) -> Contract<'a> {
35        let key = ContractKey::from_params_and_code(&parameters, &contract);
36        Contract {
37            parameters,
38            data: contract,
39            key,
40        }
41    }
42
43    /// Key portion of the specification.
44    pub fn key(&self) -> &ContractKey {
45        &self.key
46    }
47
48    /// Code portion of the specification.
49    pub fn into_code(self) -> ContractCode<'a> {
50        self.data
51    }
52}
53
54impl TryFrom<Vec<u8>> for Contract<'static> {
55    type Error = std::io::Error;
56
57    fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
58        let mut reader = Cursor::new(data);
59
60        let params_len = reader.read_u64::<LittleEndian>()?;
61        let mut params_buf = vec![0; params_len as usize];
62        reader.read_exact(&mut params_buf)?;
63        let parameters = Parameters::from(params_buf);
64
65        let contract_len = reader.read_u64::<LittleEndian>()?;
66        let mut contract_buf = vec![0; contract_len as usize];
67        reader.read_exact(&mut contract_buf)?;
68        let contract = ContractCode::from(contract_buf);
69
70        let key = ContractKey::from_params_and_code(&parameters, &contract);
71
72        Ok(Contract {
73            parameters,
74            data: contract,
75            key,
76        })
77    }
78}
79
80impl PartialEq for Contract<'_> {
81    fn eq(&self, other: &Self) -> bool {
82        self.key == other.key
83    }
84}
85
86impl Eq for Contract<'_> {}
87
88impl std::fmt::Display for Contract<'_> {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        write!(f, "ContractSpec( key: ")?;
91        internal_fmt_key(&self.key, f)?;
92        let data: String = if self.data.data.len() > 8 {
93            self.data.data[..4]
94                .iter()
95                .map(|b| char::from(*b))
96                .chain("...".chars())
97                .chain(self.data.data[4..].iter().map(|b| char::from(*b)))
98                .collect()
99        } else {
100            self.data.data.iter().copied().map(char::from).collect()
101        };
102        write!(f, ", data: [{data}])")
103    }
104}