error[E0432]: unresolved import `rand`

I am trying to generate random numbers with a canister implemented with rust but when I try to import (use rand::Rng) I get an error (subject). How can I import/use a non IC rust library within a rust canister?

------ sample code below

use rand::Rng;

#[ic_cdk_macros::query]
fn getRandom() → String {
let n1: u8 = rng.gen();
format!("{}", n1)
}

I get the following error:

error[E0432]: unresolved import rand
→ src/rust_hello/src/lib.rs:1:5
|
| use rand::Rng;
| ^^^^ use of undeclared crate or module rand

I partially solved it by adding the corresponding dependency in the cargo file, but now I get an error when compiling [getrandom v0.2.6] saying that this is not supported (Error: the wasm32-unknown-unknown target is not supported by default). So it looks like I cannot use this library. So, this raises two questions:

  1. Is it correct that I cannot use the rand library?
  2. If (1) is correct, how can I know what libraries can/not I use?
getrandom = { version = "0.2.3", features = ["js"]}
rand = "0.7.3"

Try these two out, they work as of yesterday. Some later versions error out from what I tried, but I haven’t spent the time to track down exactly what’s causing this.

1 Like

It compiles now but when I call the canister query with the random generator it outputs a n execution error (getrandom: this target is not supported).I am using dfx version 0.9.3. Should I use some other version?

[email protected]:~/rstest/rust_hello$ dfx canister call rust_hello greet world
[Canister rrkah-fqaaa-aaaaa-aaaaq-cai] Panicked at ‘could not initialize thread_rng: getrandom: this target is not supported’, /home/ildefons/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.7.3/src/rngs/thread.rs:65:17
Error: The Replica returned an error: code 5, message: “IC0503: Canister rrkah-fqaaa-aaaaa-aaaaq-cai trapped explicitly: Panicked at ‘could not initialize thread_rng: getrandom: this target is not supported’, /home/ildefons/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.7.3/src/rngs/thread.rs:65:17”

Try using it like they do in this demo app. It works great for me.

1 Like

It works. Thank you very much @GLdev.

I narrowed down the problem as follows:

THIS WORKS–>let mut rng = StdRng::from_seed(myseed);
THIS DOES NOT WORK–>let mut rng = rand::thread_rng();

Do you know why “thread_rng” is not supported? this could be relevant to anticipate other external libraries that could give execution errors.

1 Like

I think the only way to get secure unpredictable randomness is to do this:

1 Like

@paulyoung I tried your method but I get a compilation error. It says (below) that could not find CanisterId in `ic_cdk’. I declared as a query (below), is this ok?

-------Method
#[ic_cdk_macros::query]
pub async fn subnet_raw_rand() → Result<Vec, String> {
let management_canister = ic_cdk::CanisterId::from(Vec::new());
let rnd_buffer: Vec = match ic_cdk::call(management_canister, “raw_rand”, Some(())).await {
Ok(result) => result,
Err(err) => {
ic_cdk::println!(“Error invoking raw_rand: {:?} {}”, err.0, err.1);
return Err(err.1);
}
};

Ok(rnd_buffer.to_vec())

}


[email protected]:~/rstest/rust_hello$ dfx deploy
Deploying all canisters.
All canisters have already been created.
Building canisters…
Executing: cargo build --target wasm32-unknown-unknown --release -p rust_hello
Compiling rust_hello v0.1.0 (/home/ildefons/rstest/rust_hello/src/rust_hello)
error[E0433]: failed to resolve: could not find CanisterId in ic_cdk
→ src/rust_hello/src/lib.rs:55:39
|
55 | let management_canister = ic_cdk::CanisterId::from(Vec::new());
| ^^^^^^^^^^ could not find CanisterId in ic_cdk

It only works with an update call.

1 Like

I changed to ‘update’ but I get the same error (below)

Compiling rust_hello v0.1.0 (/home/ildefons/rstest/rust_hello/src/rust_hello)
error[E0433]: failed to resolve: could not find CanisterId in ic_cdk
→ src/rust_hello/src/lib.rs:55:39
|
55 | let management_canister = ic_cdk::CanisterId::from(Vec::new());
| ^^^^^^^^^^ could not find CanisterId in ic_cdk

I solved the previous error but I get a new one. Specifically, the call “ic_cdk::call” says that

"the trait for<'a> ArgumentDecoder<'a> is not implemented for std::vec::Vec<u8>"

Any idea what I can be doing wrong?

#[ic_cdk_macros::update]
pub async fn subnet_raw_rand() -> Result<Vec<u8>, String> {
    let management_canister = ic_cdk::export::Principal::management_canister();
    let rnd_buffer: Vec<u8> = match ic_cdk::call(management_canister, "raw_rand", ()).await {
        Ok(result) => result,
        Err(err) => {
            ic_cdk::println!("Error invoking raw_rand: {:?} {}", err.0, err.1);
            return Err(err.1);
        }
    };

    Ok(rnd_buffer.to_vec())
}

let (rnd_buffer,): (Vec<u8>,) = match ic_cdk::call(management_canister, "raw_rand", ()).await {

1 Like

It fixes the error

But now I get the following candid syntax error:

"subnet_raw_rand": () -> (Result<Vec<u8>, String>);
                                                    ^ Unknown token <

The " ^" symbol is below the first “<” symbol

How should I declare a candid interface for this update method? is there a guide I can follow?

Something like:

service {
  subnet_raw_rand : () -> (opt variant { ok : vec nat8; error : text });
}

See What is Candid? :: Internet Computer and Supported types :: Internet Computer

1 Like

It now compiles and deploys correctly, but I get a “FIX ME!” execution error (below). Could it be related to the candid interface? Maybe should I call the update method in a different way?

--------Execution error:
[email protected]:~/rstest/rust_hello$ dfx canister call rust_hello subnet_raw_rand
FIX ME! variant { 17_724 : table1; 3_456_837 : text } <: opt variant { ok : vec nat8; error : text } via special opt rule.
This means the sender and receiver type has diverged, and can cause data loss.
(null)

Maybe @chenyan knows but it might be due to a type mismatch.

1 Like

It looks like there are 2 threads going about the same issue.

1 Like

Rust result type uses capitalized tags, so the candid interface is

service : {
  subnet_raw_rand : () -> (opt variant { Ok : vec nat8; Err : text });
}
1 Like

It works now. Thank you everyone for your help!