Стек слишком глубокий | Использовать массив памяти для хранения множества «локальных» переменных?

У меня есть контракт, который выполняет довольно сложные вычисления с некоторыми промежуточными вычислениями, и я сталкиваюсь с проблемой «слишком глубокого стека».

Я попытался использовать массив памяти внутри функции для сохранения временных «локальных переменных» вместо создания новых локальных переменных.

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

function usingLocalVars() {
  // Get 3 uint values from a getter function call from another contract
  // and save as local variables uint a, uint b, uint c:
  var(a, b, c) = otherContract.getter(param);

  // Perform some computation an a, b, and c and save as another variable d
  uint d = someOperation(a, b, c);

  /** other code with a return **/

}

Переписано с использованием массива памяти:

function usingMemoryArray() {
  // Get 3 uint values from a getter function call from another contract
  // and store into memory array temp:

  // create memory array
  uint[4] memory temp;

  // save values into memory array
  (temp[0], temp[1], temp[2]) = otherContract.getter(param);

  // Perform some computation an a, b, and c and save into temp[3]
  temp[3] = someOperation(temp[0], temp[1], temp[2]);

  /** other code with a return **/
}

Итак, что я пытался сделать:

  1. Удалите почти все локальные переменные, выполнив вышеуказанное (массив памяти)
  2. Удалены все именованные возвращаемые переменные, т.е. returns (uint x, uint y, uint z)=>returns (uint, uint, uint)

Текущая сводка функций:

  • 1x входной параметр функции
  • массив памяти длиной 17 (все мои "временные" переменные)
  • 1x intлокальная переменная
  • Функция вызывает некоторые другие методы в рамках контракта (например, someOperation()) выше. Может ли это быть еще одной причиной этой проблемы? Необходимо ограничить локальную переменную, используемую в вызовах других методов (например, someOperation())?

Действительно ли использование массива памяти, как я упоминал выше, помогает решить эту проблему (слишком глубокий стек)?

Являются ли какие-либо вызовы функций рекурсивными? Я считаю, что в EVM это сообщение об ошибке может появиться из-за традиционных проблем типа «ваш стек вызовов слишком глубок», а также из-за помещения слишком большого количества значений в стек. Вы, кажется, взялись только за последнее.
Спасибо. Ни один из вызовов функций не является рекурсивным, и нет зацикливания. В основном вызовы функций являются просто геттерами, а также чистыми функциями.
Интересный. Есть ли шанс, что вы можете поделиться своим кодом, чтобы я мог попытаться воспроизвести проблему?
У меня слишком много проблем с запуском ваших тестов. :-) Пробовали ли вы удалять различные части функции? Например, удалить регистрацию событий и посмотреть, работает ли что-то? (Событие принимает довольно много параметров.)
Спасибо за попытку! Да, в коде много чего происходит. ОК, похоже, что мое назначение массива памяти: (temp[0]...) = getter() ограничено 8 элементами, где у меня изначально было 9. Изолируя это, работает с 8 (по крайней мере, этот бит кода), терпит неудачу с 9, так что посмотрим, решит ли это настройку.

Ответы (2)

Таким образом, мои назначения временных переменных вызывали проблему. Это работает, если ограничиться 8 заданиями одновременно:

Это не удается (9 присвоений переменных):

(temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6], temp[7], temp[8]) = (1, 2, 3, 4, 5, 6, 7, 8, 9);

Но это работает (8 заданий одновременно ):

(temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6], temp[7]) = (1, 2, 3, 4, 5, 6, 7, 8);
(temp[8], temp[9], temp[10], temp[11], temp[12], temp[13], temp[14], temp[15]) = (9, 10, 11, 12, 13, 14, 15, 16);

Кроме того, использование массива памяти позволяет избежать слишком глубокого стека локальных переменных .

Возможно, вы пробовали это, но некоторые отладки в Remix с пустыми getter()и someOperation()функциями, которые просто возвращают значения, показывают, что максимальная глубина стека достигает 12 элементов, когда я использую первый метод, и только 9 для второго. Мне еще предстоит полностью понять различия, но рассмотрите возможность использования ремикса и проверки экрана отладки, если вы еще этого не сделали.

введите описание изображения здесь

Спасибо, это отличное предложение. Я использую ремиксы, но еще не проверял.