Artikelliste pro Adresse

Ich arbeite an einer dApp und versuche, das folgende Problem zu lösen. Ich möchte eine Adresse einer dynamischen Artikelliste in einem meiner Verträge zuordnen. Auf diese Weise hat ein Benutzer, wenn er sich anmeldet, seine eigene Liste mit Elementen (ein bisschen wie die Arbeit von Kryptokitten, für jede Adresse können Sie die Liste der Kätzchen für diese Adresse haben). Meine Frage ist: Kann ich diese Zuordnung machen? Ist es schlecht/nicht effizient? Mir wurde gesagt, dass es so ist, und ich konnte nicht wirklich herausfinden, wie ich es effizient machen sollte. Einige Leute, mit denen ich zusammenarbeite, schlagen vor, diese Informationen aus der Kette zu nehmen. Ist das der richtige Ansatz? Ich hätte lieber alles onchain.

Danke

Antworten (2)

Dies ist insofern nicht effizient, als Sie jedes einzelne Element aufrufen müssten, das der Benutzer besitzt, da Sie derzeit keine Liste von Strukturen in Solidity zurückgeben können. Aber Sie können einfach eine Liste mit IDs von Artikeln zurückgeben, die dem Benutzer gehören, und dann Informationen zu diesen Artikeln erhalten (leider auch einzeln). Da es sich bei diesen Funktionen, die Informationen über Artikel zurückgeben, um "Ansichts"-Funktionen handelt, kosten sie kein Gas. Wenn der Benutzer nicht über Dutzende oder Hunderte von Artikeln verfügt, ist dies meiner Meinung nach nicht das Problem.

Der folgende Code ist nur ein Beispiel, ihm fehlt die Sicherheitslogik (jeder kann jede Funktion aufrufen).

pragma solidity ^0.4.21;

    contract ItemsAndUsers {
    struct Item {
        uint id;
        string nameOfItem;
        string typeofItem;
        uint value;
    }

    //In this form user struct doesn't make much sense as it has only one field, 
    //but we can imagine it being more complex
    struct User {
        address userAddress;
    }

    Item[] public allItems;
    User[] public allUsers;

    mapping (address => uint[]) public userItemsIds;
    mapping (uint => address) public itemIdToUser;

    function createUser() public {
        uint[] memory items;
        User memory user = User({
          userAddress: msg.sender
        });
        allUsers.push(user);
    }

    function createItem(string _name, string _type, uint _value) public {
        Item memory item = Item({
           id: allItems.length,
           nameOfItem: _name,
           typeofItem: _type,
           value: _value
        });
        allItems.push(item);
    }

    function assignItemToUser(address _userAddress, uint _itemId) public {
        itemIdToUser[_itemId] = _userAddress;
        userItemsIds[_userAddress].push(_itemId);
    }

    //This function will return list of ids of all items belonging to the _userAddress
    function getUserItems(address _userAddress) public view returns (uint[] items){
        return userItemsIds[_userAddress];
    }

    //This function returns all information about single item
    function getItemInfo(uint _itemId) public view returns (uint id, string nameOfItem, string typeofItem, uint value) {
        Item memory item = allItems[_itemId];
        return (item.id, item.nameOfItem, item.typeofItem, item.value);
    }
}

Im Grunde müssten Sie also die getUserItems-Funktion einmal aufrufen und getItemInfo für jedes Element, das dieser Benutzer besitzt

Sie möchten eine zugeordnete Struktur mit Index und Sie möchten in einer zugeordneten Struktur mit Index speichern.

keyExists(key)Zugeordnet, damit Sie oder getDetails(key)in einem Zug auflösen können . Indiziert, damit Sie die Schlüssel zählen und die Liste aufzählen können.

Jedes Mal, wenn Sie eine zugeordnete Struktur einfügen, sollten Sie auch einen Schlüssel an den Index anhängen und dabei darauf achten, doppelte Schlüssel zu vermeiden.

struct MemberStruct {
   bool isMember; 
   // ... carry on
}

mapping(address => MemberStruct) public memberStructs;
address[] public memberList;

Das ist eine Grundstruktur, die die meisten Basen abdeckt. Wenn Sie nicht löschen müssen, ist das Leben einfacher. Schauen Sie hier für bessere Beispiele: Gibt es gut gelöste und einfache Speichermuster für Solidity?

Sie können dieses Muster verwenden, um zwei Listen in einem einzigen Vertrag zu verwalten. Was Sie beschreiben, ist eine Eins-zu-Viele-Verknüpfung. Sie benötigen wahrscheinlich die CRUD-Operationen für beide Tabellen sowie eine Möglichkeit, die referenzielle Integrität zu erzwingen.

Dazu müssen Sie bidirektionale Zeiger in beiden Tabellen verwalten. https://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart-contracts-a9ab1427ff42

Wie Mike zu Recht betonte. Es ist wichtig, dass Sie die interne Organisation aufrechterhalten, damit Sie alle Vorgänge ohne unbegrenzte Schleifen oder Rekursionen abschließen können for. Wenn Sie sich dabei ertappen, wie Sie sich durch Aufzeichnungen schlängeln, ist das ein Zeichen dafür, dass die Dinge aus dem Ruder laufen. Sie müssen die Dinge so arrangieren, dass beispielsweise die benötigte Reihe sofort bekannt ist.

Ich hoffe es hilft.