casper_types/
byte_code.rs

1use alloc::{format, string::String, vec::Vec};
2use core::{
3    array::TryFromSliceError,
4    convert::TryFrom,
5    fmt::{self, Debug, Display, Formatter},
6};
7
8#[cfg(feature = "datasize")]
9use datasize::DataSize;
10#[cfg(any(feature = "testing", test))]
11use rand::{
12    distributions::{Distribution, Standard},
13    Rng,
14};
15#[cfg(feature = "json-schema")]
16use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
17use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
18
19use crate::{
20    addressable_entity, bytesrepr,
21    bytesrepr::{Bytes, Error, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
22    checksummed_hex, uref, CLType, CLTyped, HashAddr,
23};
24
25const BYTE_CODE_MAX_DISPLAY_LEN: usize = 16;
26const KEY_HASH_LENGTH: usize = 32;
27const WASM_STRING_PREFIX: &str = "byte-code-";
28
29const BYTE_CODE_PREFIX: &str = "byte-code-";
30const V1_WASM_PREFIX: &str = "v1-wasm-";
31const V2_WASM_PREFIX: &str = "v2-wasm-";
32const EMPTY_PREFIX: &str = "empty-";
33
34/// Associated error type of `TryFrom<&[u8]>` for `ByteCodeHash`.
35#[derive(Debug)]
36pub struct TryFromSliceForContractHashError(());
37
38#[derive(Debug)]
39#[non_exhaustive]
40pub enum FromStrError {
41    InvalidPrefix,
42    Hex(base16::DecodeError),
43    Hash(TryFromSliceError),
44    AccountHash(addressable_entity::FromAccountHashStrError),
45    URef(uref::FromStrError),
46}
47
48impl From<base16::DecodeError> for FromStrError {
49    fn from(error: base16::DecodeError) -> Self {
50        FromStrError::Hex(error)
51    }
52}
53
54impl From<TryFromSliceError> for FromStrError {
55    fn from(error: TryFromSliceError) -> Self {
56        FromStrError::Hash(error)
57    }
58}
59
60impl From<addressable_entity::FromAccountHashStrError> for FromStrError {
61    fn from(error: addressable_entity::FromAccountHashStrError) -> Self {
62        FromStrError::AccountHash(error)
63    }
64}
65
66impl From<uref::FromStrError> for FromStrError {
67    fn from(error: uref::FromStrError) -> Self {
68        FromStrError::URef(error)
69    }
70}
71
72impl Display for FromStrError {
73    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
74        match self {
75            FromStrError::InvalidPrefix => write!(f, "invalid prefix"),
76            FromStrError::Hex(error) => write!(f, "decode from hex: {}", error),
77            FromStrError::Hash(error) => write!(f, "hash from string error: {}", error),
78            FromStrError::AccountHash(error) => {
79                write!(f, "account hash from string error: {:?}", error)
80            }
81            FromStrError::URef(error) => write!(f, "uref from string error: {:?}", error),
82        }
83    }
84}
85
86/// An address for ByteCode records stored in global state.
87#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)]
88#[cfg_attr(feature = "datasize", derive(DataSize))]
89#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
90pub enum ByteCodeAddr {
91    /// An address for byte code to be executed against the V1 Casper execution engine.
92    V1CasperWasm(HashAddr),
93    /// An address for byte code to be executed against the V2 Casper execution engine.
94    V2CasperWasm(HashAddr),
95    /// An empty byte code record
96    Empty,
97}
98
99impl ByteCodeAddr {
100    /// Constructs a new Byte code address for Wasm.
101    pub const fn new_wasm_addr(hash_addr: HashAddr) -> Self {
102        Self::V1CasperWasm(hash_addr)
103    }
104
105    /// Returns the tag of the byte code address.
106    pub fn tag(&self) -> ByteCodeKind {
107        match self {
108            Self::Empty => ByteCodeKind::Empty,
109            Self::V1CasperWasm(_) => ByteCodeKind::V1CasperWasm,
110            Self::V2CasperWasm(_) => ByteCodeKind::V2CasperWasm,
111        }
112    }
113
114    /// Formats the `ByteCodeAddr` for users getting and putting.
115    pub fn to_formatted_string(&self) -> String {
116        format!("{}", self)
117    }
118
119    /// Parses a string formatted as per `Self::to_formatted_string()` into a
120    /// `ByteCodeAddr`.
121    pub fn from_formatted_string(input: &str) -> Result<Self, FromStrError> {
122        if let Some(byte_code) = input.strip_prefix(BYTE_CODE_PREFIX) {
123            let (addr_str, tag) = if let Some(str) = byte_code.strip_prefix(EMPTY_PREFIX) {
124                (str, ByteCodeKind::Empty)
125            } else if let Some(str) = byte_code.strip_prefix(V1_WASM_PREFIX) {
126                (str, ByteCodeKind::V1CasperWasm)
127            } else if let Some(str) = byte_code.strip_prefix(V2_WASM_PREFIX) {
128                (str, ByteCodeKind::V2CasperWasm)
129            } else {
130                return Err(FromStrError::InvalidPrefix);
131            };
132            let addr = checksummed_hex::decode(addr_str).map_err(FromStrError::Hex)?;
133            let byte_code_addr = HashAddr::try_from(addr.as_ref()).map_err(FromStrError::Hash)?;
134            return match tag {
135                ByteCodeKind::V1CasperWasm => Ok(ByteCodeAddr::V1CasperWasm(byte_code_addr)),
136                ByteCodeKind::V2CasperWasm => Ok(ByteCodeAddr::V2CasperWasm(byte_code_addr)),
137                ByteCodeKind::Empty => Ok(ByteCodeAddr::Empty),
138            };
139        }
140
141        Err(FromStrError::InvalidPrefix)
142    }
143}
144
145impl ToBytes for ByteCodeAddr {
146    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
147        let mut buffer = bytesrepr::allocate_buffer(self)?;
148        self.write_bytes(&mut buffer)?;
149        Ok(buffer)
150    }
151
152    fn serialized_length(&self) -> usize {
153        U8_SERIALIZED_LENGTH
154            + match self {
155                Self::Empty => 0,
156                Self::V1CasperWasm(_) => KEY_HASH_LENGTH,
157                Self::V2CasperWasm(_) => KEY_HASH_LENGTH,
158            }
159    }
160
161    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
162        match self {
163            Self::Empty => writer.push(self.tag() as u8),
164            Self::V1CasperWasm(addr) => {
165                writer.push(self.tag() as u8);
166                writer.extend(addr.to_bytes()?);
167            }
168            Self::V2CasperWasm(addr) => {
169                writer.push(self.tag() as u8);
170                writer.extend(addr.to_bytes()?);
171            }
172        }
173        Ok(())
174    }
175}
176
177impl FromBytes for ByteCodeAddr {
178    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
179        let (tag, remainder): (ByteCodeKind, &[u8]) = FromBytes::from_bytes(bytes)?;
180        match tag {
181            ByteCodeKind::Empty => Ok((ByteCodeAddr::Empty, remainder)),
182            ByteCodeKind::V1CasperWasm => {
183                let (addr, remainder) = HashAddr::from_bytes(remainder)?;
184                Ok((ByteCodeAddr::new_wasm_addr(addr), remainder))
185            }
186            ByteCodeKind::V2CasperWasm => {
187                let (addr, remainder) = HashAddr::from_bytes(remainder)?;
188                Ok((ByteCodeAddr::V2CasperWasm(addr), remainder))
189            }
190        }
191    }
192}
193
194impl Display for ByteCodeAddr {
195    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
196        match self {
197            ByteCodeAddr::V1CasperWasm(addr) => {
198                write!(
199                    f,
200                    "{}{}{}",
201                    BYTE_CODE_PREFIX,
202                    V1_WASM_PREFIX,
203                    base16::encode_lower(&addr)
204                )
205            }
206            ByteCodeAddr::V2CasperWasm(addr) => {
207                write!(
208                    f,
209                    "{}{}{}",
210                    BYTE_CODE_PREFIX,
211                    V2_WASM_PREFIX,
212                    base16::encode_lower(&addr)
213                )
214            }
215            ByteCodeAddr::Empty => {
216                write!(
217                    f,
218                    "{}{}{}",
219                    BYTE_CODE_PREFIX,
220                    EMPTY_PREFIX,
221                    base16::encode_lower(&[0u8; 32])
222                )
223            }
224        }
225    }
226}
227
228impl Debug for ByteCodeAddr {
229    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
230        match self {
231            ByteCodeAddr::V1CasperWasm(addr) => {
232                write!(f, "ByteCodeAddr::V1CasperWasm({:?})", addr)
233            }
234            ByteCodeAddr::V2CasperWasm(addr) => {
235                write!(f, "ByteCodeAddr::V2CasperWasm({:?})", addr)
236            }
237            ByteCodeAddr::Empty => {
238                write!(f, "ByteCodeAddr::Empty")
239            }
240        }
241    }
242}
243
244#[cfg(any(feature = "testing", test))]
245impl Distribution<ByteCodeAddr> for Standard {
246    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ByteCodeAddr {
247        match rng.gen_range(0..=2) {
248            0 => ByteCodeAddr::Empty,
249            1 => ByteCodeAddr::V1CasperWasm(rng.gen()),
250            2 => ByteCodeAddr::V2CasperWasm(rng.gen()),
251            _ => unreachable!(),
252        }
253    }
254}
255
256/// A newtype wrapping a `HashAddr` which is the raw bytes of
257/// the ByteCodeHash
258#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy)]
259#[cfg_attr(feature = "datasize", derive(DataSize))]
260pub struct ByteCodeHash(HashAddr);
261
262impl ByteCodeHash {
263    /// Constructs a new `ByteCodeHash` from the raw bytes of the contract wasm hash.
264    pub const fn new(value: HashAddr) -> ByteCodeHash {
265        ByteCodeHash(value)
266    }
267
268    /// Returns the raw bytes of the contract hash as an array.
269    pub fn value(&self) -> HashAddr {
270        self.0
271    }
272
273    /// Returns the raw bytes of the contract hash as a `slice`.
274    pub fn as_bytes(&self) -> &[u8] {
275        &self.0
276    }
277
278    /// Formats the `ByteCodeHash` for users getting and putting.
279    pub fn to_formatted_string(self) -> String {
280        format!("{}{}", WASM_STRING_PREFIX, base16::encode_lower(&self.0),)
281    }
282
283    /// Parses a string formatted as per `Self::to_formatted_string()` into a
284    /// `ByteCodeHash`.
285    pub fn from_formatted_str(input: &str) -> Result<Self, FromStrError> {
286        let remainder = input
287            .strip_prefix(WASM_STRING_PREFIX)
288            .ok_or(FromStrError::InvalidPrefix)?;
289        let bytes = HashAddr::try_from(checksummed_hex::decode(remainder)?.as_ref())?;
290        Ok(ByteCodeHash(bytes))
291    }
292}
293
294impl Default for ByteCodeHash {
295    fn default() -> Self {
296        Self::new([0u8; KEY_HASH_LENGTH])
297    }
298}
299
300impl Display for ByteCodeHash {
301    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
302        write!(f, "{}", base16::encode_lower(&self.0))
303    }
304}
305
306impl Debug for ByteCodeHash {
307    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
308        write!(f, "ByteCodeHash({})", base16::encode_lower(&self.0))
309    }
310}
311
312impl CLTyped for ByteCodeHash {
313    fn cl_type() -> CLType {
314        CLType::ByteArray(KEY_HASH_LENGTH as u32)
315    }
316}
317
318impl ToBytes for ByteCodeHash {
319    #[inline(always)]
320    fn to_bytes(&self) -> Result<Vec<u8>, Error> {
321        self.0.to_bytes()
322    }
323
324    #[inline(always)]
325    fn serialized_length(&self) -> usize {
326        self.0.serialized_length()
327    }
328
329    #[inline(always)]
330    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
331        self.0.write_bytes(writer)
332    }
333}
334
335impl FromBytes for ByteCodeHash {
336    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
337        let (bytes, rem) = FromBytes::from_bytes(bytes)?;
338        Ok((ByteCodeHash::new(bytes), rem))
339    }
340}
341
342impl From<[u8; KEY_HASH_LENGTH]> for ByteCodeHash {
343    fn from(bytes: [u8; KEY_HASH_LENGTH]) -> Self {
344        ByteCodeHash(bytes)
345    }
346}
347
348impl Serialize for ByteCodeHash {
349    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
350        if serializer.is_human_readable() {
351            self.to_formatted_string().serialize(serializer)
352        } else {
353            self.0.serialize(serializer)
354        }
355    }
356}
357
358impl<'de> Deserialize<'de> for ByteCodeHash {
359    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
360        if deserializer.is_human_readable() {
361            let formatted_string = String::deserialize(deserializer)?;
362            ByteCodeHash::from_formatted_str(&formatted_string).map_err(SerdeError::custom)
363        } else {
364            let bytes = HashAddr::deserialize(deserializer)?;
365            Ok(ByteCodeHash(bytes))
366        }
367    }
368}
369
370impl AsRef<[u8]> for ByteCodeHash {
371    fn as_ref(&self) -> &[u8] {
372        self.0.as_ref()
373    }
374}
375
376impl TryFrom<&[u8]> for ByteCodeHash {
377    type Error = TryFromSliceForContractHashError;
378
379    fn try_from(bytes: &[u8]) -> Result<Self, TryFromSliceForContractHashError> {
380        HashAddr::try_from(bytes)
381            .map(ByteCodeHash::new)
382            .map_err(|_| TryFromSliceForContractHashError(()))
383    }
384}
385
386impl TryFrom<&Vec<u8>> for ByteCodeHash {
387    type Error = TryFromSliceForContractHashError;
388
389    fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
390        HashAddr::try_from(bytes as &[u8])
391            .map(ByteCodeHash::new)
392            .map_err(|_| TryFromSliceForContractHashError(()))
393    }
394}
395
396#[cfg(feature = "json-schema")]
397impl JsonSchema for ByteCodeHash {
398    fn schema_name() -> String {
399        String::from("ByteCodeHash")
400    }
401
402    fn json_schema(gen: &mut SchemaGenerator) -> Schema {
403        let schema = gen.subschema_for::<String>();
404        let mut schema_object = schema.into_object();
405        schema_object.metadata().description =
406            Some("The hash address of the contract wasm".to_string());
407        schema_object.into()
408    }
409}
410
411/// The type of Byte code.
412#[repr(u8)]
413#[cfg_attr(feature = "datasize", derive(DataSize))]
414#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
415#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize)]
416pub enum ByteCodeKind {
417    /// Empty byte code.
418    Empty = 0,
419    /// Byte code to be executed with the version 1 Casper execution engine.
420    V1CasperWasm = 1,
421    /// Byte code to be executed with the version 2 Casper execution engine.
422    V2CasperWasm = 2,
423}
424
425impl ToBytes for ByteCodeKind {
426    fn to_bytes(&self) -> Result<Vec<u8>, Error> {
427        (*self as u8).to_bytes()
428    }
429
430    fn serialized_length(&self) -> usize {
431        U8_SERIALIZED_LENGTH
432    }
433
434    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
435        (*self as u8).write_bytes(writer)
436    }
437}
438
439impl FromBytes for ByteCodeKind {
440    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
441        let (byte_code_kind, remainder) = u8::from_bytes(bytes)?;
442        match byte_code_kind {
443            byte_code_kind if byte_code_kind == ByteCodeKind::Empty as u8 => {
444                Ok((ByteCodeKind::Empty, remainder))
445            }
446            byte_code_kind if byte_code_kind == ByteCodeKind::V1CasperWasm as u8 => {
447                Ok((ByteCodeKind::V1CasperWasm, remainder))
448            }
449            byte_code_kind if byte_code_kind == ByteCodeKind::V2CasperWasm as u8 => {
450                Ok((ByteCodeKind::V2CasperWasm, remainder))
451            }
452            _ => Err(Error::Formatting),
453        }
454    }
455}
456
457impl Display for ByteCodeKind {
458    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
459        match self {
460            ByteCodeKind::Empty => {
461                write!(f, "empty")
462            }
463            ByteCodeKind::V1CasperWasm => {
464                write!(f, "v1-casper-wasm")
465            }
466            ByteCodeKind::V2CasperWasm => {
467                write!(f, "v2-casper-wasm")
468            }
469        }
470    }
471}
472
473#[cfg(any(feature = "testing", test))]
474impl Distribution<ByteCodeKind> for Standard {
475    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ByteCodeKind {
476        match rng.gen_range(0..=2) {
477            0 => ByteCodeKind::Empty,
478            1 => ByteCodeKind::V1CasperWasm,
479            2 => ByteCodeKind::V2CasperWasm,
480            _ => unreachable!(),
481        }
482    }
483}
484
485/// A container for contract's Wasm bytes.
486#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
487#[cfg_attr(feature = "datasize", derive(DataSize))]
488#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
489pub struct ByteCode {
490    kind: ByteCodeKind,
491    bytes: Bytes,
492}
493
494impl Debug for ByteCode {
495    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
496        if self.bytes.len() > BYTE_CODE_MAX_DISPLAY_LEN {
497            write!(
498                f,
499                "ByteCode(0x{}...)",
500                base16::encode_lower(&self.bytes[..BYTE_CODE_MAX_DISPLAY_LEN])
501            )
502        } else {
503            write!(f, "ByteCode(0x{})", base16::encode_lower(&self.bytes))
504        }
505    }
506}
507
508impl ByteCode {
509    /// Creates new Wasm object from bytes.
510    pub fn new(kind: ByteCodeKind, bytes: Vec<u8>) -> Self {
511        ByteCode {
512            kind,
513            bytes: bytes.into(),
514        }
515    }
516
517    /// Consumes instance of [`ByteCode`] and returns its bytes.
518    pub fn take_bytes(self) -> Vec<u8> {
519        self.bytes.into()
520    }
521
522    /// Returns a slice of contained Wasm bytes.
523    pub fn bytes(&self) -> &[u8] {
524        self.bytes.as_ref()
525    }
526
527    /// Return the type of byte code.
528    pub fn kind(&self) -> ByteCodeKind {
529        self.kind
530    }
531}
532
533impl ToBytes for ByteCode {
534    fn to_bytes(&self) -> Result<Vec<u8>, Error> {
535        let mut buffer = bytesrepr::allocate_buffer(self)?;
536        self.write_bytes(&mut buffer)?;
537        Ok(buffer)
538    }
539
540    fn serialized_length(&self) -> usize {
541        self.kind.serialized_length() + self.bytes.serialized_length()
542    }
543
544    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
545        self.kind.write_bytes(writer)?;
546        self.bytes.write_bytes(writer)?;
547        Ok(())
548    }
549}
550
551impl FromBytes for ByteCode {
552    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
553        let (kind, remainder) = ByteCodeKind::from_bytes(bytes)?;
554        let (bytes, remainder) = Bytes::from_bytes(remainder)?;
555        Ok((ByteCode { kind, bytes }, remainder))
556    }
557}
558
559#[cfg(test)]
560mod tests {
561    use rand::RngCore;
562
563    use super::*;
564    use crate::testing::TestRng;
565
566    #[test]
567    fn debug_repr_of_short_wasm() {
568        const SIZE: usize = 8;
569        let wasm_bytes = vec![0; SIZE];
570        let byte_code = ByteCode::new(ByteCodeKind::V1CasperWasm, wasm_bytes);
571        assert_eq!(format!("{:?}", byte_code), "ByteCode(0x0000000000000000)");
572    }
573
574    #[test]
575    fn debug_repr_of_long_wasm() {
576        const SIZE: usize = 65;
577        let wasm_bytes = vec![0; SIZE];
578        let byte_code = ByteCode::new(ByteCodeKind::V1CasperWasm, wasm_bytes);
579        // String output is less than the bytes itself
580        assert_eq!(
581            format!("{:?}", byte_code),
582            "ByteCode(0x00000000000000000000000000000000...)"
583        );
584    }
585
586    #[test]
587    fn byte_code_bytesrepr_roundtrip() {
588        let rng = &mut TestRng::new();
589        let byte_code = ByteCode::new(rng.gen(), vec![]);
590        bytesrepr::test_serialization_roundtrip(&byte_code);
591
592        let mut buffer = vec![0u8; rng.gen_range(1..100)];
593        rng.fill_bytes(buffer.as_mut());
594        let byte_code = ByteCode::new(rng.gen(), buffer);
595        bytesrepr::test_serialization_roundtrip(&byte_code);
596    }
597
598    #[test]
599    fn contract_wasm_hash_from_slice() {
600        let bytes: Vec<u8> = (0..32).collect();
601        let byte_code_hash = HashAddr::try_from(&bytes[..]).expect("should create byte code hash");
602        let contract_hash = ByteCodeHash::new(byte_code_hash);
603        assert_eq!(&bytes, &contract_hash.as_bytes());
604    }
605
606    #[test]
607    fn contract_wasm_hash_from_str() {
608        let byte_code_hash = ByteCodeHash([3; KEY_HASH_LENGTH]);
609        let encoded = byte_code_hash.to_formatted_string();
610        let decoded = ByteCodeHash::from_formatted_str(&encoded).unwrap();
611        assert_eq!(byte_code_hash, decoded);
612
613        let invalid_prefix =
614            "contractwasm-0000000000000000000000000000000000000000000000000000000000000000";
615        assert!(ByteCodeHash::from_formatted_str(invalid_prefix).is_err());
616
617        let short_addr =
618            "contract-wasm-00000000000000000000000000000000000000000000000000000000000000";
619        assert!(ByteCodeHash::from_formatted_str(short_addr).is_err());
620
621        let long_addr =
622            "contract-wasm-000000000000000000000000000000000000000000000000000000000000000000";
623        assert!(ByteCodeHash::from_formatted_str(long_addr).is_err());
624
625        let invalid_hex =
626            "contract-wasm-000000000000000000000000000000000000000000000000000000000000000g";
627        assert!(ByteCodeHash::from_formatted_str(invalid_hex).is_err());
628    }
629
630    #[test]
631    fn byte_code_addr_from_str() {
632        let empty_addr = ByteCodeAddr::Empty;
633        let encoded = empty_addr.to_formatted_string();
634        let decoded = ByteCodeAddr::from_formatted_string(&encoded).unwrap();
635        assert_eq!(empty_addr, decoded);
636
637        let wasm_addr = ByteCodeAddr::V1CasperWasm([3; 32]);
638        let encoded = wasm_addr.to_formatted_string();
639        let decoded = ByteCodeAddr::from_formatted_string(&encoded).unwrap();
640        assert_eq!(wasm_addr, decoded);
641    }
642
643    #[test]
644    fn byte_code_serialization_roundtrip() {
645        let rng = &mut TestRng::new();
646        let wasm_addr = ByteCodeAddr::V1CasperWasm(rng.gen());
647        bytesrepr::test_serialization_roundtrip(&wasm_addr);
648
649        let empty_addr = ByteCodeAddr::Empty;
650        bytesrepr::test_serialization_roundtrip(&empty_addr);
651    }
652
653    #[test]
654    fn contract_wasm_hash_bytesrepr_roundtrip() {
655        let rng = &mut TestRng::new();
656        let byte_code_hash = ByteCodeHash(rng.gen());
657        bytesrepr::test_serialization_roundtrip(&byte_code_hash);
658    }
659
660    #[test]
661    fn contract_wasm_hash_bincode_roundtrip() {
662        let rng = &mut TestRng::new();
663        let byte_code_hash = ByteCodeHash(rng.gen());
664        let serialized = bincode::serialize(&byte_code_hash).unwrap();
665        let deserialized = bincode::deserialize(&serialized).unwrap();
666        assert_eq!(byte_code_hash, deserialized)
667    }
668
669    #[test]
670    fn contract_wasm_hash_json_roundtrip() {
671        let rng = &mut TestRng::new();
672        let byte_code_hash = ByteCodeHash(rng.gen());
673        let json_string = serde_json::to_string_pretty(&byte_code_hash).unwrap();
674        let decoded = serde_json::from_str(&json_string).unwrap();
675        assert_eq!(byte_code_hash, decoded)
676    }
677}