Solidity
msg.sender.call() 在 Solidity 中做了什麼?
您好正在瀏覽solidity文件。有一些我無法理解的程式碼,即使經過大量研究,我也無法找到一些令人滿意的輸出。程式碼如下:
contract Mutex { bool locked; modifier noReentrancy() { require(!locked); locked = true; _; locked = false; } /// This function is protected by a mutex, which means that /// reentrant calls from within `msg.sender.call` cannot call `f` again. /// The `return 7` statement assigns 7 to the return value but still /// executes the statement `locked = false` in the modifier. function f() public noReentrancy returns (uint) { require(msg.sender.call()); return 7; } }
有什麼
msg.sender.call()
作用?又來電f()
了?如果是,那怎麼辦?
它呼叫匿名回退函式
msg.sender
。在典型的重入攻擊中,它就像一個
withdraw
函式在做msg.sender.call.value(1 ether)()
. 然後呼叫者(智能合約)將再次呼叫該函式,因此是“重入”攻擊。在這個片段中,call
似乎沒有做任何有用的事情,但它只是為了表明locked
變數可以防止重入。
msg.sender.call()
在上呼叫回退函式msg.sender
。這是一個使用
canBeAttacked
函式擴展的範例。contract Mutex { bool locked; modifier noReentrancy() { require(!locked); locked = true; _; locked = false; } function canBeAttacked() public returns (uint) { require(msg.sender.call.value(1 ether)()); return 7; } /// This function is protected by a mutex function f() public noReentrancy returns (uint) { require(msg.sender.call()); return 7; } }
從上面的程式碼中需要注意的兩件事。
- 攻擊者可以創建具有回退的合約
的:
// attacker fallback function() { Mutex(msg.sender).canBeAttacked(); }
合約可以有另一個呼叫 的函式,
canBeAttacked()
這將不斷重新進入canBeAttacked()
並每次向攻擊者發送 1 個乙太幣。(回退需要更多程式碼來避免無限循環和耗盡gas。)這是一個可重入攻擊的例子。現在想像一個攻擊者合約有一個備份:
// attacker fallback function() { Mutex(msg.sender).f(); }
- 當攻擊者呼叫
f()
時,攻擊者回退將失敗,因為locked
istrue
,所以require(!locked)
會產生異常並恢復整個事務。另請注意,這
noReentrancy
可以防止攻擊者呼叫f()
並在攻擊者的備份中呼叫canBeAttacked
. (但他們可以像上面的#1一樣攻擊。)