You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/known_attacks.md
+46Lines changed: 46 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -344,6 +344,52 @@ This attack [was conducted](https://osolmaz.com/2018/10/18/anatomy-block-stuffin
344
344
345
345
A Block Stuffing attack can be used on any contract requiring an action within a certain time period. However, as with any attack, it is only profitable when the expected reward exceeds its cost. Cost of this attack is directly proportional to the number of blocks which need to be stuffed. If a large payout can be obtained by preventing actions from other participants, your contract will likely be targeted by such an attack.
346
346
347
+
## Insufficient gas griefing
348
+
349
+
This attack may be possible on a contract which accepts generic data and uses it to make a call another contract (a 'sub-call') via the low level `address.call()` function, as is often the case with multisignature and transaction relayer contracts.
350
+
351
+
If the call fails, the contract has two options:
352
+
353
+
1. revert the whole transaction
354
+
2. continue execution.
355
+
356
+
Take the following example of a simplified `Relayer` contract which continues execution regardless of the outcome of the subcall:
357
+
358
+
```sol
359
+
contract Relayer {
360
+
mapping (bytes => bool) executed;
361
+
362
+
function relay(bytes _data) public {
363
+
// replay protection; do not call the same transaction twice
This contract allows transaction relaying. Someone who wants to make a transaction but can't execute it by himself (e.g. due to the lack of ether to pay for gas) can sign data that he wants to pass and transfer the data with his signature over any medium. A third party "forwarder" can then submit this transaction to the network on behalf of the user.
372
+
373
+
If given just the right amount of gas, the `Relayer` would complete execution recording the `_data`argument in the `executed` mapping, but the subcall would fail because it received insufficient gas to complete execution.
374
+
375
+
Note: When a contract makes a sub-call to another contract, the EVM limits the gas forwarded to [to 63/64 of the remaining gas](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md),
376
+
377
+
An attacker can use this to censor transactions, causing them to fail by sending them with a low amount of gas. This attack is a form of "[griefing](https://en.wikipedia.org/wiki/Griefer)": It doesn't directly benefit the attacker, but causes grief for the victim. A dedicated attacker, willing to consistently spend a small amount of gas could theoretically censor all transactions this way, if they were the first to submit them to `Relayer`.
378
+
379
+
One way to address this is to implement logic requiring forwarders to provide enough gas to finish the subcall. If the miner tried to conduct the attack in this scenario, the `require` statement would fail and the inner call would revert. A user can specify a minimum gasLimit along with the other data (in this example, typically the `_gasLimit` value would be verified by a signature, but that is ommitted for simplicity in this case).
380
+
381
+
```
382
+
// contract called by Relayer
383
+
contract Executor {
384
+
function execute(bytes _data, uint _gasLimit) {
385
+
require(gasleft() >= _gasLimit);
386
+
...
387
+
}
388
+
}
389
+
```
390
+
391
+
Another solution is to permit only trusted accounts to mine the transaction.
0 commit comments