Was ist die beste Vorgehensweise zum Speichern und Abrufen großer Datenmengen in Solidity Smart Contracts?

Angenommen, ich habe eine Ereigniserstellungsseite mit einigen Formularfeldern in der Benutzeroberfläche. Und ich habe einen intelligenten Vertrag, um das Ereignis in der Ereigniszuordnung oder dem öffentlichen Array in einem Strukturformat zu speichern.

struct event{
      bytes32 name;
      uint time;
}

event[] public events;

or

mapping(uint=>event) public events;

Ich übermittle die UI und die Daten werden im Vertrag gespeichert.

Ich habe eine Seite mit Listenereignissen, auf der alle im Vertrag erstellten Ereignisse angezeigt werden.

Nachdem ich viele Foren durchsucht habe, habe ich einige Informationen erhalten, kann jemand dies bestätigen.

Ansatz 1:

Für jedes Senden oder Speichern im Vertrag wird ein Ereignis aufgerufen und die Benutzeroberfläche hat den Beobachter und wird im lokalen Speicher gespeichert und in der Benutzeroberfläche angezeigt. Die Ereignisdaten können hier ein Mapping oder Array sein.

Ich möchte keinen Zwischenspeicher für die Anwendung haben, daher erhält der Ereignisbeobachter bei jeder Aktualisierung der Benutzeroberfläche alle Zustandsdaten und aktualisiert erneut den lokalen Speicher und die Anzeige in der Benutzeroberfläche.

Ansatz 2:

Für die Ereignisübermittlung wird ein neues Ereignisobjekt erstellt und in das Ereignisarray geschoben.

Und das Schreiben der get events-Methode, um das Ereignis-Array zu durchlaufen und die Liste der String-Elemente für jeden Schlüssel im Objekt zurückzugeben und dann die Strings in einem Array von Objekten in der Benutzeroberfläche erneut zu verketten und zu destrukturieren, um sie an die Benutzeroberfläche zu binden.

Ich denke, die Berechnung für den zweiten Ansatz wird wegen der Iteration hoch sein. Da wir die Dapp entwickeln, möchte ich keine Zwischendatenbank mehr haben, die zu einem zentralisierten System wird.

Kann jemand die verschiedenen Möglichkeiten zum Speichern und Abrufen von Daten aus dem Smart Contract erklären, was bisher ein bevorzugter Weg ist.

Es wird mir sehr helfen. Vielen Dank im Voraus.

Antworten (3)

eventist ein Schlüsselwort in solidity , mit dem Sie Daten, die ein Vertrag in einem Javascript-Frontend generiert hat, einfach abrufen können. Es ist billiger, ein Ereignis zu schreiben, als in eine Speichervariable (wie Ihr structArray) zu schreiben. Sie können dann .watchfür diese Ereignisse und sie in Ihre Benutzeroberfläche ziehen. Dies ist der empfohlene Weg. Aus Leistungsgründen möchten Sie diese Ereignisdaten möglicherweise irgendwie zwischenspeichern, da das Analysieren aller Blöcke bei jedem Neuladen ziemlich ineffizient ist.

Versuchen Sie auch nicht, alle Ihre Daten in Ihren Smart Contract zu integrieren. Die Aufgabe einer gut gestalteten DApp besteht darin, nicht mehr als die unbedingt erforderlichen Elemente und Verweise auf externe Strukturen zu enthalten , aber Ihre Speicherschicht von der Blockchain getrennt zu halten. Eine Speicherschicht könnte über IPFS oder Swarm implementiert werden .

Wie Sebastian sagte, möchten Sie vorsichtig sein, welche Daten Sie im Vertrag auf der Blockchain speichern möchten.

Davon abgesehen werden die Gaskosten für die Speicherung der Daten vom Transaktionsaussteller für die Erstellung eines Ereignisses getragen. Ebenso wird jeder "transaktionsbasierte" Aufruf, der diese Daten iterieren muss, sehr kostspielig, abhängig von der Datenmenge und den Iterationen, die Sie durchführen müssen.

Wenn eine Funktion als konstant markiert ist und keine Änderung der Daten erfordert, kann sie aufgerufen werden, ohne dass Gaskosten anfallen, und daher ist das Iterieren einer Liste von Ereignissen, obwohl sie berechnungsintensiv ist, wenn sie als Transaktion ausgeführt wird, grundsätzlich kostenlos aufrufbar.

Es empfiehlt sich, einen Bereich hinzuzufügen, den Sie auflisten möchten, damit Sie die für jeden Aufruf erforderliche Verarbeitung einschränken und die Ergebnisse in Ihrer dApp anzeigen können.

Hier ist ein Beispiel für einen Vertrag, der dies kann, er ist keineswegs vollständig, aber das Kopieren und Einfügen in Remix funktioniert, um die grundlegende Funktionalität zu zeigen:

pragma solidity ^0.4.0;

contract EventManager {

    struct Event {
        bytes32 name;
        uint time;
    }

    uint totalEvents;

    mapping(uint => Event) EventList;

    event EventAdded(address indexed _senderAddress, uint _eventId);

    function addEvent(bytes32 _name, uint _time) returns(uint eventId) {
        eventId = totalEvents++;
        EventList[eventId] = Event(_name, _time);
        EventAdded(msg.sender, eventId);
    }

    function listEvents(uint _start, uint _count) constant returns(uint[] eventIds, bytes32[] eventNames, uint[] eventTimes) {

        uint maxIters = _count;
        if( (_start+_count) > totalEvents) {
            maxIters = totalEvents - _start;
        }

        eventIds = new uint[](maxIters);
        eventNames = new bytes32[](maxIters);
        eventTimes = new uint[](maxIters);

        for(uint i=0;i<maxIters;i++) {
            uint eventId = _start + i;

            Event memory e = EventList[eventId];
            eventIds[i] = eventId;
            eventNames[i] = e.name;
            eventTimes[i] = e.time;
        }
    }
}

TL/DR: Verwenden Sie eine Zuordnung mit einem dynamischen Array:

mapping(address => DataStruct[]) public dataStructsOfOwner;

Wenn mir jemand sagen könnte, wo ich diese Antwort besser posten kann, machen Sie bitte weiter.

Ich hatte eine andere Aufgabe: Speichern Sie Verträge, die einem Eigentümer zugeordnet sind. Ich habe eine kurze Simulation mit diesen beiden Optionen durchgeführt.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

struct Contract {
    string name;
    address contractAddress;
}

/**
 * @dev This Database saves an array of contracts for each owner
 */
contract Database1 {
    mapping(address => Contract[]) public contractsOfOwner;

    function addContract(
        address owner,
        string memory name,
        address contractAddress
    ) public {
        contractsOfOwner[owner].push(Contract(name, contractAddress));
    }

    function getContractsOfOwner(address owner)
        external
        view
        returns (Contract[] memory contracts)
    {
        return contractsOfOwner[owner];
    }
}

Und

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

struct Contract {
    string name;
    address contractAddress;
    address owner;
}

/**
 * @dev This Database saves an array of contracts and iterates over them to get
 * contacts by owner
 */
contract Database2 {
    address[] contracts;
    mapping(address => Contract) contractDetails;
    mapping(address => uint256) balanceOf;

    function addContract(
        address owner,
        string memory name,
        address contractAddress
    ) public {
        contracts.push(contractAddress);
        contractDetails[contractAddress] = Contract(
            name,
            contractAddress,
            owner
        );
        balanceOf[owner] += 1;
    }

    function getContractsOfOwner(address owner)
        external
        view
        returns (Contract[] memory returncontracts)
    {
        uint256 count = balanceOf[owner];
        Contract[] memory contractsOfOwner = new Contract[](count);
        uint256 i;
        uint256 resultIndex;
        for (i = 0; i < contracts.length; i++) {
            if (contractDetails[contracts[i]].owner == owner) {
                contractsOfOwner[resultIndex] = contractDetails[contracts[i]];
                resultIndex++;
            }
        }
        return contractsOfOwner;
    }
}

Überraschendes Ergebnis:

    ·--------------------------------------|---------------------------|-------------|-----------------------------·
|         Solc version: 0.8.10         ·  Optimizer enabled: true  ·  Runs: 200  ·  Block limit: 30000000 gas  
·······································|···························|·············|······························
|  Methods                             ·              111 gwei/gas               ·       3983.14 eur/eth       
·················|·····················|·············|·············|·············|···············|··············
|  Contract      ·  Method             ·  Min        ·  Max        ·  Avg        ·  # calls      ·  eur (avg)  │
·················|·····················|·············|·············|·············|···············|··············
|  Database1     ·  addContract        ·      72947  ·      90059  ·      81500  ·            4  ·      36.03  
·················|·····················|·············|·············|·············|···············|··············
|  Database2     ·  addContract        ·     122359  ·     156559  ·     135187  ·            4  ·      59.77  
·················|·····················|·············|·············|·············|···············|···························|···············|··············
|  Deployments                         ·                                         ·  % of limit   ·             
·······································|·············|·············|·············|···············|··············
|  Database1                           ·          -  ·          -  ·     406176  ·        1.4 %  ·     179.58  
·······································|·············|·············|·············|···············|··············
|  Database2                           ·          -  ·          -  ·     437581  ·        1.5 %  ·     193.47  
·······································|·············|·············|·············|···············|··············
·--------------------------------------|-------------|-------------|-------------|---------------|-------------·