¿Por qué una función simple que devuelve una 'cadena' llama a otro contrato?

Este contrato trivial:

contract Test {
    function test() returns (string) {
        return "foobar";
    }
}

Da como resultado una salida de código ensamblador (en el compilador web solidity) para la función 'prueba' que se ve así:

   tag 2            function test() returns (strin...
      JUMPDEST          function test() returns (strin...
      PUSH 0            contract Test {\n    function ...
      PUSH 60           contract Test {\n    function ...
      MSTORE            string
      PUSH C0           return "foobar"
      PUSH 40           contract Test {\n    function ...
      MSTORE            return "foobar"
      PUSH 6            return "foobar"
      PUSH 80           string
      SWAP1             return "foobar"
      DUP2          return "foobar"
      MSTORE            return "foobar"
      PUSH 666F6F6261720000000000000000000000000000000000000000000000000000         return "foobar"
      PUSH A0           return "foobar"
      MSTORE            return "foobar"
      PUSH 20           string
      PUSH C0           return "foobar"
      SWAP1             function test() returns (strin...
      DUP2          function test() returns (strin...
      MSTORE            function test() returns (strin...
      PUSH 6            return "foobar"
      PUSH E0           function test() returns (strin...
      DUP2          function test() returns (strin...
      SWAP1             function test() returns (strin...
      MSTORE            function test() returns (strin...
      DUP2          return "foobar"
      SWAP1             return "foobar"
      PUSH 100          function test() returns (strin...
      SWAP1             function test() returns (strin...
      PUSH A0           return "foobar"
      SWAP1             return "foobar"
      DUP1          return "foobar"
      DUP4          function test() returns (strin...
      DUP2          return "foobar"
      DUP5          return "foobar"
      PUSH 0            contract Test {\n    function ...
      PUSH 4            function test() returns (strin...
      PUSH 12           function test() returns (strin...
      CALL          function test() returns (strin...
      POP           
      POP           
      DUP2          function test() returns (strin...
      MLOAD             function test() returns (strin...
      PUSH FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF         
      NOT           
      AND           function test() returns (strin...
      SWAP1             function test() returns (strin...
      SWAP2             function test() returns (strin...
      MSTORE            function test() returns (strin...
      POP           
      POP           
      PUSH 40           contract Test {\n    function ...
      MLOAD             function test() returns (strin...
      PUSH 120          function test() returns (strin...
      DUP2          function test() returns (strin...
      SWAP1             function test() returns (strin...
      SUB           function test() returns (strin...
      SWAP3             function test() returns (strin...
      POP           
      SWAP1             function test() returns (strin...
      POP           
      RETURN

Puedo ver que la versión hexadecimal de la cadena y su longitud se escriben en la memoria desde el principio. Luego hace un montón de cosas raras y emite una LLAMADA con muy poca gasolina para dirigirse a '4', por lo que puedo decir. El documento amarillo de Ethereum dice que el contrato en la dirección 4 implementa la función de identidad, lo que parece algo completamente inútil en este contexto.

¿Por qué está haciendo esto para lo que parece un 'retorno' muy sencillo?

Interesante, un uso de la función de identidad en la naturaleza... ethereum.stackexchange.com/q/441/42

Respuestas (2)

Al discutir con los desarrolladores de Solidity en Gitter, esto queda claro: Solidity usa la función de identidad como una operación barata memcpy, y el optimizador no es lo suficientemente inteligente actualmente como para darse cuenta de que solo puede cargar la cadena literal en la memoria como la totalidad de la valor de retorno Por lo tanto, carga la cadena en la memoria, usa la función de identidad para copiarla en la ubicación de retorno y luego la devuelve.

El código ensamblador incluye todas las funciones requeridas para crear el contrato de las cuales la identificación es una, es decir, el contrato tiene que ser identificable. La función de 'prueba' real no usa todas las funciones en el código ensamblador.

El contrato de identidad no es para identificar cosas; es un contrato que implementa la función de identidad: literalmente produce el mismo resultado que su entrada. Y sí, forma parte del bytecode ejecutado; Eliminé el (pequeño) encabezado/constructor de implementación del ensamblaje generado.