-
Notifications
You must be signed in to change notification settings - Fork 11.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[cli] New alg for tree shaking #21356
base: main
Are you sure you want to change the base?
[cli] New alg for tree shaking #21356
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
2 Skipped Deployments
|
7b3494c
to
3fd4ec1
Compare
3fd4ec1
to
f1af2fb
Compare
f1af2fb
to
ec0080a
Compare
8b24a12
to
bde8329
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes around sui move build
look good to me, but the new algorithm does not seem quite right. I have suggested a fix and a test that would highlight the issue.
crates/sui/src/client_commands.rs
Outdated
compiled_package | ||
.dependency_ids | ||
.published | ||
.retain(|pkg_name, id| { | ||
linkage_table_ids.contains(id) | ||
|| pkgs.contains_key(pkg_name) | ||
|| pkg_name_to_orig_id | ||
.get(pkg_name) | ||
.is_some_and(|orig_id| pkg_ids.contains(orig_id)) | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not seem right:
compiled_package.dependency_ids.published
is a list of storage IDs (they point to the actual version of the package that you want to use)- similarly,
pkg_ids
is also a list of storage IDs, because it was generated by filtering the same list. linkage_table_ids
is a list of original IDs (they point to the first version of the package you want to use, regardless of its version), because that is what the key in the linkage table is.- values in
pkg_name_to_orig_id
are also original IDs.
In this code, we are freely comparing original IDs and storage IDs -- this should only work for packages that have never been upgraded -- have you tested this approach in cases involving upgraded packages? The following example should surface an issue if there is one:
- B is published depending on C v1
- A is published depending on B and C v2, but does not directly refer to anything in C v2 (the dependency just serves to upgrade B's dependency).
In that example, A's dependency list should include both B, which it does use, and C v2, which it doesn't use but is an upgrade of one of its immediate dependency's transitive dependencies.
The retention test goes something like this, I think:
compiled_package
.dependency_ids
.published
.retain(|pkg_name, id| {
pkgs.contains_key(pkg_name)
|| pkg_name_to_orig_id
.get(pkg_name)
.is_some_and(|orig_id| linkage_table_original_ids.contains(orig_id))
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this test and fixed this part, I think, but I cannot get the test to work properly. It's working when following the same steps with a CLI build. I think the issue is around publishing without tree shaking using old test-transaction-builder, which does not create a Move.lock file.
Need to think a bit what to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so here's the new test for it
K, K_v2, L_depends_on_K (with code reference to K), and M_depends_on_L_and_K_v2, with code calling function from L_depends_on_K package, but no code reference to K_v2.
All should work, but I have an intuition that all this breaks if there are no Move.lock files and only Move.toml with published-at
field. I need to understand how things worked before automated address mgmt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the test that uses the "old" way of publishing/upgrading, without automated address management, just for my sanity check.
bde8329
to
89e3602
Compare
89e3602
to
2a77055
Compare
b28b84f
to
020d05a
Compare
020d05a
to
814ab75
Compare
814ab75
to
07c4799
Compare
packages to keep for deps.
07c4799
to
ef77a66
Compare
…#21383) ## Description This PR adds support for implicit dependencies to the package management at the move layer. ## PR stack #21204 Add implicit Sui dependencies #21384 Refactors to BuildConfig #21383 Add support for implicits to move package management This also depends on @stefan-mysten 's ongoing tree-shaking work in #21356 ## Test plan See `test_sources/implicits/README.md` for a description of the new snapshot tests --- ## Release notes Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required. For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates. - [ ] Protocol: - [ ] Nodes (Validators and Full nodes): - [ ] gRPC: - [ ] JSON-RPC: - [ ] GraphQL: - [ ] CLI: - [ ] Rust SDK:
## Description This removes `sui_move_build::BuildConfig::default` and makes other small changes ## PR stack #21204 Add implicit Sui dependencies #21384 Refactors to BuildConfig #21383 Add support for implicits to move package management This also depends on @stefan-mysten 's ongoing tree-shaking work in #21356 ## Test plan This disables two broken bytecode verification tests. See DVX-786 --- ## Release notes Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required. For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates. - [ ] Protocol: - [ ] Nodes (Validators and Full nodes): - [ ] gRPC: - [ ] JSON-RPC: - [ ] GraphQL: - [ ] CLI: - [ ] Rust SDK:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still issues with how this is written, PTAL at the inline comments.
pkg_id_to_name.get(&object_id).unwrap() | ||
) | ||
} | ||
_ => anyhow!("Cannot convert data into an object: {e}"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a call to context
in disguise.
p.to_move_package(u64::MAX /* safe as this pkg comes from the network */) | ||
.map_err(|e| anyhow!(e)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this work?
p.to_move_package(u64::MAX /* safe as this pkg comes from the network */) | |
.map_err(|e| anyhow!(e)) | |
p.to_move_package(u64::MAX /* safe as this pkg comes from the network */)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately no, because p_to_move_package
returns a sui_types::ExecutionError
and here we need to return an anyhow::Error
.
// orig id | ||
for (name, id) in &pkg_name_to_orig_id { | ||
if *linkage_orig_id == id { | ||
pkgs_to_keep.insert(name); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is accidentally quadratic -- create a reverse mapping once to make this look-up efficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spurious change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, it's an intended change. I modified before the code to pass SuiClient
rather than ReadApi
, and now I reverted that to use ReadApi
everywhere where's possible, so it comes from that refactoring. Sorry for the confusion.
.map(|(name, id)| (id, name)) | ||
.collect(); | ||
let immediate_dep_move_pkgs = | ||
fetch_move_packages(read_api, &immediate_dep_pkgs_ids, &pkg_id_to_name).await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be a fair bit of massaging of data coming out of find_immediate_deps_pkgs_to_keep
to make it work for fetch_move_packages
. Does that need to happen here?
- Could the data come out of
find_immediate_deps_pkgs_to_keep
in a more appropriate form for what it's about to be used for here? - Could any other processing happen inside
fetch_move_packages
?
let immediate_dep_pkgs_linkage_tables: BTreeMap<_, _> = immediate_dep_move_pkgs | ||
.iter() | ||
.flat_map(|pkg| pkg.linkage_table()) | ||
.collect(); | ||
|
||
// for every immediate dep package, we need to use its linkage table to determine its | ||
// transitive dependencies and ensure that we keep the required packages | ||
let mut pkgs_to_keep: BTreeSet<&Symbol> = BTreeSet::new(); | ||
let published_pkgs = compiled_package.dependency_ids.published.clone(); | ||
for (linkage_orig_id, upgrade_info) in &immediate_dep_pkgs_linkage_tables { | ||
// orig id | ||
for (name, id) in &pkg_name_to_orig_id { | ||
if *linkage_orig_id == id { | ||
pkgs_to_keep.insert(name); | ||
} | ||
} | ||
|
||
// for dependencies on pkgs that are upgrades, find the name of the published | ||
// package by matching the upgraded package id with the published package id | ||
for (name, id) in &published_pkgs { | ||
if &upgrade_info.upgraded_id == id { | ||
pkgs_to_keep.insert(name); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems suspicious for a couple of reasons:
immediate_dep_pkgs_linkage_tables
saves all upgrade info, but if two immediate deps depend on the same transitive dep at different versions, then you will arbitrarily pick one.- In the upgraded package case, you are checking that the dependency exactly matches the upgraded ID of one of your dependency's dependencies.
These two details alone should set off alarm bells because what if you overwrote the version of the dependency that you meant to match with here? But the situation is worse than that, because the package being published is allowed to upgrade any of its dependency's dependencies as well, and this would not allow for that.
The correct check is to keep every published ID whose corresponding original ID shows up as a key in the linkage table of one of the immediate dependencies.
Description
This PR updates the tree shaking algorithm to use linkage tables on-chain. We need to use that because implicit dependencies feature that is being worked in #21204 would not work with this algorithm. This is due to the way transitive dependencies are computed in the previous tree shaking algorithm. Implicit dependencies will add those system dependencies to the transitive dependencies, thus system packages will get included in the final list of dependencies in the package that is to be published/upgraded after tree shaking is complete.
Test plan
Existing tests. Updated a test for system packages.
Release notes
Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required.
For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates.