trn_pact/types/
contract.rs

1// Copyright 2019 Centrality Investments Limited
2// This file is part of Pact.
3//
4// Licensed under the Apache License v2.0;
5// you may not use this file except in compliance with the License.
6// Unless required by applicable law or agreed to in writing, software
7// distributed under the License is distributed on an "AS IS" BASIS,
8// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9// See the License for the specific language governing permissions and
10// limitations under the License.
11
12// You should have received a copy of the Apache License v2.0
13// along with Pact. If not, see:
14//   <https://futureverse.com/licenses/apachev2.txt>
15
16//!
17//! Contract struct
18//!
19use crate::types::DataTable;
20use alloc::vec::Vec;
21use bit_reverse::ParallelReverse;
22
23#[cfg_attr(feature = "std", derive(Debug, PartialEq))]
24/// A binary format error
25pub enum BinaryFormatErr {
26    /// Version mismatch
27    UnsupportedVersion,
28    /// DataTable is invalid
29    MalformedDataTable(&'static str),
30    // The buffer is to short to be valid
31    TooShort,
32}
33
34/// A pact contract
35/// It has byte code and an accompanying data section
36#[cfg_attr(feature = "std", derive(Debug, PartialEq))]
37pub struct Contract {
38    pub data_table: DataTable,
39    pub bytecode: Vec<u8>,
40}
41
42impl Contract {
43    /// Encode the contract as v0 binary format into `buf`
44    pub fn encode(&self, buf: &mut Vec<u8>) {
45        buf.push(0); // binary format version: `0`
46        self.data_table.encode(buf);
47        buf.extend(self.bytecode.clone());
48    }
49    /// Decode a pact contract from v0 binary format
50    pub fn decode(buf: &Vec<u8>) -> Result<Self, BinaryFormatErr> {
51        if buf.len() < 2 {
52            return Err(BinaryFormatErr::TooShort);
53        }
54        if buf[0].swap_bits() != 0 {
55            return Err(BinaryFormatErr::UnsupportedVersion);
56        }
57        let (data_table, offset) = DataTable::decode(buf[1..].to_vec())
58            .map_err(|err| BinaryFormatErr::MalformedDataTable(err))?;
59        let bytecode = buf[1usize + offset..].to_vec();
60        Ok(Self {
61            data_table,
62            bytecode,
63        })
64    }
65}
66
67#[cfg(test)]
68mod test {
69    use super::*;
70    use crate::interpreter::{Comparator, Conjunction, OpCode, OpComp, OpConj, OpLoad};
71    use crate::types::{Numeric, PactType, StringLike};
72
73    #[test]
74    fn contract_binary_format_unsupported_version() {
75        assert_eq!(
76            Contract::decode([1, 0].to_vec().as_ref()),
77            Err(BinaryFormatErr::UnsupportedVersion)
78        );
79    }
80
81    #[test]
82    fn contract_binary_format_too_short() {
83        assert_eq!(
84            Contract::decode([0].to_vec().as_ref()),
85            Err(BinaryFormatErr::TooShort)
86        );
87    }
88
89    #[test]
90    fn contract_encode_1() {
91        let contract = Contract {
92            data_table: DataTable::new(vec![
93                PactType::Numeric(Numeric(10)),
94                PactType::Numeric(Numeric(20)),
95            ]),
96            bytecode: vec![OpCode::COMP(Comparator::new(OpComp::EQ)).into(), 0x00],
97        };
98        let mut encoded_payload = vec![];
99        contract.encode(&mut encoded_payload);
100        println!("{:?}", encoded_payload);
101    }
102
103    #[test]
104    fn contract_encode_2() {
105        let contract = Contract {
106            data_table: DataTable::new(vec![
107                PactType::Numeric(Numeric(10)),
108                PactType::StringLike(StringLike(b"hello, world".to_vec())),
109            ]),
110            bytecode: vec![
111                OpCode::COMP(Comparator::new(OpComp::EQ)).into(),
112                0x00,
113                OpCode::COMP(Comparator::new(OpComp::EQ)).into(),
114                0x11,
115            ],
116        };
117        let mut encoded_payload = vec![];
118        contract.encode(&mut encoded_payload);
119        println!("{:?}", encoded_payload);
120    }
121
122    #[test]
123    fn contract_encode_3() {
124        let contract = Contract {
125            data_table: DataTable::new(vec![
126                PactType::Numeric(Numeric(10)),
127                PactType::StringLike(StringLike(b"hello, world".to_vec())),
128            ]),
129            bytecode: vec![
130                OpCode::COMP(Comparator::new(OpComp::EQ).invert()).into(),
131                0x00,
132                OpCode::COMP(Comparator::new(OpComp::EQ).load(OpLoad::INPUT_VS_INPUT)).into(),
133                0x11,
134            ],
135        };
136        let mut encoded_payload = vec![];
137        contract.encode(&mut encoded_payload);
138        println!("{:?}", encoded_payload);
139    }
140
141    #[test]
142    fn contract_encode_4() {
143        let contract = Contract {
144            data_table: DataTable::new(vec![
145                PactType::Numeric(Numeric(10)),
146                PactType::Numeric(Numeric(20)),
147            ]),
148            bytecode: vec![
149                OpCode::COMP(Comparator::new(OpComp::EQ)).into(),
150                0x00,
151                OpCode::CONJ(Conjunction::new(OpConj::AND)).into(),
152            ],
153        };
154        let mut encoded_payload = vec![];
155        contract.encode(&mut encoded_payload);
156        println!("{:?}", encoded_payload);
157    }
158}