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}