Schleifenoptimierung, die Koordinaten in einem Gitter überprüft

Ich habe einen Vertrag erstellt, bei dem Benutzer ein Bild in einer bestimmten Koordinate festlegen können, diese Position kann nur ein Bild haben. Die Rastergröße ist 400 hoch und dynamisch breit (wird mit der Zeit wachsen) und es gibt 3 verschiedene Bildgrößen: 10 x 10, 20 x 20, 40 x 40 (Pixel).

Ich muss den Kreislauf optimieren, um die derzeit sehr hohen Gaskosten zu senken.

Hier ist meine aktuelle Implementierung, bei der Koordinaten und Größen durch 10 geteilt werden, um die Gaskosten zu senken.

pragma solidity 0.4.19;


contract Test {

    mapping (uint => bool[40]) public grid;

    function check(uint x, uint y, uint size) public {

        for(uint i = 0; i < size; i++) {
            for(uint j = 0; j < size; j++) {

                if(grid[x + i][y + j]) {
                    // image exists in this slot
                    revert();
                }

                grid[x + i][y + j] = true;

            }
        }
    }

}

Mögliche Größen:

 - small: 1 (1 slot)
 - medium: 2 (4 slots)
 - big: 4 (16 slots)

Aktuelle Gaskosten :

- Small: 43223
- Medium: 76251
- Big: 163181
Sie können die Hälfte des Benzins sparen, indem Sie einfach Ihre Zuordnung uintals boolIhren ursprünglichen Code deklarieren. Dies liegt daran, wie Solidity Booleans packt, wenn sie geschrieben werden, denke ich. Vielleicht einfacher als der Zusammenbau :-)
@benjaminion gerade ausprobiert, es erhöht sich tatsächlich viel, Gas: 351253 für das große Ganze, statt 163181. Trotzdem danke :), ich probiere alles aus, sogar die Montage, die ich nicht wirklich kenne. Ich hätte lieber eine solide Antwort, aber alles würde tun. Ich verwende Trüffel und Ganache zum Testen der Gaskosten, nur für den Fall, dass es Unterschiede zum Hauptnetz gibt.
Ja, ich habe etwas falsch gemacht :-) Entschuldigung. Ich denke, die Assemblierung könnte Ihnen hier hauptsächlich helfen, wenn Sie sie verwenden, um Lasten und Speicherungen im bitgepackten Raster zu minimieren (dh sizeBits gleichzeitig mit einer Ladung zu prüfen, anstatt sizeLadungen auszuführen; dito Speichern). Dies wird ziemlich kompliziert sein und erfordert tiefgreifende Kenntnisse über Solidity-Mapping-Speicherung. Eine einfache naive Übersetzung in Assembler kann ein wenig helfen, indem sie Grenzenüberprüfungen eliminiert, aber es ist nicht der große Preis.
Ich verstehe, vielen Dank. Vielleicht ist mein Code bereits optimiert, und ich muss akzeptieren, dass die Benutzer diese Menge an Benzin bezahlen müssen. Ich werde mich wahrscheinlich an den Solidity-Code halten, aber nur damit ich ihn aus meinem Kopf bekomme, wissen Sie, wie man ein 2D-Array oder eine Zuordnung in der Baugruppe liest / schreibt? Ich habe nichts im Internet gefunden und möchte es wirklich wissen.

Antworten (1)

Sie können alle bools hintereinander in eine einzige uint packen und Speicheraktualisierungen sparen:

pragma solidity 0.4.19;

contract Test {

    mapping (uint => uint) public grid;

    function check(uint x, uint y, uint size) public {

        for(uint i = 0; i < size; i++) {
            uint row = grid[x + i];
            for(uint j = 0; j < size; j++) {
                // if (y + j) bit is set in row
                if((row >> (y + j)) & uint(1) == uint(1)) {
                    // image exists in this slot
                    revert();
                }

                // set bit (y + j)
                row = row | (uint(1) << (y + j)); 
            }
            grid[x + i] = row;
        }
    }
}

Gaskosten neu :

- Small: 42632
- Medium: 63808
- Big: 107750

Je größer die Größe, desto größer die Verbesserung.

Beachten Sie auch, dass nachfolgende Aufrufe checkin den berührten Reihen sogar noch billiger werden, da Sie nur 5,000Gas für die Aktualisierung von Speicherplätzen bezahlen müssen, anstatt 20,000. Ein Anruf check(0,0,4)mit anschließendem Anruf check(0,4,4)kostet nur 48214 Gas.

Sie können es noch weiter optimieren, indem Sie mehrere Zeilen in einzelne Einheiten packen. Wenn jede Zeile 40 Bit hat, können Sie [256 / 40] = 6 Zeilen packen. Der Code wird jedoch etwas komplexer.


Vorherige Antwort:

Sehen Sie sich Schleifen in Assembly an http://solidity.readthedocs.io/en/develop/assembly.html#loops . Sie ermöglichen das Einsparen von Gas bei der Grenzkontrolle.

Weitere Beispiele finden Sie hier

Danke für die Antwort, ich wusste davon, aber ich kenne keine Assembly, und ich glaube, es ist ein Risiko, wenn ich einen Smart Contract codiere, den ich nicht verstehe: P. Ich suche, wie ich auf eine Zuordnung in Assembly zugreifen kann, aber ich finde noch kein Beispiel.
Ich habe versucht, den Code in Assembly zu ändern, aber ich habe Probleme beim Abrufen/Speichern des Mapping/2D-Arrays. Möchten Sie einen Blick darauf werfen?
Sicher, Sie können Ihren Code in die Frage einfügen.
@MarcosCasagrande Benjaminions Idee war in der Tat gut. Ich habe meine Antwort aktualisiert.
Wow, sehr schöne Verbesserungen. Ich führe Tests durch und alles scheint perfekt zu funktionieren! Geben Sie mir einen Moment Zeit, um den Code vollständig zu verstehen, und ich gebe Ihnen das Kopfgeld!
Vielen Dank, sehr schlau, die Bools in eine uint zu packen. You may award your bounty in 19 hours. In 19 Stunden gehört es Ihnen!