0

I'm building a pallet that requires some randomness to simulate the act of tossing a coin. That's why I'm following the same implementation as provided on the Lottery pallet. Particularly, the following method:

    pub fn generate_insecure_random_boolean(seed: u32) -> bool {
        let pallet_id = T::PalletId::get();
        let (random_seed, _) = T::Randomness::random(&(pallet_id, seed).encode());
        let random_number = <u32>::decode(&mut random_seed.as_ref())
            .expect("secure hashes should always be bigger than u32; qed");
        random_number % 2 == 0
    }

That generates a random number based on the PalletId and the value of a particular seed, which in my case, is given by the current block number:

    pub fn random_coin_side() -> CoinSide {
        let block_number = <frame_system::Pallet<T>>::block_number();
        let seed = block_number.try_into().unwrap_or_else(|_| 0u32);

        if Self::generate_insecure_random_boolean(seed) {
            // println!("Coin side: Head");
            CoinSide::Head
        } else {
            // println!("Coin side: Tail");
            CoinSide::Tail
        }
    }

This works perfectly when testing the node running through PolkadotJS, I do see the randomness and how the coin is flipped randomly.

However, my problem is when I test this function on my unit test suite. I'm always getting the same random number, even if I'm setting current block number explicitly to update the seed used. Here is my unit test:

    #[test]
    fn toss_coin_works() {
        new_test_ext().execute_with(|| {
            assert_ok!(CoinGame::create_coin(RuntimeOrigin::signed(ALICE)));
    
            let coin = CoinGame::get_coin(&ALICE).unwrap();
    
            let toss_result = CoinGame::random_coin_side();
    
            // advance 10 blocks
            System::set_block_number(24);
    
            let toss_result2 = CoinGame::random_coin_side();
    
            assert_ok!(CoinGame::toss_coin(RuntimeOrigin::signed(ALICE), toss_result.clone()));
    
            let expected_event = RuntimeEvent::CoinGame(Event::CoinGuessed(ALICE, toss_result));
            assert_eq!(last_event(), expected_event);
            assert!(false);
        });
    }

Taking into consideration that my mock environment is set by the following function:

    pub fn new_test_ext() -> sp_io::TestExternalities {
        let t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap().into();
        let mut ext = sp_io::TestExternalities::new(t);
        ext.execute_with(|| System::set_block_number(14));
        ext
    }

Why I'm not getting the same randomness on my unit test and on the substrate node running?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.