Probar valores de matriz si existe clave/valor: no funciona

Tengo un problema con el siguiente contrato. Cuando lo implemento, normalmente al llamar a la función addBalance() debería pasar a falso. Pero en cambio, no funciona por completo y recibo el siguiente mensaje. ¿Qué ocurre?

Error de máquina virtual: código de operación no válido. código de operación no válido La ejecución podría haber fallado. Depure la transacción para obtener más información.


¿Cómo puedo saber si una clave no existe?

Contrato:

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;
        }
    }


}

Respuestas (3)

Eche un vistazo aquí: ¿Existen patrones de almacenamiento sencillos y bien resueltos para Solidity?

Tú podrías.

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

Es preferible generar un error en un cambio de estado inaceptable en lugar de devolver falso en la mayoría de las situaciones . Entonces ...

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

Si hay una buena razón para devolver falso y continuar:

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

En mi opinión , casi siempre es mejor usar la dirección del miembro como clave en lugar de almacenar las estructuras en filas numeradas. Así, usando cantidades arbitrarias msg.valuecomo en tu ejemplo:

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;
    }
}

Espero eso ayude.

Ya publiqué la respuesta que resolvió mis problemas. En mi caso, era necesario para seguir trabajando cuando no existía una clave. Entonces simplemente empujaría la matriz. Pero como eso no funciona, probé con mapeos y funcionó perfecto. No sabía que solo en el mapeo cada clave posible tiene un valor y que las matrices arrojan un error cuando no existen. ¡Gracias de todos modos! :)

El acceso a la matriz está protegido en Solidity. Si intenta leer más allá del final de la matriz, obtendrá un error de código de operación no válido.

Si desea detectar esta condición usted mismo, primero puede hacer una verificación de límites:

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

Encontré la solución perfecta:

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;
        }
    }


}

Las asignaciones fueron donde obtengo un valor en cada número. ¡Gracias!

¿Qué hace membersLengthahí?