Skip to content

Conversation

tzakian
Copy link
Contributor

@tzakian tzakian commented Feb 3, 2025

This updates the VM value representation to support global values, and "fingerprinting" of the global values so that they can be properly dirtied at the end of execution.

IMPORTANT

Additional work is needed to make the fingerprinting of global values actually something we'd want to use in prod, but the underlying logic of what a fingerprint is, and how it is computed has been abstracted away into a newtype so we can update this fairly easily hopefully.

Semantic changes

This changes the semantics of execution around global values. Previously a global value would always be counted as mutated if the reference was written, even with the same value. In the implementation here this is no longer the case -- if the value is the same at time of read and the conclusion of execution, the value will not be viewed as mutated. As an example of a program that would exhibit this change in behavior:

module 0x42::a;

public struct X has key, store {
    id: UID,
    x: u64,
}

public fun update1(x: &mut UID) {
    let s: &mut X = dynamic_field::borrow_mut(x, 0);
    assert!(s.x == 10);
    s.x = 11;
    s.x = 12;
    s.x = 10;
}

public fun update2(x: &mut UID) {
    let s: &mut X = dynamic_field::borrow_mut(x, 0);
    assert!(s.x == 10);
    s.x = 10;
}

In the previous semantics, the borrowed dynamic field would show as a mutated output of the transaction, in the new semantics it will not show up as mutated as extensionally the value was unchanged.

Note however, that for move_from and move_to operations, we always view this as a dirtying operation. Eventually this logic for global value dirtying will be moved out and will be tracked in the object runtime, but for now we use this implementation to unblock the adapter updates.

NB: The code in the PR may not be working as future PRs will build on top of this.

@tzakian tzakian requested a review from cgswords February 3, 2025 20:51
Copy link

vercel bot commented Feb 3, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
sui-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Feb 19, 2025 8:11pm
2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
multisig-toolkit ⬜️ Ignored (Inspect) Visit Preview Feb 19, 2025 8:11pm
sui-kiosk ⬜️ Ignored (Inspect) Visit Preview Feb 19, 2025 8:11pm

@tzakian tzakian temporarily deployed to sui-typescript-aws-kms-test-env February 3, 2025 20:51 — with GitHub Actions Inactive
// XXX/TODO(vm-rewrite): Remove this and replace with proper value dirtying.
#[derive(Debug)]
pub struct FixedSizeVec(Box<[Value]>);
pub struct GlobalFingerprint(Option<String>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a deprecated note here so we remember to come back and fix it?

Copy link
Contributor

@cgswords cgswords left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM as a "quick and dirty hack" toward code completeness, with the understanding that we will fix it later.

…t global references.

This updates the VM value representation to support global values, and
"fingerprinting" of the global values so that they can be properly
dirtied at the end of execution.

**IMPORTANT**:

Additional work is needed to make the fingerprinting of global values
actually something we'd want to use in prod, but the underlying logic of
what a fingerprint is, and how it is computed has been abstracted away
into a newtype so we can update this fairly easily hopefully.

**Semantic changes**:

This changes the semantics of execution around global values. Previously
a global value would always be counted as mutated if the reference was
written, even with the same value. In the implementation here this is no
longer the case -- if the value is the same at time of read and the
conclusion of execution, the value will not be viewed as mutated. As an
example of a program that would exhibit this change in behavior:

```move
module 0x42::a;

public struct X has key, store {
    id: UID,
    x: u64,
}

public fun update1(x: &mut UID) {
    let s: &mut X = dynamic_field::borrow_mut(x, 0);
    assert!(s.x == 10);
    s.x = 11;
    s.x = 12;
    s.x = 10;
}

public fun update2(x: &mut UID) {
    let s: &mut X = dynamic_field::borrow_mut(x, 0);
    assert!(s.x == 10);
    s.x = 10;
}
```

In the previous semantics, the borrowed dynamic field would show as a
mutated output of the transaction, in the new semantics it will not show
up as mutated as extensionally the value was unchanged.

NB: The code in the PR may not be working as future PRs will build on top of
this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants