Список товаров по адресу

Я работаю над dApp и пытаюсь решить следующую проблему. Я хочу сопоставить адрес с динамическим списком элементов в одном из моих контрактов. Таким образом, когда пользователь входит в систему, у него есть свой собственный список элементов (немного похоже на работу криптокотят, для каждого адреса у вас может быть список котят для этого адреса). Мой вопрос: могу ли я сделать это сопоставление? Это плохо/неэффективно? Мне сказали, что это так, и я не мог понять, как это сделать эффективно. Некоторые люди, с которыми я работаю, предлагают разместить эту информацию вне сети. Это правильный подход? Я бы предпочел, чтобы все было в сети.

Спасибо

Ответы (2)

Это неэффективно, так как вам придется вызывать каждый отдельный элемент, которым владеет пользователь, потому что в настоящее время вы не можете вернуть список структур в твердости. Но вы можете легко вернуть список идентификаторов элементов, принадлежащих пользователю, а затем получить информацию об этих элементах (к сожалению, также по одному). Но поскольку эта функция, возвращающая информацию об элементах, является функцией «просмотра», она не требует газа. Если у пользователя нет десятков или сотен элементов, я не думаю, что это проблема.

Приведенный ниже код является лишь примером, в нем отсутствует логика безопасности (любой может вызвать любую функцию)

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

Таким образом, в основном вам нужно будет вызвать функцию getUserItems один раз и getItemInfo для каждого элемента, которым владеет этот пользователь.

Вам нужна сопоставленная структура с индексом, и вы хотите хранить внутри сопоставленной структуры с индексом.

Сопоставлены, так что вы можете решить keyExists(key)или getDetails(key)в один ход. Индексируется, так что вы можете подсчитать ключи и перечислить список.

Каждый раз, когда вы вставляете сопоставленную структуру, вы также должны добавлять ключ к индексу, стараясь избежать дублирования ключей.

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

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

Это базовая структура, которая охватывает большинство основ. Если вам не нужно удалять, жизнь проще. Посмотрите здесь лучшие примеры: Существуют ли хорошо решенные и простые шаблоны хранения для Solidity?

Вы можете использовать этот шаблон для поддержки двух списков в одном контракте. То, что вы описываете, - это соединение "один ко многим". Вероятно, вам понадобятся операции CRUD для обеих таблиц, а также способ обеспечения ссылочной целостности.

Для этого вам придется управлять двунаправленными указателями в обеих таблицах. https://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart-contracts-a9ab1427ff42

Как правильно заметил Майк. Крайне важно, чтобы вы поддерживали внутреннюю организацию, чтобы вы могли выполнять все операции без неограниченных forциклов или рекурсии. Если вы обнаружите, что просматриваете записи, это признак того, что что-то идет не так. Вы должны расположить вещи так, чтобы, например, нужная строка была известна сразу.

Надеюсь, поможет.