3
contract TripHistory {
       struct Trip {
           string lat;
           string lon;
       }
        mapping(string => Trip[]) trips;

        function getTrip(string _trip_id) public view returns (Trip[]) {
            return trips[_trip_id];
        }
        function storeTrip(string _trip_id, string _lat, string _lon) public  {
           trips[_trip_id].push(Trip(_lat, _lon));
        }

}

This is my contract code. Here I'm trying to store the coordinates of a particular trip. While storing the information contract executing fine. But When I retrieve the data, It should give the array of coordinates. But it is throwing an error.

reason: 'insufficient data for uint256 type'

What I'm missing here. Is there any other way to achieve what I'm trying here. Kindly help me out.

P.S: I'm new to solidity.

2 Answers 2

5

You need to put memory right after Type[] to return struct array in solidity.

Return an array of struct from a function

contract TripHistory {
  struct Trip {
    string lat;
    string lon;
  }
  mapping (string => Trip) public trips;
  uint public tripcount;

  constructor() public {
    tripcount = 0;
    storeTrip("let0","long0");
    storeTrip("let1","long1");
  }
  function storeTrip(string memory _lat, string memory _lon) public  {
    trips[tripcount] = Trip(_lat, _lon);
    tripcount++;
  }
  //return Array of structure
  function getTrip() public view returns (Trip[] memory){
      Trip[] memory trrips = new Trip[](tripcount);
      for (uint i = 0; i < tripcount; i++) {
          Trip storage trrip = trips[i];
          trrips[i] = trrip;
      }
      return trrips;
  }
}
1

It's not possible to return structs on public functions yet. A workaround to this can be found in this question: Returning a struct and reading via Web3

At the same time it's also not possible to return arrays of dynamic types (such as strings), as can be seen in this question: Solidity: Can you return dynamic arrays in a function?

A workaround in your case could be to encode the lon and lat together into a single variable of fixed length (as you know that the values are bounded, see: What is the maximum length of latitude and longitude?). So these values could be could be represented by two int16 variables. These two variables can be encoded together as one single int32 variable, as can bee seen in Is it possible to pack two uintX into uint2X?.

Then you could change your smart contract code to the following:

contract TripHistory {
    mapping(string => int32[]) trips;

    function getTrip(string _trip_id) public view returns (int32[]) {
        return trips[_trip_id];
    }
    function storeTrip(string _trip_id, int16 _lat, int16 _lon) public {
       trips[_trip_id].push((int32(_lat) << 16) | int32(_lon));
    }
}

Then you would need to decode the returned array of int32's in your client code as well, by using the bitshift operators inside your language of choice.

You can also consider changing the trip_id parameters to a datatype of set length (such as bytes32), instead of a string, as this is usually long enough to fit a unique identifier.

Let me know if this works for you.

2

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.