diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a7d1887..3e4ca7d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @dfinity/sdk +* @dfinity/dx diff --git a/Cargo.lock b/Cargo.lock index ff3a6fa..40031dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,24 +4,23 @@ version = 3 [[package]] name = "anstream" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" [[package]] name = "anstyle-parse" @@ -43,9 +42,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", "windows-sys", @@ -53,9 +52,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" @@ -65,9 +64,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "assert_cmd" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d6b683edf8d1119fe420a94f8a7e389239666aa72e65495d91c00462510151" +checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" dependencies = [ "anstyle", "bstr", @@ -115,9 +114,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "block-buffer" @@ -130,12 +129,11 @@ dependencies = [ [[package]] name = "bstr" -version = "1.5.0" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" +checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" dependencies = [ "memchr", - "once_cell", "regex-automata", "serde", ] @@ -148,9 +146,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "candid" -version = "0.9.0" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14881d34e5ad2b3e77dfbbdf3266d907f85d28faf214b843684f2e64e8acd6c7" +checksum = "749938f355699c7dd0975e505d54541cd1d84db239374470bdf500a5d885530a" dependencies = [ "anyhow", "binread", @@ -175,23 +173,24 @@ dependencies = [ [[package]] name = "candid_derive" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "041ce1020740a400035899b2909a6f4f275b79c8db502cbd59ace9b2cc88af58" +checksum = "158403ea38fab5904ae47a5d67eb7047650a91681407f5ccbcbcabc4f4ffb489" dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.37", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -202,45 +201,43 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.3.10" +version = "4.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" +checksum = "824956d0dca8334758a5b7f7e50518d66ea319330cbceedcf76905c2f6ab30e3" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.10" +version = "4.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" +checksum = "122ec64120a49b4563ccaedcbea7818d069ed8e9aa6d829b82d8a4128936b2ab" dependencies = [ "anstream", "anstyle", "clap_lex", - "once_cell", "strsim", ] [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.37", ] [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "codespan-reporting" @@ -260,9 +257,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -288,9 +285,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.97" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88abab2f5abbe4c56e8f1fb431b784d710b709888f35755a160e62e33fe38e8" +checksum = "bbe98ba1789d56fb3db3bee5e032774d4f421b685de7ba703643584ba24effbe" dependencies = [ "cc", "cxxbridge-flags", @@ -300,9 +297,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.97" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0c11acd0e63bae27dcd2afced407063312771212b7a823b4fd72d633be30fb" +checksum = "c4ce20f6b8433da4841b1dadfb9468709868022d829d5ca1f2ffbda928455ea3" dependencies = [ "cc", "codespan-reporting", @@ -310,24 +307,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.22", + "syn 2.0.37", ] [[package]] name = "cxxbridge-flags" -version = "1.0.97" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3816ed957c008ccd4728485511e3d9aaf7db419aa321e3d2c5a2f3411e36c8" +checksum = "20888d9e1d2298e2ff473cee30efe7d5036e437857ab68bbfea84c74dba91da2" [[package]] name = "cxxbridge-macro" -version = "1.0.97" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26acccf6f445af85ea056362561a24ef56cdc15fcc685f03aec50b9c702cb6d" +checksum = "2fa16a70dd58129e4dfffdff535fb1bce66673f7bbeec4a5a1765a504e1ccd84" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.37", ] [[package]] @@ -360,21 +357,21 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -399,12 +396,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "generic-array" @@ -454,12 +448,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - [[package]] name = "hex" version = "0.4.3" @@ -468,7 +456,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "ic-wasm" -version = "0.5.0" +version = "0.5.1" dependencies = [ "anyhow", "assert_cmd", @@ -499,50 +487,19 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "ad227c3af19d4914570ad36d30409928b75967c298feb9ea1969db3a610bb14e" dependencies = [ "equivalent", "hashbrown 0.14.0", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - -[[package]] -name = "is-terminal" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" -dependencies = [ - "hermit-abi", - "rustix 0.38.1", - "windows-sys", -] - [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -570,48 +527,42 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "link-cplusplus" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" dependencies = [ "cc", ] [[package]] name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -631,32 +582,32 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "num_enum" -version = "0.5.11" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.37", ] [[package]] @@ -667,15 +618,15 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "predicates" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" +checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" dependencies = [ "anstyle", "difflib", @@ -701,12 +652,13 @@ dependencies = [ [[package]] name = "pretty" -version = "0.10.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9940b913ee56ddd94aec2d3cd179dd47068236f42a1a6415ccf9d880ce2a61" +checksum = "b55c4d17d994b637e2f4daf6e5dc5d660d209d5642377d675d7a1c3ab69fa579" dependencies = [ "arrayvec", "typed-arena", + "unicode-width", ] [[package]] @@ -721,9 +673,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -739,9 +691,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -757,9 +709,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" [[package]] name = "rustc-demangle" @@ -769,77 +721,63 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25693a73057a1b4cb56179dd3c7ea21a7c6c5ee7d85781f5749b46f34b79c" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys", -] - -[[package]] -name = "rustix" -version = "0.38.1" +version = "0.38.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc6396159432b5c8490d4e301d8c705f61860b8b6c863bf79942ce5401968f3" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys", "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "scratch" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.37", ] [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -903,9 +841,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.22" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -914,23 +852,22 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall", - "rustix 0.37.21", + "rustix", "windows-sys", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] @@ -943,22 +880,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.37", ] [[package]] @@ -969,11 +906,11 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.11" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.0.1", "toml_datetime", "winnow", ] @@ -986,15 +923,15 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" @@ -1004,9 +941,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "utf8parse" @@ -1130,9 +1067,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -1154,9 +1091,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1169,51 +1106,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 00d8f47..5df674b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ic-wasm" -version = "0.5.0" +version = "0.5.1" authors = ["DFINITY Stiftung"] edition = "2021" description = "A library for performing Wasm transformations specific to canisters running on the Internet Computer" diff --git a/README.md b/README.md index 2aa9806..163da37 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ Usage: `ic-wasm -o resource --remove_cycles_transfer Instrument canister method to emit execution trace to stable memory. -Usage: `ic-wasm -o instrument --trace-only func1 --trace-only func2` +Usage: `ic-wasm -o instrument --trace-only func1 --trace-only func2 --start-page 16 --page-limit 30` Instrumented canister has the following additional endpoints: @@ -106,16 +106,69 @@ Instrumented canister has the following additional endpoints: When `--trace-only` flag is provided, the counter and trace logging will only happen during the execution of that function, instead of tracing the whole update call. Note that the function itself has to be non-recursive. -Current limitations: +#### Working with upgrades and stable memory -* Logs are stored in the first few pages of stable memory (up to 32 pages). This may break: - + break upgrade - + break manual access to stable memory - + `canister_init` in Motoko cannot be profiled, because it uses `stable_size` to decide if there are stable vars to decode +By default, execution trace is stored in the first few pages (up to 32 pages) of stable memory. Without any user side support, we cannot profile upgrade or code which accesses stable memory. If the canister can pre-allocate a fixed region of stable memory at `canister_init`, we can then pass this address to `ic-wasm` via the `--start-page` flag, so that the trace is written to this pre-allocated space without corrupting the rest of the stable memory access. + +Another optional flag `--page-limit` specifies the number of pre-allocated pages in stable memory. By default, it's set to 30 pages. We only store trace up to `page-limit` pages, the remaining trace is dropped. Currently, due to the message size limit, we can only store 2M of trace data, which equates to roughly 30 pages. This limitation can be lifted in the future by supporting streamed output of the trace. + +The recommended way of pre-allocating stable memory is via the `Region` library in Motoko, and `ic-stable-structures` in Rust. But developers are free to use any other libraries or even the raw stable memory system API to pre-allocate space, as long as the developer can guarantee that the pre-allocated space is not touched by the rest of the code. + +The following is the code sample for pre-allocating stable memory in Motoko (with `--start-page 16`), + +```motoko +import Region "mo:base/Region"; +actor { + stable let profiling = do { + let r = Region.new(); + ignore Region.grow(r, 32); + r; + }; + ... +} +``` + +and in Rust (with `--start-page 1`) + +```rust +use ic_stable_structures::{ + memory_manager::{MemoryId, MemoryManager}, + writer::Writer, + DefaultMemoryImpl, Memory, +}; +thread_local! { + static MEMORY_MANAGER: RefCell> = + RefCell::new(MemoryManager::init(DefaultMemoryImpl::default())); +} +const PROFILING: MemoryId = MemoryId::new(0); +const UPGRADES: MemoryId = MemoryId::new(1); + +#[ic_cdk::init] +fn init() { + let memory = MEMORY_MANAGER.with(|m| m.borrow().get(PROFILING)); + memory.grow(32); + ... +} +#[ic_cdk::pre_upgrade] +fn pre_upgrade() { + let mut memory = MEMORY_MANAGER.with(|m| m.borrow().get(UPGRADES)); + ... +} +#[ic_cdk::post_upgrade] +fn post_upgrade() { + let memory = MEMORY_MANAGER.with(|m| m.borrow().get(UPGRADES)); + ... +} +``` + +#### Current limitations + +* Without pre-allocating stable memory from user code, we cannot profile upgrade or code that accesses stable memory. +* Since the pre-allocation happens in `canister_init`, we cannot profile `canister_init`. * If heartbeat is present, it's hard to measure any other method calls. It's also hard to measure a specific heartbeat event. * We only store the first 2M of profiling data. * We cannot measure query calls. -* No concurrent calls +* No concurrent calls. ## Library diff --git a/src/bin/main.rs b/src/bin/main.rs index 3ad64cc..3b93e26 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -67,8 +67,15 @@ enum SubCommand { }, /// Instrument canister method to emit execution trace to stable memory (experimental) Instrument { + /// Trace only the specified list of functions. The function cannot be recursive #[clap(short, long)] trace_only: Option>, + /// If the canister preallocates a stable memory region, specify the starting page. Required if you want to profile upgrades, or the canister uses stable memory + #[clap(short, long)] + start_page: Option, + /// The number of pages of the preallocated stable memory + #[clap(short, long, requires("start_page"))] + page_limit: Option, }, } @@ -102,11 +109,19 @@ fn main() -> anyhow::Result<()> { always_inline_max_function_size, keep_name_section, )?, - SubCommand::Instrument { trace_only } => match trace_only { - None => ic_wasm::instrumentation::instrument(&mut m, &[]), - Some(vec) => ic_wasm::instrumentation::instrument(&mut m, vec), + SubCommand::Instrument { + trace_only, + start_page, + page_limit, + } => { + use ic_wasm::instrumentation::{instrument, Config}; + let config = Config { + trace_only_funcs: trace_only.clone().unwrap_or(vec![]), + start_address: start_page.map(|page| page * 65536), + page_limit: *page_limit, + }; + instrument(&mut m, config).map_err(|e| anyhow::anyhow!("{e}"))?; } - .map_err(|e| anyhow::anyhow!("{e}"))?, SubCommand::Resource { remove_cycles_transfer, limit_stable_memory_page, diff --git a/src/instrumentation.rs b/src/instrumentation.rs index ba85df4..e728f97 100644 --- a/src/instrumentation.rs +++ b/src/instrumentation.rs @@ -4,6 +4,10 @@ use walrus::*; use crate::utils::*; use std::collections::HashSet; +const METADATA_SIZE: i32 = 24; +const DEFAULT_PAGE_LIMIT: i32 = 30; +const LOG_ITEM_SIZE: i32 = 12; + struct InjectionPoint { position: usize, cost: i64, @@ -29,11 +33,31 @@ struct Variables { dynamic_counter64_func: FunctionId, } +pub struct Config { + pub trace_only_funcs: Vec, + pub start_address: Option, + pub page_limit: Option, +} +impl Config { + pub fn is_preallocated(&self) -> bool { + self.start_address.is_some() + } + pub fn log_start_address(&self) -> i32 { + self.start_address.unwrap_or(0) + METADATA_SIZE + } + pub fn metadata_start_address(&self) -> i32 { + self.start_address.unwrap_or(0) + } + pub fn page_limit(&self) -> i32 { + self.page_limit.unwrap_or(DEFAULT_PAGE_LIMIT) + } +} + /// When trace_only_funcs is not empty, counting and tracing is only enabled for those listed functions per update call. /// TODO: doesn't handle recursive entry functions. Need to create a wrapper for the recursive entry function. -pub fn instrument(m: &mut Module, trace_only_funcs: &[String]) -> Result<(), String> { +pub fn instrument(m: &mut Module, config: Config) -> Result<(), String> { let mut trace_only_ids = HashSet::new(); - for name in trace_only_funcs.iter() { + for name in config.trace_only_funcs.iter() { let id = match m.funcs.by_name(name) { Some(id) => id, None => return Err(format!("func \"{name}\" not found")), @@ -85,7 +109,7 @@ pub fn instrument(m: &mut Module, trace_only_funcs: &[String]) -> Result<(), Str ); } } - let writer = make_stable_writer(m, &vars); + let writer = make_stable_writer(m, &vars, &config); let printer = make_printer(m, &vars, writer); for (id, func) in m.funcs.iter_local_mut() { if id != printer @@ -101,9 +125,13 @@ pub fn instrument(m: &mut Module, trace_only_funcs: &[String]) -> Result<(), Str //inject_start(m, vars.is_init); inject_init(m, vars.is_init); } + // Persist globals + inject_pre_upgrade(m, &vars, &config); + inject_post_upgrade(m, &vars, &config); + inject_canister_methods(m, &vars); let leb = make_leb128_encoder(m); - make_stable_getter(m, &vars, leb); + make_stable_getter(m, &vars, leb, &config); make_getter(m, &vars); make_toggle_func(m, "__toggle_tracing", vars.is_init); make_toggle_func(m, "__toggle_entry", vars.is_entry); @@ -400,7 +428,7 @@ fn make_dynamic_counter64( .local_get(size); builder.finish(vec![size], &mut m.funcs) } -fn make_stable_writer(m: &mut Module, vars: &Variables) -> FunctionId { +fn make_stable_writer(m: &mut Module, vars: &Variables, config: &Config) -> FunctionId { let writer = get_ic_func_id(m, "stable_write"); let grow = get_ic_func_id(m, "stable_grow"); let mut builder = FunctionBuilder::new( @@ -408,6 +436,9 @@ fn make_stable_writer(m: &mut Module, vars: &Variables) -> FunctionId { &[ValType::I32, ValType::I32, ValType::I32], &[], ); + let start_address = config.log_start_address(); + let size_limit = config.page_limit() * 65536; + let is_preallocated = config.is_preallocated(); let offset = m.locals.add(ValType::I32); let src = m.locals.add(ValType::I32); let size = m.locals.add(ValType::I32); @@ -415,38 +446,54 @@ fn make_stable_writer(m: &mut Module, vars: &Variables) -> FunctionId { .func_body() .local_get(offset) .local_get(size) - .binop(BinaryOp::I32Add) - .global_get(vars.page_size) - .i32_const(65536) - .binop(BinaryOp::I32Mul) + .binop(BinaryOp::I32Add); + if is_preallocated { + builder.func_body().i32_const(size_limit); + } else { + builder + .func_body() + .global_get(vars.page_size) + .i32_const(65536) + .binop(BinaryOp::I32Mul) + .i32_const(METADATA_SIZE) + .binop(BinaryOp::I32Sub); + } + builder + .func_body() .binop(BinaryOp::I32GtS) .if_else( None, |then| { - // TODO: This assumes user code doesn't use stable memory - then.global_get(vars.page_size) - .i32_const(30) // cannot use the full 2M, because Candid header takes some extra bytes - .binop(BinaryOp::I32GtS) // trace >= 2M - .if_else( - None, - |then| { - then.return_(); - }, - |else_| { - else_ - .i32_const(1) - .call(grow) - .drop() - .global_get(vars.page_size) - .i32_const(1) - .binop(BinaryOp::I32Add) - .global_set(vars.page_size); - }, - ); + if is_preallocated { + then.return_(); + } else { + // This assumes user code doesn't use stable memory + then.global_get(vars.page_size) + .i32_const(30) // cannot use the full 2M, because Candid header takes some extra bytes + .binop(BinaryOp::I32GtS) // trace >= 2M + .if_else( + None, + |then| { + then.return_(); + }, + |else_| { + else_ + .i32_const(1) + .call(grow) + .drop() + .global_get(vars.page_size) + .i32_const(1) + .binop(BinaryOp::I32Add) + .global_set(vars.page_size); + }, + ); + } }, |_| {}, ) + .i32_const(start_address) .local_get(offset) + .binop(BinaryOp::I32Add) .local_get(src) .local_get(size) .call(writer) @@ -486,10 +533,10 @@ fn make_printer(m: &mut Module, vars: &Variables, writer: FunctionId) -> Functio .global_get(vars.total_counter) .store(memory, StoreKind::I64 { atomic: false }, MemArg { offset: 0, align: 8 }) .global_get(vars.log_size) - .i32_const(12) + .i32_const(LOG_ITEM_SIZE) .binop(BinaryOp::I32Mul) .i32_const(0) - .i32_const(12) + .i32_const(LOG_ITEM_SIZE) .call(writer) // restore memory .i32_const(0) @@ -523,8 +570,13 @@ fn inject_canister_methods(m: &mut Module, vars: &Variables) { ExportItem::Function(id) if e.name != "canister_update __motoko_async_helper" && (e.name.starts_with("canister_update") - || e.name.starts_with("canister_query") - || e.name.starts_with("canister_heartbeat")) => + || e.name.starts_with("canister_query") + || e.name.starts_with("canister_composite_query") + || e.name.starts_with("canister_heartbeat") + // don't clear logs for timer and post_upgrade, as they are trigger by other signals + //|| e.name == "canister_global_timer" + //|| e.name == "canister_post_upgrade" + || e.name == "canister_pre_upgrade") => { Some(id) } @@ -547,22 +599,93 @@ fn inject_canister_methods(m: &mut Module, vars: &Variables) { } } fn inject_init(m: &mut Module, is_init: GlobalId) { - match get_export_func_id(m, "canister_init") { - Some(id) => { - let mut builder = get_builder(m, id); - // canister_init in Motoko use stable_size to decide if there is stable memory to deserialize - // We can only enable profiling at the end of init, otherwise stable.grow breaks this check. - builder.i32_const(0).global_set(is_init); - } - None => { - let mut builder = FunctionBuilder::new(&mut m.types, &[], &[]); - builder.func_body().i32_const(0).global_set(is_init); - let id = builder.finish(vec![], &mut m.funcs); - m.exports.add("canister_init", id); - } - } + let mut builder = get_or_create_export_func(m, "canister_init"); + // canister_init in Motoko use stable_size to decide if there is stable memory to deserialize. + // Region initialization in Motoko is also done here. + // We can only enable profiling at the end of init, otherwise stable.grow breaks this check. + builder.i32_const(0).global_set(is_init); } -fn make_stable_getter(m: &mut Module, vars: &Variables, leb: FunctionId) { +fn inject_pre_upgrade(m: &mut Module, vars: &Variables, config: &Config) { + let writer = get_ic_func_id(m, "stable_write"); + let memory = get_memory_id(m); + let mut builder = get_or_create_export_func(m, "canister_pre_upgrade"); + #[rustfmt::skip] + builder + // no need to backup memory, since this is the end of the pre-upgrade. + // persist globals + .i32_const(0) + .global_get(vars.total_counter) + .store(memory, StoreKind::I64 { atomic: false }, MemArg { offset: 0, align: 8 }) + .i32_const(8) + .global_get(vars.log_size) + .store(memory, StoreKind::I32 { atomic: false }, MemArg { offset: 0, align: 4 }) + .i32_const(12) + .global_get(vars.page_size) + .store(memory, StoreKind::I32 { atomic: false }, MemArg { offset: 0, align: 4 }) + .i32_const(16) + .global_get(vars.is_init) + .store(memory, StoreKind::I32 { atomic: false }, MemArg { offset: 0, align: 4 }) + .i32_const(20) + .global_get(vars.is_entry) + .store(memory, StoreKind::I32 { atomic: false }, MemArg { offset: 0, align: 4 }) + .i32_const(config.metadata_start_address()) + .i32_const(0) + .i32_const(METADATA_SIZE) + .call(writer); +} +fn inject_post_upgrade(m: &mut Module, vars: &Variables, config: &Config) { + let reader = get_ic_func_id(m, "stable_read"); + let memory = get_memory_id(m); + let a = m.locals.add(ValType::I64); + let b = m.locals.add(ValType::I64); + let c = m.locals.add(ValType::I64); + let mut builder = get_or_create_export_func(m, "canister_post_upgrade"); + #[rustfmt::skip] + inject_top(&mut builder, vec![ + // backup + Const { value: Value::I32(0) }.into(), + Load { memory, kind: LoadKind::I64 { atomic: false }, arg: MemArg { offset: 0, align: 8 } }.into(), + LocalSet { local: a }.into(), + Const { value: Value::I32(8) }.into(), + Load { memory, kind: LoadKind::I64 { atomic: false }, arg: MemArg { offset: 0, align: 8 } }.into(), + LocalSet { local: b }.into(), + Const { value: Value::I32(16) }.into(), + Load { memory, kind: LoadKind::I64 { atomic: false }, arg: MemArg { offset: 0, align: 8 } }.into(), + LocalSet { local: c }.into(), + // load from stable memory + Const { value: Value::I32(0) }.into(), + Const { value: Value::I32(config.metadata_start_address()) }.into(), + Const { value: Value::I32(METADATA_SIZE) }.into(), + Call { func: reader }.into(), + Const { value: Value::I32(0) }.into(), + Load { memory, kind: LoadKind::I64 { atomic: false }, arg: MemArg { offset: 0, align: 8 } }.into(), + GlobalSet { global: vars.total_counter }.into(), + Const { value: Value::I32(8) }.into(), + Load { memory, kind: LoadKind::I32 { atomic: false }, arg: MemArg { offset: 0, align: 4 } }.into(), + GlobalSet { global: vars.log_size }.into(), + Const { value: Value::I32(12) }.into(), + Load { memory, kind: LoadKind::I32 { atomic: false }, arg: MemArg { offset: 0, align: 4 } }.into(), + GlobalSet { global: vars.page_size }.into(), + Const { value: Value::I32(16) }.into(), + Load { memory, kind: LoadKind::I32 { atomic: false }, arg: MemArg { offset: 0, align: 4 } }.into(), + GlobalSet { global: vars.is_init }.into(), + Const { value: Value::I32(20) }.into(), + Load { memory, kind: LoadKind::I32 { atomic: false }, arg: MemArg { offset: 0, align: 4 } }.into(), + GlobalSet { global: vars.is_entry }.into(), + // restore + Const { value: Value::I32(0) }.into(), + LocalGet { local: a }.into(), + Store { memory, kind: StoreKind::I64 { atomic: false }, arg: MemArg { offset: 0, align: 8 } }.into(), + Const { value: Value::I32(8) }.into(), + LocalGet { local: b }.into(), + Store { memory, kind: StoreKind::I64 { atomic: false }, arg: MemArg { offset: 0, align: 8 } }.into(), + Const { value: Value::I32(16) }.into(), + LocalGet { local: c }.into(), + Store { memory, kind: StoreKind::I64 { atomic: false }, arg: MemArg { offset: 0, align: 8 } }.into(), + ]); +} + +fn make_stable_getter(m: &mut Module, vars: &Variables, leb: FunctionId, config: &Config) { let memory = get_memory_id(m); let reply_data = get_ic_func_id(m, "msg_reply_data_append"); let reply = get_ic_func_id(m, "msg_reply"); @@ -587,14 +710,14 @@ fn make_stable_getter(m: &mut Module, vars: &Variables, leb: FunctionId) { .i32_const(5) .call(reply_data) .i32_const(0) - .i32_const(0) + .i32_const(config.log_start_address()) .global_get(vars.log_size) - .i32_const(12) + .i32_const(LOG_ITEM_SIZE) .binop(BinaryOp::I32Mul) .call(reader) .i32_const(0) .global_get(vars.log_size) - .i32_const(12) + .i32_const(LOG_ITEM_SIZE) .binop(BinaryOp::I32Mul) .call(reply_data) .call(reply); diff --git a/src/utils.rs b/src/utils.rs index e81b1d5..7770573 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -140,6 +140,21 @@ pub(crate) fn get_export_func_id(m: &Module, method: &str) -> Option None } } +pub(crate) fn get_or_create_export_func<'a>( + m: &'a mut Module, + method: &'a str, +) -> InstrSeqBuilder<'a> { + let id = match get_export_func_id(m, method) { + Some(id) => id, + None => { + let builder = FunctionBuilder::new(&mut m.types, &[], &[]); + let id = builder.finish(vec![], &mut m.funcs); + m.exports.add(method, id); + id + } + }; + get_builder(m, id) +} pub(crate) fn get_builder(m: &mut Module, id: FunctionId) -> InstrSeqBuilder<'_> { if let FunctionKind::Local(func) = &mut m.funcs.get_mut(id).kind { diff --git a/tests/README.md b/tests/README.md index c735b5d..b76bfda 100644 --- a/tests/README.md +++ b/tests/README.md @@ -2,5 +2,61 @@ To regenerate the Wasm file: * `wat.wasm` is generated from the [dfinity/examples/wasm/counter](https://github.com/dfinity/examples/tree/master/wasm/counter) * `motoko.wasm` is generated from [dfinity/examples/motoko/counter](https://github.com/dfinity/examples/tree/master/motoko/counter) -* `rust.wasm` is generated from [dfinity/cdk-rs/examples/counter](https://github.com/dfinity/cdk-rs/tree/main/examples/counter/src/counter_rs) +* `motoko-region.wasm` is generated by adding the following in the Motoko counter code: +```motoko +import Region "mo:base/Region"; +actor { + stable let profiling = do { + let r = Region.new(); + ignore Region.grow(r, 32); + r; + }; + ... +} +``` +* `rust.wasm` is generated from [dfinity/examples/rust/counter](https://github.com/dfinity/examples/tree/master/rust/counter), and add the following pre/post-upgrade hooks: +```rust +use ic_stable_structures::{ + memory_manager::{MemoryId, MemoryManager}, + writer::Writer, + DefaultMemoryImpl, Memory, +}; +thread_local! { + static MEMORY_MANAGER: RefCell> = + RefCell::new(MemoryManager::init(DefaultMemoryImpl::default())); +} + +const UPGRADES: MemoryId = MemoryId::new(0); + +#[ic_cdk::pre_upgrade] +fn pre_upgrade() { + let bytes = COUNTER.with(|counter| Encode!(counter).unwrap()); + let len = bytes.len() as u32; + let mut memory = MEMORY_MANAGER.with(|m| m.borrow().get(UPGRADES)); + let mut writer = Writer::new(&mut memory, 0); + writer.write(&len.to_le_bytes()).unwrap(); + writer.write(&bytes).unwrap(); +} +#[ic_cdk::post_upgrade] +fn post_upgrade() { + let memory = MEMORY_MANAGER.with(|m| m.borrow().get(UPGRADES)); + let mut len_bytes = [0; 4]; + memory.read(0, &mut len_bytes); + let len = u32::from_le_bytes(len_bytes) as usize; + let mut bytes = vec![0; len]; + memory.read(4, &mut bytes); + let value = Decode!(&bytes, Nat).unwrap(); + COUNTER.with(|cell| *cell.borrow_mut() = value); +} +``` +* `rust-region.wasm` is generated by adding the following in the Rust counter code: +```rust +const PROFILING: MemoryId = MemoryId::new(100); +#[ic_cdk::init] +fn init() { + let memory = MEMORY_MANAGER.with(|m| m.borrow().get(PROFILING)); + memory.grow(32); + ... +} +``` * `classes.wasm` is generated from [dfinity/examples/motoko/classes](https://github.com/dfinity/examples/blob/master/motoko/classes/src/map/Map.mo) diff --git a/tests/deployable.ic-repl.sh b/tests/deployable.ic-repl.sh index 9416ced..7cf583e 100644 --- a/tests/deployable.ic-repl.sh +++ b/tests/deployable.ic-repl.sh @@ -14,8 +14,18 @@ function install(wasm) { ); S }; +function upgrade(S, wasm) { + call ic.install_code( + record { + arg = encode (); + wasm_module = wasm; + mode = variant { upgrade }; + canister_id = S; + } + ); +}; -function motoko(wasm) { +function counter(wasm) { let S = install(wasm); call S.set(42); call S.inc(); @@ -28,19 +38,6 @@ function motoko(wasm) { assert _ == (45 : nat); S }; -function rust(wasm) { - let S = install(wasm); - call S.write((42 : nat)); - call S.inc(); - call S.read(); - assert _ == (43 : nat); - - call S.inc(); - call S.inc(); - call S.read(); - assert _ == (45 : nat); - S -}; function wat(wasm) { let S = install(wasm); call S.set((42 : int64)); @@ -89,25 +86,42 @@ function classes_redirect(wasm) { assert _ ~= "zz73r-nyaaa-aabbb-aaaca-cai not found"; S }; +function check_profiling(S, cycles, len) { + call S.__get_cycles(); + assert _ == (cycles : int64); + call S.__get_profiling(); + assert _.size() == (len : nat); + null +}; -let S = motoko(file("ok/motoko-instrument.wasm")); -call S.__get_cycles(); -assert _ == (9003 : int64); -let S = motoko(file("ok/motoko-gc-instrument.wasm")); -call S.__get_cycles(); -assert _ == (295 : int64); -motoko(file("ok/motoko-shrink.wasm")); -motoko(file("ok/motoko-limit.wasm")); +let S = counter(file("ok/motoko-instrument.wasm")); +check_profiling(S, 9397, 78); +let S = counter(file("ok/motoko-gc-instrument.wasm")); +check_profiling(S, 250, 4); +let wasm = file("ok/motoko-region-instrument.wasm"); +let S = counter(wasm); +check_profiling(S, 463666, 78); +upgrade(S, wasm); +call S.get(); +assert _ == (45 : nat); +check_profiling(S, 474294, 460); +counter(file("ok/motoko-shrink.wasm")); +counter(file("ok/motoko-limit.wasm")); -let S = rust(file("ok/rust-instrument.wasm")); -call S.__get_cycles(); -assert _ == (136378 : int64); -rust(file("ok/rust-shrink.wasm")); -rust(file("ok/rust-limit.wasm")); +let S = counter(file("ok/rust-instrument.wasm")); +check_profiling(S, 53149, 576); +let wasm = file("ok/rust-region-instrument.wasm"); +let S = counter(wasm); +check_profiling(S, 126136, 574); +upgrade(S, wasm); +call S.get(); +assert _ == (45 : nat); +check_profiling(S, 911310, 2344); +counter(file("ok/rust-shrink.wasm")); +counter(file("ok/rust-limit.wasm")); let S = wat(file("ok/wat-instrument.wasm")); -call S.__get_cycles(); -assert _ == (189 : int64); +check_profiling(S, 189, 2); wat(file("ok/wat-shrink.wasm")); wat(file("ok/wat-limit.wasm")); diff --git a/tests/motoko-region.wasm b/tests/motoko-region.wasm new file mode 100644 index 0000000..bc67e5c Binary files /dev/null and b/tests/motoko-region.wasm differ diff --git a/tests/motoko.wasm b/tests/motoko.wasm index 6f3310b..caaf753 100644 Binary files a/tests/motoko.wasm and b/tests/motoko.wasm differ diff --git a/tests/ok/motoko-gc-instrument.wasm b/tests/ok/motoko-gc-instrument.wasm index 90f3a93..2c3c853 100644 Binary files a/tests/ok/motoko-gc-instrument.wasm and b/tests/ok/motoko-gc-instrument.wasm differ diff --git a/tests/ok/motoko-instrument.wasm b/tests/ok/motoko-instrument.wasm index 3caed0a..e59e7a1 100644 Binary files a/tests/ok/motoko-instrument.wasm and b/tests/ok/motoko-instrument.wasm differ diff --git a/tests/ok/motoko-limit.wasm b/tests/ok/motoko-limit.wasm index 35d0dc8..0801200 100644 Binary files a/tests/ok/motoko-limit.wasm and b/tests/ok/motoko-limit.wasm differ diff --git a/tests/ok/motoko-region-instrument.wasm b/tests/ok/motoko-region-instrument.wasm new file mode 100644 index 0000000..0d62a15 Binary files /dev/null and b/tests/ok/motoko-region-instrument.wasm differ diff --git a/tests/ok/motoko-shrink.wasm b/tests/ok/motoko-shrink.wasm index bc293db..767a606 100644 Binary files a/tests/ok/motoko-shrink.wasm and b/tests/ok/motoko-shrink.wasm differ diff --git a/tests/ok/rust-instrument.wasm b/tests/ok/rust-instrument.wasm index 66a2d27..4e29853 100644 Binary files a/tests/ok/rust-instrument.wasm and b/tests/ok/rust-instrument.wasm differ diff --git a/tests/ok/rust-limit.wasm b/tests/ok/rust-limit.wasm index e1b2cba..3c338ec 100644 Binary files a/tests/ok/rust-limit.wasm and b/tests/ok/rust-limit.wasm differ diff --git a/tests/ok/rust-region-instrument.wasm b/tests/ok/rust-region-instrument.wasm new file mode 100644 index 0000000..30fb265 Binary files /dev/null and b/tests/ok/rust-region-instrument.wasm differ diff --git a/tests/ok/rust-shrink.wasm b/tests/ok/rust-shrink.wasm index e1b2cba..3c338ec 100644 Binary files a/tests/ok/rust-shrink.wasm and b/tests/ok/rust-shrink.wasm differ diff --git a/tests/ok/wat-instrument.wasm b/tests/ok/wat-instrument.wasm index e724ba7..9ab72fb 100644 Binary files a/tests/ok/wat-instrument.wasm and b/tests/ok/wat-instrument.wasm differ diff --git a/tests/rust-region.wasm b/tests/rust-region.wasm new file mode 100644 index 0000000..7c67517 Binary files /dev/null and b/tests/rust-region.wasm differ diff --git a/tests/rust.wasm b/tests/rust.wasm index 23f119f..93e8f45 100644 Binary files a/tests/rust.wasm and b/tests/rust.wasm differ diff --git a/tests/tests.rs b/tests/tests.rs index 10e6043..91fb22a 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -48,6 +48,13 @@ fn instrumentation() { .assert() .success(); assert_wasm("motoko-gc-instrument.wasm"); + wasm_input("motoko-region.wasm", true) + .arg("instrument") + .arg("-s") + .arg("16") + .assert() + .success(); + assert_wasm("motoko-region-instrument.wasm"); wasm_input("wat.wasm", true) .arg("instrument") .assert() @@ -58,6 +65,13 @@ fn instrumentation() { .assert() .success(); assert_wasm("rust-instrument.wasm"); + wasm_input("rust-region.wasm", true) + .arg("instrument") + .arg("-s") + .arg("1") + .assert() + .success(); + assert_wasm("rust-region-instrument.wasm"); } #[test] @@ -209,9 +223,9 @@ fn metadata() { .assert() .stdout( r#"icp:public candid:service -icp:private candid:args icp:private motoko:stable-types icp:private motoko:compiler +icp:public candid:args "#, ) .success(); @@ -220,7 +234,7 @@ icp:private motoko:compiler .arg("metadata") .arg("motoko:compiler") .assert() - .stdout("0.6.25\n") + .stdout("0.10.0\n") .success(); // Get a non-existed metadata wasm_input("motoko.wasm", false) @@ -258,9 +272,9 @@ icp:private motoko:compiler .assert() .stdout( r#"icp:public candid:service -icp:private candid:args icp:private motoko:stable-types icp:private motoko:compiler +icp:public candid:args icp:public whatever "#, )