0

When I use function setDailyAssessmentInfo, error is raised:

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? VM Exception while processing transaction: invalid opcode

Here is my code:

pragma solidity ^0.4.21;

contract DailyAssessmentScoreContract {

   struct dailyAssessment{
        string dailyAssessmentId;
        string[] period;
        uint[] score;
    }
    dailyAssessment[] daily_assessment;


   function stringsEqual(string storage _a, string memory _b) internal returns (bool) {
        bytes storage a = bytes(_a);
        bytes memory b = bytes(_b);
        if (a.length != b.length)
            return false;
        // @todo unroll this loop
        for (uint i = 0; i < a.length; i ++)
            if (a[i] != b[i])
                return false;
        return true;
    }
    function stringToUint(string s) constant returns (uint result) {
        bytes memory b = bytes(s);
        uint i;
        result = 0;
        for (i = 0; i < b.length; i++) {
            uint c = uint(b[i]);
            if (c >= 48 && c <= 57) {
                result = result * 10 + (c - 48);
            }
        }
    }

   function setDailyAssessmentInfo(string _dailyAssessmentId, string _period, string _score) public {
       bool write = false;
       uint score = stringToUint(_score);
       for(uint i=0; i<=daily_assessment.length; i++)
       {                                                                                                                                                                                                                                                            
           if(stringsEqual(daily_assessment[i].dailyAssessmentId, _dailyAssessmentId))
           {
               daily_assessment[i].period.push(_period);
               daily_assessment[i].score.push(score);
               write = true;
           }
       }
       if(write==false)
        {
            daily_assessment[i].dailyAssessmentId=_dailyAssessmentId;
            daily_assessment[i].period.push(_period);
            daily_assessment[i].score.push(score);
        }
   }

   function getDailyAssessmentInfo(string _dailyAssessmentId) public constant returns (uint) {
       uint score;
       for(uint i=0;i<=daily_assessment.length;i++)
       {
           if(stringsEqual(daily_assessment[i].dailyAssessmentId, _dailyAssessmentId))
           {
               uint sum = 0;
               uint scoreLength = daily_assessment[i].score.length;
               for(uint j=0;j<=scoreLength;j++)
               {
                    sum = sum + daily_assessment[i].score[j];
               }
                score = sum / scoreLength;
           }
       }

       return (score);
   }   
}
0

The problem lies in

for(uint i=0; i<=daily_assessment.length; i++)

Iterating over array, if it grows too large might cause an out of gas error and since being a variable length array is causing gas estimation error.

You can change your design to use mapping instead of array.

mapping(string => dailyAssessment) daily_assessment;

Use a map in which key will be the daily assessment id and value will be the struct dailyAssessment.

function setDailyAssessmentInfo(string _dailyAssessmentId, string _period, string _score) public {
   bool write = false;
   uint score = stringToUint(_score);

   dailyAssessment storage assessment = daily_assesment[_dailyAssesmentId];
   if(assesment.dailyAssesmentId == _dailyAssesmentId)
       {
           assessment.period.push(_period);
           assessment.score.push(score);
           write = true;
       }

Regarding your comment : "here is another problem that I want to use "getDailyAssessmentInfo" to get the sum of score array,a error raise likes above Gas estimation errored with the following message", the problem is exactly the same. It seems you are calculating average of the scores in this getDailyAssessmentInfo function. It involves using a loop over all the score and calculate the average. So, the ideal solution would be calculating average without using any loops.

I suggest you to calculate average when inserting the data (in setDailyAssessmentInfo), store it and just fetch that average score using a get function. But, remember that the calculation should not use loop. I have used simple idea in the code below to do so.

struct dailyAssessment{
    string dailyAssessmentId;
    string[] period;
    uint[] score;
    uint averageScore;
}

function getDailyAssessmentInfo(string _id) returns (uint){
   return daily_assessment[_id].averageScore;
}

function setDailyAssessmentInfo(string _dailyAssessmentId, string _period, uint _score) public {
   uint average = daily_assessment[_dailyAssessmentId].averageScore;
   uint N = daily_assessment[_dailyAssessmentId].score.length;

   uint newAverage = (average * N + _score) / (N + 1);
   daily_assessment[_dailyAssessmentId].averageScore = newAverage;

Hope it helped.

  • Thank u,it works.here is another problem that I want to use "getDailyAssessmentInfo" to get the sum of score array,a error raise likes above "Gas estimation errored with the following message" – Kyrie Jun 4 '18 at 1:15
  • function getDailyAssessmentInfo(string _dailyAssessmentId) public returns (uint) { uint score; uint sum = 0; uint scoreLength = daily_assessment[_dailyAssessmentId].score.length; for(uint j=0;j<=scoreLength;j++) { sum = sum + daily_assessment[_dailyAssessmentId].score[j]; } score = sum / scoreLength; return (score); } – Kyrie Jun 4 '18 at 1:16
  • @Kyrie I have updated the answer to reflect your second problem. If that solved your problem then upvote and accept the answer. – biplavo Jun 4 '18 at 7:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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