Error de compilación de pila demasiado profunda, pero ¿la función solo tiene 5 parámetros?

Tengo una función, que se muestra en su totalidad a continuación, que obtiene el temido error del compilador "stack too deep". He leído varias de las otras publicaciones en este foro sobre este error, pero todas lo atribuyen a pasar demasiados parámetros a la función. Como puede ver a continuación, solo tengo 5 parámetros de método. He marcado la línea que el compilador a través de Remix marca con el error "stack too deep".

¿Por qué recibo este error y cómo puedo solucionarlo?:

/**
 * @notice Make payments to the bands and players by calculating and then storing
 *  the amount due them in the claims map.  For bands that we don't find an
 *  address for in the band addresses array, put the amount in escrow 
 *  for them, using the owner ID associated with a given ID as the escrow 
 *  key.
 * 
 * NOTE: All the array must be of the same length and are to be greated as 
 *  "columns" of a table where each array element at the same index is
 *   onefield value in the row.
 * 
 * @param _aryVideoIds - An array of the video IDs that were used in the 
 *  game.
 * @param _aryOwnerIds - An array of the entities that own each of the 
 *  videos.  For example, a channel ID for a YouTube video if this game was 
 *  played using YouTube videos, where the channel belongs to the band that 
 *  owns or made the video.
 * @param _aryWinnerAddr - an array of the winners from each round of 
 *  game play.  Each winner in a row won the round the video ID for the video 
 *  in the same row of the table.
 * @param _aryBandAddr - an array of the addresses for each band that 
 *  was involved in the game.  Each address corresponds to the band who the 
 *  video belongs to.
 */
function makePayments(
        uint256 _gameId, 
        bytes32[] _aryVideoIds, 
        bytes32[] _aryOwnerIds,
        address[] _aryWinnerAddr,
        address[] _aryBandAddr
    )
        public payable 
        onlyIfValidGameId(_gameId) onlyIfHouseAddr(_gameId) onlyIfPlayingState(_gameId) {
    // The arrays all must have the same length and that length must be non-zero.
    require(_aryVideoIds.length > 0, "(makePayments) The video ID array is empty.");
    require(_aryVideoIds.length == _aryOwnerIds.length && _aryOwnerIds.length == _aryWinnerAddr.length && _aryWinnerAddr.length == _aryBandAddr.length,
        "(makePayments) One or more of the given arrays is not the same length.");

    // Change the game to the GAME OVER state or several of the payment function 
    //  calls below will fail because they require the game to be in the game over 
    //  state.
    // --------->>>>>>>> STACK TOO DEEP ERROR OCCURS HERE.
    s_mapGameIdToGame[_gameId].gameState = enGameState.GAME_OVER;

    uint256 numVideos = _aryVideoIds.length;

    // Calculate the amount due the house.
    uint256 housePayment = s_mapGameIdToGame[_gameId].gameBalance.div(100).mul(pct_house);

    // Calculate the remaining funds after removing the house percentage.
    uint256 remainder = s_mapGameIdToGame[_gameId].gameBalance - housePayment;

    require(remainder > 0, "(makePayments) The game balance after removing the house percentage is 0 or less.");

    uint256 bandPaymentPool = 0;
    uint256 perBandPayment = 0;
    uint256 playerPaymentPool = 0;
    uint256 perVideoPayment = 0;

    // Calculate the amount of money to be distributed to the bands and the players.
    if (s_mapGameIdToGame[_gameId].bandDonationPercent == 0)
    {
        // Everything goes to the players.
        playerPaymentPool = remainder;
        perVideoPayment = playerPaymentPool.div(numVideos);
    } 
    else if (s_mapGameIdToGame[_gameId].bandDonationPercent == 100)
    {
        // Everything goes to the bands.
        bandPaymentPool = remainder;
        perBandPayment = bandPaymentPool.div(numVideos);
    }
    else
    {
        // Split the remainder between the players and the bands according to the 
        //  band donation percentage.
        bandPaymentPool = remainder.div(100).mul(s_mapGameIdToGame[_gameId].bandDonationPercent);

        // The band payment pool is distributed evenly across the number of participating bands.
        perBandPayment = bandPaymentPool.div(numVideos);

        // Calculate the amount of funds to distributed across the players.
        playerPaymentPool = remainder.sub(bandPaymentPool);

        // The per player payment is based on the number of games each player won.  However,
        //  the amount paid for each video is based on the number of videos in the game.
        perVideoPayment = playerPaymentPool.div(numVideos);
    }

    // Watch out for having no payments at all to make.
    require(perBandPayment == 0 && perVideoPayment == 0, "(makePayments) There are no payments to be made for this game, given the current amounts.");

    // Process the band payments if we have any.
    if (perBandPayment > 0)
    {
        processBandPayments(_gameId, _aryOwnerIds, _aryBandAddr, perBandPayment);
    }

    if (perVideoPayment > 0)
    {
        // Process the player payments.
        processPlayerPayments(_gameId, _aryWinnerAddr, perVideoPayment);
    }
}

Respuestas (3)

Bueno, tienes 12 variables en función ya que los parámetros y los valores devueltos también se agregan a la pila. Creo que los parámetros modificadores también están incluidos, como puede ver aquí . Entonces, dependiendo de lo que haya en los modificadores, puede exceder el límite.

eche un vistazo a mi auto-respuesta en cuanto a lo que eliminó el error. Me gustaría sus comentarios si usted está tan inclinado.

Estoy publicando una respuesta a esto en caso de que ayude a alguien más. Tenga en cuenta que no he realizado pruebas exhaustivas y cuidadosas para ver los detalles reales y las ramificaciones de esta corrección.

Resulta que fue un problema extraño con el encadenamiento de operaciones de SafeMath en una sola línea. No digo que sea un problema con SafeMath (una biblioteca fantástica) . Solo estoy señalando la línea que cambié y, al hacerlo, me deshice del problema. Mi conjetura sin educación en este punto sobre cuál es el problema, es que puede ser un problema del compilador de Solidity.

Esta es la línea original según mi publicación original:

// Calculate the amount due the house.
uint256 housePayment = s_mapGameIdToGame[_gameId].gameBalance.div(100).mul(pct_house);

Aquí está mi refactorización de esa línea donde todo lo que hice fue dividir las operaciones aritméticas en líneas de código separadas:

uint256 gameBalance = s_mapGameIdToGame[_gameId].gameBalance;
uint256 gameBalanceTemp = gameBalance.mul(pct_house);
uint256 housePayment = gameBalanceTemp.div(100);

Después de hacer esto, el error "pila demasiado profunda" desapareció. Su experiencia puede ser diferente.

Puede estar relacionado con el hecho de que está pasando matrices de tamaño variable. Dado que el compilador no sabe qué tamaño se espera, solo puede asignar un tamaño arbitrario para esa variable, lo que genera el mismo error que se ve cuando se pasan demasiados parámetros. Editar (se agregaron algunas sugerencias): puede solucionar este problema de la siguiente manera:

  • Dividir la función problemática en múltiples funciones
eche un vistazo a mi auto-respuesta en cuanto a lo que eliminó el error. Me gustaría sus comentarios si usted está tan inclinado.
Las matrices se pasan por referencia, no por valor.