Skip to content

security: BlockProducer commits account-model root in UTXO mode #2075

@createkr

Description

@createkr

Summary

BlockProducer.get_state_root() computes the block state commitment from the legacy balances account-model table even when the node is operating against the UTXO database. In UTXO mode, block headers can therefore commit to a state root that does not match the actual spendable state.

Impact

This is a consensus-correctness bug. Two honest validators with the same UTXO set can derive different block state_root values if their legacy balances tables diverge or are stale. A produced block can then carry a header commitment that does not match the underlying UTXO ledger state.

Root cause

node/rustchain_block_producer.py always does:

  • query balances
  • hash (wallet, balance_urtc, wallet_nonce) rows

and never consults UtxoDB.compute_state_root().

Fix

When a utxo_db handle is available, BlockProducer should use utxo_db.compute_state_root() and only fall back to the legacy account-model path when no UTXO database is attached (or when UTXO root computation fails).

Validation

I prepared a fix with focused coverage for:

  • UTXO root preferred when utxo_db is present
  • legacy fallback when no utxo_db is attached
  • roots differ between account-model and UTXO-mode state
  • empty UTXO root handling
  • state-root changes after spends
  • deterministic root behavior
  • graceful fallback if UTXO root computation raises

Payout wallet: RTC1d48d848a5aa5ecf2c5f01aa5fb64837daaf2f35

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions