Pila demasiado profunda | ¿Usar matriz de memoria para almacenar muchas variables "locales"?

Tengo un contrato que está haciendo un cálculo bastante complejo con algunos cálculos intermedios, y me encuentro con el problema de "pila demasiado profunda".

Intenté usar una matriz de memoria dentro de la función para guardar "variables locales" temporales en lugar de crear nuevas variables locales.

Por ejemplo, en lugar de:

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 **/

}

Reescrito usando matriz de memoria:

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 **/
}

Entonces, lo que he intentado hacer:

  1. Elimine casi todas las variables locales haciendo lo anterior (matriz de memoria)
  2. Se eliminaron todas las variables de retorno con nombre, es decir, returns (uint x, uint y, uint z)=>returns (uint, uint, uint)

Resumen de la función actual:

  • 1 parámetro de entrada de función
  • matriz de memoria de longitud 17 (todas mis variables "temp")
  • 1x intvariable local
  • La función llama a algunos otros métodos dentro del contrato (como someOperation()) arriba. ¿Sería esto potencialmente otra causa de este problema? ¿ Necesita limitar el var local utilizado en otras llamadas a métodos (por ejemplo, someOperation())?

¿El uso de una matriz de memoria como mencioné anteriormente realmente ayuda con este problema (la pila es demasiado profunda)?

¿Alguna de las llamadas a funciones es recursiva? Creo que en el EVM, ese mensaje de error puede provenir del tipo de problema tradicional "su pila de llamadas es demasiado profunda", así como también empujar demasiados valores en la pila. Parece que solo has abordado lo último.
Gracias. Ninguna de las llamadas a funciones es recursiva y no hay bucles. Básicamente, las llamadas a funciones son solo captadores y funciones puras.
Interesante. ¿Hay alguna posibilidad de que pueda compartir su código para que pueda intentar reproducir el problema?
Tengo demasiados problemas para intentar que se ejecuten las pruebas. :-) ¿Ha intentado eliminar varias piezas de la función? Por ejemplo, ¿eliminar el registro de eventos y ver si las cosas funcionan entonces? (El evento toma bastantes parámetros).
¡Gracias por intentarlo! Sí, están sucediendo muchas cosas en el código. OK, parece que mi asignación de matriz de memoria: (temp[0]...) = getter() está limitada a 8 elementos, donde originalmente tenía 9. Aislar eso, funciona con 8 (al menos ese bit de código), falla con 9, así que veremos si ajustando con eso se resuelve.

Respuestas (2)

Entonces mis asignaciones de variables temporales estaban causando el problema. Funciona si se limita a 8 asignaciones a la vez:

Esto falla (9 asignaciones de variables):

(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);

Pero esto funciona (8 asignaciones a la vez ):

(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);

Y también, el uso de la matriz de memoria evita el problema de la pila demasiado profunda de las variables locales .

Tal vez haya intentado esto, pero algunas depuraciones en Remix con funciones vacías getter()y someOperation()que solo devuelven valores muestran que la profundidad máxima de la pila alcanza los 12 elementos cuando uso el primer método, pero solo 9 para el segundo. Todavía tengo que entender completamente las diferencias, pero considere usar remix y verificar la pantalla de depuración para ayudar si aún no lo ha hecho.

ingrese la descripción de la imagen aquí

Gracias, es una gran sugerencia. Yo uso remix pero no lo había comprobado todavía.