Pasar la dirección de una estructura asignada en almacenamiento en un contrato, a una función en otro contrato

Tengo un contrato que declara una matriz de estructuras asignadas en storage.

Desde este contrato, invoco una función en otro contrato, que toma una sola estructura como entrada.

Para solucionar los "obstáculos de sintaxis", paso los contenidos (variables) de la estructura.

Necesitaba agregar algunas variables más a la estructura y ahora aparece el siguiente error de compilación:

Pila demasiado profunda, intente eliminar las variables locales.

Instintivamente creo que la única solución es pasar la estructura a la función "por dirección"

Dado que tengo la matriz de estas estructuras asignadas en storage, creo que debería ser factible.

Sin embargo, no importa cómo intente escribirlo, sigo recibiendo errores.

Cuando declaro el tipo de retorno como address, obtengo el siguiente error de compilación:

Tipo de argumento de retorno struct La referencia de almacenamiento de MyStruct no se puede convertir implícitamente a la dirección de tipo esperada.

Cuando declaro el tipo de retorno como MyStruct storage, obtengo el siguiente error de compilación:

La ubicación debe ser memoria para funciones visibles públicamente (elimine la palabra clave "almacenamiento").

Cuando declaro el tipo de retorno como MyStruct memory, obtengo el siguiente error de tiempo de ejecución :

Carga de memoria estática de más de 32 bytes solicitada.

¿El estándar Solidity establece en alguna parte que esto no es factible?

Gracias.

Hola. Un ejemplo de código sería genial para entenderlo fácilmente y ayudarlo
@GregJeanmart: necesitaría minimizar algunos 2 o 3 contratos y luego pegarlos aquí.
Puede publicar un enlace a una esencia en lugar de pegarlos directamente aquí.
@HarryWright: Gracias, pero he renunciado a la posibilidad de resolver el problema original (uso de la pila) pasando una estructura de almacenamiento por referencia, ya que parece no ser compatible con Solidity (bueno, solo es compatible con funciones internas de lo que Me he reunido hasta ahora, pero estoy haciendo llamadas de función entre contratos aquí).

Respuestas (2)

Instintivamente creo que la única solución es pasar la estructura a la función "por dirección"

No puede acceder a las direcciones físicas de las variables de almacenamiento (como puede hacerlo con C), esto no está permitido en Solidity. El tipo de dirección solo se usa para hacer referencia a las direcciones de otras cuentas (de contrato o externas), y no se usa para hacer referencia a las direcciones de memoria.

Una solución alternativa sería usar un contrato inteligente para almacenar sus datos en lugar de una estructura. De esta manera, podría pasar la dirección del contrato inteligente en lugar de tener que pasar los datos. He publicado un ejemplo a continuación:

contract Person {
    uint public age;
    uint public weight;

    function Person(uint _age, uint _weight) public {
        age = _age;
        weight = _weight;
    }
}

contract PersonHolder {

    address[] public people; // Could use Person[] here

    function addPerson(uint age, uint weight) public {
        people.push(new Person(age, weight));
    }

    function getPerson(uint index) public view returns (Person) {
        require(people.length > index);

        return Person(people[index]);
    }
}
Hmmm... reemplace el structcon un contract... Eso es interesante; Lo probaré, gracias!!!
PD: Para a struct, se "creó" implícitamente un constructor para mí. ¿Realmente necesito declararlo explícitamente si cambio a contract?
Sí, es correcto, deberá escribir un constructor para un contrato.
Bien, algunas notas para su solución (de trabajo): 1. Cuando realmente uso la instancia del contrato que se pasa a alguna función dada, necesito usar una función 'captador' en la variable a la que quiero acceder. Por ejemplo, supongamos que alguna función toma Person person, y quiero acceder a age, entonces necesito usar person.age(). Esto podría generar algún tipo de impacto en el tiempo de ejecución, que ahora necesito investigar. 2. El compilador me obliga a cambiar el modificador de función de purea view. ¿Alguna idea de por qué?
Una última pregunta: con respecto a una función que returns (Person): ¿devuelve una referencia a ese objeto en la peoplematriz, o devuelve una réplica del mismo (que supongo que produciría copiar el objeto original en la pila antes de invocar la función)? Dado que su solución revocó el Stack too deeperror que había recibido anteriormente, creo que el primero es correcto (es decir, el Personobjeto se devuelve por referencia ). ¿Alguna posibilidad de que puedas confirmar esto? ¡¡¡Gracias!!!
En términos de impacto en el tiempo de ejecución, el getter para las propiedades de la persona, por ejemplo, la edad, no costará gasolina, ya que es una llamada, no una transacción. Las funciones puras solo se pueden usar cuando no se lee el estado del contrato, las funciones de vista le permiten leer el estado del contrato. Cuando lo hago returns (Person), lo que en realidad estoy devolviendo es una dirección en forma de referencia de contrato. También podría hacerlo returns (address), pero necesitaría convertir la dirección como una referencia de contrato de Persona para acceder a sus métodos de forma nativa. Encantado de ayudarle :-)
Muy útil, gracias!!! Sin embargo, una pregunta "pegajosa" Pure functions can only be used when contract state is not read, pero este es el estado de un contrato diferente (es decir, no el contrato en el que reside la función). ¿Por qué no puede ser la función pureentonces? ¿No pureafirma que la función es "pura" sólo con respecto al contrato de "posesión"?
La documentación establece que una función pura no puede llamar a ninguna función no pura. La función getter generada para el otro contrato no es pura, creo que es por eso que no puede realizar esta operación.
La documentación establece que una función pura no puede llamar a ninguna función no pura. La función getter generada para el otro contrato no es pura, creo que es por eso que no puede realizar esta operación.
Me di cuenta de que su solución básicamente significa que crearé e implementaré muchos contratos. En mi caso específico, alrededor de 1100. En términos de "memoria", consumirá exactamente lo mismo que usar una matriz de estructuras. Pero, ¿estaré pagando una gran "penalización" por usar contratos en lugar de estructuras? Gracias.

Puede que realmente no entienda tu problema. Pero desde mi experiencia y muchas investigaciones en Internet:

  1. 1: Solidity no maneja muy bien (para desarrolladores) objetos de tamaño dinámico (como matrices, cadenas)
  2. 2: algunos tipos no se pueden devolver de una llamada de contrato

Por ejemplo, tengo un contrato que realiza una llamada a otro contrato, algunos tipos de variables no se pueden devolver de esta manera (pero sí con una llamada externa, como una llamada web3js). Esto incluye tipos "profundos", como estructuras.

Nota : esta no es una declaración oficial, solo algunas cosas que obtuve de la experiencia / lectura, si alguien tiene una documentación oficial, haga otra respuesta correcta :)

Mi matriz de estructuras no es dinámica: MyStruct[10][20] private myStructLists.
Sí, pero sus estructuras son demasiado "profundas" (además, están en una matriz, por lo que es aún más profunda :/)
Su respuesta me lleva a la conclusión de que necesitaría resolver el problema original ( Stack too deep, try removing local variables) usando un enfoque diferente. ¿Alguna idea además de lo obvio que se menciona explícitamente en este error?
No precisamente. Trato de simplificar y trabajar con los tipos más "básicos" cuando estoy codificando en solidez, así que evito estructuras, arreglos y esas cosas.
No cambia el resultado final del problema al que me enfrento. Puedo reducir esas estructuras y arreglos todo lo que quieras, pero en el fondo, tengo una función que toma algo así como 9 variables de tipo uint256y realiza llamadas a funciones internas, lo que eventualmente conduce a un uso de la pila por encima del límite permitido.
No puedo ayudarte más en eso, lo siento. Mi conocimiento no es fuerte. Solo trata de averiguarlo por ti mismo o espera a que alguien mejor que yo te proponga algo :)