Search code examples
substrate

How to generate a random number within a range in substrate?


I want generate random number within a certain range. How to do that in substrate?

 fn draw_juror_for_citizen_profile_function(
        citizen_id: u128,
        length: usize,
    ) -> DispatchResult {

        let nonce = Self::get_and_increment_nonce();

        let random_seed = T::RandomnessSource::random(&nonce).encode();
        let random_number = u64::decode(&mut random_seed.as_ref())
        .expect("secure hashes should always be bigger than u32; qed");
        
        Ok(())
    }

I can't use rand package because it doesn't support no_std.

rng.gen_range(0..10));

Solution

  • I think you need to use the Randomness chain extension for this. See the Randomness docs.

    This example shows how to call Randomness from a contract.

    There is some discussion and another code exaxmple here.

    EDIT: I'm not sure how random or appropriate this is but you could build on top of your random_seed snippet. In your example you say you need a random number between 0 and 10 so you could do:

            fn max_index(array: &[u8]) -> usize {
                let mut i = 0;
    
                for (j, &value) in array.iter().enumerate() {
                    if value > array[i] {
                        i = j;
                    }
                }
    
                i
            }
    
            // generate your random seed
            let arr1 = [0; 2];
            let seed = self.env().random(&arr1).0;
    
            // find the maximum index for the slice [0..10]
            let rand_index = max_index(&seed.as_ref()[0..10]);
    

    The returned number would be in the range 0-10. However, this is obviously limited by the fact you're starting with a [u8; 32]. For larger ranges maybe you simply concatenate u8 arrays.

    Also note that this code simply takes the first max index if there are duplicates.