`external` vs` public` лучшие практики

Помимо модификатора public Ethereum вводит external. Оба они могут быть выведены за пределы контракта и внутри (более поздний по шаблону this.f ()). Кроме того, согласно документам :

  

Внешние функции иногда более эффективны, когда они получают   большие массивы данных.

, но нет никакой дополнительной информации о том, что действительно означает sometimes, и если это усиление эффективности сохраняется и для внутренних вызовов.

Каковы наилучшие методы использования ключевого слова external vs public? Существуют ли какие-либо образцы или рекомендации?

65 голосов | спросил Jakub Wojciechowski 4 J000000Tuesday17 2017, 13:58:47

2 ответа


96

Простой пример, демонстрирующий этот эффект, выглядит следующим образом:

pragma solidity^0.4.12;

contract Test {
    function test(uint[20] a) public returns (uint){
         return a[10]*2;
    }

    function test2(uint[20] a) external returns (uint){
         return a[10]*2;
    }
}

Вызывая каждую функцию, мы видим, что функция public использует 496 газа, а функция external использует только 261.

Разница заключается в том, что в публичных функциях Solidity немедленно копирует аргументы массива в память, а внешние функции могут читать непосредственно из calldata. Распределение памяти дорого, тогда как чтение из calldata дешево.

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

Для внешних функций компилятору не нужно разрешать внутренние вызовы, и поэтому он позволяет считывать аргументы непосредственно из calldata, сохраняя шаг копирования.

Что касается лучших практик, вы должны использовать external, если вы ожидаете, что функция будет только когда-либо вызвана извне, и используйте public, если вам нужно вызвать функцию внутри , Практически никогда не имеет смысла использовать шаблон this.f(), так как для этого требуется реальный CALL, что дорого. Кроме того, передача массивов с помощью этого метода была бы намного дороже, чем передача их внутренне.

По существу вы увидите преимущества производительности с external в любое время, когда вы только вызываете функцию извне и передаете большие массивы.

Примеры для дифференциации:

public - все могут получить доступ к

внешний - Нельзя получить доступ внутренне, только внешне

внутренний - только этот контракт и контракты, вытекающие из него, могут получить доступ к

private - доступен только из этого договора

ответил Tjaden Hess 4 J000000Tuesday17 2017, 16:32:47
0

Реструктуризация ответа выше для ясности:

pragma solidity^0.4.12;

contract Test {

    /*
    Cost: 496 Gas 
    This can be called internally or externally
    Since internal calls expects function arguements to be allocated to memory, solidity immediately
    copies array arguments to memory (This is what cost the additional gas.) 
    */
    function test(uint[20] a) public returns (uint) {
        return a[10] * 2;
    }

    /*
    Cost: Gas 261
    Doesnt allow internal calls, read directly from CALLDATA saving on the copying step(memory allocation).
    */
    function test(uint[20] a) external returns (uint) {
        return a[10] * 2;
    }


    /*
     Executed via JUMPs in code, array arguments are passed internally by pointers to memmory
      Function expects argument to be located in memory. 
     */
    function test(uint[20] a) internal returns (uint) {
        return a[10] * 2;
    }
}
  • Внутренние вызовы являются самыми дешевыми, поскольку они выполняются с помощью кода JUMP, передавая указатели в память.
  • Внутренние вызовы для публичных функций дороги, потому что внутренние вызовы функций ожидают, что аргументы будут выделены в память, поскольку публичная функция не знает, является ли вызов внешним или внутренним, он копирует аргументы в память и, следовательно, дороже.
  • Если вы знаете, что функция будет вызвана извне, используйте external

  • Практически никогда не имеет смысла использовать шаблон this.f (), поскольку для этого требуется выполнение реального CALL, что дорого.

ответил Shivam Sinha 30 J000000Monday18 2018, 01:18:20

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132