Meine Frage bezieht sich auf das Finden von Schlüsseln, die gültigen Werten in einem bestimmten Bereich (n_start, n_end) zur Laufzeit zugeordnet sind, wenn möglich mit minimalem Gas.
mapping(uint => myStruct) clusterContract;
uint
enthält die Blocknummer auf der Blockchain. Dies kann also zwischen 0 und 1.000.000 liegen und sich weiter erhöhen. Basierend auf dem Verhalten des Clients wird ein neues Mapping generiert, aber es kann einige leere Stellen geben, z. B. wie mappings
folgt:
clusterContract[0] = structA;
clusterContract[1001] = structB;
clusterContract[1002] = structC;
clusterContract[1003] = structD;
clusterContract[1100] = structE;
clusterContract[2000] = structF;
clusterContract[7999] = structG;
clusterContract[8001] = structH;
Folgende Antwort sagt das:
Leider nicht. Eine Zuordnung gleicht nur einen Schlüssel einem Wert zu. Es hat keine Liste von beidem per se.
An dieser Stelle zum Beispiel : Ich möchte nur Strukturen erreichen, die von gültigen Schlüsseln zwischen 1000 und 8000 zeigen, die 1001 (structB), 1002 (structC), 1002 (structD), 2000 (structF) und 7999 (structG) sein sollten ) .
Um diese einzige Lösung zu erreichen, die ich mir ausgedacht habe, besteht darin, alle Elemente von 1000 bis 8000 zu durchlaufen und zu überprüfen, ob jede Blocknummer einen gültigen Schlüssel hat oder nicht, und wenn sie gültig ist, die Operation auszuführen, die ich ausführen möchte:
for(int i=1000; i++; i<8000) {
if( clusterContract[i] ) //check whether key exists. I could not figure out how to check key exists or not.
clusterContract[i].StructX.val = 64; //or do something else.
}
[F] Wie Sie sehen können, muss ich 7000 Werte durchlaufen, um zu prüfen, ob ihre Schlüssel gültig sind oder nicht. Ist dies eine vorgeschlagene Lösung, bei der der Gasverbrauch ineffizient sein könnte, da ich 7000 if then
oder mehr machen muss, wenn die Reichweite zunimmt? Jede empfohlene Lösung wäre sehr willkommen. Bitte beachten Sie, dass der binäre Suchbaum eine gute Lösung sein könnte, aber wenn der Baum wieder größer wird, würde es ineffizientes Gas zum Hinzufügen neuer Knoten oder zum Suchen innerhalb des Baums geben.
=> Oder wenn ich die Schlüsselgültigkeitsprüfung entferne (ob Schlüssel i
vorhanden ist oder nicht), wenn dieses Codestück von Solidity in das Codestück der niedrigsten Ebene (Ethereum Virtual Machine-Code) konvertiert wird, werden nicht vorhandene Schlüssel automatisch ignoriert, da dies nicht der Fall ist existieren? Daher werden nur gültige Schlüssel berücksichtigt und es werden nicht 7000 Elemente durchlaufen.
for(int i=1000; i++; i<8000)
clusterContract[i].StructX.val = 64; //only existing keys are updated.
Vielen Dank für Ihre wertvolle Zeit und Hilfe. Es tut mir leid, wenn es Grammatikfehler gibt, ich habe mein Bestes getan, um dieses Problem mit einigen Beispielen zu erklären.
Dies ist eine ziemlich hohe Abstraktionsebene, da ich nicht genau weiß, was die Anwendung tun wird oder wie Sie die Bereitstellung strukturieren werden. Dreiteilige Antwort.
Erstens wäre ich misstrauisch gegenüber einem Schleifenprozess. Versuchen Sie, wann immer möglich zu vermeiden, und halten Sie es in Grenzen, wenn es unvermeidlich ist. Die Begründung beinhaltet die Tatsache, dass die Schätzung von Gas schwierig sein kann und es möglich ist, dass der Prozess aufgrund der Blockgasgrenze überhaupt nicht ausgeführt werden kann.
Es ist oft möglich, so etwas zu umgehen, indem man einen einzelnen Schritt ... // oder etwas anderes ... als Funktion ausgibt. Sie verlassen sich auf etwas außerhalb des Vertrags, dh einen Knotenserver oder einen UI-Client usw., um eine Schleife zu durchlaufen und diese Funktion so oft wie nötig aufzurufen.
Zweiter Teil. Das Iterieren über ein Mapping selbst ist nicht möglich, aber so etwas wird oft benötigt. Eine Lösung besteht darin, einen Index zu verwalten und darüber zu iterieren.
address[] clusterContractIndex;
Als ich darüber nachdachte, wie ich ein Beispiel präsentieren könnte, entwickelte ich das Gefühl, dass die Zuordnung nach Blocknummer nicht der richtige Weg ist, also wechselte ich zur Zuordnung nach Adresse. Mit dieser Änderung kommt es nicht zu Kollisionen, wenn im selben Block mehrere erstellt werden. Möglicherweise möchten Sie die Blocknummer zur Struktur hinzufügen, um sie irgendwo aufzuzeichnen, während Sie die Details ausarbeiten. Beachten Sie, dass dies nicht erforderlich ist, um Verträge in einem bestimmten Block zu erstellen.
Betrachten Sie als allgemeine Gewohnheit die Nützlichkeit einiger Funktionen, um das Mapping iterierbar zu machen:
function getContractCount() returns(uint count) {
return clusterContractIndex.length;
}
function getContractAtIndex(uint row) returns(address contract) {
return clusterContractIndex[row];
}
Schreiben Sie innerhalb der Funktion, die sie aufzeichnet, die Strukturen in die Zuordnung und auch push()
die Schlüssel in den Index:
function newClusterContract(address newContract) {
clusterStructs[newContract] = contractStruct;
clusterContractIndex.push(newContract);
Dies ist ein kumulativer Nur-Hinzufügen-Prozess. Jetzt können Sie die Verträge in der Reihenfolge, in der sie erstellt wurden, oder direkt nach ihrer Adresse erhalten mit:
function getContract(address contract) returns(contract details) {}
Dritter. Effiziente Suche und Filterung. Ich habe noch keinen guten On-Chain-Suchprozess :-)
In der Praxis können Sie diese Anforderung möglicherweise ausschließen und sich auf Offchain-Dienste wie eine Datenbank oder sogar eine In-Memory-Sortierung durch eine Browser-Benutzeroberfläche (je nach erwartetem Umfang) verlassen. Das Fazit hier ist, dass die meisten Dinge, die so aussehen, als ob eine Onchain-Index-/Such-/Filterlösung erforderlich wäre, wirklich besser von Offchain-Prozessen gehandhabt werden.
Fügen Sie dem Vertrag einen Ereignisemitter hinzu, wenn sich der Status ändert.
event LogNewContract(address contract);
Und wenn es passiert:
LogNewContract(address newContract);
Wenn Sie mit dem Erstellen der Benutzeroberfläche beginnen, werden Sie wahrscheinlich feststellen, dass ein Beobachter darüber eine synchronisierte Kopie der On-Chain-Wahrheiten aufbewahren, Dinge schnell sortieren und filtern und dann die Details eines Vertrags abrufen kann, von dem bekannt ist, dass er existiert. So wie es klingt, muss es nur alle Verträge finden, die tatsächlich in einem bestimmten Bereich von Blocknummern existieren. Kunden erhalten die Blocknummer, in der ein Vertrag erstellt wurde, wenn das Ereignis eintrifft. Es ist ein Bonusstück für jedes erhaltene Ereignis.
Ich hoffe es hilft.
ps Sie können sich die Zuordnung als eine Tabelle vorstellen, in der alle möglichen Adressen vorhanden sind und alle verbleibenden Spalten zuverlässig auf 0 initialisiert werden. Wenn Sie eine Struktur von einer "leeren" Adresse ziehen, an die Sie nie geschrieben haben, werden alle Felder in der Struktur sein alle 0. 0, false, 0x0, leerer String, je nach Typ.
AKTUALISIEREN
Ich habe einen Bestellstatistikbaum erstellt, der eine Reihe von Problemen löst, wie z. B. das Finden des Medians oder Rangs eines Werts in einer sortierten Liste, und gleichzeitig eine Methode bietet, um die Gaskosten in jeder Größenordnung auf ein absolutes Maximum / Worst-Case-Limit zu begrenzen.
Dieses Repo baut auf Bokky Poobahs Red Black Tree auf, der die Grundlage für den selbstausgleichenden Baum bildet. https://github.com/rob-Hitchens/OrderStatisticsTree
Alper
Rob Hitchens
Cogito ergo sum
mappingVariable[key]
Ergebnis das Ergebnis liefern, oder? Leider kämpfe ich mit diesem Problem ethereum.stackexchange.com/q/25283/3137 Können Sie bitte helfen?Rob Hitchens
Cogito ergo sum
mappingVariable[key]
fehlschlägt, wenn der Schlüssel ein Mitglied des Arrays ist; selbst in einerstruct
. Ich wäre Ihnen dankbar, wenn Sie mir dabei helfen könnten, bitte.