0

Given two contracts as follows, contract TestData calls contract Reg to fetch data that had already been stored in its map using get_attributes function.

pragma solidity ^0.4.21;
contract Reg {
    mapping (address=>bytes32[5]) Map;

    //Filling the map
    function fill_map(bytes32[5] _attributes) public  {
            Map[msg.sender] = _attributes;
    }

    //Returns data in the map corresponding to an address
    function get_attributes(address _id) view public returns (bytes32[5]){
        return Map[_id];
    }
}


contract TestData {

    address Address;
    function get_address (address _Address) public{   
        Address = _Address;
    } 

    //Retreive data from Reg contract
    bytes32[5] fetched;
    function fetch(address _reg_Adress) public view returns (bytes32[5]) {
        Reg r = Reg(_reg_Adress);
        fetched = r.get_attributes(Address);
        return (fetched);
    }

    //Retreive input data from user
    bytes32[5] inputs;
    function getInputs(bytes32[5] _inputs) public view returns (bytes32[5]){
            inputs = _inputs;
            return (inputs);
    }    

    //Compare input data with fetched data
    bool[5] a = [false,false,false,false,false];
    function compare() public view returns(bool[5]){
        for(uint i=0;i<5;i++){
            for(uint j=0;j<5;j++){
                if(inputs[i] == fetched[j]){
                    a[i] = true;                 
                }
            }
        }

        return (a);
    }  

}

This is how I test it:

  1. Fill the map with ["0x0","0x1","0x2","0x3","0x4"]

  2. For user input I also input ["0x0","0x1","0x2","0x3","0x4"]

The output is correct returning [true,true,true,true,true].

However, if I change the input say, ["0xA","0x1","0x2","0x3","0x4"], the output remains [true,true,true,true,true] although it should be [false,true,true,true,true].

Does something happen to the data as it is being fetched from the Reg contract? When I try testing the same code but with two input arrays rather than fetching the data, it works fine.

Also, I have been looking for other ways to do the comparisons. Is there any other efficient way other than looping?

6
  • Don't you want i<5 and j<5? You're stopping after comparing 3 elements.
    – user19510
    Jun 4, 2018 at 18:48
  • Yes, that is correct. I fixed it in the question. However, it is still not working when I change the input values. Jun 4, 2018 at 19:02
  • Then can you update the question with the current results? What are the values for which it works and what are the values for which it doesn't work? What is the output in both cases?
    – user19510
    Jun 4, 2018 at 19:03
  • Are you perhaps calling compare as a transaction? If so, it will permanently modify a, and subsequent calls will inherit the values in there. (Once an element is set to true, it will never go back.) You should probably just move the declaration of a inside compare() anyway.
    – user19510
    Jun 4, 2018 at 19:07
  • Ah, @Jaime's answer points out another issue. Your nested loop means you're testing whether each element in input matches any element of fetched. If you only want to match corresponding elements, you need to drop the inner loop as suggested in that answer.
    – user19510
    Jun 4, 2018 at 19:08

2 Answers 2

0

The function compare is almost right, the errors are elsewhere

function fetch(address _reg_Adress) public view returns (bytes32[5])

you have to remove view from here

function getInputs(bytes32[5] _inputs) public view returns (bytes32[5])

also from here.

Then move your array into the function and define it as memory.

//Compare input data with fetched data
function compare() public view returns(bool[5]){
    bool[5] memory a = [false,false,false,false,false];

    for(uint i=0;i<5;i++){
        for(uint j=0;j<5;j++){
            if(inputs[i] == fetched[j]){
                a[i] = true;                 
            }
        }
    }

    return (a);
}

if not, you should remove view also from the method compare to make it work

after this changes the result would be false,true,true,true,true as expected.

2
  • How did removing view solve the problem? Jun 5, 2018 at 13:50
  • if you define the function as view you can't change the contract state (eg its variables) so the value of the members of the contract are not the one expected.
    – qbsp
    Jun 5, 2018 at 13:54
0

There are several issues:

First your for loop is stopping early, at 3 when the limit should be i<5.

Also your second for is not necessary. Your function can be:

function compare() public view returns(bool[5]){
    bool[5] memory a;
    for(uint i=0;i<5;i++){
        for(uint j=0;j<5;j++){
            if(inputs[i] == fetched[j]){
                a[i] = true;                 
            }
        }
    }

    return (a);
}  

You could also do the follwoing to ensure a is updated etither when the values is true or false:

function compare() public view returns(bool[5]){
    bool[5] memory a;
    for(uint i=0;i<5;i++){
        for(uint j=0;j<5;j++){
            a[i] = (inputs[i] == fetched[j]);                 
        }
    }

    return (a);
}  

finally, your functions modify state variables so these cannot be view.

Hope this helps




UPDATE: Full code.

pragma solidity ^0.4.21;
contract Reg {
    mapping (address=>bytes32[5]) public Map;

    //Filling the map
    function fill_map(bytes32[5] _attributes) public  {
            Map[msg.sender] = _attributes;
    }

    //Returns data in the map corresponding to an address
    function get_attributes(address _id) view public returns (bytes32[5]){
        return Map[_id];
    }
}


contract TestData {

    address Address;
    function get_address (address _Address) public{   
        Address = _Address;
    } 

    //Retreive data from Reg contract
    bytes32[5] public fetched;
    function fetch(address _reg_Adress) public returns (bytes32[5]) {
        Reg r = Reg(_reg_Adress);
        fetched = r.get_attributes(Address);
        return (fetched);
    }

    //Retreive input data from user
    bytes32[5] public inputs;
    function getInputs(bytes32[5] _inputs) public returns (bytes32[5]){
            inputs = _inputs;
            return (inputs);
    }    

    //Compare input data with fetched data

    function compare() public view returns(bool[5]){
        bool[5] memory a;
        for(uint i=0;i<5;i++){
            for(uint j=0;j<5;j++){
                if(inputs[i] == fetched[j]){
                    a[i] = true;                 
                }
            }
        }

        return (a);
    }  

}
7
  • You are right about stopping early. I did fix that. However, your if statement compares each element in the first array with the corresponding element in the other array. I am trying to find whether each element in the first array is in the second array or not. Therefore, I believe I need the second loop. Jun 4, 2018 at 19:10
  • Then yes, the second loop is necessary. I edited the answer. Let me know if this solves your problem
    – Jaime
    Jun 4, 2018 at 19:16
  • It does not. Array a continues to return [true,true,true,true,true] Jun 4, 2018 at 19:18
  • I just modified the code, this works for me in remix. The issue is that when you try the first time a is all true. Then you tried with something that gives false, but your code only update a when is true so the true value is not changed. Putting it inside, initialize a to false when the function is executed. Let me know
    – Jaime
    Jun 4, 2018 at 19:49
  • Try it out with a false test case at first. For example, ["0x0","0x1","0x2","0x3","0x4"] and ["0xA","0x1","0x2","0x3","0x4"] should give [false,true,true,true,true], however it still gives [true,true,true,true,true]. Jun 4, 2018 at 23:24

Your Answer

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

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