From 38f7d3c9e50176041a1c8342c41a0773c3b24e51 Mon Sep 17 00:00:00 2001 From: Andriy Berestovskyy Date: Tue, 27 Aug 2024 14:58:42 +0200 Subject: [PATCH] feat: EXC-1698: Add Canister Snapshots example --- .github/CODEOWNERS | 13 +- .../rust-canister-snapshots-example.yaml | 44 ++ rust/canister-snapshots/.cargo/config.toml | 4 + rust/canister-snapshots/.gitignore | 25 + rust/canister-snapshots/Cargo.lock | 543 ++++++++++++++++++ rust/canister-snapshots/Cargo.toml | 5 + rust/canister-snapshots/Makefile | 36 ++ rust/canister-snapshots/README.md | 172 ++++++ rust/canister-snapshots/dfx.json | 17 + rust/canister-snapshots/rust-toolchain.toml | 4 + rust/canister-snapshots/src/chat/Cargo.toml | 12 + rust/canister-snapshots/src/chat/chat.did | 5 + rust/canister-snapshots/src/chat/src/lib.rs | 51 ++ 13 files changed, 925 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/rust-canister-snapshots-example.yaml create mode 100644 rust/canister-snapshots/.cargo/config.toml create mode 100644 rust/canister-snapshots/.gitignore create mode 100644 rust/canister-snapshots/Cargo.lock create mode 100644 rust/canister-snapshots/Cargo.toml create mode 100644 rust/canister-snapshots/Makefile create mode 100644 rust/canister-snapshots/README.md create mode 100644 rust/canister-snapshots/dfx.json create mode 100644 rust/canister-snapshots/rust-toolchain.toml create mode 100644 rust/canister-snapshots/src/chat/Cargo.toml create mode 100644 rust/canister-snapshots/src/chat/chat.did create mode 100644 rust/canister-snapshots/src/chat/src/lib.rs diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f249057cd..898752273 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -61,6 +61,7 @@ /rust/basic_dao/ @dfinity/testing-verification /rust/basic_ethereum/ @dfinity/cross-chain-team /rust/canister-info/ @dfinity/testing-verification +/rust/canister-snapshots/ @dfinity/execution /rust/canister_logs/ @dfinity/execution /rust/composite_query/ @dfinity/execution /rust/counter/ @dfinity/growth @@ -68,21 +69,21 @@ /rust/dip721-nft-container/ @dfinity/sdk /rust/encrypted-notes-dapp-vetkd/ @dfinity/dept-crypto-library /rust/encrypted-notes-dapp/ @dfinity/dept-crypto-library -/rust/face-recognition/ @dfinity/runtime +/rust/face-recognition/ @dfinity/execution /rust/guards/ @dfinity/cross-chain-team /rust/hello/ @dfinity/sdk /rust/icp_transfer/ @dfinity/growth -/rust/image-classification/ @dfinity/runtime +/rust/image-classification/ @dfinity/execution /rust/nft-wallet/ @dfinity/growth /rust/parallel_calls/ @dfinity/research -/rust/performance_counters/ @dfinity/runtime -/rust/periodic_tasks/ @dfinity/runtime +/rust/performance_counters/ @dfinity/execution +/rust/periodic_tasks/ @dfinity/execution /rust/pub-sub/ @dfinity/growth -/rust/qrcode/ @dfinity/runtime +/rust/qrcode/ @dfinity/execution /rust/query_stats/ @dfinity/consensus /rust/send_http_get/ @dfinity/growth /rust/send_http_post/ @dfinity/growth -/rust/simd/ @dfinity/runtime +/rust/simd/ @dfinity/execution /rust/threshold-ecdsa/ @dfinity/dept-crypto-library /rust/threshold-schnorr/ @dfinity/dept-crypto-library /rust/token_transfer/ @dfinity/growth diff --git a/.github/workflows/rust-canister-snapshots-example.yaml b/.github/workflows/rust-canister-snapshots-example.yaml new file mode 100644 index 000000000..1b56729b5 --- /dev/null +++ b/.github/workflows/rust-canister-snapshots-example.yaml @@ -0,0 +1,44 @@ +name: rust-canister-snapshots +on: + push: + branches: + - master + pull_request: + paths: + - rust/canister-snapshots/** + - .github/workflows/provision-darwin.sh + - .github/workflows/provision-linux.sh + - .github/workflows/rust-canister-snapshots-example.yaml + - .ic-commit +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + rust-canister-snapshots-example-darwin: + runs-on: macos-12 + steps: + - uses: actions/checkout@v1 + - name: Provision Darwin + run: DFX_VERSION="0.23.0-beta.3" bash .github/workflows/provision-darwin.sh + - name: Remove networks.json + run: rm -f ~/.config/dfx/networks.json + - name: Rust Canister Snapshots Darwin + run: | + dfx start --background + pushd rust/canister-snapshots + make test + popd + rust-canister-snapshots-example-linux: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v1 + - name: Provision Linux + run: DFX_VERSION="0.23.0-beta.3" bash .github/workflows/provision-linux.sh + - name: Remove networks.json + run: rm -f ~/.config/dfx/networks.json + - name: Rust Canister Snapshots Linux + run: | + dfx start --background + pushd rust/canister-snapshots + make test + popd diff --git a/rust/canister-snapshots/.cargo/config.toml b/rust/canister-snapshots/.cargo/config.toml new file mode 100644 index 000000000..23395912a --- /dev/null +++ b/rust/canister-snapshots/.cargo/config.toml @@ -0,0 +1,4 @@ +[build] +target = ["wasm32-unknown-unknown"] + +[target.wasm32-unknown-unknown] diff --git a/rust/canister-snapshots/.gitignore b/rust/canister-snapshots/.gitignore new file mode 100644 index 000000000..49c89a1c9 --- /dev/null +++ b/rust/canister-snapshots/.gitignore @@ -0,0 +1,25 @@ +# Various IDEs and Editors +.vscode/ +.idea/ +**/*~ + +# Mac OSX temporary files +.DS_Store +**/.DS_Store + +# dfx temporary files +.dfx/ + +# generated files +**/declarations/ + +# rust +target/ + +# frontend code +node_modules/ +dist/ +.svelte-kit/ + +# environment variables +.env diff --git a/rust/canister-snapshots/Cargo.lock b/rust/canister-snapshots/Cargo.lock new file mode 100644 index 000000000..aa5323e0f --- /dev/null +++ b/rust/canister-snapshots/Cargo.lock @@ -0,0 +1,543 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "binread" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" +dependencies = [ + "binread_derive", + "lazy_static", + "rustversion", +] + +[[package]] +name = "binread_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" +dependencies = [ + "either", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "candid" +version = "0.10.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c30ee7f886f296b6422c0ff017e89dd4f831521dfdcc76f3f71aae1ce817222" +dependencies = [ + "anyhow", + "binread", + "byteorder", + "candid_derive", + "hex", + "ic_principal", + "leb128", + "num-bigint", + "num-traits", + "paste", + "pretty", + "serde", + "serde_bytes", + "stacker", + "thiserror", +] + +[[package]] +name = "candid_derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3de398570c386726e7a59d9887b68763c481477f9a043fb998a2e09d428df1a9" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "cc" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chat" +version = "0.1.0" +dependencies = [ + "candid", + "ic-cdk", + "ic-cdk-macros", +] + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "ic-cdk" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8ecacd682fa05a985253592963306cb9799622d7b1cce4b1edb89c6ec85be1" +dependencies = [ + "candid", + "ic-cdk-macros", + "ic0", + "serde", + "serde_bytes", +] + +[[package]] +name = "ic-cdk-macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4d857135deef20cc7ea8f3869a30cd9cfeb1392b3a81043790b2cd82adc3e0" +dependencies = [ + "candid", + "proc-macro2", + "quote", + "serde", + "serde_tokenstream", + "syn 2.0.76", +] + +[[package]] +name = "ic0" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de254dd67bbd58073e23dc1c8553ba12fa1dc610a19de94ad2bbcd0460c067f" + +[[package]] +name = "ic_principal" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1762deb6f7c8d8c2bdee4b6c5a47b60195b74e9b5280faa5ba29692f8e17429c" +dependencies = [ + "crc32fast", + "data-encoding", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pretty" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55c4d17d994b637e2f4daf6e5dc5d660d209d5642377d675d7a1c3ab69fa579" +dependencies = [ + "arrayvec", + "typed-arena", + "unicode-width", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "serde" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "serde_tokenstream" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64060d864397305347a78851c51588fd283767e7e7589829e8121d65512340f1" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.76", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "stacker" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/rust/canister-snapshots/Cargo.toml b/rust/canister-snapshots/Cargo.toml new file mode 100644 index 000000000..c1eafd5b0 --- /dev/null +++ b/rust/canister-snapshots/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members = [ + "src/chat" +] +resolver = "2" diff --git a/rust/canister-snapshots/Makefile b/rust/canister-snapshots/Makefile new file mode 100644 index 000000000..1630d64e1 --- /dev/null +++ b/rust/canister-snapshots/Makefile @@ -0,0 +1,36 @@ +.PHONY: all +all: build + +.PHONY: build +.SILENT: build +build: + dfx canister create --all + dfx build + +.PHONY: install +.SILENT: install +install: build + dfx canister install chat + +.PHONY: upgrade +.SILENT: upgrade +upgrade: build + dfx canister install chat --mode=upgrade + +.PHONY: deploy +.SILENT: deploy +deploy: + dfx deploy chat + +.PHONY: test +.SILENT: test +test: deploy + dfx canister call chat append "Hi there!" | grep -qw '()' && echo 'PASS' + dfx canister call chat dump | grep -qw 'Hi' && echo 'PASS' + dfx canister call chat remove_spam | grep -qw '0' && echo 'PASS' + dfx canister call chat dump | grep -qwvw 'Hi' && echo 'PASS' + +.PHONY: clean +.SILENT: clean +clean: + rm -fr .dfx diff --git a/rust/canister-snapshots/README.md b/rust/canister-snapshots/README.md new file mode 100644 index 000000000..17dcb5dfc --- /dev/null +++ b/rust/canister-snapshots/README.md @@ -0,0 +1,172 @@ +--- +keywords: [advanced, rust, backup, restore, snapshots] +--- + +# Canister Snapshots Example + +[View this sample's code on GitHub](https://github.com/dfinity/examples/tree/master/rust/canister-snapshots) + +## Overview + +This example demonstrates the process of taking and loading canister snapshots. +It features a canister named `chat`, which functions as a miniature database. +The `remove_spam` canister method intentionally includes a bug to simulate data loss. +The example outlines the steps to install the canister, create a snapshot, +and subsequently restore the data after the simulated data loss. + +## Prerequisites + +This example requires an installation of: + +- [x] Install the [IC SDK](https://internetcomputer.org/docs/current/developer-docs/setup/install/index.mdx). Note: the Canister Snapshots feature requires `dfx` version `0.23.0-beta.3` or later. +- [x] Clone the example dapp project: `git clone https://github.com/dfinity/examples` + +- ### Step 1: Begin by opening a terminal window and navigating into the project's directory + +```sh +cd examples/rust/canister-snapshots +``` + +- ### Step 2: Start a clean local Internet Computer replica and a web server + +```sh +dfx stop +dfx start --clean +``` + +This terminal will stay blocked, printing log messages, until the `Ctrl+C` is pressed or `dfx stop` command is run. + +Example output: + +```sh +% dfx stop && dfx start --clean +Running dfx start for version 0.23.0-beta.3 +[...] +Replica API running on 127.0.0.1:4943 +``` + +- ### Step 3: Open another terminal window in the same directory + +```sh +cd examples/rust/canister-snapshots +``` + +- ### Step 4: Compile and deploy `chat` canister + +```sh +dfx deploy +``` + +Example output: + +```sh +% dfx deploy +Deploying all canisters. +[...] +Deployed canisters. +URLs: + Backend canister via Candid interface: + chat: http://127.0.0.1:4943/?canisterId=... +``` + +- ### Step 5: Populate the database with data + +```sh +dfx canister call chat append 'Hi there!' +dfx canister call chat dump +``` + +Example output: + +```sh +% dfx canister call chat append 'Hi there!' +() +% dfx canister call chat dump +(vec { "Hi there!" }) +``` + +- ### Step 6: Take canister snapshot + +Canister `chat` is currently running, and snapshots should not be taken of active canisters. +Therefore, the canister should be stopped before taking a snapshot and then restarted. + +```sh +dfx canister stop chat +dfx canister snapshot create chat +dfx canister start chat +``` + +Example output: + +```sh +% dfx canister stop chat +Stopping code for canister chat, with canister_id bkyz2-fmaaa-aaaaa-qaaaq-cai +% dfx canister snapshot create chat +Created a new snapshot of canister chat. Snapshot ID: 000000000000000080000000001000010101 +% dfx canister start chat +Starting code for canister chat, with canister_id bkyz2-fmaaa-aaaaa-qaaaq-cai +``` + +- ### Step 7: Simulate data loss + +The `remove_spam` canister method intentionally includes a bug to simulate data loss. + +```sh +dfx canister call chat remove_spam +dfx canister call chat dump +``` + +Example output: + +```sh +% dfx canister call chat remove_spam +(0 : nat64) +% dfx canister call chat dump +(vec {}) +``` + +There is no more data in the database. + +- ### Step 8: Restore the canister state from the snapshot + +Canister `chat` is currently running, and snapshots should not be applied to active canisters. +Therefore, the canister must be stopped before applying the snapshot and then restarted. + +```sh +dfx canister stop chat +dfx canister snapshot list chat +dfx canister snapshot load chat 000000000000000080000000001000010101 +dfx canister start chat +dfx canister call chat dump +``` + +Example output: + +```sh +% dfx canister stop chat +Stopping code for canister chat, with canister_id bkyz2-fmaaa-aaaaa-qaaaq-cai +% dfx canister snapshot list chat +000000000000000080000000001000010101: 1.61MiB, taken at 2024-08-27 18:19:20 UTC +% dfx canister snapshot load chat 000000000000000080000000001000010101 +Loaded snapshot 000000000000000080000000001000010101 in canister chat +% dfx canister start chat +Starting code for canister chat, with canister_id bkyz2-fmaaa-aaaaa-qaaaq-cai +% dfx canister call chat dump +(vec { "Hi there!" }) +``` + +The canister state has been successfully restored from the snapshot. + +## Conclusion + +Canister Snapshots are a powerful new tool for developers. +In the event of accidental data loss, bugs, or configuration errors, +canisters can be quickly restored to a previous working state. +Snapshots help ensure that critical data and services remain accessible +even in the face of unexpected events, providing developers with peace of mind. + +## Security considerations and best practices + +If you base your application on this example, we recommend you familiarize +yourself with and adhere to the [security best practices](https://internetcomputer.org/docs/current/references/security/) +for developing on the Internet Computer. This example may not implement all the best practices. diff --git a/rust/canister-snapshots/dfx.json b/rust/canister-snapshots/dfx.json new file mode 100644 index 000000000..9d557e08c --- /dev/null +++ b/rust/canister-snapshots/dfx.json @@ -0,0 +1,17 @@ +{ + "canisters": { + "chat": { + "candid": "src/chat/chat.did", + "package": "chat", + "type": "rust" + } + }, + "defaults": { + "build": { + "args": "", + "packtool": "" + } + }, + "output_env_file": ".env", + "version": 1 +} \ No newline at end of file diff --git a/rust/canister-snapshots/rust-toolchain.toml b/rust/canister-snapshots/rust-toolchain.toml new file mode 100644 index 000000000..fc78a71e2 --- /dev/null +++ b/rust/canister-snapshots/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.80" +targets = ["wasm32-unknown-unknown"] +components = ["rustfmt", "clippy"] diff --git a/rust/canister-snapshots/src/chat/Cargo.toml b/rust/canister-snapshots/src/chat/Cargo.toml new file mode 100644 index 000000000..46ac5a565 --- /dev/null +++ b/rust/canister-snapshots/src/chat/Cargo.toml @@ -0,0 +1,12 @@ +[package] +edition = "2021" +name = "chat" +version = "0.1.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +candid = "0.10" +ic-cdk = "0.16" +ic-cdk-macros = "0.16.0" diff --git a/rust/canister-snapshots/src/chat/chat.did b/rust/canister-snapshots/src/chat/chat.did new file mode 100644 index 000000000..b6f6ca2b6 --- /dev/null +++ b/rust/canister-snapshots/src/chat/chat.did @@ -0,0 +1,5 @@ +service : { + "dump": () -> (vec text) query; + "append": (text) -> (); + "remove_spam": () -> (nat64); +} diff --git a/rust/canister-snapshots/src/chat/src/lib.rs b/rust/canister-snapshots/src/chat/src/lib.rs new file mode 100644 index 000000000..827502c96 --- /dev/null +++ b/rust/canister-snapshots/src/chat/src/lib.rs @@ -0,0 +1,51 @@ +//! This is a simple chat backend to demonstrate Canister Snapshots. +use std::{cell::RefCell, collections::HashSet}; + +thread_local! { + static CHAT: RefCell> = Default::default(); +} + +/// Appends a new message to the chat database. +#[ic_cdk_macros::update] +fn append(message: String) { + CHAT.with_borrow_mut(|chat| chat.push(message)); +} + +/// Dumps all the chat messages. +#[ic_cdk_macros::query] +fn dump() -> Vec { + CHAT.with_borrow(|chat| chat.clone()) +} + +/// Removes messages containing spam keywords from the chat. +/// +/// Returns the number of messages removed. +/// +/// Move fast and break things! This method is BROKEN. +/// Can you spot the bug? +/// +/// DISCLAIMER: While the Canister Snapshots feature is a valuable tool, +/// it should not be a substitute for comprehensive testing. +#[ic_cdk_macros::update] +fn remove_spam() -> u64 { + let spam_keywords = HashSet::from(["coupon", "giveaway", "casino"]); + + let chat = CHAT.take(); + let mut new_chat = vec![]; + let mut spam = 0; + for message in chat { + if message.split(" ").any(|word| spam_keywords.contains(word)) { + spam += 1; + new_chat.push("(removed spam message)".into()); + } else { + new_chat.push(message); + } + } + if spam == 0 { + ic_cdk::println!("No spam keywords found, the chat is unchanged."); + } else { + ic_cdk::println!("Removed {spam} messages, updating the chat..."); + CHAT.set(new_chat); + } + spam +}