On Apothem, a few XDC accounts hold more than 2^256 - 1 wei. xOneRS keeps the full value in the account leaf and in a side map, and it shows the EVM only the value modulo 2^256. This is the rule that geth-XDC follows.

This post describes main of xOneRS today. Sources: the wide-balance spec, the proof document, issue #7 and PR #606.

Why can XDC state hold a balance above 2^256?

geth-XDC stores two values for an account. One is the balance wrapped to 256 bits. The other is the true integer, kept only when it is above 2^256 - 1.

The spec states the rule. The EVM sees the balance modulo 2^256 and the account leaf carries the true integer. Gas purchase follows core/state_transition.go:497-557 (buyGas). CanTransfer is true for a wide sender (core/evm.go:156). The issue adds the pinned geth-XDC definition of the two fields (core/types/state_account.go:36-46).

How does an account get that large? The spike report says it needs an account that already holds about 2^256. The nine Apothem genesis accounts hold 2^256 - 1 each. The report lists two Apothem accounts that were wide at block 85,227,570. One holds 2.9363 x 2^256. A unit test in crates/xone-consensus/tests/reward_penalty.rs shows a reward pushing a genesis-funded account over the line.

The spike report finds no wide account on net2040 at block 730,247. For mainnet it uses a supply argument: genesis supply is 2^95, so no account can be wide.

What does the EVM see, and what does the leaf store?

The EVM sees the low 256 bits. BALANCE, SELFBALANCE and SELFDESTRUCT use that wrapped value. The leaf stores the full integer as an RLP big integer with no length limit.

xOne adds one rule that geth-XDC does not have. A balance must be in 0..=2^264 - 1. A credit above that bound is a typed error, not a wrap. The spike report says the bound leaves at least a factor of 16 over the whole Apothem supply.

Two more geth-XDC rules from the issue: a wide sender can always pay (buyGas skips the wrapped check), and SetBalance clears the wide value.

How does xOneRS keep the true value?

xOneRS wraps the revm journal and keeps the true value of each wide account in a side map. The module is xone_evm::journal::WideJournal. The spec names it as the production version of option B in the spike.

  • The wrapped low part always stays in revm's AccountInfo::balance. Stock revm code reads what geth's GetBalance returns.
  • The side map has its own undo log. It moves with revm's checkpoints, so a reverted call restores both values.
  • An account below 2^256 takes a fast path that calls stock revm.
  • The wide-sender branch of XdcHandler::validate_against_state_and_deduct_caller handles gas purchase.
  • No revm source file changes (revm =43.0.3).

At the start of each block, the executor loads every wide account into the side map (crates/xone-executor/src/lib.rs). The node keeps the set of wide accounts in its history, and it reads them from the state at start. An address it cannot find is an error, never a silently narrowed balance (crates/xone-node/src/services/core.rs).

How do unwind and reorg restore it?

Each block records the old value of every wide account it changes. A branch switch replays those records from the highest block down. This is the fix in PR #606.

HistInner::push stores the value before the block in wide_undo. pop_to restores it. can_pop_to refuses a switch only when a popped block lies below undo_from and wide accounts are held. After a restart, the blocks replayed above the checkpoint have their undo again.

Before this change, the node refused every branch switch while it held a wide account. The post-mortem has that story. This post does not repeat it.

Which tests cover it?

REFERENCE TABLEScroll to explore all columns →
Test What it checks
crates/xone-evm/tests/wide_matrix.rs::matrix_equals_geth 40 rows of the oracle matrix through the production journal and handler: balances, storage, outcome and state root equal geth
crates/xone-primitives/tests/wide_balance.rs 5 tests: encoding equals Go for 8 boundary values, round trip, bound, strict RLP, a mutant check
crates/xone-state/tests/oracle.rs leaf and slim forms equal geth, roots over 50 mutations, unwind to each step, narrowing changes the root
crates/xone-node/src/services/hist.rs::a_reorg_across_wide_balances_restores_them undo over three blocks, a one-block reorg, a deeper pop, and a refusal below the first undo
crates/xone-snap/tests/sync.rs a snap sync of 10,000 accounts with at least 100 wide ones reaches the exact root

The matrix runs at two rule sets (blocks 40,000,000 and 72,000,000, Apothem parameters). It covers credit, debit across the line, CanTransfer, buyGas, refunds, rewards, CREATE, CALL value, SELFDESTRUCT, nested revert and out-of-gas revert. The proof document records all of these green on 2026-11-14. It did not re-run the Go oracle.

Do the other clients handle wide balances?

Yes. They use the same matrix file. The three other repositories are private, so their links need access.

  • xOneTS: the ADR-002 addendum says the wide balance is carried outside the EVM library's account type, as a side value.
  • xOnePy: the adapter keeps the true balance up to 2^264 - 1 and shows the EVM the value modulo 2^256.
  • xOneC: WideBalance uses intx::uint<320> with the same bound.

What is still open?

Issue #7 is open. The last status check on 2026-11-14 says the matrix, option B and zero revm patches are done.

  • Owner decisions. The issue lists three: accept the range 0..2^264 - 1, accept the open gaps, accept option B.
  • Special transactions. The 0x89 and 0x90 rows and the TRC21 fee path go to issue #28, which is open.
  • Legacy history. No block was found where BALANCE or SELFDESTRUCT touched a wide account. The question is open.
  • Mainnet. There is no mainnet archive. The claim rests on the supply argument.
  • Deep reorgs. A switch below undo_from is still refused while wide accounts are held.

For parity status, see state of parity. For gates, see the roadmap gates. For networks, see networks.

Frequently asked questions

Does BALANCE return the true balance of a wide account?

No. BALANCE and SELFBALANCE return the value modulo 2^256, as in geth-XDC. The leaf and the side map keep the true integer.

Is there a limit on a balance in xOne?

Yes. The legal range is 0..2^264 - 1. geth-XDC has no bound. In xOne, a credit above the bound is a typed error.

Can a wide account pay for gas?

Yes. In geth-XDC, buyGas skips the wrapped check and CanTransfer is true for a wide sender. The xOneRS handler follows this rule.

Sources