Solidity

每個地址的項目列表

  • January 10, 2020

我正在開發一個 dApp,我正在嘗試解決以下問題。我想將地址映射到我的一份契約中的動態項目列表。這樣,當使用者登錄時,他/她就有了自己的項目列表(有點像 cryptokittens 的工作方式,對於每個地址,您都可以擁有該地址的小貓列表)。我的問題是:我可以做這個映射嗎?是不是很糟糕/沒有效率?有人告訴我,我真的不知道如何有效地做到這一點。與我一起工作的一些人建議將此資訊放在鏈下。這是正確的方法嗎?我寧願一切都在鏈上。

謝謝

這在某種程度上效率不高,您必須呼叫使用者擁有的每個項目,因為目前您無法以可靠的方式返回結構列表。但是您可以輕鬆地返回屬於使用者的項目的 id 列表,然後獲取有關這些項目的資訊(不幸的是,也是一項一項)。但是由於這個返回項目資訊的函式是“查看”函式,所以它們不會花費任何氣體。如果使用者沒有數十或數百個項目,我認為這不是問題。

下面的程式碼只是一個例子,它缺乏安全邏輯(任何人都可以呼叫任何函式)

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循環或遞歸的情況下完成所有操作。如果您發現自己在循環瀏覽記錄,則表明事情偏離了軌道。例如,您必須安排事情以便立即知道所需的行。

希望能幫助到你。

引用自:https://ethereum.stackexchange.com/questions/45809