The function loops through the players array to check for duplicates. With the array getting longer more checks should be done. This increases gas cost, so for newcomers at later stage of the round of the raffle, gas cost will be higher.
function testEnterRaffleGasCostInefficient() public {
uint256 playersCount = 100
address[] memory newPlayers = new address[](playersCount);
// make 3 iterations of adding 100 players
uint iterations = 3
uint previousIterationUsedGas = 0
for(uint iter = 0; iter < iterations; iter++) {
for (uint i=0; i < playersCount; i++){
newPlayers[i] = address((iter * playersCount) + i);
}
uint gasStart = gasleft();
puppyRaffle.enterRaffle{value: playersCount * entranceFee}(newPlayers);
uint gasEnd = gasleft();
uint gasUsed = gasStart - gasEnd;
console.log("Gas used for next 100 players", gasUsed);
assert(gasUsed > previousIterationUsedGas);
previousIterationUsedGas = gasUsed
}
}
@@ -30,6 +30,9 @@ contract PuppyRaffle is ReentrancyGuard, ERC721, Ownable {
address public feeAddress;
uint64 public totalFees = 0;
+ uint256 public raffleId = 1;
+ mapping(address => uint256) addressToRaffleId;
+
// mappings to keep track of token traits
mapping(uint256 => uint256) public tokenIdToRarity;
mapping(uint256 => string) public rarityToUri;
@@ -80,15 +83,10 @@ contract PuppyRaffle is ReentrancyGuard, ERC721, Ownable {
function enterRaffle(address[] memory newPlayers) public payable {
require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
for (uint256 i = 0; i < newPlayers.length; i++) {
+ require(addressToRaffleId[newPlayers[i]] != raffleId, "PuppyRaffle: Duplicate player");
+ addressToRaffleId[newPlayers[i]] = raffleId;
players.push(newPlayers[i]);
}
-
- // Check for duplicates
- for (uint256 i = 0; i < players.length - 1; i++) {
- for (uint256 j = i + 1; j < players.length; j++) {
- require(players[i] != players[j], "PuppyRaffle: Duplicate player");
- }
- }
emit RaffleEnter(newPlayers);
}
@@ -125,6 +123,7 @@ contract PuppyRaffle is ReentrancyGuard, ERC721, Ownable {
function selectWinner() external {
require(block.timestamp >= raffleStartTime + raffleDuration, "PuppyRaffle: Raffle not over");
require(players.length >= 4, "PuppyRaffle: Need at least 4 players");
+ raffleId = raffleId + 1;
uint256 winnerIndex =
uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp, block.difficulty))) % players.length;
address winner = players[winnerIndex];