¿Cómo obtener el valor de retorno de un contrato de una llamada de contrato?

Si un contrato devuelve algo, (ya sea una cadena o return true/return false) ¿cómo obtener su valor de retorno?
Quiero decir, ¿dónde se almacena el valor de retorno? ¿Es necesario usar RETURNDATACOPYo el valor está en la pila en el caso de return true/return false ? Si está en la pila, ¿cómo saber si el contrato salió debido a un problema en la ejecución (como reversión o falta de gasolina) o porque la ejecución tuvo éxito al devolver falso?

Por supuesto, estoy hablando mientras conozco el sitio o el tipo de valor devuelto, por lo que RETURNDATASIZEno es necesario utilizarlo. No quiero una respuesta de Solidity o Vyper, sino saber cómo funcionan las cosas a bajo nivel.

Respuestas (1)

Hay un montón de preguntas aquí que intentaré desempacar.

1. ¿Cómo obtener su valor de retorno?

Cuando un contrato termina en la EVM, tiene un estado de detención, denotado H. Este estado de parada toma tres valores posibles:

  • ()cuando la ejecución debe detenerse sin valor de retorno
  • el conjunto vacío, llamémoslo Nonecuando la ejecución deba continuar
  • o una lista de dos números (offset, length)que corresponden a un valor de retorno

La convención es que offsetcorresponda lengtha los bytes en la memoria mem[offset, offset + length - 1]correspondientes a los datos de retorno.

2. ¿Dónde se almacena el valor devuelto?

Sin embargo, su pregunta es ¿cómo llegan allí los datos de retorno? Bueno, típicamente el contrato compilado llenará la memoria de la máquina con los datos requeridos antes de la terminación.

3. ¿Es necesario utilizar RETURNDATACOPY?

RETURNDATACOPYes en realidad para el caso especial en el que un contrato llama a otro y necesita recopilar los datos de devolución de ese otro contrato. Conceptualmente, cuando se llama a otro contrato, el contrato principal puede acceder a los datos de devolución en una variable llamada outputo mu_oen notación de papel amarillo.

El objetivo de RETURNDATACOPYes copiar datos desde mu_ola memoria actual mu_mpara que puedan ser devueltos.

4. Si está en la pila, ¿cómo saber si el contrato salió por un problema en la ejecución?

Entonces, como se discutió anteriormente, los datos de devolución se almacenan en la memoria antes de detener el contrato. Hay otras formas de entender cómo se detuvo el contrato, en particular el estado de detención, la función de detención excepcional y otras.

5. ¿Dónde se devuelven los datos después de la llamada al contrato principal?

En memoria. Este es un extracto de la definición de CALLen el papel amarillo.

Extracto de la definición de CALL

Como puede ver, los datos de salida se guardan en la memoria y luego mu_ose introducen como una abreviatura/puntero a esa parte en la memoria.

Sí, ya sé que el RETURNcódigo de operación lee datos de la memoria... Pero mi pregunta es ¿dónde están los datos después de que la llamada se devuelva al contrato principal?
En memoria. He editado la respuesta para mostrar eso. En particular, cuando ejecuta CALL, especifica dónde exactamente en la memoria se escribirán los datos de retorno.
¿Incluso para un simple valor de retorno verdadero/falso?
¡Sí, de hecho! EVM no distingue en términos de simplicidad.
Y si se empuja cero en la pila, ¿entonces la ejecución del contrato se revirtió por algún motivo? ¿no es así?
Bueno, 0 es lo mismo que falso en EVM, por lo que es un valor de retorno válido. La reversión ocurre cuando se usa el REVERTcódigo de operación.
No, lo siento, me refería a la devolución inmediatamente después del final de la llamada. Y por alguna razón, me refería a algo así como REVERTsin gasolina o desbordamiento de la pila.