I've come across an example of how a race condition can happen in a scenario like this that I don't understand how it could occur:
Bob creates RaceCondition(100, token). Alice trusts RaceCondition with all its tokens. Alice calls buy(150) Bob sees the transaction, and calls changePrice(300). The transaction of Bob is mined before the one of Alice and as a result, Bob received 300 tokens.
The example code has something like this:
contract RaceCondition{
address private owner;
uint public price;
ERC20 token;
function RaceCondition(uint _price, ERC20 _token)
public
{
owner = msg.sender;
price = _price;
token = _token;
}
// If the owner sees someone calls buy
// he can call changePrice to set a new price
// If his transaction is mined first, he can
// receive more tokens than excepted by the new buyer
function buy(uint new_price) payable
public
{
require(msg.value >= price);
// we assume that the RaceCondition contract
// has enough allowance
token.transferFrom(msg.sender, owner, price);
price = new_price;
owner = msg.sender;
}
function changePrice(uint new_price){
require(msg.sender == owner);
price = new_price;
}
}
However, I don't understand how a race condition can happen with the given example.
- Is the example implying that even though Bob had sent in his transaction later than Alice, Bob likely paid a higher gas fee so that his transaction gets mined before Alice's?
- If this was the case, are we assuming that Alice's and Bob's transactions are sent to the same block which could allow this to happen? But this would mean Bob has to make his transaction within split seconds right after Alice's transaction to be in the same block and also be in time enough to have his transaction mined before hers?
- The example mentioned that Bob can call
changePrice
after Alice calledbuy
to receive more tokens than expected. But I don't see how this can happen:- Assuming Bob managed to get his call to
changePrice(300)
to be locked in before Alice'sbuy(150)
call, Alice'sbuy(150)
call would throw exception becauserequire(msg.value >= price);
would return false, wouldn't it? I.e.,150 >= 300
is false, hence, reverts, wouldn't it?
- Assuming Bob managed to get his call to