Efficient way of checking and inserting array address that is unqiue











up vote
1
down vote

favorite












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;
}









share|improve this question









New contributor




vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
























    up vote
    1
    down vote

    favorite












    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;
    }









    share|improve this question









    New contributor




    vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






















      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      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;
      }









      share|improve this question









      New contributor




      vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      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;
      }






      solidity contract-development contract-design gas arrays






      share|improve this question









      New contributor




      vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 2 days ago





















      New contributor




      vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 2 days ago









      vincentsty

      1414




      1414




      New contributor




      vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      vincentsty is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          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 = addres(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;
          }





          share|improve this answer






























            up vote
            1
            down vote













            I have created contracts like this before and have seen many of the issues you are having. In short, these operations you are attempting to perform are expensive. Thus, the best way to do this is simply do it efficiently.



            In order to satisfy the requirements, I would put the entire function in a loop that iterates over each address that is passed in. In order to make it as efficient as possible, you can use an if statement to check if the address already exists. If it does, you can simply move onto the next address without performing more calculations on the current one. Depending on how you are passing in addresses, this may have huge gas savings.



            As an example, you could do:



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


            function insertAddress(address addressUser) public returns (bool)
            {
            for (uint256 i = 0; i < addressUser.length; i++) {
            if (address does not exist) {
            push addressUser to addressList
            insert addressUser to userAddr
            }
            }

            return true;
            }


            Edit based on the new requirements




            The array need to be unique. If one of the array address already exists, reject and revert entire operation.




            If this is the case, then the above does not apply and what you originally had is the best way to do it.



            Edit based on comments



            Thinking about it logically, in order to check the array you must check every address. This requires opcodes that check each item, and you cannot get around this. After these checks are performed, you must write each item to the blockchain, which also requires opcodes for each of these. This whole process is computationally expensive, and is the reason why a lot of this logic is generally suggested off-chain.



            One thing you can do is compare the hashes of the arrays (one that you are submitting and one that is being checked). You can take the keccack256 of each array in order to ensure a unique hash. You can store this hash in the smart contract and submit a hash to be checked, rather than the entire array. By doing this, you are now only performing one check, as opposed to N checks (N being the number of items in the array).



            You will still be required to loop to add all the items to the smart contract, but now you have effectively removed one loop.



            An example would be:



            address public addressList;
            mapping (address => bool) public userAddr;
            mapping (bytes32 => bool) public doesHashExist;


            function insertAddress(address addressUser) public returns (bool)
            {
            bytes32 newHash = keccak256(addressUser);
            require(!doesHashExist[newHash]);
            for (uint256 i = 0; i < addressUser.length; i++) {
            push addressUser to addressList
            insert addressUser to userAddr
            }
            }
            doesHashExist[newHash] = True;
            return true;
            }


            You will see that there is a new mapping that is used to store hashes that exist on the contract. The function now only does a single check (as well as a hashing) to confirm existence of the array. Finally, it saves the hash.






            share|improve this answer



















            • 1




              The above u array is to skip and insert non unique address which i have seen it is being practiced a lot. but the requirement for the dapp is to reject entire operation even if one of it is unique.
              – vincentsty
              2 days ago








            • 1




              Yup, i know it works, but it require at least 3 for loop (one for checking if the array pass in itself is unique, one for checking whether the array pass in have existing value, one for inserting). I am trying to look for a more cost effective way.
              – vincentsty
              2 days ago








            • 1




              The requirement must be satisfied in the smart contract itself as per the requirement. It should not be reliant on external validation. Between, is there a way to reduce 3 for loop to 2? (eg: for loop to checking array itself is unique can be checked with other more efficient way?)
              – vincentsty
              2 days ago








            • 1




              Why would it be suggested to do offchain. Offchain validation can be bypass easily by directly calling to the smart contract function from user wallet address
              – vincentsty
              2 days ago








            • 1




              You can take the keccak256 of each array in order to ensure a unique hash. Didn't really understand how this will reduce one for loop. keccak256(array addressList1) === keccak256(array addressList2) only can check if two array list is same (in terms of length, value and order of value). It cannot identified if an item of an array does exist in another array Or i misunderstand the implementation.
              – vincentsty
              2 days ago













            Your Answer








            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "642"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });






            vincentsty is a new contributor. Be nice, and check out our Code of Conduct.










             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fethereum.stackexchange.com%2fquestions%2f62572%2fefficient-way-of-checking-and-inserting-array-address-that-is-unqiue%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            2
            down vote



            accepted










            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 = addres(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;
            }





            share|improve this answer



























              up vote
              2
              down vote



              accepted










              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 = addres(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;
              }





              share|improve this answer

























                up vote
                2
                down vote



                accepted







                up vote
                2
                down vote



                accepted






                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 = addres(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;
                }





                share|improve this 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 = addres(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;
                }






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited yesterday

























                answered 2 days ago









                dievardump

                1364




                1364






















                    up vote
                    1
                    down vote













                    I have created contracts like this before and have seen many of the issues you are having. In short, these operations you are attempting to perform are expensive. Thus, the best way to do this is simply do it efficiently.



                    In order to satisfy the requirements, I would put the entire function in a loop that iterates over each address that is passed in. In order to make it as efficient as possible, you can use an if statement to check if the address already exists. If it does, you can simply move onto the next address without performing more calculations on the current one. Depending on how you are passing in addresses, this may have huge gas savings.



                    As an example, you could do:



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


                    function insertAddress(address addressUser) public returns (bool)
                    {
                    for (uint256 i = 0; i < addressUser.length; i++) {
                    if (address does not exist) {
                    push addressUser to addressList
                    insert addressUser to userAddr
                    }
                    }

                    return true;
                    }


                    Edit based on the new requirements




                    The array need to be unique. If one of the array address already exists, reject and revert entire operation.




                    If this is the case, then the above does not apply and what you originally had is the best way to do it.



                    Edit based on comments



                    Thinking about it logically, in order to check the array you must check every address. This requires opcodes that check each item, and you cannot get around this. After these checks are performed, you must write each item to the blockchain, which also requires opcodes for each of these. This whole process is computationally expensive, and is the reason why a lot of this logic is generally suggested off-chain.



                    One thing you can do is compare the hashes of the arrays (one that you are submitting and one that is being checked). You can take the keccack256 of each array in order to ensure a unique hash. You can store this hash in the smart contract and submit a hash to be checked, rather than the entire array. By doing this, you are now only performing one check, as opposed to N checks (N being the number of items in the array).



                    You will still be required to loop to add all the items to the smart contract, but now you have effectively removed one loop.



                    An example would be:



                    address public addressList;
                    mapping (address => bool) public userAddr;
                    mapping (bytes32 => bool) public doesHashExist;


                    function insertAddress(address addressUser) public returns (bool)
                    {
                    bytes32 newHash = keccak256(addressUser);
                    require(!doesHashExist[newHash]);
                    for (uint256 i = 0; i < addressUser.length; i++) {
                    push addressUser to addressList
                    insert addressUser to userAddr
                    }
                    }
                    doesHashExist[newHash] = True;
                    return true;
                    }


                    You will see that there is a new mapping that is used to store hashes that exist on the contract. The function now only does a single check (as well as a hashing) to confirm existence of the array. Finally, it saves the hash.






                    share|improve this answer



















                    • 1




                      The above u array is to skip and insert non unique address which i have seen it is being practiced a lot. but the requirement for the dapp is to reject entire operation even if one of it is unique.
                      – vincentsty
                      2 days ago








                    • 1




                      Yup, i know it works, but it require at least 3 for loop (one for checking if the array pass in itself is unique, one for checking whether the array pass in have existing value, one for inserting). I am trying to look for a more cost effective way.
                      – vincentsty
                      2 days ago








                    • 1




                      The requirement must be satisfied in the smart contract itself as per the requirement. It should not be reliant on external validation. Between, is there a way to reduce 3 for loop to 2? (eg: for loop to checking array itself is unique can be checked with other more efficient way?)
                      – vincentsty
                      2 days ago








                    • 1




                      Why would it be suggested to do offchain. Offchain validation can be bypass easily by directly calling to the smart contract function from user wallet address
                      – vincentsty
                      2 days ago








                    • 1




                      You can take the keccak256 of each array in order to ensure a unique hash. Didn't really understand how this will reduce one for loop. keccak256(array addressList1) === keccak256(array addressList2) only can check if two array list is same (in terms of length, value and order of value). It cannot identified if an item of an array does exist in another array Or i misunderstand the implementation.
                      – vincentsty
                      2 days ago

















                    up vote
                    1
                    down vote













                    I have created contracts like this before and have seen many of the issues you are having. In short, these operations you are attempting to perform are expensive. Thus, the best way to do this is simply do it efficiently.



                    In order to satisfy the requirements, I would put the entire function in a loop that iterates over each address that is passed in. In order to make it as efficient as possible, you can use an if statement to check if the address already exists. If it does, you can simply move onto the next address without performing more calculations on the current one. Depending on how you are passing in addresses, this may have huge gas savings.



                    As an example, you could do:



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


                    function insertAddress(address addressUser) public returns (bool)
                    {
                    for (uint256 i = 0; i < addressUser.length; i++) {
                    if (address does not exist) {
                    push addressUser to addressList
                    insert addressUser to userAddr
                    }
                    }

                    return true;
                    }


                    Edit based on the new requirements




                    The array need to be unique. If one of the array address already exists, reject and revert entire operation.




                    If this is the case, then the above does not apply and what you originally had is the best way to do it.



                    Edit based on comments



                    Thinking about it logically, in order to check the array you must check every address. This requires opcodes that check each item, and you cannot get around this. After these checks are performed, you must write each item to the blockchain, which also requires opcodes for each of these. This whole process is computationally expensive, and is the reason why a lot of this logic is generally suggested off-chain.



                    One thing you can do is compare the hashes of the arrays (one that you are submitting and one that is being checked). You can take the keccack256 of each array in order to ensure a unique hash. You can store this hash in the smart contract and submit a hash to be checked, rather than the entire array. By doing this, you are now only performing one check, as opposed to N checks (N being the number of items in the array).



                    You will still be required to loop to add all the items to the smart contract, but now you have effectively removed one loop.



                    An example would be:



                    address public addressList;
                    mapping (address => bool) public userAddr;
                    mapping (bytes32 => bool) public doesHashExist;


                    function insertAddress(address addressUser) public returns (bool)
                    {
                    bytes32 newHash = keccak256(addressUser);
                    require(!doesHashExist[newHash]);
                    for (uint256 i = 0; i < addressUser.length; i++) {
                    push addressUser to addressList
                    insert addressUser to userAddr
                    }
                    }
                    doesHashExist[newHash] = True;
                    return true;
                    }


                    You will see that there is a new mapping that is used to store hashes that exist on the contract. The function now only does a single check (as well as a hashing) to confirm existence of the array. Finally, it saves the hash.






                    share|improve this answer



















                    • 1




                      The above u array is to skip and insert non unique address which i have seen it is being practiced a lot. but the requirement for the dapp is to reject entire operation even if one of it is unique.
                      – vincentsty
                      2 days ago








                    • 1




                      Yup, i know it works, but it require at least 3 for loop (one for checking if the array pass in itself is unique, one for checking whether the array pass in have existing value, one for inserting). I am trying to look for a more cost effective way.
                      – vincentsty
                      2 days ago








                    • 1




                      The requirement must be satisfied in the smart contract itself as per the requirement. It should not be reliant on external validation. Between, is there a way to reduce 3 for loop to 2? (eg: for loop to checking array itself is unique can be checked with other more efficient way?)
                      – vincentsty
                      2 days ago








                    • 1




                      Why would it be suggested to do offchain. Offchain validation can be bypass easily by directly calling to the smart contract function from user wallet address
                      – vincentsty
                      2 days ago








                    • 1




                      You can take the keccak256 of each array in order to ensure a unique hash. Didn't really understand how this will reduce one for loop. keccak256(array addressList1) === keccak256(array addressList2) only can check if two array list is same (in terms of length, value and order of value). It cannot identified if an item of an array does exist in another array Or i misunderstand the implementation.
                      – vincentsty
                      2 days ago















                    up vote
                    1
                    down vote










                    up vote
                    1
                    down vote









                    I have created contracts like this before and have seen many of the issues you are having. In short, these operations you are attempting to perform are expensive. Thus, the best way to do this is simply do it efficiently.



                    In order to satisfy the requirements, I would put the entire function in a loop that iterates over each address that is passed in. In order to make it as efficient as possible, you can use an if statement to check if the address already exists. If it does, you can simply move onto the next address without performing more calculations on the current one. Depending on how you are passing in addresses, this may have huge gas savings.



                    As an example, you could do:



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


                    function insertAddress(address addressUser) public returns (bool)
                    {
                    for (uint256 i = 0; i < addressUser.length; i++) {
                    if (address does not exist) {
                    push addressUser to addressList
                    insert addressUser to userAddr
                    }
                    }

                    return true;
                    }


                    Edit based on the new requirements




                    The array need to be unique. If one of the array address already exists, reject and revert entire operation.




                    If this is the case, then the above does not apply and what you originally had is the best way to do it.



                    Edit based on comments



                    Thinking about it logically, in order to check the array you must check every address. This requires opcodes that check each item, and you cannot get around this. After these checks are performed, you must write each item to the blockchain, which also requires opcodes for each of these. This whole process is computationally expensive, and is the reason why a lot of this logic is generally suggested off-chain.



                    One thing you can do is compare the hashes of the arrays (one that you are submitting and one that is being checked). You can take the keccack256 of each array in order to ensure a unique hash. You can store this hash in the smart contract and submit a hash to be checked, rather than the entire array. By doing this, you are now only performing one check, as opposed to N checks (N being the number of items in the array).



                    You will still be required to loop to add all the items to the smart contract, but now you have effectively removed one loop.



                    An example would be:



                    address public addressList;
                    mapping (address => bool) public userAddr;
                    mapping (bytes32 => bool) public doesHashExist;


                    function insertAddress(address addressUser) public returns (bool)
                    {
                    bytes32 newHash = keccak256(addressUser);
                    require(!doesHashExist[newHash]);
                    for (uint256 i = 0; i < addressUser.length; i++) {
                    push addressUser to addressList
                    insert addressUser to userAddr
                    }
                    }
                    doesHashExist[newHash] = True;
                    return true;
                    }


                    You will see that there is a new mapping that is used to store hashes that exist on the contract. The function now only does a single check (as well as a hashing) to confirm existence of the array. Finally, it saves the hash.






                    share|improve this answer














                    I have created contracts like this before and have seen many of the issues you are having. In short, these operations you are attempting to perform are expensive. Thus, the best way to do this is simply do it efficiently.



                    In order to satisfy the requirements, I would put the entire function in a loop that iterates over each address that is passed in. In order to make it as efficient as possible, you can use an if statement to check if the address already exists. If it does, you can simply move onto the next address without performing more calculations on the current one. Depending on how you are passing in addresses, this may have huge gas savings.



                    As an example, you could do:



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


                    function insertAddress(address addressUser) public returns (bool)
                    {
                    for (uint256 i = 0; i < addressUser.length; i++) {
                    if (address does not exist) {
                    push addressUser to addressList
                    insert addressUser to userAddr
                    }
                    }

                    return true;
                    }


                    Edit based on the new requirements




                    The array need to be unique. If one of the array address already exists, reject and revert entire operation.




                    If this is the case, then the above does not apply and what you originally had is the best way to do it.



                    Edit based on comments



                    Thinking about it logically, in order to check the array you must check every address. This requires opcodes that check each item, and you cannot get around this. After these checks are performed, you must write each item to the blockchain, which also requires opcodes for each of these. This whole process is computationally expensive, and is the reason why a lot of this logic is generally suggested off-chain.



                    One thing you can do is compare the hashes of the arrays (one that you are submitting and one that is being checked). You can take the keccack256 of each array in order to ensure a unique hash. You can store this hash in the smart contract and submit a hash to be checked, rather than the entire array. By doing this, you are now only performing one check, as opposed to N checks (N being the number of items in the array).



                    You will still be required to loop to add all the items to the smart contract, but now you have effectively removed one loop.



                    An example would be:



                    address public addressList;
                    mapping (address => bool) public userAddr;
                    mapping (bytes32 => bool) public doesHashExist;


                    function insertAddress(address addressUser) public returns (bool)
                    {
                    bytes32 newHash = keccak256(addressUser);
                    require(!doesHashExist[newHash]);
                    for (uint256 i = 0; i < addressUser.length; i++) {
                    push addressUser to addressList
                    insert addressUser to userAddr
                    }
                    }
                    doesHashExist[newHash] = True;
                    return true;
                    }


                    You will see that there is a new mapping that is used to store hashes that exist on the contract. The function now only does a single check (as well as a hashing) to confirm existence of the array. Finally, it saves the hash.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited 2 days ago

























                    answered 2 days ago









                    shane

                    1,5992530




                    1,5992530








                    • 1




                      The above u array is to skip and insert non unique address which i have seen it is being practiced a lot. but the requirement for the dapp is to reject entire operation even if one of it is unique.
                      – vincentsty
                      2 days ago








                    • 1




                      Yup, i know it works, but it require at least 3 for loop (one for checking if the array pass in itself is unique, one for checking whether the array pass in have existing value, one for inserting). I am trying to look for a more cost effective way.
                      – vincentsty
                      2 days ago








                    • 1




                      The requirement must be satisfied in the smart contract itself as per the requirement. It should not be reliant on external validation. Between, is there a way to reduce 3 for loop to 2? (eg: for loop to checking array itself is unique can be checked with other more efficient way?)
                      – vincentsty
                      2 days ago








                    • 1




                      Why would it be suggested to do offchain. Offchain validation can be bypass easily by directly calling to the smart contract function from user wallet address
                      – vincentsty
                      2 days ago








                    • 1




                      You can take the keccak256 of each array in order to ensure a unique hash. Didn't really understand how this will reduce one for loop. keccak256(array addressList1) === keccak256(array addressList2) only can check if two array list is same (in terms of length, value and order of value). It cannot identified if an item of an array does exist in another array Or i misunderstand the implementation.
                      – vincentsty
                      2 days ago
















                    • 1




                      The above u array is to skip and insert non unique address which i have seen it is being practiced a lot. but the requirement for the dapp is to reject entire operation even if one of it is unique.
                      – vincentsty
                      2 days ago








                    • 1




                      Yup, i know it works, but it require at least 3 for loop (one for checking if the array pass in itself is unique, one for checking whether the array pass in have existing value, one for inserting). I am trying to look for a more cost effective way.
                      – vincentsty
                      2 days ago








                    • 1




                      The requirement must be satisfied in the smart contract itself as per the requirement. It should not be reliant on external validation. Between, is there a way to reduce 3 for loop to 2? (eg: for loop to checking array itself is unique can be checked with other more efficient way?)
                      – vincentsty
                      2 days ago








                    • 1




                      Why would it be suggested to do offchain. Offchain validation can be bypass easily by directly calling to the smart contract function from user wallet address
                      – vincentsty
                      2 days ago








                    • 1




                      You can take the keccak256 of each array in order to ensure a unique hash. Didn't really understand how this will reduce one for loop. keccak256(array addressList1) === keccak256(array addressList2) only can check if two array list is same (in terms of length, value and order of value). It cannot identified if an item of an array does exist in another array Or i misunderstand the implementation.
                      – vincentsty
                      2 days ago










                    1




                    1




                    The above u array is to skip and insert non unique address which i have seen it is being practiced a lot. but the requirement for the dapp is to reject entire operation even if one of it is unique.
                    – vincentsty
                    2 days ago






                    The above u array is to skip and insert non unique address which i have seen it is being practiced a lot. but the requirement for the dapp is to reject entire operation even if one of it is unique.
                    – vincentsty
                    2 days ago






                    1




                    1




                    Yup, i know it works, but it require at least 3 for loop (one for checking if the array pass in itself is unique, one for checking whether the array pass in have existing value, one for inserting). I am trying to look for a more cost effective way.
                    – vincentsty
                    2 days ago






                    Yup, i know it works, but it require at least 3 for loop (one for checking if the array pass in itself is unique, one for checking whether the array pass in have existing value, one for inserting). I am trying to look for a more cost effective way.
                    – vincentsty
                    2 days ago






                    1




                    1




                    The requirement must be satisfied in the smart contract itself as per the requirement. It should not be reliant on external validation. Between, is there a way to reduce 3 for loop to 2? (eg: for loop to checking array itself is unique can be checked with other more efficient way?)
                    – vincentsty
                    2 days ago






                    The requirement must be satisfied in the smart contract itself as per the requirement. It should not be reliant on external validation. Between, is there a way to reduce 3 for loop to 2? (eg: for loop to checking array itself is unique can be checked with other more efficient way?)
                    – vincentsty
                    2 days ago






                    1




                    1




                    Why would it be suggested to do offchain. Offchain validation can be bypass easily by directly calling to the smart contract function from user wallet address
                    – vincentsty
                    2 days ago






                    Why would it be suggested to do offchain. Offchain validation can be bypass easily by directly calling to the smart contract function from user wallet address
                    – vincentsty
                    2 days ago






                    1




                    1




                    You can take the keccak256 of each array in order to ensure a unique hash. Didn't really understand how this will reduce one for loop. keccak256(array addressList1) === keccak256(array addressList2) only can check if two array list is same (in terms of length, value and order of value). It cannot identified if an item of an array does exist in another array Or i misunderstand the implementation.
                    – vincentsty
                    2 days ago






                    You can take the keccak256 of each array in order to ensure a unique hash. Didn't really understand how this will reduce one for loop. keccak256(array addressList1) === keccak256(array addressList2) only can check if two array list is same (in terms of length, value and order of value). It cannot identified if an item of an array does exist in another array Or i misunderstand the implementation.
                    – vincentsty
                    2 days ago












                    vincentsty is a new contributor. Be nice, and check out our Code of Conduct.










                     

                    draft saved


                    draft discarded


















                    vincentsty is a new contributor. Be nice, and check out our Code of Conduct.













                    vincentsty is a new contributor. Be nice, and check out our Code of Conduct.












                    vincentsty is a new contributor. Be nice, and check out our Code of Conduct.















                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fethereum.stackexchange.com%2fquestions%2f62572%2fefficient-way-of-checking-and-inserting-array-address-that-is-unqiue%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

                    Alcedinidae

                    RAC Tourist Trophy