¿Por qué el gas requerido se estima infinito?

Tengo una advertencia de verificación de pelusa en Remix para mi contrato inteligente en Solidity:addFeature(int128,uint256,bool,uint256,uint256,uint16,uint16,address) high: infinite. If the gas requirement of a function is higher than the block gas limit, it cannot be executed. Please avoid loops in your functions or actions that modify large areas of storage (this includes clearing or copying arrays in storage)

Featurees una estructura con muchos campos:

struct Feature {
    int128 key;
    uint256 goal;
    bool finishOnGoal;
    uint campaignStart; // timestamp
    uint campaignFinish; // timestamp

    PledgeType pledgeType; // enum
    FixedPledge fixedPledge; // description for enum value #1
    VariablePledge variablePledge; // description for enum value #2

    PrepaymentType prepaymentType; // enum
    FixedPrepayment fixedPrepayment; // description for enum value #1
    PercentPrepayment percentPrepayment; // description for enum value #2

    uint16 maxDevelopmentDelay; // days
    uint16 developmentDuration; // days

    ConfirmationType confirmationType; // enum
    UserConfirmation userConfirmation; // description for enum value #1

    address developer;
}

...

// featureKey => feature
mapping (int128 => Feature) features;

// featureKey => feature
mapping (int128 => FeatureData) data;

...

// common feature data
function addFeature(
    int128 key,
    uint256 goal,
    bool finishOnGoal,
    uint campaignStart,  // timestamp
    uint campaignFinish, // timestamp
    uint16 maxDevelopmentDelay,
    uint16 developmentDuration,
    address developer) public
    ownerOnly
    withState(key, State.NotSet)
{
    Feature memory feature;
    feature.key = key;
    feature.goal = goal;
    feature.finishOnGoal = finishOnGoal;
    feature.campaignStart = campaignStart;
    feature.campaignFinish = campaignFinish;
    feature.maxDevelopmentDelay = maxDevelopmentDelay;
    feature.developmentDuration = developmentDuration;
    feature.developer = developer;

    FeatureData memory featureData;
    featureData.state = State.Deployment;
    featureData.backers = new address[](0);
    featureData.raised = 0;
    featureData.prepaid = 0;

    features[key] = feature;
    data[key] = featureData;
}

¿Por qué tengo esta advertencia? ¿Qué se puede/debe cambiar para solucionarlo (sin perder funcionalidad)? AFAIK no hay modificaciones de bucles ni matrices aquí ( solo mapas ).

No ha compartido suficiente código para intentar reproducir la advertencia, pero hubiera esperado que no se pudiera compilar... No estoy seguro de cómo se supone que se debe copiar en la FeatureDatamemoria en el almacenamiento debido a la backersmatriz de tamaño dinámico . ¿Podría compartir suficiente código para que sea posible compilar esto?
aunque realmente no siento que la descripción de los campos de estructura sea útil aquí, actualicé el código fuente en la pregunta
Este código aún no se puede compilar. No quiero tratar de inventar definiciones de todos los diferentes tipos. Comparta algún código fuente compilable que reproduzca el problema. Una forma de hacerlo sería compartir todo su código. Otra forma (¡mejor!) de hacerlo sería recortar el código hasta que sea mínimo pero aún reproduzca el problema. Por ejemplo, elimine la mayoría de los campos y vea si aún puede activar la advertencia.

Respuestas (1)

Aquí hay un contrato mínimo que muestra el problema:

pragma solidity ^0.4.24;

contract Test {
    mapping (uint128 => address[]) data;

    function addFeature() public {
        data[0] = new address[](0);
    }
}

Puede verificar que este es el problema que tiene al deshacerse del address[]campo FeatureDatay verificar si aún obtiene una estimación de gas infinita.

Creo que el problema es que el análisis estático no es lo suficientemente sofisticado como para saber que la matriz que está copiando siempre tiene una longitud de 0. Solo ve que una matriz debe copiarse de la memoria al almacenamiento y no puede hacer una buena estimación de gas. .

Dicho esto, el código simple anterior tiene un costo de gasolina aproximadamente fijo, por lo que es seguro ignorar la advertencia. Si verifica que el mismo problema está causando la advertencia en su código, creo que también puede ignorarlo.

Si desea deshacerse de la advertencia, puede escribir este código en su lugar. Sospecho que esto es más eficiente en gas de todos modos:

FeatureData storage featureData = data[key];
featureData.state = State.Deployment;
featureData.backers.length = 0;
featureData.raised = 0;
featureData.prepaid = 0;
Creo que "el análisis estático no es lo suficientemente sofisticado" es la respuesta y es un falso positivo en mi caso. @smarx muchas gracias por el ejemplo de código purificado