From 169b5927c5107d122c8c006a98f9f5772eb9dc10 Mon Sep 17 00:00:00 2001 From: Rijnard van Tonder Date: Tue, 23 Jan 2024 14:35:16 -0800 Subject: [PATCH] move: versioned toolchain compilation to verify source (#15731) ## Description Implements versioned toolchain builds to verify bytecode when publishing packages. That is, on `publish`, verifies package dependencies and compiles modules with prior compiler versions if needed. Guarded by `SUI_RUN_TOOLCHAIN_BUILD`. discussion. ## Test Plan Added a test that requires a dep to compile with the current compiler by reading from Move.lock. Supporting a prior compiler is TBD. All new functionality gated for now by `SUI_RUN_TOOLCHAIN_BUILD`. --- If your changes are not user-facing and do not break anything, you can skip the following section. Otherwise, please briefly describe what has changed under the Release Notes section. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes --- Cargo.lock | 220 +++++++--- Cargo.toml | 4 + crates/sui-source-validation/Cargo.toml | 12 +- .../versioned-a-depends-on-b/Move.toml | 10 + .../versioned-a-depends-on-b/sources/a.move | 11 + .../fixture/versioned-b/Move.lock | 11 + .../fixture/versioned-b/Move.toml | 7 + .../fixture/versioned-b/sources/b.move | 12 + .../fixture/versioned-b/sources/c.move | 8 + .../fixture/versioned-b/sources/d.move | 8 + crates/sui-source-validation/src/lib.rs | 384 +++++++++++++++++- crates/sui-source-validation/src/tests.rs | 159 +++++--- crates/workspace-hack/Cargo.toml | 28 +- 13 files changed, 734 insertions(+), 140 deletions(-) create mode 100644 crates/sui-source-validation/fixture/versioned-a-depends-on-b/Move.toml create mode 100644 crates/sui-source-validation/fixture/versioned-a-depends-on-b/sources/a.move create mode 100644 crates/sui-source-validation/fixture/versioned-b/Move.lock create mode 100644 crates/sui-source-validation/fixture/versioned-b/Move.toml create mode 100644 crates/sui-source-validation/fixture/versioned-b/sources/b.move create mode 100644 crates/sui-source-validation/fixture/versioned-b/sources/c.move create mode 100644 crates/sui-source-validation/fixture/versioned-b/sources/d.move diff --git a/Cargo.lock b/Cargo.lock index b52e891e5ceb2..6fd7fd52ba864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1638,7 +1638,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.6.2", "object", "rustc-demangle", ] @@ -1870,9 +1870,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bitmaps" @@ -3503,7 +3503,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7a532c1f99a0f596f6960a60d1e119e91582b24b39e2d83a190e61262c3ef0c" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "byteorder", "chrono", "diesel_derives", @@ -4015,13 +4015,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -4671,12 +4670,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -6138,9 +6137,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libloading" @@ -6225,9 +6224,9 @@ checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" [[package]] name = "linux-raw-sys" -version = "0.4.7" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" @@ -6474,6 +6473,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.7.14" @@ -7527,7 +7535,7 @@ dependencies = [ "prometheus", "rand 0.8.5", "serde", - "serde_yaml 0.9.29", + "serde_yaml 0.9.21", "tabled", "tempfile", "tokio", @@ -8045,7 +8053,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "crossbeam-channel", "filetime", "fsevent-sys", @@ -10281,7 +10289,7 @@ dependencies = [ "aes", "aes-gcm", "async-trait", - "bitflags 2.3.3", + "bitflags 2.4.1", "byteorder", "chacha20", "ctr", @@ -10420,7 +10428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" dependencies = [ "bitflags 1.3.2", - "errno 0.3.1", + "errno 0.3.8", "io-lifetimes", "libc", "linux-raw-sys 0.3.1", @@ -10429,15 +10437,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 2.3.3", - "errno 0.3.1", + "bitflags 2.4.1", + "errno 0.3.8", "libc", - "linux-raw-sys 0.4.7", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.12", + "windows-sys 0.52.0", ] [[package]] @@ -10857,11 +10865,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.109" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ - "indexmap 2.1.0", + "indexmap 1.9.3", "itoa", "ryu", "serde", @@ -10889,9 +10897,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" dependencies = [ "serde", ] @@ -10959,11 +10967,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.29" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129" +checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" dependencies = [ - "indexmap 2.1.0", + "indexmap 1.9.3", "itoa", "ryu", "serde", @@ -12246,7 +12254,7 @@ dependencies = [ "tempfile", "thiserror", "toml 0.7.4", - "toml_edit 0.19.15", + "toml_edit 0.19.10", "workspace-hack", ] @@ -12755,7 +12763,7 @@ dependencies = [ "prometheus-http-query", "reqwest", "serde", - "serde_yaml 0.9.29", + "serde_yaml 0.9.21", "strum_macros 0.24.3", "telemetry-subscribers", "tokio", @@ -13423,12 +13431,16 @@ dependencies = [ [[package]] name = "sui-source-validation" -version = "0.1.0" +version = "1.18.0" dependencies = [ "anyhow", + "colored", "expect-test", + "flate2", "futures", "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", "move-compiler", "move-core-types", "move-package", @@ -13439,11 +13451,13 @@ dependencies = [ "sui-sdk", "sui-test-transaction-builder", "sui-types", + "tar", "tempfile", "test-cluster", "thiserror", "tokio", "tracing", + "ureq", "workspace-hack", ] @@ -13987,7 +14001,7 @@ dependencies = [ "strum 0.24.1", "tempfile", "tokio", - "toml_edit 0.19.15", + "toml_edit 0.19.10", "tracing", "tracing-subscriber", "workspace-hack", @@ -14197,7 +14211,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.0", "redox_syscall 0.3.5", - "rustix 0.38.8", + "rustix 0.38.28", "windows-sys 0.48.0", ] @@ -14617,8 +14631,8 @@ dependencies = [ "indexmap 1.9.3", "serde", "serde_spanned", - "toml_datetime 0.6.5", - "toml_edit 0.19.15", + "toml_datetime 0.6.2", + "toml_edit 0.19.10", ] [[package]] @@ -14629,9 +14643,9 @@ checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" dependencies = [ "serde", ] @@ -14662,14 +14676,14 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.15" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" dependencies = [ - "indexmap 2.1.0", + "indexmap 1.9.3", "serde", "serde_spanned", - "toml_datetime 0.6.5", + "toml_datetime 0.6.2", "winnow", ] @@ -15211,9 +15225,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" [[package]] name = "unsigned-varint" @@ -15244,6 +15258,22 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "ureq" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" +dependencies = [ + "base64 0.21.2", + "flate2", + "log", + "once_cell", + "rustls 0.21.6", + "rustls-webpki", + "url", + "webpki-roots 0.25.2", +] + [[package]] name = "url" version = "2.3.1" @@ -15627,6 +15657,15 @@ dependencies = [ "windows-targets 0.48.0", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -15657,6 +15696,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -15669,6 +15723,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -15681,6 +15741,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -15693,6 +15759,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -15705,6 +15777,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -15717,6 +15795,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -15729,6 +15813,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -15741,11 +15831,17 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" -version = "0.5.33" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" dependencies = [ "memchr", ] @@ -15903,7 +15999,7 @@ dependencies = [ "bitcoin-private", "bitcoin_hashes", "bitflags 1.3.2", - "bitflags 2.3.3", + "bitflags 2.4.1", "bitmaps", "bitvec 0.20.4", "bitvec 1.0.1", @@ -16089,7 +16185,7 @@ dependencies = [ "enum_dispatch", "equivalent", "errno 0.2.8", - "errno 0.3.1", + "errno 0.3.8", "error-code", "eth-keystore", "ethabi", @@ -16268,7 +16364,7 @@ dependencies = [ "linked-hash-map", "linux-raw-sys 0.1.4", "linux-raw-sys 0.3.1", - "linux-raw-sys 0.4.7", + "linux-raw-sys 0.4.12", "lock_api", "log", "lru 0.10.0", @@ -16297,7 +16393,8 @@ dependencies = [ "mime_guess", "minibytes", "minimal-lexical", - "miniz_oxide", + "miniz_oxide 0.6.2", + "miniz_oxide 0.7.1", "mio 0.7.14", "mio 0.8.5", "mockall", @@ -16561,7 +16658,7 @@ dependencies = [ "rusticata-macros", "rustix 0.36.6", "rustix 0.37.7", - "rustix 0.38.8", + "rustix 0.38.28", "rustls 0.20.7", "rustls 0.21.6", "rustls-native-certs", @@ -16610,7 +16707,7 @@ dependencies = [ "serde_with", "serde_with_macros", "serde_yaml 0.8.26", - "serde_yaml 0.9.29", + "serde_yaml 0.9.21", "serial_test", "serial_test_derive", "sha-1 0.10.1", @@ -16708,10 +16805,10 @@ dependencies = [ "toml 0.5.10", "toml 0.7.4", "toml_datetime 0.5.1", - "toml_datetime 0.6.5", + "toml_datetime 0.6.2", "toml_edit 0.14.4", "toml_edit 0.15.0", - "toml_edit 0.19.15", + "toml_edit 0.19.10", "tonic 0.10.0", "tonic 0.9.2", "tonic-build", @@ -16756,6 +16853,7 @@ dependencies = [ "unsigned-varint", "untrusted 0.7.1", "unzip-n", + "ureq", "url", "urlencoding", "utf-8", @@ -16876,11 +16974,13 @@ dependencies = [ [[package]] name = "xattr" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc6ab6ec1907d1a901cdbcd2bd4cb9e7d64ce5c9739cbb97d3c391acd8c7fae" +checksum = "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1" dependencies = [ "libc", + "linux-raw-sys 0.4.12", + "rustix 0.38.28", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index afa17929a15c6..18f5b5848809f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -324,6 +324,7 @@ enum_dispatch = "^0.3" expect-test = "1.4.0" eyre = "0.6.8" fdlimit = "0.2.1" +flate2 = "1.0.28" fs_extra = "1.3.0" futures = "0.3.28" futures-core = "0.3.21" @@ -462,6 +463,7 @@ synstructure = "0.12" sysinfo = "0.27.5" tabled = { version = "0.12" } tap = "1.0.1" +tar = "0.4.40" tempfile = "3.3.0" test-fuzz = "3.0.4" thiserror = "1.0.40" @@ -507,6 +509,7 @@ tracing-subscriber = { version = "0.3.15", default-features = false, features = ttl_cache = "0.5.1" uint = "0.9.4" unescape = "0.1.0" +ureq = "2.9.1" url = "2.3.1" uuid = { version = "1.1.2", features = ["v4", "fast-rng"] } webpki = { version = "0.101.0", package = "rustls-webpki", features = [ @@ -521,6 +524,7 @@ versions = "4.1.0" # Move dependencies move-binary-format = { path = "external-crates/move/crates/move-binary-format" } move-bytecode-utils = { path = "external-crates/move/crates/move-bytecode-utils" } +move-bytecode-source-map = { path = "external-crates/move/crates/move-bytecode-source-map" } move-cli = { path = "external-crates/move/crates/move-cli" } move-compiler = { path = "external-crates/move/crates/move-compiler" } move-core-types = { path = "external-crates/move/crates/move-core-types" } diff --git a/crates/sui-source-validation/Cargo.toml b/crates/sui-source-validation/Cargo.toml index 9e0a56130b6b8..18e5728b2335c 100644 --- a/crates/sui-source-validation/Cargo.toml +++ b/crates/sui-source-validation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sui-source-validation" -version = "0.1.0" +version.workspace = true authors = ["Mysten Labs "] license = "Apache-2.0" publish = false @@ -11,7 +11,9 @@ path = "src/lib.rs" [dependencies] anyhow.workspace = true +colored.workspace = true thiserror.workspace = true +tracing.workspace = true futures.workspace = true sui-json-rpc-types.workspace = true @@ -20,12 +22,20 @@ sui-sdk.workspace = true sui-move-build.workspace = true move-binary-format.workspace = true +move-bytecode-source-map.workspace = true +move-command-line-common.workspace = true move-compiler.workspace = true move-core-types.workspace = true move-package.workspace = true move-symbol-pool.workspace = true + +tar.workspace = true +tempfile.workspace = true +flate2.workspace = true +ureq.workspace = true workspace-hack.workspace = true + [dev-dependencies] expect-test.workspace = true diff --git a/crates/sui-source-validation/fixture/versioned-a-depends-on-b/Move.toml b/crates/sui-source-validation/fixture/versioned-a-depends-on-b/Move.toml new file mode 100644 index 0000000000000..9bef6d2b789c9 --- /dev/null +++ b/crates/sui-source-validation/fixture/versioned-a-depends-on-b/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "a" +version = "0.0.1" +published-at = "$STORAGE_ID" + +[dependencies] +b = { local = "../versioned-b" } + +[addresses] +a = "$RUNTIME_ID" diff --git a/crates/sui-source-validation/fixture/versioned-a-depends-on-b/sources/a.move b/crates/sui-source-validation/fixture/versioned-a-depends-on-b/sources/a.move new file mode 100644 index 0000000000000..11a8793f137c8 --- /dev/null +++ b/crates/sui-source-validation/fixture/versioned-a-depends-on-b/sources/a.move @@ -0,0 +1,11 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module a::a { + use b::b::b; + use b::b::c; + + public fun a() : u64 { + b() + c() + } +} diff --git a/crates/sui-source-validation/fixture/versioned-b/Move.lock b/crates/sui-source-validation/fixture/versioned-b/Move.lock new file mode 100644 index 0000000000000..1a4025d6561d0 --- /dev/null +++ b/crates/sui-source-validation/fixture/versioned-b/Move.lock @@ -0,0 +1,11 @@ +# @generated by Move, please check-in and do not edit manually. + +[move] +version = 0 +manifest_digest = "C70E0438875A0C3B10FA5995F317F701134E629D1B2E5F3DCA3621E50034F809" +deps_digest = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" + +[move.toolchain-version] +compiler-version = "$COMPILER_VERSION" +edition = "legacy" +flavor = "sui" diff --git a/crates/sui-source-validation/fixture/versioned-b/Move.toml b/crates/sui-source-validation/fixture/versioned-b/Move.toml new file mode 100644 index 0000000000000..d369173206855 --- /dev/null +++ b/crates/sui-source-validation/fixture/versioned-b/Move.toml @@ -0,0 +1,7 @@ +[package] +name = "b" +version = "0.0.2" +published-at = "$STORAGE_ID" + +[addresses] +b = "$RUNTIME_ID" diff --git a/crates/sui-source-validation/fixture/versioned-b/sources/b.move b/crates/sui-source-validation/fixture/versioned-b/sources/b.move new file mode 100644 index 0000000000000..1ffd27a1b91f2 --- /dev/null +++ b/crates/sui-source-validation/fixture/versioned-b/sources/b.move @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module b::b { + public fun b(): u64 { + 42 + } + + public fun c(): u64 { + b() + 1 + } +} diff --git a/crates/sui-source-validation/fixture/versioned-b/sources/c.move b/crates/sui-source-validation/fixture/versioned-b/sources/c.move new file mode 100644 index 0000000000000..fab61c011c983 --- /dev/null +++ b/crates/sui-source-validation/fixture/versioned-b/sources/c.move @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module b::c { + public fun c(): u64 { + 43 + } +} diff --git a/crates/sui-source-validation/fixture/versioned-b/sources/d.move b/crates/sui-source-validation/fixture/versioned-b/sources/d.move new file mode 100644 index 0000000000000..afda18d7d3fd3 --- /dev/null +++ b/crates/sui-source-validation/fixture/versioned-b/sources/d.move @@ -0,0 +1,8 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module b::d { + public fun d(): u64 { + 44 + } +} diff --git a/crates/sui-source-validation/src/lib.rs b/crates/sui-source-validation/src/lib.rs index 4d550257f824e..19973bfc43991 100644 --- a/crates/sui-source-validation/src/lib.rs +++ b/crates/sui-source-validation/src/lib.rs @@ -1,18 +1,42 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +use anyhow::{anyhow, bail, ensure}; +use colored::Colorize; use core::fmt; use futures::future; use move_binary_format::access::ModuleAccess; use move_binary_format::CompiledModule; +use move_bytecode_source_map::utils::source_map_from_file; +use move_compiler::editions::{Edition, Flavor}; +use move_compiler::shared::NumericalAddress; +use move_package::compilation::package_layout::CompiledPackageLayout; +use move_package::lock_file::schema::{Header, ToolchainVersion}; +use move_package::source_package::layout::SourcePackageLayout; +use move_package::source_package::parsed_manifest::{FileName, PackageName}; +use std::ffi::OsStr; +use std::fs::File; +use std::io::{self, Seek}; +use std::path::{Path, PathBuf}; +use std::process::Command; use std::{collections::HashMap, fmt::Debug}; use sui_move_build::CompiledPackage; use sui_types::error::SuiObjectResponseError; +use tar::Archive; +use tempfile::TempDir; use thiserror::Error; +use tracing::{debug, info}; +use move_command_line_common::env::MOVE_HOME; +use move_command_line_common::files::MOVE_COMPILED_EXTENSION; +use move_command_line_common::files::{ + extension_equals, find_filenames, MOVE_EXTENSION, SOURCE_MAP_EXTENSION, +}; use move_compiler::compiled_unit::NamedCompiledModule; use move_core_types::account_address::AccountAddress; -use move_package::compilation::compiled_package::CompiledPackage as MoveCompiledPackage; +use move_package::compilation::compiled_package::{ + CompiledPackage as MoveCompiledPackage, CompiledUnitWithSource, +}; use move_symbol_pool::Symbol; use sui_sdk::apis::ReadApi; use sui_sdk::error::Error; @@ -23,6 +47,11 @@ use sui_types::base_types::ObjectID; #[cfg(test)] mod tests; +const CURRENT_COMPILER_VERSION: &str = env!("CARGO_PKG_VERSION"); +const LEGACY_COMPILER_VERSION: &str = CURRENT_COMPILER_VERSION; // TODO: update this when Move 2024 is released +const PRE_TOOLCHAIN_MOVE_LOCK_VERSION: u64 = 0; // Used to detect lockfiles pre-toolchain versioning support +const CANONICAL_BINARY_NAME: &str = "sui"; + #[derive(Debug, Error)] pub enum SourceVerificationError { #[error("Could not read a dependency's on-chain object: {0:?}")] @@ -58,6 +87,9 @@ pub enum SourceVerificationError { module: Symbol, }, + #[error("Cannot check local module for {package}: {message}")] + CannotCheckLocalModules { package: Symbol, message: String }, + #[error("On-chain address cannot be zero")] ZeroOnChainAddresSpecifiedFailure, @@ -331,7 +363,14 @@ fn local_modules( let mut map = LocalModules::new(); if include_deps { - for (package, local_unit) in &compiled_package.deps_compiled_units { + // Compile dependencies with prior compilers if needed. + let deps_compiled_units = units_for_toolchain(&compiled_package.deps_compiled_units) + .map_err(|e| SourceVerificationError::CannotCheckLocalModules { + package: compiled_package.compiled_package_info.package_name, + message: e.to_string(), + })?; + + for (package, local_unit) in deps_compiled_units { let m = &local_unit.unit; let module = m.name; let address = m.address.into_inner(); @@ -339,7 +378,7 @@ fn local_modules( continue; } - map.insert((address, module), (*package, m.module.clone())); + map.insert((address, module), (package, m.module.clone())); } } @@ -349,7 +388,23 @@ fn local_modules( // Include the root compiled units, at their current addresses. SourceMode::Verify => { - for local_unit in &compiled_package.root_compiled_units { + // Compile root modules with prior compiler if needed. + let root_compiled_units = { + let root_compiled_units = compiled_package + .root_compiled_units + .iter() + .map(|u| ("root".into(), u.clone())) + .collect::>(); + + units_for_toolchain(&root_compiled_units).map_err(|e| { + SourceVerificationError::CannotCheckLocalModules { + package: compiled_package.compiled_package_info.package_name, + message: e.to_string(), + } + })? + }; + + for (_, local_unit) in root_compiled_units { let m = &local_unit.unit; let module = m.name; @@ -368,7 +423,23 @@ fn local_modules( // Include the root compiled units, and any unpublished dependencies with their // addresses substituted SourceMode::VerifyAt(root_address) => { - for local_unit in &compiled_package.root_compiled_units { + // Compile root modules with prior compiler if needed. + let root_compiled_units = { + let root_compiled_units = compiled_package + .root_compiled_units + .iter() + .map(|u| ("root".into(), u.clone())) + .collect::>(); + + units_for_toolchain(&root_compiled_units).map_err(|e| { + SourceVerificationError::CannotCheckLocalModules { + package: compiled_package.compiled_package_info.package_name, + message: e.to_string(), + } + })? + }; + + for (_, local_unit) in root_compiled_units { let m = &local_unit.unit; let module = m.name; @@ -396,3 +467,306 @@ fn local_modules( Ok(map) } + +fn current_toolchain() -> ToolchainVersion { + ToolchainVersion { + compiler_version: CURRENT_COMPILER_VERSION.into(), + edition: Edition::LEGACY, /* does not matter, unused for current_toolchain */ + flavor: Flavor::Sui, /* does not matter, unused for current_toolchain */ + } +} + +fn legacy_toolchain() -> ToolchainVersion { + ToolchainVersion { + compiler_version: LEGACY_COMPILER_VERSION.into(), + edition: Edition::LEGACY, + flavor: Flavor::Sui, + } +} + +/// Ensures `compiled_units` are compiled with the right compiler version, based on +/// Move.lock contents. This works by detecting if a compiled unit requires a prior compiler version: +/// - If so, download the compiler, recompile the unit, and return that unit in the result. +/// - If not, simply keep the current compiled unit. +fn units_for_toolchain( + compiled_units: &Vec<(PackageName, CompiledUnitWithSource)>, +) -> anyhow::Result> { + if std::env::var("SUI_RUN_TOOLCHAIN_BUILD").is_err() { + return Ok(compiled_units.clone()); + } + let mut package_version_map: HashMap)> = + HashMap::new(); + // First iterate over packages, mapping the required version for each package in `package_version_map`. + for (package, local_unit) in compiled_units { + if let Some((_, units)) = package_version_map.get_mut(package) { + // We've processed this package's required version. + units.push(local_unit.clone()); + continue; + } + + if sui_types::is_system_package(local_unit.unit.address.into_inner()) { + // System packages are always compiled with the current compiler. + package_version_map.insert(*package, (current_toolchain(), vec![local_unit.clone()])); + continue; + } + + let package_root = SourcePackageLayout::try_find_root(&local_unit.source_path)?; + let lock_file = package_root.join("Move.lock"); + if !lock_file.exists() { + // No lock file implies current compiler for this package. + package_version_map.insert(*package, (current_toolchain(), vec![local_unit.clone()])); + continue; + } + + let mut lock_file = File::open(lock_file)?; + let lock_version = Header::read(&mut lock_file)?.version; + if lock_version == PRE_TOOLCHAIN_MOVE_LOCK_VERSION { + // No need to attempt reading lock file toolchain + debug!("{package} on legacy compiler",); + package_version_map.insert(*package, (legacy_toolchain(), vec![local_unit.clone()])); + continue; + } + + // Read lock file toolchain info + lock_file.rewind()?; + let toolchain_version = ToolchainVersion::read(&mut lock_file)?; + match toolchain_version { + // No ToolchainVersion and new Move.lock version implies current compiler. + None => { + debug!("{package} on current compiler @ {CURRENT_COMPILER_VERSION}",); + package_version_map + .insert(*package, (current_toolchain(), vec![local_unit.clone()])); + } + // This dependency uses the current compiler. + Some(ToolchainVersion { + compiler_version, .. + }) if compiler_version == CURRENT_COMPILER_VERSION => { + debug!("{package} on current compiler @ {CURRENT_COMPILER_VERSION}",); + package_version_map + .insert(*package, (current_toolchain(), vec![local_unit.clone()])); + } + // This dependency needs a prior compiler. Mark it and compile. + Some(toolchain_version) => { + println!( + "{} {package} compiler @ {}", + "REQUIRE".bold().green(), + toolchain_version.compiler_version.yellow(), + ); + package_version_map.insert(*package, (toolchain_version, vec![local_unit.clone()])); + } + } + } + + let mut units = vec![]; + // Iterate over compiled units, and check if they need to be recompiled and replaced by a prior compiler's output. + for (package, (toolchain_version, local_units)) in package_version_map { + if toolchain_version.compiler_version == CURRENT_COMPILER_VERSION { + let local_units: Vec<_> = local_units.iter().map(|u| (package, u.clone())).collect(); + units.extend(local_units); + continue; + } + + if local_units.is_empty() { + bail!("Expected one or more modules, but none found"); + } + let package_root = SourcePackageLayout::try_find_root(&local_units[0].source_path)?; + let install_dir = tempfile::tempdir()?; // place compiled packages in this temp dir, don't pollute this packages build dir + download_and_compile( + package_root.clone(), + &install_dir, + &toolchain_version, + &package, + )?; + + let compiled_unit_paths = vec![package_root.clone()]; + let compiled_units = find_filenames(&compiled_unit_paths, |path| { + extension_equals(path, MOVE_COMPILED_EXTENSION) + })?; + let build_path = install_dir + .path() + .join(CompiledPackageLayout::path(&CompiledPackageLayout::Root)) + .join(package.as_str()); + debug!("build path is {}", build_path.display()); + + // Add all units compiled with the previous compiler. + for bytecode_path in compiled_units { + info!("bytecode path {bytecode_path}, {package}"); + let local_unit = decode_bytecode_file(build_path.clone(), &package, &bytecode_path)?; + units.push((package, local_unit)) + } + } + Ok(units) +} + +fn download_and_compile( + root: PathBuf, + install_dir: &TempDir, + ToolchainVersion { + compiler_version, + edition, + flavor, + }: &ToolchainVersion, + dep_name: &Symbol, +) -> anyhow::Result<()> { + let dest_dir = PathBuf::from_iter([&*MOVE_HOME, "binaries"]); // E.g., ~/.move/binaries + let dest_version = dest_dir.join(compiler_version); + let mut dest_canonical_binary = dest_version.clone(); + dest_canonical_binary.extend(["target", "release", CANONICAL_BINARY_NAME]); + + if !dest_canonical_binary.exists() { + // Check the platform and proceed if we can download a binary. If not, the user should follow error instructions to sideload the binary. + let platform = detect_platform(&root, compiler_version, &dest_canonical_binary)?; + // Download if binary does not exist. + let url = format!("https://github.com/MystenLabs/sui/releases/download/mainnet-v{}/sui-mainnet-v{}-{}.tgz", compiler_version, compiler_version, platform); + + println!( + "{} compiler @ {} (this may take a while)", + "DOWNLOADING".bold().green(), + compiler_version.yellow() + ); + + let mut response = ureq::get(&url).call()?.into_reader(); + let dest_tarball = dest_version.join(format!("{}.tgz", compiler_version)); + debug!("tarball destination: {} ", dest_tarball.display()); + if let Some(parent) = dest_tarball.parent() { + std::fs::create_dir_all(parent) + .map_err(|e| anyhow!("failed to create directory for tarball: {e}"))?; + } + let mut dest_file = File::create(&dest_tarball)?; + io::copy(&mut response, &mut dest_file)?; + + // Extract the tarball using the tar crate + let tar_gz = File::open(&dest_tarball)?; + let tar = flate2::read::GzDecoder::new(tar_gz); + let mut archive = Archive::new(tar); + archive + .unpack(&dest_version) + .map_err(|e| anyhow!("failed to untar compiler binary: {e}"))?; + + let mut dest_binary = dest_version.clone(); + dest_binary.extend(["target", "release", &format!("sui-{platform}")]); + let dest_binary_os = OsStr::new(dest_binary.as_path()); + set_executable_permission(dest_binary_os)?; + std::fs::rename(dest_binary_os, dest_canonical_binary.clone())?; + } + + debug!( + "{} move build --default-move-edition {} --default-move-flavor {} -p {} --install-dir {}", + dest_canonical_binary.display(), + edition.to_string().as_str(), + flavor.to_string().as_str(), + root.display(), + install_dir.path().display(), + ); + info!( + "{} {} (compiler @ {})", + "BUILDING".bold().green(), + dep_name.as_str(), + compiler_version.yellow() + ); + Command::new(dest_canonical_binary) + .args([ + OsStr::new("move"), + OsStr::new("build"), + OsStr::new("--default-move-edition"), + OsStr::new(edition.to_string().as_str()), + OsStr::new("--default-move-flavor"), + OsStr::new(flavor.to_string().as_str()), + OsStr::new("-p"), + OsStr::new(root.as_path()), + OsStr::new("--install-dir"), + OsStr::new(install_dir.path()), + ]) + .output() + .map_err(|e| { + anyhow!("failed to build package from compiler binary {compiler_version}: {e}",) + })?; + Ok(()) +} + +fn detect_platform( + package_path: &Path, + compiler_version: &String, + dest_dir: &Path, +) -> anyhow::Result { + let s = match (std::env::consts::OS, std::env::consts::ARCH) { + ("macos", "aarch64") => "macos-arm64", + ("macos", "x86_64") => "macos-x86_64", + ("linux", "x86_64") => "ubuntu-x86_64", + ("windows", "x86_64") => "windows-x86_64", + (os, arch) => bail!( + "The package {} needs to be built with sui compiler version {compiler_version} but there \ + is no binary release available to download for your platform:\n\ + Operating System: {os}\n\ + Architecture: {arch}\n\ + You can manually put a `sui` binary for your platform in {} and rerun your command to continue.", + package_path.display(), + dest_dir.display(), + ), + }; + Ok(s.into()) +} + +#[cfg(unix)] +fn set_executable_permission(path: &OsStr) -> anyhow::Result<()> { + use std::fs; + use std::os::unix::prelude::PermissionsExt; + let mut perms = fs::metadata(path)?.permissions(); + perms.set_mode(0o755); + fs::set_permissions(path, perms)?; + Ok(()) +} + +#[cfg(not(unix))] +fn set_executable_permission(path: &OsStr) -> anyhow::Result<()> { + Command::new("icacls") + .args([path, OsStr::new("/grant"), OsStr::new("Everyone:(RX)")]) + .status()?; + Ok(()) +} + +fn decode_bytecode_file( + root_path: PathBuf, + package_name: &Symbol, + bytecode_path_str: &str, +) -> anyhow::Result { + let package_name_opt = Some(*package_name); + let bytecode_path = Path::new(bytecode_path_str); + let path_to_file = CompiledPackageLayout::path_to_file_after_category(bytecode_path); + let bytecode_bytes = std::fs::read(bytecode_path)?; + let source_map = source_map_from_file( + &root_path + .join(CompiledPackageLayout::SourceMaps.path()) + .join(&path_to_file) + .with_extension(SOURCE_MAP_EXTENSION), + )?; + let source_path = &root_path + .join(CompiledPackageLayout::Sources.path()) + .join(path_to_file) + .with_extension(MOVE_EXTENSION); + ensure!( + source_path.is_file(), + "Error decoding package: Unable to find corresponding source file for '{bytecode_path_str}' in package {package_name}" + ); + let module = CompiledModule::deserialize_with_defaults(&bytecode_bytes)?; + let (address_bytes, module_name) = { + let id = module.self_id(); + let parsed_addr = NumericalAddress::new( + id.address().into_bytes(), + move_compiler::shared::NumberFormat::Hex, + ); + let module_name = FileName::from(id.name().as_str()); + (parsed_addr, module_name) + }; + let unit = NamedCompiledModule { + package_name: package_name_opt, + address: address_bytes, + name: module_name, + module, + source_map, + }; + Ok(CompiledUnitWithSource { + unit, + source_path: source_path.clone(), + }) +} diff --git a/crates/sui-source-validation/src/tests.rs b/crates/sui-source-validation/src/tests.rs index bde1209296a8e..25c942e22f73f 100644 --- a/crates/sui-source-validation/src/tests.rs +++ b/crates/sui-source-validation/src/tests.rs @@ -21,29 +21,29 @@ use sui_types::{ }; use test_cluster::TestClusterBuilder; -use crate::{BytecodeSourceVerifier, SourceMode}; +use crate::{BytecodeSourceVerifier, SourceMode, CURRENT_COMPILER_VERSION}; #[tokio::test] async fn successful_verification() -> anyhow::Result<()> { let mut cluster = TestClusterBuilder::new().build().await; let context = &mut cluster.wallet; + let b_ref_fixtures = tempfile::tempdir()?; let b_ref = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; publish_package(context, b_src).await.0 }; + let b_pkg_fixtures = tempfile::tempdir()?; let b_pkg = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", b_ref.0.into()).await?; + let b_src = copy_published_package(&b_pkg_fixtures, "b", b_ref.0.into()).await?; compile_package(b_src) }; + let a_fixtures = tempfile::tempdir()?; let (a_pkg, a_ref) = { - let fixtures = tempfile::tempdir()?; - copy_published_package(&fixtures, "b", b_ref.0.into()).await?; - let a_src = copy_published_package(&fixtures, "a", SuiAddress::ZERO).await?; + copy_published_package(&a_fixtures, "b", b_ref.0.into()).await?; + let a_src = copy_published_package(&a_fixtures, "a", SuiAddress::ZERO).await?; ( compile_package(a_src.clone()), publish_package(context, a_src).await.0, @@ -122,15 +122,15 @@ async fn successful_verification_module_ordering() -> anyhow::Result<()> { // where the on-chain package (which is compiled with self-address = 0x0, and later substituted) // orders module handles (references to other modules) differently to the package compiled as a // dependency with its self-address already set as its published address. + let z_ref_fixtures = tempfile::tempdir()?; let z_ref = { - let fixtures = tempfile::tempdir()?; - let z_src = copy_published_package(&fixtures, "z", SuiAddress::ZERO).await?; + let z_src = copy_published_package(&z_ref_fixtures, "z", SuiAddress::ZERO).await?; publish_package(context, z_src).await.0 }; + let z_pkg_fixtures = tempfile::tempdir()?; let z_pkg = { - let fixtures = tempfile::tempdir()?; - let z_src = copy_published_package(&fixtures, "z", z_ref.0.into()).await?; + let z_src = copy_published_package(&z_pkg_fixtures, "z", z_ref.0.into()).await?; compile_package(z_src) }; @@ -151,22 +151,23 @@ async fn successful_verification_upgrades() -> anyhow::Result<()> { let mut cluster = TestClusterBuilder::new().build().await; let context = &mut cluster.wallet; + let b_v1_fixtures = tempfile::tempdir()?; let (b_v1, b_cap) = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_v1_fixtures, "b", SuiAddress::ZERO).await?; publish_package(context, b_src).await }; + let b_v2_fixtures = tempfile::tempdir()?; let b_v2 = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b-v2", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_v2_fixtures, "b-v2", SuiAddress::ZERO).await?; upgrade_package(context, b_v1.0, b_cap.0, b_src).await }; + let b_fixtures = tempfile::tempdir()?; let (b_pkg, e_pkg) = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_upgraded_package(&fixtures, "b-v2", b_v2.0.into(), b_v1.0.into()).await?; - let e_src = copy_published_package(&fixtures, "e", SuiAddress::ZERO).await?; + let b_src = + copy_upgraded_package(&b_fixtures, "b-v2", b_v2.0.into(), b_v1.0.into()).await?; + let e_src = copy_published_package(&b_fixtures, "e", SuiAddress::ZERO).await?; (compile_package(b_src), compile_package(e_src)) }; @@ -191,16 +192,16 @@ async fn fail_verification_bad_address() -> anyhow::Result<()> { let mut cluster = TestClusterBuilder::new().build().await; let context = &mut cluster.wallet; + let b_ref_fixtures = tempfile::tempdir()?; let b_ref = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; publish_package(context, b_src).await.0 }; + let a_pkg_fixtures = tempfile::tempdir()?; let a_pkg = { - let fixtures = tempfile::tempdir()?; - copy_published_package(&fixtures, "b", b_ref.0.into()).await?; - let a_src = copy_published_package(&fixtures, "a", SuiAddress::ZERO).await?; + copy_published_package(&a_pkg_fixtures, "b", b_ref.0.into()).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; publish_package(context, a_src.clone()).await; compile_package(a_src) }; @@ -225,9 +226,9 @@ async fn fail_to_verify_unpublished_root() -> anyhow::Result<()> { let mut cluster = TestClusterBuilder::new().build().await; let context = &mut cluster.wallet; + let b_pkg_fixtures = tempfile::tempdir()?; let b_pkg = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_pkg_fixtures, "b", SuiAddress::ZERO).await?; compile_package(b_src) }; @@ -253,16 +254,16 @@ async fn rpc_call_failed_during_verify() -> anyhow::Result<()> { let mut cluster = TestClusterBuilder::new().build().await; let context = &mut cluster.wallet; + let b_ref_fixtures = tempfile::tempdir()?; let b_ref = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; publish_package(context, b_src).await.0 }; + let a_ref_fixtures = tempfile::tempdir()?; let a_ref = { - let fixtures = tempfile::tempdir()?; - copy_published_package(&fixtures, "b", b_ref.0.into()).await?; - let a_src = copy_published_package(&fixtures, "a", SuiAddress::ZERO).await?; + copy_published_package(&a_ref_fixtures, "b", b_ref.0.into()).await?; + let a_src = copy_published_package(&a_ref_fixtures, "a", SuiAddress::ZERO).await?; publish_package(context, a_src).await.0 }; let _a_addr: SuiAddress = a_ref.0.into(); @@ -306,12 +307,12 @@ async fn package_not_found() -> anyhow::Result<()> { let context = &mut cluster.wallet; let mut stable_addrs = HashMap::new(); + let a_pkg_fixtures = tempfile::tempdir()?; let a_pkg = { - let fixtures = tempfile::tempdir()?; let b_id = SuiAddress::random_for_testing_only(); stable_addrs.insert(b_id, ""); - copy_published_package(&fixtures, "b", b_id).await?; - let a_src = copy_published_package(&fixtures, "a", SuiAddress::ZERO).await?; + copy_published_package(&a_pkg_fixtures, "b", b_id).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; compile_package(a_src) }; @@ -359,11 +360,11 @@ async fn dependency_is_an_object() -> anyhow::Result<()> { let mut cluster = TestClusterBuilder::new().build().await; let context = &mut cluster.wallet; + let a_pkg_fixtures = tempfile::tempdir()?; let a_pkg = { - let fixtures = tempfile::tempdir()?; let b_id = SUI_SYSTEM_STATE_OBJECT_ID.into(); - copy_published_package(&fixtures, "b", b_id).await?; - let a_src = copy_published_package(&fixtures, "a", SuiAddress::ZERO).await?; + copy_published_package(&a_pkg_fixtures, "b", b_id).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; compile_package(a_src) }; let client = context.get_client().await?; @@ -386,17 +387,17 @@ async fn module_not_found_on_chain() -> anyhow::Result<()> { let mut cluster = TestClusterBuilder::new().build().await; let context = &mut cluster.wallet; + let b_ref_fixtures = tempfile::tempdir()?; let b_ref = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; tokio::fs::remove_file(b_src.join("sources").join("c.move")).await?; publish_package(context, b_src).await.0 }; + let a_pkg_fixtures = tempfile::tempdir()?; let a_pkg = { - let fixtures = tempfile::tempdir()?; - copy_published_package(&fixtures, "b", b_ref.0.into()).await?; - let a_src = copy_published_package(&fixtures, "a", SuiAddress::ZERO).await?; + copy_published_package(&a_pkg_fixtures, "b", b_ref.0.into()).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; compile_package(a_src) }; let client = context.get_client().await?; @@ -418,18 +419,18 @@ async fn module_not_found_locally() -> anyhow::Result<()> { let context = &mut cluster.wallet; let mut stable_addrs = HashMap::new(); + let b_ref_fixtures = tempfile::tempdir()?; let b_ref = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; publish_package(context, b_src).await.0 }; + let a_pkg_fixtures = tempfile::tempdir()?; let a_pkg = { - let fixtures = tempfile::tempdir()?; let b_id = b_ref.0.into(); stable_addrs.insert(b_id, "b_id"); - let b_src = copy_published_package(&fixtures, "b", b_id).await?; - let a_src = copy_published_package(&fixtures, "a", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&a_pkg_fixtures, "b", b_id).await?; + let a_src = copy_published_package(&a_pkg_fixtures, "a", SuiAddress::ZERO).await?; tokio::fs::remove_file(b_src.join("sources").join("d.move")).await?; compile_package(a_src) }; @@ -453,9 +454,9 @@ async fn module_bytecode_mismatch() -> anyhow::Result<()> { let context = &mut cluster.wallet; let mut stable_addrs = HashMap::new(); + let b_ref_fixtures = tempfile::tempdir()?; let b_ref = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; // Modify a module before publishing let c_path = b_src.join("sources").join("c.move"); @@ -467,12 +468,12 @@ async fn module_bytecode_mismatch() -> anyhow::Result<()> { publish_package(context, b_src).await.0 }; + let a_fixtures = tempfile::tempdir()?; let (a_pkg, a_ref) = { - let fixtures = tempfile::tempdir()?; let b_id = b_ref.0.into(); stable_addrs.insert(b_id, ""); - copy_published_package(&fixtures, "b", b_id).await?; - let a_src = copy_published_package(&fixtures, "a", SuiAddress::ZERO).await?; + copy_published_package(&a_fixtures, "b", b_id).await?; + let a_src = copy_published_package(&a_fixtures, "a", SuiAddress::ZERO).await?; let compiled = compile_package(a_src.clone()); // Modify a module before publishing @@ -514,32 +515,32 @@ async fn multiple_failures() -> anyhow::Result<()> { let mut stable_addrs = HashMap::new(); // Publish package `b::b` on-chain without c.move. + let b_ref_fixtures = tempfile::tempdir()?; let b_ref = { - let fixtures = tempfile::tempdir()?; - let b_src = copy_published_package(&fixtures, "b", SuiAddress::ZERO).await?; + let b_src = copy_published_package(&b_ref_fixtures, "b", SuiAddress::ZERO).await?; tokio::fs::remove_file(b_src.join("sources").join("c.move")).await?; publish_package(context, b_src).await.0 }; // Publish package `c::c` on-chain, unmodified. + let c_ref_fixtures = tempfile::tempdir()?; let c_ref = { - let fixtures = tempfile::tempdir()?; - let c_src = copy_published_package(&fixtures, "c", SuiAddress::ZERO).await?; + let c_src = copy_published_package(&c_ref_fixtures, "c", SuiAddress::ZERO).await?; publish_package(context, c_src).await.0 }; // Compile local package `d` that references: // - `b::b` (c.move exists locally but not on chain => error) // - `c::c` (d.move exists on-chain but we delete it locally before compiling => error) + let d_pkg_fixtures = tempfile::tempdir()?; let d_pkg = { - let fixtures = tempfile::tempdir()?; let b_id = b_ref.0.into(); let c_id = c_ref.0.into(); stable_addrs.insert(b_id, ""); stable_addrs.insert(c_id, ""); - copy_published_package(&fixtures, "b", b_id).await?; - let c_src = copy_published_package(&fixtures, "c", c_id).await?; - let d_src = copy_published_package(&fixtures, "d", SuiAddress::ZERO).await?; + copy_published_package(&d_pkg_fixtures, "b", b_id).await?; + let c_src = copy_published_package(&d_pkg_fixtures, "c", c_id).await?; + let d_src = copy_published_package(&d_pkg_fixtures, "d", SuiAddress::ZERO).await?; tokio::fs::remove_file(c_src.join("sources").join("d.move")).await?; // delete local module in `c` compile_package(d_src) }; @@ -561,6 +562,36 @@ async fn multiple_failures() -> anyhow::Result<()> { Ok(()) } +#[tokio::test] +async fn successful_versioned_dependency_verification() -> anyhow::Result<()> { + let mut cluster = TestClusterBuilder::new().build().await; + let context = &mut cluster.wallet; + + let b_ref_fixtures = tempfile::tempdir()?; + let b_ref = { + let b_src = + copy_published_package(&b_ref_fixtures, "versioned-b", SuiAddress::ZERO).await?; + publish_package(context, b_src).await.0 + }; + + let a_fixtures = tempfile::tempdir()?; + let a_pkg = { + copy_published_package(&a_fixtures, "versioned-b", b_ref.0.into()).await?; + let a_src = + copy_published_package(&a_fixtures, "versioned-a-depends-on-b", SuiAddress::ZERO) + .await?; + compile_package(a_src.clone()) + }; + + let client = context.get_client().await?; + let verifier = BytecodeSourceVerifier::new(client.read_api()); + + // Verify versioned dependency + verifier.verify_package_deps(&a_pkg).await.unwrap(); + + Ok(()) +} + /// Compile the package at absolute path `package`. fn compile_package(package: impl AsRef) -> CompiledPackage { move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks)); @@ -659,6 +690,14 @@ async fn copy_upgraded_package<'s>( toml = toml.replace("$RUNTIME_ID", &runtime_id.to_string()); tokio::fs::write(dst.join("Move.toml"), toml).await?; + // Copy Move.lock file if it exists, performing replacements + let lock_file = src.join("Move.lock"); + if lock_file.exists() { + let mut toml = tokio::fs::read_to_string(lock_file).await?; + toml = toml.replace("$COMPILER_VERSION", CURRENT_COMPILER_VERSION); + tokio::fs::write(dst.join("Move.lock"), toml).await?; + } + // Make destination source directory tokio::fs::create_dir(dst.join("sources")).await?; diff --git a/crates/workspace-hack/Cargo.toml b/crates/workspace-hack/Cargo.toml index c932fccc2de6b..147d9473b1142 100644 --- a/crates/workspace-hack/Cargo.toml +++ b/crates/workspace-hack/Cargo.toml @@ -453,7 +453,8 @@ mime = { version = "0.3", default-features = false } mime_guess = { version = "2", default-features = false } minibytes = { git = "https://github.com/MystenLabs/mysticeti", rev = "318d61d27f47d257d99a86983d835e9e9756bc59", default-features = false, features = ["frommmap"] } minimal-lexical = { version = "0.2", default-features = false, features = ["std"] } -miniz_oxide = { version = "0.6", default-features = false, features = ["with-alloc"] } +miniz_oxide-3b31131e45eafb45 = { package = "miniz_oxide", version = "0.6", default-features = false } +miniz_oxide-ca01ad9e24f5d932 = { package = "miniz_oxide", version = "0.7", default-features = false, features = ["with-alloc"] } mio-c38e5c1d305a1b54 = { package = "mio", version = "0.8", features = ["net", "os-ext"] } mockall = { version = "0.11", default-features = false } more-asserts = { version = "0.3", default-features = false } @@ -817,6 +818,7 @@ universal-hash = { version = "0.5", default-features = false } unsafe-libyaml = { version = "0.2", default-features = false } unsigned-varint = { version = "0.7", default-features = false, features = ["std"] } untrusted = { version = "0.7", default-features = false } +ureq = { version = "2" } url = { version = "2", features = ["serde"] } urlencoding = { version = "2", default-features = false } utf-8 = { version = "0.7", default-features = false } @@ -831,10 +833,11 @@ walkdir = { version = "2", default-features = false } want = { version = "0.3", default-features = false } wasm-bindgen = { version = "0.2" } webpki = { version = "0.22", default-features = false, features = ["std"] } +webpki-roots-2ffb4c3fe830441c = { package = "webpki-roots", version = "0.25", default-features = false } webpki-roots-3c51e837cfc5589a = { package = "webpki-roots", version = "0.22", default-features = false } whoami = { version = "1" } winapi = { version = "0.3", default-features = false, features = ["basetsd", "memoryapi", "minwindef"] } -winnow = { version = "0.5" } +winnow = { version = "0.4" } wyz-6f8ce4dd05d13bba = { package = "wyz", version = "0.2", default-features = false, features = ["alloc"] } wyz-d8f496e17d97b5cb = { package = "wyz", version = "0.5", default-features = false } x509-parser = { version = "0.14" } @@ -1352,7 +1355,8 @@ mime = { version = "0.3", default-features = false } mime_guess = { version = "2", default-features = false } minibytes = { git = "https://github.com/MystenLabs/mysticeti", rev = "318d61d27f47d257d99a86983d835e9e9756bc59", default-features = false, features = ["frommmap"] } minimal-lexical = { version = "0.2", default-features = false, features = ["std"] } -miniz_oxide = { version = "0.6", default-features = false, features = ["with-alloc"] } +miniz_oxide-3b31131e45eafb45 = { package = "miniz_oxide", version = "0.6", default-features = false } +miniz_oxide-ca01ad9e24f5d932 = { package = "miniz_oxide", version = "0.7", default-features = false, features = ["with-alloc"] } mio-c38e5c1d305a1b54 = { package = "mio", version = "0.8", features = ["net", "os-ext"] } mockall = { version = "0.11", default-features = false } mockall_derive = { version = "0.11", default-features = false } @@ -1785,6 +1789,7 @@ unsafe-libyaml = { version = "0.2", default-features = false } unsigned-varint = { version = "0.7", default-features = false, features = ["std"] } untrusted = { version = "0.7", default-features = false } unzip-n = { version = "0.1", default-features = false } +ureq = { version = "2" } url = { version = "2", features = ["serde"] } urlencoding = { version = "2", default-features = false } utf-8 = { version = "0.7", default-features = false } @@ -1806,11 +1811,12 @@ wasm-bindgen-macro = { version = "0.2", default-features = false, features = ["s wasm-bindgen-macro-support = { version = "0.2", default-features = false, features = ["spans"] } wasm-bindgen-shared = { version = "0.2", default-features = false } webpki = { version = "0.22", default-features = false, features = ["std"] } +webpki-roots-2ffb4c3fe830441c = { package = "webpki-roots", version = "0.25", default-features = false } webpki-roots-3c51e837cfc5589a = { package = "webpki-roots", version = "0.22", default-features = false } which = { version = "4", default-features = false } whoami = { version = "1" } winapi = { version = "0.3", default-features = false, features = ["basetsd", "memoryapi", "minwindef"] } -winnow = { version = "0.5" } +winnow = { version = "0.4" } wyz-6f8ce4dd05d13bba = { package = "wyz", version = "0.2", default-features = false, features = ["alloc"] } wyz-d8f496e17d97b5cb = { package = "wyz", version = "0.5", default-features = false } x509-parser = { version = "0.14" } @@ -1837,7 +1843,7 @@ core-foundation-sys = { version = "0.8", default-features = false } cpp_demangle = { version = "0.4" } cpufeatures = { version = "0.2", default-features = false } debugid = { version = "0.8", default-features = false } -errno-468e82937335b1c9 = { package = "errno", version = "0.3", default-features = false } +errno-468e82937335b1c9 = { package = "errno", version = "0.3", default-features = false, features = ["std"] } errno-6f8ce4dd05d13bba = { package = "errno", version = "0.2", default-features = false } eth-keystore = { version = "0.5", default-features = false } findshlibs = { version = "0.10", default-features = false } @@ -1872,7 +1878,6 @@ stable_deref_trait = { version = "1" } symbolic-common = { version = "10", default-features = false } symbolic-demangle = { version = "10", default-features = false, features = ["cpp", "rust"] } uuid-c38e5c1d305a1b54 = { package = "uuid", version = "0.8", features = ["serde", "v4"] } -webpki-roots-2ffb4c3fe830441c = { package = "webpki-roots", version = "0.25", default-features = false } xattr = { version = "1" } [target.aarch64-apple-darwin.build-dependencies] @@ -1885,7 +1890,7 @@ core-foundation-sys = { version = "0.8", default-features = false } cpp_demangle = { version = "0.4" } cpufeatures = { version = "0.2", default-features = false } debugid = { version = "0.8", default-features = false } -errno-468e82937335b1c9 = { package = "errno", version = "0.3", default-features = false } +errno-468e82937335b1c9 = { package = "errno", version = "0.3", default-features = false, features = ["std"] } errno-6f8ce4dd05d13bba = { package = "errno", version = "0.2", default-features = false } eth-keystore = { version = "0.5", default-features = false } findshlibs = { version = "0.10", default-features = false } @@ -1921,7 +1926,6 @@ stable_deref_trait = { version = "1" } symbolic-common = { version = "10", default-features = false } symbolic-demangle = { version = "10", default-features = false, features = ["cpp", "rust"] } uuid-c38e5c1d305a1b54 = { package = "uuid", version = "0.8", features = ["serde", "v4"] } -webpki-roots-2ffb4c3fe830441c = { package = "webpki-roots", version = "0.25", default-features = false } xattr = { version = "1" } [target.x86_64-unknown-linux-gnu.dependencies] @@ -1942,7 +1946,7 @@ jemalloc-ctl = { version = "0.5" } jemalloc-sys = { version = "0.5" } libc = { version = "0.2", default-features = false, features = ["extra_traits"] } linux-raw-sys-468e82937335b1c9 = { package = "linux-raw-sys", version = "0.3", default-features = false, features = ["errno", "general", "ioctl", "no_std"] } -linux-raw-sys-9fbad63c4bcf4a8f = { package = "linux-raw-sys", version = "0.4", default-features = false, features = ["errno", "general", "ioctl", "no_std"] } +linux-raw-sys-9fbad63c4bcf4a8f = { package = "linux-raw-sys", version = "0.4", default-features = false, features = ["elf", "errno", "general", "ioctl", "no_std", "std"] } linux-raw-sys-c65f7effa3be6d31 = { package = "linux-raw-sys", version = "0.1", default-features = false, features = ["errno", "general", "ioctl", "no_std"] } memmap2-d8f496e17d97b5cb = { package = "memmap2", version = "0.5", default-features = false } memoffset-3b31131e45eafb45 = { package = "memoffset", version = "0.6" } @@ -1967,7 +1971,6 @@ stable_deref_trait = { version = "1" } symbolic-common = { version = "10", default-features = false } symbolic-demangle = { version = "10", default-features = false, features = ["cpp", "rust"] } uuid-c38e5c1d305a1b54 = { package = "uuid", version = "0.8", features = ["serde", "v4"] } -webpki-roots-2ffb4c3fe830441c = { package = "webpki-roots", version = "0.25", default-features = false } xattr = { version = "1" } [target.x86_64-unknown-linux-gnu.build-dependencies] @@ -1990,7 +1993,7 @@ jemalloc-ctl = { version = "0.5" } jemalloc-sys = { version = "0.5" } libc = { version = "0.2", default-features = false, features = ["extra_traits"] } linux-raw-sys-468e82937335b1c9 = { package = "linux-raw-sys", version = "0.3", default-features = false, features = ["errno", "general", "ioctl", "no_std"] } -linux-raw-sys-9fbad63c4bcf4a8f = { package = "linux-raw-sys", version = "0.4", default-features = false, features = ["errno", "general", "ioctl", "no_std"] } +linux-raw-sys-9fbad63c4bcf4a8f = { package = "linux-raw-sys", version = "0.4", default-features = false, features = ["elf", "errno", "general", "ioctl", "no_std", "std"] } linux-raw-sys-c65f7effa3be6d31 = { package = "linux-raw-sys", version = "0.1", default-features = false, features = ["errno", "general", "ioctl", "no_std"] } memmap2-d8f496e17d97b5cb = { package = "memmap2", version = "0.5", default-features = false } memoffset-3b31131e45eafb45 = { package = "memoffset", version = "0.6" } @@ -2016,7 +2019,6 @@ stable_deref_trait = { version = "1" } symbolic-common = { version = "10", default-features = false } symbolic-demangle = { version = "10", default-features = false, features = ["cpp", "rust"] } uuid-c38e5c1d305a1b54 = { package = "uuid", version = "0.8", features = ["serde", "v4"] } -webpki-roots-2ffb4c3fe830441c = { package = "webpki-roots", version = "0.25", default-features = false } xattr = { version = "1" } [target.x86_64-pc-windows-msvc.dependencies] @@ -2041,7 +2043,6 @@ schannel = { version = "0.1", default-features = false } scrypt = { version = "0.10", default-features = false } str-buf = { version = "1", default-features = false } uuid-c38e5c1d305a1b54 = { package = "uuid", version = "0.8", features = ["serde", "v4"] } -webpki-roots-2ffb4c3fe830441c = { package = "webpki-roots", version = "0.25", default-features = false } widestring = { version = "0.5" } winapi = { version = "0.3", default-features = false, features = ["cfg", "combaseapi", "consoleapi", "errhandlingapi", "evntrace", "fileapi", "handleapi", "heapapi", "ifdef", "impl-default", "in6addr", "inaddr", "ioapiset", "iphlpapi", "knownfolders", "libloaderapi", "lmaccess", "lmapibuf", "lmcons", "minwinbase", "namedpipeapi", "netioapi", "ntlsa", "ntsecapi", "ntstatus", "objbase", "objidl", "oleauto", "pdh", "powerbase", "processenv", "processthreadsapi", "profileapi", "psapi", "rpcdce", "securitybaseapi", "shellapi", "shlobj", "std", "stringapiset", "synchapi", "sysinfoapi", "wbemcli", "winbase", "wincon", "windef", "winerror", "winioctl", "winnt", "winsock2", "winuser", "ws2ipdef", "ws2tcpip", "wtypesbase"] } winapi-util = { version = "0.1", default-features = false } @@ -2077,7 +2078,6 @@ scrypt = { version = "0.10", default-features = false } str-buf = { version = "1", default-features = false } uuid-c38e5c1d305a1b54 = { package = "uuid", version = "0.8", features = ["serde", "v4"] } vcpkg = { version = "0.2", default-features = false } -webpki-roots-2ffb4c3fe830441c = { package = "webpki-roots", version = "0.25", default-features = false } widestring = { version = "0.5" } winapi = { version = "0.3", default-features = false, features = ["cfg", "combaseapi", "consoleapi", "errhandlingapi", "evntrace", "fileapi", "handleapi", "heapapi", "ifdef", "impl-default", "in6addr", "inaddr", "ioapiset", "iphlpapi", "knownfolders", "libloaderapi", "lmaccess", "lmapibuf", "lmcons", "minwinbase", "namedpipeapi", "netioapi", "ntlsa", "ntsecapi", "ntstatus", "objbase", "objidl", "oleauto", "pdh", "powerbase", "processenv", "processthreadsapi", "profileapi", "psapi", "rpcdce", "securitybaseapi", "shellapi", "shlobj", "std", "stringapiset", "synchapi", "sysinfoapi", "wbemcli", "winbase", "wincon", "windef", "winerror", "winioctl", "winnt", "winsock2", "winuser", "ws2ipdef", "ws2tcpip", "wtypesbase"] } winapi-util = { version = "0.1", default-features = false }