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