Estructuras anidadas con asignaciones en el interior

Tengo el siguiente código:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.7.0;
pragma experimental ABIEncoderV2; 

contract VenueRegistry{
    struct Queue{
        uint head;
        uint tail;
        mapping(uint => address) queue;
    }

    struct Venue{
        uint id;
        Queue queue;
    }

    mapping (uint => Venue) public venues;

}

Obtuve el siguiente error:

TypeError: el tipo interno o recursivo no está permitido para las variables de estado públicas. mapeo (uint => Venue) lugares públicos;

Así que hice el venuesprivado y escribí un getter:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.7.0;
pragma experimental ABIEncoderV2; 

contract VenueRegistry{
    struct Queue{
        uint head;
        uint tail;
        mapping(uint => address) queue;
    }

    struct Venue{
        uint id;
        Queue queue;
    }

    mapping (uint => Venue) venues;

    function getVenue(uint _index) public view returns(Venue memory){
        return venues[_index];
    }
}

Entonces me sale el siguiente error:

Solo las bibliotecas pueden usar el tipo de mapeo en funciones públicas o externas.

El problema parece estar en el mapeo dentro de struct Queue. Cuando elimino el mapeo, funciona. ¿Hay alguna manera de tener estructuras anidadas con asignaciones dentro de ellas?

Respuestas (1)

El problema es su uso publiccon estructuras de datos incompatibles, en dos lugares.

Primero, esta línea:

pragma solidity >=0.4.22 <0.7.0;

Hace que sea imposible replicar sus resultados porque nadie está seguro de qué compilador está usando. Por esta razón, es bueno ser específico en un contrato principal, para forzar una determinada versión. Está bien si los contratos heredados, las bibliotecas, etc. tienen más flexibilidad porque el contrato principal aún forzará el problema.

Usé Solc 6.6.

En la línea 16:

publichace varias cosas a una variable de estado. Es todo o nada: muy conveniente si los quiere todos, pero puede codificar manualmente las cosas si no quiere todo. Una de esas cosas es un captador "gratuito" que parece function variable(args) public returns(....

Funciona con variables escalares, matrices y asignaciones, por lo que uint public x;está bien y uint[] public x;está bien, pero myComplexStructWithMoreIndexedStuff[] public x;no es compatible. En resumen, esto se debe a que el compilador no está seguro de cómo construir el captador por usted.

Ningún problema. Simplemente haga que sea privado o interno y codifique su propia función getter para solicitar los argumentos, obtener los elementos y devolver una respuesta.

Entonces:

mapping (uint => Venue) private venues;

En la línea 18:

Nuevamente, publicestá tratando de devolver una estructura con un mapeo dentro. Una estructura sola sería suficiente para causar un problema junto con public.

Para estructuras, matrices y asignaciones, los argumentos de función son punteros de almacenamiento, lo que significa una referencia de 32 bytes a una ubicación de almacenamiento, no los datos reales. Esto funciona bien para contextos internos y privados donde el contrato confía en sí mismo. Sin embargo, los punteros de almacenamiento no se pueden pasar ni pasar.

Tenga en cuenta que el sistema no iterará sobre los datos para producir una respuesta larga sobre los valores de la variable, y probablemente nunca lo hará, porque eso sería una complejidad O(n): alta actividad de CPU y E/S en la cadena, lo que no quieres Dado que no puede devolver todos los elementos de una matriz y no puede devolver un puntero simple al almacenamiento, no hay nada que pueda hacer.

Podrías reescribirlo para devolver un elemento y cualquier elemento, así:

function getVenueQueueElement(uint id, uint row) public view returns(address) {
  return venues[id].queue[row];
}

Podría considerar una mejor estructura de datos para facilitar la enumeración de los lugares y los miembros de la cola que existen para que los clientes no soliciten tonterías y los objetos del contrato si lo hacen.

Eche un vistazo a este explicador actualizado y asegúrese de leer las partes 1 y 2 para comprender realmente lo que está sucediendo y los problemas abordados: https://medium.com/robhitchens/solidity-crud-epilogue-e563e794fde

Utiliza punteros de almacenamiento internamente . Son cosas misteriosas, por lo que esto podría ayudar: https://blog.b9lab.com/storage-pointers-in-solidity-7dcfaa536089

Espero eso ayude.