casper_types/execution/
execution_result.rs

1use alloc::{boxed::Box, string::String, vec::Vec};
2
3#[cfg(feature = "datasize")]
4use datasize::DataSize;
5#[cfg(any(feature = "testing", test))]
6use rand::distributions::Distribution;
7#[cfg(any(feature = "testing", test))]
8use rand::Rng;
9#[cfg(feature = "json-schema")]
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12use tracing::error;
13
14use super::{ExecutionResultV1, ExecutionResultV2};
15#[cfg(any(feature = "testing", test))]
16use crate::testing::TestRng;
17use crate::{
18    bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
19    Transfer, U512,
20};
21
22const V1_TAG: u8 = 0;
23const V2_TAG: u8 = 1;
24
25/// The versioned result of executing a single deploy.
26#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
27#[cfg_attr(feature = "datasize", derive(DataSize))]
28#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
29#[serde(deny_unknown_fields)]
30pub enum ExecutionResult {
31    /// Version 1 of execution result type.
32    #[serde(rename = "Version1")]
33    V1(ExecutionResultV1),
34    /// Version 2 of execution result type.
35    #[serde(rename = "Version2")]
36    V2(Box<ExecutionResultV2>),
37}
38
39impl ExecutionResult {
40    /// Returns cost.
41    pub fn cost(&self) -> U512 {
42        match self {
43            ExecutionResult::V1(result) => result.cost(),
44            ExecutionResult::V2(result) => result.cost,
45        }
46    }
47
48    /// Returns consumed amount.
49    pub fn consumed(&self) -> U512 {
50        match self {
51            ExecutionResult::V1(result) => result.cost(),
52            ExecutionResult::V2(result) => result.consumed.value(),
53        }
54    }
55
56    /// Returns refund amount.
57    pub fn refund(&self) -> Option<U512> {
58        match self {
59            ExecutionResult::V1(_) => None,
60            ExecutionResult::V2(result) => Some(result.refund),
61        }
62    }
63
64    /// Returns a random ExecutionResult.
65    #[cfg(any(feature = "testing", test))]
66    pub fn random(rng: &mut TestRng) -> Self {
67        if rng.gen_bool(0.5) {
68            Self::V1(rand::distributions::Standard.sample(rng))
69        } else {
70            Self::V2(Box::new(ExecutionResultV2::random(rng)))
71        }
72    }
73
74    /// Returns the error message, if any.
75    pub fn error_message(&self) -> Option<String> {
76        match self {
77            ExecutionResult::V1(v1) => match v1 {
78                ExecutionResultV1::Failure { error_message, .. } => Some(error_message.clone()),
79                ExecutionResultV1::Success { .. } => None,
80            },
81            ExecutionResult::V2(v2) => v2.error_message.clone(),
82        }
83    }
84
85    /// Returns transfers, if any.
86    pub fn transfers(&self) -> Vec<Transfer> {
87        match self {
88            ExecutionResult::V1(_) => {
89                vec![]
90            }
91            ExecutionResult::V2(execution_result) => execution_result.transfers.clone(),
92        }
93    }
94}
95
96impl From<ExecutionResultV1> for ExecutionResult {
97    fn from(value: ExecutionResultV1) -> Self {
98        ExecutionResult::V1(value)
99    }
100}
101
102impl From<ExecutionResultV2> for ExecutionResult {
103    fn from(value: ExecutionResultV2) -> Self {
104        ExecutionResult::V2(Box::new(value))
105    }
106}
107
108impl ToBytes for ExecutionResult {
109    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
110        let mut buffer = bytesrepr::allocate_buffer(self)?;
111        self.write_bytes(&mut buffer)?;
112        Ok(buffer)
113    }
114
115    fn serialized_length(&self) -> usize {
116        U8_SERIALIZED_LENGTH
117            + match self {
118                ExecutionResult::V1(result) => result.serialized_length(),
119                ExecutionResult::V2(result) => result.serialized_length(),
120            }
121    }
122
123    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
124        match self {
125            ExecutionResult::V1(result) => {
126                V1_TAG.write_bytes(writer)?;
127                result.write_bytes(writer)
128            }
129            ExecutionResult::V2(result) => {
130                V2_TAG.write_bytes(writer)?;
131                result.write_bytes(writer)
132            }
133        }
134    }
135}
136
137impl FromBytes for ExecutionResult {
138    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
139        if bytes.is_empty() {
140            error!("FromBytes for ExecutionResult: bytes length should not be 0");
141        }
142        let (tag, remainder) = match u8::from_bytes(bytes) {
143            Ok((tag, rem)) => (tag, rem),
144            Err(err) => {
145                error!(%err, "FromBytes for ExecutionResult");
146                return Err(err);
147            }
148        };
149        match tag {
150            V1_TAG => {
151                let (result, remainder) = ExecutionResultV1::from_bytes(remainder)?;
152                Ok((ExecutionResult::V1(result), remainder))
153            }
154            V2_TAG => {
155                let (result, remainder) = ExecutionResultV2::from_bytes(remainder)?;
156                Ok((ExecutionResult::V2(Box::new(result)), remainder))
157            }
158            _ => {
159                error!(%tag, rem_len = remainder.len(), "FromBytes for ExecutionResult: unknown tag");
160                Err(bytesrepr::Error::Formatting)
161            }
162        }
163    }
164}
165
166#[cfg(test)]
167mod tests {
168    use rand::Rng;
169
170    use super::*;
171    use crate::testing::TestRng;
172
173    #[test]
174    fn bytesrepr_roundtrip() {
175        let rng = &mut TestRng::new();
176        let execution_result = ExecutionResult::V1(rng.gen());
177        bytesrepr::test_serialization_roundtrip(&execution_result);
178        let execution_result = ExecutionResult::from(ExecutionResultV2::random(rng));
179        bytesrepr::test_serialization_roundtrip(&execution_result);
180    }
181
182    #[test]
183    fn bincode_roundtrip() {
184        let rng = &mut TestRng::new();
185        let execution_result = ExecutionResult::V1(rng.gen());
186        let serialized = bincode::serialize(&execution_result).unwrap();
187        let deserialized = bincode::deserialize(&serialized).unwrap();
188        assert_eq!(execution_result, deserialized);
189
190        let execution_result = ExecutionResult::from(ExecutionResultV2::random(rng));
191        let serialized = bincode::serialize(&execution_result).unwrap();
192        let deserialized = bincode::deserialize(&serialized).unwrap();
193        assert_eq!(execution_result, deserialized);
194    }
195
196    #[test]
197    fn json_roundtrip() {
198        let rng = &mut TestRng::new();
199        let execution_result = ExecutionResult::V1(rng.gen());
200        let serialized = serde_json::to_string(&execution_result).unwrap();
201        let deserialized = serde_json::from_str(&serialized).unwrap();
202        assert_eq!(execution_result, deserialized);
203
204        let execution_result = ExecutionResult::from(ExecutionResultV2::random(rng));
205        let serialized = serde_json::to_string(&execution_result).unwrap();
206        println!("{:#}", serialized);
207        let deserialized = serde_json::from_str(&serialized).unwrap();
208        assert_eq!(execution_result, deserialized);
209    }
210}