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

Code before:
    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.
 * - If receiving a transaction during a rescanning process, assign all its
 *   (not already known) transactions' timestamps to the block time.
 * - If receiving a block with a future timestamp, assign all its (not already
 *   known) transactions' timestamps to the current time.
 * - If receiving a block with a past timestamp, before the most recent known
 *   transaction (that we care about), assign all its (not already known)
 *   transactions' timestamps to the same timestamp as that most-recent-known
 *   transaction.
 * - If receiving a block with a past timestamp, but after the most recent known
 *   transaction, assign all its (not already known) transactions' timestamps to
 *   the block time.
 *
 * For more information see CWalletTx::nTimeSmart,
 * https://bitcointalk.org/?topic=54527, or
 * https://github.com/bitcoin/bitcoin/pull/1393.
 */
unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old_block) const
{

Review comment (bug):
Should it not check the `persistent` boolean parameter of the locked coin just like it's checked in `UnlockCoin`? Otherwise, it tries to erase a locked coin that was not persisted to disk.

Scenario: I lock a coin by calling `lockunspent` RPC with `unlock: false` and `persistent: false`. I then try to unlock all coins by calling `lockunspent` RPC with `unlock: true` and letting the `persistent` param being null. 
Though the RPC still returns `true` probably because of the SQLITE's design: https://stackoverflow.com/q/55409865

Code after:
    }
    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
{
    AssertLockHeld(cs_wallet);
    return m_locked_coins.count(output) > 0;
}

void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
{
    AssertLockHeld(cs_wallet);
    for (const auto& [coin, _] : m_locked_coins) {
        vOutpts.push_back(coin);
    }
}

/**
 * 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