contract_transcode/
env_types.rs

1// Copyright (C) Use Ink (UK) Ltd.
2// This file is part of cargo-contract.
3//
4// cargo-contract is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// cargo-contract is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with cargo-contract.  If not, see <http://www.gnu.org/licenses/>.
16
17use crate::{
18    assert_not_shortened_hex,
19    AccountId32,
20    Hex,
21    Value,
22};
23use anyhow::{
24    Context,
25    Result,
26};
27use primitive_types::U128;
28use scale::{
29    Decode,
30    Encode,
31    Output,
32};
33use scale_info::{
34    form::PortableForm,
35    IntoPortable,
36    Path,
37    TypeInfo,
38};
39use std::{
40    boxed::Box,
41    collections::HashMap,
42    convert::TryFrom,
43    str::FromStr,
44};
45
46/// Provides custom encoding and decoding for predefined environment types.
47#[derive(Default)]
48pub struct EnvTypesTranscoder {
49    encoders: HashMap<u32, Box<dyn CustomTypeEncoder>>,
50    decoders: HashMap<u32, Box<dyn CustomTypeDecoder>>,
51}
52
53impl EnvTypesTranscoder {
54    /// Construct an `EnvTypesTranscoder` from the given type registry.
55    pub fn new(
56        encoders: HashMap<u32, Box<dyn CustomTypeEncoder>>,
57        decoders: HashMap<u32, Box<dyn CustomTypeDecoder>>,
58    ) -> Self {
59        Self { encoders, decoders }
60    }
61
62    /// If the given type id is for a type with custom encoding, encodes the given value
63    /// with the custom encoder and returns `true`. Otherwise returns `false`.
64    ///
65    /// # Errors
66    ///
67    /// - If the custom encoding fails.
68    pub fn try_encode<O>(
69        &self,
70        type_id: u32,
71        value: &Value,
72        output: &mut O,
73    ) -> Result<bool>
74    where
75        O: Output,
76    {
77        match self.encoders.get(&type_id) {
78            Some(encoder) => {
79                tracing::debug!("Encoding type {:?} with custom encoder", type_id);
80                let encoded_env_type = encoder
81                    .encode_value(value)
82                    .context("Error encoding custom type")?;
83                output.write(&encoded_env_type);
84                Ok(true)
85            }
86            None => Ok(false),
87        }
88    }
89
90    /// If the given type lookup id is for an environment type with custom
91    /// decoding, decodes the given input with the custom decoder and returns
92    /// `Some(value)`. Otherwise returns `None`.
93    ///
94    /// # Errors
95    ///
96    /// - If the custom decoding fails.
97    pub fn try_decode(&self, type_id: u32, input: &mut &[u8]) -> Result<Option<Value>> {
98        match self.decoders.get(&type_id) {
99            Some(decoder) => {
100                tracing::debug!("Decoding type {:?} with custom decoder", type_id);
101                let decoded = decoder.decode_value(input)?;
102                Ok(Some(decoded))
103            }
104            None => {
105                tracing::debug!("No custom decoder found for type {:?}", type_id);
106                Ok(None)
107            }
108        }
109    }
110}
111
112#[derive(Clone, Debug, Eq, PartialEq, Hash)]
113pub struct PathKey(Vec<String>);
114
115impl PathKey {
116    pub fn from_type<T>() -> Self
117    where
118        T: TypeInfo,
119    {
120        let type_info = T::type_info();
121        let path = type_info.path.into_portable(&mut Default::default());
122        PathKey::from(&path)
123    }
124}
125
126impl From<&Path<PortableForm>> for PathKey {
127    fn from(path: &Path<PortableForm>) -> Self {
128        PathKey(path.segments.to_vec())
129    }
130}
131
132pub type TypesByPath = HashMap<PathKey, u32>;
133
134/// Implement this trait to define custom encoding for a type in a `scale-info` type
135/// registry.
136pub trait CustomTypeEncoder: Send + Sync {
137    fn encode_value(&self, value: &Value) -> Result<Vec<u8>>;
138}
139
140/// Implement this trait to define custom decoding for a type in a `scale-info` type
141/// registry.
142pub trait CustomTypeDecoder: Send + Sync {
143    fn decode_value(&self, input: &mut &[u8]) -> Result<Value>;
144}
145
146/// Custom encoding/decoding for the Substrate `AccountId` type.
147///
148/// Enables an `AccountId` to be input/output as an SS58 Encoded literal e.g.
149/// `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY`.
150#[derive(Clone)]
151pub struct AccountId;
152
153impl CustomTypeEncoder for AccountId {
154    fn encode_value(&self, value: &Value) -> Result<Vec<u8>> {
155        let account_id = match value {
156            Value::Literal(literal) => {
157                AccountId32::from_str(literal).map_err(|e| {
158                    anyhow::anyhow!(
159                        "Error parsing AccountId from literal `{}`: {}",
160                        literal,
161                        e
162                    )
163                })?
164            }
165            Value::String(string) => {
166                AccountId32::from_str(string).map_err(|e| {
167                    anyhow::anyhow!(
168                        "Error parsing AccountId from string '{}': {}",
169                        string,
170                        e
171                    )
172                })?
173            }
174            Value::Hex(hex) => {
175                AccountId32::try_from(hex.bytes()).map_err(|_| {
176                    anyhow::anyhow!(
177                        "Error converting hex bytes `{:?}` to AccountId",
178                        hex.bytes()
179                    )
180                })?
181            }
182            _ => {
183                return Err(anyhow::anyhow!(
184                    "Expected a string, literal, or hex for an AccountId"
185                ))
186            }
187        };
188        Ok(account_id.encode())
189    }
190}
191
192impl CustomTypeDecoder for AccountId {
193    fn decode_value(&self, input: &mut &[u8]) -> Result<Value> {
194        let account_id = AccountId32::decode(input)?;
195        Ok(Value::Literal(account_id.to_ss58check()))
196    }
197}
198
199/// Custom decoding for the `Hash` or `[u8; 32]` type so that it is displayed as a hex
200/// encoded string.
201#[derive(Clone)]
202pub struct Hash;
203
204impl CustomTypeEncoder for Hash {
205    fn encode_value(&self, value: &Value) -> Result<Vec<u8>> {
206        // todo currently using H256 here
207        let h256 = match value {
208            Value::Literal(literal) => {
209                primitive_types::H256::from_str(literal).map_err(|e| {
210                    anyhow::anyhow!(
211                        "Error parsing H256 from literal `{}`: {}",
212                        literal,
213                        e
214                    )
215                })?
216            }
217            Value::String(string) => {
218                primitive_types::H256::from_str(string).map_err(|e| {
219                    anyhow::anyhow!("Error parsing H256 from string '{}': {}", string, e)
220                })?
221            }
222            Value::Hex(hex) => primitive_types::H256::from_slice(hex.bytes()),
223            _ => {
224                return Err(anyhow::anyhow!(
225                    "Expected a string, hex, uint, or literal for a U256"
226                ))
227            }
228        };
229        Ok(h256.encode())
230    }
231}
232
233impl CustomTypeDecoder for Hash {
234    fn decode_value(&self, input: &mut &[u8]) -> Result<Value> {
235        let hash = primitive_types::H256::decode(input)?;
236        Ok(Value::Hex(Hex::from_str(&format!("{hash:?}"))?))
237    }
238}
239
240/// Custom decoding for the `H160` or `[u8; 20]` type so that it is displayed as a hex
241/// encoded string.
242#[derive(Clone)]
243pub struct H160;
244
245impl CustomTypeDecoder for H160 {
246    fn decode_value(&self, input: &mut &[u8]) -> Result<Value> {
247        let h160 = primitive_types::H160::decode(input)?;
248        Ok(Value::Hex(Hex::from_str(&format!("{h160:?}"))?))
249    }
250}
251
252impl CustomTypeEncoder for H160 {
253    fn encode_value(&self, value: &Value) -> Result<Vec<u8>> {
254        let h160 = match value {
255            Value::Literal(literal) => {
256                primitive_types::H160::from_str(literal).map_err(|e| {
257                    anyhow::anyhow!(
258                        "Error parsing H160 from literal `{}`: {}",
259                        literal,
260                        e
261                    )
262                })?
263            }
264            Value::String(string) => {
265                assert_not_shortened_hex(string);
266                primitive_types::H160::from_str(string).map_err(|e| {
267                    anyhow::anyhow!("Error parsing H160 from string '{}': {}", string, e)
268                })?
269            }
270            Value::Hex(hex) => primitive_types::H160::from_slice(hex.bytes()),
271            _ => {
272                return Err(anyhow::anyhow!(
273                    "Expected a string, literal, or hex for an H160"
274                ))
275            }
276        };
277        Ok(h160.encode())
278    }
279}
280
281/// Custom decoding for the `U256` or `[u8; 32]` type so that it is displayed as a hex
282/// encoded string.
283#[derive(Clone)]
284pub struct U256;
285
286impl CustomTypeDecoder for U256 {
287    fn decode_value(&self, input: &mut &[u8]) -> Result<Value> {
288        let u256 = primitive_types::U256::decode(input)?;
289        Ok(Value::Literal(format!("{}", u256)))
290    }
291}
292
293impl CustomTypeEncoder for U256 {
294    fn encode_value(&self, value: &Value) -> Result<Vec<u8>> {
295        let u256 = match value {
296            Value::Literal(literal) => {
297                primitive_types::U256::from_str(literal).map_err(|e| {
298                    anyhow::anyhow!(
299                        "Error parsing U256 from literal `{}`: {}",
300                        literal,
301                        e
302                    )
303                })?
304            }
305            Value::String(string) => {
306                primitive_types::U256::from_str(string).map_err(|e| {
307                    anyhow::anyhow!("Error parsing U256 from string '{}': {}", string, e)
308                })?
309            }
310            Value::UInt(uint128) => {
311                let u_128 = U128::from(*uint128);
312                primitive_types::U256::from(u_128)
313            }
314            // todo from_slice?
315            Value::Hex(hex) => primitive_types::U256::from_little_endian(hex.bytes()),
316            _ => {
317                return Err(anyhow::anyhow!(
318                    "Expected a string, hex, uint, or literal for a U256"
319                ))
320            }
321        };
322        let ret = u256.encode();
323        Ok(ret)
324    }
325}
326
327/// Custom decoding for the `H256` or `[u8; 32]` type so that it is displayed as a hex
328/// encoded string.
329#[derive(Clone)]
330pub struct H256;
331
332impl CustomTypeDecoder for H256 {
333    fn decode_value(&self, input: &mut &[u8]) -> Result<Value> {
334        let h256 = primitive_types::H256::decode(input)?;
335        Ok(Value::Hex(Hex::from_str(&format!("{h256:?}"))?))
336    }
337}
338
339impl CustomTypeEncoder for H256 {
340    fn encode_value(&self, value: &Value) -> Result<Vec<u8>> {
341        let h256 = match value {
342            Value::Literal(literal) => {
343                primitive_types::H256::from_str(literal).map_err(|e| {
344                    anyhow::anyhow!(
345                        "Error parsing H256 from literal `{}`: {}",
346                        literal,
347                        e
348                    )
349                })?
350            }
351            Value::String(string) => {
352                primitive_types::H256::from_str(string).map_err(|e| {
353                    anyhow::anyhow!("Error parsing H256 from string '{}': {}", string, e)
354                })?
355            }
356            Value::Hex(hex) => primitive_types::H256::from_slice(hex.bytes()),
357            _ => {
358                return Err(anyhow::anyhow!(
359                    "Expected a string, hex, uint, or literal for a H256"
360                ))
361            }
362        };
363        Ok(h256.encode())
364    }
365}
366
367/*
368#[cfg(test)]
369mod tests {
370    use super::*;
371}
372*/