Solidity

將建構子結果推送到合約成員數組

  • February 20, 2019

我正在嘗試在 Solidity 中執行以下操作:

BetCampaign memory newCampaign = BetCampaign(id, new Bet[](0), betEndTime, false);
betCampaigns.push(newCampaign);

使用以下成員聲明:

BetCampaign[] public betCampaigns;

但我不斷收到以下錯誤:

UnimplementedFeatureError: Copying of type struct Betting.Bet memory[] memory to storage not yet supported.

我嘗試將 newCampaign 聲明更改為“儲存”而不是“記憶體”,但這也會導致錯誤。我該如何解決這個問題?

這是我正在使用的整個文件:

pragma solidity ^0.5.0;

contract Betting {

   struct Bet {
       uint betId;
       uint campaignId;
       address sender;
       uint stake;
       bool betValue;
   }

   struct BetCampaign {
       uint campaignId;
       Bet[] bets;
       mapping(address => bool) userReserved; // mapping ignored in constructor (?)
       uint betEndTime;
       bool isEnded;
   }

   event BetCampaignCreated(uint campaignId, uint betEndTime);
   event BetAdded(uint betId, uint campaignId, address indexed user, uint256 betAmount, bool betsTrue);

   BetCampaign[] public betCampaigns;
   mapping(uint => bool)  betCampaignReserved;
   mapping(uint => bool) betReserved;
   uint nonce;

   constructor() public {
       nonce = 0;
   }

   modifier isLater(uint time) {
       require(time > now, "The end time must be in the future");
       _;
   }

   modifier campaignExistsM(uint campaignId) {
       require(campaignExists(campaignId), "The campaign does not exist");
       _;
   }

   modifier userNotInCampaign(uint campaignId, address user) {
       require(!betPlaced(campaignId, user));
       _;
   }

   modifier userInCampaign(uint campaignId, address user) {
       require(betPlaced(campaignId, user));
       _;
   }

   modifier isSelf(address target) {
       require(msg.sender == target);
       _;
   }

   modifier enoughMoney(uint amount) {
       require(msg.value >= amount);
       _;
   }

   function generateId() internal returns (uint) {
       nonce += 1;
       return uint(keccak256(abi.encodePacked(nonce)));
   }

   function campaignExists(uint campaignId) internal view returns (bool) {
       return betCampaignReserved[campaignId];
   }

   function createCampaign(uint betEndTime) public isLater(betEndTime) {
       while (true) {
           uint id = generateId();
           if (!campaignExists(id)) {
               BetCampaign memory newCampaign = BetCampaign(id, new Bet[](0), betEndTime, false);
               betCampaigns.push(newCampaign);
               betCampaignReserved[id] = true;
               emit BetCampaignCreated(id, betEndTime);
               break;
           }
       }
   }

   function getCampaignInformation(uint campaignId) public view campaignExistsM(campaignId) returns (uint, uint, bool) {
       BetCampaign memory campaign;
       for (uint i = 0; i < betCampaigns.length; i++) {
           if (betCampaigns[i].campaignId == campaignId) {
               campaign = betCampaigns[i];
               break;
           }
       }
       return (campaign.campaignId, campaign.betEndTime, campaign.isEnded);
   }

   function getCampaign(uint campaignId) internal view campaignExistsM(campaignId) returns (BetCampaign storage) {
       uint index = 0;
       for (uint i = 0; i < betCampaigns.length; i++) {
           if (betCampaigns[i].campaignId == campaignId) {
               index = i;
               break;
           }
       }
       BetCampaign storage campaign = betCampaigns[index];
       return campaign;
   }

   function betExists(uint betId) internal view returns (bool) {
       return betReserved[betId];
   }

   function addBet(uint campaignId, address sender, uint stake, bool betValue)
   payable public isSelf(sender) enoughMoney(stake) campaignExistsM(campaignId) userNotInCampaign(campaignId, sender) {
       while (true) {
           uint id = generateId();
           if (!betExists(id)) {
               BetCampaign storage campaign = getCampaign(campaignId);
               campaign.bets.push(Bet(id, campaignId, sender, stake, betValue));
               campaign.userReserved[sender] = true;
               emit BetAdded(id, campaignId, sender, stake, betValue);
               break;
           }
       }
   }

   function getBet(uint campaignId, address sender)
   public view campaignExistsM(campaignId) userInCampaign(campaignId, sender) returns (uint, uint, address, uint, bool) {
       Bet memory bet;
       BetCampaign memory campaign = getCampaign(campaignId);
       for (uint i = 0; i < campaign.bets.length; i++) {
           if (campaign.bets[i].sender == sender) {
               bet = campaign.bets[i];
           }
       }
       return (bet.betId, bet.campaignId, bet.sender, bet.stake, bet.betValue);
   }

   function betPlaced(uint campaignId, address sender) public view campaignExistsM(campaignId) returns (bool) {
       BetCampaign storage campaign = getCampaign(campaignId);
       return campaign.userReserved[sender];
   }

}

的數組BetCampaign並不理想,這會很尷尬。

struct BetCampaign {
       uint campaignId;
       Bet[] bets;
       mapping(address => bool) userReserved; // mapping ignored in constructor (?)
       uint betEndTime;
       bool isEnded;
}

BetCampaign[] public betCampaigns;

您遇到了麻煩,因為您無法將在記憶體中建構的實例複製到儲存中,並且您不想建構儲存單例只是為了將其複制(推送)到數組中。這將在一次移動中使用兩次昂貴的儲存空間。

這在另一方面是次優的。包括類似的idstruct這意味著在列表中釣魚以找到匹配的。

像這樣重構來解決這兩個問題。

struct BetCampaign {
       // uint campaignId;
       Bet[] bets;
       mapping(address => bool) userReserved; // mapping ignored in constructor (?)
       uint betEndTime;
       bool isEnded;
}

// BetCampaign[] public betCampaigns;
mapping(uint => BetCampaign) public betCampaigns; // id => struct

現在,您可以在單個操作中按 ID 查找匹配的廣告系列。您還解決了令人討厭的記憶體/儲存問題,因為您將始終寫入betCampaigns[]映射中的索引。

檢查此是否有重要警告:https ://blog.b9lab.com/storage-pointers-in-solidity-7dcfaa536089

檢查此以獲取有用的模式並詳細說明所描述的解決方案:https ://medium.com/@robhitchens/solidity-crud-part-1-824ffa69509a

希望能幫助到你。

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