Solidity
無法可靠地返回地址數組
我有一個簡單的賭博遊戲的以下程式碼。除了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; } }
地址數組是
storage
但returns
函式的必須是記憶體。這意味著遍歷儲存的列表並將所有數據複製到記憶體中。一個更寬鬆的編譯器可能會讓這看起來像是一件可以做的事情。在 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; }
不要那樣做!
希望能幫助到你。