Using Rust packages from a Motoko canister

My project is currently written entirely in Motoko. There is an SDK I would like to use (specifically the presigned function, to generate a presigned URL so my users can upload files directly to CDNs that support the S3 Object Storage interface), but the SDK isn’t available in Motoko. There is a Rust version, however.

I would like to avoid setting up a lambda on AWS just to generate this URL, so I’m thinking I could create a Rust canister that uses the SDK, add it to my project alongside my Motoko canisters, and have my Motoko canister call into that Rust canister directly when it needs to generate the URL.

Is this the right way to go about things? Are there examples you could point me to where a Motoko canister communicates with a Rust canister in the same project?

1 Like

It’s something that is being investigated, how to integrate Motoko with Rust code
But right now the way to do it is just separating the motoko and rust canisters and make calls between them

It is a bit more subtle than that. See this thread Exploration: calling Rust functions from Motoko.

If you use this and composite queries, because if the way motoko works, it is like it is on your canister. Performance should be roughly the same unless you are passing a ton of data across.

Reading through the thread linked above, it looks like the best way for me to proceed, at least at the current time, is to use Canpack. I’m getting node errors running the canpack command, so I’ve filed an issue there, but I’m reaching out to this community to see if anyone has had success lately using Canpack to expose a Rust crate’s functions to a Motoko canister, or if there’s an alternative best-practice by now.

Resolved the issue in this PR. The most common approach is to create a separate Rust canister and then call methods from Motoko. Canpack is essentially a wrapper which generates the Rust canister from a config file. Note that this only works for libraries which export a top-level canpack! macro. Here is more information for anyone reading this who is interested.

I’ve put together a minimal example of using a Rust crate in a Motoko canister in this repo - zkTrainer.

This commit is the very start of a developer grant-funded project (outlined here) but I’ve used it to create a framework that I can build upon further and to share the details here for the benefit of anyone who might come across this thread while searching for ways to go about this.

The steps I used to set this up are as follows:

  • check prerequisites and run the usual commands to start a new dfx project
      dfx start --clean --background
      dfx new my-project --type=rust
      cd my-project
      code . (to open VSCode)
  • rename my-project-backend to wrapper (or whatever name you prefer) using find & replace, and rename the directory accordingly
  • (also search for the same text with underscore instead of hyphen)
  • separately start a dfx Motoko project
  • copy the directory containing main.mo into src in my-project
  • if renaming the directory, replace the name throughout the project
  • add details into dfx.json file
  • copy Cargo.toml file from Rust backend directory into Motoko backend directory (here) and edit package name
  • copy .did file from Rust backend directory into Motoko backend directory (here) and edit file name
  • from the project root folder run
      cargo add <crate-name>
      cargo build --target wasm32-unknown-unknown --release

I then wrote the code for the Rust wrapper and Motoko backend as shown in the links so as to be able to wrap a single type and method from the winterfell crate and use it in a Motoko canister.

This might not be the most efficient way to achieve this (and doesn’t use Canpack) but it does produce a working example. Happy to hear if anyone has suggestions for improvement.

1 Like