3

Below I extracted the logic which calls a remote contract to calculate the amount of tokens to withdraw funds.

contact Example {

  mapping (address => uint256) balances;
  ERC20 token = ...; // remote token contract
  uint256 contract_eth_value = ...;

  ...

  function () payable {
    // User's address.
    address user = msg.sender;
    // Retrieve current token balance of contract.
    // HERE !!!!!!!!!!!!!!!!!!!!!!!!!
    uint256 contract_token_balance = token.balanceOf(address(this));
    // Disallow token withdrawals if there are no tokens to withdraw.
    uint256 tokens_to_withdraw = (balances[user] * contract_token_balance) / contract_eth_value;
    // Update the value of tokens currently held by the contract.
    contract_eth_value -= balances[user];
    // Update the user's balance prior to sending to prevent recursive call.
    balances[user] = 0;
    // Send the funds.  Throws on failure to prevent loss of funds.
    if(!token.transfer(user, tokens_to_withdraw)) throw;
  }
}

I've searched solidity documentation for an answer but with no success. What I'm wondering or better what I'm afraid about is that when a call to a remote contract is executed, the contract function looses atomicity. If what I'm saying is true then the call above could lead to race conditions and thus unexpected results. This case would certainly be non-atomic in some distributed databases but I'm not sure if that also stands for Ethereum-based applications (contracts).

I would appreciate if an expert could take some time and explain this situation in details. A link to the official documentation/statement on that is also welcome.

UPDATE: I found a similar debate here

5

All transactions in Ethereum are run serially. Just one after another. Everything your transaction does, including calling from one contract to another, happens within the context of your transaction and nothing else runs until your contract is done.

So race conditions are totally not a concern. You can call balanceOf() on another contract, put the result in a local variable, and use it with no worries that the balance in the other contract will change before you're done.

  • Thanks for the answer! So you are saying that the whole Ethereum system stops and waits for a single transaction to be mined/finished? So, one transaction processing at a time, system wide? If so then I understand that the retrieved token balance in the example above will be valid. Can you confirm that? Can you please point me to some official documentation which explains the execution as you explained? Thanks! – xpepermint Sep 6 '17 at 8:00
  • 1
    Miners put transactions into blocks in whatever order they like. After blocks get valid hashes, all full nodes run the transactions in them, in the same order, one at a time. For official documentation see the white paper: github.com/ethereum/wiki/wiki/… – Dennis Peterson Sep 6 '17 at 19:18
  • And for the really official documentation see the yellow paper, which is a complete formal spec: github.com/ethereum/yellowpaper – Dennis Peterson Sep 6 '17 at 19:20
  • @DennisPeterson Instruction inside a smart contract are run serially. But can several transaction in the same block be run in parallel ? – user2284570 May 25 '18 at 15:46
  • Not with today's Ethereum, pretty much the whole point of the blockchain is to put transactions in order one after another. Each block has the transactions in a definite order. Later with sharding, the transactions within a shard will run one after another, but the different shards will run in parallel. – Dennis Peterson May 26 '18 at 20:30
4

Strictly speaking race conditions are not a problem within an Ethereum transaction: The entire transaction is atomic, no other transaction can be inserted into the control flow while it's running, and the whole thing can be rolled back on error.

You do of course need to think about race conditions between things that happen between external calls to a transaction, for example when you are checking contract state using a JavaScript app and deciding what further transactions to send based on the results.

However, what you do need to worry about is reentrancy. When you call another contract, it can do whatever it likes - including calling back into functions in your contract. Calls from contracts that your contract called all form part of the same transaction, and they can insert themselves into the control flow and cause changes to the state of your contract, before your function has finished running. See this explanation in the ConsenSys smart contract best practices document for details.

  • Instruction inside a smart contract are run serially. But can several transaction in the same block be run in parallel ? – user2284570 May 25 '18 at 15:46
  • No, transactions are run strictly in series. – Edmund Edgar May 25 '18 at 22:03
1

As others answers have correctly discussed, race conditions in individual transactions aren't a concern in Ethereum.

However, interactions with contracts that require multiple transactions are susceptible to race conditions. For example, all ERC20 tokens are vulnerable to race conditions in token price changes as well as transfers/approvals. This is because transactions are not guaranteed to be mined in the order that they are submitted to the blockchain.

The set of transactions included in a block is a function of the transactions' gas price. Moreover, miners have the freedom to order the transactions within a block however they choose. This allows an attacker to attempt to front-run a contract operation composed of multiple transactions by submitting another transaction with a high gas cost that gets mined before the target's contract operation is completed. A malicious miner can even reorder the transactions in the block to ensure that its race condition transaction is included in the correct sequence.

For more information, as well as other examples of common smart contract vulnerabilities, consult this GitHub repo:

https://github.com/trailofbits/not-so-smart-contracts/tree/master/race_condition

  • This should be the correct answer. – lllllllllllll Dec 1 '18 at 14:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.