Solidity – Efficient Way of Checking and Inserting Unique Array Addresses

arrayscontract-designcontract-developmentgassolidity

I have a following requirement that need to be cater in dapp.

  1. Insert array of address
  2. The array need to be unique. If one of the array address already exists, reject and revert entire operation.
  3. dapp must able to retrieve the user address list
  4. dapp must able to detect if a user address exists based on a user address input

Note:

  1. The above requirement must be satisfied.
  2. Full Validation checking must be done by smart contract.(cannot rely on client side checking alone).

Trying to use 3 for loop doesn't seems be a very clever way for this as it become a cost expensive operation. Unfortunately this is the only solution i can think of to satisfy above condition. Anyone have experience on dealing with this?

// probably only one of mapping or list is needed
address[] public addressList;
mapping (address => bool) public userAddr; 


    function insertAddress(address[] addressUser) public returns (bool) {
        // loop addressUser and check if it is unique
        // loop addressUser and check if it exists in mapping
        // loop and push addressUser to addressList + insert addressUser to userAddr


        return true;
    }

Best Answer

Seeing your requirement I would do :

address[] public addressList;
mapping (address => bool) public userAddr; 

function insertAddress(address[] addressUser) public returns (bool) {
    // used to check adressUser uniqueness
    mapping (address => bool) memory uniq;
    for(uint i = 0; i < addressUser.length, i++) {
        address addr = addressUser[i];
        // check if addressUser is unique
        require(uniq[addr] == false);
        uniq[addr] = true;
        // if addr is not already list
        if (userAddr[addr] == false) {
            userAddr[addr] = true;
            addressList.push(addr);
        }
    }

    return true;
}

Edit:

After seeing another contract you could use the method here and require that all address are sent in increasing order. It is probably less costly in term of gas since less memory allocation.

That would do :

function insertAddress(address[] addressUser) public returns (bool) {
    // used to check adressUser uniqueness
    address lastAddr = address(0);
    for(uint i = 0; i < addressUser.length, i++) {
        address addr = addressUser[i];
        // check if addressUser is unique
        // by forcing all address to be sent 
        // in increasing order
        require(addr > lastAddr);
        lastAddr = addr;
        // if addr is not already in list
        if (userAddr[addr] == false) {
            userAddr[addr] = true;
            addressList.push(addr);
        }
    }

    return true;
}

 

Related Topic