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 practice richest.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; } }