On XDPoS v2, a block is final when the 3-chain commit rule commits it: a quorum certificate (QC) certifies a block whose parent and grandparent come from the two rounds just before it, and then the grandparent is committed. xOneRS exposes that point in two ways: the finalized block tag, which returns the latest committed block, and eth_getBlockFinalityByNumber, which returns 100 for a committed block. An exchange or a bridge should wait for one of these, not for a fixed number of blocks, because a timeout round delays the commit.

For what a QC and a timeout are, see QC, TC and timeouts. For what happens to transactions when a branch is dropped, see reorgs and the transaction pool.

When is an XDPoS v2 block final?

The commit rule in spec/consensus/v2-commit.md, from geth-XDC engine_v2/utils.go:530-598:

  1. A QC certifies block B.
  2. P is the parent of B and G its grandparent. round(P) must be round(B) - 1 and round(G) must be round(B) - 2.
  3. If they are, and nothing at or above G is committed already, G is committed and becomes the highest committed block.

Three blocks of three consecutive rounds are needed. A timeout between them breaks the chain, and the rule waits for the next three consecutive rounds. Blocks up to two after the V2 switch block commit nothing.

How do I read finality from xOne?

REFERENCE TABLEScroll to explore all columns →
Method What it returns Source
finalized block tag (for example eth_getBlockByNumber("finalized", false)) the latest QC-committed V2 block; an error finalized block not found before the first commit; never the head types.rs resolve_tag
safe block tag an error safe block not found: XDPoS never sets a safe block same
eth_getBlockFinalityByNumber / ByHash 100 for a canonical V2 block at or below the committed block; otherwise the signer share len(signers) * 100 / len(masternodes) (integer division); 0 for an unknown block xdc-eth-extensions.md

The finalized tag follows geth-XDC: its commit hook sets the finalized block to the latest V2 committed block (eth/backend.go:433-436). Before PR #353 (merged 2026-11-14), xOneRS answered finalized with the head, which could overstate finality; the v0.1.0 release has that older behaviour.

The XDPoS_* methods are different: their block parameters accept finalized but treat it as the head (xdpos-namespace.md). Do not use an XDPoS_* call to read finality.

How many confirmations should an exchange wait for?

Wait until the deposit block is at or below the finalized block, or until eth_getBlockFinalityByNumber returns 100 for it. The spec defines finality by the commit rule, not by a block count: when no round times out, the committed block is two blocks below the certified block, and each timeout round adds a wait for the next three consecutive rounds. On net2040, 379 of 933 epochs had at least one round that made no block (epoch lengths), so timeouts are common enough to matter.

What can still change below the head?

Blocks above the committed block can be replaced. A one-block reorg is normal on XDPoS v2 when a round times out (the reorg post-mortem). xOneRS refuses to reorg below the committed block: the test deep_reorg_below_the_committed_block_is_refused in crates/xone-sync/tests/chain.rs checks it.

The collected competitor articles state no claim about XDPoS finality, so this post has no comparison table.

Frequently asked questions

Which RPC call tells me a block on XDC is final?

eth_getBlockByNumber("finalized", false) returns the latest committed block, and eth_getBlockFinalityByNumber(n) returns 100 when block n is committed. Both are served by xOneRS on main.

Is a fixed number of confirmations safe on XDC?

The commit rule does not use a fixed count: it needs three blocks of consecutive rounds, and a timeout round delays it. Read the finalized block instead of counting.

Why does safe return an error?

XDPoS never sets a safe block. geth-XDC answers safe block not found, and xOneRS does the same.

Can a finalized block be reverted?

xOneRS refuses a reorg below the committed block, and a test covers that rule.

Sources