Solidity

返回反映結構關聯之間全域狀態的映射數組?

  • February 20, 2019

我正在尋找一種類似於“返回鍵值對列表”的構造,我認為它可以作為映射數組來實現。是對的嗎?

也就是說,我想要一個包含 (key,value) 列表的資料結構,我將使用它作為全域狀態,將一些結構連結到另一個結構。

我的意思是這樣的:

// so I have place structs
struct Place {
 uint8 placeid;
 string nameOfPlace;
 ...etc
}

// and a place can contain no more than 1 banner.    
// banners have all been to a place, but they aren't necessarily
// in a place right now. They may have been replaced with another 
// banner.
struct Banner {
 uint8 bannerid;
 uint8 placeAt; // this must match a placeid
 string thingTheBannerSays;
 uint8 timestamp;
}

Place[] places;                        // list all places
mapping(uint8 => Place)  placesById    // given an id, return the place
Banner[] banners;
mapping(uint8 => Banner)  bannersById  // given an id, return the place

// what's missing for me is a data structure
// with global state of [(place0,bannerN),(place1,bannerM)] 
// for all places.  This is what I'm looking for.

function listBannersAtPlacesRightNow() returns (???? arrayOfMappings) {
 ??? mappings[] = arrayOfMappings
 for(uint8 i =0; i < places.length; i++) {
    maxTime[i] = 0;       // declare this correctly
    idWhereMaxTime[i] = 0; // gross, would rather be null
    for(uint8 j=0; j < banners.length; j++) {
       if(banners[j].timestamp > maxTime[i]) {
         maxTime[i] = banners[j].timestamp // high water ;
         idWhereMaxTime[i] = banners[j];
       }
      }
    arrayOfMappings[i] = (places[i], idWheremaxTime[i]);
  }
return arrayOfMappings;
}

抱歉,我對此很陌生,但如果不清楚,換句話說,我想要一些變數來維持全域狀態,即“我是一個地方,我可以有 0 或 1 個橫幅。這是一個列表“

醜陋的準蟒蛇可能會澄清醜陋的準堅固性,這將是這樣的:

places = [{"placeid": 0, "nameofplace": "home"}, {"placeid":1, "nameofplace": "center"}]

banners = [
{"bannerid": 0, "placeAt": 0, "thingthebannersays": "hello!"},
{"bannerid": 1, "placeAt": 0, "thingthebannersays": "hello again from home!"},
{"bannerid": 2, "placeAt": 0, "thingthebannersays": "this replaces 1!"},
{"bannerid": 3, "placeAt": 1, "thingthebannersays": "this is at center!"}]

bannerAtPlaces = [(0,2), #place 0 has current banner 2
                 (1,3)  #place 1 has banner 3
]

def setBannerAtPlaces(placeid, bannerid):
 # this updates bannerAtPlaces according to some rules
 # such as the most-recent timestamp given in the solidity
 # section

# BUT If I wanted to see which places contained which banners, I'd just
# print(bannerAtPlaces).  This is the call I'm looking to repeat
# in solidity.

這一切都出現了,因為我寧願讓 Place 的結構包含一個用於bannerid 的欄位,但不幸的是,我希望 Place 能夠擁有 0 個橫幅,而且看起來我無法為此初始化 null —我必須預設為bannerid = 0. 但是bannerid==0是一個真正的bannerid。它不能同時出現在兩個地方,它已經在其他地方,並且不能成為所有新地方的橫幅的預設設置。

指定全域狀態的列表的原因是為了在瀏覽器中輕鬆呈現它,作為顯示所有 (Place, Banner) 對的畫廊。

我現在在這裡看到一個類似的問題

我不太確定你描述的基數。我選擇了“橫幅一次只能出現在一個地方,而一個地方要麼有或沒有正好有 1 個橫幅。”

for循環是 Solidity 中的嚴重問題。我們需要組織資料結構,以便我們可以在任何規模上以一致的 gas 成本完成所有事情 - O(1)。看到這個:https ://blog.b9lab.com/getting-loopy-with-solidity-1d51794622ad

我不認為你需要一對多的加入,但如果你確實看看這個想法:https ://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart-契約-a9ab1427ff42

該連結有點讓您陷入困境。它連結到 CRUD 系列,該系列解釋了我用來繪製這個快速草圖的模式:

pragma solidity 0.4.25;

contract Banners {

   struct BannerStruct {
       string marque;
       bytes32 placeId; // 0 or 1 placeId
       uint idPointer;
   }

   struct PlaceStruct {
       string name;
       bytes32 bannerId; // 0 or 1 bannerId
       uint idPointer;
   }

   mapping(bytes32 => BannerStruct) public bannerStructs;
   mapping(bytes32 => PlaceStruct) public placeStructs;

   bytes32[] public bannerIdList;
   bytes32[] public placeIdList;

   function getBannerCount() public view returns(uint) {
       return bannerIdList.length;
   }

   function getPlaceCount() public view returns(uint) {
       return placeIdList.length;
   }

   function isBanner(bytes32 bannerId) public view returns(bool) {
       if(bannerIdList.length==0) return false; // there aren't any, so false
       return bannerIdList[bannerStructs[bannerId].idPointer] == bannerId;
   }

   function isPlace(bytes32 placeId) public view returns(bool) {
       if(placeIdList.length==0) return false;
       return placeIdList[placeStructs[placeId].idPointer] == placeId;
   }

   function placeHasBanner(bytes32 placeId) public view returns(bool) {
       return isBanner(placeStructs[placeId].bannerId);
   }

   function newBanner(bytes32 bannerId, string marque) public returns(bool) {
       require(!isBanner(bannerId)); // no dups
       bannerStructs[bannerId].marque = marque;
       bannerStructs[bannerId].idPointer = bannerIdList.push(bannerId) - 1;
       return true;
   }

   function newPlace(bytes32 placeId, string name) public returns(bool) {
       require(!isPlace(placeId));
       placeStructs[placeId].name = name;
       placeStructs[placeId].idPointer = placeIdList.push(placeId) - 1;
       return true;
   }

   function setPlaceBanner(bytes32 placeId, bytes32 bannerId) public returns(bool) {
       require(isPlace(placeId));
       require(isBanner(bannerId));
       if(bannerStructs[bannerId].placeId != 0) { // moving it. A banner can only be in one place???
           bytes32 oldPlace = bannerStructs[bannerId].placeId;
           placeStructs[oldPlace].bannerId = bytes32(0);
       }
       bannerStructs[bannerId].placeId = placeId;
       placeStructs[placeId].bannerId = bannerId;
   }
}

當您繼續往下看時,您還會發現您可能希望減少儲存在鏈上的元數據量。出於這個原因,我的結構很稀疏。https://blog.b9lab.com/the-joy-of-minimalism-in-smart-contract-design-2303010c8b09

希望能幫助到你。

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