solidez: usando una matriz en una estructura

Estoy diseñando/desarrollando un contrato inteligente en el que tenemos 2 tipos de objetos: objetos móviles y objetos inmóviles. El estado de ambos tipos cambia de vez en cuando. ex. en el caso de un objeto en movimiento, su ubicación se puede cambiar, pero en un objeto que no se mueve no tenemos cambio de ubicación, pero también ex. tenemos el cambio de propietario del objeto. Entonces, definí a structde la siguiente manera:

struct Object{
    byte[] nonMoveState;
    byte[] MoveState;
  }
  mapping(address => Object) state;

Y también definí un evento de la siguiente manera para mantener el historial de cambios para mostrarlo en el hash de la transacción:

event changeAction(address indexed objectAdd, byte actionType, byte actionValue);

Ahora, necesito registrar todos los cambios, ej. en caso de objeto en movimiento, su lugar se cambia de París a Londres. Entonces, si lo hago de la siguiente manera:

function setAction(address indexed objectAdd, byte actionType, byte actionValue) public returns (bool) {

    state[objectAdd].MoveState[].push("actionValue");
    emit changeAction(address indexed objectAdd, byte actionType, byte actionValue);

    return true;
  }

Y función de invocación:

setAction(0xE07b6e5a2026CC916A4E2Beb03767ae0ED6af773, "change place", "Paris");

setAction(0xE07b6e5a2026CC916A4E2Beb03767ae0ED6af773, "change place", "London");

¿Hay algo mal?

***Información adicional: De hecho, en el caso de un objeto en movimiento, la nueva "acción" es leída/escrita por RFID/NFC y luego el nuevo estado se almacena en la cadena de bloques.

Respuestas (1)

Puede usar matrices (y mappingy struct) anidadas dentro de estructuras. Yo no lo haría así.

byte[]es una matriz de un solo byte. Una forma natural de trabajar con eso es cuando desea consumir o agregar un byte a la vez. No sería mi primera opción para un trozo como "París".

Usted menciona la necesidad de registrar todos los cambios. No dijiste para consumo de quién. Esto es importante porque existe una forma barata y natural de hacerlo, basada en el supuesto de que el contrato siempre estará interesado en el estado actual. Es decir, el contrato no necesita acceso a la historia, pero los observadores sí. Usa eventos para eso.

Usar an addresspara una clave es natural si el tema es un usuario o un contrato. Podría sugerir usar un sin sentido bytes32en otros casos.

Aquí hay un patrón de propósito general adaptado para su ejemplo. Consulte ¿Existen patrones de almacenamiento sencillos y bien resueltos para Solidity?

pragma solidity 0.4.19; 

contract Object {

    struct ObjectStruct {
        bytes32 location;
        address owner; // caution about using "owner" because it has a de facto meaning in standard contracts. Landlord, titleHolder ... 
        bool isObject;
    }

    mapping(bytes32 => ObjectStruct) public objectStructs;
    bytes32[] public objectList;

    event LogNewObject(address sender, bytes32 uid, bytes32 location, address owner);
    event LogChangeObjectLocation(address sender, bytes32 uid, bytes32 newLocation);
    event LogChangeObjectOwner(address sender, bytes32 uid, address newOwner);

    function isObject(bytes32 _uid) public view returns(bool isIndeed) {
        return objectStructs[_uid].isObject;
    }

    function getObjectCount() public view returns(uint count) {
        return objectList.length;
    }

    function newObject(bytes32 _uid, bytes32 _location, address _owner) public returns(bool success) {
        require(!isObject(_uid));
        objectStructs[_uid].location = _location;
        objectStructs[_uid].owner = _owner;
        objectStructs[_uid].isObject = true;
        objectList.push(_uid);
        LogNewObject(msg.sender, _uid, _location, _owner);
        return true;
    }

    function changeObjectLocation(bytes32 _uid, bytes32 _newLocation) public returns(bool success) {
        require(isObject(_uid));
        objectStructs[_uid].location = _newLocation;
        LogChangeObjectLocation(msg.sender, _uid, _newLocation);
        return true;
    }

    function changeObjectOwner(bytes32 _uid, address _newOwner) public returns(bool success) {
        require(isObject(_uid));
        objectStructs[_uid].owner = _newOwner;
        LogChangeObjectOwner(msg.sender, _uid, _newOwner);
        return true;
    }

}

Espero eso ayude.

Seguro que ayuda demasiado. Gracias. Solo tenía una pregunta: "¿cuándo" necesitamos cambiar la dirección del propietario del objeto (con la función changeObjectOwner)? de hecho, ¿en qué situación? ¿Podría por favor mencionar un ejemplo? Gracias. Mientras tanto, agrego información adicional en mi pregunta.
También tendría otra pregunta: si queremos generalizar "ubicación de bytes32;" en struct, de modo que su nombre sería "estado" que incluye varios sub_estado ej. "ubicación", "precio", "vendido", etc. ¿Cómo podemos definir tal "estado" en nuestra estructura? Gracias de nuevo.
Expliqué mi pregunta con más detalles aquí: ethereum.stackexchange.com/questions/47529/… Gracias por su ayuda.