Solidity

無法可靠地返回地址數組

  • February 3, 2022

我有一個簡單的賭博遊戲的以下程式碼。除了getPlayers函式外,程式碼工作正常

pragma solidity >=0.4.22 <0.6.0;

contract Lottery {
address payable public manager;
address payable [] public players; 

constructor () public {
   manager = msg.sender;
}
function enter() public payable {

   require(msg.value > 0.01 ether); //condition
   players.push(msg.sender);
}

function random() private view returns(uint) {
   return uint(keccak256(abi.encodePacked(block.difficulty, now, 
players)));
}

function pickWinner() public restricted{
   uint index = random() % players.length;
   players[index].transfer(address(this).balance);
   players = new address payable[](0); // new dynamic array

}

modifier restricted() {
   require(msg.sender == manager); // security
   _;
}

function getPlayers() public payable returns (address[] memory) {
   return players;
   // Error in the above line saying
   // "Return argument type address payable[] storage ref is not implicitly convertible to expected type(type of first return variable)  address[] memory."

}
}

這裡有很多問題。

我不確定pragma solidity >=0.4.22 <0.6.0;它的起源,但它被很多人接受並出現在許多例子中。問題是在連續的編譯器版本中有太多的重大變化,以至於它經常是正確的。在我看來,最好準確地指定程式碼是為哪個編譯器編寫的。

我意識到這不是您的問題,但該enter()功能的設置是為了吞下無法檢索的資金。沒有進行會計處理,也沒有檢查過多的金額(錯誤)。至少,要求精確的數量並拒絕使用者錯誤。

require(msg.value = ticketPrice);

播放器函式正在返回完整的數組。這是一種反模式,因為它會在超過塊 gasLimit 時停止工作。沒有必要實現這樣的功能。

首先,在函式中發出一個事件enter()來通知觀察者狀態發生了變化。這使得假設任何感興趣的一方已經擁有完整的玩家名單是合理的。

event LogNewPlayer(address newPlayer);

emit LogNewPlayer(playerAddress);

其次,使狀態可以以每筆交易的固定成本被發現,與規模無關。迭代應該是客戶端的關注點。如果單個交易總是以合理的成本完成,客戶可以無休止地迭代。最好有很多便宜的操作而不是一項昂貴的操作。

pragma solidity 0.5.1;

contract Lottery {

   address payable[] public players;

   // above is just enough wrapper to compiler and test these.

   function getPlayerAtIndex(uint index) public view returns(address player) {
       return players[index];
   }

   function getPlayerCount() public view returns(uint count) {
       return players.length;
   }
}

地址數組是storagereturns函式的必須是記憶體。這意味著遍歷儲存的列表並將所有數據複製到記憶體中。

一個更寬鬆的編譯器可能會讓這看起來像是一件可以做的事情。在 Solidity 5.x 中,我相信你必須明確地處理轉換,所以很明顯你知道你在做什麼。由於可擴展性問題,這將是可怕的。就像是:

function grossDoNotUse() public view returns(address[] memory) {
   address[] memory playerList;
   for(uint i=0; i<getPlayerCount(); i++) {
       playerList[i] = players[i];
   }
   return playerList;
}

不要那樣做!

希望能幫助到你。

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