¿Cómo leo una matriz dentro de una estructura?

Como parte del aprendizaje de la solidez y el desarrollo de contratos inteligentes, estoy desarrollando un sistema simple de gestión/seguimiento de piezas. Tengo una estructura y un mapeo para una lista de partes como tal:

struct Part {
   uint pNumber;
   string pName;
   string pDesc;
   string pManuf;
   string[] owners;
}
mapping(uint => Part) public part_store;
uint public partsCount;

Estoy agregando nuevas partes al mapeo usando el siguiente método:

function createPart (string _pName, string _pDesc, string _pManuf) public {
        partsCount++;
        part_store[partsCount].pNumber = partsCount;
        part_store[partsCount].pName = _pName;
        part_store[partsCount].pDesc = _pDesc;
        part_store[partsCount].pManuf = _pManuf; 
        part_store[partsCount].owners.push(_pManuf);

        /* Trigger event */
        emit partCreatedEvent(partsCount);
    }

Todo se compila sin errores y puedo enviar esta transacción a través de Truffle. Obtengo un ID de transacción cuando creo piezas nuevas.

Ahora estoy tratando de leer los datos dentro de la parte, pero no veo la matriz donde presioné los datos. Parece que el último dato en el objeto es el fabricante. Pero no muestra que haya empujado al fabricante original como propietario de esa parte.

> contract.part_store(1)
Result:
[ BigNumber { s: 1, e: 0, c: [1] },
   'part name',
   'part desc',
   'part Manuf' ]
>

¿No he definido correctamente la matriz y le he enviado datos? ¿Cómo puedo leer los datos dentro de esa matriz? Necesito una matriz porque esta es una manera fácil de almacenar los propietarios de las partes, ya que los propietarios pueden cambiar (es decir, definir un nuevo propietario empujando el nuevo propietario a la matriz para la parte específica).

Gracias a todos.

EDITAR : parece que si defino una matriz fuera de una estructura y publicpuedo leer el valor:

string[] public test1;
string[] test2;
function writeElem() public {
   test1.push("t1");
   test2.push("t2");
}

resultados:

> contract.writeElem()
...tx: 0x88...
...txHas: 0x88...
> contract.test1(0)
't1'
> contract.test2(0)
TypeError: app.test2 is not a function
> contract.test2
undefined

No creo que pueda definir variables en una estructura pública o privada, así que tal vez por eso no puedo leer esos datos. ¿Podría ser algo con acceso a datos para arreglos en Solidity?

Respuestas (2)

Lo que sucede es que el captador "gratuito" que está utilizando no admite el valor indexado, por lo que simplemente lo omite. El captador "gratuito" de the public mappinges aproximadamente

function part_store(uint index) public view returns(uint, string, string, string) {
  Part storage p = part_store[index];
  return (p.pNumber, p.pName, p.pDesc, p.pManu);
}

Tienes que hacer una función para obtener la información que falta. Tienes latitud. Simplemente puede continuar con lo que comencé y agregar la matriz, pero no soy un gran admirador debido a problemas de escala y costo de gasolina.

en su lugar podrías

function getProductOwnerCount(uint part) public view returns(uint) { 
  return prod_store[part].owners.length; 
}

function getProductOwnerAtIndex(uint part, uint index) public view returns(address) { 
  return prod_store[part].owners[index]; 
}

Esas dos funciones permiten que cualquier observador establezca la longitud de la matriz (para que no se salgan del final) y obtengan cualquier fila que les interese. O bien, el cliente puede iterar sobre todas las filas para obtenerlas todas. Vale la pena señalar que es posible que los clientes ya conozcan a la mayoría de los propietarios si han estado observando los registros de eventos y si se han emitido eventos cada vez que se agregó un propietario (debería).

Espero eso ayude.

Gracias por tu comentario. Ya he probado de una manera similar a getProductOwnerAtIndex. Sin embargo, la matriz almacenará una lista de cadenas de nombres en lugar de direcciones. En este caso dirá ...returns(string)y no dirección. Cuando trato de hacer eso, obtengoTypeError: Data location must be "memory" for return parameter in function, but none was given.
Acabo de responder a mi propia pregunta. Puede devolver cadenas siempre que utilice la memorypalabra clave como tal ...returns(string memory) {. Del mismo modo, haga lo mismo para las matrices de cadenas, pero también debe definir pragma experimental ABIEncoderV2;para poder hacer eso. Gracias por señalarme en la dirección correcta.
Derecho. Lo nuevo del compilador.

Fue capaz de encontrar una respuesta a mi pregunta. Puede devolver cadenas siempre que use la memorypalabra clave.

function getProductOwner() public view returns(string memory) {
    return part_store[1].owners[0];
}

Del mismo modo, haga lo mismo para las matrices de cadenas, pero también debe agregar una nueva definición de pragma en la parte superior de la página de origen para poder hacer eso. Recibirá advertencias pero no errores, supongo que esto se debe a que es una característica nueva que eventualmente será completamente funcional en Solidity.

pragma experimental ABIEncoderV2;

function getProductOwners() public view returns(string[] memory) {
    return part_store[1].owners;
}

Aquí está la prueba que hice en Remix.ingrese la descripción de la imagen aquí