casper_types/
execution_result.rs

1//! This file provides types to allow conversion from an EE `ExecutionResult` into a similar type
2//! which can be serialized to a valid binary or JSON representation.
3//!
4//! It is stored as metadata related to a given deploy, and made available to clients via the
5//! JSON-RPC API.
6
7// TODO - remove once schemars stops causing warning.
8#![allow(clippy::field_reassign_with_default)]
9
10use core::convert::TryFrom;
11
12use alloc::{
13    boxed::Box,
14    format,
15    string::{String, ToString},
16    vec,
17    vec::Vec,
18};
19
20#[cfg(feature = "datasize")]
21use datasize::DataSize;
22use num::{FromPrimitive, ToPrimitive};
23use num_derive::{FromPrimitive, ToPrimitive};
24#[cfg(feature = "json-schema")]
25use once_cell::sync::Lazy;
26use rand::{
27    distributions::{Distribution, Standard},
28    seq::SliceRandom,
29    Rng,
30};
31#[cfg(feature = "json-schema")]
32use schemars::JsonSchema;
33use serde::{Deserialize, Serialize};
34
35#[cfg(feature = "json-schema")]
36use crate::KEY_HASH_LENGTH;
37use crate::{
38    account::AccountHash,
39    bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
40    system::auction::{Bid, EraInfo, UnbondingPurse, WithdrawPurse},
41    CLValue, DeployInfo, NamedKey, Transfer, TransferAddr, U128, U256, U512,
42};
43
44#[derive(FromPrimitive, ToPrimitive, Debug)]
45#[repr(u8)]
46enum ExecutionResultTag {
47    Failure = 0,
48    Success = 1,
49}
50
51impl TryFrom<u8> for ExecutionResultTag {
52    type Error = bytesrepr::Error;
53
54    fn try_from(value: u8) -> Result<Self, Self::Error> {
55        FromPrimitive::from_u8(value).ok_or(bytesrepr::Error::Formatting)
56    }
57}
58
59#[derive(FromPrimitive, ToPrimitive, Debug)]
60#[repr(u8)]
61enum OpTag {
62    Read = 0,
63    Write = 1,
64    Add = 2,
65    NoOp = 3,
66}
67
68impl TryFrom<u8> for OpTag {
69    type Error = bytesrepr::Error;
70
71    fn try_from(value: u8) -> Result<Self, Self::Error> {
72        FromPrimitive::from_u8(value).ok_or(bytesrepr::Error::Formatting)
73    }
74}
75
76#[derive(FromPrimitive, ToPrimitive, Debug)]
77#[repr(u8)]
78enum TransformTag {
79    Identity = 0,
80    WriteCLValue = 1,
81    WriteAccount = 2,
82    WriteContractWasm = 3,
83    WriteContract = 4,
84    WriteContractPackage = 5,
85    WriteDeployInfo = 6,
86    WriteTransfer = 7,
87    WriteEraInfo = 8,
88    WriteBid = 9,
89    WriteWithdraw = 10,
90    AddInt32 = 11,
91    AddUInt64 = 12,
92    AddUInt128 = 13,
93    AddUInt256 = 14,
94    AddUInt512 = 15,
95    AddKeys = 16,
96    Failure = 17,
97    WriteUnbonding = 18,
98}
99
100impl TryFrom<u8> for TransformTag {
101    type Error = bytesrepr::Error;
102
103    fn try_from(value: u8) -> Result<Self, Self::Error> {
104        FromPrimitive::from_u8(value).ok_or(bytesrepr::Error::Formatting)
105    }
106}
107
108#[cfg(feature = "json-schema")]
109static EXECUTION_RESULT: Lazy<ExecutionResult> = Lazy::new(|| {
110    let operations = vec![
111        Operation {
112            key: "account-hash-2c4a11c062a8a337bfc97e27fd66291caeb2c65865dcb5d3ef3759c4c97efecb"
113                .to_string(),
114            kind: OpKind::Write,
115        },
116        Operation {
117            key: "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1"
118                .to_string(),
119            kind: OpKind::Read,
120        },
121    ];
122
123    let transforms = vec![
124        TransformEntry {
125            key: "uref-2c4a11c062a8a337bfc97e27fd66291caeb2c65865dcb5d3ef3759c4c97efecb-007"
126                .to_string(),
127            transform: Transform::AddUInt64(8u64),
128        },
129        TransformEntry {
130            key: "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1"
131                .to_string(),
132            transform: Transform::Identity,
133        },
134    ];
135
136    let effect = ExecutionEffect {
137        operations,
138        transforms,
139    };
140
141    let transfers = vec![
142        TransferAddr::new([89; KEY_HASH_LENGTH]),
143        TransferAddr::new([130; KEY_HASH_LENGTH]),
144    ];
145
146    ExecutionResult::Success {
147        effect,
148        transfers,
149        cost: U512::from(123_456),
150    }
151});
152
153/// The result of executing a single deploy.
154#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
155#[cfg_attr(feature = "datasize", derive(DataSize))]
156#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
157#[serde(deny_unknown_fields)]
158pub enum ExecutionResult {
159    /// The result of a failed execution.
160    Failure {
161        /// The effect of executing the deploy.
162        effect: ExecutionEffect,
163        /// A record of Transfers performed while executing the deploy.
164        transfers: Vec<TransferAddr>,
165        /// The cost of executing the deploy.
166        cost: U512,
167        /// The error message associated with executing the deploy.
168        error_message: String,
169    },
170    /// The result of a successful execution.
171    Success {
172        /// The effect of executing the deploy.
173        effect: ExecutionEffect,
174        /// A record of Transfers performed while executing the deploy.
175        transfers: Vec<TransferAddr>,
176        /// The cost of executing the deploy.
177        cost: U512,
178    },
179}
180
181impl ExecutionResult {
182    // This method is not intended to be used by third party crates.
183    #[doc(hidden)]
184    #[cfg(feature = "json-schema")]
185    pub fn example() -> &'static Self {
186        &EXECUTION_RESULT
187    }
188
189    fn tag(&self) -> ExecutionResultTag {
190        match self {
191            ExecutionResult::Failure {
192                effect: _,
193                transfers: _,
194                cost: _,
195                error_message: _,
196            } => ExecutionResultTag::Failure,
197            ExecutionResult::Success {
198                effect: _,
199                transfers: _,
200                cost: _,
201            } => ExecutionResultTag::Success,
202        }
203    }
204}
205
206impl Distribution<ExecutionResult> for Standard {
207    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ExecutionResult {
208        let op_count = rng.gen_range(0..6);
209        let mut operations = Vec::new();
210        for _ in 0..op_count {
211            let op = [OpKind::Read, OpKind::Add, OpKind::NoOp, OpKind::Write]
212                .choose(rng)
213                .unwrap();
214            operations.push(Operation {
215                key: rng.gen::<u64>().to_string(),
216                kind: *op,
217            });
218        }
219
220        let transform_count = rng.gen_range(0..6);
221        let mut transforms = Vec::new();
222        for _ in 0..transform_count {
223            transforms.push(TransformEntry {
224                key: rng.gen::<u64>().to_string(),
225                transform: rng.gen(),
226            });
227        }
228
229        let execution_effect = ExecutionEffect::new(transforms);
230
231        let transfer_count = rng.gen_range(0..6);
232        let mut transfers = vec![];
233        for _ in 0..transfer_count {
234            transfers.push(TransferAddr::new(rng.gen()))
235        }
236
237        if rng.gen() {
238            ExecutionResult::Failure {
239                effect: execution_effect,
240                transfers,
241                cost: rng.gen::<u64>().into(),
242                error_message: format!("Error message {}", rng.gen::<u64>()),
243            }
244        } else {
245            ExecutionResult::Success {
246                effect: execution_effect,
247                transfers,
248                cost: rng.gen::<u64>().into(),
249            }
250        }
251    }
252}
253
254// TODO[goral09]: Add `write_bytes` impl.
255impl ToBytes for ExecutionResult {
256    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
257        let mut buffer = bytesrepr::allocate_buffer(self)?;
258        let tag_byte = self.tag().to_u8().ok_or(bytesrepr::Error::Formatting)?;
259        buffer.push(tag_byte);
260        match self {
261            ExecutionResult::Failure {
262                effect,
263                transfers,
264                cost,
265                error_message,
266            } => {
267                buffer.extend(effect.to_bytes()?);
268                buffer.extend(transfers.to_bytes()?);
269                buffer.extend(cost.to_bytes()?);
270                buffer.extend(error_message.to_bytes()?);
271            }
272            ExecutionResult::Success {
273                effect,
274                transfers,
275                cost,
276            } => {
277                buffer.extend(effect.to_bytes()?);
278                buffer.extend(transfers.to_bytes()?);
279                buffer.extend(cost.to_bytes()?);
280            }
281        }
282        Ok(buffer)
283    }
284
285    fn serialized_length(&self) -> usize {
286        U8_SERIALIZED_LENGTH
287            + match self {
288                ExecutionResult::Failure {
289                    effect: execution_effect,
290                    transfers,
291                    cost,
292                    error_message,
293                } => {
294                    execution_effect.serialized_length()
295                        + transfers.serialized_length()
296                        + cost.serialized_length()
297                        + error_message.serialized_length()
298                }
299                ExecutionResult::Success {
300                    effect: execution_effect,
301                    transfers,
302                    cost,
303                } => {
304                    execution_effect.serialized_length()
305                        + transfers.serialized_length()
306                        + cost.serialized_length()
307                }
308            }
309    }
310}
311
312impl FromBytes for ExecutionResult {
313    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
314        let (tag, remainder) = u8::from_bytes(bytes)?;
315        match TryFrom::try_from(tag)? {
316            ExecutionResultTag::Failure => {
317                let (effect, remainder) = ExecutionEffect::from_bytes(remainder)?;
318                let (transfers, remainder) = Vec::<TransferAddr>::from_bytes(remainder)?;
319                let (cost, remainder) = U512::from_bytes(remainder)?;
320                let (error_message, remainder) = String::from_bytes(remainder)?;
321                let execution_result = ExecutionResult::Failure {
322                    effect,
323                    transfers,
324                    cost,
325                    error_message,
326                };
327                Ok((execution_result, remainder))
328            }
329            ExecutionResultTag::Success => {
330                let (execution_effect, remainder) = ExecutionEffect::from_bytes(remainder)?;
331                let (transfers, remainder) = Vec::<TransferAddr>::from_bytes(remainder)?;
332                let (cost, remainder) = U512::from_bytes(remainder)?;
333                let execution_result = ExecutionResult::Success {
334                    effect: execution_effect,
335                    transfers,
336                    cost,
337                };
338                Ok((execution_result, remainder))
339            }
340        }
341    }
342}
343
344/// The journal of execution transforms from a single deploy.
345#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Default, Debug)]
346#[cfg_attr(feature = "datasize", derive(DataSize))]
347#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
348#[serde(deny_unknown_fields)]
349pub struct ExecutionEffect {
350    /// The resulting operations.
351    pub operations: Vec<Operation>,
352    /// The journal of execution transforms.
353    pub transforms: Vec<TransformEntry>,
354}
355
356impl ExecutionEffect {
357    /// Constructor for [`ExecutionEffect`].
358    pub fn new(transforms: Vec<TransformEntry>) -> Self {
359        Self {
360            transforms,
361            operations: Default::default(),
362        }
363    }
364}
365
366// TODO[goral09]: Add `write_bytes` impl.
367impl ToBytes for ExecutionEffect {
368    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
369        let mut buffer = bytesrepr::allocate_buffer(self)?;
370        buffer.extend(self.operations.to_bytes()?);
371        buffer.extend(self.transforms.to_bytes()?);
372        Ok(buffer)
373    }
374
375    fn serialized_length(&self) -> usize {
376        self.operations.serialized_length() + self.transforms.serialized_length()
377    }
378}
379
380impl FromBytes for ExecutionEffect {
381    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
382        let (operations, remainder) = Vec::<Operation>::from_bytes(bytes)?;
383        let (transforms, remainder) = Vec::<TransformEntry>::from_bytes(remainder)?;
384        let json_execution_journal = ExecutionEffect {
385            operations,
386            transforms,
387        };
388        Ok((json_execution_journal, remainder))
389    }
390}
391
392/// An operation performed while executing a deploy.
393#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
394#[cfg_attr(feature = "datasize", derive(DataSize))]
395#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
396#[serde(deny_unknown_fields)]
397pub struct Operation {
398    /// The formatted string of the `Key`.
399    pub key: String,
400    /// The type of operation.
401    pub kind: OpKind,
402}
403
404// TODO[goral09]: Add `write_bytes` impl.
405impl ToBytes for Operation {
406    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
407        let mut buffer = bytesrepr::allocate_buffer(self)?;
408        buffer.extend(self.key.to_bytes()?);
409        buffer.extend(self.kind.to_bytes()?);
410        Ok(buffer)
411    }
412
413    fn serialized_length(&self) -> usize {
414        self.key.serialized_length() + self.kind.serialized_length()
415    }
416}
417
418impl FromBytes for Operation {
419    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
420        let (key, remainder) = String::from_bytes(bytes)?;
421        let (kind, remainder) = OpKind::from_bytes(remainder)?;
422        let operation = Operation { key, kind };
423        Ok((operation, remainder))
424    }
425}
426
427/// The type of operation performed while executing a deploy.
428#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)]
429#[cfg_attr(feature = "datasize", derive(DataSize))]
430#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
431#[serde(deny_unknown_fields)]
432pub enum OpKind {
433    /// A read operation.
434    Read,
435    /// A write operation.
436    Write,
437    /// An addition.
438    Add,
439    /// An operation which has no effect.
440    NoOp,
441}
442
443impl OpKind {
444    fn tag(&self) -> OpTag {
445        match self {
446            OpKind::Read => OpTag::Read,
447            OpKind::Write => OpTag::Write,
448            OpKind::Add => OpTag::Add,
449            OpKind::NoOp => OpTag::NoOp,
450        }
451    }
452}
453
454// TODO[goral09]: Add `write_bytes` impl.
455impl ToBytes for OpKind {
456    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
457        let tag_bytes = self.tag().to_u8().ok_or(bytesrepr::Error::Formatting)?;
458        tag_bytes.to_bytes()
459    }
460
461    fn serialized_length(&self) -> usize {
462        U8_SERIALIZED_LENGTH
463    }
464}
465
466impl FromBytes for OpKind {
467    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
468        let (tag, remainder) = u8::from_bytes(bytes)?;
469        match TryFrom::try_from(tag)? {
470            OpTag::Read => Ok((OpKind::Read, remainder)),
471            OpTag::Write => Ok((OpKind::Write, remainder)),
472            OpTag::Add => Ok((OpKind::Add, remainder)),
473            OpTag::NoOp => Ok((OpKind::NoOp, remainder)),
474        }
475    }
476}
477
478/// A transformation performed while executing a deploy.
479#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
480#[cfg_attr(feature = "datasize", derive(DataSize))]
481#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
482#[serde(deny_unknown_fields)]
483pub struct TransformEntry {
484    /// The formatted string of the `Key`.
485    pub key: String,
486    /// The transformation.
487    pub transform: Transform,
488}
489
490// TODO[goral09]: Add `write_bytes`.
491impl ToBytes for TransformEntry {
492    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
493        let mut buffer = bytesrepr::allocate_buffer(self)?;
494        buffer.extend(self.key.to_bytes()?);
495        buffer.extend(self.transform.to_bytes()?);
496        Ok(buffer)
497    }
498
499    fn serialized_length(&self) -> usize {
500        self.key.serialized_length() + self.transform.serialized_length()
501    }
502}
503
504impl FromBytes for TransformEntry {
505    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
506        let (key, remainder) = String::from_bytes(bytes)?;
507        let (transform, remainder) = Transform::from_bytes(remainder)?;
508        let transform_entry = TransformEntry { key, transform };
509        Ok((transform_entry, remainder))
510    }
511}
512
513/// The actual transformation performed while executing a deploy.
514#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
515#[cfg_attr(feature = "datasize", derive(DataSize))]
516#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
517#[serde(deny_unknown_fields)]
518pub enum Transform {
519    /// A transform having no effect.
520    Identity,
521    /// Writes the given CLValue to global state.
522    WriteCLValue(CLValue),
523    /// Writes the given Account to global state.
524    WriteAccount(AccountHash),
525    /// Writes a smart contract as Wasm to global state.
526    WriteContractWasm,
527    /// Writes a smart contract to global state.
528    WriteContract,
529    /// Writes a smart contract package to global state.
530    WriteContractPackage,
531    /// Writes the given DeployInfo to global state.
532    WriteDeployInfo(DeployInfo),
533    /// Writes the given EraInfo to global state.
534    WriteEraInfo(EraInfo),
535    /// Writes the given Transfer to global state.
536    WriteTransfer(Transfer),
537    /// Writes the given Bid to global state.
538    WriteBid(Box<Bid>),
539    /// Writes the given Withdraw to global state.
540    WriteWithdraw(Vec<WithdrawPurse>),
541    /// Adds the given `i32`.
542    AddInt32(i32),
543    /// Adds the given `u64`.
544    AddUInt64(u64),
545    /// Adds the given `U128`.
546    AddUInt128(U128),
547    /// Adds the given `U256`.
548    AddUInt256(U256),
549    /// Adds the given `U512`.
550    AddUInt512(U512),
551    /// Adds the given collection of named keys.
552    AddKeys(Vec<NamedKey>),
553    /// A failed transformation, containing an error message.
554    Failure(String),
555    /// Writes the given Unbonding to global state.
556    WriteUnbonding(Vec<UnbondingPurse>),
557}
558
559impl Transform {
560    fn tag(&self) -> TransformTag {
561        match self {
562            Transform::Identity => TransformTag::Identity,
563            Transform::WriteCLValue(_) => TransformTag::WriteCLValue,
564            Transform::WriteAccount(_) => TransformTag::WriteAccount,
565            Transform::WriteContractWasm => TransformTag::WriteContractWasm,
566            Transform::WriteContract => TransformTag::WriteContract,
567            Transform::WriteContractPackage => TransformTag::WriteContractPackage,
568            Transform::WriteDeployInfo(_) => TransformTag::WriteDeployInfo,
569            Transform::WriteEraInfo(_) => TransformTag::WriteEraInfo,
570            Transform::WriteTransfer(_) => TransformTag::WriteTransfer,
571            Transform::WriteBid(_) => TransformTag::WriteBid,
572            Transform::WriteWithdraw(_) => TransformTag::WriteWithdraw,
573            Transform::AddInt32(_) => TransformTag::AddInt32,
574            Transform::AddUInt64(_) => TransformTag::AddUInt64,
575            Transform::AddUInt128(_) => TransformTag::AddUInt128,
576            Transform::AddUInt256(_) => TransformTag::AddUInt256,
577            Transform::AddUInt512(_) => TransformTag::AddUInt512,
578            Transform::AddKeys(_) => TransformTag::AddKeys,
579            Transform::Failure(_) => TransformTag::Failure,
580            Transform::WriteUnbonding(_) => TransformTag::WriteUnbonding,
581        }
582    }
583}
584
585// TODO[goral09]: Add `write_bytes` impl.
586impl ToBytes for Transform {
587    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
588        let mut buffer = bytesrepr::allocate_buffer(self)?;
589        let tag_bytes = self.tag().to_u8().ok_or(bytesrepr::Error::Formatting)?;
590        buffer.insert(0, tag_bytes);
591        match self {
592            Transform::Identity => {}
593            Transform::WriteCLValue(value) => {
594                buffer.extend(value.to_bytes()?);
595            }
596            Transform::WriteAccount(account_hash) => {
597                buffer.extend(account_hash.to_bytes()?);
598            }
599            Transform::WriteContractWasm => {}
600            Transform::WriteContract => {}
601            Transform::WriteContractPackage => {}
602            Transform::WriteDeployInfo(deploy_info) => {
603                buffer.extend(deploy_info.to_bytes()?);
604            }
605            Transform::WriteEraInfo(era_info) => {
606                buffer.extend(era_info.to_bytes()?);
607            }
608            Transform::WriteTransfer(transfer) => {
609                buffer.extend(transfer.to_bytes()?);
610            }
611            Transform::WriteBid(bid) => {
612                buffer.extend(bid.to_bytes()?);
613            }
614            Transform::WriteWithdraw(unbonding_purses) => {
615                buffer.extend(unbonding_purses.to_bytes()?);
616            }
617            Transform::AddInt32(value) => {
618                buffer.extend(value.to_bytes()?);
619            }
620            Transform::AddUInt64(value) => {
621                buffer.extend(value.to_bytes()?);
622            }
623            Transform::AddUInt128(value) => {
624                buffer.extend(value.to_bytes()?);
625            }
626            Transform::AddUInt256(value) => {
627                buffer.extend(value.to_bytes()?);
628            }
629            Transform::AddUInt512(value) => {
630                buffer.extend(value.to_bytes()?);
631            }
632            Transform::AddKeys(value) => {
633                buffer.extend(value.to_bytes()?);
634            }
635            Transform::Failure(value) => {
636                buffer.extend(value.to_bytes()?);
637            }
638            Transform::WriteUnbonding(value) => {
639                buffer.extend(value.to_bytes()?);
640            }
641        }
642        Ok(buffer)
643    }
644
645    fn serialized_length(&self) -> usize {
646        let body_len = match self {
647            Transform::WriteCLValue(value) => value.serialized_length(),
648            Transform::WriteAccount(value) => value.serialized_length(),
649            Transform::WriteDeployInfo(value) => value.serialized_length(),
650            Transform::WriteEraInfo(value) => value.serialized_length(),
651            Transform::WriteTransfer(value) => value.serialized_length(),
652            Transform::AddInt32(value) => value.serialized_length(),
653            Transform::AddUInt64(value) => value.serialized_length(),
654            Transform::AddUInt128(value) => value.serialized_length(),
655            Transform::AddUInt256(value) => value.serialized_length(),
656            Transform::AddUInt512(value) => value.serialized_length(),
657            Transform::AddKeys(value) => value.serialized_length(),
658            Transform::Failure(value) => value.serialized_length(),
659            Transform::Identity
660            | Transform::WriteContractWasm
661            | Transform::WriteContract
662            | Transform::WriteContractPackage => 0,
663            Transform::WriteBid(value) => value.serialized_length(),
664            Transform::WriteWithdraw(value) => value.serialized_length(),
665            Transform::WriteUnbonding(value) => value.serialized_length(),
666        };
667        U8_SERIALIZED_LENGTH + body_len
668    }
669}
670
671impl FromBytes for Transform {
672    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
673        let (tag, remainder) = u8::from_bytes(bytes)?;
674        match TryFrom::try_from(tag)? {
675            TransformTag::Identity => Ok((Transform::Identity, remainder)),
676            TransformTag::WriteCLValue => {
677                let (cl_value, remainder) = CLValue::from_bytes(remainder)?;
678                Ok((Transform::WriteCLValue(cl_value), remainder))
679            }
680            TransformTag::WriteAccount => {
681                let (account_hash, remainder) = AccountHash::from_bytes(remainder)?;
682                Ok((Transform::WriteAccount(account_hash), remainder))
683            }
684            TransformTag::WriteContractWasm => Ok((Transform::WriteContractWasm, remainder)),
685            TransformTag::WriteContract => Ok((Transform::WriteContract, remainder)),
686            TransformTag::WriteContractPackage => Ok((Transform::WriteContractPackage, remainder)),
687            TransformTag::WriteDeployInfo => {
688                let (deploy_info, remainder) = DeployInfo::from_bytes(remainder)?;
689                Ok((Transform::WriteDeployInfo(deploy_info), remainder))
690            }
691            TransformTag::WriteEraInfo => {
692                let (era_info, remainder) = EraInfo::from_bytes(remainder)?;
693                Ok((Transform::WriteEraInfo(era_info), remainder))
694            }
695            TransformTag::WriteTransfer => {
696                let (transfer, remainder) = Transfer::from_bytes(remainder)?;
697                Ok((Transform::WriteTransfer(transfer), remainder))
698            }
699            TransformTag::AddInt32 => {
700                let (value_i32, remainder) = i32::from_bytes(remainder)?;
701                Ok((Transform::AddInt32(value_i32), remainder))
702            }
703            TransformTag::AddUInt64 => {
704                let (value_u64, remainder) = u64::from_bytes(remainder)?;
705                Ok((Transform::AddUInt64(value_u64), remainder))
706            }
707            TransformTag::AddUInt128 => {
708                let (value_u128, remainder) = U128::from_bytes(remainder)?;
709                Ok((Transform::AddUInt128(value_u128), remainder))
710            }
711            TransformTag::AddUInt256 => {
712                let (value_u256, remainder) = U256::from_bytes(remainder)?;
713                Ok((Transform::AddUInt256(value_u256), remainder))
714            }
715            TransformTag::AddUInt512 => {
716                let (value_u512, remainder) = U512::from_bytes(remainder)?;
717                Ok((Transform::AddUInt512(value_u512), remainder))
718            }
719            TransformTag::AddKeys => {
720                let (value, remainder) = Vec::<NamedKey>::from_bytes(remainder)?;
721                Ok((Transform::AddKeys(value), remainder))
722            }
723            TransformTag::Failure => {
724                let (value, remainder) = String::from_bytes(remainder)?;
725                Ok((Transform::Failure(value), remainder))
726            }
727            TransformTag::WriteBid => {
728                let (bid, remainder) = Bid::from_bytes(remainder)?;
729                Ok((Transform::WriteBid(Box::new(bid)), remainder))
730            }
731            TransformTag::WriteWithdraw => {
732                let (withdraw_purses, remainder) =
733                    <Vec<WithdrawPurse> as FromBytes>::from_bytes(remainder)?;
734                Ok((Transform::WriteWithdraw(withdraw_purses), remainder))
735            }
736            TransformTag::WriteUnbonding => {
737                let (unbonding_purses, remainder) =
738                    <Vec<UnbondingPurse> as FromBytes>::from_bytes(remainder)?;
739                Ok((Transform::WriteUnbonding(unbonding_purses), remainder))
740            }
741        }
742    }
743}
744
745impl Distribution<Transform> for Standard {
746    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Transform {
747        // TODO - include WriteDeployInfo and WriteTransfer as options
748        match rng.gen_range(0..13) {
749            0 => Transform::Identity,
750            1 => Transform::WriteCLValue(CLValue::from_t(true).unwrap()),
751            2 => Transform::WriteAccount(AccountHash::new(rng.gen())),
752            3 => Transform::WriteContractWasm,
753            4 => Transform::WriteContract,
754            5 => Transform::WriteContractPackage,
755            6 => Transform::AddInt32(rng.gen()),
756            7 => Transform::AddUInt64(rng.gen()),
757            8 => Transform::AddUInt128(rng.gen::<u64>().into()),
758            9 => Transform::AddUInt256(rng.gen::<u64>().into()),
759            10 => Transform::AddUInt512(rng.gen::<u64>().into()),
760            11 => {
761                let mut named_keys = Vec::new();
762                for _ in 0..rng.gen_range(1..6) {
763                    named_keys.push(NamedKey {
764                        name: rng.gen::<u64>().to_string(),
765                        key: rng.gen::<u64>().to_string(),
766                    });
767                }
768                Transform::AddKeys(named_keys)
769            }
770            12 => Transform::Failure(rng.gen::<u64>().to_string()),
771            _ => unreachable!(),
772        }
773    }
774}
775
776#[cfg(test)]
777mod tests {
778    use rand::{rngs::SmallRng, Rng, SeedableRng};
779
780    use super::*;
781
782    fn get_rng() -> SmallRng {
783        let mut seed = [0u8; 32];
784        getrandom::getrandom(seed.as_mut()).unwrap();
785        SmallRng::from_seed(seed)
786    }
787
788    #[test]
789    fn bytesrepr_test_transform() {
790        let mut rng = get_rng();
791        let transform: Transform = rng.gen();
792        bytesrepr::test_serialization_roundtrip(&transform);
793    }
794
795    #[test]
796    fn bytesrepr_test_execution_result() {
797        let mut rng = get_rng();
798        let execution_result: ExecutionResult = rng.gen();
799        bytesrepr::test_serialization_roundtrip(&execution_result);
800    }
801}