Каковы распространенные ловушки или ограничения при программировании в Solidity?

О чем вы хотели бы предупредить других разработчиков?

Что работает на большинстве других языков, но не работает или ведет себя так, как ожидалось, в Solidity?

Только для примера: какие параметры можно передавать функциям, что можно возвращать из функций?

Ответы (6)

Объявление локального массива (или другого ссылочного типа ) и предположение, что он будет создан в памяти, но фактически перезапишет хранилище :

/// THIS CONTRACT CONTAINS AN ERROR
contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x;
        x.push(2);
        data = x;
    }
}

Тип локальной переменной x — uint[] storage, но поскольку хранилище не выделяется динамически, перед использованием его необходимо назначить из переменной состояния. Таким образом, для x не будет выделено место в памяти, а вместо этого он будет функционировать только как псевдоним для уже существующей переменной в памяти.

Что произойдет, так это то, что компилятор интерпретирует x как указатель хранилища и заставит его указывать на слот хранения 0 по умолчанию. Это приводит к тому, что параметр someVariable (находящийся в слоте хранения 0) модифицируется с помощью x.push(2).

Правильный способ сделать это следующий:

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x = data;
        x.push(2);
    }
}

OR

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] memory x = new uint[](1);
        x[0] = 2;
        data = x;
    }
}
Можете ли вы привести пример кода?
@JossieCalderon Хороший звонок, спасибо, надеюсь, стало намного понятнее.

Из документов

В for (var i = 0; i < arrayName.length; i++) { ... } тип i будет uint8, потому что это наименьший тип, необходимый для хранения значения 0. Если в массиве больше чем 255 элементов, цикл не завершится.

также

Пока нельзя использовать массивы массивов во внешних функциях. ... Вы можете использовать только один уровень динамических массивов [где угодно].

а также

Из-за ограничений EVM невозможно вернуть динамическое содержимое из вызовов внешних функций. Функция f в контракте C { function f() return (uint[]) { ... } } вернет что-то, если она вызывается из web3.js, но не из Solidity. Единственным обходным решением на данный момент является использование больших массивов статического размера.

  • Всегда предоставляйте достаточно газа для транзакции (90% ошибок новичков возникают из-за нехватки газа)
  • Исключения будут потреблять весь транзакционный газ (используйте с осторожностью)
  • Это не может быть легко проверено, если ваш контракт выдает исключение
  • Нелегко проверить, закончился ли газ в вашей транзакции.
  • Что-то может работать с тестовой сетью, но может не работать в частной тестовой сети (отметьте, чтобы это работало в обоих случаях)
  • Ограниченная поддержка строк без внешних библиотек.
  • Некоторые функции могут дать сбой (например, отправить), проверьте возвращаемое значение
  • Следите за проблемами повторного входа (особенно при отправке денег или других токенов)

string[] не разрешены в параметрах функции или возвращаемых значениях.

обратитесь к обсуждению здесь:
нельзя ли использовать массив строк в качестве аргумента функции прочности?

returnsс именованными выходными параметрами вводит новую локальную переменную.

Например, из этого вопроса :

contract Test {
    address owner;

    function Test(){
        owner = msg.sender;
    }

    function getOwner() returns (address owner) {
        return owner;
    }
}

Здесь вводится getOwnerновая переменная и инициализируется нулем. ownerПо совпадению он переопределяет переменную состояния owner, что приводит к неожиданному результату.


Сопоставления разрешены только для переменных состояния (или в качестве типов ссылок на хранилище во внутренних функциях).

Например, из этого вопроса :

function getBalance(address addr) returns (uint, uint) {
    mapping(address => uint)  balancers;
    balancers[msg.sender] = 500;

    return (balancesA[addr], balancesB[addr]);
}

Здесь mapping(address => uint) balancesне выделяется новое отображение, но вводится неинициализированная переменная. Следовательно, доступ balancers[msg.sender]недействителен.

  • Использование deleteв массиве оставляет зазор, поэтому вам нужно сместить элементы вручную и обновить свойство длины.

  • stringто же самое, bytesно не разрешает доступ к длине или индексу.

  • bytesто же самое, byte[]но упаковано плотно (дороже).

  • Суффиксы даты нельзя применять к переменным.

  • Solidity наследует правила области видимости от JavaScript; нет области видимости блока.

Чтобы узнать больше о солидности, посетите https://github.com/miguelmota/solidity-idiosyncrasies.