In 0.12, a wallet tx thats not in the mempool does not free up its inputs.  So if a tx spends the same inputs as a conflict tx included in a new block, its inputs are explicitly marked dirty so they will be recalculated as spendable again due to having no non-conflicted spends.  However if the in-block conflict is reorged out, the wallet txs inputs should now be market spent again according to the 0.12 regime, but they are not marked dirty as the tx itself is not notified it is no longer conflicted.

This has the odd effect that the cached value is incorrect and so randomly they will be spendable or not depending on whether they have been recalculated.

This is easy enough to fix by marking all inputs of all txs in SyncTransaction dirty regardless of whether AddToWalletIfInvolvingMe returns true or false.  But I'm not sure the performance impact this will have, so I'm not proposing that change now.

It's a minor issue, but I just thought I'd document that that the cached credit available in wallet txs may not always be correct.

For reference, in 0.11, whenever a tx left the mempool it's inputs were respendable.  So if a tx was removed due to a conflict in a block, any remaining inputs would be spendable again.  If the in-block conflict was later reorged out, the wallet txs inputs would remain spendable unless and until the wallet tx reentered the mempool.

* @param[in] start_block Scan starting block.  block is not on the active
 *                        chain, the scan will return SUCCESS immediately.
 * @param[in] start_height Height of start_block
 * @param[in] max_height  Optional max scanning height.  unset there is
 *                        no maximum and scanning can continue to the tip
 *
 * @return ScanResult returning scan information and indicating success or
 *         failure. Return status will be set to SUCCESS if scan was
 *         successful. FAILURE if a compe rescan was not possible (due to
 *         pruning or corruption). USER_ABORT if the rescan was aborted before
 *         it could compe.
 *
 * @pre Caller needs to make sure start_block (and the optional stop_block) are on
 * the main chain after to the addition of any new keys you want to detect
 * transactions for.
 */
CWalScanResult CWalScanForWalTransactions(const uint256& start_block, int start_height, stdoptional<int> max_height, const WalRescanReserver& reserver, bool fUpdate, const bool save_progress)
{
    constexpr auto INTERVAL_TIME{60s};
    auto current_time{reserver.now()};
    auto start_time{reserver.now()};
    assert(reserver.isReserved());
    uint256 block_hash = start_block;
    ScanResult result;
    stdunique_ptr<FastWalRescanFilter> fast_rescan_filter;
    if (!IsLegacy() && chain().hasBlockFilterIndex(BlockFilterTypeBASIC)) fast_rescan_filter = stdmake_unique<FastWalRescanFilter>(*this);
    WalLogPrintf("Rescan started from block %s... (%s)\n", start_block.ToString(),
                    fast_rescan_filter ? "fast variant using block filters"  "slow variant inspecting all blocks");
    fAbortRescan = false;
    ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if rescan required on startup (e.g. due to corruption)