https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/提供了一个与使用Reentrancy Guard相关的简单示例。
另一种防止重入的方法是显式检查和拒绝此类调用。下面是可重入守卫的一个简单版本,您可以看到这个想法:
contract Guarded {
...
bool locked = false;
function withdraw() external {
require(!locked, "Reentrant call detected!");
locked = true;
... // Multiple Payments
locked = false;
}
}但是在这里,我认为还有另一个问题,如果检测到重入调用,withdraw()函数将被返回,而locked仍然是true。因此,我们将无法在进一步的调用中重新输入withdraw()函数,因为locked仍然是true。
问:在锁之间多付不同的费用安全吗?一个例子如下:
contract Guarded {
...
bool locked = false;
function withdraw() external {
require(!locked, "Reentrant call detected!");
locked = true;
// Payment-1
(bool success, ) = msg.sender.call.value(balanceOfPayment1[msg.sender])("");
require(success, "Transfer failed.");
balanceOfPayment1[msg.sender] = 0;
// Payment-2
(bool success, ) = msg.sender.call.value(balanceOfPayment2[msg.sender])("");
require(success, "Transfer failed.");
balanceOfPayment2[msg.sender] = 0;
locked = false;
}
}发布于 2020-01-03 01:13:19
不是的。
您的互斥锁(locked)将阻止重新进入,但重入并不是唯一的漏洞。
DoS是可能的,它可能不是故意的。
这一行,付款后2:
require(success, "Transfer failed.");
您是否考虑过,如果交易在此阶段中止,付款1将不会发生?这意味着,除非player1合作,否则player2是不会得到报酬的。
许多开发人员认为不能拒绝付款,这样做是不可取的,因此很可能不会发生这种情况,但这些假设会给您带来麻烦。
transfer.中,即.call。在没有解释的情况下,合同要做的最安全的事情就是还原,这样做可能会使整个事务恢复正常。如果任何一个transfers失败,您的函数将完全恢复整个事务(都是transfer )。建议采用退出模式。也就是说,进行会计核算,让用户通过为此目的建立的函数来申请他们的资金。这样,每个交互中只有一个“不受信任”的参与者,即msg.sender。这样做可以将关注点分开,这样他们就更不可能互相干涉。
为了清晰。锁应该完成它的工作,即防止重新进入,但是单个事务中的多个传输是一个错误的方向,因为它会带来相当大的风险。
希望能帮上忙。
https://ethereum.stackexchange.com/questions/78675
复制相似问题