Speichern Sie Daten in Mapping vs. Array

Ich sehe, dass es einige Solidity-Beispiele gibt, die mappingzum Speichern von Zuständen verwendet werden, und einige verwenden arrays.

In diesem Beispiel wird zum Beispiel Mapping verwendet:

struct Campaign {
   ....
}
uint numCampaigns;
mapping (uint => Campaign) campaigns;

und es gibt ein Array:

Proposal[] public proposals;
struct Proposal {
   ....
}

Ich verstehe, dass es ein wenig anderes Muster zum Hinzufügen eines neuen Werts gibt, im Grunde, weil Arrays das .lengthAttribut haben. Zumindest im Vergleich zu mapping (uint => ...). Das ist alles, was ich sehe, vielleicht übersehe ich etwas?

Nehmen wir an, ich habe ein ähnliches Muster: einen Vertrag, der einige Strukturen/Dokumente betreibt (Vertrag hat Funktionen zum Hinzufügen und Aktualisieren solcher Dokumente). Es könnte eine unbegrenzte Anzahl von Dokumenten laut Vertrag verarbeitet werden. Mein Bauchgefühl sagt mir, dass ich es verwenden sollte mapping, aber ich kann keinen Beweis finden. Meine Frage ist also, welche und wann ich wählen soll.

Antworten (3)

mappingwird allgemein empfohlen. Für diesen Anwendungsfall eines Vertrags, der eine unbegrenzte Anzahl von Dokumenten haben könnte, die aktualisiert werden könnten, gilt die Empfehlung.

Der Hauptvorteil eines Arrays besteht in der Iteration. Aber die Iteration muss begrenzt werden, nicht nur aus Geschwindigkeitsgründen, sondern möglicherweise auch aus Sicherheitsgründen. Als extremes Beispiel könnte einem Vertrag ein dauerhafter Denial-of-Service auferlegt werden, wenn sein Dienst das Iterieren über ein Array beinhaltet, das ein Angreifer füllen kann, sodass die Iterations- und Betriebskosten dauerhaft das Blockgaslimit überschreiten.

Ein Kommentar von @PaulS legt nahe, dass das Iterieren eines Arrays der Länge 50 relativ effizient ist; Es wird empfohlen, die Anwendungsfälle zu testen, um auch Details wie gewünschte oder akzeptable Gaskosten zu identifizieren.

Beachten Sie zur Verdeutlichung, dass Sie nicht versuchen sollten, alle Arrays durch Mappings zu ersetzen: Mappings können nur für Daten im Speicher verwendet werden .

Was ist ein guter Weg, um das DoS-Problem zu umgehen, wenn Sie noch eine Iteration benötigen?
@eth Können Sie kommentieren, warum Mappings empfohlen werden?
@ComandanteCheth Welcher Teil dieser Antwort muss geklärt werden? Sie können auch sowohl ein Mapping als auch ein Array verwenden: Die Hauptgefahr, auf die Sie bei einem Array achten müssen, ist zu viel Iteration.
@Raine: Sie könnten eine Funktion haben, die einen Startindex verwendet und immer eine feste Anzahl von Wiederholungen durchführt, sodass mehrere Transaktionen mit einem anderen Startindex verwendet werden.

Dies ist ein für Ihre Anwendung spezifisches Designproblem. Was müssen Sie mit den Dokumenten tun? Wenn Sie beispielsweise ein bestimmtes Dokument für eine Aktualisierung benötigen, ist eine Zuordnung viel einfacher als das Schleifen über ein Array von Dokumenten. Das Speichern von Dokumenten nach einer ID würde dies vereinfachen:

mapping(uint256 => Document);
Ich mache einige Lookups und reduziere viel in meiner Anwendung. Also benutze ich beide gleichzeitig. Ich verwende ein Array für die Iteration und eine Karte für die Suche. In Wirklichkeit sind O (n) Spaziergänge für < 50 Länge eigentlich ziemlich effizient, daher könnte eine Zuordnung zu viel des Guten sein.

Es läuft alles auf die Tatsache hinaus, dass Sie Arrays verwenden, um diese Dokumente zu speichern, und diese Arrays unbegrenzt wachsen, und weil Sie immer über die gesamte Länge Ihrer Arrays iterieren, müssen Sie am Ende möglicherweise eine enorme Menge an Gas ausgeben nur um ein bestimmtes Dokument innerhalb des Vorschlags-Arrays nachzuschlagen.

Um dieses Problem zu lösen, sollten Sie die Verwendung von Arrays innerhalb Ihres Vertrags vollständig einstellen und stattdessen eine etwas andere Datenstruktur verwenden.

Die Datenstruktur, die Sie zum Speichern all dieser Vorschläge verwenden sollten, ist kein Array, sondern eine Zuordnung.

Ein Mapping ist ein Referenztyp, der uns innerhalb von Solidity zur Verfügung steht. Eine Zuordnung ist wie eine Sammlung von Schlüssel/Wert-Paaren, also ähnlich wie ein JavaScript-Objekt, aber es gibt einige diskrete und eindeutige Unterschiede zwischen einer Zuordnung und einem JavaScript-Objekt.

Warum also wird ein Mapping Ihr Problem lösen?

Es läuft alles auf die Suchzeit für jede dieser Datenstrukturen hinaus. Wenn wir in der Informatikdisziplin versuchen, ein Datenelement in einem Array zu finden, ist der beste Fall, den wir für die Ausführung dieser Suche erhalten können, die lineare Zeit. Wenn wir sagen, dass die Suche innerhalb des Arrays eine lineare Zeit ist, bedeutet dies, dass die Ausführung der Suche für jeden zusätzlichen Datensatz, den wir diesem Array hinzufügen, etwas länger dauert.

Wenn wir 100 Elemente im Array haben, kann es 100 Sekunden dauern. Mit anderen Worten, die Größe des Arrays bestimmt, wie lange die Suche dauern wird.

Das wird Sie in Schwierigkeiten mit den Gaspreisen bringen, wenn Sie sich für Arrays entscheiden.

Der große Unterschied zwischen einem Array und einem Mapping besteht darin, dass eine Suche innerhalb eines Mappings in der Informatikdisziplin Constant Time genannt wird.

Wenn wir von konstanter Zeit sprechen, bedeutet dies, dass es immer gleich viel Zeit in Anspruch nimmt, egal wie viele Daten wir in diesem Mapping speichern. Wenn wir also einen Vorschlag haben, dauert es eine Sekunde, aber wenn wir tausend Vorschläge haben, dauert es immer noch nur eine Sekunde, um diese Vorschläge zu durchlaufen.

Natürlich möchten Sie hier definitiv Mapping verwenden.