1use crate::base_types::{ObjectID, SequenceNumber};
5use crate::digests::{ObjectDigest, TransactionEventsDigest};
6use crate::effects::{EffectsObjectChange, IDOperation, ObjectIn, ObjectOut, TransactionEffects};
7use crate::execution::SharedInput;
8use crate::execution_status::ExecutionStatus;
9use crate::gas::GasCostSummary;
10use crate::message_envelope::Message;
11use crate::object::Owner;
12use crate::transaction::{
13 InputObjectKind, SenderSignedData, SharedObjectMutability, TransactionDataAPI,
14};
15use std::collections::{BTreeMap, BTreeSet};
16
17pub struct TestEffectsBuilder {
18 transaction: SenderSignedData,
19 status: Option<ExecutionStatus>,
21 shared_input_versions: BTreeMap<ObjectID, SequenceNumber>,
23 events_digest: Option<TransactionEventsDigest>,
24 created_objects: Vec<(ObjectID, Owner)>,
25 mutated_objects: Vec<(ObjectID, SequenceNumber, Owner)>,
27 deleted_objects: Vec<(ObjectID, SequenceNumber)>,
29 wrapped_objects: Vec<(ObjectID, SequenceNumber)>,
31 unwrapped_objects: Vec<(ObjectID, Owner)>,
33 frozen_objects: BTreeSet<ObjectID>,
35}
36
37impl TestEffectsBuilder {
38 pub fn new(transaction: &SenderSignedData) -> Self {
39 Self {
40 transaction: transaction.clone(),
41 status: None,
42 shared_input_versions: BTreeMap::new(),
43 events_digest: None,
44 created_objects: vec![],
45 mutated_objects: vec![],
46 deleted_objects: vec![],
47 wrapped_objects: vec![],
48 unwrapped_objects: vec![],
49 frozen_objects: BTreeSet::new(),
50 }
51 }
52
53 pub fn with_status(mut self, status: ExecutionStatus) -> Self {
54 self.status = Some(status);
55 self
56 }
57
58 pub fn with_shared_input_versions(
59 mut self,
60 versions: BTreeMap<ObjectID, SequenceNumber>,
61 ) -> Self {
62 assert!(self.shared_input_versions.is_empty());
63 self.shared_input_versions = versions;
64 self
65 }
66
67 pub fn with_events_digest(mut self, digest: TransactionEventsDigest) -> Self {
68 self.events_digest = Some(digest);
69 self
70 }
71
72 pub fn with_created_objects(
73 mut self,
74 objects: impl IntoIterator<Item = (ObjectID, Owner)>,
75 ) -> Self {
76 self.created_objects.extend(objects);
77 self
78 }
79
80 pub fn with_mutated_objects(
81 mut self,
82 objects: impl IntoIterator<Item = (ObjectID, SequenceNumber, Owner)>,
84 ) -> Self {
85 self.mutated_objects.extend(objects);
86 self
87 }
88
89 pub fn with_wrapped_objects(
90 mut self,
91 objects: impl IntoIterator<Item = (ObjectID, SequenceNumber)>,
92 ) -> Self {
93 self.wrapped_objects.extend(objects);
94 self
95 }
96
97 pub fn with_unwrapped_objects(
98 mut self,
99 objects: impl IntoIterator<Item = (ObjectID, Owner)>,
100 ) -> Self {
101 self.unwrapped_objects.extend(objects);
102 self
103 }
104
105 pub fn with_deleted_objects(
106 mut self,
107 objects: impl IntoIterator<Item = (ObjectID, SequenceNumber)>,
108 ) -> Self {
109 self.deleted_objects.extend(objects);
110 self
111 }
112
113 pub fn with_frozen_objects(mut self, objects: impl IntoIterator<Item = ObjectID>) -> Self {
114 self.frozen_objects.extend(objects);
115 self
116 }
117
118 pub fn build(self) -> TransactionEffects {
119 let lamport_version = self.get_lamport_version();
120 let status = self.status.unwrap_or(ExecutionStatus::Success);
121 let shared_objects = self
123 .shared_input_versions
124 .iter()
125 .map(|(id, version)| SharedInput::Existing((*id, *version, ObjectDigest::MIN)))
126 .collect();
127 let executed_epoch = 0;
128 let sender = self.transaction.transaction_data().sender();
129 let changed_objects = self
131 .transaction
132 .transaction_data()
133 .input_objects()
134 .unwrap()
135 .iter()
136 .filter_map(|kind| match kind {
137 InputObjectKind::ImmOrOwnedMoveObject((id, _, _))
138 if self.frozen_objects.contains(id) =>
139 {
140 None
141 }
142 InputObjectKind::ImmOrOwnedMoveObject(oref) => Some((
143 oref.0,
144 EffectsObjectChange {
145 input_state: ObjectIn::Exist((
146 (oref.1, oref.2),
147 Owner::AddressOwner(sender),
148 )),
149 output_state: ObjectOut::ObjectWrite((
150 ObjectDigest::MAX,
152 Owner::AddressOwner(sender),
153 )),
154 id_operation: IDOperation::None,
155 },
156 )),
157 InputObjectKind::MovePackage(_) => None,
158 InputObjectKind::SharedMoveObject {
159 id,
160 initial_shared_version,
161 mutability,
162 } => {
163 let mutable = match mutability {
164 SharedObjectMutability::Mutable => true,
165 SharedObjectMutability::Immutable => false,
166 SharedObjectMutability::NonExclusiveWrite => todo!(),
167 };
168 mutable.then_some((
169 *id,
170 EffectsObjectChange {
171 input_state: ObjectIn::Exist((
172 (
173 *self
174 .shared_input_versions
175 .get(id)
176 .unwrap_or(initial_shared_version),
177 ObjectDigest::MIN,
178 ),
179 Owner::Shared {
180 initial_shared_version: *initial_shared_version,
181 },
182 )),
183 output_state: ObjectOut::ObjectWrite((
184 ObjectDigest::MAX,
186 Owner::Shared {
187 initial_shared_version: *initial_shared_version,
188 },
189 )),
190 id_operation: IDOperation::None,
191 },
192 ))
193 }
194 })
195 .chain(self.created_objects.into_iter().map(|(id, owner)| {
196 (
197 id,
198 EffectsObjectChange {
199 input_state: ObjectIn::NotExist,
200 output_state: ObjectOut::ObjectWrite((ObjectDigest::random(), owner)),
201 id_operation: IDOperation::Created,
202 },
203 )
204 }))
205 .chain(
206 self.mutated_objects
207 .into_iter()
208 .map(|(id, version, owner)| {
209 (
210 id,
211 EffectsObjectChange {
212 input_state: ObjectIn::Exist((
213 (version, ObjectDigest::random()),
214 Owner::AddressOwner(sender),
215 )),
216 output_state: ObjectOut::ObjectWrite((
217 ObjectDigest::random(),
218 owner,
219 )),
220 id_operation: IDOperation::None,
221 },
222 )
223 }),
224 )
225 .chain(self.deleted_objects.into_iter().map(|(id, version)| {
226 (
227 id,
228 EffectsObjectChange {
229 input_state: ObjectIn::Exist((
230 (version, ObjectDigest::random()),
231 Owner::AddressOwner(sender),
232 )),
233 output_state: ObjectOut::NotExist,
234 id_operation: IDOperation::Deleted,
235 },
236 )
237 }))
238 .chain(self.wrapped_objects.into_iter().map(|(id, version)| {
239 (
240 id,
241 EffectsObjectChange {
242 input_state: ObjectIn::Exist((
243 (version, ObjectDigest::random()),
244 Owner::AddressOwner(sender),
245 )),
246 output_state: ObjectOut::NotExist,
247 id_operation: IDOperation::None,
248 },
249 )
250 }))
251 .chain(self.unwrapped_objects.into_iter().map(|(id, owner)| {
252 (
253 id,
254 EffectsObjectChange {
255 input_state: ObjectIn::NotExist,
256 output_state: ObjectOut::ObjectWrite((ObjectDigest::random(), owner)),
257 id_operation: IDOperation::None,
258 },
259 )
260 }))
261 .collect();
262 let gas_object_id = self.transaction.transaction_data().gas()[0].0;
263 let event_digest = self.events_digest;
264 let dependencies = vec![];
265 TransactionEffects::new_from_execution_v2(
266 status,
267 executed_epoch,
268 GasCostSummary::default(),
269 shared_objects,
270 BTreeSet::new(),
271 self.transaction.digest(),
272 lamport_version,
273 changed_objects,
274 Some(gas_object_id),
275 event_digest,
276 dependencies,
277 )
278 }
279
280 fn get_lamport_version(&self) -> SequenceNumber {
281 SequenceNumber::lamport_increment(
282 self.transaction
283 .transaction_data()
284 .input_objects()
285 .unwrap()
286 .iter()
287 .filter_map(|kind| kind.version())
288 .chain(
289 self.transaction
290 .transaction_data()
291 .receiving_objects()
292 .iter()
293 .map(|oref| oref.1),
294 )
295 .chain(self.shared_input_versions.values().copied())
296 .chain(self.mutated_objects.iter().map(|(_, v, _)| *v))
297 .chain(self.deleted_objects.iter().map(|(_, v)| *v))
298 .chain(self.wrapped_objects.iter().map(|(_, v)| *v)),
299 )
300 }
301}