You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This example canister shows some advanced behavior between guards and asynchronous code. This example is meant for Rust
6
4
canister developers that are already familiar
7
-
with [asynchronous code](https://internetcomputer.org/docs/current/developer-docs/smart-contracts/advanced-features/async-code/)
5
+
with [asynchronous code](https://internetcomputer.org/docs/references/async-code)
8
6
and the security best-practices related
9
-
to [inter-canister calls and rollbacks](https://internetcomputer.org/docs/current/developer-docs/security/rust-canister-development-security-best-practices#inter-canister-calls-and-rollbacks).
7
+
to [inter-canister calls and rollbacks](https://internetcomputer.org/docs/building-apps/security/inter-canister-calls#inter-canister-calls-and-rollbacks).
10
8
11
9
## Guard to maintain invariants
12
10
@@ -17,7 +15,7 @@ requests by contacting a ledger canister, where crucially double minting should
17
15
18
16
One tricky part in this scenario is that an item can therefore only be marked as processed after the asynchronous code
19
17
has completed, meaning in the callback. As mentioned in
20
-
the [security best-practices](https://internetcomputer.org/docs/current/developer-docs/security/rust-canister-development-security-best-practices#securely-handle-traps-in-callbacks),
18
+
the [security best-practices](https://internetcomputer.org/docs/building-apps/security/inter-canister-calls#securely-handle-traps-in-callbacks),
21
19
it's not always feasible to guarantee that the callback will not trap, which in that case would break the invariant due
22
20
to the state being rolled back.
23
21
@@ -27,42 +25,35 @@ another message than the callback, which is the case for true asynchronous code
27
25
etc.). It's in particular not enough to `await` a function that's declared to be `async`, since if the future can polled
28
26
until completion directly, everything will be executed in a single message.
29
27
30
-
## Automated integration tests
28
+
## Deploying from ICP Ninja
31
29
32
-
To run the integration tests under `tests/` install [PocketIC server](https://github.com/dfinity/pocketic) and then run:
cargo build --target wasm32-unknown-unknown --release && cargo test
36
-
```
32
+
## Build and deploy from the command-line
37
33
38
-
##Manual testing with `dfx`
34
+
### 1. [Download and install the IC SDK.](https://internetcomputer.org/docs/building-apps/getting-started/install)
39
35
40
-
### Setup
36
+
### 2. Download your project from ICP Ninja using the 'Download files' button on the upper left corner, or [clone the GitHub examples repository.](https://github.com/dfinity/examples/)
41
37
42
-
Start `dfx`:
38
+
### 3. Navigate into the project's directory.
43
39
44
-
```shell
45
-
dfx start --background
46
-
```
47
-
48
-
Deploy the canister:
40
+
### 4. Deploy the project to your local environment:
49
41
50
-
```shell
51
-
dfx deploy
42
+
```
43
+
dfx start --background --clean && dfx deploy
52
44
```
53
45
54
-
You should now be able to query the canister, e.g., to check if an item is processed:
46
+
## Automated integration tests
47
+
48
+
To run the integration tests under `tests/` install [PocketIC server](https://github.com/dfinity/pocketic) and then run:
55
49
56
50
```shell
57
-
dfx canister call guards is_item_processed 'mint'
51
+
cargo build --target wasm32-unknown-unknown --release && cargo test
58
52
```
59
53
60
-
This should return `(null)` since the canister currently has an empty state.
61
-
62
54
### Test
63
55
64
-
As an example, we show how the behavior tested in `should_process_single_item_and_mark_it_as_processed` can be tested
65
-
manually.
56
+
Below tests the behavior in `should_process_single_item_and_mark_it_as_processed` manually.
66
57
67
58
Set the item `"mint"` to be processed:
68
59
@@ -76,27 +67,22 @@ As a sanity check, ensure that the item is not yet processed:
76
67
dfx canister call guards is_item_processed 'mint'
77
68
```
78
69
79
-
should return `(opt false)`.
70
+
This should return `(opt false)`.
80
71
81
72
Process the item by calling the *panicking* callback:
Since the queried endpoint panics on purpose, expect some error message similar to:
88
-
89
-
```text
90
-
2024-05-29 11:54:39.817800 UTC: [Canister bkyz2-fmaaa-aaaaa-qaaaq-cai] Panicked at 'panicking callback!', src/lib.rs:47:5
91
-
Error: Failed update call.
92
-
Caused by: Failed update call.
93
-
The replica returned a rejection error: reject code CanisterError, reject message Canister bkyz2-fmaaa-aaaaa-qaaaq-cai trapped explicitly: Panicked at 'panicking callback!', src/lib.rs:47:5, error code None
94
-
```
95
-
96
78
Ensure that the guard was executed to ensure that the item is marked as processed despite the previous panic:
97
79
98
80
```shell
99
81
dfx canister call guards is_item_processed 'mint'
100
82
```
101
83
102
84
This should return `(opt true)`.
85
+
86
+
## Security considerations and best practices
87
+
88
+
If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://internetcomputer.org/docs/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices.
0 commit comments