Почему требуемый газ оценивается как бесконечный?

У меня есть предупреждение о проверке ворса в Remix для моего смарт-контракта в 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)

Featureпредставляет собой структуру с множеством полей:

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;
}

Почему у меня это предупреждение? Что можно/нужно изменить, чтобы это исправить (без потери функциональности)? Насколько я знаю, здесь нет ни циклов, ни модификаций массивов ( только карты ).

Вы не предоставили достаточно кода, чтобы попытаться воспроизвести предупреждение, но я ожидал, что это не удастся скомпилировать... Я не уверен, как в памяти FeatureDataпредполагается копировать в хранилище из-за backersмассива с динамическим размером . Не могли бы вы поделиться достаточным количеством кода, чтобы это можно было скомпилировать?
хотя я действительно не считаю, что описание полей структуры здесь полезно, я обновил исходный код в вопросе
Этот код все еще не может быть скомпилирован. Я не хочу пытаться составить определения всех различных типов. Поделитесь компилируемым исходным кодом, который воспроизводит проблему. Один из способов сделать это — поделиться всем своим кодом. Другой (лучший!) способ сделать это - урезать код до минимального, но все еще воспроизводит проблему. Например, удалите большинство полей и посмотрите, сможете ли вы по-прежнему вызывать предупреждение.

Ответы (1)

Вот минимальный контракт, демонстрирующий проблему:

pragma solidity ^0.4.24;

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

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

Вы можете убедиться, что это проблема, с которой вы столкнулись, избавившись от поля address[]и FeatureDataпроверив, получаете ли вы по-прежнему оценку бесконечного газа.

Я считаю, что проблема в том, что статический анализ недостаточно сложен, чтобы знать, что массив, который вы копируете, всегда имеет длину 0. Он просто видит, что массив необходимо скопировать из памяти в хранилище, и не может сделать хорошую оценку газа. .

Тем не менее, приведенный выше простой код имеет примерно фиксированную стоимость газа, поэтому предупреждение можно игнорировать. Если вы подтвердите, что та же проблема вызывает предупреждение в вашем коде, я считаю, что вам также безопасно игнорировать его.

Если вы хотите избавиться от предупреждения, вы можете вместо этого написать этот код. Я подозреваю, что в любом случае это более эффективно с точки зрения газа:

FeatureData storage featureData = data[key];
featureData.state = State.Deployment;
featureData.backers.length = 0;
featureData.raised = 0;
featureData.prepaid = 0;
я считаю, что «статический анализ недостаточно сложен» - это ответ, и в моем случае он ложноположительный. @smarx большое спасибо за очищенный пример кода