Warum wird der Gasbedarf als unendlich geschätzt?

Ich habe eine Flusenprüfungswarnung in Remix für meinen Smart Contract in 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)

Featureist eine Struktur mit vielen Feldern:

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

Warum habe ich diese Warnung? Was kann / sollte geändert werden, um das Problem zu beheben (ohne die Funktionalität zu verlieren)? AFAIK gibt es hier weder Schleifen- noch Array- Modifikationen ( nur Karten ).

Sie haben nicht genug Code geteilt, um zu versuchen, die Warnung zu reproduzieren, aber ich hätte erwartet, dass dies nicht kompiliert werden kann ... Ich bin mir nicht sicher, wie ein FeatureDataIn-Memory aufgrund des backersArrays mit dynamischer Größe in den Speicher kopiert werden soll . Könnten Sie genug Code teilen, damit es möglich ist, dies zu kompilieren?
Obwohl ich nicht wirklich der Meinung bin, dass die Beschreibung von Struct-Feldern hier hilfreich ist, habe ich den Quellcode in der Frage aktualisiert
Dieser Code kann immer noch nicht kompiliert werden. Ich möchte nicht versuchen, Definitionen für all die verschiedenen Typen zu erfinden. Geben Sie einen kompilierbaren Quellcode frei, der das Problem reproduziert. Eine Möglichkeit, dies zu tun, wäre, Ihren gesamten Code zu teilen. Eine andere (bessere!) Möglichkeit wäre, den Code zu kürzen, bis er minimal ist, aber das Problem immer noch reproduziert. Löschen Sie zB die meisten Felder und prüfen Sie, ob Sie die Warnung noch auslösen können.

Antworten (1)

Hier ist ein Minimalvertrag, der das Problem zeigt:

pragma solidity ^0.4.24;

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

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

address[]Sie können überprüfen, ob dies das Problem ist, das Sie haben, indem Sie das Feld aus entfernen FeatureDataund prüfen, ob Sie immer noch eine unendliche Gasschätzung erhalten.

Ich glaube , das Problem ist, dass die statische Analyse nicht ausgefeilt genug ist, um zu wissen, dass das Array, das Sie kopieren, immer die Länge 0 hat. Es sieht nur, dass ein Array vom Speicher in den Speicher kopiert werden muss, und kann keine gute Gasschätzung vornehmen .

Der obige einfache Code hat jedoch ungefähr feste Benzinkosten, sodass die Warnung sicher ignoriert werden kann. Wenn Sie überprüfen, dass das gleiche Problem die Warnung in Ihrem Code verursacht, können Sie sie meiner Meinung nach auch ignorieren.

Wenn Sie die Warnung loswerden möchten, können Sie stattdessen diesen Code schreiben. Ich vermute, dass dies sowieso gaseffizienter ist:

FeatureData storage featureData = data[key];
featureData.state = State.Deployment;
featureData.backers.length = 0;
featureData.raised = 0;
featureData.prepaid = 0;
Ich glaube, "statische Analyse ist nicht ausgefeilt genug" ist die Antwort und in meinem Fall ist sie falsch positiv. @smarx vielen Dank für das gereinigte Codebeispiel