sui_types/
accumulator_metadata.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    MoveTypeTagTrait, MoveTypeTagTraitGeneric, SUI_ACCUMULATOR_ROOT_OBJECT_ID,
6    SUI_FRAMEWORK_ADDRESS, SUI_FRAMEWORK_PACKAGE_ID,
7    base_types::{ObjectID, SequenceNumber, SuiAddress},
8    collection_types::Bag,
9    dynamic_field::{DynamicFieldKey, DynamicFieldObject},
10    error::SuiResult,
11    object::Object,
12    storage::{ChildObjectResolver, ObjectStore},
13};
14use move_core_types::{
15    ident_str,
16    identifier::IdentStr,
17    language_storage::{StructTag, TypeTag},
18};
19use serde::{Deserialize, Serialize};
20
21pub const ACCUMULATOR_METADATA_MODULE: &IdentStr = ident_str!("accumulator_metadata");
22pub const ACCUMULATOR_OBJECT_COUNT_KEY_STRUCT_NAME: &IdentStr =
23    ident_str!("AccumulatorObjectCountKey");
24pub const ACCUMULATOR_OWNER_KEY_TYPE: &IdentStr = ident_str!("OwnerKey");
25pub const ACCUMULATOR_OWNER_TYPE: &IdentStr = ident_str!("Owner");
26pub const ACCUMULATOR_METADATA_KEY_TYPE: &IdentStr = ident_str!("MetadataKey");
27pub const ACCUMULATOR_METADATA_TYPE: &IdentStr = ident_str!("Metadata");
28
29#[derive(Serialize, Deserialize)]
30pub struct AccumulatorOwner {
31    pub balances: Bag,
32    pub owner: SuiAddress,
33}
34
35impl MoveTypeTagTrait for AccumulatorOwner {
36    fn get_type_tag() -> TypeTag {
37        TypeTag::Struct(Box::new(StructTag {
38            address: SUI_FRAMEWORK_ADDRESS,
39            module: ACCUMULATOR_METADATA_MODULE.to_owned(),
40            name: ACCUMULATOR_OWNER_TYPE.to_owned(),
41            type_params: vec![],
42        }))
43    }
44}
45
46#[derive(Serialize, Deserialize, Debug, Default)]
47pub struct MetadataKey(u8);
48
49impl MoveTypeTagTraitGeneric for MetadataKey {
50    fn get_type_tag(type_params: &[TypeTag]) -> TypeTag {
51        TypeTag::Struct(Box::new(StructTag {
52            address: SUI_FRAMEWORK_PACKAGE_ID.into(),
53            module: ACCUMULATOR_METADATA_MODULE.to_owned(),
54            name: ACCUMULATOR_METADATA_KEY_TYPE.to_owned(),
55            type_params: type_params.to_vec(),
56        }))
57    }
58}
59
60#[derive(Serialize, Deserialize)]
61pub struct AccumulatorMetadata {
62    /// Any per-balance fields we wish to add in the future.
63    fields: Bag,
64}
65
66impl MoveTypeTagTraitGeneric for AccumulatorMetadata {
67    fn get_type_tag(type_params: &[TypeTag]) -> TypeTag {
68        TypeTag::Struct(Box::new(StructTag {
69            address: SUI_FRAMEWORK_ADDRESS,
70            module: ACCUMULATOR_METADATA_MODULE.to_owned(),
71            name: ACCUMULATOR_METADATA_TYPE.to_owned(),
72            type_params: type_params.to_vec(),
73        }))
74    }
75}
76
77#[derive(Serialize, Deserialize, Debug)]
78pub struct OwnerKey {
79    owner: SuiAddress,
80}
81
82impl MoveTypeTagTrait for OwnerKey {
83    fn get_type_tag() -> TypeTag {
84        TypeTag::Struct(Box::new(StructTag {
85            address: SUI_FRAMEWORK_ADDRESS,
86            module: ACCUMULATOR_METADATA_MODULE.to_owned(),
87            name: ACCUMULATOR_OWNER_KEY_TYPE.to_owned(),
88            type_params: vec![],
89        }))
90    }
91}
92
93impl AccumulatorOwner {
94    pub fn type_() -> StructTag {
95        StructTag {
96            address: SUI_FRAMEWORK_ADDRESS,
97            module: ACCUMULATOR_METADATA_MODULE.to_owned(),
98            name: ACCUMULATOR_OWNER_TYPE.to_owned(),
99            type_params: vec![],
100        }
101    }
102
103    pub fn get_object_id(owner: SuiAddress) -> SuiResult<ObjectID> {
104        let key = OwnerKey { owner };
105        DynamicFieldKey(
106            SUI_ACCUMULATOR_ROOT_OBJECT_ID,
107            key,
108            OwnerKey::get_type_tag(),
109        )
110        .object_id()
111    }
112
113    pub fn exists(
114        child_object_resolver: &dyn ChildObjectResolver,
115        version_bound: Option<SequenceNumber>,
116        owner: SuiAddress,
117    ) -> SuiResult<bool> {
118        let key = OwnerKey { owner };
119
120        DynamicFieldKey(
121            SUI_ACCUMULATOR_ROOT_OBJECT_ID,
122            key,
123            OwnerKey::get_type_tag(),
124        )
125        .into_id_with_bound(version_bound.unwrap_or(SequenceNumber::MAX))?
126        .exists(child_object_resolver)
127    }
128
129    pub fn load_object(
130        child_object_resolver: &dyn ChildObjectResolver,
131        root_version: Option<SequenceNumber>,
132        owner: SuiAddress,
133    ) -> SuiResult<Option<Object>> {
134        let key = OwnerKey { owner };
135        Ok(DynamicFieldKey(
136            SUI_ACCUMULATOR_ROOT_OBJECT_ID,
137            key,
138            OwnerKey::get_type_tag(),
139        )
140        .into_id_with_bound(root_version.unwrap_or(SequenceNumber::MAX))?
141        .load_object(child_object_resolver)?
142        .map(|o| o.into_object()))
143    }
144
145    pub fn from_object(object: Object) -> SuiResult<Self> {
146        DynamicFieldObject::<OwnerKey>::new(object).load_value::<Self>()
147    }
148
149    pub fn load(
150        child_object_resolver: &dyn ChildObjectResolver,
151        root_version: Option<SequenceNumber>,
152        owner: SuiAddress,
153    ) -> SuiResult<Option<Self>> {
154        let key = OwnerKey { owner };
155        DynamicFieldKey(
156            SUI_ACCUMULATOR_ROOT_OBJECT_ID,
157            key,
158            OwnerKey::get_type_tag(),
159        )
160        .into_id_with_bound(root_version.unwrap_or(SequenceNumber::MAX))?
161        .load_object(child_object_resolver)?
162        .map(|o| o.load_value::<Self>())
163        .transpose()
164    }
165
166    pub fn metadata_exists(
167        &self,
168        child_object_resolver: &dyn ChildObjectResolver,
169        version_bound: Option<SequenceNumber>,
170        type_: &TypeTag,
171    ) -> SuiResult<bool> {
172        let key = MetadataKey::default();
173        DynamicFieldKey(
174            *self.balances.id.object_id(),
175            key,
176            MetadataKey::get_type_tag(std::slice::from_ref(type_)),
177        )
178        .into_id_with_bound(version_bound.unwrap_or(SequenceNumber::MAX))?
179        .exists(child_object_resolver)
180    }
181
182    pub fn load_metadata(
183        &self,
184        child_object_resolver: &dyn ChildObjectResolver,
185        version_bound: Option<SequenceNumber>,
186        type_: &TypeTag,
187    ) -> SuiResult<Option<AccumulatorMetadata>> {
188        let key = MetadataKey::default();
189        DynamicFieldKey(
190            *self.balances.id.object_id(),
191            key,
192            MetadataKey::get_type_tag(std::slice::from_ref(type_)),
193        )
194        .into_id_with_bound(version_bound.unwrap_or(SequenceNumber::MAX))?
195        .load_object(child_object_resolver)?
196        .map(|o| o.load_value::<AccumulatorMetadata>())
197        .transpose()
198    }
199}
200
201/// Rust version of the Move sui::accumulator_metadata::AccumulatorObjectCountKey type.
202/// This is used as a dynamic field key to store the net count of accumulator objects
203/// as a dynamic field on the accumulator root object.
204///
205/// There is no u8 in the Move definition, however empty structs in Move
206/// are represented as a single byte 0 in the serialized data.
207#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
208pub struct AccumulatorObjectCountKey(u8);
209
210impl MoveTypeTagTrait for AccumulatorObjectCountKey {
211    fn get_type_tag() -> TypeTag {
212        TypeTag::Struct(Box::new(StructTag {
213            address: SUI_FRAMEWORK_ADDRESS,
214            module: ACCUMULATOR_METADATA_MODULE.to_owned(),
215            name: ACCUMULATOR_OBJECT_COUNT_KEY_STRUCT_NAME.to_owned(),
216            type_params: vec![],
217        }))
218    }
219}
220
221/// Reads the accumulator object count from the accumulator root's dynamic fields.
222pub fn get_accumulator_object_count(object_store: &dyn ObjectStore) -> SuiResult<Option<u64>> {
223    DynamicFieldKey(
224        SUI_ACCUMULATOR_ROOT_OBJECT_ID,
225        AccumulatorObjectCountKey(0),
226        AccumulatorObjectCountKey::get_type_tag(),
227    )
228    .into_unbounded_id()?
229    .load_object(object_store)
230    .map(|o| o.load_value::<u64>())
231    .transpose()
232}