Почему простая функция, возвращающая «строку», вызывает другой контракт?

Этот тривиальный контракт:

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

В результате вывод ассемблерного кода (в веб-компиляторе Solidity) для функции 'test' выглядит следующим образом:

   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

Я вижу, что шестнадцатеричная версия строки и ее длина записываются в память довольно рано. Затем он делает много странных вещей и, насколько я могу судить, выдает ЗВОНОК с очень небольшим количеством газа по адресу «4». В желтой книге Ethereum говорится, что контракт по адресу 4 реализует функцию идентификации, которую в данном контексте кажется совершенно бессмысленной.

Почему он делает это для того, что выглядит очень простым «возвратом»?

Интересно, использование функции идентификации в дикой природе... ethereum.stackexchange.com/q/441/42

Ответы (2)

При обсуждении с разработчиками Solidity на Gitter становится ясно: Solidity использует функцию идентификации как дешевую memcpyоперацию, а оптимизатор в настоящее время недостаточно умен, чтобы понять, что он может просто загрузить строковый литерал в память как полноту возвращаемое значение. Таким образом, он загружает строку в память, использует функцию идентификации для memcpy в место возврата, а затем возвращает ее.

Ассемблерный код включает в себя все функции, необходимые для создания контракта, одной из которых является идентификация, т. е. контракт должен быть идентифицируемым. Фактическая функция «тест» не использует все функции ассемблерного кода.

Контракт идентичности предназначен не для идентификации вещей; это контракт, который реализует функцию идентификации — он буквально производит тот же результат, что и ввод. И да, он является частью исполняемого байт-кода; Я удалил (небольшой) заголовок/конструктор развертывания из сгенерированной сборки.