Rust CDK v0.5.1 is out

I’m happy to announce that Rust CDK 0.5.1 is out.
There are a few great additions hiding behind the minor version bump:

  1. The long-standing issue with panicking after .await is finally closed. The Rust CDK will correctly free resources if you trap across async boundaries. Huge thanks to @AdamS for elegantly implementing cleanups.
  2. @christian exposed call_raw* and arg_data_raw functions. This API allows you to call canisters that do not encode their arguments as Candid or forward calls without decoding the payload.
  3. @hpeebles implemented BufferedStableReader and BufferedStableWriter API for more efficient serialization (don’t forget to measure when you optimize!).
  4. @roman-kashitsyn added notify* family of functions relying on the trick that @nomeata described in his blog post. If your canister uses only notify* calls, it safe to upgrade the canister without stopping it first. The notify is a regular call setting a non-existing function as a callback. One practical implication of that implementation is that you get a refund if you attach cycles to the notification and the destination canister traps.

Enjoy building on the IC with the improved Rust CDK!

26 Likes
  1. @roman-kashitsyn added notify* family of functions relying on the trick that @nomeata described in his blog post . If your canister uses only notify* calls, it safe to upgrade the canister without stopping it first. The notify is a regular call setting a non-existing function as a callback. One practical implication of that implementation is that you get a refund if you attach cycles to the notification and the destination canister traps.

Very exciting! Do you happen to know if and when Motoko will support the same thing?

Since 0.6.17, released last December. Sometimes Motoko isn’t last :slight_smile:

4 Likes

Wooot! Nice work, very excited to try this.

1 Like

Hi @AdamS, can we hear about the elegance of these cleanups?
How does it work and how is it used?

In motoko, using ignore await canister_a.method(xxx)

  1. @hpeebles implemented BufferedStableReader and BufferedStableWriter API for more efficient serialization (don’t forget to measure when you optimize!).

Curious what techniques you use to measure?

You can find the implementation in these PRs:

Actually, I don’t think that’s correct. The shared function needs to be declared as a oneway function (returning (), not async ()) and just called without an await.

So, for this example:

Actor:

actor canister_a {
    // `()` return  declares a Candid oneway function  that can't be awaited. 
   public shared func method() : () { 
     ...
   };
}

Client:

   canister_a.method(); // no `await` possible (given return type of `()`, not `async ()`)

Ain’'t that right, @nomeata?

1 Like

I think I would call it the exact opposite of elegant. It takes advantage of the fact that WASM is single-threaded to use global state. Essentially, it sets a global bool, executes the future, and then unsets it; the executor, when asked to execute a future, checks the global bool, and if it is set then it doesn’t actually execute the future but simply drops it.

The behavior is that all destructors are run in the case of an inter-canister trap, but execution does not continue. You can attach custom cleanup logic by placing it in a destructor via a crate like scope_guard.

2 Likes

II tthhiinnkk ssoo, yyeess.