Explorar o código

[entropy] audit 4. users can influence the Entropy revealed result (#1179)

* add a check for blockhash

* add comment

* update test name

* comment update

* change block number

* change order for assertions

* pre commit run

* names and comments
Dev Kalra hai 1 ano
pai
achega
5d951ee755

+ 12 - 1
target_chains/ethereum/contracts/contracts/entropy/Entropy.sol

@@ -259,7 +259,18 @@ abstract contract Entropy is IEntropy, EntropyState {
 
         bytes32 blockHash = bytes32(uint256(0));
         if (req.useBlockhash) {
-            blockHash = blockhash(req.blockNumber);
+            bytes32 _blockHash = blockhash(req.blockNumber);
+
+            // The `blockhash` function will return zero if the req.blockNumber is equal to the current
+            // block number, or if it is not within the 256 most recent blocks. This allows the user to
+            // select between two random numbers by executing the reveal function in the same block as the
+            // request, or after 256 blocks. This gives each user two chances to get a favorable result on
+            // each request.
+            // Revert this transaction for when the blockHash is 0;
+            if (_blockHash == bytes32(uint256(0)))
+                revert EntropyErrors.BlockhashUnavailable();
+
+            blockHash = _blockHash;
         }
 
         randomNumber = combineRandomValues(

+ 75 - 0
target_chains/ethereum/contracts/forge-test/Entropy.t.sol

@@ -405,6 +405,81 @@ contract EntropyTest is Test, EntropyTestUtils {
             true
         );
 
+        vm.roll(1235);
+        assertRevealSucceeds(
+            user2,
+            provider1,
+            sequenceNumber,
+            42,
+            provider1Proofs[sequenceNumber],
+            blockhash(1234)
+        );
+    }
+
+    function testNoCheckOnBlockNumberWhenNoBlockHashUsed() public {
+        vm.roll(1234);
+        uint64 sequenceNumber = request(user2, provider1, 42, false);
+
+        vm.roll(1236);
+        assertRevealSucceeds(
+            user2,
+            provider1,
+            sequenceNumber,
+            42,
+            provider1Proofs[sequenceNumber],
+            ALL_ZEROS
+        );
+
+        vm.roll(1234);
+        sequenceNumber = request(user2, provider1, 42, false);
+
+        vm.roll(1234);
+        assertRevealSucceeds(
+            user2,
+            provider1,
+            sequenceNumber,
+            42,
+            provider1Proofs[sequenceNumber],
+            ALL_ZEROS
+        );
+
+        vm.roll(1234);
+        sequenceNumber = request(user2, provider1, 42, false);
+
+        vm.roll(1234 + 257);
+        assertRevealSucceeds(
+            user2,
+            provider1,
+            sequenceNumber,
+            42,
+            provider1Proofs[sequenceNumber],
+            ALL_ZEROS
+        );
+    }
+
+    function testCheckOnBlockNumberWhenBlockHashUsed() public {
+        vm.roll(1234);
+        uint64 sequenceNumber = request(user2, provider1, 42, true);
+
+        vm.roll(1234);
+        assertRevealReverts(
+            user2,
+            provider1,
+            sequenceNumber,
+            42,
+            provider1Proofs[sequenceNumber]
+        );
+
+        vm.roll(1234 + 257);
+        assertRevealReverts(
+            user2,
+            provider1,
+            sequenceNumber,
+            42,
+            provider1Proofs[sequenceNumber]
+        );
+
+        vm.roll(1235);
         assertRevealSucceeds(
             user2,
             provider1,

+ 2 - 1
target_chains/ethereum/contracts/forge-test/EntropyGasBenchmark.t.sol

@@ -107,8 +107,9 @@ contract EntropyGasBenchmark is Test, EntropyTestUtils {
 
     function testBasicFlow() public {
         uint userRandom = 42;
+        vm.roll(10);
         uint64 sequenceNumber = requestHelper(user1, userRandom, true);
-
+        vm.roll(12);
         revealHelper(sequenceNumber, userRandom);
     }
 }

+ 2 - 0
target_chains/ethereum/entropy_sdk/solidity/EntropyErrors.sol

@@ -22,4 +22,6 @@ library EntropyErrors {
     error InvalidUpgradeMagic();
     // The msg.sender is not allowed to invoke this call.
     error Unauthorized();
+    // The blockhash is 0.
+    error BlockhashUnavailable();
 }