Fragen Sie jede Struktur einer Mapping- vs. Looping-Getter-Funktion für das Front-End ab?

Ich habe eine Zuordnung von Strukturen und eine Zählervariable, um zu verfolgen, wie viele Strukturen in der Zuordnung gespeichert sind.

Für die Front-End-Entwicklung würden Sie empfehlen, jede Struktur mit dem automatisch generierten Getter mymapping[mystruct_index] abzufragen. Oder ist es besser, eine bestimmte Getter-Funktion zu erstellen, um X-Strukturen zu durchlaufen und Strukturen beispielsweise in Arrays von 50 abzurufen. Auch wenn ich die Getter-Funktion verwende, um nur wenige Zeilen der Struktur anstelle der gesamten Struktur abzurufen, führt dies zu einer besseren Effizienz, als einfach eine Abfrage für eine Struktur durchzuführen? Haben Sie Erfahrung in Bezug auf die Front-End-Interaktion mit Smart Contracts, was ist Ihrer Meinung nach das beste Design für Effizienz und langfristige Rentabilität des Smart Contract? Mit freundlichen Grüßen

Antworten (1)

Solidity unterstützt derzeit nicht die Rückgabe einer Zuordnung oder einer Liste mit variabler Größe, daher müssten Sie eine Getter-Funktion implementieren, wie Sie beschrieben haben, die einen Index akzeptiert.

Der Ansatz, den Sie meiner Meinung nach beschreiben, besteht darin, eine zweite Liste neben der Zuordnung zu führen und sie zu verwenden, um die Zuordnung in Blöcken wie dem folgenden Quellcode zurückzugeben.

contract SomeContract {

  mapping(address => uint256) public someMapping;
  address[] public addresses;

  function addValue(address _newAddress, uint256 _newValue) public {
    someMapping[_newAddress] = _newValue;
    addresses.push(_newAddress);
  }

  function getAddressCount() public view returns (uint256 _count) {
    return addresses.length;
  }

  function getValueByIndex(uint256 _index) public view returns (uint256 _val) {
    return someMapping[addresses[_index]];
  }

  // Get the values from mapping in chunks of size 10
  // This isn't a feasible solution in my opinion
  function getValuesChunk(uint256 _index) public view returns (uint256[10] memory _chunk) {
    uint256[10] memory vals;
    require(_index < 2^256 - 10, 'Index would wrap around unsafely');
    for (uint256 i = _index; i < _index+10; i++) {
        vals[i] = someMapping[addresses[i]];
    }
    return vals;
  }
}

Die viewMethoden sind schreibgeschützt und kosten kein Gas, sodass Sie sie technisch so oft aufrufen können, wie Sie möchten, um Werte für Ihr Frontend anzuzeigen. Es gibt jedoch einige Gründe, dies nicht zu tun. * Es würde immer noch CPU-Leistung auf Ihrem Ethereum-Knoten verbrauchen. Wenn die Liste groß genug ist, könnte Ihr Knoten dies als DoS-Angriff betrachten und Sie drosseln oder sperren. Wenn Sie Ihren eigenen Knoten betreiben, ist das eine Menge Arbeit oder AWS-Credits, die Sie für Blockchain-Operationen verbrennen müssen. * Die Zuordnung ändert sich zwischen Aufrufen von nicht wesentlich addValue. Sie würden die Arbeit des Abrufens der meisten gleichen Werte jedes Mal wiederholen, selbst wenn Sie in Ihrem Front-End etwas zwischenspeichern.

Stattdessen würde ich empfehlen, Solidity-Ereignisse (EVM-Protokolle) zu verwenden, eine Einrichtung, mit der Sie ein Ereignis ausgeben können, das von einer Datenbank abgerufen wird, die es ermöglicht, die One-Pass-Indizierung mehrmals außerhalb der Kette zu lesen, wie z. B. Subgraph https:// thegraph .com/

Auf diese Weise können Sie Ihren Solidity-Code minimal und sauber halten und kein Gas für einen komplizierten Vertrag ausgeben, nur um die Front-End-Funktionalität zu unterstützen, die Sie einfach auf Systeme auslagern können, die dafür entwickelt wurden (GraphQL + React + Typescript).

contract SomeContract {

  event NewValue (
      address _address,
      uint256 _value
      );
  mapping(address => uint256) public someMapping;


  function addValue(address _newAddress, uint256 _newValue) public {
    someMapping[_newAddress] = _newValue;
    emit NewValue(_newAddress, _newValue);
  }

}

Hoffe das hilft.

OK danke. Ich verstehe nur nicht, warum Sie den getValueByAddress-Getter erstellt haben, da someMapping öffentlich ist und ich in der Lage sein sollte, someMapping(address) durchzuführen? Ich kann es von meiner Truffle-Testumgebung aus tun, aber sagen Sie, dass es auf Mainet nicht möglich ist? Mit freundlichen Grüßen
@paul-ham Außerdem ist meine Zuordnung etwas anders: Der Schlüssel ist ein uint-Index, der mit dem Zähler verknüpft ist: Zuordnung (uint => struct) mymapping; uint MappingCounter; // verfolgt, wie viele Strukturen in der Zuordnung vorhanden sind. Ich habe darüber nachgedacht, eine Getter-Funktion zu erstellen, die ein aus dem Speicher erstelltes Array zurückgibt, indem sie Mapping-Strukturen durchläuft
@KevinWad gerne geschehen. lol mein Name ist @paul-pham, nicht @paul-ham, das ist ein anderes Frühstücksessen. Sie haben Recht, die öffentliche Zuordnung benötigt keinen separaten Getter, ich werde meine Antwort aktualisieren, um sie zu entfernen. Außerdem habe ich vergessen, dass Ihr Wert eine Struktur ist, aber das allgemeine Prinzip meiner Antwort gilt immer noch. Anstatt zurückzugeben, uint256 _valuewürden Sie Ihren Strukturtyp zurückgeben.
Ja, ich entschuldige mich. Ok vielen Dank. Um fortzufahren, wenn ich mich auf den öffentlichen Mapping-Getter ohne zusätzliche Getter-Funktion verlasse, muss ich, wenn das Mapping größer wird, Off-Chain-Methoden verwenden, da ich sonst mit Dos-Problemen konfrontiert werde, ist es richtig? Und was bedeutet das „Wenn Sie Ihren eigenen Knoten betreiben, ist das eine Menge Arbeit oder AWS-Credits, die Sie für Blockchain-Operationen verbrennen müssen“ ? Mit freundlichen Grüßen
Kein Problem. Das Aufrufen des öffentlichen Getters für das Mapping hat feste Kosten für einzelne Aufrufe. Wenn Sie jedes Mal alle Mapping-Werte abrufen möchten , sind, wie Sie sagten, immer mehr Aufrufe erforderlich, wenn das Mapping größer wird. Der Rest meiner Antwort passt hier nicht, ich habe es in einen Kern verschoben: gist.github.com/cryptogoth/edbacf61517bb9100b742b69ccd5fbc1 Hoffe, es hilft