diff --git a/CHANGELOG.md b/CHANGELOG.md index aa33cb3695..a6b2f662d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,21 @@ The `dfx cycles` command no longer needs nor accepts the `--cycles-ledger-canist Updated to candid 0.10, ic-cdk 0.12, and ic-cdk-timers 0.6 +### fix: store playground canister acquisition timestamps with nanosecond precision on all platforms + +They've always been stored with nanosecond precisions on Linux and Macos. +Now they are stored with nanosecond precision on Windows too. + +## Dependencies + +### Motoko + +Updated Motoko to [0.10.4](https://github.com/dfinity/motoko/releases/tag/0.10.4) + +### Frontend canister + +Module hash: b625e04115725038808dcd6db1e398def28e981f8d6de464bb8438b2656864c8 + # 0.15.3 ### fix: allow `http://localhost:*` as `connect-src` in the asset canister's CSP @@ -1341,7 +1356,7 @@ Additionally, after build step, the `.wasm` file is archived with `gzip`. ### chore: Move all `frontend canister`-related code into the SDK repo | from (`repository` `path`) | to (path in `dfinity/sdk` repository) | summary | -| :------------------------------------------ | :--------------------------------------------- | :------------------------------------------------------------------------------------------ | +|:--------------------------------------------|:-----------------------------------------------|:--------------------------------------------------------------------------------------------| | `dfinity/cdk-rs` `/src/ic-certified-assets` | `/src/canisters/frontend/ic-certified-asset` | the core of the frontend canister | | `dfinity/certified-assets` `/` | `/src/canisters/frontend/ic-frontend-canister` | wraps `ic-certified-assets` to build the canister wasm | | `dfinity/agent-rs` `/ic-asset` | `/src/canisters/frontend/ic-asset` | library facilitating interactions with frontend canister (e.g. uploading or listing assets) | diff --git a/Cargo.lock b/Cargo.lock index 157ee92686..8936a6b315 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,10 +112,11 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aead" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ + "crypto-common", "generic-array", ] @@ -126,20 +127,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", - "cipher", + "cipher 0.3.0", "cpufeatures", "opaque-debug", ] +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.4.4", + "cpufeatures", +] + [[package]] name = "aes-gcm" -version = "0.9.4" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", - "aes", - "cipher", + "aes 0.8.3", + "cipher 0.4.4", "ctr", "ghash", "subtle", @@ -574,7 +586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" dependencies = [ "block-padding", - "cipher", + "cipher 0.3.0", ] [[package]] @@ -599,47 +611,26 @@ dependencies = [ [[package]] name = "borsh" -version = "0.10.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" dependencies = [ "borsh-derive", - "hashbrown 0.13.2", + "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" dependencies = [ + "once_cell", + "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.38", + "syn_derive", ] [[package]] @@ -820,10 +811,7 @@ dependencies = [ "arbitrary", "candid", "codespan-reporting", - "console", "convert_case 0.6.0", - "ctrlc", - "dialoguer", "fake", "hex", "lalrpop", @@ -860,6 +848,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" version = "0.4.31" @@ -893,6 +887,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.4.7" @@ -1197,6 +1201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] @@ -1212,11 +1217,11 @@ dependencies = [ [[package]] name = "ctr" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher", + "cipher 0.4.4", ] [[package]] @@ -1432,9 +1437,9 @@ dependencies = [ [[package]] name = "deunicode" -version = "1.4.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" +checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6" [[package]] name = "dfx" @@ -1446,7 +1451,6 @@ dependencies = [ "anyhow", "apply-patch", "argon2", - "atty", "backoff", "base64 0.13.1", "byte-unit", @@ -1540,6 +1544,7 @@ dependencies = [ "clap", "dialoguer", "directories-next", + "dunce", "flate2", "hex", "humantime-serde", @@ -1781,9 +1786,9 @@ dependencies = [ [[package]] name = "elsa" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" +checksum = "714f766f3556b44e7e4776ad133fcc3445a489517c25c704ace411bb14790194" dependencies = [ "stable_deref_trait", ] @@ -1889,9 +1894,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fake" -version = "2.9.2" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c25829bde82205da46e1823b2259db6273379f626fc211f126f65654a2669be" +checksum = "26221445034074d46b276e13eb97a265ebdb8ed8da705c4dddd3dd20b66b45d2" dependencies = [ "deunicode", "rand", @@ -2164,9 +2169,9 @@ dependencies = [ [[package]] name = "ghash" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ "opaque-debug", "polyval", @@ -2272,15 +2277,6 @@ dependencies = [ "ahash 0.7.7", ] -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.6", -] - [[package]] name = "hashbrown" version = "0.14.2" @@ -2624,9 +2620,9 @@ dependencies = [ [[package]] name = "ic-cdk" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ec8231f413b8a4d74b99d7df26d6e917d6528a6245abde27f251210dcf9b72" +checksum = "9f3d204af0b11c45715169c997858edb58fa8407d08f4fae78a6b415dd39a362" dependencies = [ "candid", "ic-cdk-macros", @@ -2637,9 +2633,9 @@ dependencies = [ [[package]] name = "ic-cdk-macros" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff30a6ddb3b50f1b7df689d203d2135b037706678368b1d73a9a98e17f87a9b4" +checksum = "a5a618e4020cea88e933d8d2f8c7f86d570ec06213506a80d4f2c520a9bba512" dependencies = [ "candid", "proc-macro2", @@ -3282,6 +3278,15 @@ dependencies = [ "regex", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -4338,9 +4343,9 @@ dependencies = [ [[package]] name = "polyval" -version = "0.5.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" dependencies = [ "cfg-if 1.0.0", "cpufeatures", @@ -4415,7 +4420,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" +dependencies = [ + "toml_edit 0.21.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", ] [[package]] @@ -4813,9 +4850,9 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" [[package]] name = "rust_decimal" -version = "1.32.0" +version = "1.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd" +checksum = "06676aec5ccb8fc1da723cc8c0f9a46549f21ebb8753d3915c6c41db1e7f1dc4" dependencies = [ "arrayvec 0.7.4", "borsh", @@ -5049,7 +5086,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1da5c423b8783185fd3fecd1c8796c267d2c089d894ce5a93c280a5d3f780a2" dependencies = [ - "aes", + "aes 0.7.5", "block-modes", "hkdf", "lazy_static", @@ -5097,9 +5134,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.190" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -5136,9 +5173,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.190" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", @@ -5544,11 +5581,11 @@ checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "supports-color" -version = "1.3.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba6faf2ca7ee42fdd458f4347ae0a9bd6bcc445ad7cb57ad82b383f18870d6f" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" dependencies = [ - "atty", + "is-terminal", "is_ci", ] @@ -5574,6 +5611,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "sysinfo" version = "0.28.4" @@ -5868,7 +5917,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] @@ -5893,6 +5942,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -6007,11 +6067,11 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array", + "crypto-common", "subtle", ] diff --git a/Cargo.toml b/Cargo.toml index d6cf229dff..54970ef0d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,15 +18,15 @@ rust-version = "1.71.1" license = "Apache-2.0" [workspace.dependencies] -candid = "0.10" -candid_parser = "0.1" -ic-agent = "0.31.0" +candid = "0.10.0" +candid_parser = "0.1.2" +ic-agent = { git = "https://github.com/dfinity/agent-rs.git", rev = "a7f44ad05e77fc89b8447dd65b345e7a62fd1042" } ic-asset = { path = "src/canisters/frontend/ic-asset" } ic-cdk = "0.12.0" -ic-identity-hsm = "0.31.0" -ic-utils = "0.31.0" +ic-identity-hsm = { git = "https://github.com/dfinity/agent-rs.git", rev = "a7f44ad05e77fc89b8447dd65b345e7a62fd1042" } +ic-utils = { git = "https://github.com/dfinity/agent-rs.git", rev = "a7f44ad05e77fc89b8447dd65b345e7a62fd1042" } -aes-gcm = "0.9.4" +aes-gcm = "0.10.3" anyhow = "1.0.56" anstyle = "1.0.0" argon2 = "0.4.0" @@ -69,21 +69,6 @@ tokio = "1.35" url = "2.1.0" walkdir = "2.3.2" -[patch.crates-io.ic-agent] -version = "0.31.0" -git = "https://github.com/dfinity/agent-rs.git" -rev = "a7f44ad05e77fc89b8447dd65b345e7a62fd1042" - -[patch.crates-io.ic-identity-hsm] -version = "0.31.0" -git = "https://github.com/dfinity/agent-rs.git" -rev = "a7f44ad05e77fc89b8447dd65b345e7a62fd1042" - -[patch.crates-io.ic-utils] -version = "0.31.0" -git = "https://github.com/dfinity/agent-rs.git" -rev = "a7f44ad05e77fc89b8447dd65b345e7a62fd1042" - [profile.release] panic = 'abort' lto = true diff --git a/e2e/tests-dfx/assetscanister.bash b/e2e/tests-dfx/assetscanister.bash index 9054596d96..6656c6849b 100644 --- a/e2e/tests-dfx/assetscanister.bash +++ b/e2e/tests-dfx/assetscanister.bash @@ -884,13 +884,12 @@ check_permission_failure() { assert_command dfx canister call --query e2e_project_frontend get '(record{key="/text-with-newlines.txt";accept_encodings=vec{"identity"}})' - assert_command dfx canister call --query e2e_project_frontend get_chunk '(record{key="/text-with-newlines.txt";content_encoding="identity";index=0;sha256=opt vec { 243; 191; 114; 177; 83; 18; 144; 121; 131; 38; 109; 183; 89; 244; 120; 136; 53; 187; 14; 74; 8; 112; 86; 100; 115; 8; 179; 155; 69; 78; 95; 160; }})' + assert_command dfx canister call --query e2e_project_frontend get_chunk '(record{key="/text-with-newlines.txt";content_encoding="identity";index=0;sha256=opt blob "\f3\bf\72\b1\53\12\90\79\83\26\6d\b7\59\f4\78\88\35\bb\0e\4a\08\70\56\64\73\08\b3\9b\45\4e\5f\a0" })' assert_command_fail dfx canister call --query e2e_project_frontend get_chunk '(record{key="/text-with-newlines.txt";content_encoding="identity";index=0})' assert_match 'sha256 required' - assert_command_fail dfx canister call --query e2e_project_frontend get_chunk '(record{key="/text-with-newlines.txt";content_encoding="identity";index=0;sha256=opt vec { 88; 87; 86; }})' + assert_command_fail dfx canister call --query e2e_project_frontend get_chunk '(record{key="/text-with-newlines.txt";content_encoding="identity";index=0;sha256=opt blob "XWV" })' assert_match 'sha256 mismatch' - assert_command dfx canister call --query e2e_project_frontend http_request_streaming_callback '(record{key="/text-with-newlines.txt";content_encoding="identity";index=0;sha256=opt vec { 243; 191; 114; 177; 83; 18; 144; 121; 131; 38; 109; 183; 89; 244; 120; 136; 53; 187; 14; 74; 8; 112; 86; 100; 115; 8; 179; 155; 69; 78; 95; 160; }})' assert_command dfx canister call --query e2e_project_frontend http_request_streaming_callback '(record{key="/text-with-newlines.txt";content_encoding="identity";index=0;sha256=opt blob "\f3\bf\72\b1\53\12\90\79\83\26\6d\b7\59\f4\78\88\35\bb\0e\4a\08\70\56\64\73\08\b3\9b\45\4e\5f\a0"})' assert_command_fail dfx canister call --query e2e_project_frontend http_request_streaming_callback '(record{key="/text-with-newlines.txt";content_encoding="identity";index=0;sha256=opt vec { 88; 87; 86; }})' assert_match 'sha256 mismatch' @@ -913,7 +912,7 @@ check_permission_failure() { assert_command dfx canister call --update e2e_project_frontend store '(record{key="AA"; content_type="text/plain"; content_encoding="identity"; content=blob "hello, world!"})' assert_eq '()' - assert_command dfx canister call --update e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' + assert_command dfx canister call --update e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=blob"XWV"})' assert_eq '()' assert_command dfx canister call --query e2e_project_frontend retrieve '("B")' --output idl diff --git a/e2e/tests-dfx/basic-project.bash b/e2e/tests-dfx/basic-project.bash index 603c235592..766a90f6fb 100644 --- a/e2e/tests-dfx/basic-project.bash +++ b/e2e/tests-dfx/basic-project.bash @@ -48,7 +48,7 @@ teardown() { '( variant { 17_724 = record { - 153_986_224 = blob "\44\49\44\4c\00\01\71\11\48\65\6c\6c\6f\2c\20\42\6c\75\65\62\65\72\72\79\21" + 153_986_224 = blob "\44\49\44\4c\00\01\71\11\48\65\6c\6c\6f\2c\20\42\6c\75\65\62\65\72\72\79\21"; } }, )' diff --git a/e2e/tests-dfx/build_granular.bash b/e2e/tests-dfx/build_granular.bash index d60b824b53..3b50ec9d94 100644 --- a/e2e/tests-dfx/build_granular.bash +++ b/e2e/tests-dfx/build_granular.bash @@ -67,7 +67,7 @@ teardown() { dfx canister install e2e_project_frontend assert_command dfx canister call --query e2e_project_frontend retrieve '("/binary/noise.txt")' --output idl - assert_eq '(blob "\b8\01 \80\0aw12 \00xy\0aKL\0b\0ajk")' + assert_eq '(blob "\b8\01\20\80\0a\77\31\32\20\00\78\79\0a\4b\4c\0b\0a\6a\6b")' assert_command dfx canister call --query e2e_project_frontend retrieve '("/text-with-newlines.txt")' --output idl assert_eq '(blob "cherries\0ait\27s cherry season\0aCHERRIES")' diff --git a/e2e/tests-dfx/identity.bash b/e2e/tests-dfx/identity.bash index a39681152f..4550368a5a 100644 --- a/e2e/tests-dfx/identity.bash +++ b/e2e/tests-dfx/identity.bash @@ -146,13 +146,13 @@ teardown() { assert_eq '(false)' # these all fail (other identities are not initializer; cannot store assets): - assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' --identity bob - assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' --identity default - assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' + assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=blob"XWV"})' --identity bob + assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=blob"XWV"})' --identity default + assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=blob"XWV"})' assert_command_fail dfx canister call e2e_project_frontend retrieve '("B")' # but alice, the initializer, can store assets: - assert_command dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' --identity alice + assert_command dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=blob"XWV"})' --identity alice assert_eq '()' assert_command dfx canister call --output idl e2e_project_frontend retrieve '("B")' assert_eq '(blob "XWV")' diff --git a/e2e/tests-dfx/wallet.bash b/e2e/tests-dfx/wallet.bash index b2c134f758..66bd979f98 100644 --- a/e2e/tests-dfx/wallet.bash +++ b/e2e/tests-dfx/wallet.bash @@ -131,7 +131,7 @@ teardown() { assert_command dfx canister call "$WALLET" wallet_call \ "(record { canister = principal \"$(dfx canister id e2e_project_backend)\"; method_name = \"amInitializer\"; args = blob \"DIDL\00\00\"; cycles = (0:nat64)})" - assert_eq '(variant { 17_724 = record { 153_986_224 = blob "DIDL\00\01~\01" } })' # True in DIDL. + assert_eq '(variant { 17_724 = record { 153_986_224 = blob "\44\49\44\4c\00\01\7e\01" } })' # True in DIDL. } @test "forward user call through wallet: deploy" { @@ -147,7 +147,7 @@ teardown() { assert_command dfx canister call e2e_project_backend amInitializer assert_command dfx canister call "$WALLET" wallet_call \ "(record { canister = principal \"$(dfx canister id e2e_project_backend)\"; method_name = \"amInitializer\"; args = blob \"DIDL\00\00\"; cycles = (0:nat64)})" - assert_eq '(variant { 17_724 = record { 153_986_224 = blob "DIDL\00\01~\01" } })' # True in DIDL. + assert_eq '(variant { 17_724 = record { 153_986_224 = blob "\44\49\44\4c\00\01\7e\01" } })' # True in DIDL. } @test "a 64-bit wallet can still be called in the 128-bit context" { diff --git a/nix/sources.json b/nix/sources.json index e0c9af5fe6..1a8ef923db 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -144,25 +144,25 @@ "owner": "dfinity", "sha256": "0x78h0xy31jdsinrhfa0hb9xyggs3cbn5jfxxy30gfjc4a6j04p1", "type": "tarball", - "url": "https://github.com/dfinity/motoko/releases/download/0.10.3/motoko-base-library.tar.gz", + "url": "https://github.com/dfinity/motoko/releases/download/0.10.4/motoko-base-library.tar.gz", "url_template": "https://github.com/dfinity/motoko/releases/download//motoko-base-library.tar.gz", - "version": "0.10.3" + "version": "0.10.4" }, "motoko-x86_64-darwin": { "builtin": false, - "sha256": "0ws8i03fvq42zkjrlwlmz67p2dfm7wzng3ilm3gg5igfpqrvvf2w", + "sha256": "0mv708lj4hzr3c6ld9mr25l0anvanx6agfrmad7ccw29dnbixjr1", "type": "file", - "url": "https://github.com/dfinity/motoko/releases/download/0.10.3/motoko-Darwin-x86_64-0.10.3.tar.gz", + "url": "https://github.com/dfinity/motoko/releases/download/0.10.4/motoko-Darwin-x86_64-0.10.4.tar.gz", "url_template": "https://github.com/dfinity/motoko/releases/download//motoko-Darwin-x86_64-.tar.gz", - "version": "0.10.3" + "version": "0.10.4" }, "motoko-x86_64-linux": { "builtin": false, - "sha256": "1h19zkw49qwi8q9sllizpyy84ibgaq85i6p0jc6n8fr5gdy0bs7q", + "sha256": "0ml813b4108h3dxcz7lhpcihn4vp1yg9g66chc767hagzsabkgj8", "type": "file", - "url": "https://github.com/dfinity/motoko/releases/download/0.10.3/motoko-Linux-x86_64-0.10.3.tar.gz", + "url": "https://github.com/dfinity/motoko/releases/download/0.10.4/motoko-Linux-x86_64-0.10.4.tar.gz", "url_template": "https://github.com/dfinity/motoko/releases/download//motoko-Linux-x86_64-.tar.gz", - "version": "0.10.3" + "version": "0.10.4" }, "replica-x86_64-darwin": { "builtin": false, diff --git a/src/canisters/frontend/ic-asset/src/sync.rs b/src/canisters/frontend/ic-asset/src/sync.rs index 51ed0281b4..b927d1513e 100644 --- a/src/canisters/frontend/ic-asset/src/sync.rs +++ b/src/canisters/frontend/ic-asset/src/sync.rs @@ -138,7 +138,7 @@ async fn commit_in_stages( commit_batch( canister, CommitBatchArguments { - batch_id: Nat::from(0u8), + batch_id: Nat::from(0_u8), operations: operations.into(), }, ) @@ -156,7 +156,7 @@ async fn commit_in_stages( commit_batch( canister, CommitBatchArguments { - batch_id: Nat::from(0u8), + batch_id: Nat::from(0_u8), operations: operations.into(), }, ) @@ -239,7 +239,7 @@ pub(crate) fn gather_asset_descriptors( let entries = WalkDir::new(&dir) .into_iter() .filter_entry(|entry| { - if let Ok(canonical_path) = &entry.path().canonicalize() { + if let Ok(canonical_path) = &dfx_core::fs::canonicalize(entry.path()) { let config = configuration .get_asset_config(canonical_path) .unwrap_or_default(); diff --git a/src/canisters/frontend/ic-certified-assets/Cargo.toml b/src/canisters/frontend/ic-certified-assets/Cargo.toml index d4d1d0d5c7..7f5028204a 100644 --- a/src/canisters/frontend/ic-certified-assets/Cargo.toml +++ b/src/canisters/frontend/ic-certified-assets/Cargo.toml @@ -33,4 +33,3 @@ anyhow.workspace = true ic-response-verification-test-utils = { git = "https://github.com/dfinity/response-verification.git", rev = "a65009624b61736df6d2dc17756bdbd02a84f599" } ic-certification-testing = { git = "https://github.com/dfinity/response-verification.git", rev = "a65009624b61736df6d2dc17756bdbd02a84f599" } ic-crypto-tree-hash = { git = "https://github.com/dfinity/ic.git", rev = "1290256484f59c3d950c5e9a098e97383b248ad6" } - diff --git a/src/canisters/frontend/ic-certified-assets/src/lib.rs b/src/canisters/frontend/ic-certified-assets/src/lib.rs index 80ddeba765..087f81bc59 100644 --- a/src/canisters/frontend/ic-certified-assets/src/lib.rs +++ b/src/canisters/frontend/ic-certified-assets/src/lib.rs @@ -18,7 +18,7 @@ use crate::{ types::*, }; use asset_certification::types::{certification::AssetKey, rc_bytes::RcBytes}; -use candid::Principal; +use candid::{candid_method, Principal}; use ic_cdk::api::{call::ManualReply, caller, data_certificate, set_certified_data, time, trap}; use ic_cdk::{query, update}; use serde_bytes::ByteBuf; @@ -33,16 +33,19 @@ thread_local! { } #[query] +#[candid_method(query)] fn api_version() -> u16 { 1 } #[update(guard = "is_manager_or_controller")] +#[candid_method(update)] fn authorize(other: Principal) { STATE.with(|s| s.borrow_mut().grant_permission(other, &Permission::Commit)) } #[update(guard = "is_manager_or_controller")] +#[candid_method(update)] fn grant_permission(arg: GrantPermissionArguments) { STATE.with(|s| { s.borrow_mut() @@ -51,6 +54,7 @@ fn grant_permission(arg: GrantPermissionArguments) { } #[update] +#[candid_method(update)] async fn validate_grant_permission(arg: GrantPermissionArguments) -> Result { Ok(format!( "grant {} permission to principal {}", @@ -59,6 +63,7 @@ async fn validate_grant_permission(arg: GrantPermissionArguments) -> Result Result { Ok(format!( "revoke {} permission from principal {}", @@ -98,27 +105,32 @@ async fn validate_revoke_permission(arg: RevokePermissionArguments) -> Result ManualReply> { STATE.with(|s| ManualReply::one(s.borrow().list_permitted(&Permission::Commit))) } #[update(manual_reply = true)] +#[candid_method(update)] fn list_permitted(arg: ListPermittedArguments) -> ManualReply> { STATE.with(|s| ManualReply::one(s.borrow().list_permitted(&arg.permission))) } #[update(guard = "is_controller")] +#[candid_method(update)] async fn take_ownership() { let caller = ic_cdk::api::caller(); STATE.with(|s| s.borrow_mut().take_ownership(caller)) } #[update] +#[candid_method(update)] async fn validate_take_ownership() -> Result { Ok("revoke all permissions, then gives the caller Commit permissions".to_string()) } #[query] +#[candid_method(query)] fn retrieve(key: AssetKey) -> RcBytes { STATE.with(|s| match s.borrow().retrieve(&key) { Ok(bytes) => bytes, @@ -127,6 +139,7 @@ fn retrieve(key: AssetKey) -> RcBytes { } #[update(guard = "can_commit")] +#[candid_method(update)] fn store(arg: StoreArg) { STATE.with(move |s| { if let Err(msg) = s.borrow_mut().store(arg, time()) { @@ -137,6 +150,7 @@ fn store(arg: StoreArg) { } #[update(guard = "can_prepare")] +#[candid_method(update)] fn create_batch() -> CreateBatchResponse { STATE.with(|s| match s.borrow_mut().create_batch(time()) { Ok(batch_id) => CreateBatchResponse { batch_id }, @@ -145,6 +159,7 @@ fn create_batch() -> CreateBatchResponse { } #[update(guard = "can_prepare")] +#[candid_method(update)] fn create_chunk(arg: CreateChunkArg) -> CreateChunkResponse { STATE.with(|s| match s.borrow_mut().create_chunk(arg, time()) { Ok(chunk_id) => CreateChunkResponse { chunk_id }, @@ -153,6 +168,7 @@ fn create_chunk(arg: CreateChunkArg) -> CreateChunkResponse { } #[update(guard = "can_commit")] +#[candid_method(update)] fn create_asset(arg: CreateAssetArguments) { STATE.with(|s| { if let Err(msg) = s.borrow_mut().create_asset(arg) { @@ -163,6 +179,7 @@ fn create_asset(arg: CreateAssetArguments) { } #[update(guard = "can_commit")] +#[candid_method(update)] fn set_asset_content(arg: SetAssetContentArguments) { STATE.with(|s| { if let Err(msg) = s.borrow_mut().set_asset_content(arg, time()) { @@ -173,6 +190,7 @@ fn set_asset_content(arg: SetAssetContentArguments) { } #[update(guard = "can_commit")] +#[candid_method(update)] fn unset_asset_content(arg: UnsetAssetContentArguments) { STATE.with(|s| { if let Err(msg) = s.borrow_mut().unset_asset_content(arg) { @@ -183,6 +201,7 @@ fn unset_asset_content(arg: UnsetAssetContentArguments) { } #[update(guard = "can_commit")] +#[candid_method(update)] fn delete_asset(arg: DeleteAssetArguments) { STATE.with(|s| { s.borrow_mut().delete_asset(arg); @@ -191,6 +210,7 @@ fn delete_asset(arg: DeleteAssetArguments) { } #[update(guard = "can_commit")] +#[candid_method(update)] fn clear() { STATE.with(|s| { s.borrow_mut().clear(); @@ -199,6 +219,7 @@ fn clear() { } #[update(guard = "can_commit")] +#[candid_method(update)] fn commit_batch(arg: CommitBatchArguments) { STATE.with(|s| { if let Err(msg) = s.borrow_mut().commit_batch(arg, time()) { @@ -209,6 +230,7 @@ fn commit_batch(arg: CommitBatchArguments) { } #[update(guard = "can_prepare")] +#[candid_method(update)] fn propose_commit_batch(arg: CommitBatchArguments) { STATE.with(|s| { if let Err(msg) = s.borrow_mut().propose_commit_batch(arg) { @@ -218,6 +240,7 @@ fn propose_commit_batch(arg: CommitBatchArguments) { } #[update(guard = "can_prepare")] +#[candid_method(update)] fn compute_evidence(arg: ComputeEvidenceArguments) -> Option { STATE.with(|s| match s.borrow_mut().compute_evidence(arg) { Err(msg) => trap(&msg), @@ -226,6 +249,7 @@ fn compute_evidence(arg: ComputeEvidenceArguments) -> Option { } #[update(guard = "can_commit")] +#[candid_method(update)] fn commit_proposed_batch(arg: CommitProposedBatchArguments) { STATE.with(|s| { if let Err(msg) = s.borrow_mut().commit_proposed_batch(arg, time()) { @@ -236,11 +260,13 @@ fn commit_proposed_batch(arg: CommitProposedBatchArguments) { } #[update] +#[candid_method(update)] fn validate_commit_proposed_batch(arg: CommitProposedBatchArguments) -> Result { STATE.with(|s| s.borrow_mut().validate_commit_proposed_batch(arg)) } #[update(guard = "can_prepare")] +#[candid_method(update)] fn delete_batch(arg: DeleteBatchArguments) { STATE.with(|s| { if let Err(msg) = s.borrow_mut().delete_batch(arg) { @@ -250,6 +276,7 @@ fn delete_batch(arg: DeleteBatchArguments) { } #[query] +#[candid_method(query)] fn get(arg: GetArg) -> EncodedAsset { STATE.with(|s| match s.borrow().get(arg) { Ok(asset) => asset, @@ -258,6 +285,7 @@ fn get(arg: GetArg) -> EncodedAsset { } #[query] +#[candid_method(query)] fn get_chunk(arg: GetChunkArg) -> GetChunkResponse { STATE.with(|s| match s.borrow().get_chunk(arg) { Ok(content) => GetChunkResponse { content }, @@ -266,11 +294,13 @@ fn get_chunk(arg: GetChunkArg) -> GetChunkResponse { } #[query] +#[candid_method(query)] fn list() -> Vec { STATE.with(|s| s.borrow().list_assets()) } #[query] +#[candid_method(query)] fn certified_tree() -> CertifiedTree { let certificate = data_certificate().unwrap_or_else(|| trap("no data certificate available")); @@ -278,6 +308,7 @@ fn certified_tree() -> CertifiedTree { } #[query] +#[candid_method(query)] fn http_request(req: HttpRequest) -> HttpResponse { let certificate = data_certificate().unwrap_or_else(|| trap("no data certificate available")); @@ -291,6 +322,7 @@ fn http_request(req: HttpRequest) -> HttpResponse { } #[query] +#[candid_method(query)] fn http_request_streaming_callback(token: StreamingCallbackToken) -> StreamingCallbackHttpResponse { STATE.with(|s| { s.borrow() @@ -300,6 +332,7 @@ fn http_request_streaming_callback(token: StreamingCallbackToken) -> StreamingCa } #[query] +#[candid_method(query)] fn get_asset_properties(key: AssetKey) -> AssetProperties { STATE.with(|s| { s.borrow() @@ -309,6 +342,7 @@ fn get_asset_properties(key: AssetKey) -> AssetProperties { } #[update(guard = "can_commit")] +#[candid_method(update)] fn set_asset_properties(arg: SetAssetPropertiesArguments) { STATE.with(|s| { if let Err(msg) = s.borrow_mut().set_asset_properties(arg) { @@ -318,16 +352,19 @@ fn set_asset_properties(arg: SetAssetPropertiesArguments) { } #[update(guard = "can_prepare")] +#[candid_method(update)] fn get_configuration() -> ConfigurationResponse { STATE.with(|s| s.borrow().get_configuration()) } #[update(guard = "can_commit")] +#[candid_method(update)] fn configure(arg: ConfigureArguments) { STATE.with(|s| s.borrow_mut().configure(arg)) } #[update] +#[candid_method(update)] fn validate_configure(arg: ConfigureArguments) -> Result { Ok(format!("configure: {:?}", arg)) } @@ -378,9 +415,7 @@ fn is_controller() -> Result<(), String> { pub fn init(args: Option) { if let Some(upgrade_arg) = args { - let AssetCanisterArgs::Init(InitArgs {}) = upgrade_arg else { - ic_cdk::trap("Cannot initialize the canister with an Upgrade argument. Please provide an Init argument.") - }; + let AssetCanisterArgs::Init(InitArgs {}) = upgrade_arg else { ic_cdk::trap("Cannot initialize the canister with an Upgrade argument. Please provide an Init argument.")}; } STATE.with(|s| { let mut s = s.borrow_mut(); diff --git a/src/canisters/frontend/ic-certified-assets/src/state_machine.rs b/src/canisters/frontend/ic-certified-assets/src/state_machine.rs index 4521a1eed8..01d8d36e8e 100644 --- a/src/canisters/frontend/ic-certified-assets/src/state_machine.rs +++ b/src/canisters/frontend/ic-certified-assets/src/state_machine.rs @@ -472,8 +472,8 @@ impl State { self.assets.clear(); self.batches.clear(); self.chunks.clear(); - self.next_batch_id = Nat::from(1u8); - self.next_chunk_id = Nat::from(1u8); + self.next_batch_id = Nat::from(1_u8); + self.next_chunk_id = Nat::from(1_u8); } pub fn has_permission(&self, principal: &Principal, permission: &Permission) -> bool { @@ -566,7 +566,7 @@ impl State { } } let batch_id = self.next_batch_id.clone(); - self.next_batch_id += 1u8; + self.next_batch_id += 1_u8; self.batches.insert( batch_id.clone(), @@ -607,7 +607,7 @@ impl State { batch.expires_at = Int::from(now + BATCH_EXPIRY_NANOS); let chunk_id = self.next_chunk_id.clone(); - self.next_chunk_id += 1u8; + self.next_chunk_id += 1_u8; batch.chunk_content_total_size += arg.content.as_ref().len(); self.chunks.insert( @@ -1093,7 +1093,9 @@ impl From for State { prepare_principals, manage_permissions_principals, assets: stable_state.stable_assets, - next_batch_id: stable_state.next_batch_id.unwrap_or_else(|| Nat::from(1u8)), + next_batch_id: stable_state + .next_batch_id + .unwrap_or_else(|| Nat::from(1_u8)), configuration: stable_state.configuration.unwrap_or_default(), ..Self::default() }; diff --git a/src/canisters/frontend/ic-certified-assets/src/tests.rs b/src/canisters/frontend/ic-certified-assets/src/tests.rs index 30a610a16f..7e77c6c9aa 100644 --- a/src/canisters/frontend/ic-certified-assets/src/tests.rs +++ b/src/canisters/frontend/ic-certified-assets/src/tests.rs @@ -10,10 +10,11 @@ use crate::types::{ }; use crate::url_decode::{url_decode, UrlDecodeError}; use candid::{Nat, Principal}; -use ic_certification_testing::CertificateBuilder; use ic_crypto_tree_hash::Digest; +use ic_response_verification::ResponseVerificationError; use ic_response_verification_test_utils::{ - base64_encode, create_canister_id, get_current_timestamp, + base64_encode, create_canister_id, get_current_timestamp, CanisterData, CertificateBuilder, + CertificateData, }; use serde_bytes::ByteBuf; use std::collections::HashMap; @@ -33,20 +34,21 @@ pub fn verify_response( state: &State, request: &HttpRequest, response: &HttpResponse, -) -> anyhow::Result { +) -> Result { let mut response = response.clone(); let current_time = get_current_timestamp(); let canister_id = create_canister_id("rdmx6-jaaaa-aaaaa-aaadq-cai"); let min_requested_verification_version = request.get_certificate_version(); // inject certificate into IC-Certificate header with 'certificate=::' - let data = CertificateBuilder::new( - &canister_id.to_string(), - Digest(state.root_hash()).as_bytes(), - )? - .with_time(current_time) - .build()?; - let replacement_cert_value = base64_encode(&data.cbor_encoded_certificate); + let (_cert, root_key, cert_cbor) = + CertificateBuilder::new(CertificateData::CanisterData(CanisterData { + canister_id, + certified_data: Digest(state.root_hash()), + })) + .with_time(current_time) + .build(); + let replacement_cert_value = base64_encode(&cert_cbor); let (_, header_value) = response .headers .iter_mut() @@ -58,28 +60,26 @@ pub fn verify_response( ); // actual verification - let request = ic_http_certification::http::HttpRequest { + let request = ic_response_verification::types::Request { method: request.method.clone(), url: request.url.clone(), headers: request.headers.clone(), - body: request.body[..].into(), }; - let response = ic_http_certification::http::HttpResponse { + let response = ic_response_verification::types::Response { status_code: response.status_code, headers: response.headers, body: response.body[..].into(), - upgrade: None, }; - Ok(ic_response_verification::verify_request_response_pair( + ic_response_verification::verify_request_response_pair( request, response, canister_id.as_ref(), current_time, MAX_CERT_TIME_OFFSET_NS, - &data.root_key, + &root_key, min_requested_verification_version.try_into().unwrap(), ) - .map(|res| res.response.is_some())?) + .map(|res| res.passed) } fn certified_http_request(state: &State, request: HttpRequest) -> HttpResponse { @@ -962,7 +962,7 @@ fn uses_streaming_for_multichunk_assets() { .http_request_streaming_callback(StreamingCallbackToken { key: "/index.html".to_string(), content_encoding: "identity".to_string(), - index: Nat::from(1u8), + index: Nat::from(1_u8), sha256: None, }) .unwrap_err(), @@ -1005,7 +1005,7 @@ fn get_and_get_chunk_for_multichunk_assets() { .get_chunk(GetChunkArg { key: "/index.html".to_string(), content_encoding: "identity".to_string(), - index: Nat::from(1u8), + index: Nat::from(1_u8), sha256: chunk_0.sha256, }) .unwrap(); @@ -1017,7 +1017,7 @@ fn get_and_get_chunk_for_multichunk_assets() { .get_chunk(GetChunkArg { key: "/index.html".to_string(), content_encoding: "identity".to_string(), - index: Nat::from(1u8), + index: Nat::from(1_u8), sha256: None, }) .unwrap_err(), @@ -3347,7 +3347,7 @@ mod validate_commit_proposed_batch { let time_now = 100_000_000_000; match state.validate_commit_proposed_batch(CommitProposedBatchArguments { - batch_id: 1u8.into(), + batch_id: 1_u8.into(), evidence: Default::default(), }) { Err(err) if err.contains("batch not found") => (), @@ -3356,7 +3356,7 @@ mod validate_commit_proposed_batch { match state.commit_proposed_batch( CommitProposedBatchArguments { - batch_id: 1u8.into(), + batch_id: 1_u8.into(), evidence: Default::default(), }, time_now, diff --git a/src/dfx-core/Cargo.toml b/src/dfx-core/Cargo.toml index d9b64bc314..2f7a12daff 100644 --- a/src/dfx-core/Cargo.toml +++ b/src/dfx-core/Cargo.toml @@ -17,6 +17,7 @@ candid = { workspace = true } clap = { workspace = true, features = ["string"] } dialoguer = { workspace = true } directories-next.workspace = true +dunce = "1.0" flate2 = { workspace = true, default-features = false, features = ["zlib-ng"] } hex = { workspace = true, features = ["serde"] } humantime-serde = "1.1.1" diff --git a/src/dfx-core/src/config/model/canister_id_store.rs b/src/dfx-core/src/config/model/canister_id_store.rs index 76485bef5a..68693ac0f1 100644 --- a/src/dfx-core/src/config/model/canister_id_store.rs +++ b/src/dfx-core/src/config/model/canister_id_store.rs @@ -23,11 +23,14 @@ pub type CanisterIds = BTreeMap; pub type CanisterTimestamps = BTreeMap; +// OffsetDateTime has nanosecond precision, while SystemTime is OS-dependent (100ns on Windows) +pub type AcquisitionDateTime = OffsetDateTime; + #[derive(Debug, Clone, Default)] -pub struct NetworkNametoCanisterTimestamp(BTreeMap); +pub struct NetworkNametoCanisterTimestamp(BTreeMap); impl Deref for NetworkNametoCanisterTimestamp { - type Target = BTreeMap; + type Target = BTreeMap; fn deref(&self) -> &Self::Target { &self.0 @@ -48,7 +51,7 @@ impl Serialize for NetworkNametoCanisterTimestamp { let out = self.0.iter().map(|(key, time)| { ( key, - OffsetDateTime::from(*time) + AcquisitionDateTime::from(*time) .format(&Rfc3339) .expect("Failed to serialise timestamp"), ) @@ -63,12 +66,12 @@ impl<'de> Deserialize<'de> for NetworkNametoCanisterTimestamp { D: serde::Deserializer<'de>, { let map: BTreeMap = Deserialize::deserialize(deserializer)?; - let btree: BTreeMap = map + let btree: BTreeMap = map .into_iter() - .map(|(key, timestamp)| (key, OffsetDateTime::parse(×tamp, &Rfc3339))) + .map(|(key, timestamp)| (key, AcquisitionDateTime::parse(×tamp, &Rfc3339))) .try_fold(BTreeMap::new(), |mut map, (key, result)| match result { Ok(value) => { - map.insert(key, SystemTime::from(value)); + map.insert(key, value); Ok(map) } Err(err) => Err(err), @@ -178,7 +181,7 @@ impl CanisterIdStore { Ok(store) } - pub fn get_timestamp(&self, canister_name: &str) -> Option<&SystemTime> { + pub fn get_timestamp(&self, canister_name: &str) -> Option<&AcquisitionDateTime> { self.acquisition_timestamps .get(canister_name) .and_then(|timestamp_map| timestamp_map.get(&self.network_descriptor.name)) @@ -277,7 +280,7 @@ impl CanisterIdStore { &mut self, canister_name: &str, canister_id: &str, - timestamp: Option, + timestamp: Option, ) -> Result<(), CanisterIdStoreError> { let network_name = &self.network_descriptor.name; match self.ids.get_mut(canister_name) { diff --git a/src/dfx-core/src/fs/mod.rs b/src/dfx-core/src/fs/mod.rs index 83eb3d412c..adddaf3d49 100644 --- a/src/dfx-core/src/fs/mod.rs +++ b/src/dfx-core/src/fs/mod.rs @@ -11,7 +11,7 @@ use std::fs::{Metadata, Permissions, ReadDir}; use std::path::{Path, PathBuf}; pub fn canonicalize(path: &Path) -> Result { - path.canonicalize() + dunce::canonicalize(path) .map_err(|err| FsError::new(CanonicalizePathFailed(path.to_path_buf(), err))) } diff --git a/src/dfx-core/src/identity/pem_safekeeping.rs b/src/dfx-core/src/identity/pem_safekeeping.rs index ca520114a5..baa5f10b59 100644 --- a/src/dfx-core/src/identity/pem_safekeeping.rs +++ b/src/dfx-core/src/identity/pem_safekeeping.rs @@ -20,7 +20,7 @@ use crate::error::identity::write_pem_to_file::WritePemToFileError::{ use crate::identity::identity_file_locations::IdentityFileLocations; use crate::identity::keyring_mock; use crate::identity::pem_safekeeping::PromptMode::{DecryptingToUse, EncryptingToCreate}; -use aes_gcm::aead::{Aead, NewAead}; +use aes_gcm::aead::{Aead, KeyInit}; use aes_gcm::{Aes256Gcm, Key, Nonce}; use argon2::{password_hash::PasswordHasher, Argon2}; use slog::{debug, trace, Logger}; @@ -201,7 +201,7 @@ fn encrypt( let hash = argon2 .hash_password(password.as_bytes(), &config.pw_salt) .map_err(EncryptionError::HashPasswordFailed)?; - let key = Key::clone_from_slice(hash.hash.unwrap().as_ref()); + let key = Key::::clone_from_slice(hash.hash.unwrap().as_ref()); let cipher = Aes256Gcm::new(&key); let nonce = Nonce::from_slice(config.file_nonce.as_slice()); @@ -225,7 +225,7 @@ fn decrypt( let hash = argon2 .hash_password(password.as_bytes(), &config.pw_salt) .map_err(HashPasswordFailed)?; - let key = Key::clone_from_slice(hash.hash.unwrap().as_ref()); + let key = Key::::clone_from_slice(hash.hash.unwrap().as_ref()); let cipher = Aes256Gcm::new(&key); let nonce = Nonce::from_slice(config.file_nonce.as_slice()); diff --git a/src/dfx/Cargo.toml b/src/dfx/Cargo.toml index 1868b3e058..5927305ff4 100644 --- a/src/dfx/Cargo.toml +++ b/src/dfx/Cargo.toml @@ -34,13 +34,12 @@ anstyle.workspace = true anyhow.workspace = true apply-patch.path = "../lib/apply-patch" argon2.workspace = true -atty = "0.2.13" backoff.workspace = true base64.workspace = true byte-unit = { workspace = true, features = ["serde"] } bytes.workspace = true candid = { workspace = true } -candid_parser = { workspace = true, features = ["all"] } +candid_parser = { workspace = true, features = ["random"] } clap = { workspace = true, features = [ "derive", "env", @@ -105,7 +104,7 @@ shell-words = "1.1.0" slog = { workspace = true, features = ["max_level_trace"] } slog-async.workspace = true slog-term.workspace = true -supports-color = "1.3.0" +supports-color = "2.1.0" sysinfo = "0.28.4" tar.workspace = true tempfile.workspace = true diff --git a/src/dfx/assets/dfx-asset-sources.toml b/src/dfx/assets/dfx-asset-sources.toml index 607a569c23..7e21b9f154 100644 --- a/src/dfx/assets/dfx-asset-sources.toml +++ b/src/dfx/assets/dfx-asset-sources.toml @@ -26,8 +26,8 @@ url = 'https://download.dfinity.systems/ic/69e1408347723dbaa7a6cd2faa9b65c42abbe sha256 = '1f33354049b6c83c8be06344d913a8bcfdb61ba9234706a8bf3cdb3d620723ab' [x86_64-darwin.motoko] -url = 'https://github.com/dfinity/motoko/releases/download/0.10.3/motoko-Darwin-x86_64-0.10.3.tar.gz' -sha256 = '5cb8bd33beeec5f2dea8348e673f3fd535718ff995729ae5fc82e0ed06884873' +url = 'https://github.com/dfinity/motoko/releases/download/0.10.4/motoko-Darwin-x86_64-0.10.4.tar.gz' +sha256 = '21cb1e976d4970c64e5335bba74cb76a5b056811b9a6460d1bf9432229026757' # The replica and canister_sandbox binaries must have the same revision. [x86_64-darwin.replica] @@ -48,7 +48,7 @@ url = 'https://download.dfinity.systems/ic/69e1408347723dbaa7a6cd2faa9b65c42abbe sha256 = '04d06a093913ef59d9d4c7cdc14a0751cff6465384d60204e03d5f396edfb38b' [x86_64-darwin.motoko-base] -url = 'https://github.com/dfinity/motoko/releases/download/0.10.3/motoko-base-library.tar.gz' +url = 'https://github.com/dfinity/motoko/releases/download/0.10.4/motoko-base-library.tar.gz' sha256 = '3ee345fb0357ee9305e911d8aa30a00675114c3247af79bb16b8c21f8477dc3c' [x86_64-darwin.ic-btc-canister] @@ -80,8 +80,8 @@ url = 'https://download.dfinity.systems/ic/69e1408347723dbaa7a6cd2faa9b65c42abbe sha256 = '8d8c51033cb2cd20049ca4e048144b895684d7a4fdbd07719476797b53ebafb5' [x86_64-linux.motoko] -url = 'https://github.com/dfinity/motoko/releases/download/0.10.3/motoko-Linux-x86_64-0.10.3.tar.gz' -sha256 = 'f8e8057c7b253b640d93e09a5810566f4582bcbf3f52aa134691e344f8fc29c0' +url = 'https://github.com/dfinity/motoko/releases/download/0.10.4/motoko-Linux-x86_64-0.10.4.tar.gz' +sha256 = '48beb994fe4fc1630e83cc98979e0f77130b23bb909ecf7a1b108140d6088856' # The replica and canister_sandbox binaries must have the same revision. [x86_64-linux.replica] @@ -102,7 +102,7 @@ url = 'https://download.dfinity.systems/ic/69e1408347723dbaa7a6cd2faa9b65c42abbe sha256 = '966a84f1e563049e09381b39cbcde24b0c77032ee2cfddb40962eecb70925809' [x86_64-linux.motoko-base] -url = 'https://github.com/dfinity/motoko/releases/download/0.10.3/motoko-base-library.tar.gz' +url = 'https://github.com/dfinity/motoko/releases/download/0.10.4/motoko-base-library.tar.gz' sha256 = '3ee345fb0357ee9305e911d8aa30a00675114c3247af79bb16b8c21f8477dc3c' [x86_64-linux.ic-btc-canister] diff --git a/src/dfx/src/commands/deps/init.rs b/src/dfx/src/commands/deps/init.rs index 988ef5b839..05e0b81172 100644 --- a/src/dfx/src/commands/deps/init.rs +++ b/src/dfx/src/commands/deps/init.rs @@ -8,7 +8,7 @@ use crate::lib::error::DfxResult; use crate::util::{check_candid_file, fuzzy_parse_argument}; use anyhow::{anyhow, bail}; use candid::Principal; -use candid_parser::types::IDLTypes; +use candid_parser::{types::IDLTypes, typing::ast_to_type}; use clap::Parser; use slog::{info, warn, Logger}; @@ -73,7 +73,7 @@ fn set_init( let candid_args_idl_types: IDLTypes = candid_args.parse()?; let mut types = vec![]; for ty in candid_args_idl_types.args.iter() { - types.push(candid_parser::typing::ast_to_type(&env, ty)?); + types.push(ast_to_type(&env, ty)?); } let arguments = opts.argument.as_deref(); diff --git a/src/dfx/src/commands/language_service.rs b/src/dfx/src/commands/language_service.rs index ed927f5040..fe25382a55 100644 --- a/src/dfx/src/commands/language_service.rs +++ b/src/dfx/src/commands/language_service.rs @@ -12,6 +12,7 @@ use dfx_core::config::model::dfinity::{ }; use dfx_core::network::provider::{create_network_descriptor, LocalBindDetermination}; use fn_error_context::context; +use std::io::{stdout, IsTerminal}; use std::path::PathBuf; use std::process::Stdio; @@ -36,7 +37,7 @@ pub struct LanguageServiceOpts { pub fn exec(env: &dyn Environment, opts: LanguageServiceOpts) -> DfxResult { let force_tty = opts.force_tty; // Are we being run from a terminal? That's most likely not what we want - if atty::is(atty::Stream::Stdout) && !force_tty { + if stdout().is_terminal() && !force_tty { Err(anyhow!("The `_language-service` command is meant to be run by editors to start a language service. You probably don't want to run it from a terminal.\nIf you _really_ want to, you can pass the --force-tty flag.")) } else if let Some(config) = env.get_config() { let main_path = get_main_path(config.get_config(), opts.canister)?; diff --git a/src/dfx/src/commands/new.rs b/src/dfx/src/commands/new.rs index 99f205b162..708adff9b6 100644 --- a/src/dfx/src/commands/new.rs +++ b/src/dfx/src/commands/new.rs @@ -2,6 +2,7 @@ use crate::config::cache::DiskBasedCache; use crate::lib::environment::Environment; use crate::lib::error::{DfxError, DfxResult}; use crate::lib::manifest::{get_latest_version, is_upgrade_necessary}; +use crate::lib::program; use crate::util::assets; use crate::util::clap::parsers::project_name_parser; use anyhow::{anyhow, bail, ensure, Context}; @@ -249,12 +250,12 @@ fn write_files_from_entries( #[context("Failed to run 'npm install'.")] fn npm_install(location: &Path) -> DfxResult { - std::process::Command::new("npm") + Command::new(program::NPM) .arg("install") .arg("--quiet") .arg("--no-progress") - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) .current_dir(location) .spawn() .map_err(DfxError::from) @@ -271,7 +272,7 @@ fn scaffold_frontend_code( variables: &BTreeMap, ) -> DfxResult { let log = env.get_logger(); - let node_installed = std::process::Command::new("node") + let node_installed = Command::new(program::NODE) .arg("--version") .output() .is_ok(); @@ -383,12 +384,12 @@ fn scaffold_frontend_code( } fn get_agent_js_version_from_npm(dist_tag: &str) -> DfxResult { - std::process::Command::new("npm") + Command::new(program::NPM) .arg("show") .arg("@dfinity/agent") .arg(&format!("dist-tags.{}", dist_tag)) - .stdout(std::process::Stdio::piped()) - .stderr(std::process::Stdio::inherit()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) .spawn() .map_err(DfxError::from) .and_then(|child| { diff --git a/src/dfx/src/config/cache.rs b/src/dfx/src/config/cache.rs index 9ab80c47dd..7491d8e701 100644 --- a/src/dfx/src/config/cache.rs +++ b/src/dfx/src/config/cache.rs @@ -11,6 +11,7 @@ use indicatif::{ProgressBar, ProgressDrawTarget}; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use semver::Version; +use std::io::{stderr, IsTerminal}; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; @@ -77,7 +78,7 @@ pub fn install_version(v: &str, force: bool) -> Result { // expensive step, and if this fails we can't continue anyway. let current_exe = dfx_core::foundation::get_current_exe()?; - let b: Option = if atty::is(atty::Stream::Stderr) { + let b: Option = if stderr().is_terminal() { let b = ProgressBar::new_spinner(); b.set_draw_target(ProgressDrawTarget::stderr()); b.set_message(format!("Installing version {} of dfx...", v)); diff --git a/src/dfx/src/lib/builders/assets.rs b/src/dfx/src/lib/builders/assets.rs index f6c6afe68f..701075a4df 100644 --- a/src/dfx/src/lib/builders/assets.rs +++ b/src/dfx/src/lib/builders/assets.rs @@ -6,6 +6,7 @@ use crate::lib::canister_info::CanisterInfo; use crate::lib::environment::Environment; use crate::lib::error::{BuildError, DfxError, DfxResult}; use crate::lib::models::canister::CanisterPool; +use crate::lib::program; use crate::util; use anyhow::{anyhow, Context}; use candid::Principal as CanisterId; @@ -218,7 +219,7 @@ fn build_frontend( } else if build_frontend { // Frontend build. slog::info!(logger, "Building frontend..."); - let mut cmd = std::process::Command::new("npm"); + let mut cmd = std::process::Command::new(program::NPM); // Provide DFX_NETWORK at build time cmd.env("DFX_NETWORK", network_name); diff --git a/src/dfx/src/lib/builders/mod.rs b/src/dfx/src/lib/builders/mod.rs index f2eae5ce14..88b95e9abc 100644 --- a/src/dfx/src/lib/builders/mod.rs +++ b/src/dfx/src/lib/builders/mod.rs @@ -104,12 +104,13 @@ pub trait CanisterBuilder { .context("`output` must not be None")?; if generate_output_dir.exists() { - let generate_output_dir = generate_output_dir.canonicalize().with_context(|| { - format!( - "Failed to canonicalize output dir {}.", - generate_output_dir.to_string_lossy() - ) - })?; + let generate_output_dir = dfx_core::fs::canonicalize(generate_output_dir) + .with_context(|| { + format!( + "Failed to canonicalize output dir {}.", + generate_output_dir.to_string_lossy() + ) + })?; if !generate_output_dir.starts_with(info.get_workspace_root()) { bail!( "Directory at '{}' is outside the workspace root.", @@ -324,9 +325,7 @@ fn ensure_trailing_newline(s: String) -> String { pub fn run_command(args: Vec, vars: &[Env<'_>], cwd: &Path) -> DfxResult<()> { let (command_name, arguments) = args.split_first().unwrap(); - let canonicalized = cwd - .join(command_name) - .canonicalize() + let canonicalized = dfx_core::fs::canonicalize(&cwd.join(command_name)) .or_else(|_| which::which(command_name)) .map_err(|_| anyhow!("Cannot find command or file {command_name}"))?; let mut cmd = Command::new(&canonicalized); diff --git a/src/dfx/src/lib/canister_info.rs b/src/dfx/src/lib/canister_info.rs index ece83fb847..628a6a7e59 100644 --- a/src/dfx/src/lib/canister_info.rs +++ b/src/dfx/src/lib/canister_info.rs @@ -12,7 +12,6 @@ use dfx_core::config::model::dfinity::{ use dfx_core::network::provider::get_network_context; use dfx_core::util; use fn_error_context::context; -use ic_wasm::optimize::OptLevel; use std::path::{Path, PathBuf}; pub mod assets; @@ -237,18 +236,12 @@ impl CanisterInfo { self.shrink } - pub fn get_optimize(&self) -> Option { + pub fn get_optimize(&self) -> Option { // Cycles defaults to O3, Size defaults to Oz self.optimize.map(|level| match level { - WasmOptLevel::Cycles => OptLevel::O3, - WasmOptLevel::Size => OptLevel::Oz, - WasmOptLevel::O4 => OptLevel::O4, - WasmOptLevel::O3 => OptLevel::O3, - WasmOptLevel::O2 => OptLevel::O2, - WasmOptLevel::O1 => OptLevel::O1, - WasmOptLevel::O0 => OptLevel::O0, - WasmOptLevel::Oz => OptLevel::Oz, - WasmOptLevel::Os => OptLevel::Os, + WasmOptLevel::Cycles => WasmOptLevel::O3, + WasmOptLevel::Size => WasmOptLevel::Oz, + other => other, }) } diff --git a/src/dfx/src/lib/canister_info/assets.rs b/src/dfx/src/lib/canister_info/assets.rs index bde5259d7f..e00e675cbf 100644 --- a/src/dfx/src/lib/canister_info/assets.rs +++ b/src/dfx/src/lib/canister_info/assets.rs @@ -34,7 +34,7 @@ impl AssetsCanisterInfo { let input_root = &self.input_root; let source_paths: Vec = source_paths.iter().map(|x| input_root.join(x)).collect(); for source_path in &source_paths { - let canonical = source_path.canonicalize().with_context(|| { + let canonical = dfx_core::fs::canonicalize(source_path).with_context(|| { format!( "Unable to determine canonical location of asset source path {}", source_path.to_string_lossy() diff --git a/src/dfx/src/lib/mod.rs b/src/dfx/src/lib/mod.rs index 2de6df22db..62d9502403 100644 --- a/src/dfx/src/lib/mod.rs +++ b/src/dfx/src/lib/mod.rs @@ -24,6 +24,7 @@ pub mod network; pub mod nns_types; pub mod operations; pub mod package_arguments; +pub mod program; pub mod progress_bar; pub mod project; pub mod replica; diff --git a/src/dfx/src/lib/models/canister.rs b/src/dfx/src/lib/models/canister.rs index c7f5d3de7d..5f435683d9 100644 --- a/src/dfx/src/lib/models/canister.rs +++ b/src/dfx/src/lib/models/canister.rs @@ -12,9 +12,12 @@ use crate::util::{assets, check_candid_file}; use anyhow::{anyhow, bail, Context}; use candid::Principal as CanisterId; use dfx_core::config::model::canister_id_store::CanisterIdStore; -use dfx_core::config::model::dfinity::{CanisterMetadataSection, Config, MetadataVisibility}; +use dfx_core::config::model::dfinity::{ + CanisterMetadataSection, Config, MetadataVisibility, WasmOptLevel, +}; use fn_error_context::context; use ic_wasm::metadata::{add_metadata, remove_metadata, Kind}; +use ic_wasm::optimize::OptLevel; use itertools::Itertools; use petgraph::graph::{DiGraph, NodeIndex}; use rand::{thread_rng, RngCore}; @@ -127,9 +130,15 @@ impl Canister { // optimize or shrink if let Some(level) = info.get_optimize() { - //trace!(logger, "Optimizing WASM at level {}", level); - ic_wasm::optimize::optimize(&mut m, &level, false, &None, false) - .context("Failed to optimize the WASM module.")?; + trace!(logger, "Optimizing WASM at level {}", level); + ic_wasm::optimize::optimize( + &mut m, + &wasm_opt_level_convert(level), + false, + &None, + false, + ) + .context("Failed to optimize the WASM module.")?; modified = true; } else if info.get_shrink() == Some(true) || (info.get_shrink().is_none() && (info.is_rust() || info.is_motoko())) @@ -311,20 +320,46 @@ impl Canister { } } +fn wasm_opt_level_convert(opt_level: WasmOptLevel) -> OptLevel { + use WasmOptLevel::*; + match opt_level { + O0 => OptLevel::O0, + O1 => OptLevel::O1, + O2 => OptLevel::O2, + O3 => OptLevel::O3, + O4 => OptLevel::O4, + Os => OptLevel::Os, + Oz => OptLevel::Oz, + Size => OptLevel::Oz, + Cycles => OptLevel::O3, + } +} + fn separate_candid(path: &Path) -> DfxResult<(String, String)> { - use candid_parser::utils::{instantiate_candid, CandidSource}; - // TODO: comments are omitted in the output - let (init_args, (env, actor)) = instantiate_candid(CandidSource::File(path))?; - let init_args = candid::pretty::candid::pp_args(&init_args) - .pretty(80) - .to_string(); - let service_did = candid::pretty::candid::compile(&env, &Some(actor)); - Ok((service_did, init_args)) + let (env, actor) = check_candid_file(path)?; + let actor = actor.ok_or_else(|| anyhow!("provided candid file contains no main service"))?; + if let candid::types::internal::TypeInner::Class(args, ty) = actor.as_ref() { + use candid_parser::pretty::{ + candid::{compile, pp_ty}, + utils::{concat, enclose}, + }; + + let actor = Some(ty.clone()); + let service_did = compile(&env, &actor); + let doc = concat(args.iter().map(pp_ty), ","); + let init_args = enclose("(", doc, ")").pretty(80).to_string(); + Ok((service_did, init_args)) + } else { + // The original candid from builder output doesn't contain init_args + // Use it directly to avoid items reordering + let service_did = dfx_core::fs::read_to_string(path)?; + let init_args = String::from("()"); + Ok((service_did, init_args)) + } } #[context("{} is not a valid subtype of {}", specified_idl_path.display(), compiled_idl_path.display())] fn check_valid_subtype(compiled_idl_path: &Path, specified_idl_path: &Path) -> DfxResult { - use candid::types::subtype::{subtype_with_config, OptReport}; let (mut env, opt_specified) = check_candid_file(specified_idl_path).context("Checking specified candid file.")?; let specified_type = @@ -335,13 +370,7 @@ fn check_valid_subtype(compiled_idl_path: &Path, specified_idl_path: &Path) -> D opt_compiled.expect("Compiled did file should contain some service interface"); let mut gamma = HashSet::new(); let specified_type = env.merge_type(env2, specified_type); - subtype_with_config( - OptReport::Error, - &mut gamma, - &env, - &compiled_type, - &specified_type, - )?; + candid::types::subtype::subtype(&mut gamma, &env, &compiled_type, &specified_type)?; Ok(()) } diff --git a/src/dfx/src/lib/operations/canister/install_canister.rs b/src/dfx/src/lib/operations/canister/install_canister.rs index 1bd13cd42b..3f94596cec 100644 --- a/src/dfx/src/lib/operations/canister/install_canister.rs +++ b/src/dfx/src/lib/operations/canister/install_canister.rs @@ -414,9 +414,7 @@ fn run_post_install_task( let cwd = canister.get_workspace_root(); let words = shell_words::split(task) .with_context(|| format!("Error interpreting post-install task `{task}`"))?; - let canonicalized = cwd - .join(&words[0]) - .canonicalize() + let canonicalized = dfx_core::fs::canonicalize(&cwd.join(&words[0])) .or_else(|_| which::which(&words[0])) .map_err(|_| anyhow!("Cannot find command or file {}", &words[0]))?; let mut command = Command::new(&canonicalized); diff --git a/src/dfx/src/lib/operations/canister/motoko_playground.rs b/src/dfx/src/lib/operations/canister/motoko_playground.rs index e780763b8a..1d6d41db4a 100644 --- a/src/dfx/src/lib/operations/canister/motoko_playground.rs +++ b/src/dfx/src/lib/operations/canister/motoko_playground.rs @@ -1,17 +1,16 @@ +use crate::lib::{environment::Environment, error::DfxResult}; +use anyhow::{bail, Context}; +use candid::{encode_args, CandidType, Decode, Deserialize, Encode, Principal}; +use dfx_core::config::model::canister_id_store::AcquisitionDateTime; use dfx_core::config::model::network_descriptor::{ NetworkTypeDescriptor, MAINNET_MOTOKO_PLAYGROUND_CANISTER_ID, }; -use num_traits::ToPrimitive; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -use anyhow::{bail, Context}; -use candid::{encode_args, CandidType, Decode, Deserialize, Encode, Principal}; use fn_error_context::context; use ic_utils::interfaces::management_canister::builders::InstallMode; +use num_traits::ToPrimitive; use rand::Rng; use slog::{debug, info}; - -use crate::lib::{environment::Environment, error::DfxResult}; +use std::time::SystemTime; /// Arguments for the `getCanisterId` call. #[derive(CandidType)] @@ -28,19 +27,17 @@ pub struct CanisterInfo { } impl CanisterInfo { - #[context("Failed to construct playground canister info.")] - pub fn from(id: Principal, timestamp: &SystemTime) -> DfxResult { - let timestamp = candid::Int::from(timestamp.duration_since(UNIX_EPOCH)?.as_nanos()); - Ok(Self { id, timestamp }) + pub fn from(id: Principal, timestamp: &AcquisitionDateTime) -> Self { + let timestamp = candid::Int::from(timestamp.unix_timestamp_nanos()); + Self { id, timestamp } } - #[context("Failed to turn CanisterInfo into SystemTime")] - pub fn get_timestamp(&self) -> DfxResult { - UNIX_EPOCH - .checked_add(Duration::from_nanos( - self.timestamp.0.to_u64().context("u64 overflow")?, - )) - .context("Failed to make absolute time from offset") + #[context("Failed to get timestamp from CanisterInfo")] + pub fn get_timestamp(&self) -> DfxResult { + AcquisitionDateTime::from_unix_timestamp_nanos( + self.timestamp.0.to_i128().context("i128 overflow")?, + ) + .context("Failed to make unix timestamp from nanos") } } @@ -122,7 +119,7 @@ pub async fn reserve_canister_with_playground( pub async fn authorize_asset_uploader( env: &dyn Environment, canister_id: Principal, - canister_timestamp: &SystemTime, + canister_timestamp: &AcquisitionDateTime, principal_to_authorize: &Principal, ) -> DfxResult { let agent = env.get_agent(); @@ -135,7 +132,7 @@ pub async fn authorize_asset_uploader( } else { bail!("Trying to authorize asset uploader on non-playground network.") }; - let canister_info = CanisterInfo::from(canister_id, canister_timestamp)?; + let canister_info = CanisterInfo::from(canister_id, canister_timestamp); let nested_arg = Encode!(&principal_to_authorize)?; let call_arg = Encode!(&canister_info, &"authorize", &nested_arg)?; @@ -152,13 +149,13 @@ pub async fn authorize_asset_uploader( pub async fn playground_install_code( env: &dyn Environment, canister_id: Principal, - canister_timestamp: &SystemTime, + canister_timestamp: &AcquisitionDateTime, arg: &[u8], wasm_module: &[u8], mode: InstallMode, is_asset_canister: bool, -) -> DfxResult { - let canister_info = CanisterInfo::from(canister_id, canister_timestamp)?; +) -> DfxResult { + let canister_info = CanisterInfo::from(canister_id, canister_timestamp); let agent = env.get_agent(); let playground_canister = match env.get_network_descriptor().r#type { NetworkTypeDescriptor::Playground { @@ -204,7 +201,7 @@ fn create_nonce() -> (candid::Int, candid::Nat) { if (hash & 0xc0000000) == 0 { return (timestamp, nonce); } - nonce += 1u8; + nonce += 1_u8; } } diff --git a/src/dfx/src/lib/program.rs b/src/dfx/src/lib/program.rs new file mode 100644 index 0000000000..d853413992 --- /dev/null +++ b/src/dfx/src/lib/program.rs @@ -0,0 +1,9 @@ +#[cfg(target_os = "windows")] +pub const NPM: &str = "npm.cmd"; +#[cfg(unix)] +pub const NPM: &str = "npm"; + +#[cfg(target_os = "windows")] +pub const NODE: &str = "node.exe"; +#[cfg(unix)] +pub const NODE: &str = "node"; diff --git a/src/dfx/src/util/assets.rs b/src/dfx/src/util/assets.rs index d4a417368a..a5e87ba165 100644 --- a/src/dfx/src/util/assets.rs +++ b/src/dfx/src/util/assets.rs @@ -7,7 +7,7 @@ use std::io::Read; include!(concat!(env!("OUT_DIR"), "/load_assets.rs")); pub fn dfinity_logo() -> String { - let colors = supports_color::on(atty::Stream::Stdout); + let colors = supports_color::on(supports_color::Stream::Stdout); if let Some(colors) = colors { //Some terminals, notably MacOS's Terminal.app, do not support Truecolor (RGB-colored characters) properly. //Therefore we use xterm256 coloring when the program is running in such a terminal. diff --git a/src/dfx/src/util/mod.rs b/src/dfx/src/util/mod.rs index a48cabc27f..e0afdecea3 100644 --- a/src/dfx/src/util/mod.rs +++ b/src/dfx/src/util/mod.rs @@ -6,6 +6,7 @@ use backoff::ExponentialBackoff; use bytes::Bytes; use candid::types::{value::IDLValue, Function, Type, TypeEnv, TypeInner}; use candid::IDLArgs; +use candid_parser::error::pretty_diagnose; use candid_parser::typing::pretty_check_file; use dfx_core::fs::create_dir_all; use fn_error_context::context; @@ -179,12 +180,8 @@ pub fn blob_from_arguments( None => { let arguments = arguments.unwrap_or("()"); candid_parser::parse_idl_args(arguments) - .or_else(|e| { - candid_parser::error::pretty_diagnose("Candid argument", arguments, &e) - .unwrap(); - //error_invalid_argument!("Invalid Candid values: {}", e) - Err(e) - })? + .or_else(|e| pretty_wrap("Candid argument", arguments, e)) + .map_err(|e| error_invalid_argument!("Invalid Candid values: {}", e))? .to_bytes() } Some((env, func)) => { @@ -247,11 +244,12 @@ pub fn fuzzy_parse_argument( Ok(IDLValue::Text(arg_str.to_string())) } else { candid_parser::parse_idl_value(arg_str) + .or_else(|e| pretty_wrap("Candid argument", arg_str, e)) } .map(|v| IDLArgs::new(&[v])) } else { - //candid::pretty_parse::("Candid argument", arg_str) candid_parser::parse_idl_args(arg_str) + .or_else(|e| pretty_wrap("Candid argument", arg_str, e)) } }); let bytes = args @@ -261,6 +259,15 @@ pub fn fuzzy_parse_argument( Ok(bytes) } +fn pretty_wrap( + file_name: &str, + source: &str, + e: candid_parser::Error, +) -> Result { + pretty_diagnose(file_name, source, &e)?; + Err(e) +} + pub fn format_as_trillions(amount: u128) -> String { const SCALE: u32 = 12; // trillion = 10^12 const FRACTIONAL_PRECISION: u32 = 3; diff --git a/src/distributed/assetstorage.wasm.gz b/src/distributed/assetstorage.wasm.gz index eb402f7605..08649715e2 100755 Binary files a/src/distributed/assetstorage.wasm.gz and b/src/distributed/assetstorage.wasm.gz differ