solidity的高阶语法4
1.提款模式
提款模式确保不会造成安全威胁的直接转接呼叫。 以下合约显示了使用转账调用发送以太币的不安全方式。
pragma solidity ^0.5.0;contract Test {address payable public richest;uint public mostSent;constructor() public payable {richest = msg.sender;mostSent = msg.value;}function becomeRichest() public payable returns (bool) {if (msg.value > mostSent) {// Insecure practicerichest.transfer(msg.value);richest = msg.sender;mostSent = msg.value;return true;} else {return false;}} }
通过使最富有的合约成为后备功能失败的合约,可以使上述合约处于不可用状态。 当后备函数失败时,becomeRichest()函数也会失败,合约将永远卡住。 为了缓解这个问题,我们可以使用 Withdrawal Pattern。
在提款模式中,我们会在每次转账前重置待处理金额。 它将确保只有调用者合约失败。
pragma solidity ^0.5.0;contract Test {address public richest;uint public mostSent;mapping (address => uint) pendingWithdrawals;constructor() public payable {richest = msg.sender;mostSent = msg.value;}function becomeRichest() public payable returns (bool) {if (msg.value > mostSent) {pendingWithdrawals[richest] += msg.value;richest = msg.sender;mostSent = msg.value;return true;} else {return false;}}function withdraw() public {uint amount = pendingWithdrawals[msg.sender];pendingWithdrawals[msg.sender] = 0;msg.sender.transfer(amount);} }
2.限制访问
限制访问合同是一种常见做法。 默认情况下,合约状态是只读的,除非将其指定为公共状态。
我们可以限制谁可以修改合约的状态或使用修饰符调用合约的函数。 我们将创建并使用多个修饰符,如下所述 −
onlyBy − 一旦用于函数,则只有提到的调用者可以调用该函数。
onlyAfter − 一旦用于函数,则可以在一定时间段后调用该函数。
costs − 一旦用于函数,则仅当提供特定值时调用者才能调用该函数。
示例
pragma solidity ^0.5.0;contract Test {address public owner = msg.sender;uint public creationTime = now;modifier onlyBy(address _account) {require(msg.sender == _account,"Sender not authorized.");_;}function changeOwner(address _newOwner) public onlyBy(owner) {owner = _newOwner;}modifier onlyAfter(uint _time) {require(now >= _time,"Function called too early.");_;}function disown() public onlyBy(owner) onlyAfter(creationTime + 6 weeks) {delete owner;}modifier costs(uint _amount) {require(msg.value >= _amount,"Not enough Ether provided.");_;if (msg.value > _amount)msg.sender.transfer(msg.value - _amount);}function forceOwnerChange(address _newOwner) public payable costs(200 ether) {owner = _newOwner;if (uint(owner) & 0 == 1) return; } }