|
| 1 | +use std::iter; |
1 | 2 | // Copyright (c) 2022, Mysten Labs, Inc.
|
2 | 3 | // SPDX-License-Identifier: Apache-2.0
|
3 | 4 | use super::*;
|
@@ -966,6 +967,82 @@ impl<const ALL_OBJ_VER: bool, S: Eq + Serialize + for<'de> Deserialize<'de>>
|
966 | 967 | Ok(assigned_seq)
|
967 | 968 | }
|
968 | 969 |
|
| 970 | + /// This function is called at the end of epoch for each transaction that's |
| 971 | + /// executed locally on the validator but didn't make to the last checkpoint. |
| 972 | + /// The effects of the execution is reverted here. |
| 973 | + /// The following things are reverted: |
| 974 | + /// 1. Certificate and effects are deleted. |
| 975 | + /// 2. Latest parent_sync entries for each mutated object are deleted. |
| 976 | + /// 3. All new object states are deleted. |
| 977 | + /// 4. owner_index table change is reverted. |
| 978 | + pub fn revert_state_update(&self, tx_digest: &TransactionDigest) -> SuiResult { |
| 979 | + let effects = self.get_effects(tx_digest)?; |
| 980 | + let mut write_batch = self.certificates.batch(); |
| 981 | + write_batch = write_batch.delete_batch(&self.certificates, iter::once(tx_digest))?; |
| 982 | + write_batch = write_batch.delete_batch(&self.effects, iter::once(tx_digest))?; |
| 983 | + |
| 984 | + let all_new_refs = effects |
| 985 | + .mutated |
| 986 | + .iter() |
| 987 | + .chain(effects.created.iter()) |
| 988 | + .chain(effects.unwrapped.iter()) |
| 989 | + .map(|(r, _)| r) |
| 990 | + .chain(effects.deleted.iter()) |
| 991 | + .chain(effects.wrapped.iter()); |
| 992 | + write_batch = write_batch.delete_batch(&self.parent_sync, all_new_refs)?; |
| 993 | + |
| 994 | + let all_new_object_keys = effects |
| 995 | + .mutated |
| 996 | + .iter() |
| 997 | + .chain(effects.created.iter()) |
| 998 | + .chain(effects.unwrapped.iter()) |
| 999 | + .map(|((id, version, _), _)| ObjectKey(*id, *version)); |
| 1000 | + write_batch = write_batch.delete_batch(&self.objects, all_new_object_keys)?; |
| 1001 | + |
| 1002 | + // Reverting the change to the owner_index table is most complex. |
| 1003 | + // For each newly created (i.e. created and unwrapped) object, the entry in owner_index |
| 1004 | + // needs to be deleted; for each mutated object, we need to query the object state of |
| 1005 | + // the older version, and then rewrite the entry with the old object info. |
| 1006 | + // TODO: Validators should not need to maintain owner_index. |
| 1007 | + // This is dependent on https://github.com/MystenLabs/sui/issues/2629. |
| 1008 | + let owners_to_delete = effects |
| 1009 | + .created |
| 1010 | + .iter() |
| 1011 | + .chain(effects.unwrapped.iter()) |
| 1012 | + .chain(effects.mutated.iter()) |
| 1013 | + .map(|((id, _, _), owner)| (*owner, *id)); |
| 1014 | + write_batch = write_batch.delete_batch(&self.owner_index, owners_to_delete)?; |
| 1015 | + let mutated_objects = effects |
| 1016 | + .mutated |
| 1017 | + .iter() |
| 1018 | + .map(|(r, _)| r) |
| 1019 | + .chain(effects.deleted.iter()) |
| 1020 | + .chain(effects.wrapped.iter()) |
| 1021 | + .map(|(id, version, _)| { |
| 1022 | + ObjectKey( |
| 1023 | + *id, |
| 1024 | + version |
| 1025 | + .decrement() |
| 1026 | + .expect("version revert should never fail"), |
| 1027 | + ) |
| 1028 | + }); |
| 1029 | + let old_objects = self |
| 1030 | + .objects |
| 1031 | + .multi_get(mutated_objects)? |
| 1032 | + .into_iter() |
| 1033 | + .map(|obj_opt| { |
| 1034 | + let obj = obj_opt.expect("Older object version not found"); |
| 1035 | + ( |
| 1036 | + (obj.owner, obj.id()), |
| 1037 | + ObjectInfo::new(&obj.compute_object_reference(), &obj), |
| 1038 | + ) |
| 1039 | + }); |
| 1040 | + write_batch = write_batch.insert_batch(&self.owner_index, old_objects)?; |
| 1041 | + |
| 1042 | + write_batch.write()?; |
| 1043 | + Ok(()) |
| 1044 | + } |
| 1045 | + |
969 | 1046 | /// Returns the last entry we have for this object in the parents_sync index used
|
970 | 1047 | /// to facilitate client and authority sync. In turn the latest entry provides the
|
971 | 1048 | /// latest object_reference, and also the latest transaction that has interacted with
|
|
0 commit comments