0

I'm trying to a smart-contract where user can register himself (in an sorted array) and when a amount of people is registered (here 2) a Battle is created and firsts registered users battle each other.

The code isn't an issue, but my main concern is what will appends if multiple requests come in the same bloc and miners will sort requests on a queue (who have to be the same for everyone) ? How can I avoid conflict ?

Example: I have 3 users (A, B, and C). A is already registered on the contract, B and C try to register in the same bloc. What is a miner take the transaction and do [A, B, C] so A will battle B and C will stay in the registered array. But in the same way another miner take [A, C, B] create a Battle between A and C and keep B. Both A+B and A+C battles happens in the same time and remaining array are not the same. What'll happens on this case ?

I tried to search online (and found nothing good), or code a simple example and test it using Ganache and multiple browser on Remix but it's really painful to test it..

This is my test code (who work fine..) But I don't know how to be sure about it ? Any idea, link, suggestion, ...

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

contract RegisteredQueue {

    struct Registered {
        address addr;
        uint value;
    }
    struct Battle {
        Registered reg1;
        Registered reg2;
    }

    event NewRegistered (Registered indexed registered);
    event NewBattle (Battle indexed battle);
    
    Registered[] public registeredValues;
    Battle[] public battlesDone;

    function register(uint _value) public {
        for (uint i=0; i<registeredValues.length; i++) {
            require(registeredValues[i].addr != msg.sender, "You're already registred");
        }

        registeredValues.push(Registered(msg.sender, _value));
        uint l = registeredValues.length;

        emit NewRegistered(registeredValues[l-1]);

        if (l >= 2) {
            
            // Create a Battle between both
            battlesDone.push(Battle(registeredValues[0], registeredValues[1]));
            emit NewBattle(battlesDone[battlesDone.length - 1]);

            // Remove 2 firsts elements in the array without creating gap    
            for (uint idx=2; idx<l; idx++) {
                registeredValues[idx-2] = registeredValues[idx];
            }
            // Remove the 2 lasts (if exist)
            registeredValues.pop();
            registeredValues.pop();
        }
    }

    function countRegistered() public view returns(uint) {
        return registeredValues.length;
    }
    function countBattle() public view returns(uint) {
        return battlesDone.length;
    }
}

1 Answer 1

1

You don't have to worry about that, Yes two miners can receive different version of a transaction like you suspect, they both might mine it as well and broadcast to network, but only one of them will be confirmed and recorded by the network.

So best scenario in this case would be to just wait for few confirmations.

You can read more about race conditions in these QA's

What happens if two different states of smart contract conflict?

What is the order and concurrency behavior of multiple calls to a contract in a single transaction?

Race conditions when calling remote contracts

2
  • 1
    Okay I understand, This can append multiple time and sorted multiple way, but only the first to confirm the block will set his state as the real version and others will take it as "the truth" (and only his events will be emit right?). So, my code is well done and secure ? =]
    – Arthur
    Commented Jan 7, 2022 at 13:12
  • 1
    Yes, And yes your code looks good to me. Commented Jan 8, 2022 at 11:55

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.