Untitled diff
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2013 The PPCoin developers
// Copyright (c) 2011-2013 The Peercoin developers
// Copyright (c) 2015-2015 The Decent developers
// Distributed under the MIT/X11 software license, see the accompanying
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "wallet.h"
#include "wallet.h"
#include "walletdb.h"
#include "walletdb.h"
#include "crypter.h"
#include "crypter.h"
#include "ui_interface.h"
#include "ui_interface.h"
#include "kernel.h"
#include "kernel.h"
#include <boost/algorithm/string/replace.hpp>
#include "bitcoinrpc.h"
#include "base58.h"
#include "encryptionutils.h"
using namespace std;
using namespace std;
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// mapWallet
// mapWallet
//
//
CPubKey CWallet::GenerateNewKey()
std::vector<unsigned char> CWallet::GenerateNewKey()
{
{
    bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
    bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
    RandAddSeedPerfmon();
    RandAddSeedPerfmon();
    CKey key;
    CKey key;
    key.MakeNewKey(fCompressed);
    key.MakeNewKey(fCompressed);
    // Compressed public keys were introduced in version 0.6.0
    // Compressed public keys were introduced in version 0.6.0
    if (fCompressed)
    if (fCompressed)
        SetMinVersion(FEATURE_COMPRPUBKEY);
        SetMinVersion(FEATURE_COMPRPUBKEY);
    if (!AddKey(key))
    if (!AddKey(key))
        throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
        throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
    return key.GetPubKey();
    return key.GetPubKey();
}
}
bool CWallet::AddKey(const CKey& key)
bool CWallet::AddKey(const CKey& key)
{
{
    if (!CCryptoKeyStore::AddKey(key))
    if (!CCryptoKeyStore::AddKey(key))
        return false;
        return false;
    if (!fFileBacked)
    if (!fFileBacked)
        return true;
        return true;
    if (!IsCrypted())
    if (!IsCrypted())
        return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
        return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
    return true;
    return true;
}
}
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
{
{
    if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
    if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
        return false;
        return false;
    if (!fFileBacked)
    if (!fFileBacked)
        return true;
        return true;
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        if (pwalletdbEncryption)
        if (pwalletdbEncryption)
            return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
            return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
        else
        else
            return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
            return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
    }
    }
    return false;
    return false;
}
}
bool CWallet::AddCScript(const CScript& redeemScript)
bool CWallet::AddCScript(const CScript& redeemScript)
{
{
    if (!CCryptoKeyStore::AddCScript(redeemScript))
    if (!CCryptoKeyStore::AddCScript(redeemScript))
        return false;
        return false;
    if (!fFileBacked)
    if (!fFileBacked)
        return true;
        return true;
    return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
    return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
}
}
// ppcoin: optional setting to unlock wallet for block minting only;
// peercoin: optional setting to unlock wallet for block minting only;
//         serves to disable the trivial sendmoney when OS account compromised
//         serves to disable the trivial sendmoney when OS account compromised
bool fWalletUnlockMintOnly = false;
bool fWalletUnlockMintOnly = false;
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
{
    if (!IsLocked())
    if (!IsLocked())
        return false;
        return false;
    CCrypter crypter;
    CCrypter crypter;
    CKeyingMaterial vMasterKey;
    CKeyingMaterial vMasterKey;
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
        BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
        {
        {
            if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
            if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
                return false;
                return false;
            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
                return false;
                return false;
            if (CCryptoKeyStore::Unlock(vMasterKey))
            if (CCryptoKeyStore::Unlock(vMasterKey))
                return true;
                return true;
        }
        }
    }
    }
    return false;
    return false;
}
}
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
{
{
    bool fWasLocked = IsLocked();
    bool fWasLocked = IsLocked();
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        Lock();
        Lock();
        CCrypter crypter;
        CCrypter crypter;
        CKeyingMaterial vMasterKey;
        CKeyingMaterial vMasterKey;
        BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
        BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
        {
        {
            if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
            if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
                return false;
                return false;
            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
                return false;
                return false;
            if (CCryptoKeyStore::Unlock(vMasterKey))
            if (CCryptoKeyStore::Unlock(vMasterKey))
            {
            {
                int64 nStartTime = GetTimeMillis();
                int64 nStartTime = GetTimeMillis();
                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
                pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
                pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
                nStartTime = GetTimeMillis();
                nStartTime = GetTimeMillis();
                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
                pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
                pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
                if (pMasterKey.second.nDeriveIterations < 25000)
                if (pMasterKey.second.nDeriveIterations < 25000)
                    pMasterKey.second.nDeriveIterations = 25000;
                    pMasterKey.second.nDeriveIterations = 25000;
                printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
                printf("Portfolio passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
                if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
                if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
                    return false;
                    return false;
                if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
                if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
                    return false;
                    return false;
                CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
                CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
                if (fWasLocked)
                if (fWasLocked)
                    Lock();
                    Lock();
                return true;
                return true;
            }
            }
        }
        }
    }
    }
    return false;
    return false;
}
}
void CWallet::SetBestChain(const CBlockLocator& loc)
void CWallet::SetBestChain(const CBlockLocator& loc)
{
{
    CWalletDB walletdb(strWalletFile);
    CWalletDB walletdb(strWalletFile);
    walletdb.WriteBestBlock(loc);
    walletdb.WriteBestBlock(loc);
}
}
// This class implements an addrIncoming entry that causes pre-0.4
// This class implements an addrIncoming entry that causes pre-0.4
// clients to crash on startup if reading a private-key-encrypted wallet.
// clients to crash on startup if reading a private-key-encrypted wallet.
class CCorruptAddress
class CCorruptAddress
{
{
public:
public:
    IMPLEMENT_SERIALIZE
    IMPLEMENT_SERIALIZE
    (
    (
        if (nType & SER_DISK)
        if (nType & SER_DISK)
            READWRITE(nVersion);
            READWRITE(nVersion);
    )
    )
};
};
bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
{
{
    if (nWalletVersion >= nVersion)
    if (nWalletVersion >= nVersion)
        return true;
        return true;
    // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
    // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
    if (fExplicit && nVersion > nWalletMaxVersion)
    if (fExplicit && nVersion > nWalletMaxVersion)
            nVersion = FEATURE_LATEST;
            nVersion = FEATURE_LATEST;
    nWalletVersion = nVersion;
    nWalletVersion = nVersion;
    if (nVersion > nWalletMaxVersion)
    if (nVersion > nWalletMaxVersion)
        nWalletMaxVersion = nVersion;
        nWalletMaxVersion = nVersion;
    if (fFileBacked)
    if (fFileBacked)
    {
    {
        CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
        CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
        if (nWalletVersion >= 40000)
        if (nWalletVersion >= 40000)
        {
        {
            // Versions prior to 0.4.0 did not support the "minversion" record.
            // Versions prior to 0.4.0 did not support the "minversion" record.
            // Use a CCorruptAddress to make them crash instead.
            // Use a CCorruptAddress to make them crash instead.
            CCorruptAddress corruptAddress;
            CCorruptAddress corruptAddress;
            pwalletdb->WriteSetting("addrIncoming", corruptAddress);
            pwalletdb->WriteSetting("addrIncoming", corruptAddress);
        }
        }
        if (nWalletVersion > 40000)
        if (nWalletVersion > 40000)
            pwalletdb->WriteMinVersion(nWalletVersion);
            pwalletdb->WriteMinVersion(nWalletVersion);
        if (!pwalletdbIn)
        if (!pwalletdbIn)
            delete pwalletdb;
            delete pwalletdb;
    }
    }
    return true;
    return true;
}
}
bool CWallet::SetMaxVersion(int nVersion)
bool CWallet::SetMaxVersion(int nVersion)
{
{
    // cannot downgrade below current version
    // cannot downgrade below current version
    if (nWalletVersion > nVersion)
    if (nWalletVersion > nVersion)
        return false;
        return false;
    nWalletMaxVersion = nVersion;
    nWalletMaxVersion = nVersion;
    return true;
    return true;
}
}
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
{
    if (IsCrypted())
    if (IsCrypted())
        return false;
        return false;
    CKeyingMaterial vMasterKey;
    CKeyingMaterial vMasterKey;
    RandAddSeedPerfmon();
    RandAddSeedPerfmon();
    vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
    vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
    RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
    RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
    CMasterKey kMasterKey;
    CMasterKey kMasterKey;
    RandAddSeedPerfmon();
    RandAddSeedPerfmon();
    kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
    kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
    RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
    RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
    CCrypter crypter;
    CCrypter crypter;
    int64 nStartTime = GetTimeMillis();
    int64 nStartTime = GetTimeMillis();
    crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
    crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
    kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
    kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
    nStartTime = GetTimeMillis();
    nStartTime = GetTimeMillis();
    crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
    crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
    kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
    kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
    if (kMasterKey.nDeriveIterations < 25000)
    if (kMasterKey.nDeriveIterations < 25000)
        kMasterKey.nDeriveIterations = 25000;
        kMasterKey.nDeriveIterations = 25000;
    printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
    printf("Encrypting portfolio with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
    if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
    if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
        return false;
        return false;
    if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
    if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
        return false;
        return false;
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
        mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
        if (fFileBacked)
        if (fFileBacked)
        {
        {
            pwalletdbEncryption = new CWalletDB(strWalletFile);
            pwalletdbEncryption = new CWalletDB(strWalletFile);
            if (!pwalletdbEncryption->TxnBegin())
            if (!pwalletdbEncryption->TxnBegin())
                return false;
                return false;
            pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
            pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
        }
        }
        if (!EncryptKeys(vMasterKey))
        if (!EncryptKeys(vMasterKey))
        {
        {
            if (fFileBacked)
            if (fFileBacked)
                pwalletdbEncryption->TxnAbort();
                pwalletdbEncryption->TxnAbort();
            exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
            exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
        }
        }
        // Encryption was introduced in version 0.4.0
        // Encryption was introduced in version 0.4.0
        SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
        SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
        if (fFileBacked)
        if (fFileBacked)
        {
        {
            if (!pwalletdbEncryption->TxnCommit())
            if (!pwalletdbEncryption->TxnCommit())
                exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
                exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
            delete pwalletdbEncryption;
            delete pwalletdbEncryption;
            pwalletdbEncryption = NULL;
            pwalletdbEncryption = NULL;
        }
        }
        Lock();
        Lock();
        Unlock(strWalletPassphrase);
        Unlock(strWalletPassphrase);
        NewKeyPool();
        NewKeyPool();
        Lock();
        Lock();
        // Need to completely rewrite the wallet file; if we don't, bdb might keep
        // Need to completely rewrite the wallet file; if we don't, bdb might keep
        // bits of the unencrypted private key in slack space in the database file.
        // bits of the unencrypted private key in slack space in the database file.
        CDB::Rewrite(strWalletFile);
        CDB::Rewrite(strWalletFile);
    }
    }
    return true;
    return true;
}
}
void CWallet::WalletUpdateSpent(const CTransaction &tx)
void CWallet::WalletUpdateSpent(const CTransaction &tx)
{
{
    // Anytime a signature is successfully verified, it's proof the outpoint is spent.
    // Anytime a signature is successfully verified, it's proof the outpoint is spent.
    // Update the wallet spent flag if it doesn't know due to wallet.dat being
    // Update the wallet spent flag if it doesn't know due to wallet.dat being
    // restored from backup or the user making copies of wallet.dat.
    // restored from backup or the user making copies of wallet.dat.
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        BOOST_FOREACH(const CTxIn& txin, tx.vin)
        BOOST_FOREACH(const CTxIn& txin, tx.vin)
        {
        {
            map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
            map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
            if (mi != mapWallet.end())
            if (mi != mapWallet.end())
            {
            {
                CWalletTx& wtx = (*mi).second;
                CWalletTx& wtx = (*mi).second;
                // Decent: skip empty TX
                if (wtx.vout.empty())
                    continue;
                if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
                if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
                {
                {
                    printf("WalletUpdateSpent found spent coin %sppc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
                    printf("WalletUpdateSpent found spent unit %sDCT %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
                    wtx.MarkSpent(txin.prevout.n);
                    wtx.MarkSpent(txin.prevout.n);
                    wtx.WriteToDisk();
                    wtx.WriteToDisk();
                    vWalletUpdated.push_back(txin.prevout.hash);
                    vWalletUpdated.push_back(txin.prevout.hash);
                }
                }
            }
            }
        }
        }
    }
    }
}
}
void CWallet::MarkDirty()
void CWallet::MarkDirty()
{
{
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
        BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
            item.second.MarkDirty();
            item.second.MarkDirty();
    }
    }
}
}
bool CWallet::AddToWallet(const CWalletTx& wtxIn)
bool CWallet::AddToWallet(const CWalletTx& wtxIn)
{
{
    uint256 hash = wtxIn.GetHash();
    uint256 hash = wtxIn.GetHash();
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        // Inserts only if not already there, returns tx inserted or tx found
        // Inserts only if not already there, returns tx inserted or tx found
        pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
        pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
        CWalletTx& wtx = (*ret.first).second;
        CWalletTx& wtx = (*ret.first).second;
        wtx.BindWallet(this);
        wtx.BindWallet(this);
        bool fInsertedNew = ret.second;
        bool fInsertedNew = ret.second;
        if (fInsertedNew)
        if (fInsertedNew)
            wtx.nTimeReceived = GetAdjustedTime();
            wtx.nTimeReceived = GetAdjustedTime();
        bool fUpdated = false;
        bool fUpdated = false;
        if (!fInsertedNew)
        if (!fInsertedNew)
        {
        {
            // Merge
            // Merge
            if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
            if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
            {
            {
                wtx.hashBlock = wtxIn.hashBlock;
                wtx.hashBlock = wtxIn.hashBlock;
                fUpdated = true;
                fUpdated = true;
            }
            }
            if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
            if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
            {
            {
                wtx.vMerkleBranch = wtxIn.vMerkleBranch;
                wtx.vMerkleBranch = wtxIn.vMerkleBranch;
                wtx.nIndex = wtxIn.nIndex;
                wtx.nIndex = wtxIn.nIndex;
                fUpdated = true;
                fUpdated = true;
            }
            }
            if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
            if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
            {
            {
                wtx.fFromMe = wtxIn.fFromMe;
                wtx.fFromMe = wtxIn.fFromMe;
                fUpdated = true;
                fUpdated = true;
            }
            }
            fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
            fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
        }
        }
        //// debug print
        //// debug print
        printf("AddToWallet %s  %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
        printf("AddToWallet %s  %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
        // Write to disk
        // Write to disk
        if (fInsertedNew || fUpdated)
        if (fInsertedNew || fUpdated)
            if (!wtx.WriteToDisk())
            if (!wtx.WriteToDisk())
                return false;
                return false;
#ifndef QT_GUI
#ifndef QT_GUI
        // If default receiving address gets used, replace it with a new one
        // If default receiving address gets used, replace it with a new one
        CScript scriptDefaultKey;
        CScript scriptDefaultKey;
        scriptDefaultKey.SetDestination(vchDefaultKey.GetID());
        scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
        {
        {
            if (txout.scriptPubKey == scriptDefaultKey)
            if (txout.scriptPubKey == scriptDefaultKey)
            {
            {
                CPubKey newDefaultKey;
                std::vector<unsigned char> newDefaultKey;
                if (GetKeyFromPool(newDefaultKey, false))
                if (GetKeyFromPool(newDefaultKey, false))
                {
                {
                    SetDefaultKey(newDefaultKey);
                    SetDefaultKey(newDefaultKey);
                    SetAddressBookName(vchDefaultKey.GetID(), "");
                    SetAddressBookName(CBitcoinAddress(vchDefaultKey), "");
                }
                }
            }
            }
        }
        }
#endif
#endif
        // Notify UI
        // Notify UI
        vWalletUpdated.push_back(hash);
        vWalletUpdated.push_back(hash);
        // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
        // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
        WalletUpdateSpent(wtx);
        WalletUpdateSpent(wtx);
        // notify an external script when a wallet transaction comes in or is updated
        std::string strCmd = GetArg("-walletnotify", "");
        if ( !strCmd.empty())
        {
            boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
            boost::thread t(runCommand, strCmd); // thread runs free
        }
    }
    }
    // Refresh UI
    // Refresh UI
    MainFrameRepaint();
    MainFrameRepaint();
    return true;
    return true;
}
}
// Add a transaction to the wallet, or update it.
// Add a transaction to the wallet, or update it.
// pblock is optional, but should be provided if the transaction is known to be in a block.
// pblock is optional, but should be provided if the transaction is known to be in a block.
// If fUpdate is true, existing transactions will be updated.
// If fUpdate is true, existing transactions will be updated.
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
{
{
    uint256 hash = tx.GetHash();
    uint256 hash = tx.GetHash();
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        bool fExisted = mapWallet.count(hash);
        bool fExisted = mapWallet.count(hash);
        if (fExisted && !fUpdate) return false;
        if (fExisted && !fUpdate) return false;
        if (fExisted || IsMine(tx) || IsFromMe(tx))
        if (fExisted || IsMine(tx) || IsFromMe(tx))
        {
        {
            CWalletTx wtx(this,tx);
            CWalletTx wtx(this,tx);
            // Get merkle branch if transaction was found in a block
            // Get merkle branch if transaction was found in a block
            if (pblock)
            if (pblock)
                wtx.SetMerkleBranch(pblock);
                wtx.SetMerkleBranch(pblock);
            return AddToWallet(wtx);
            return AddToWallet(wtx);
        }
        }
        else
        else
            WalletUpdateSpent(tx);
            WalletUpdateSpent(tx);
    }
    }
    return false;
    return false;
}
}
bool CWallet::EraseFromWallet(uint256 hash)
bool CWallet::EraseFromWallet(uint256 hash)
{
{
    if (!fFileBacked)
    if (!fFileBacked)
        return false;
        return false;
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        if (mapWallet.erase(hash))
        if (mapWallet.erase(hash))
            CWalletDB(strWalletFile).EraseTx(hash);
            CWalletDB(strWalletFile).EraseTx(hash);
    }
    }
    return true;
    return true;
}
}
bool CWallet::IsMine(const CTxIn &txin) const
bool CWallet::IsMine(const CTxIn &txin) const
{
{
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
        map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
        if (mi != mapWallet.end())
        if (mi != mapWallet.end())
        {
        {
            const CWalletTx& prev = (*mi).second;
            const CWalletTx& prev = (*mi).second;
            if (txin.prevout.n < prev.vout.size())
            if (txin.prevout.n < prev.vout.size())
                if (IsMine(prev.vout[txin.prevout.n]))
                if (IsMine(prev.vout[txin.prevout.n]))
                    return true;
                    return true;
        }
        }
    }
    }
    return false;
    return false;
}
}
int64 CWallet::GetDebit(const CTxIn &txin) const
int64 CWallet::GetDebit(const CTxIn &txin) const
{
{
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
        map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
        if (mi != mapWallet.end())
        if (mi != mapWallet.end())
        {
        {
            const CWalletTx& prev = (*mi).second;
            const CWalletTx& prev = (*mi).second;
            if (txin.prevout.n < prev.vout.size())
            if (txin.prevout.n < prev.vout.size())
                if (IsMine(prev.vout[txin.prevout.n]))
                if (IsMine(prev.vout[txin.prevout.n]))
                    return prev.vout[txin.prevout.n].nValue;
                    return prev.vout[txin.prevout.n].nValue;
        }
        }
    }
    }
    return 0;
    return 0;
}
}
bool CWallet::IsChange(const CTxOut& txout) const
bool CWallet::IsChange(const CTxOut& txout) const
{
{
    CTxDestination address;
    CBitcoinAddress address;
    // TODO: fix handling of 'change' outputs. The assumption is that any
    // TODO: fix handling of 'change' outputs. The assumption is that any
    // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
    // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
    // is change. That assumption is likely to break when we implement multisignature
    // is change. That assumption is likely to break when we implement multisignature
    // wallets that return change back into a multi-signature-protected address;
    // wallets that return change back into a multi-signature-protected address;
    // a better way of identifying which outputs are 'the send' and which are
    // a better way of identifying which outputs are 'the send' and which are
    // 'the change' will need to be implemented (maybe extend CWalletTx to remember
    // 'the change' will need to be implemented (maybe extend CWalletTx to remember
    // which output, if any, was change).
    // which output, if any, was change).
    if (ExtractDestination(txout.scriptPubKey, address) && ::IsMine(*this, address))
    if (ExtractAddress(txout.scriptPubKey, address) && HaveKey(address))
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        if (!mapAddressBook.count(address))
        if (!mapAddressBook.count(address))
            return true;
            return true;
    }
    }
    return false;
    return false;
}
}
int64 CWalletTx::GetTxTime() const
int64 CWalletTx::GetTxTime() const
{
{
    return nTimeReceived;
    return nTimeReceived;
}
}
int CWalletTx::GetRequestCount() const
int CWalletTx::GetRequestCount() const
{
{
    // Returns -1 if it wasn't being tracked
    // Returns -1 if it wasn't being tracked
    int nRequests = -1;
    int nRequests = -1;
    {
    {
        LOCK(pwallet->cs_wallet);
        LOCK(pwallet->cs_wallet);
        if (IsCoinBase() || IsCoinStake())
        if (IsCoinBase() || IsCoinStake())
        {
        {
            // Generated block
            // Generated block
            if (hashBlock != 0)
            if (hashBlock != 0)
            {
            {
                map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
                map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
                if (mi != pwallet->mapRequestCount.end())
                if (mi != pwallet->mapRequestCount.end())
                    nRequests = (*mi).second;
                    nRequests = (*mi).second;
            }
            }
        }
        }
        else
        else
        {
        {
            // Did anyone request this transaction?
            // Did anyone request this transaction?
            map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
            map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
            if (mi != pwallet->mapRequestCount.end())
            if (mi != pwallet->mapRequestCount.end())
            {
            {
                nRequests = (*mi).second;
                nRequests = (*mi).second;
                // How about the block it's in?
                // How about the block it's in?
                if (nRequests == 0 && hashBlock != 0)
                if (nRequests == 0 && hashBlock != 0)
                {
                {
                    map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
                    map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
                    if (mi != pwallet->mapRequestCount.end())
                    if (mi != pwallet->mapRequestCount.end())
                        nRequests = (*mi).second;
                        nRequests = (*mi).second;
                    else
                    else
                        nRequests = 1; // If it's in someone else's block it must have got out
                        nRequests = 1; // If it's in someone else's block it must have got out
                }
                }
            }
            }
        }
        }
    }
    }
    return nRequests;
    return nRequests;
}
}
void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CTxDestination, int64> >& listReceived,
void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CBitcoinAddress, int64> >& listReceived,
                           list<pair<CTxDestination, int64> >& listSent, int64& nFee, string& strSentAccount) const
                           list<pair<CBitcoinAddress, int64> >& listSent, int64& nFee, string& strSentAccount) const
{
{
    nGeneratedImmature = nGeneratedMature = nFee = 0;
    nGeneratedImmature = nGeneratedMature = nFee = 0;
    listReceived.clear();
    listReceived.clear();
    listSent.clear();
    listSent.clear();
    strSentAccount = strFromAccount;
    strSentAccount = strFromAccount;
    if (IsCoinBase() || IsCoinStake())
    if (IsCoinBase() || IsCoinStake())
    {
    {
        if (GetBlocksToMaturity() > 0)
        if (GetBlocksToMaturity() > 0)
            nGeneratedImmature = pwallet->GetCredit(*this) - pwallet->GetDebit(*this);
            nGeneratedImmature = pwallet->GetCredit(*this) - pwallet->GetDebit(*this);
        else
        else
            nGeneratedMature = GetCredit() - GetDebit();
            nGeneratedMature = GetCredit() - GetDebit();
        return;
        return;
    }
    }
    // Compute fee:
    // Compute fee:
    int64 nDebit = GetDebit();
    int64 nDebit = GetDebit();
    if (nDebit > 0) // debit>0 means we signed/sent this transaction
    if (nDebit > 0) // debit>0 means we signed/sent this transaction
    {
    {
        int64 nValueOut = GetValueOut();
        int64 nValueOut = GetValueOut();
        nFee = nDebit - nValueOut;
        nFee = nDebit - nValueOut;
    }
    }
    // Sent/received.
    // Sent/received.
    BOOST_FOREACH(const CTxOut& txout, vout)
    BOOST_FOREACH(const CTxOut& txout, vout)
    {
    {
        CTxDestination address;
        CBitcoinAddress address;
        vector<unsigned char> vchPubKey;
        vector<unsigned char> vchPubKey;
        if (!ExtractDestination(txout.scriptPubKey, address))
        if (!ExtractAddress(txout.scriptPubKey, address))
        {
        {
            printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
            printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
                   this->GetHash().ToString().c_str());
                   this->GetHash().ToString().c_str());
            address = " unknown ";
        }
        }
        // Don't report 'change' txouts
        // Don't report 'change' txouts
        if (nDebit > 0 && pwallet->IsChange(txout))
        if (nDebit > 0 && pwallet->IsChange(txout))
            continue;
            continue;
        if (nDebit > 0)
        if (nDebit > 0)
            listSent.push_back(make_pair(address, txout.nValue));
            listSent.push_back(make_pair(address, txout.nValue));
        if (pwallet->IsMine(txout))
        if (pwallet->IsMine(txout))
            listReceived.push_back(make_pair(address, txout.nValue));
            listReceived.push_back(make_pair(address, txout.nValue));
    }
    }
}
}
void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived, 
void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived, 
                                  int64& nSent, int64& nFee) const
                                  int64& nSent, int64& nFee) const
{
{
    nGenerated = nReceived = nSent = nFee = 0;
    nGenerated = nReceived = nSent = nFee = 0;
    int64 allGeneratedImmature, allGeneratedMature, allFee;
    int64 allGeneratedImmature, allGeneratedMature, allFee;
    allGeneratedImmature = allGeneratedMature = allFee = 0;
    allGeneratedImmature = allGeneratedMature = allFee = 0;
    string strSentAccount;
    string strSentAccount;
    list<pair<CTxDestination, int64> > listReceived;
    list<pair<CBitcoinAddress, int64> > listReceived;
    list<pair<CTxDestination, int64> > listSent;
    list<pair<CBitcoinAddress, int64> > listSent;
    GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
    GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
    if (strAccount == "")
    if (strAccount == "")
        nGenerated = allGeneratedMature;
        nGenerated = allGeneratedMature;
    if (strAccount == strSentAccount)
    if (strAccount == strSentAccount)
    {
    {
        BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& s, listSent)
        BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& s, listSent)
            nSent += s.second;
            nSent += s.second;
        nFee = allFee;
        nFee = allFee;
    }
    }
    {
    {
        LOCK(pwallet->cs_wallet);
        LOCK(pwallet->cs_wallet);
        BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
        BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
        {
        {
            if (pwallet->mapAddressBook.count(r.first))
            if (pwallet->mapAddressBook.count(r.first))
            {
            {
                map<CTxDestination, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
                map<CBitcoinAddress, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
                if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
                if (mi != pwallet->mapAddressBook.end() && ((*mi).second == strAccount || (*mi).first.ToString() == strAccount))
                    nReceived += r.second;
                    nReceived += r.second;
            }
            }
            else if (strAccount.empty())
            else if (strAccount.empty())
            {
            {
                nReceived += r.second;
                nReceived += r.second;
            }
            }
        }
        }
    }
    }
}
}
void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
{
{
    vtxPrev.clear();
    vtxPrev.clear();
    const int COPY_DEPTH = 3;
    const int COPY_DEPTH = 3;
    if (SetMerkleBranch() < COPY_DEPTH)
    if (SetMerkleBranch() < COPY_DEPTH)
    {
    {
        vector<uint256> vWorkQueue;
        vector<uint256> vWorkQueue;
        BOOST_FOREACH(const CTxIn& txin, vin)
        BOOST_FOREACH(const CTxIn& txin, vin)
            vWorkQueue.push_back(txin.prevout.hash);
            vWorkQueue.push_back(txin.prevout.hash);
        // This critsect is OK because txdb is already open
        // This critsect is OK because txdb is already open
        {
        {
            LOCK(pwallet->cs_wallet);
            LOCK(pwallet->cs_wallet);
            map<uint256, const CMerkleTx*> mapWalletPrev;
            map<uint256, const CMerkleTx*> mapWalletPrev;
            set<uint256> setAlreadyDone;
            set<uint256> setAlreadyDone;
            for (unsigned int i = 0; i < vWorkQueue.size(); i++)
            for (unsigned int i = 0; i < vWorkQueue.size(); i++)
            {
            {
                uint256 hash = vWorkQueue[i];
                uint256 hash = vWorkQueue[i];
                if (setAlreadyDone.count(hash))
                if (setAlreadyDone.count(hash))
                    continue;
                    continue;
                setAlreadyDone.insert(hash);
                setAlreadyDone.insert(hash);
                CMerkleTx tx;
                CMerkleTx tx;
                map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
                map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
                if (mi != pwallet->mapWallet.end())
                if (mi != pwallet->mapWallet.end())
                {
                {
                    tx = (*mi).second;
                    tx = (*mi).second;
                    BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
                    BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
                        mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
                        mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
                }
                }
                else if (mapWalletPrev.count(hash))
                else if (mapWalletPrev.count(hash))
                {
                {
                    tx = *mapWalletPrev[hash];
                    tx = *mapWalletPrev[hash];
                }
                }
                else if (!fClient && txdb.ReadDiskTx(hash, tx))
                else if (!fClient && txdb.ReadDiskTx(hash, tx))
                {
                {
                    ;
                    ;
                }
                }
                else
                else
                {
                {
                    printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
                    printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
                    continue;
                    continue;
                }
                }
                int nDepth = tx.SetMerkleBranch();
                int nDepth = tx.SetMerkleBranch();
                vtxPrev.push_back(tx);
                vtxPrev.push_back(tx);
                if (nDepth < COPY_DEPTH)
                if (nDepth < COPY_DEPTH)
                {
                {
                    BOOST_FOREACH(const CTxIn& txin, tx.vin)
                    BOOST_FOREACH(const CTxIn& txin, tx.vin)
                        vWorkQueue.push_back(txin.prevout.hash);
                        vWorkQueue.push_back(txin.prevout.hash);
                }
                }
            }
            }
        }
        }
    }
    }
    reverse(vtxPrev.begin(), vtxPrev.end());
    reverse(vtxPrev.begin(), vtxPrev.end());
}
}
bool CWalletTx::WriteToDisk()
bool CWalletTx::WriteToDisk()
{
{
    return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
    return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
}
}
// Scan the block chain (starting in pindexStart) for transactions
// Scan the block chain (starting in pindexStart) for transactions
// from or to us. If fUpdate is true, found transactions that already
// from or to us. If fUpdate is true, found transactions that already
// exist in the wallet will be updated.
// exist in the wallet will be updated.
int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
{
{
    int ret = 0;
    int ret = 0;
    CBlockIndex* pindex = pindexStart;
    CBlockIndex* pindex = pindexStart;
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        while (pindex)
        while (pindex)
        {
        {
            CBlock block;
            CBlock block;
            block.ReadFromDisk(pindex, true);
            block.ReadFromDisk(pindex, true);
            BOOST_FOREACH(CTransaction& tx, block.vtx)
            BOOST_FOREACH(CTransaction& tx, block.vtx)
            {
            {
                if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
                if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
                    ret++;
                    ret++;
            }
            }
            pindex = pindex->pnext;
            pindex = pindex->pnext;
        }
        }
    }
    }
    return ret;
    return ret;
}
}
int CWallet::ScanForWalletTransaction(const uint256& hashTx)
int CWallet::ScanForWalletTransaction(const uint256& hashTx)
{
{
    CTransaction tx;
    CTransaction tx;
    tx.ReadFromDisk(COutPoint(hashTx, 0));
    tx.ReadFromDisk(COutPoint(hashTx, 0));
    if (AddToWalletIfInvolvingMe(tx, NULL, true, true))
    if (AddToWalletIfInvolvingMe(tx, NULL, true, true))
        return 1;
        return 1;
    return 0;
    return 0;
}
}
void CWallet::ReacceptWalletTransactions()
void CWallet::ReacceptWalletTransactions()
{
{
    CTxDB txdb("r");
    CTxDB txdb("r");
    bool fRepeat = true;
    bool fRepeat = true;
    while (fRepeat)
    while (fRepeat)
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        fRepeat = false;
        fRepeat = false;
        vector<CDiskTxPos> vMissingTx;
        vector<CDiskTxPos> vMissingTx;
        BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
        BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
        {
        {
            CWalletTx& wtx = item.second;
            CWalletTx& wtx = item.second;
            if ((wtx.IsCoinBase() && wtx.IsSpent(0)) || (wtx.IsCoinStake() && wtx.IsSpent(1)))
            if ((wtx.IsCoinBase() && wtx.IsSpent(0)) || (wtx.IsCoinStake() && wtx.IsSpent(1)))
                continue;
                continue;
            CTxIndex txindex;
            CTxIndex txindex;
            bool fUpdated = false;
            bool fUpdated = false;
            if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
            if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
            {
            {
                // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
                // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
                if (txindex.vSpent.size() != wtx.vout.size())
                if (txindex.vSpent.size() != wtx.vout.size())
                {
                {
                    printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
                    printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
                    continue;
                    continue;
                }
                for (unsigned int i = 0; i < txindex.v