1use std::collections::BTreeMap;
6
7use serde::{Deserialize, Serialize};
8use tap::Pipe;
9
10use crate::{
11 base_types::ObjectRef,
12 effects::{
13 IDOperation, ObjectIn, ObjectOut, TransactionEffects, TransactionEffectsAPI,
14 TransactionEvents,
15 },
16 messages_checkpoint::{CertifiedCheckpointSummary, CheckpointContents},
17 object::Object,
18 storage::BackingPackageStore,
19 transaction::Transaction,
20};
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
23pub struct CheckpointData {
24 pub checkpoint_summary: CertifiedCheckpointSummary,
25 pub checkpoint_contents: CheckpointContents,
26 pub transactions: Vec<CheckpointTransaction>,
27}
28
29impl CheckpointData {
30 pub fn latest_live_output_objects(&self) -> Vec<&Object> {
33 let mut latest_live_objects = BTreeMap::new();
34 for tx in self.transactions.iter() {
35 for obj in tx.output_objects.iter() {
36 latest_live_objects.insert(obj.id(), obj);
37 }
38 for obj_ref in tx.removed_object_refs_post_version() {
39 latest_live_objects.remove(&(obj_ref.0));
40 }
41 }
42 latest_live_objects.into_values().collect()
43 }
44
45 pub fn eventually_removed_object_refs_post_version(&self) -> Vec<ObjectRef> {
48 let mut eventually_removed_object_refs = BTreeMap::new();
49 for tx in self.transactions.iter() {
50 for obj_ref in tx.removed_object_refs_post_version() {
51 eventually_removed_object_refs.insert(obj_ref.0, obj_ref);
52 }
53 for obj in tx.output_objects.iter() {
54 eventually_removed_object_refs.remove(&(obj.id()));
55 }
56 }
57 eventually_removed_object_refs.into_values().collect()
58 }
59
60 pub fn input_objects(&self) -> Vec<&Object> {
61 self.transactions
62 .iter()
63 .flat_map(|tx| &tx.input_objects)
64 .collect()
65 }
66
67 pub fn all_objects(&self) -> Vec<&Object> {
68 self.transactions
69 .iter()
70 .flat_map(|tx| &tx.input_objects)
71 .chain(self.transactions.iter().flat_map(|tx| &tx.output_objects))
72 .collect()
73 }
74}
75
76#[derive(Clone, Debug, Serialize, Deserialize)]
77pub struct CheckpointTransaction {
78 pub transaction: Transaction,
80 pub effects: TransactionEffects,
82 pub events: Option<TransactionEvents>,
84 pub input_objects: Vec<Object>,
87 pub output_objects: Vec<Object>,
90}
91
92impl CheckpointTransaction {
93 pub fn removed_objects_pre_version(&self) -> impl Iterator<Item = &Object> {
95 match &self.effects {
97 TransactionEffects::V1(v1) => {
98 v1.changed_objects().iter().filter_map(|(id, change)| {
99 match (
100 &change.input_state,
101 &change.output_state,
102 &change.id_operation,
103 ) {
104 (
106 ObjectIn::Exist(((version, _d), _o)),
107 ObjectOut::NotExist,
108 IDOperation::Deleted,
109 ) => Some((id, version)),
110
111 (
113 ObjectIn::Exist(((version, _), _)),
114 ObjectOut::NotExist,
115 IDOperation::None,
116 ) => Some((id, version)),
117 _ => None,
118 }
119 })
120 }
121 }
122 .map(|(id, version)| {
124 self.input_objects
125 .iter()
126 .find(|o| &o.id() == id && &o.version() == version)
127 .expect("all removed objects should show up in input objects")
128 })
129 }
130
131 pub fn removed_object_refs_post_version(&self) -> impl Iterator<Item = ObjectRef> {
132 let deleted = self.effects.deleted().into_iter();
133 let wrapped = self.effects.wrapped().into_iter();
134 let unwrapped_then_deleted = self.effects.unwrapped_then_deleted().into_iter();
135 deleted.chain(wrapped).chain(unwrapped_then_deleted)
136 }
137
138 pub fn changed_objects(&self) -> impl Iterator<Item = (&Object, Option<&Object>)> {
139 match &self.effects {
141 TransactionEffects::V1(v1) => {
142 v1.changed_objects().iter().filter_map(|(id, change)| {
143 match (
144 &change.input_state,
145 &change.output_state,
146 &change.id_operation,
147 ) {
148 (ObjectIn::NotExist, ObjectOut::ObjectWrite(_), IDOperation::Created) => {
150 Some(((id, &v1.lamport_version), None))
151 }
152 (
153 ObjectIn::NotExist,
154 ObjectOut::PackageWrite((version, _)),
155 IDOperation::Created,
156 ) => Some(((id, version), None)),
157
158 (ObjectIn::NotExist, ObjectOut::ObjectWrite(_), IDOperation::None) => {
160 Some(((id, &v1.lamport_version), None))
161 }
162
163 (ObjectIn::Exist(((old_version, _), _)), ObjectOut::ObjectWrite(_), _) => {
165 Some(((id, &v1.lamport_version), Some(old_version)))
166 }
167 (
168 ObjectIn::Exist(((old_version, _), _)),
169 ObjectOut::PackageWrite((version, _)),
170 _,
171 ) => Some(((id, version), Some(old_version))),
172
173 _ => None,
174 }
175 })
176 }
177 }
178 .map(|((id, version), old_version)| {
180 let object = self
181 .output_objects
182 .iter()
183 .find(|o| &o.id() == id && &o.version() == version)
184 .expect("changed objects should show up in output objects");
185
186 let old_object = old_version.map(|old_version| {
187 self.input_objects
188 .iter()
189 .find(|o| &o.id() == id && &o.version() == old_version)
190 .expect("mutated objects should have a previous version in input objects")
191 });
192
193 (object, old_object)
194 })
195 }
196
197 pub fn created_objects(&self) -> impl Iterator<Item = &Object> {
198 match &self.effects {
200 TransactionEffects::V1(v1) => {
201 v1.changed_objects().iter().filter_map(|(id, change)| {
202 match (
203 &change.input_state,
204 &change.output_state,
205 &change.id_operation,
206 ) {
207 (ObjectIn::NotExist, ObjectOut::ObjectWrite(_), IDOperation::Created) => {
209 Some((id, &v1.lamport_version))
210 }
211 (
212 ObjectIn::NotExist,
213 ObjectOut::PackageWrite((version, _)),
214 IDOperation::Created,
215 ) => Some((id, version)),
216
217 _ => None,
218 }
219 })
220 }
221 }
222 .map(|(id, version)| {
224 self.output_objects
225 .iter()
226 .find(|o| &o.id() == id && &o.version() == version)
227 .expect("created objects should show up in output objects")
228 })
229 }
230}
231
232impl BackingPackageStore for CheckpointData {
233 fn get_package_object(
234 &self,
235 package_id: &crate::base_types::ObjectID,
236 ) -> crate::error::IotaResult<Option<crate::storage::PackageObject>> {
237 self.transactions
238 .iter()
239 .flat_map(|transaction| transaction.output_objects.iter())
240 .find(|object| object.is_package() && &object.id() == package_id)
241 .cloned()
242 .map(crate::storage::PackageObject::new)
243 .pipe(Ok)
244 }
245}