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
The Fuel relayer synchronizes the Fuel L2 with Ethereum mainnet by processing deposit transactions on Ethereum once the block containing a transaction has received sufficient confirmations, currently at least 100. This enables users to receive their deposited asset on the Fuel L2 and potentially withdraw it.
This mechanism and its configuration are not safe as Ethereum mainnet can experience periods of non-finality and block confirmations do not have any bearing on whether a transaction is final. In May 2023 the beacon chain failed to finalize for 9 epochs which corresponds to 149 blocks, indicating that Fuel’s configuration may process transasctions that are subsequently reorged and allow double spending deposits.
Instead, the Fuel relayer should only make logs available to the block producer which are finalized; that is, the block is justified (it has received attestations from two-thirds validators) and is 1 epoch behind a block is also justified. Double spends would require burning of staked Ether, which is prohibitively expensive.
Ethereum blocks are considered final after two epochs. Each epoch contains 32 slots. A slot takes 12s so epoch is around 6.4min and two epochs will take 12.8min. After 13min we are sure that our deposits will not be reverted by some big reorganization. So we are okay to say that everything older [sic] then ~100blocks is finalized.
Figure 43.2: the Relayer considers non-finalized blocks as final given sufficient confirmations (fuel-core/crates/services/relayer/src/service/state.rs#71–84)
implEthHeights{/// Create a new Ethereum block height from the current/// block height and the desired finalization period.fnnew(current:u64,finalization_period:u64) -> Self{Self(Heights(
current.saturating_sub(finalization_period)..=current,))}/// Get the finalized eth block height.fnfinalized(&self) -> u64{*self.0.0.start()}}
Exploit Scenario
The Beacon Chain fails to finalize as it did in May 2023 due to a client bug or network latency. Fuel processes deposit transactions of blocks that are produced but not finalized. Some deposit transactions are reorged from Ethereum mainnet, allowing attackers to deposit again and receive twice what they deposited.
Recommendations
Short term, modify the relayer to only process logs of finalized blocks and ensure the block producer validates that it is not processing non-finalized deposit transactions.
Long term, stay up-to-date on modifications and incidents pertaining to the Ethereum consensus layer that may have an impact on the Fuel L2.
Related issues:
- Closes#1336
This PR changes the approach a Fuel node uses to determine the finalized
blocks on the Ethereum blockchain.
**The existing approach:**
- Assume a "finalization period" - a period of time after which we
assume a block is finalized. Generally, we assume a block is finalized
after 100 new blocks have been produced afterwards
- Observe what the current block height is as reported by the Ethereum
client
- Subtract the finalization period from the current height to get an
assumed finalized block, i.e. current block height - 100
The problem with this approach, as outlined by Trail of Bits, is that
finality cannot be guaranteed simply by the amount of time passed alone.
**This PR proposes a more robust approach:**
- Use the Ethereum client to query for the most recently finalized block
directly. This is done using the `Finalized` tag in the query. See
gakonst/ethers-rs#1792
This approach removes any assumption on our side as to what the
finalized block is, and gets the canonically accepted finalized block
from Ethereum.
crypto523
pushed a commit
to crypto523/fuel-core
that referenced
this issue
Oct 7, 2024
Related issues:
- ClosesFuelLabs/fuel-core#1336
This PR changes the approach a Fuel node uses to determine the finalized
blocks on the Ethereum blockchain.
**The existing approach:**
- Assume a "finalization period" - a period of time after which we
assume a block is finalized. Generally, we assume a block is finalized
after 100 new blocks have been produced afterwards
- Observe what the current block height is as reported by the Ethereum
client
- Subtract the finalization period from the current height to get an
assumed finalized block, i.e. current block height - 100
The problem with this approach, as outlined by Trail of Bits, is that
finality cannot be guaranteed simply by the amount of time passed alone.
**This PR proposes a more robust approach:**
- Use the Ethereum client to query for the most recently finalized block
directly. This is done using the `Finalized` tag in the query. See
gakonst/ethers-rs#1792
This approach removes any assumption on our side as to what the
finalized block is, and gets the canonically accepted finalized block
from Ethereum.
Description
The Fuel relayer synchronizes the Fuel L2 with Ethereum mainnet by processing deposit transactions on Ethereum once the block containing a transaction has received sufficient confirmations, currently at least 100. This enables users to receive their deposited asset on the Fuel L2 and potentially withdraw it.
This mechanism and its configuration are not safe as Ethereum mainnet can experience periods of non-finality and block confirmations do not have any bearing on whether a transaction is final. In May 2023 the beacon chain failed to finalize for 9 epochs which corresponds to 149 blocks, indicating that Fuel’s configuration may process transasctions that are subsequently reorged and allow double spending deposits.
Instead, the Fuel relayer should only make logs available to the block producer which are finalized; that is, the block is justified (it has received attestations from two-thirds validators) and is 1 epoch behind a block is also justified. Double spends would require burning of staked Ether, which is prohibitively expensive.
Figure 43.1: the finality criteria defined in the Fuel Relayer Specification
Figure 43.2: the Relayer considers non-finalized blocks as final given sufficient confirmations (fuel-core/crates/services/relayer/src/service/state.rs#71–84)
Exploit Scenario
The Beacon Chain fails to finalize as it did in May 2023 due to a client bug or network latency. Fuel processes deposit transactions of blocks that are produced but not finalized. Some deposit transactions are reorged from Ethereum mainnet, allowing attackers to deposit again and receive twice what they deposited.
Recommendations
Short term, modify the relayer to only process logs of finalized blocks and ensure the block producer validates that it is not processing non-finalized deposit transactions.
Long term, stay up-to-date on modifications and incidents pertaining to the Ethereum consensus layer that may have an impact on the Fuel L2.
References
The text was updated successfully, but these errors were encountered: