1use bytes::Buf;
10use bytes::BufMut;
11use move_core_types::account_address::AccountAddress;
12use move_core_types::identifier::Identifier;
13use move_core_types::language_storage::StructTag;
14use move_core_types::language_storage::TypeTag;
15use sui_consistent_store::Decode;
16use sui_consistent_store::Encode;
17use sui_consistent_store::error::DecodeError;
18use sui_consistent_store::error::EncodeError;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26pub struct U64Be(pub u64);
27
28impl Encode for U64Be {
29 fn encode_into<B: BufMut>(&self, buf: &mut B) -> Result<(), EncodeError> {
30 buf.put_slice(&self.0.to_be_bytes());
31 Ok(())
32 }
33}
34
35impl Decode for U64Be {
36 fn decode<B: Buf>(buf: &mut B) -> Result<Self, DecodeError> {
37 if buf.remaining() != 8 {
38 return Err(DecodeError::msg(format!(
39 "expected 8 bytes for U64Be, got {}",
40 buf.remaining(),
41 )));
42 }
43 Ok(U64Be(buf.get_u64()))
44 }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
54pub struct U64Varint(pub u64);
55
56impl Encode for U64Varint {
57 fn encode_into<B: BufMut>(&self, buf: &mut B) -> Result<(), EncodeError> {
58 prost::encoding::encode_varint(self.0, buf);
59 Ok(())
60 }
61}
62
63impl Decode for U64Varint {
64 fn decode<B: Buf>(buf: &mut B) -> Result<Self, DecodeError> {
65 let value = prost::encoding::decode_varint(buf)
66 .map_err(|e| DecodeError::with_source("decode varint", e))?;
67 if buf.has_remaining() {
68 return Err(DecodeError::msg(format!(
69 "expected exact varint length, {} bytes remain",
70 buf.remaining(),
71 )));
72 }
73 Ok(U64Varint(value))
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Hash)]
89pub struct StructTagKey(pub StructTag);
90
91impl Encode for StructTagKey {
92 fn encode_into<B: BufMut>(&self, buf: &mut B) -> Result<(), EncodeError> {
93 let bytes = bcs::to_bytes(&self.0)
94 .map_err(|e| EncodeError::with_source("bcs encode StructTag", e))?;
95 buf.put_slice(&bytes);
96 Ok(())
97 }
98}
99
100impl Decode for StructTagKey {
101 fn decode<B: Buf>(buf: &mut B) -> Result<Self, DecodeError> {
102 let tag = read_struct_tag(buf)?;
103 Ok(StructTagKey(tag))
104 }
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Hash)]
111pub struct TypeTagKey(pub TypeTag);
112
113impl Encode for TypeTagKey {
114 fn encode_into<B: BufMut>(&self, buf: &mut B) -> Result<(), EncodeError> {
115 let bytes = bcs::to_bytes(&self.0)
116 .map_err(|e| EncodeError::with_source("bcs encode TypeTag", e))?;
117 buf.put_slice(&bytes);
118 Ok(())
119 }
120}
121
122impl Decode for TypeTagKey {
123 fn decode<B: Buf>(buf: &mut B) -> Result<Self, DecodeError> {
124 let tag = read_type_tag(buf)?;
125 Ok(TypeTagKey(tag))
126 }
127}
128
129pub(crate) fn read_struct_tag<B: Buf>(buf: &mut B) -> Result<StructTag, DecodeError> {
132 if buf.remaining() < AccountAddress::LENGTH {
133 return Err(DecodeError::msg(format!(
134 "StructTag truncated at address: {} bytes left",
135 buf.remaining(),
136 )));
137 }
138 let mut addr = [0u8; AccountAddress::LENGTH];
139 buf.copy_to_slice(&mut addr);
140 let address = AccountAddress::new(addr);
141 let module = read_identifier(buf)?;
142 let name = read_identifier(buf)?;
143 let n_params = read_uleb128(buf)? as usize;
144 let mut type_params = Vec::with_capacity(n_params);
145 for _ in 0..n_params {
146 type_params.push(read_type_tag(buf)?);
147 }
148 Ok(StructTag {
149 address,
150 module,
151 name,
152 type_params,
153 })
154}
155
156pub(crate) fn read_type_tag<B: Buf>(buf: &mut B) -> Result<TypeTag, DecodeError> {
159 let variant = read_uleb128(buf)?;
160 Ok(match variant {
161 0 => TypeTag::Bool,
162 1 => TypeTag::U8,
163 2 => TypeTag::U64,
164 3 => TypeTag::U128,
165 4 => TypeTag::Address,
166 5 => TypeTag::Signer,
167 6 => TypeTag::Vector(Box::new(read_type_tag(buf)?)),
168 7 => TypeTag::Struct(Box::new(read_struct_tag(buf)?)),
169 8 => TypeTag::U16,
170 9 => TypeTag::U32,
171 10 => TypeTag::U256,
172 v => {
173 return Err(DecodeError::msg(format!("unknown TypeTag variant: {v}",)));
174 }
175 })
176}
177
178pub(crate) fn write_uleb128<B: BufMut>(value: u32, buf: &mut B) {
183 let mut v = value;
184 while v >= 0x80 {
185 buf.put_u8(((v & 0x7f) as u8) | 0x80);
186 v >>= 7;
187 }
188 buf.put_u8(v as u8);
189}
190
191pub(crate) fn read_uleb128<B: Buf>(buf: &mut B) -> Result<u32, DecodeError> {
194 let mut value: u64 = 0;
195 for shift in (0..32).step_by(7) {
196 if !buf.has_remaining() {
197 return Err(DecodeError::msg("uleb128 truncated"));
198 }
199 let byte = buf.get_u8();
200 let digit = byte & 0x7f;
201 value |= u64::from(digit) << shift;
202 if digit == byte {
203 if shift > 0 && digit == 0 {
204 return Err(DecodeError::msg("non-canonical uleb128"));
205 }
206 return u32::try_from(value).map_err(|_| DecodeError::msg("uleb128 overflow"));
207 }
208 }
209 Err(DecodeError::msg("uleb128 overflow"))
210}
211
212fn read_identifier<B: Buf>(buf: &mut B) -> Result<Identifier, DecodeError> {
215 let len = read_uleb128(buf)? as usize;
216 if buf.remaining() < len {
217 return Err(DecodeError::msg(format!(
218 "Identifier truncated: need {len} bytes, have {}",
219 buf.remaining(),
220 )));
221 }
222 let bytes = buf.copy_to_bytes(len);
223 let s =
224 std::str::from_utf8(&bytes).map_err(|e| DecodeError::with_source("Identifier utf8", e))?;
225 Identifier::new(s).map_err(|e| DecodeError::with_source("Identifier", e))
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 fn ident(s: &str) -> Identifier {
233 Identifier::new(s).unwrap()
234 }
235
236 fn struct_tag(addr: u8, module: &str, name: &str, params: Vec<TypeTag>) -> StructTag {
237 StructTag {
238 address: AccountAddress::new([addr; 32]),
239 module: ident(module),
240 name: ident(name),
241 type_params: params,
242 }
243 }
244
245 fn assert_struct_tag_byte_identical(tag: &StructTag) {
251 let via_key = StructTagKey(tag.clone()).encode().unwrap();
252 let via_bcs = bcs::to_bytes(tag).unwrap();
253 assert_eq!(via_key, via_bcs);
254 }
255
256 fn round_trip_struct(tag: StructTag) {
257 assert_struct_tag_byte_identical(&tag);
258 let bytes = StructTagKey(tag.clone()).encode().unwrap();
259 let decoded = StructTagKey::decode(&mut &bytes[..]).unwrap();
260 assert_eq!(decoded.0, tag);
261 }
262
263 fn round_trip_type(tag: TypeTag) {
264 let bytes = TypeTagKey(tag.clone()).encode().unwrap();
265 assert_eq!(bytes, bcs::to_bytes(&tag).unwrap());
266 let decoded = TypeTagKey::decode(&mut &bytes[..]).unwrap();
267 assert_eq!(decoded.0, tag);
268 }
269
270 #[test]
273 fn struct_tag_leaves_trailing_bytes_intact() {
274 let tag = struct_tag(2, "sui", "SUI", vec![]);
275 let mut bytes = bcs::to_bytes(&tag).unwrap();
276 let trailer = b"trailing payload";
277 bytes.extend_from_slice(trailer);
278
279 let mut cursor: &[u8] = &bytes;
280 let decoded = StructTagKey::decode(&mut cursor).unwrap();
281 assert_eq!(decoded.0, tag);
282 assert_eq!(cursor, trailer);
283 }
284
285 #[test]
286 fn struct_tag_no_type_params() {
287 round_trip_struct(struct_tag(2, "sui", "SUI", vec![]));
288 }
289
290 #[test]
291 fn struct_tag_with_primitive_param() {
292 round_trip_struct(struct_tag(2, "balance", "Balance", vec![TypeTag::U64]));
293 }
294
295 #[test]
296 fn struct_tag_with_nested_struct_param() {
297 round_trip_struct(struct_tag(
299 2,
300 "coin",
301 "Coin",
302 vec![TypeTag::Struct(Box::new(struct_tag(
303 2,
304 "sui",
305 "SUI",
306 vec![],
307 )))],
308 ));
309 }
310
311 #[test]
312 fn struct_tag_with_vector_of_struct_param() {
313 round_trip_struct(struct_tag(
315 2,
316 "bag",
317 "Bag",
318 vec![TypeTag::Vector(Box::new(TypeTag::Struct(Box::new(
319 struct_tag(2, "sui", "SUI", vec![]),
320 ))))],
321 ));
322 }
323
324 #[test]
325 fn type_tag_primitive_variants_round_trip() {
326 for tag in [
327 TypeTag::Bool,
328 TypeTag::U8,
329 TypeTag::U16,
330 TypeTag::U32,
331 TypeTag::U64,
332 TypeTag::U128,
333 TypeTag::U256,
334 TypeTag::Address,
335 TypeTag::Signer,
336 ] {
337 round_trip_type(tag);
338 }
339 }
340
341 #[test]
342 fn type_tag_nested_vectors_round_trip() {
343 round_trip_type(TypeTag::Vector(Box::new(TypeTag::Vector(Box::new(
344 TypeTag::U64,
345 )))));
346 }
347
348 #[test]
349 fn type_tag_decode_rejects_unknown_variant() {
350 let err = TypeTagKey::decode(&mut &[0x0bu8][..]).unwrap_err();
353 assert!(
354 err.to_string().contains("unknown TypeTag variant"),
355 "unexpected error: {err}",
356 );
357 }
358}
359
360#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
363pub struct UnitKey;
364
365impl Encode for UnitKey {
366 fn encode_into<B: BufMut>(&self, _buf: &mut B) -> Result<(), EncodeError> {
367 Ok(())
368 }
369}
370
371impl Decode for UnitKey {
372 fn decode<B: Buf>(buf: &mut B) -> Result<Self, DecodeError> {
373 if buf.has_remaining() {
374 return Err(DecodeError::msg(format!(
375 "expected 0 bytes for UnitKey, got {}",
376 buf.remaining(),
377 )));
378 }
379 Ok(UnitKey)
380 }
381}