Untitled diff
707 lines
// 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
// 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 "txdb.h"
#include "main.h"
#include "wallet.h"
#include "wallet.h"
#include "walletdb.h"
#include "walletdb.h"
#include "crypter.h"
#include "crypter.h"
#include "util.h"
#include "ui_interface.h"
#include "ui_interface.h"
#include "base58.h"
#include "base58.h"
#include "kernel.h"
#include "kernel.h"
#include "net.h"
#include "init.h"
#include "coincontrol.h"
#include "coincontrol.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace std;
extern int nMinerSleep;
extern int nStakeMaxAge;
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//
// mapWallet
// mapWallet
//
//
struct CompareValueOnly
struct CompareValueOnly
{
{
    bool operator()(const pair<int64_t, pair<const CWalletTx*, unsigned int> >& t1,
    bool operator()(const pair<int64, pair<const CWalletTx*, unsigned int> >& t1,
                    const pair<int64_t, pair<const CWalletTx*, unsigned int> >& t2) const
                    const pair<int64, pair<const CWalletTx*, unsigned int> >& t2) const
    {
    {
        return t1.first < t2.first;
        return t1.first < t2.first;
    }
    }
};
};
CPubKey CWallet::GenerateNewKey()
CPubKey CWallet::GenerateNewKey()
{
{
    AssertLockHeld(cs_wallet); // mapKeyMetadata
    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);
    CPubKey pubkey = key.GetPubKey();
    // Create new metadata
    int64_t nCreationTime = GetTime();
    mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
    if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
        nTimeFirstKey = nCreationTime;
    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)
{
{
    AssertLockHeld(cs_wallet); // mapKeyMetadata
    CPubKey pubkey = key.GetPubKey();
    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(pubkey, key.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]);
        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 CPubKey &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, mapKeyMetadata[vchPubKey.GetID()]);
            return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
        else
        else
            return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]);
            return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
    }
    }
    return false;
    return false;
}
}
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
{
    AssertLockHeld(cs_wallet); // mapKeyMetadata
    if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
        nTimeFirstKey = meta.nCreateTime;
    mapKeyMetadata[pubkey.GetID()] = meta;
    return true;
}
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
    return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
}
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);
}
}
bool CWallet::LoadCScript(const CScript& redeemScript)
{
    /* A sanity check was added in pull #3843 to avoid adding redeemScripts
    * that never can be redeemed. However, old wallets may still contain
    * these. Do not add them to the wallet and warn. */
   if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
   {
       std::string strAddr = CBitcoinAddress(redeemScript.GetID()).ToString();
       LogPrintf("%s: Warning: This wallet contains a redeemScript of size %u which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
           __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
       return true;
   }
   return CCryptoKeyStore::AddCScript(redeemScript);
}
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_t 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;
                LogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
                printf("Wallet 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
// clients to crash on startup if reading a private-key-encrypted wallet.
class CCorruptAddress
{
public:
    IMPLEMENT_SERIALIZE
    (
        if (nType & SER_DISK)
            READWRITE(nVersion);
    )
};
bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
{
{
    LOCK(cs_wallet); // nWalletVersion
    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)
        {
            // Versions prior to 0.4.0 did not support the "minversion" record.
            // Use a CCorruptAddress to make them crash instead.
            CCorruptAddress 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)
{
{
    LOCK(cs_wallet); // nWalletVersion, nWalletMaxVersion
    // 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_t 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;
    LogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
    printf("Encrypting Wallet 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);
    }
    }
    NotifyStatusChanged(this);
    NotifyStatusChanged(this);
    return true;
    return true;
}
}
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
int64 CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
{
{
    AssertLockHeld(cs_wallet); // nOrderPosNext
    int64 nRet = nOrderPosNext++;
    int64_t nRet = nOrderPosNext++;
    if (pwalletdb) {
    if (pwalletdb) {
        pwalletdb->WriteOrderPosNext(nOrderPosNext);
        pwalletdb->WriteOrderPosNext(nOrderPosNext);
    } else {
    } else {
        CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext);
        CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext);
    }
    }
    return nRet;
    return nRet;
}
}
CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
{
{
    AssertLockHeld(cs_wallet); // mapWallet
    CWalletDB walletdb(strWalletFile);
    CWalletDB walletdb(strWalletFile);
    // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
    // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
    TxItems txOrdered;
    TxItems txOrdered;
    // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
    // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
    // would make this much faster for applications that do this a lot.
    // would make this much faster for applications that do this a lot.
    for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
    for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
    {
    {
        CWalletTx* wtx = &((*it).second);
        CWalletTx* wtx = &((*it).second);
        txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
        txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
    }
    }
    acentries.clear();
    acentries.clear();
    walletdb.ListAccountCreditDebit(strAccount, acentries);
    walletdb.ListAccountCreditDebit(strAccount, acentries);
    BOOST_FOREACH(CAccountingEntry& entry, acentries)
    BOOST_FOREACH(CAccountingEntry& entry, acentries)
    {
    {
        txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
        txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
    }
    }
    return txOrdered;
    return txOrdered;
}
}
void CWallet::WalletUpdateSpent(const CTransaction &tx, bool fBlock)
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;
                if (txin.prevout.n >= wtx.vout.size())
                if (txin.prevout.n >= wtx.vout.size())
                    LogPrintf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString());
                    printf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str());
                else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
                else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
                {
                {
                    LogPrintf("WalletUpdateSpent found spent coin %shbn %s\n", FormatMoney(wtx.GetCredit()), wtx.GetHash().ToString());
                    printf("WalletUpdateSpent found spent coin %sMNT %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();
                    NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
                    NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
                }
                }
            }
            }
        }
        }
    }
    }
    if (fBlock)
    {
       uint256 hash = tx.GetHash();
       map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
       CWalletTx& wtx = (*mi).second;
       BOOST_FOREACH(const CTxOut& txout, tx.vout)
       {
           if (IsMine(txout))
           {
              wtx.MarkUnspent(&txout - &tx.vout[0]);
              wtx.WriteToDisk();
           }
       }
    }
}
}
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();
            wtx.nOrderPos = IncOrderPosNext();
            wtx.nOrderPos = IncOrderPosNext();
            wtx.nTimeSmart = wtx.nTimeReceived;
            wtx.nTimeSmart = wtx.nTimeReceived;
            if (wtxIn.hashBlock != 0)
            if (wtxIn.hashBlock != 0)
            {
            {
                if (mapBlockIndex.count(wtxIn.hashBlock))
                if (mapBlockIndex.count(wtxIn.hashBlock))
                {
                {
                    unsigned int latestNow = wtx.nTimeReceived;
                    unsigned int latestNow = wtx.nTimeReceived;
                    unsigned int latestEntry = 0;
                    unsigned int latestEntry = 0;
                    {
                    {
                        // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
                        // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
                        int64_t latestTolerated = latestNow + 300;
                        int64 latestTolerated = latestNow + 300;
                        std::list<CAccountingEntry> acentries;
                        std::list<CAccountingEntry> acentries;
                        TxItems txOrdered = OrderedTxItems(acentries);
                        TxItems txOrdered = OrderedTxItems(acentries);
                        for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
                        for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
                        {
                        {
                            CWalletTx *const pwtx = (*it).second.first;
                            CWalletTx *const pwtx = (*it).second.first;
                            if (pwtx == &wtx)
                            if (pwtx == &wtx)
                                continue;
                                continue;
                            CAccountingEntry *const pacentry = (*it).second.second;
                            CAccountingEntry *const pacentry = (*it).second.second;
                            int64_t nSmartTime;
                            int64 nSmartTime;
                            if (pwtx)
                            if (pwtx)
                            {
                            {
                                nSmartTime = pwtx->nTimeSmart;
                                nSmartTime = pwtx->nTimeSmart;
                                if (!nSmartTime)
                                if (!nSmartTime)
                                    nSmartTime = pwtx->nTimeReceived;
                                    nSmartTime = pwtx->nTimeReceived;
                            }
                            }
                            else
                            else
                                nSmartTime = pacentry->nTime;
                                nSmartTime = pacentry->nTime;
                            if (nSmartTime <= latestTolerated)
                            if (nSmartTime <= latestTolerated)
                            {
                            {
                                latestEntry = nSmartTime;
                                latestEntry = nSmartTime;
                                if (nSmartTime > latestNow)
                                if (nSmartTime > latestNow)
                                    latestNow = nSmartTime;
                                    latestNow = nSmartTime;
                                break;
                                break;
                            }
                            }
                        }
                        }
                    }
                    }
                    unsigned int& blocktime = mapBlockIndex[wtxIn.hashBlock]->nTime;
                    unsigned int& blocktime = mapBlockIndex[wtxIn.hashBlock]->nTime;
                    wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
                    wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
                }
                }
                else
                else
                    LogPrintf("AddToWallet() : found %s in block %s not in index\n",
                    printf("AddToWallet() : found %s in block %s not in index\n",
                           wtxIn.GetHash().ToString().substr(0,10),
                           wtxIn.GetHash().ToString().substr(0,10).c_str(),
                           wtxIn.hashBlock.ToString());
                           wtxIn.hashBlock.ToString().c_str());
            }
            }
        }
        }
        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
        LogPrintf("AddToWallet %s  %s%s\n", wtxIn.GetHash().ToString().substr(0,10), (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;
        if (!fHaveGUI) {
		if(!fHaveGUI){
            // If default receiving address gets used, replace it with a new one
			// If default receiving address gets used, replace it with a new one
            if (vchDefaultKey.IsValid()) {
			CScript scriptDefaultKey;
                CScript scriptDefaultKey;
			scriptDefaultKey.SetDestination(vchDefaultKey.GetID());
                scriptDefaultKey.SetDestination(vchDefaultKey.GetID());
			BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                BOOST_FOREACH(const CTxOut& txout, wtx.vout)
			{
                {
				if (txout.scriptPubKey == scriptDefaultKey)
                    if (txout.scriptPubKey == scriptDefaultKey)
				{
                    {
					CPubKey newDefaultKey;
                        CPubKey newDefaultKey;
					if (GetKeyFromPool(newDefaultKey, false))
                        if (GetKeyFromPool(newDefaultKey, false))
					{
                        {
						SetDefaultKey(newDefaultKey);
                            SetDefaultKey(newDefaultKey);
						SetAddressBookName(vchDefaultKey.GetID(), "");
                            SetAddressBookName(vchDefaultKey.GetID(), "");
					}
                        }
				}
                    }
			}
                }
		}
            }
        }
        // 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, (wtxIn.hashBlock != 0));
        WalletUpdateSpent(wtx);
        // Notify UI of new or updated transaction
        // Notify UI of new or updated transaction
        NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
        NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
        // notify an external script when a wallet transaction comes in or is updated
		// notify an external script when a wallet transaction comes in or is updated
        std::string strCmd = GetArg("-walletnotify", "");
        std::string strCmd = GetArg("-walletnotify", "");
        if ( !strCmd.empty())
        if ( !strCmd.empty())
        {
        {
            boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
            boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
            boost::thread t(runCommand, strCmd); // thread runs free
            boost::thread t(runCommand, strCmd); // thread runs free
        }
        }
        // notify an external script when a wallet transaction is received
        std::string strCmdNewNotify = GetArg("-newtxnotify", "");
        if ( !strCmdNewNotify.empty() && fInsertedNew)
        {
             boost::replace_all(strCmdNewNotify, "%s", wtxIn.GetHash().GetHex());
             boost::thread t(runCommand, strCmdNewNotify); // thread runs free
        }
        // notify an external script when a wallet transaction is confirmed
        std::string strCmdConfNotify = GetArg("-confirmnotify", "");
        if ( !strCmdConfNotify.empty() && fUpdated)
        {
            boost::replace_all(strCmdConfNotify, "%s", wtxIn.GetHash().GetHex());
            boost::thread t(runCommand, strCmdConfNotify); // thread runs free
        }
    }
    }
    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_t 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;
    CTxDestination 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 (ExtractDestination(txout.scriptPubKey, address) && ::IsMine(*this, address))
    {
    {
        LOCK(cs_wallet);
        LOCK(cs_wallet);
        if (!mapAddressBook.count(address))
        if (!mapAddressBook.count(address))
            return true;
            return true;
    }
    }
    return false;
    return false;
}
}
int64_t CWalletTx::GetTxTime() const
int64 CWalletTx::GetTxTime() const
{
{
    int64_t n = nTimeSmart;
    int64 n = nTimeSmart;
    return n ? n : nTimeReceived;
    return n ? n : 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(list<pair<CTxDestination, int64_t> >& listReceived,
void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CTxDestination, int64> >& listReceived,
                           list<pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, string& strSentAccount) const
                           list<pair<CTxDestination, int64> >& listSent, int64& nFee, string& strSentAccount) const
{
{
    nFee = 0;
    nGeneratedImmature = nGeneratedMature = nFee = 0;
    listReceived.clear();
    listReceived.clear();
    listSent.clear();
    listSent.clear();
    strSen
    strSentAccount = strFromAccount;
    // Compute fee:
    int64 nDebit = GetDebit();
    if (nDebit > 0) // debit>0 means we signed/sent this transaction
    {
        int64 nValueOut = GetValueOut();
        nFee = nDebit - nValueOut;
    }
    // Sent/received.
    BOOST_FOREACH(const CTxOut& txout, vout)
    {
        CTxDestination address;
        vector<unsigned char> vchPubKey;
        if (!ExtractDestination(txout.scriptPubKey, address))
        {
			if(!IsCoinBaseOrStake())
			{
				printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
                   this->GetHash().ToString().c_str());
			}
			continue;
        }
        // Don't report 'change' txouts
        if (nDebit > 0 && pwallet->IsChange(txout))
            continue;
        if (nDebit > 0)
            listSent.push_back(make_pair(address, txout.nValue));
        if (pwallet->IsMine(txout))
		{
			if(IsCoinBaseOrStake())
			{
				if(GetBlocksToMaturity() > 0)
					nGeneratedImmature += txout.nValue;
				else
					nGeneratedMature += txout.nValue;
			}
			else
				listReceived.push_back(make_pair(address, txout.nValue));
		}
    }
}
void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGeneratedImmature, int64& nGeneratedMature, int64& nReceived,
                                  int64& nSent, int64& nFee) const
{
    nGeneratedImmature = nGeneratedMature = nReceived = nSent = nFee = 0;
    int64 allGeneratedImmature, allGeneratedMature, allFee;
    string strSentAccount;
    list<pair<CTxDestination, int64> > listReceived;
    list<pair<CTxDestination, int64> > listSent;
    GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
    if (strAccount == strSentAccount)
    {
        BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& s, listSent)
            nSent += s.second;
        nFee = allFee;
		nGeneratedImmature = allGeneratedImmature;
		nGeneratedMature = allGeneratedMature;
    }
    {
        LOCK(pwallet->cs_wallet);
        BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
        {
            if (pwallet->mapAddressBook.count(r.first))
            {
                map<CTxDestination, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
                if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
                    nReceived += r.second;
            }
            else if (strAccount.empty())
            {
                nReceived += r.second;
            }
        }
    }
}
void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
{
    vtxPrev.clear();
    const int COPY_DEPTH = 3;
    if (SetMerkleBranch() < COPY_DEPTH)
    {
        vector<uint256> vWorkQueue;
        BOOST_FOREACH(const CTxIn& txin, vin)