Security

什麼是擊敗搶先攻擊的“預送出”方案?

  • August 11, 2020

我寫信是為了詢問可行的策略來解決事務排序依賴 (TOD) 錯誤。

我從最佳實踐指南中了解到,我們可以使用所謂的“預送出”方案來擊敗 TOD 攻擊:https ://consensys.github.io/smart-contract-best-practices/known_attacks/#front-執行-又名-事務-排序-依賴

但是,我仍然不清楚“預先承諾”方案是如何實施的。任何人都可以闡明這種實現的一些亮點或一些程式碼片段嗎?另外,除了這種“預先承諾”的方案,還有什麼辦法可以打敗 TOD 攻擊呢?

========更新=====================

contract TransactionOrdering { 
uint256 price; address owner; 

function buy(uint256 amount) {
  cost = price * amount       
  return cost;                
}                             

 function setPrice(uint256 _price) {
   // owner can set the price.      
   if (msg.sender == owner)         
     price = _price;                
 }                                  
}                                    

假設當合約所有者看到buy使用者的一筆交易時,合約所有者會在前端執行一筆setPrice交易以提高價格。可以使用該pre-committed模式來擊敗此類攻擊嗎?非常感謝。

假設您有一個抽獎活動並且可以預訂一個號碼

contract Raffle {
   mapping(uint256 => address) reserved;

   event Reserved(uint256 value, address owner);

   function reserve(uint256 value) public {
       require(reserved[value] == address(0), "Already reserved");
       reserved[value] = msg.sender;
       emit Reserved(value, msg.sender);
   }
}

該合約受搶先交易影響。如果您保留編號 42,任何人都可以在您的交易被探勘之前看到它。惡意行為者可以送出一筆交易,以更高的汽油價格保留相同數量的交易,並使您的保留失敗。

一個常見的解決方案是首先送出雜湊而不是您的數據。在第二步中,您將揭示產生已送出雜湊的數據。

  1. 通過使用隨機 nonce、值和地址呼叫摘要函式來計算您的雜湊值。隨機數是為了防止攻擊者使用蠻力嘗試從雜湊中獲取您的值。
  2. 將計算出來的雜湊發送給合約。由於承諾是由使用者儲存的,攻擊者可以發送相同的散列,但不會阻止合法使用者註冊散列。
  3. 致電reveal以顯示您的數據並進行預訂。這裡所有的數據都可供攻擊者使用,但它在這個階段無法進行保留,並且暴力破解先前保留的雜湊應該是不可行的。

.

contract Raffle {

   mapping(address => bytes32) commitments;
   mapping(uint256 => address) reserved;

   event Reserved(uint256 value, address owner);

   function commit(bytes32 hash) public {
       require(commitments[msg.sender] == bytes32(0), "Already committed");
       commitments[msg.sender] = hash;
   }

   function reveal(uint256 nonce, uint256 value) public {
       bytes32 d = digest(nonce, value, msg.sender);
       require(commitments[msg.sender] == d, "Invalid data");
       require(reserved[value] == address(0), "Already reserved");
       reserved[value] = msg.sender;
       emit Reserved(value, msg.sender);
   }

   function digest(uint256 nonce, uint256 value, address sender) public pure returns (bytes32) {
       return keccak256(abi.encodePacked(nonce, value, sender));
   }
}

引用自:https://ethereum.stackexchange.com/questions/73570