sui_move_natives_latest/object_runtime/fingerprint.rs
1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use move_binary_format::errors::{PartialVMError, PartialVMResult};
5use move_core_types::vm_status::StatusCode;
6use move_vm_runtime::execution::values::Value;
7use sui_types::base_types::{MoveObjectType, ObjectID};
8
9/// This type is used to track if an object has changed since it was read from storage. Ideally,
10/// this would just store the owner ID+type+BCS bytes of the object; however, due to pending
11/// rewrites in the adapter, that would be too much code churn. Instead, we use the `Value` since
12/// the `RuntimeResults` operate over `Value` and not BCS bytes.
13pub struct ObjectFingerprint(Option<ObjectFingerprint_>);
14
15enum ObjectFingerprint_ {
16 /// The object did not exist (as a child object) in storage at the start of the transaction.
17 Empty,
18 // The object was loaded as a child object from storage.
19 Preexisting {
20 owner: ObjectID,
21 ty: MoveObjectType,
22 value: Value,
23 },
24}
25
26impl ObjectFingerprint {
27 /// Creates a new object fingerprint for a child object not found in storage.
28 /// Will be internally disabled if the feature is not enabled in the protocol config.
29 pub fn none() -> Self {
30 Self(Some(ObjectFingerprint_::Empty))
31 }
32
33 /// Creates a new object fingerprint for a child found in storage.
34 /// Will be internally disabled if the feature is not enabled in the protocol config.
35 pub fn preexisting(
36 preexisting_owner: &ObjectID,
37 preexisting_type: &MoveObjectType,
38 preexisting_value: &Value,
39 ) -> PartialVMResult<Self> {
40 Ok(Self(Some(ObjectFingerprint_::Preexisting {
41 owner: *preexisting_owner,
42 ty: preexisting_type.clone(),
43 value: preexisting_value.copy_value(),
44 })))
45 }
46
47 /// Checks if the object has changed since it was read from storage.
48 /// Gives an invariant violation if the fingerprint is disabled.
49 /// Gives an invariant violation if the values do not have the same layout, but the owner and
50 /// type are thesame.
51 pub fn object_has_changed(
52 &self,
53 final_owner: &ObjectID,
54 final_type: &MoveObjectType,
55 final_value: &Option<Value>,
56 ) -> PartialVMResult<bool> {
57 use ObjectFingerprint_ as F;
58 let Some(inner) = &self.0 else {
59 return Err(
60 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR).with_message(
61 "Object fingerprint not enabled, yet we were asked for the changes".to_string(),
62 ),
63 );
64 };
65 Ok(match (inner, final_value) {
66 (F::Empty, None) => false,
67 (F::Empty, Some(_)) | (F::Preexisting { .. }, None) => true,
68 (
69 F::Preexisting {
70 owner: preexisting_owner,
71 ty: preexisting_type,
72 value: preexisting_value,
73 },
74 Some(final_value),
75 ) => {
76 // owner changed or value changed.
77 // For the value, we must first check if the types are the same before comparing the
78 // values
79 !(preexisting_owner == final_owner
80 && preexisting_type == final_type
81 && preexisting_value.equals(final_value)?)
82 }
83 })
84 }
85}