Wenn ich Remix verwende, gibt es ein Problem „Gasschätzung fehlgeschlagen, VM-Ausnahme während der Verarbeitung der Transaktion: ungültiger Opcode“

Wenn ich function verwende setDailyAssessmentInfo, wird ein Fehler ausgelöst:

Fehlerhafte Gasschätzung mit folgender Meldung (siehe unten). Die Ausführung der Transaktion wird wahrscheinlich fehlschlagen. Möchten Sie das Senden erzwingen? VM-Ausnahme während der Verarbeitung der Transaktion: ungültiger Opcode

Hier ist mein 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);
   }   
}

Antworten (1)

Das Problem liegt darin

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

Das Iterieren über das Array, wenn es zu groß wird, kann einen Gasfehler verursachen, und da es sich um ein Array mit variabler Länge handelt, verursacht es einen Gasschätzungsfehler.

Sie können Ihr Design so ändern, dass es mappinganstelle von Array verwendet wird.

mapping(string => dailyAssessment) daily_assessment;

Verwenden Sie a map, wobei keydas daily assessment idund valuedas struct sein wird 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;
       }

In Bezug auf Ihren Kommentar: „Hier ist ein weiteres Problem, das ich mit „getDailyAssessmentInfo“ verwenden möchte, um die Summe des Score-Arrays abzurufen. Anscheinend berechnen Sie den Durchschnitt der Ergebnisse in dieser getDailyAssessmentInfoFunktion. Es beinhaltet die Verwendung einer Schleife über alle Punkte und die Berechnung des Durchschnitts. Die ideale Lösung wäre also die Berechnung des Durchschnitts ohne Verwendung von Schleifen.

Ich schlage vor, dass Sie beim Einfügen der Daten (in setDailyAssessmentInfo) den Durchschnitt berechnen, ihn speichern und diesen Durchschnittswert einfach mit einer Get-Funktion abrufen. Denken Sie jedoch daran, dass die Berechnung keine Schleife verwenden sollte. Ich habe dazu eine einfache Idee im folgenden Code verwendet.

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;

Hoffe es hat geholfen.

Vielen Dank, es funktioniert. Hier ist ein weiteres Problem, das ich mit "getDailyAssessmentInfo" verwenden möchte, um die Summe des Score-Arrays abzurufen.
function getDailyAssessmentInfo(string _dailyAssessmentId) öffentliche Rückgaben (uint) {uint score; Einheitssumme = 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; Rückkehr (Punktzahl); }
@Kyrie Ich habe die Antwort aktualisiert, um Ihr zweites Problem widerzuspiegeln. Wenn das Ihr Problem gelöst hat, stimmen Sie zu und akzeptieren Sie die Antwort.