0

I am trying to assign unique tickets for users. The user can choose the number of tickets and get an allotment. The allocated tickets will be mapped to users.

pragma solidity ^0.8.11;
contract UniqTicket
{
    // Initializing the state variable
    uint public randNonce = 0;

    mapping(address => uint256[]) public participants;
    uint256[] public allTickets;

 
    function randMod(uint _modulus) public returns(uint){
        randNonce++;
        return uint(keccak256(abi.encodePacked(block.timestamp, msg.sender, randNonce, block.difficulty))) % _modulus;
    }


    function allotTickets(uint256 size) public{
        for(uint i=0; i<size; i++) {
            uint256 ticket = randMod(1000);
            participants[msg.sender].push(ticket);
            allTickets.push(ticket);
        }
    }

    function getTickets(address _user) public view returns(uint256[] memory) {
      return participants[_user];
    }

    function fetchAllTickets() public view returns(uint256[] memory) {
        return allTickets;
    }

}

When users choose allotTickets(200). The user is getting duplicate numbers. Though randNonce is a unique counter.

Looking out for a solution, how to get unique numbers.

Sample Output:

[427,257,673,731,304,357,2,959,236,931,766,322,929,42,69,897,902,116,972,408,27,397,13,141,337,238,520,680,847,657,44,630,649,722,715,81,126,569,952,874,925,354,907,101,649,548,259,8,678,10,297,256,371,369,338,355,446,248,36,639,169,742,802,391,886,117,230,781,230,279,693,9,532,456,276,148,105,863,134,161,19,954,231,949,849,477,211,305,570,281,575,548,340,348,758,15,794,311,634,639,753,50,33,856,59,142,505,201,331,513,913,801,660,739,830,641,888,975,481,236,473,624,243,86,976,871,606,736,726,780,571,53,98,470,702,437,33,688,332,639,392,720,751,107,377,544,235,773,625,544,451,315,68,559,217,491,401,75,549,781,267,217,308,430,776,163,300,438,631,125,689,787,503,805,277,828,430,377,133,122,343,913,637,712,862,247,348,964,824,189,711,666,730,43,704,896,829,771,696,983]

Thank you

1 Answer 1

2

To ensure unique ticket numbers, you can use a mapping to keep track of the allocated tickets. Please use this code below:

pragma solidity ^0.8.11;

contract UniqTicket {
    // Initializing the state variable
    uint public randNonce = 0;

    mapping(address => uint256[]) public participants;
    mapping(uint256 => bool) public allocatedTickets;
    uint256[] public allTickets;

    function randMod(uint _modulus) public returns(uint){
        randNonce++;
        return uint(keccak256(abi.encodePacked(block.timestamp, msg.sender, randNonce, block.difficulty))) % _modulus;
    }

    function allotTickets(uint256 size) public {
        for(uint i = 0; i < size; i++) {
            uint256 ticket = randMod(1000);
            while (allocatedTickets[ticket]) {
                ticket = randMod(1000);
            }
            allocatedTickets[ticket] = true;
            participants[msg.sender].push(ticket);
            allTickets.push(ticket);
        }
    }

    function getTickets(address _user) public view returns(uint256[] memory) {
        return participants[_user];
    }

    function fetchAllTickets() public view returns(uint256[] memory) {
        return allTickets;
    }
}

I added a new mapping called allocated tickets to keep track of the allocated ticket numbers. In the allotTickets function, added a while loop to generate a new random ticket number if the current ticket number is already allocated. This ensures that each ticket number is unique. Please note that this method may not be efficient for a large number of tickets, as the while loop may run for a long time if there are only a few unallocated tickets left. In such cases, you may want to consider alternative methods for generating unique ticket numbers.

4
  • Ya checking back on mapping will solve the problem. What I am trying to understand is why by default it's not giving a unique random number. As i have passed timestamp, randnonce and block difficulty. Where as randNonce will be always unique
    – Gourav
    Commented Jun 11, 2023 at 7:21
  • 1
    The random number generation method you're using is not guaranteed to produce unique numbers, even though you're using randNonce, block.timestamp, and block.difficulty as inputs. The reason is that the output of the keccak256 function is deterministic, meaning that it will always produce the same output for the same input. In your case, you're using the modulo operator (% _modulus) to limit the range of the random numbers. This operation can cause collisions, where different inputs produce the same output after applying the modulo operation. Commented Jun 11, 2023 at 7:30
  • As a result, even though randNonce is unique for each call, the output of the randMod function may not be unique. Commented Jun 11, 2023 at 7:30
  • 2
    @DEFIExpert: Can you ask your first comment as a separate question? Gourav spent time helping answer your original question, so please check it and accept it if it works. Gourav: moderators basically can only delete or not delete comments, and I think it would be more confusing to delete a comment at this stage. Thank you for helping the community!
    – eth
    Commented Jun 11, 2023 at 20:02

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.