{"record":{"id":"e46def8a68bccb28","repo":"linera-io/linera-protocol","slug":"the-balances-are-incoherent-for-address-0-balan","errorCode":null,"errorMessage":"The balances are incoherent for address {0}, balances {1}, {2}","messagePattern":"The balances are incoherent for address (.+?), balances (.+?), (.+?)","errorType":"validation","errorClass":"EvmExecutionError","httpStatus":null,"severity":"critical","filePath":"linera-execution/src/evm/database.rs","lineNumber":604,"sourceCode":"    pub fn new(runtime: Runtime) -> Self {\n        Self {\n            inner: InnerDatabase::new(runtime),\n            modules: Arc::new(Mutex::new(HashMap::new())),\n        }\n    }\n\n    pub fn lock_runtime(&self) -> std::sync::MutexGuard<'_, Runtime> {\n        self.inner.lock_runtime()\n    }\n\n    /// Balances of the contracts have to be checked when\n    /// writing. There is a balance in Linera and a balance\n    /// in EVM and they have to be coherent.\n    fn check_balance(&self, address: Address, revm_balance: U256) -> Result<(), ExecutionError> {\n        let mut runtime = self.inner.runtime.lock().unwrap();\n        let owner = address.into();\n        let linera_balance: U256 = runtime.read_owner_balance(owner)?.into();\n        ensure!(\n            linera_balance == revm_balance,\n            EvmExecutionError::IncoherentBalances(address, linera_balance, revm_balance)\n        );\n        Ok(())\n    }\n\n    /// Effectively commits changes to storage.\n    pub fn commit_contract_changes(\n        &self,\n        account: &revm_state::Account,\n    ) -> Result<(), ExecutionError> {\n        let mut runtime = self.inner.runtime.lock().unwrap();\n        let mut batch = Batch::new();\n        let key_prefix = get_category_key(KeyCategory::Storage);\n        let key_info = get_category_key(KeyCategory::AccountInfo);\n        if account.is_selfdestructed() {\n            batch.delete_key_prefix(key_prefix);\n            batch.put_key_value(key_info, &AccountInfo::default())?;","sourceCodeStart":586,"sourceCodeEnd":622,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-execution/src/evm/database.rs#L586-L622","documentation":"Raised by the EVM adapter's ContractDatabase::check_balance during commit_changes for every writable, non-faucet contract account: the Linera-side balance of the contract's owner (read via the Linera runtime) must equal the balance the EVM (revm) computed for that address. The EVM bridge mirrors ETH balances in Linera's native accounting; any divergence means the EVM execution changed a contract's value without the corresponding Linera transfer (or vice versa), so the block is rejected rather than committing incoherent state.","triggerScenarios":"An EVM application moves ETH in a way the bridge does not mirror back into Linera balances: raw value transfers on paths outside the faucet precompile, selfdestruct value-recovery flows, precompile transfers, or bugs in the balance wiring. FAUCET_ADDRESS (0x...4000) is explicitly exempt from checks; ordinary contract accounts are not.","commonSituations":"Porting Solidity contracts that rely on value semantics Linera's bridge does not support; running a newer/older contract bytecode against a linera-execution version whose balance accounting changed; genuine protocol bugs in the EVM adapter itself.","solutions":["Ensure the contract's ETH transfers only use the supported paths (the bridge's transfer precompile at address 0x0b / the faucet address flow)","Reproduce with the contract on a local testnet and inspect which transaction desynchronizes the balance (the error prints address, Linera balance, and revm balance)","Update to the latest linera-protocol version — EVM balance-coherency fixes have landed repeatedly","If it reproduces on current versions with a minimal contract, report it as a bug with the bytecode and transaction"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// In app tests, run the ETH-transfer scenario on a local testnet first; the adapter's\n// check fires at commit time, so a dry-run execution surfaces the incoherence before mainnet.","typeGuard":"fn is_incoherent_balance(err: &ExecutionError) -> Option<(&Address, &U256, &U256)> {\n    match err {\n        ExecutionError::EvmError(evm_error!::IncoherentBalances(addr, linera, evm)) => Some((addr, linera, evm)),\n        _ => None,\n    }\n}","tryCatchPattern":"match client.execute_operations(ops, vec![]).await {\n    Err(e) if is_incoherent_balance(&e).is_some() => {\n        // Address and both balances are in the error: log them, halt the deploy,\n        // and audit the contract's ETH-transfer paths.\n        tracing::error!(error = %e, \"EVM/Linera balance divergence; blocking further submissions\");\n        return Err(e.into());\n    }\n    other => other,\n}","preventionTips":["Keep contract ETH transfers on the bridge-supported paths (transfer precompile/faucet address); avoid selfdestruct-value and raw value-sending patterns","Test any value-moving contract on a Linera devnet where check_balance failures surface before production","Stay on the latest linera-protocol release — EVM balance coherency has ongoing fixes"],"tags":["linera","evm","solidity","balance","state-consistency"],"backgroundTag":"state-inconsistency","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}