MarkConflicted assumes that m_last_block_processed_height is always valid. However it may not be valid when a chain is not attached, as happens in the wallet tool and during migration. In such situations, when the conflicting height is also negative (which occurs on loading when no chain is available), the calculation of the number of conflict confirms results in a non-negative value which passes the existing check for valid values. This will subsequently hit an assertion in GetTxDepthInMainChain.
Furthermore, MarkConflicted is also only called on loading a transaction whose parent has a stored state of TxStateConflicted and was loaded before the child transaction. This depends on the loading order, which for both sqlite and bdb depends on the txids.
We can avoid this by explicitly checking that both m_last_block_processed_height and conflicting_height are non-negative. Both tool_wallet.py and wallet_migration.py are updated to create wallets with a state that triggers the assertion.
Fixes #28510