Repository: bitcoin/bitcoin
File: src/wallet/wallet.cpp (C++)

Code before:
    if (batch) {
        return batch->WriteLockedUTXO(output);
    }
    return true;
}

bool CWallet::UnlockCoin(const COutPoint& output, WalletBatch* batch)
{
    AssertLockHeld(cs_wallet);
    bool was_locked = setLockedCoins.erase(output);
    if (batch && was_locked) {
        return batch->EraseLockedUTXO(output);
    }
    return true;
}

bool CWallet::UnlockAllCoins()
{
    AssertLockHeld(cs_wallet);
    bool success = true;
    WalletBatch batch(GetDatabase());
    for (auto it = setLockedCoins.begin(); it != setLockedCoins.end(); ++it) {
        success &= batch.EraseLockedUTXO(*it);
    }
    setLockedCoins.clear();
    return success;
}

bool CWallet::IsLockedCoin(const COutPoint& output) const
{
    AssertLockHeld(cs_wallet);
    return setLockedCoins.count(output) > 0;
}

void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
{
    AssertLockHeld(cs_wallet);
    for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
         it != setLockedCoins.end(); it++) {
        COutPoint outpt = (*it);
        vOutpts.push_back(outpt);
    }
}

/**
 * Compute smart timestamp for a transaction being added to the wallet.
 *
 * Logic:
 * - If sending a transaction, assign its timestamp to the current time.
 * - If receiving a transaction outside a block, assign its timestamp to the
 *   current time.

Review comment (performance):
I see the previous code also needed to figure out whether the locked coin was persisted on disk while unlocking, but it did so in a slightly complicated way as it depended on whether the DB batch was passed in the unlock flow. Theoretically it could be possible that the code forgets to pass the said batch in the unlock flow leading to unintended scenarios.
The new code seems more robust to me as it explicitly tracks whether the coin was persisted on disk.
 

Code after:
        return signer_spk_man->DisplayAddress(dest, signer);
    }
    return util::Error{_("There is no ScriptPubKeyManager for this address")};
}

void CWallet::LoadLockedCoin(const COutPoint& coin, bool persistent)
{
    AssertLockHeld(cs_wallet);
    m_locked_coins.emplace(coin, persistent);
}

bool CWallet::LockCoin(const COutPoint& output, bool persist)
{
    AssertLockHeld(cs_wallet);
    LoadLockedCoin(output, persist);
    if (persist) {
        WalletBatch batch(GetDatabase());
        return batch.WriteLockedUTXO(output);
    }
    return true;
}

bool CWallet::UnlockCoin(const COutPoint& output)
{
    AssertLockHeld(cs_wallet);
    auto locked_coin_it = m_locked_coins.find(output);
    if (locked_coin_it != m_locked_coins.end()) {
        bool persisted = locked_coin_it->second;
        m_locked_coins.erase(locked_coin_it);
        if (persisted) {
            WalletBatch batch(GetDatabase());
            return batch.EraseLockedUTXO(output);
        }
    }
    return true;
}

bool CWallet::UnlockAllCoins()
{
    AssertLockHeld(cs_wallet);
    bool success = true;
    WalletBatch batch(GetDatabase());
    for (const auto& [coin, persistent] : m_locked_coins) {
        if (persistent) success = success && batch.EraseLockedUTXO(coin);
    }
    m_locked_coins.clear();
    return success;
}

bool CWallet::IsLockedCoin(const COutPoint& output) const
{