_Follow along with this video:_ --- ### Denial of Service Let's dive right in and take a look at the DoS contract brought up in our [**Remix**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/denial-of-service/DoS.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js) example. <details open> <summary>DoS Contract</summary> ```js // SPDX-License-Identifier: MIT pragma solidity 0.8.20; contract DoS { address[] entrants; function enter() public { // Check for duplicate entrants for (uint256 i; i < entrants.length; i++) { if (entrants[i] == msg.sender) { revert("You've already entered!"); } } entrants.push(msg.sender); } } ``` </details> We can see right away that this `enter` function is doing something very similar to what we saw in `PuppyRaffle::enterRaffle`. Every time someone calls this function, it checks for a duplicate in the `entrants` array, and if one isn't found `msg.sender` is added to `entrants`. The problem arises when the size of our `entrants` array grows. Every time someone is added to the `entrants` array, another loop is added to the duplicate check and as a result `more gas is consumed`. ### Remix Example We can see this in action by deploying our contract on Remix and comparing the gas consumed when we call this function subsequent times (remember, you'll need to switch your address being used). Here's what it looks like for the first four people calling the `enter` function. ::image{src='/security-section-4/11-exploit-denial-of-service/exploit-denial-of-service1.png' style='width: 75%; height: auto;'} This kind of behavior raises questions about fairness and ultimately is going to lead to a `denial of service` in that it will become impractical for anyone to interact with this function, because gas costs will be too high. ### Exploring DoS attack in Foundry Conveniently, if you clone the [**sc-exploits-minimized**](https://github.com/Cyfrin/sc-exploits-minimized) repo. I've included a test suite to illustrate these attack vectors as well. ```bash git clone https://github.com/Cyfrin/sc-exploits-minimized cd sc-exploits-minimized make ``` The above series of commands will clone the repo and build it locally. Once this is done, I want to draw you attention to `/test/unit/DoSTest.t.sol` To summarize, this test deploys the same `DoS` contract we've been looking at: ```js function setUp() public { dos = new DoS(); } ``` Calls the `enter` function and records the gas costs of those calls: ```js vm.prank(warmUpAddress); dos.enter(); uint256 gasStartA = gasleft(); vm.prank(personA); dos.enter(); uint256 gasCostA = gasStartA - gasleft(); uint256 gasStartB = gasleft(); vm.prank(personB); dos.enter(); uint256 gasCostB = gasStartB - gasleft(); uint256 gasStartC = gasleft(); vm.prank(personC); dos.enter(); uint256 gasCostC = gasStartC - gasleft(); ``` And finally prints the gas costs and asserts that each call is more expensive than the last: ```js console2.log("Gas cost A: %s", gasCostA); console2.log("Gas cost B: %s", gasCostB); console2.log("Gas cost C: %s", gasCostC); assert(gasCostC > gasCostB); assert(gasCostB > gasCostA); ``` If we run this test with `forge test --mt test_denialOfService -vvv` we see that the test indeed passes and we get a print out corroborating the vulnerability! ::image{src='/security-section-4/11-exploit-denial-of-service/exploit-denial-of-service2.png' style='width: 75%; height: auto;'} I challenge you to play with this test a little bit and customize it. See if you can adjust it to print out the gas costs with 1000 entrants! ### Wrap Up As can be seen, DoS attacks can be very impactful for a protocol. They can inject unfairness and cause interactions to be prohibitively expensive. In our next lesson, we'll be looking at a case study of one such attack.
Explore a DoS attack using a minimalistic DOS contract. Learn how loops and arrays can make a protocol unusable.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Solidity Developer
Smart Contract SecurityDuration: 25min
Duration: 1h 18min
Duration: 35min
Duration: 2h 28min
Duration: 5h 03min
Duration: 5h 22min
Duration: 4h 33min
Duration: 2h 01min
Duration: 1h 40min
Testimonials
Read what our students have to say about this course.
Chainlink
Chainlink
Gustavo Gonzalez
Solutions Engineer at OpenZeppelin
Francesco Andreoli
Lead Devrel at Metamask
Albert Hu
DeForm Founding Engineer
Radek
Senior Developer Advocate at Ceramic
Boidushya
WalletConnect
Idris
Developer Relations Engineer at Axelar