1

I have a problem with the following contract. When I deploy it, normally on calling the function addBalance() it should go into the false. But instead, it completely does not work and I get the following message. What's wrong?

VM error: invalid opcode. invalid opcode The execution might have thrown. Debug the transaction to get more information.


How can I find out if a key does not exist?

Contract:

pragma solidity ^0.4.24;

contract MembersContract {

    struct Member {
        uint balance;
        address member;
        bool exists;
    }

    Member[] public members;

    constructor() public {
        members.push(Member(0, 0x0, true));
    }

    function addbalance(uint _balance) public returns(bool _success){
        if(members[1].exists == true) {
            members[1].balance = 400;
        }
        else {
            return false;
        }
    }


}
1

Have a look here: Are there well-solved and simple storage patterns for Solidity?

You could.

function isMember(uint index) public view returns(bool isIndeed) {
  return members[index].exists;
}

It's preferable to throw an error on an unacceptable state change rather than return false in most situations. So ...

function addBalance(uint index) public returns(bool success) {
  require(isMember(index);
  members[index] += msg.value; // (or _balance if you prefer)
  return true;
}

If there is a good reason to return false and carry on:

function addBalance(uint index) public returns(bool success) {
  if(!isMember(index) return false;
  if(isMember(index)) member[index] += msg.value;
  return true;
}

In my opinion it's almost always better to use the member address as the key instead of storing the structs in numbered rows. Like that, using arbitrary amounts instead msg.value as in your example:

pragma solidity ^0.4.24;

contract MembersContract {

    struct Member {
        uint balance;
        bool exists;
    }

    mapping(address => Member) public members;

    function isMember(address member) public view returns(bool isIndeed) {
        return members[member].exists;
    }

    function addMember(address member) public returns(bool success) {
        require(!isMember(member));
        members[member].exists = true;
        return true;
    }

    function addBalance(address member, uint amount) public returns(bool success){
        require(isMember(member));
        members[member].balance += amount;
        return true;
    }
}

Hope it helps.

  • I already posted the answer that solved my issues. In my case, it was needed to continue working when a key did not exist. Then I would simply push the array. But as that does not work, I tried with mappings and that worked perfect. I did not know that only in mapping every possible key has a value and that arrays throw an error when they don't exist. Thank you anyway! :) – dkb Aug 22 '18 at 22:52
0

Array access is guarded in Solidity. If you try to read past the end of the array, you'll get an invalid opcode error.

If you want to catch this condition yourself, you could do a bounds check first:

if (members.length > 1 && members[1].exists) {
    ...
}
0

Found the perfect solution:

pragma solidity ^0.4.24;

contract MembersContract {

    struct Member {
        uint balance;
        address member;
        bool exists;
    }

    mapping(uint => Member) public members;
    uint membersLength;

    constructor() public {
        members[0] = Member(100, 0x0, true);
    }

    function addbalance(uint _balance) public returns(bool _success){
        if(members[1].exists == true) {
            members[1].balance = _balance;
            return true;
        }
        else {
            return false;
        }
    }


}

Mappings were where I get a value on every number. Thanks!

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.