Lista de artículos por dirección

Estoy trabajando en una dApp y estoy tratando de resolver el siguiente problema. Quiero asignar una dirección a una lista dinámica de artículos en uno de mis contratos. De esta manera, cuando un usuario inicia sesión, tiene su propia lista de elementos (un poco como el trabajo de cryptokittens, para cada dirección puede tener la lista de gatitos para esa dirección). Mi pregunta es: ¿puedo hacer este mapeo? ¿Es malo/no eficiente? Me han dicho que lo es, y realmente no podía imaginarme cómo hacerlo de manera eficiente. Algunas personas con las que trabajo sugieren poner esta información fuera de la cadena. ¿Es este el enfoque correcto? Prefiero tener todo onchain.

Gracias

Respuestas (2)

Esto no es eficiente en el sentido de que tendría que solicitar cada elemento que posee el usuario porque actualmente no puede devolver la lista de estructuras en solidez. Pero puede devolver fácilmente la lista de ID de elementos que pertenecen al usuario y luego obtener información sobre estos elementos (desafortunadamente también uno por uno). Pero como esta función que devuelve información sobre los artículos son funciones de "vista", no cuestan nada. Si el usuario no tiene docenas o cientos de elementos, no creo que este sea el problema.

El siguiente código es solo un ejemplo, carece de lógica de seguridad (cualquiera puede llamar a cualquier función)

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);
    }
}

Entonces, básicamente, tendría que llamar a la función getUserItems una vez y getItemInfo para cada elemento que posee este usuario

Desea una estructura asignada con índice y desea almacenar dentro de una estructura asignada con índice.

Asignado, para que pueda resolver keyExists(key)o getDetails(key)en un solo movimiento. Indexado, para que pueda contar las claves y enumerar la lista.

Cada vez que inserte una estructura mapeada, también debe agregar una clave al índice, teniendo cuidado de evitar claves duplicadas.

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

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

Esa es una estructura básica que cubre la mayoría de las bases. Si no necesita borrar, la vida es más fácil. Eche un vistazo aquí para obtener mejores ejemplos: ¿Existen patrones de almacenamiento simples y bien resueltos para Solidity?

Puede usar ese patrón para mantener dos listas en un solo contrato. Lo que estás describiendo es una combinación de uno a muchos. Probablemente necesite las operaciones CRUD para ambas tablas, además de una forma de hacer cumplir la integridad referencial.

Para lograr eso, deberá administrar punteros bidireccionales en ambas tablas. https://medium.com/@robhitchens/reforzando-la-integridad-referencial-en-ethereum-smart-contracts-a9ab1427ff42

Como bien señaló Mike. Es vital que mantenga la organización interna para que pueda completar todas las operaciones sin forbucles ilimitados ni recursividad. Si te encuentras recorriendo los registros, es una señal de que las cosas no están bien encaminadas. Debe organizar las cosas para que la fila necesaria, por ejemplo, se conozca de inmediato.

Espero eso ayude.