0
0
Blockchain / Solidityprogramming~20 mins

Reentrancy guard pattern in Blockchain / Solidity - Practice Problems & Coding Challenges

Choose your learning style9 modes available
Challenge - 5 Problems
🎖️
Reentrancy Guard Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
Predict Output
intermediate
2:00remaining
What is the output of this Solidity contract call?

Consider this simplified Solidity contract using a reentrancy guard. What will be the value of counter after calling increment() once?

Blockchain / Solidity
pragma solidity ^0.8.0;

contract ReentrancyGuard {
    bool private locked;
    uint public counter;

    modifier noReentrant() {
        require(!locked, "No reentrancy");
        locked = true;
        _;
        locked = false;
    }

    function increment() public noReentrant {
        counter += 1;
        if(counter < 3) {
            increment();
        }
    }
}
AThe call will revert with "No reentrancy" error
Bcounter will be 3
Ccounter will be 2
Dcounter will be 1
Attempts:
2 left
💡 Hint

Think about what happens when the function calls itself recursively with the reentrancy guard active.

🧠 Conceptual
intermediate
1:30remaining
Why is a reentrancy guard important in smart contracts?

Which of the following best explains why a reentrancy guard is used in smart contracts?

ATo increase the speed of contract execution by caching results
BTo allow the contract to call external contracts safely
CTo stop a function from being called again before the first call finishes, avoiding unexpected state changes
DTo prevent multiple users from calling the contract at the same time
Attempts:
2 left
💡 Hint

Think about what happens if a function changes state and then calls an external contract that calls back before the first call finishes.

🔧 Debug
advanced
2:00remaining
Identify the bug in this reentrancy guard implementation

What is wrong with this reentrancy guard modifier?

Blockchain / Solidity
modifier noReentrant() {
    require(!locked, "No reentrancy");
    _;
    locked = true;
}
AThe modifier does not check the <code>locked</code> variable at all
BThe <code>locked</code> variable is never set to false, so the guard locks forever
CThe <code>require</code> condition is reversed, allowing reentrancy
DThe modifier sets <code>locked</code> before the function body, which is incorrect
Attempts:
2 left
💡 Hint

Look at when locked is set to true and if it ever resets.

📝 Syntax
advanced
1:30remaining
Which option correctly implements a reentrancy guard modifier in Solidity?

Choose the correct Solidity code for a reentrancy guard modifier that prevents reentrant calls.

A
modifier noReentrant() {
    require(!locked, "No reentrancy");
    locked = true;
    _;
    locked = false;
}
B
modifier noReentrant() {
    locked = true;
    require(!locked, "No reentrancy");
    _;
    locked = false;
}
C
modifier noReentrant() {
    require(locked, "No reentrancy");
    locked = true;
    _;
    locked = false;
}
D
modifier noReentrant() {
    require(!locked, "No reentrancy");
    _;
    locked = true;
    locked = false;
}
Attempts:
2 left
💡 Hint

The guard must check locked before setting it to true and running the function body.

🚀 Application
expert
2:30remaining
How many times will the fallback function be called in this contract during a reentrant attack?

Given this contract snippet, how many times will the fallback function be called if an attacker tries to reenter during withdraw()?

Blockchain / Solidity
pragma solidity ^0.8.0;

contract Vulnerable {
    mapping(address => uint) public balances;
    bool private locked;

    modifier noReentrant() {
        require(!locked, "No reentrancy");
        locked = true;
        _;
        locked = false;
    }

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint amount) public noReentrant {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        balances[msg.sender] -= amount;
    }

    fallback() external payable {
        if (balances[msg.sender] > 0) {
            withdraw(balances[msg.sender]);
        }
    }
}
AThe fallback function will be called multiple times until the balance is zero
BThe fallback function will cause an infinite loop and run forever
CThe fallback function will never be called due to the reentrancy guard
DThe fallback function will be called exactly once
Attempts:
2 left
💡 Hint

Consider how the noReentrant modifier affects the recursive call inside fallback().