1

pragma solidity ^0.5.0;

I get invalid opcode error when trying to estimate gas needed for my transaction from react-native using the following line of code:

const gasAmount = await contract.methods
      .Track(RecordOwner, account, meidcalRecordHash)
      .estimateGas({from: account});

After some searching, I found this answer, which states that invalid opcode can be the result of either one of the following runtime operations:

(1)assert of an expression which evaluates to false

(2)array[i] where i >= array.length

However, I do not see any of these two possible runtime operation in my solidity "Track" function

   function Track(
        address _patientID,
        address _doctorID,
        string memory _recordHash
    ) public {
        

        // Get the record hash index
        uint256 i;
        uint256 recordHashIndex;
        string[] memory patient_recordHashes = getPatientRecordHashes(
            _patientID
        );

        for (i = 0; i < patient_recordHashes.length; i++) {
            // CHANGED count to patient_recordHashes.length
            string memory patient_recordHash = patient_recordHashes[i];
          
            if (
                keccak256(abi.encodePacked(patient_recordHash)) ==
                keccak256(abi.encodePacked(_recordHash))
            ) {
                recordHashIndex = i;
            }
        }

        // Get the doctor address index
        uint256 doctorIndex;
        address[] memory patient_listOfDoctors = getPatientRecordListOfDoctors(
            _patientID,
            recordHashIndex
        );
        for (i = 0; i < patient_listOfDoctors.length; i++) {
            if (patient_listOfDoctors[i] == _doctorID) {
                doctorIndex = i;
            }
        }
      

        // Set the bool value corresponding to the "recordHashIndex" & "doctorIndex" to true
        IsRecordSeen[_patientID][recordHashIndex][doctorIndex] = true;

        // Destroy/remove the medical record from the dcotor view screen
        delete patientToDoctorRecordNames[_patientID][_doctorID][recordHashIndex];
        delete patientToDoctorRecordHashes[_patientID][_doctorID][recordHashIndex];
        delete patientToDoctorEncKeyHashes[_patientID][_doctorID][recordHashIndex];
    } // end of the Track function



//Some of the function used inside the Track function:

// Get all the record hashes of a patient
    function getPatientRecordHashes(address _patientID)
        public
        view
        userExists(_patientID)
        returns (string[] memory)
    {
        return patientRecordHashes[_patientID];
    }

  // Get the list of doctors with access to a specific medical record of a patient
    function getPatientRecordListOfDoctors(address _patientID, uint256 index)
        public
        view
        userExists(_patientID)
        returns (address[] memory)
    {
        return patientRecordListOfDoctors[_patientID][index];
    }

Is there something wrong inside the Track function that cause invalid opcode ? Any hint would be highly appreciated

Update1: I have just tested the "Track" function on remix. It is working fine. Also, the estimate gas sometimes works, but not all the time. any hint on why this is happening, please?

const gasAmount = await contract.methods
      .Track(RecordOwner, account, meidcalRecordHash)
      .estimateGas({from: account});

some data structures used :

mapping(address => mapping(address => string[]))
    public patientToDoctorRecordHashes;

mapping(address => mapping(uint256 => address[]))
    public patientRecordListOfDoctors;

mapping(address => string[]) public patientRecordHashes;







mapping(address => mapping(uint256 => bool[])) public IsRecordSeen;

Update2: Please note there is also an "Add" function that is usually called before the "Track" function. This "Add" function has multiple "push" operations inside. some of these push operations are:

    patientRecordHashes[_patientID].push(_recordHash);
    doctorListOfPatients[doctorAddress].push(_patientID);
     patientToDoctorRecordHashes[_patientID][doctorAddress].push( _recordHash);
    IsRecordSeen[_patientID][count].push(false);
7
  • BTW, as the user who wrote that answer about invalid opcodes, I can tell you that there is yet one more trigger that can cause them: calling a function which receives an enum parameter as input, and passing it a value larger than that enum's max value. This is a rather poor decision of the Solidity compiler development team, but it is nevertheless the current behavior. Commented Aug 10, 2020 at 6:20
  • As to your question: The state-variables patientRecordHashes and patientRecordListOfDoctors are missing in your code. We have no idea what they are (arrays or mappings) and how they are initialized. Obviously, your question cannot be answered without this information! Commented Aug 10, 2020 at 6:30
  • Added them above . mapping(address => mapping(address => string[])) public patientToDoctorRecordHashes; mapping(address => mapping(uint256 => address[])) public patientRecordListOfDoctors; mapping(address => string[]) public patientRecordHashes;
    – user63058
    Commented Aug 10, 2020 at 16:48
  • However, I do not see any of these two possible runtime operation - I could not find a single occurrence of push in your code (and in this entire webpage to be honest, except for the one that i just mentioned). So obviously every storage array in your code is of length 0. Thus, obviously any attempt to access any of the arrays in your contract would result with an invalid opcode, exactly as stated in the 2nd bullet in the answer that you've quoted! Commented Aug 10, 2020 at 17:44
  • A generic way to see if the opcode invalid is in the code is to look at the assembly output of the function. You can do this by solc --asm. The output should have comments that denote entry point of your function.
    – hrkrshnn
    Commented Aug 10, 2020 at 17:47

0

Your Answer

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