casper_types/execution/
execution_result.rs1use 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#[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 #[serde(rename = "Version1")]
33 V1(ExecutionResultV1),
34 #[serde(rename = "Version2")]
36 V2(Box<ExecutionResultV2>),
37}
38
39impl ExecutionResult {
40 pub fn cost(&self) -> U512 {
42 match self {
43 ExecutionResult::V1(result) => result.cost(),
44 ExecutionResult::V2(result) => result.cost,
45 }
46 }
47
48 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 pub fn refund(&self) -> Option<U512> {
58 match self {
59 ExecutionResult::V1(_) => None,
60 ExecutionResult::V2(result) => Some(result.refund),
61 }
62 }
63
64 #[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 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 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}