integrate a few extra .h files
authorWladimir J. van der Laan <laanwj@gmail.com>
Sat, 14 May 2011 15:25:05 +0000 (17:25 +0200)
committerWladimir J. van der Laan <laanwj@gmail.com>
Sat, 14 May 2011 15:25:05 +0000 (17:25 +0200)
bitcoin.pro
core/include/bignum.h
core/include/key.h [new file with mode: 0644]
core/include/main.h [new file with mode: 0644]
core/include/net.h [new file with mode: 0644]
core/include/serialize.h
core/include/strlcpy.h [new file with mode: 0644]
core/include/util.h
core/src/util.cpp [new file with mode: 0644]
gui/include/bitcoinaddressvalidator.h
gui/src/sendcoinsdialog.cpp

index 84ecc9a..6934013 100644 (file)
@@ -2,6 +2,7 @@ TEMPLATE = app
 TARGET =
 DEPENDPATH += .
 INCLUDEPATH += gui/include core/include cryptopp/include
+unix:LIBS += -lssl
 
 # Input
 HEADERS += gui/include/bitcoingui.h \
@@ -29,7 +30,11 @@ HEADERS += gui/include/bitcoingui.h \
     cryptopp/include/cryptopp/iterhash.h \
     cryptopp/include/cryptopp/cryptlib.h \
     cryptopp/include/cryptopp/cpu.h \
-    cryptopp/include/cryptopp/config.h
+    cryptopp/include/cryptopp/config.h \
+    core/include/strlcpy.h \
+    core/include/main.h \
+    core/include/net.h \
+    core/include/key.h
 SOURCES += gui/src/bitcoin.cpp gui/src/bitcoingui.cpp \
     gui/src/transactiontablemodel.cpp \
     gui/src/addresstablemodel.cpp \
@@ -41,7 +46,8 @@ SOURCES += gui/src/bitcoin.cpp gui/src/bitcoingui.cpp \
     gui/src/editaddressdialog.cpp \
     gui/src/bitcoinaddressvalidator.cpp \
     cryptopp/src/sha.cpp \
-    cryptopp/src/cpu.cpp
+    cryptopp/src/cpu.cpp \
+    core/src/util.cpp
 
 RESOURCES += \
     gui/bitcoin.qrc
index c207af1..5b4c78e 100644 (file)
@@ -7,11 +7,8 @@
 #include <stdexcept>
 #include <vector>
 #include <openssl/bn.h>
-#include <util.h>
-
-
-
 
+#include "util.h"
 
 class bignum_error : public std::runtime_error
 {
diff --git a/core/include/key.h b/core/include/key.h
new file mode 100644 (file)
index 0000000..390602e
--- /dev/null
@@ -0,0 +1,171 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_KEY_H
+#define BITCOIN_KEY_H
+
+// secp160k1
+// const unsigned int PRIVATE_KEY_SIZE = 192;
+// const unsigned int PUBLIC_KEY_SIZE  = 41;
+// const unsigned int SIGNATURE_SIZE   = 48;
+//
+// secp192k1
+// const unsigned int PRIVATE_KEY_SIZE = 222;
+// const unsigned int PUBLIC_KEY_SIZE  = 49;
+// const unsigned int SIGNATURE_SIZE   = 57;
+//
+// secp224k1
+// const unsigned int PRIVATE_KEY_SIZE = 250;
+// const unsigned int PUBLIC_KEY_SIZE  = 57;
+// const unsigned int SIGNATURE_SIZE   = 66;
+//
+// secp256k1:
+// const unsigned int PRIVATE_KEY_SIZE = 279;
+// const unsigned int PUBLIC_KEY_SIZE  = 65;
+// const unsigned int SIGNATURE_SIZE   = 72;
+//
+// see www.keylength.com
+// script supports up to 75 for single byte push
+
+
+
+class key_error : public std::runtime_error
+{
+public:
+    explicit key_error(const std::string& str) : std::runtime_error(str) {}
+};
+
+
+// secure_allocator is defined in serialize.h
+typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
+
+
+
+class CKey
+{
+protected:
+    EC_KEY* pkey;
+    bool fSet;
+
+public:
+    CKey()
+    {
+        pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+        if (pkey == NULL)
+            throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
+        fSet = false;
+    }
+
+    CKey(const CKey& b)
+    {
+        pkey = EC_KEY_dup(b.pkey);
+        if (pkey == NULL)
+            throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
+        fSet = b.fSet;
+    }
+
+    CKey& operator=(const CKey& b)
+    {
+        if (!EC_KEY_copy(pkey, b.pkey))
+            throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
+        fSet = b.fSet;
+        return (*this);
+    }
+
+    ~CKey()
+    {
+        EC_KEY_free(pkey);
+    }
+
+    bool IsNull() const
+    {
+        return !fSet;
+    }
+
+    void MakeNewKey()
+    {
+        if (!EC_KEY_generate_key(pkey))
+            throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
+        fSet = true;
+    }
+
+    bool SetPrivKey(const CPrivKey& vchPrivKey)
+    {
+        const unsigned char* pbegin = &vchPrivKey[0];
+        if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
+            return false;
+        fSet = true;
+        return true;
+    }
+
+    CPrivKey GetPrivKey() const
+    {
+        unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
+        if (!nSize)
+            throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
+        CPrivKey vchPrivKey(nSize, 0);
+        unsigned char* pbegin = &vchPrivKey[0];
+        if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
+            throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
+        return vchPrivKey;
+    }
+
+    bool SetPubKey(const vector<unsigned char>& vchPubKey)
+    {
+        const unsigned char* pbegin = &vchPubKey[0];
+        if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
+            return false;
+        fSet = true;
+        return true;
+    }
+
+    vector<unsigned char> GetPubKey() const
+    {
+        unsigned int nSize = i2o_ECPublicKey(pkey, NULL);
+        if (!nSize)
+            throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
+        vector<unsigned char> vchPubKey(nSize, 0);
+        unsigned char* pbegin = &vchPubKey[0];
+        if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
+            throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
+        return vchPubKey;
+    }
+
+    bool Sign(uint256 hash, vector<unsigned char>& vchSig)
+    {
+        vchSig.clear();
+        unsigned char pchSig[10000];
+        unsigned int nSize = 0;
+        if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey))
+            return false;
+        vchSig.resize(nSize);
+        memcpy(&vchSig[0], pchSig, nSize);
+        return true;
+    }
+
+    bool Verify(uint256 hash, const vector<unsigned char>& vchSig)
+    {
+        // -1 = error, 0 = bad sig, 1 = good
+        if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
+            return false;
+        return true;
+    }
+
+    static bool Sign(const CPrivKey& vchPrivKey, uint256 hash, vector<unsigned char>& vchSig)
+    {
+        CKey key;
+        if (!key.SetPrivKey(vchPrivKey))
+            return false;
+        return key.Sign(hash, vchSig);
+    }
+
+    static bool Verify(const vector<unsigned char>& vchPubKey, uint256 hash, const vector<unsigned char>& vchSig)
+    {
+        CKey key;
+        if (!key.SetPubKey(vchPubKey))
+            return false;
+        return key.Verify(hash, vchSig);
+    }
+};
+
+#endif
diff --git a/core/include/main.h b/core/include/main.h
new file mode 100644 (file)
index 0000000..7c9ace0
--- /dev/null
@@ -0,0 +1,2059 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_MAIN_H
+#define BITCOIN_MAIN_H
+
+#include "bignum.h"
+#include "net.h"
+#include "key.h"
+
+class COutPoint;
+class CInPoint;
+class CDiskTxPos;
+class CCoinBase;
+class CTxIn;
+class CTxOut;
+class CTransaction;
+class CBlock;
+class CBlockIndex;
+class CWalletTx;
+class CKeyItem;
+
+static const unsigned int MAX_BLOCK_SIZE = 1000000;
+static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
+static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
+static const int64 COIN = 100000000;
+static const int64 CENT = 1000000;
+static const int64 MIN_TX_FEE = 50000;
+static const int64 MAX_MONEY = 21000000 * COIN;
+inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
+static const int COINBASE_MATURITY = 100;
+#ifdef USE_UPNP
+static const int fHaveUPnP = true;
+#else
+static const int fHaveUPnP = false;
+#endif
+
+
+
+
+
+
+extern CCriticalSection cs_main;
+extern std::map<uint256, CBlockIndex*> mapBlockIndex;
+extern uint256 hashGenesisBlock;
+extern CBigNum bnProofOfWorkLimit;
+extern CBlockIndex* pindexGenesisBlock;
+extern int nBestHeight;
+extern CBigNum bnBestChainWork;
+extern CBigNum bnBestInvalidWork;
+extern uint256 hashBestChain;
+extern CBlockIndex* pindexBest;
+extern unsigned int nTransactionsUpdated;
+extern std::map<uint256, int> mapRequestCount;
+extern CCriticalSection cs_mapRequestCount;
+extern std::map<std::string, std::string> mapAddressBook;
+extern CCriticalSection cs_mapAddressBook;
+extern std::vector<unsigned char> vchDefaultKey;
+extern double dHashesPerSec;
+extern int64 nHPSTimerStart;
+
+// Settings
+extern int fGenerateBitcoins;
+extern int64 nTransactionFee;
+extern CAddress addrIncoming;
+extern int fLimitProcessors;
+extern int nLimitProcessors;
+extern int fMinimizeToTray;
+extern int fMinimizeOnClose;
+extern int fUseUPnP;
+
+
+
+
+
+
+
+bool CheckDiskSpace(uint64 nAdditionalBytes=0);
+FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
+FILE* AppendBlockFile(unsigned int& nFileRet);
+bool AddKey(const CKey& key);
+vector<unsigned char> GenerateNewKey();
+bool AddToWallet(const CWalletTx& wtxIn);
+void WalletUpdateSpent(const COutPoint& prevout);
+int ScanForWalletTransactions(CBlockIndex* pindexStart);
+void ReacceptWalletTransactions();
+bool LoadBlockIndex(bool fAllowNew=true);
+void PrintBlockTree();
+bool ProcessMessages(CNode* pfrom);
+bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv);
+bool SendMessages(CNode* pto, bool fSendTrickle);
+int64 GetBalance();
+bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
+bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
+bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
+bool BroadcastTransaction(CWalletTx& wtxNew);
+string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
+string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
+void GenerateBitcoins(bool fGenerate);
+void ThreadBitcoinMiner(void* parg);
+CBlock* CreateNewBlock(CReserveKey& reservekey);
+void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime);
+void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
+bool CheckWork(CBlock* pblock, CReserveKey& reservekey);
+void BitcoinMiner();
+bool CheckProofOfWork(uint256 hash, unsigned int nBits);
+bool IsInitialBlockDownload();
+string GetWarnings(string strFor);
+
+
+
+
+
+
+
+
+
+
+
+
+class CDiskTxPos
+{
+public:
+    unsigned int nFile;
+    unsigned int nBlockPos;
+    unsigned int nTxPos;
+
+    CDiskTxPos()
+    {
+        SetNull();
+    }
+
+    CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn)
+    {
+        nFile = nFileIn;
+        nBlockPos = nBlockPosIn;
+        nTxPos = nTxPosIn;
+    }
+
+    IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
+    void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; }
+    bool IsNull() const { return (nFile == -1); }
+
+    friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b)
+    {
+        return (a.nFile     == b.nFile &&
+                a.nBlockPos == b.nBlockPos &&
+                a.nTxPos    == b.nTxPos);
+    }
+
+    friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b)
+    {
+        return !(a == b);
+    }
+
+    string ToString() const
+    {
+        if (IsNull())
+            return strprintf("null");
+        else
+            return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);
+    }
+
+    void print() const
+    {
+        printf("%s", ToString().c_str());
+    }
+};
+
+
+
+
+class CInPoint
+{
+public:
+    CTransaction* ptx;
+    unsigned int n;
+
+    CInPoint() { SetNull(); }
+    CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
+    void SetNull() { ptx = NULL; n = -1; }
+    bool IsNull() const { return (ptx == NULL && n == -1); }
+};
+
+
+
+
+class COutPoint
+{
+public:
+    uint256 hash;
+    unsigned int n;
+
+    COutPoint() { SetNull(); }
+    COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
+    IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
+    void SetNull() { hash = 0; n = -1; }
+    bool IsNull() const { return (hash == 0 && n == -1); }
+
+    friend bool operator<(const COutPoint& a, const COutPoint& b)
+    {
+        return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
+    }
+
+    friend bool operator==(const COutPoint& a, const COutPoint& b)
+    {
+        return (a.hash == b.hash && a.n == b.n);
+    }
+
+    friend bool operator!=(const COutPoint& a, const COutPoint& b)
+    {
+        return !(a == b);
+    }
+
+    string ToString() const
+    {
+        return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n);
+    }
+
+    void print() const
+    {
+        printf("%s\n", ToString().c_str());
+    }
+};
+
+
+
+
+//
+// An input of a transaction.  It contains the location of the previous
+// transaction's output that it claims and a signature that matches the
+// output's public key.
+//
+class CTxIn
+{
+public:
+    COutPoint prevout;
+    CScript scriptSig;
+    unsigned int nSequence;
+
+    CTxIn()
+    {
+        nSequence = UINT_MAX;
+    }
+
+    explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX)
+    {
+        prevout = prevoutIn;
+        scriptSig = scriptSigIn;
+        nSequence = nSequenceIn;
+    }
+
+    CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX)
+    {
+        prevout = COutPoint(hashPrevTx, nOut);
+        scriptSig = scriptSigIn;
+        nSequence = nSequenceIn;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(prevout);
+        READWRITE(scriptSig);
+        READWRITE(nSequence);
+    )
+
+    bool IsFinal() const
+    {
+        return (nSequence == UINT_MAX);
+    }
+
+    friend bool operator==(const CTxIn& a, const CTxIn& b)
+    {
+        return (a.prevout   == b.prevout &&
+                a.scriptSig == b.scriptSig &&
+                a.nSequence == b.nSequence);
+    }
+
+    friend bool operator!=(const CTxIn& a, const CTxIn& b)
+    {
+        return !(a == b);
+    }
+
+    string ToString() const
+    {
+        string str;
+        str += strprintf("CTxIn(");
+        str += prevout.ToString();
+        if (prevout.IsNull())
+            str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
+        else
+            str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
+        if (nSequence != UINT_MAX)
+            str += strprintf(", nSequence=%u", nSequence);
+        str += ")";
+        return str;
+    }
+
+    void print() const
+    {
+        printf("%s\n", ToString().c_str());
+    }
+
+    bool IsMine() const;
+    int64 GetDebit() const;
+};
+
+
+
+
+//
+// An output of a transaction.  It contains the public key that the next input
+// must be able to sign with to claim it.
+//
+class CTxOut
+{
+public:
+    int64 nValue;
+    CScript scriptPubKey;
+
+    CTxOut()
+    {
+        SetNull();
+    }
+
+    CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
+    {
+        nValue = nValueIn;
+        scriptPubKey = scriptPubKeyIn;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(nValue);
+        READWRITE(scriptPubKey);
+    )
+
+    void SetNull()
+    {
+        nValue = -1;
+        scriptPubKey.clear();
+    }
+
+    bool IsNull()
+    {
+        return (nValue == -1);
+    }
+
+    uint256 GetHash() const
+    {
+        return SerializeHash(*this);
+    }
+
+    bool IsMine() const
+    {
+        return ::IsMine(scriptPubKey);
+    }
+
+    int64 GetCredit() const
+    {
+        if (!MoneyRange(nValue))
+            throw runtime_error("CTxOut::GetCredit() : value out of range");
+        return (IsMine() ? nValue : 0);
+    }
+
+    bool IsChange() const
+    {
+        // On a debit transaction, a txout that's mine but isn't in the address book is change
+        vector<unsigned char> vchPubKey;
+        if (ExtractPubKey(scriptPubKey, true, vchPubKey))
+            CRITICAL_BLOCK(cs_mapAddressBook)
+                if (!mapAddressBook.count(PubKeyToAddress(vchPubKey)))
+                    return true;
+        return false;
+    }
+
+    int64 GetChange() const
+    {
+        if (!MoneyRange(nValue))
+            throw runtime_error("CTxOut::GetChange() : value out of range");
+        return (IsChange() ? nValue : 0);
+    }
+
+    friend bool operator==(const CTxOut& a, const CTxOut& b)
+    {
+        return (a.nValue       == b.nValue &&
+                a.scriptPubKey == b.scriptPubKey);
+    }
+
+    friend bool operator!=(const CTxOut& a, const CTxOut& b)
+    {
+        return !(a == b);
+    }
+
+    string ToString() const
+    {
+        if (scriptPubKey.size() < 6)
+            return "CTxOut(error)";
+        return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
+    }
+
+    void print() const
+    {
+        printf("%s\n", ToString().c_str());
+    }
+};
+
+
+
+
+//
+// The basic transaction that is broadcasted on the network and contained in
+// blocks.  A transaction can contain multiple inputs and outputs.
+//
+class CTransaction
+{
+public:
+    int nVersion;
+    vector<CTxIn> vin;
+    vector<CTxOut> vout;
+    unsigned int nLockTime;
+
+
+    CTransaction()
+    {
+        SetNull();
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(this->nVersion);
+        nVersion = this->nVersion;
+        READWRITE(vin);
+        READWRITE(vout);
+        READWRITE(nLockTime);
+    )
+
+    void SetNull()
+    {
+        nVersion = 1;
+        vin.clear();
+        vout.clear();
+        nLockTime = 0;
+    }
+
+    bool IsNull() const
+    {
+        return (vin.empty() && vout.empty());
+    }
+
+    uint256 GetHash() const
+    {
+        return SerializeHash(*this);
+    }
+
+    bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
+    {
+        // Time based nLockTime implemented in 0.1.6
+        if (nLockTime == 0)
+            return true;
+        if (nBlockHeight == 0)
+            nBlockHeight = nBestHeight;
+        if (nBlockTime == 0)
+            nBlockTime = GetAdjustedTime();
+        if ((int64)nLockTime < (nLockTime < 500000000 ? (int64)nBlockHeight : nBlockTime))
+            return true;
+        foreach(const CTxIn& txin, vin)
+            if (!txin.IsFinal())
+                return false;
+        return true;
+    }
+
+    bool IsNewerThan(const CTransaction& old) const
+    {
+        if (vin.size() != old.vin.size())
+            return false;
+        for (int i = 0; i < vin.size(); i++)
+            if (vin[i].prevout != old.vin[i].prevout)
+                return false;
+
+        bool fNewer = false;
+        unsigned int nLowest = UINT_MAX;
+        for (int i = 0; i < vin.size(); i++)
+        {
+            if (vin[i].nSequence != old.vin[i].nSequence)
+            {
+                if (vin[i].nSequence <= nLowest)
+                {
+                    fNewer = false;
+                    nLowest = vin[i].nSequence;
+                }
+                if (old.vin[i].nSequence < nLowest)
+                {
+                    fNewer = true;
+                    nLowest = old.vin[i].nSequence;
+                }
+            }
+        }
+        return fNewer;
+    }
+
+    bool IsCoinBase() const
+    {
+        return (vin.size() == 1 && vin[0].prevout.IsNull());
+    }
+
+    int GetSigOpCount() const
+    {
+        int n = 0;
+        foreach(const CTxIn& txin, vin)
+            n += txin.scriptSig.GetSigOpCount();
+        foreach(const CTxOut& txout, vout)
+            n += txout.scriptPubKey.GetSigOpCount();
+        return n;
+    }
+
+    bool IsStandard() const
+    {
+        foreach(const CTxIn& txin, vin)
+            if (!txin.scriptSig.IsPushOnly())
+                return error("nonstandard txin: %s", txin.scriptSig.ToString().c_str());
+        foreach(const CTxOut& txout, vout)
+            if (!::IsStandard(txout.scriptPubKey))
+                return error("nonstandard txout: %s", txout.scriptPubKey.ToString().c_str());
+        return true;
+    }
+
+    bool IsMine() const
+    {
+        foreach(const CTxOut& txout, vout)
+            if (txout.IsMine())
+                return true;
+        return false;
+    }
+
+    bool IsFromMe() const
+    {
+        return (GetDebit() > 0);
+    }
+
+    int64 GetDebit() const
+    {
+        int64 nDebit = 0;
+        foreach(const CTxIn& txin, vin)
+        {
+            nDebit += txin.GetDebit();
+            if (!MoneyRange(nDebit))
+                throw runtime_error("CTransaction::GetDebit() : value out of range");
+        }
+        return nDebit;
+    }
+
+    int64 GetCredit() const
+    {
+        int64 nCredit = 0;
+        foreach(const CTxOut& txout, vout)
+        {
+            nCredit += txout.GetCredit();
+            if (!MoneyRange(nCredit))
+                throw runtime_error("CTransaction::GetCredit() : value out of range");
+        }
+        return nCredit;
+    }
+
+    int64 GetChange() const
+    {
+        if (IsCoinBase())
+            return 0;
+        int64 nChange = 0;
+        foreach(const CTxOut& txout, vout)
+        {
+            nChange += txout.GetChange();
+            if (!MoneyRange(nChange))
+                throw runtime_error("CTransaction::GetChange() : value out of range");
+        }
+        return nChange;
+    }
+
+    int64 GetValueOut() const
+    {
+        int64 nValueOut = 0;
+        foreach(const CTxOut& txout, vout)
+        {
+            nValueOut += txout.nValue;
+            if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
+                throw runtime_error("CTransaction::GetValueOut() : value out of range");
+        }
+        return nValueOut;
+    }
+
+    static bool AllowFree(double dPriority)
+    {
+        // Large (in bytes) low-priority (new, small-coin) transactions
+        // need a fee.
+        return dPriority > COIN * 144 / 250;
+    }
+
+    int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true) const
+    {
+        // Base fee is 1 cent per kilobyte
+        unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
+        unsigned int nNewBlockSize = nBlockSize + nBytes;
+        int64 nMinFee = (1 + (int64)nBytes / 1000) * MIN_TX_FEE;
+
+        if (fAllowFree)
+        {
+            if (nBlockSize == 1)
+            {
+                // Transactions under 10K are free
+                // (about 4500bc if made of 50bc inputs)
+                if (nBytes < 10000)
+                    nMinFee = 0;
+            }
+            else
+            {
+                // Free transaction area
+                if (nNewBlockSize < 27000)
+                    nMinFee = 0;
+            }
+        }
+
+        // To limit dust spam, require MIN_TX_FEE if any output is less than 0.01
+        if (nMinFee < MIN_TX_FEE)
+            foreach(const CTxOut& txout, vout)
+                if (txout.nValue < CENT)
+                    nMinFee = MIN_TX_FEE;
+
+        // Raise the price as the block approaches full
+        if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2)
+        {
+            if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN)
+                return MAX_MONEY;
+            nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize);
+        }
+
+        if (!MoneyRange(nMinFee))
+            nMinFee = MAX_MONEY;
+        return nMinFee;
+    }
+
+
+    bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)
+    {
+        CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb");
+        if (!filein)
+            return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");
+
+        // Read transaction
+        if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
+            return error("CTransaction::ReadFromDisk() : fseek failed");
+        filein >> *this;
+
+        // Return file pointer
+        if (pfileRet)
+        {
+            if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
+                return error("CTransaction::ReadFromDisk() : second fseek failed");
+            *pfileRet = filein.release();
+        }
+        return true;
+    }
+
+    friend bool operator==(const CTransaction& a, const CTransaction& b)
+    {
+        return (a.nVersion  == b.nVersion &&
+                a.vin       == b.vin &&
+                a.vout      == b.vout &&
+                a.nLockTime == b.nLockTime);
+    }
+
+    friend bool operator!=(const CTransaction& a, const CTransaction& b)
+    {
+        return !(a == b);
+    }
+
+
+    string ToString() const
+    {
+        string str;
+        str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
+            GetHash().ToString().substr(0,10).c_str(),
+            nVersion,
+            vin.size(),
+            vout.size(),
+            nLockTime);
+        for (int i = 0; i < vin.size(); i++)
+            str += "    " + vin[i].ToString() + "\n";
+        for (int i = 0; i < vout.size(); i++)
+            str += "    " + vout[i].ToString() + "\n";
+        return str;
+    }
+
+    void print() const
+    {
+        printf("%s", ToString().c_str());
+    }
+
+
+    bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet);
+    bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
+    bool ReadFromDisk(COutPoint prevout);
+    bool DisconnectInputs(CTxDB& txdb);
+    bool ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
+                       CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
+    bool ClientConnectInputs();
+    bool CheckTransaction() const;
+    bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
+    bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL)
+    {
+        CTxDB txdb("r");
+        return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
+    }
+protected:
+    bool AddToMemoryPoolUnchecked();
+public:
+    bool RemoveFromMemoryPool();
+};
+
+
+
+
+
+//
+// A transaction with a merkle branch linking it to the block chain
+//
+class CMerkleTx : public CTransaction
+{
+public:
+    uint256 hashBlock;
+    vector<uint256> vMerkleBranch;
+    int nIndex;
+
+    // memory only
+    mutable char fMerkleVerified;
+
+
+    CMerkleTx()
+    {
+        Init();
+    }
+
+    CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
+    {
+        Init();
+    }
+
+    void Init()
+    {
+        hashBlock = 0;
+        nIndex = -1;
+        fMerkleVerified = false;
+    }
+
+
+    IMPLEMENT_SERIALIZE
+    (
+        nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
+        nVersion = this->nVersion;
+        READWRITE(hashBlock);
+        READWRITE(vMerkleBranch);
+        READWRITE(nIndex);
+    )
+
+
+    int SetMerkleBranch(const CBlock* pblock=NULL);
+    int GetDepthInMainChain(int& nHeightRet) const;
+    int GetDepthInMainChain() const { int nHeight; return GetDepthInMainChain(nHeight); }
+    bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
+    int GetBlocksToMaturity() const;
+    bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true);
+    bool AcceptToMemoryPool() { CTxDB txdb("r"); return AcceptToMemoryPool(txdb); }
+};
+
+
+
+
+//
+// A transaction with a bunch of additional info that only the owner cares
+// about.  It includes any unrecorded transactions needed to link it back
+// to the block chain.
+//
+class CWalletTx : public CMerkleTx
+{
+public:
+    vector<CMerkleTx> vtxPrev;
+    map<string, string> mapValue;
+    vector<pair<string, string> > vOrderForm;
+    unsigned int fTimeReceivedIsTxTime;
+    unsigned int nTimeReceived;  // time received by this node
+    char fFromMe;
+    string strFromAccount;
+    vector<char> vfSpent;
+
+    // memory only
+    mutable char fDebitCached;
+    mutable char fCreditCached;
+    mutable char fAvailableCreditCached;
+    mutable char fChangeCached;
+    mutable int64 nDebitCached;
+    mutable int64 nCreditCached;
+    mutable int64 nAvailableCreditCached;
+    mutable int64 nChangeCached;
+
+    // memory only UI hints
+    mutable unsigned int nTimeDisplayed;
+    mutable int nLinesDisplayed;
+    mutable char fConfirmedDisplayed;
+
+
+    CWalletTx()
+    {
+        Init();
+    }
+
+    CWalletTx(const CMerkleTx& txIn) : CMerkleTx(txIn)
+    {
+        Init();
+    }
+
+    CWalletTx(const CTransaction& txIn) : CMerkleTx(txIn)
+    {
+        Init();
+    }
+
+    void Init()
+    {
+        vtxPrev.clear();
+        mapValue.clear();
+        vOrderForm.clear();
+        fTimeReceivedIsTxTime = false;
+        nTimeReceived = 0;
+        fFromMe = false;
+        strFromAccount.clear();
+        vfSpent.clear();
+        fDebitCached = false;
+        fCreditCached = false;
+        fAvailableCreditCached = false;
+        fChangeCached = false;
+        nDebitCached = 0;
+        nCreditCached = 0;
+        nAvailableCreditCached = 0;
+        nChangeCached = 0;
+        nTimeDisplayed = 0;
+        nLinesDisplayed = 0;
+        fConfirmedDisplayed = false;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        CWalletTx* pthis = const_cast<CWalletTx*>(this);
+        if (fRead)
+            pthis->Init();
+        char fSpent = false;
+
+        if (!fRead)
+        {
+            pthis->mapValue["fromaccount"] = pthis->strFromAccount;
+
+            string str;
+            foreach(char f, vfSpent)
+            {
+                str += (f ? '1' : '0');
+                if (f)
+                    fSpent = true;
+            }
+            pthis->mapValue["spent"] = str;
+        }
+
+        nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action);
+        READWRITE(vtxPrev);
+        READWRITE(mapValue);
+        READWRITE(vOrderForm);
+        READWRITE(fTimeReceivedIsTxTime);
+        READWRITE(nTimeReceived);
+        READWRITE(fFromMe);
+        READWRITE(fSpent);
+
+        if (fRead)
+        {
+            pthis->strFromAccount = pthis->mapValue["fromaccount"];
+
+            if (mapValue.count("spent"))
+                foreach(char c, pthis->mapValue["spent"])
+                    pthis->vfSpent.push_back(c != '0');
+            else
+                pthis->vfSpent.assign(vout.size(), fSpent);
+        }
+
+        pthis->mapValue.erase("fromaccount");
+        pthis->mapValue.erase("version");
+        pthis->mapValue.erase("spent");
+    )
+
+    // marks certain txout's as spent
+    // returns true if any update took place
+    bool UpdateSpent(const vector<char>& vfNewSpent)
+    {
+        bool fReturn = false;
+        for (int i=0; i < vfNewSpent.size(); i++)
+        {
+            if (i == vfSpent.size())
+                break;
+
+            if (vfNewSpent[i] && !vfSpent[i])
+            {
+                vfSpent[i] = true;
+                fReturn = true;
+                fAvailableCreditCached = false;
+            }
+        }
+        return fReturn;
+    }
+
+    void MarkDirty()
+    {
+        fCreditCached = false;
+        fAvailableCreditCached = false;
+        fDebitCached = false;
+        fChangeCached = false;
+    }
+
+    void MarkSpent(unsigned int nOut)
+    {
+        if (nOut >= vout.size())
+            throw runtime_error("CWalletTx::MarkSpent() : nOut out of range");
+        vfSpent.resize(vout.size());
+        if (!vfSpent[nOut])
+        {
+            vfSpent[nOut] = true;
+            fAvailableCreditCached = false;
+        }
+    }
+
+    bool IsSpent(unsigned int nOut) const
+    {
+        if (nOut >= vout.size())
+            throw runtime_error("CWalletTx::IsSpent() : nOut out of range");
+        if (nOut >= vfSpent.size())
+            return false;
+        return (!!vfSpent[nOut]);
+    }
+
+    int64 GetDebit() const
+    {
+        if (vin.empty())
+            return 0;
+        if (fDebitCached)
+            return nDebitCached;
+        nDebitCached = CTransaction::GetDebit();
+        fDebitCached = true;
+        return nDebitCached;
+    }
+
+    int64 GetCredit(bool fUseCache=true) const
+    {
+        // Must wait until coinbase is safely deep enough in the chain before valuing it
+        if (IsCoinBase() && GetBlocksToMaturity() > 0)
+            return 0;
+
+        // GetBalance can assume transactions in mapWallet won't change
+        if (fUseCache && fCreditCached)
+            return nCreditCached;
+        nCreditCached = CTransaction::GetCredit();
+        fCreditCached = true;
+        return nCreditCached;
+    }
+
+    int64 GetAvailableCredit(bool fUseCache=true) const
+    {
+        // Must wait until coinbase is safely deep enough in the chain before valuing it
+        if (IsCoinBase() && GetBlocksToMaturity() > 0)
+            return 0;
+
+        if (fUseCache && fAvailableCreditCached)
+            return nAvailableCreditCached;
+
+        int64 nCredit = 0;
+        for (int i = 0; i < vout.size(); i++)
+        {
+            if (!IsSpent(i))
+            {
+                const CTxOut &txout = vout[i];
+                nCredit += txout.GetCredit();
+                if (!MoneyRange(nCredit))
+                    throw runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+            }
+        }
+
+        nAvailableCreditCached = nCredit;
+        fAvailableCreditCached = true;
+        return nCredit;
+    }
+
+
+    int64 GetChange() const
+    {
+        if (fChangeCached)
+            return nChangeCached;
+        nChangeCached = CTransaction::GetChange();
+        fChangeCached = true;
+        return nChangeCached;
+    }
+
+    void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<string /* address */, int64> >& listReceived,
+                    list<pair<string /* address */, int64> >& listSent, int64& nFee, string& strSentAccount) const;
+
+    void GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived, 
+                           int64& nSent, int64& nFee) const;
+
+    bool IsFromMe() const
+    {
+        return (GetDebit() > 0);
+    }
+
+    bool IsConfirmed() const
+    {
+        // Quick answer in most cases
+        if (!IsFinal())
+            return false;
+        if (GetDepthInMainChain() >= 1)
+            return true;
+        if (!IsFromMe()) // using wtx's cached debit
+            return false;
+
+        // If no confirmations but it's from us, we can still
+        // consider it confirmed if all dependencies are confirmed
+        map<uint256, const CMerkleTx*> mapPrev;
+        vector<const CMerkleTx*> vWorkQueue;
+        vWorkQueue.reserve(vtxPrev.size()+1);
+        vWorkQueue.push_back(this);
+        for (int i = 0; i < vWorkQueue.size(); i++)
+        {
+            const CMerkleTx* ptx = vWorkQueue[i];
+
+            if (!ptx->IsFinal())
+                return false;
+            if (ptx->GetDepthInMainChain() >= 1)
+                continue;
+            if (!ptx->IsFromMe())
+                return false;
+
+            if (mapPrev.empty())
+                foreach(const CMerkleTx& tx, vtxPrev)
+                    mapPrev[tx.GetHash()] = &tx;
+
+            foreach(const CTxIn& txin, ptx->vin)
+            {
+                if (!mapPrev.count(txin.prevout.hash))
+                    return false;
+                vWorkQueue.push_back(mapPrev[txin.prevout.hash]);
+            }
+        }
+        return true;
+    }
+
+    bool WriteToDisk()
+    {
+        return CWalletDB().WriteTx(GetHash(), *this);
+    }
+
+
+    int64 GetTxTime() const;
+    int GetRequestCount() const;
+
+    void AddSupportingTransactions(CTxDB& txdb);
+
+    bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true);
+    bool AcceptWalletTransaction() { CTxDB txdb("r"); return AcceptWalletTransaction(txdb); }
+
+    void RelayWalletTransaction(CTxDB& txdb);
+    void RelayWalletTransaction() { CTxDB txdb("r"); RelayWalletTransaction(txdb); }
+};
+
+
+
+
+//
+// A txdb record that contains the disk location of a transaction and the
+// locations of transactions that spend its outputs.  vSpent is really only
+// used as a flag, but having the location is very helpful for debugging.
+//
+class CTxIndex
+{
+public:
+    CDiskTxPos pos;
+    vector<CDiskTxPos> vSpent;
+
+    CTxIndex()
+    {
+        SetNull();
+    }
+
+    CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs)
+    {
+        pos = posIn;
+        vSpent.resize(nOutputs);
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        if (!(nType & SER_GETHASH))
+            READWRITE(nVersion);
+        READWRITE(pos);
+        READWRITE(vSpent);
+    )
+
+    void SetNull()
+    {
+        pos.SetNull();
+        vSpent.clear();
+    }
+
+    bool IsNull()
+    {
+        return pos.IsNull();
+    }
+
+    friend bool operator==(const CTxIndex& a, const CTxIndex& b)
+    {
+        return (a.pos    == b.pos &&
+                a.vSpent == b.vSpent);
+    }
+
+    friend bool operator!=(const CTxIndex& a, const CTxIndex& b)
+    {
+        return !(a == b);
+    }
+    int GetDepthInMainChain() const;
+};
+
+
+
+
+
+//
+// Nodes collect new transactions into a block, hash them into a hash tree,
+// and scan through nonce values to make the block's hash satisfy proof-of-work
+// requirements.  When they solve the proof-of-work, they broadcast the block
+// to everyone and the block is added to the block chain.  The first transaction
+// in the block is a special one that creates a new coin owned by the creator
+// of the block.
+//
+// Blocks are appended to blk0001.dat files on disk.  Their location on disk
+// is indexed by CBlockIndex objects in memory.
+//
+class CBlock
+{
+public:
+    // header
+    int nVersion;
+    uint256 hashPrevBlock;
+    uint256 hashMerkleRoot;
+    unsigned int nTime;
+    unsigned int nBits;
+    unsigned int nNonce;
+
+    // network and disk
+    vector<CTransaction> vtx;
+
+    // memory only
+    mutable vector<uint256> vMerkleTree;
+
+
+    CBlock()
+    {
+        SetNull();
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(this->nVersion);
+        nVersion = this->nVersion;
+        READWRITE(hashPrevBlock);
+        READWRITE(hashMerkleRoot);
+        READWRITE(nTime);
+        READWRITE(nBits);
+        READWRITE(nNonce);
+
+        // ConnectBlock depends on vtx being last so it can calculate offset
+        if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))
+            READWRITE(vtx);
+        else if (fRead)
+            const_cast<CBlock*>(this)->vtx.clear();
+    )
+
+    void SetNull()
+    {
+        nVersion = 1;
+        hashPrevBlock = 0;
+        hashMerkleRoot = 0;
+        nTime = 0;
+        nBits = 0;
+        nNonce = 0;
+        vtx.clear();
+        vMerkleTree.clear();
+    }
+
+    bool IsNull() const
+    {
+        return (nBits == 0);
+    }
+
+    uint256 GetHash() const
+    {
+        return Hash(BEGIN(nVersion), END(nNonce));
+    }
+
+    int64 GetBlockTime() const
+    {
+        return (int64)nTime;
+    }
+
+    int GetSigOpCount() const
+    {
+        int n = 0;
+        foreach(const CTransaction& tx, vtx)
+            n += tx.GetSigOpCount();
+        return n;
+    }
+
+
+    uint256 BuildMerkleTree() const
+    {
+        vMerkleTree.clear();
+        foreach(const CTransaction& tx, vtx)
+            vMerkleTree.push_back(tx.GetHash());
+        int j = 0;
+        for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
+        {
+            for (int i = 0; i < nSize; i += 2)
+            {
+                int i2 = min(i+1, nSize-1);
+                vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]),  END(vMerkleTree[j+i]),
+                                           BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
+            }
+            j += nSize;
+        }
+        return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
+    }
+
+    vector<uint256> GetMerkleBranch(int nIndex) const
+    {
+        if (vMerkleTree.empty())
+            BuildMerkleTree();
+        vector<uint256> vMerkleBranch;
+        int j = 0;
+        for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
+        {
+            int i = min(nIndex^1, nSize-1);
+            vMerkleBranch.push_back(vMerkleTree[j+i]);
+            nIndex >>= 1;
+            j += nSize;
+        }
+        return vMerkleBranch;
+    }
+
+    static uint256 CheckMerkleBranch(uint256 hash, const vector<uint256>& vMerkleBranch, int nIndex)
+    {
+        if (nIndex == -1)
+            return 0;
+        foreach(const uint256& otherside, vMerkleBranch)
+        {
+            if (nIndex & 1)
+                hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
+            else
+                hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
+            nIndex >>= 1;
+        }
+        return hash;
+    }
+
+
+    bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet)
+    {
+        // Open history file to append
+        CAutoFile fileout = AppendBlockFile(nFileRet);
+        if (!fileout)
+            return error("CBlock::WriteToDisk() : AppendBlockFile failed");
+
+        // Write index header
+        unsigned int nSize = fileout.GetSerializeSize(*this);
+        fileout << FLATDATA(pchMessageStart) << nSize;
+
+        // Write block
+        nBlockPosRet = ftell(fileout);
+        if (nBlockPosRet == -1)
+            return error("CBlock::WriteToDisk() : ftell failed");
+        fileout << *this;
+
+        // Flush stdio buffers and commit to disk before returning
+        fflush(fileout);
+        if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
+        {
+#ifdef __WXMSW__
+            _commit(_fileno(fileout));
+#else
+            fsync(fileno(fileout));
+#endif
+        }
+
+        return true;
+    }
+
+    bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true)
+    {
+        SetNull();
+
+        // Open history file to read
+        CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb");
+        if (!filein)
+            return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
+        if (!fReadTransactions)
+            filein.nType |= SER_BLOCKHEADERONLY;
+
+        // Read block
+        filein >> *this;
+
+        // Check the header
+        if (!CheckProofOfWork(GetHash(), nBits))
+            return error("CBlock::ReadFromDisk() : errors in block header");
+
+        return true;
+    }
+
+
+
+    void print() const
+    {
+        printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n",
+            GetHash().ToString().substr(0,20).c_str(),
+            nVersion,
+            hashPrevBlock.ToString().substr(0,20).c_str(),
+            hashMerkleRoot.ToString().substr(0,10).c_str(),
+            nTime, nBits, nNonce,
+            vtx.size());
+        for (int i = 0; i < vtx.size(); i++)
+        {
+            printf("  ");
+            vtx[i].print();
+        }
+        printf("  vMerkleTree: ");
+        for (int i = 0; i < vMerkleTree.size(); i++)
+            printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str());
+        printf("\n");
+    }
+
+
+    bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
+    bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
+    bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
+    bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew);
+    bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
+    bool CheckBlock() const;
+    bool AcceptBlock();
+};
+
+
+
+
+
+
+//
+// The block chain is a tree shaped structure starting with the
+// genesis block at the root, with each block potentially having multiple
+// candidates to be the next block.  pprev and pnext link a path through the
+// main/longest chain.  A blockindex may have multiple pprev pointing back
+// to it, but pnext will only point forward to the longest branch, or will
+// be null if the block is not part of the longest chain.
+//
+class CBlockIndex
+{
+public:
+    const uint256* phashBlock;
+    CBlockIndex* pprev;
+    CBlockIndex* pnext;
+    unsigned int nFile;
+    unsigned int nBlockPos;
+    int nHeight;
+    CBigNum bnChainWork;
+
+    // block header
+    int nVersion;
+    uint256 hashMerkleRoot;
+    unsigned int nTime;
+    unsigned int nBits;
+    unsigned int nNonce;
+
+
+    CBlockIndex()
+    {
+        phashBlock = NULL;
+        pprev = NULL;
+        pnext = NULL;
+        nFile = 0;
+        nBlockPos = 0;
+        nHeight = 0;
+        bnChainWork = 0;
+
+        nVersion       = 0;
+        hashMerkleRoot = 0;
+        nTime          = 0;
+        nBits          = 0;
+        nNonce         = 0;
+    }
+
+    CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block)
+    {
+        phashBlock = NULL;
+        pprev = NULL;
+        pnext = NULL;
+        nFile = nFileIn;
+        nBlockPos = nBlockPosIn;
+        nHeight = 0;
+        bnChainWork = 0;
+
+        nVersion       = block.nVersion;
+        hashMerkleRoot = block.hashMerkleRoot;
+        nTime          = block.nTime;
+        nBits          = block.nBits;
+        nNonce         = block.nNonce;
+    }
+
+    CBlock GetBlockHeader() const
+    {
+        CBlock block;
+        block.nVersion       = nVersion;
+        if (pprev)
+            block.hashPrevBlock = pprev->GetBlockHash();
+        block.hashMerkleRoot = hashMerkleRoot;
+        block.nTime          = nTime;
+        block.nBits          = nBits;
+        block.nNonce         = nNonce;
+        return block;
+    }
+
+    uint256 GetBlockHash() const
+    {
+        return *phashBlock;
+    }
+
+    int64 GetBlockTime() const
+    {
+        return (int64)nTime;
+    }
+
+    CBigNum GetBlockWork() const
+    {
+        CBigNum bnTarget;
+        bnTarget.SetCompact(nBits);
+        if (bnTarget <= 0)
+            return 0;
+        return (CBigNum(1)<<256) / (bnTarget+1);
+    }
+
+    bool IsInMainChain() const
+    {
+        return (pnext || this == pindexBest);
+    }
+
+    bool CheckIndex() const
+    {
+        return CheckProofOfWork(GetBlockHash(), nBits);
+    }
+
+    bool EraseBlockFromDisk()
+    {
+        // Open history file
+        CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+");
+        if (!fileout)
+            return false;
+
+        // Overwrite with empty null block
+        CBlock block;
+        block.SetNull();
+        fileout << block;
+
+        return true;
+    }
+
+    enum { nMedianTimeSpan=11 };
+
+    int64 GetMedianTimePast() const
+    {
+        int64 pmedian[nMedianTimeSpan];
+        int64* pbegin = &pmedian[nMedianTimeSpan];
+        int64* pend = &pmedian[nMedianTimeSpan];
+
+        const CBlockIndex* pindex = this;
+        for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
+            *(--pbegin) = pindex->GetBlockTime();
+
+        sort(pbegin, pend);
+        return pbegin[(pend - pbegin)/2];
+    }
+
+    int64 GetMedianTime() const
+    {
+        const CBlockIndex* pindex = this;
+        for (int i = 0; i < nMedianTimeSpan/2; i++)
+        {
+            if (!pindex->pnext)
+                return GetBlockTime();
+            pindex = pindex->pnext;
+        }
+        return pindex->GetMedianTimePast();
+    }
+
+
+
+    string ToString() const
+    {
+        return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",
+            pprev, pnext, nFile, nBlockPos, nHeight,
+            hashMerkleRoot.ToString().substr(0,10).c_str(),
+            GetBlockHash().ToString().substr(0,20).c_str());
+    }
+
+    void print() const
+    {
+        printf("%s\n", ToString().c_str());
+    }
+};
+
+
+
+//
+// Used to marshal pointers into hashes for db storage.
+//
+class CDiskBlockIndex : public CBlockIndex
+{
+public:
+    uint256 hashPrev;
+    uint256 hashNext;
+
+    CDiskBlockIndex()
+    {
+        hashPrev = 0;
+        hashNext = 0;
+    }
+
+    explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex)
+    {
+        hashPrev = (pprev ? pprev->GetBlockHash() : 0);
+        hashNext = (pnext ? pnext->GetBlockHash() : 0);
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        if (!(nType & SER_GETHASH))
+            READWRITE(nVersion);
+
+        READWRITE(hashNext);
+        READWRITE(nFile);
+        READWRITE(nBlockPos);
+        READWRITE(nHeight);
+
+        // block header
+        READWRITE(this->nVersion);
+        READWRITE(hashPrev);
+        READWRITE(hashMerkleRoot);
+        READWRITE(nTime);
+        READWRITE(nBits);
+        READWRITE(nNonce);
+    )
+
+    uint256 GetBlockHash() const
+    {
+        CBlock block;
+        block.nVersion        = nVersion;
+        block.hashPrevBlock   = hashPrev;
+        block.hashMerkleRoot  = hashMerkleRoot;
+        block.nTime           = nTime;
+        block.nBits           = nBits;
+        block.nNonce          = nNonce;
+        return block.GetHash();
+    }
+
+
+    string ToString() const
+    {
+        string str = "CDiskBlockIndex(";
+        str += CBlockIndex::ToString();
+        str += strprintf("\n                hashBlock=%s, hashPrev=%s, hashNext=%s)",
+            GetBlockHash().ToString().c_str(),
+            hashPrev.ToString().substr(0,20).c_str(),
+            hashNext.ToString().substr(0,20).c_str());
+        return str;
+    }
+
+    void print() const
+    {
+        printf("%s\n", ToString().c_str());
+    }
+};
+
+
+
+
+
+
+
+
+//
+// Describes a place in the block chain to another node such that if the
+// other node doesn't have the same branch, it can find a recent common trunk.
+// The further back it is, the further before the fork it may be.
+//
+class CBlockLocator
+{
+protected:
+    vector<uint256> vHave;
+public:
+
+    CBlockLocator()
+    {
+    }
+
+    explicit CBlockLocator(const CBlockIndex* pindex)
+    {
+        Set(pindex);
+    }
+
+    explicit CBlockLocator(uint256 hashBlock)
+    {
+        map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
+        if (mi != mapBlockIndex.end())
+            Set((*mi).second);
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        if (!(nType & SER_GETHASH))
+            READWRITE(nVersion);
+        READWRITE(vHave);
+    )
+
+    void SetNull()
+    {
+        vHave.clear();
+    }
+
+    bool IsNull()
+    {
+        return vHave.empty();
+    }
+
+    void Set(const CBlockIndex* pindex)
+    {
+        vHave.clear();
+        int nStep = 1;
+        while (pindex)
+        {
+            vHave.push_back(pindex->GetBlockHash());
+
+            // Exponentially larger steps back
+            for (int i = 0; pindex && i < nStep; i++)
+                pindex = pindex->pprev;
+            if (vHave.size() > 10)
+                nStep *= 2;
+        }
+        vHave.push_back(hashGenesisBlock);
+    }
+
+    int GetDistanceBack()
+    {
+        // Retrace how far back it was in the sender's branch
+        int nDistance = 0;
+        int nStep = 1;
+        foreach(const uint256& hash, vHave)
+        {
+            map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+            if (mi != mapBlockIndex.end())
+            {
+                CBlockIndex* pindex = (*mi).second;
+                if (pindex->IsInMainChain())
+                    return nDistance;
+            }
+            nDistance += nStep;
+            if (nDistance > 10)
+                nStep *= 2;
+        }
+        return nDistance;
+    }
+
+    CBlockIndex* GetBlockIndex()
+    {
+        // Find the first block the caller has in the main chain
+        foreach(const uint256& hash, vHave)
+        {
+            map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+            if (mi != mapBlockIndex.end())
+            {
+                CBlockIndex* pindex = (*mi).second;
+                if (pindex->IsInMainChain())
+                    return pindex;
+            }
+        }
+        return pindexGenesisBlock;
+    }
+
+    uint256 GetBlockHash()
+    {
+        // Find the first block the caller has in the main chain
+        foreach(const uint256& hash, vHave)
+        {
+            map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+            if (mi != mapBlockIndex.end())
+            {
+                CBlockIndex* pindex = (*mi).second;
+                if (pindex->IsInMainChain())
+                    return hash;
+            }
+        }
+        return hashGenesisBlock;
+    }
+
+    int GetHeight()
+    {
+        CBlockIndex* pindex = GetBlockIndex();
+        if (!pindex)
+            return 0;
+        return pindex->nHeight;
+    }
+};
+
+
+
+
+
+
+//
+// Private key that includes an expiration date in case it never gets used.
+//
+class CWalletKey
+{
+public:
+    CPrivKey vchPrivKey;
+    int64 nTimeCreated;
+    int64 nTimeExpires;
+    string strComment;
+    //// todo: add something to note what created it (user, getnewaddress, change)
+    ////   maybe should have a map<string, string> property map
+
+    CWalletKey(int64 nExpires=0)
+    {
+        nTimeCreated = (nExpires ? GetTime() : 0);
+        nTimeExpires = nExpires;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        if (!(nType & SER_GETHASH))
+            READWRITE(nVersion);
+        READWRITE(vchPrivKey);
+        READWRITE(nTimeCreated);
+        READWRITE(nTimeExpires);
+        READWRITE(strComment);
+    )
+};
+
+
+
+
+
+
+//
+// Account information.
+// Stored in wallet with key "acc"+string account name
+//
+class CAccount
+{
+public:
+    vector<unsigned char> vchPubKey;
+
+    CAccount()
+    {
+        SetNull();
+    }
+
+    void SetNull()
+    {
+        vchPubKey.clear();
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        if (!(nType & SER_GETHASH))
+            READWRITE(nVersion);
+        READWRITE(vchPubKey);
+    )
+};
+
+
+
+//
+// Internal transfers.
+// Database key is acentry<account><counter>
+//
+class CAccountingEntry
+{
+public:
+    string strAccount;
+    int64 nCreditDebit;
+    int64 nTime;
+    string strOtherAccount;
+    string strComment;
+
+    CAccountingEntry()
+    {
+        SetNull();
+    }
+
+    void SetNull()
+    {
+        nCreditDebit = 0;
+        nTime = 0;
+        strAccount.clear();
+        strOtherAccount.clear();
+        strComment.clear();
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        if (!(nType & SER_GETHASH))
+            READWRITE(nVersion);
+        // Note: strAccount is serialized as part of the key, not here.
+        READWRITE(nCreditDebit);
+        READWRITE(nTime);
+        READWRITE(strOtherAccount);
+        READWRITE(strComment);
+    )
+};
+
+
+
+
+
+
+
+
+
+//
+// Alerts are for notifying old versions if they become too obsolete and
+// need to upgrade.  The message is displayed in the status bar.
+// Alert messages are broadcast as a vector of signed data.  Unserializing may
+// not read the entire buffer if the alert is for a newer version, but older
+// versions can still relay the original data.
+//
+class CUnsignedAlert
+{
+public:
+    int nVersion;
+    int64 nRelayUntil;      // when newer nodes stop relaying to newer nodes
+    int64 nExpiration;
+    int nID;
+    int nCancel;
+    set<int> setCancel;
+    int nMinVer;            // lowest version inclusive
+    int nMaxVer;            // highest version inclusive
+    set<string> setSubVer;  // empty matches all
+    int nPriority;
+
+    // Actions
+    string strComment;
+    string strStatusBar;
+    string strReserved;
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(this->nVersion);
+        nVersion = this->nVersion;
+        READWRITE(nRelayUntil);
+        READWRITE(nExpiration);
+        READWRITE(nID);
+        READWRITE(nCancel);
+        READWRITE(setCancel);
+        READWRITE(nMinVer);
+        READWRITE(nMaxVer);
+        READWRITE(setSubVer);
+        READWRITE(nPriority);
+
+        READWRITE(strComment);
+        READWRITE(strStatusBar);
+        READWRITE(strReserved);
+    )
+
+    void SetNull()
+    {
+        nVersion = 1;
+        nRelayUntil = 0;
+        nExpiration = 0;
+        nID = 0;
+        nCancel = 0;
+        setCancel.clear();
+        nMinVer = 0;
+        nMaxVer = 0;
+        setSubVer.clear();
+        nPriority = 0;
+
+        strComment.clear();
+        strStatusBar.clear();
+        strReserved.clear();
+    }
+
+    string ToString() const
+    {
+        string strSetCancel;
+        foreach(int n, setCancel)
+            strSetCancel += strprintf("%d ", n);
+        string strSetSubVer;
+        foreach(string str, setSubVer)
+            strSetSubVer += "\"" + str + "\" ";
+        return strprintf(
+                "CAlert(\n"
+                "    nVersion     = %d\n"
+                "    nRelayUntil  = %"PRI64d"\n"
+                "    nExpiration  = %"PRI64d"\n"
+                "    nID          = %d\n"
+                "    nCancel      = %d\n"
+                "    setCancel    = %s\n"
+                "    nMinVer      = %d\n"
+                "    nMaxVer      = %d\n"
+                "    setSubVer    = %s\n"
+                "    nPriority    = %d\n"
+                "    strComment   = \"%s\"\n"
+                "    strStatusBar = \"%s\"\n"
+                ")\n",
+            nVersion,
+            nRelayUntil,
+            nExpiration,
+            nID,
+            nCancel,
+            strSetCancel.c_str(),
+            nMinVer,
+            nMaxVer,
+            strSetSubVer.c_str(),
+            nPriority,
+            strComment.c_str(),
+            strStatusBar.c_str());
+    }
+
+    void print() const
+    {
+        printf("%s", ToString().c_str());
+    }
+};
+
+class CAlert : public CUnsignedAlert
+{
+public:
+    vector<unsigned char> vchMsg;
+    vector<unsigned char> vchSig;
+
+    CAlert()
+    {
+        SetNull();
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(vchMsg);
+        READWRITE(vchSig);
+    )
+
+    void SetNull()
+    {
+        CUnsignedAlert::SetNull();
+        vchMsg.clear();
+        vchSig.clear();
+    }
+
+    bool IsNull() const
+    {
+        return (nExpiration == 0);
+    }
+
+    uint256 GetHash() const
+    {
+        return SerializeHash(*this);
+    }
+
+    bool IsInEffect() const
+    {
+        return (GetAdjustedTime() < nExpiration);
+    }
+
+    bool Cancels(const CAlert& alert) const
+    {
+        if (!IsInEffect())
+            return false; // this was a no-op before 31403
+        return (alert.nID <= nCancel || setCancel.count(alert.nID));
+    }
+
+    bool AppliesTo(int nVersion, string strSubVerIn) const
+    {
+        return (IsInEffect() &&
+                nMinVer <= nVersion && nVersion <= nMaxVer &&
+                (setSubVer.empty() || setSubVer.count(strSubVerIn)));
+    }
+
+    bool AppliesToMe() const
+    {
+        return AppliesTo(VERSION, ::pszSubVer);
+    }
+
+    bool RelayTo(CNode* pnode) const
+    {
+        if (!IsInEffect())
+            return false;
+        // returns true if wasn't already contained in the set
+        if (pnode->setKnown.insert(GetHash()).second)
+        {
+            if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
+                AppliesToMe() ||
+                GetAdjustedTime() < nRelayUntil)
+            {
+                pnode->PushMessage("alert", *this);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    bool CheckSignature()
+    {
+        CKey key;
+        if (!key.SetPubKey(ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284")))
+            return error("CAlert::CheckSignature() : SetPubKey failed");
+        if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
+            return error("CAlert::CheckSignature() : verify signature failed");
+
+        // Now unserialize the data
+        CDataStream sMsg(vchMsg);
+        sMsg >> *(CUnsignedAlert*)this;
+        return true;
+    }
+
+    bool ProcessAlert();
+};
+
+
+
+
+
+
+
+
+
+
+extern map<uint256, CTransaction> mapTransactions;
+extern map<uint256, CWalletTx> mapWallet;
+extern vector<uint256> vWalletUpdated;
+extern CCriticalSection cs_mapWallet;
+extern map<vector<unsigned char>, CPrivKey> mapKeys;
+extern map<uint160, vector<unsigned char> > mapPubKeys;
+extern CCriticalSection cs_mapKeys;
+extern CKey keyUser;
+
+#endif
diff --git a/core/include/net.h b/core/include/net.h
new file mode 100644 (file)
index 0000000..746dd02
--- /dev/null
@@ -0,0 +1,1046 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_NET_H
+#define BITCOIN_NET_H
+
+#include <deque>
+#include <boost/array.hpp>
+#include <arpa/inet.h>
+#include <openssl/rand.h>
+
+class CMessageHeader;
+class CAddress;
+class CInv;
+class CRequestTracker;
+class CNode;
+class CBlockIndex;
+extern int nBestHeight;
+
+
+
+inline unsigned short GetDefaultPort() { return fTestNet ? 18333 : 8333; }
+static const unsigned int PUBLISH_HOPS = 5;
+enum
+{
+    NODE_NETWORK = (1 << 0),
+};
+
+
+
+
+bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet);
+bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
+bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
+bool GetMyExternalIP(unsigned int& ipRet);
+bool AddAddress(CAddress addr, int64 nTimePenalty=0);
+void AddressCurrentlyConnected(const CAddress& addr);
+CNode* FindNode(unsigned int ip);
+CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
+void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
+bool AnySubscribed(unsigned int nChannel);
+void MapPort(bool fMapPort);
+void DNSAddressSeed();
+bool BindListenPort(std::string& strError=REF(std::string()));
+void StartNode(void* parg);
+bool StopNode();
+
+
+
+
+
+
+
+
+//
+// Message header
+//  (4) message start
+//  (12) command
+//  (4) size
+//  (4) checksum
+
+extern char pchMessageStart[4];
+
+class CMessageHeader
+{
+public:
+    enum { COMMAND_SIZE=12 };
+    char pchMessageStart[sizeof(::pchMessageStart)];
+    char pchCommand[COMMAND_SIZE];
+    unsigned int nMessageSize;
+    unsigned int nChecksum;
+
+    CMessageHeader()
+    {
+        memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
+        memset(pchCommand, 0, sizeof(pchCommand));
+        pchCommand[1] = 1;
+        nMessageSize = -1;
+        nChecksum = 0;
+    }
+
+    CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
+    {
+        memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
+        strncpy(pchCommand, pszCommand, COMMAND_SIZE);
+        nMessageSize = nMessageSizeIn;
+        nChecksum = 0;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(FLATDATA(pchMessageStart));
+        READWRITE(FLATDATA(pchCommand));
+        READWRITE(nMessageSize);
+        if (nVersion >= 209)
+            READWRITE(nChecksum);
+    )
+
+    std::string GetCommand()
+    {
+        if (pchCommand[COMMAND_SIZE-1] == 0)
+            return std::string(pchCommand, pchCommand + strlen(pchCommand));
+        else
+            return std::string(pchCommand, pchCommand + COMMAND_SIZE);
+    }
+
+    bool IsValid()
+    {
+        // Check start string
+        if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
+            return false;
+
+        // Check the command string for errors
+        for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
+        {
+            if (*p1 == 0)
+            {
+                // Must be all zeros after the first zero
+                for (; p1 < pchCommand + COMMAND_SIZE; p1++)
+                    if (*p1 != 0)
+                        return false;
+            }
+            else if (*p1 < ' ' || *p1 > 0x7E)
+                return false;
+        }
+
+        // Message size
+        if (nMessageSize > MAX_SIZE)
+        {
+            printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize);
+            return false;
+        }
+
+        return true;
+    }
+};
+
+
+
+
+
+
+static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
+
+class CAddress
+{
+public:
+    uint64 nServices;
+    unsigned char pchReserved[12];
+    unsigned int ip;
+    unsigned short port;
+
+    // disk and network only
+    unsigned int nTime;
+
+    // memory only
+    unsigned int nLastTry;
+
+    CAddress()
+    {
+        Init();
+    }
+
+    CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        ip = ipIn;
+        port = htons(portIn == 0 ? GetDefaultPort() : portIn);
+        nServices = nServicesIn;
+    }
+
+    explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        ip = sockaddr.sin_addr.s_addr;
+        port = sockaddr.sin_port;
+        nServices = nServicesIn;
+    }
+
+    explicit CAddress(const char* pszIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        Lookup(pszIn, *this, nServicesIn, fNameLookup, portIn);
+    }
+
+    explicit CAddress(const char* pszIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        Lookup(pszIn, *this, nServicesIn, fNameLookup, 0, true);
+    }
+
+    explicit CAddress(std::string strIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, portIn);
+    }
+
+    explicit CAddress(std::string strIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, 0, true);
+    }
+
+    void Init()
+    {
+        nServices = NODE_NETWORK;
+        memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
+        ip = INADDR_NONE;
+        port = htons(GetDefaultPort());
+        nTime = 100000000;
+        nLastTry = 0;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        if (fRead)
+            const_cast<CAddress*>(this)->Init();
+        if (nType & SER_DISK)
+            READWRITE(nVersion);
+        if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
+            READWRITE(nTime);
+        READWRITE(nServices);
+        READWRITE(FLATDATA(pchReserved)); // for IPv6
+        READWRITE(ip);
+        READWRITE(port);
+    )
+
+    friend inline bool operator==(const CAddress& a, const CAddress& b)
+    {
+        return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
+                a.ip   == b.ip &&
+                a.port == b.port);
+    }
+
+    friend inline bool operator!=(const CAddress& a, const CAddress& b)
+    {
+        return (!(a == b));
+    }
+
+    friend inline bool operator<(const CAddress& a, const CAddress& b)
+    {
+        int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
+        if (ret < 0)
+            return true;
+        else if (ret == 0)
+        {
+            if (ntohl(a.ip) < ntohl(b.ip))
+                return true;
+            else if (a.ip == b.ip)
+                return ntohs(a.port) < ntohs(b.port);
+        }
+        return false;
+    }
+
+    std::vector<unsigned char> GetKey() const
+    {
+        CDataStream ss;
+        ss.reserve(18);
+        ss << FLATDATA(pchReserved) << ip << port;
+
+        #if defined(_MSC_VER) && _MSC_VER < 1300
+        return std::vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
+        #else
+        return std::vector<unsigned char>(ss.begin(), ss.end());
+        #endif
+    }
+
+    struct sockaddr_in GetSockAddr() const
+    {
+        struct sockaddr_in sockaddr;
+        memset(&sockaddr, 0, sizeof(sockaddr));
+        sockaddr.sin_family = AF_INET;
+        sockaddr.sin_addr.s_addr = ip;
+        sockaddr.sin_port = port;
+        return sockaddr;
+    }
+
+    bool IsIPv4() const
+    {
+        return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
+    }
+
+    bool IsRoutable() const
+    {
+        return IsValid() &&
+            !(GetByte(3) == 10 ||
+              (GetByte(3) == 192 && GetByte(2) == 168) ||
+              GetByte(3) == 127 ||
+              GetByte(3) == 0);
+    }
+
+    bool IsValid() const
+    {
+        // Clean up 3-byte shifted addresses caused by garbage in size field
+        // of addr messages from versions before 0.2.9 checksum.
+        // Two consecutive addr messages look like this:
+        // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
+        // so if the first length field is garbled, it reads the second batch
+        // of addr misaligned by 3 bytes.
+        if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
+            return false;
+
+        return (ip != 0 && ip != INADDR_NONE && port != htons(USHRT_MAX));
+    }
+
+    unsigned char GetByte(int n) const
+    {
+        return ((unsigned char*)&ip)[3-n];
+    }
+
+    std::string ToStringIPPort() const
+    {
+        return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
+    }
+
+    std::string ToStringIP() const
+    {
+        return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
+    }
+
+    std::string ToStringPort() const
+    {
+        return strprintf("%u", ntohs(port));
+    }
+
+    std::string ToString() const
+    {
+        return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
+    }
+
+    void print() const
+    {
+        printf("CAddress(%s)\n", ToString().c_str());
+    }
+};
+
+
+
+
+
+
+
+enum
+{
+    MSG_TX = 1,
+    MSG_BLOCK,
+};
+
+static const char* ppszTypeName[] =
+{
+    "ERROR",
+    "tx",
+    "block",
+};
+
+class CInv
+{
+public:
+    int type;
+    uint256 hash;
+
+    CInv()
+    {
+        type = 0;
+        hash = 0;
+    }
+
+    CInv(int typeIn, const uint256& hashIn)
+    {
+        type = typeIn;
+        hash = hashIn;
+    }
+
+    CInv(const std::string& strType, const uint256& hashIn)
+    {
+        int i;
+        for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
+        {
+            if (strType == ppszTypeName[i])
+            {
+                type = i;
+                break;
+            }
+        }
+        if (i == ARRAYLEN(ppszTypeName))
+            throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
+        hash = hashIn;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(type);
+        READWRITE(hash);
+    )
+
+    friend inline bool operator<(const CInv& a, const CInv& b)
+    {
+        return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
+    }
+
+    bool IsKnownType() const
+    {
+        return (type >= 1 && type < ARRAYLEN(ppszTypeName));
+    }
+
+    const char* GetCommand() const
+    {
+        if (!IsKnownType())
+            throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
+        return ppszTypeName[type];
+    }
+
+    std::string ToString() const
+    {
+        return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
+    }
+
+    void print() const
+    {
+        printf("CInv(%s)\n", ToString().c_str());
+    }
+};
+
+
+
+
+
+class CRequestTracker
+{
+public:
+    void (*fn)(void*, CDataStream&);
+    void* param1;
+
+    explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
+    {
+        fn = fnIn;
+        param1 = param1In;
+    }
+
+    bool IsNull()
+    {
+        return fn == NULL;
+    }
+};
+
+
+
+
+
+extern bool fClient;
+extern bool fAllowDNS;
+extern uint64 nLocalServices;
+extern CAddress addrLocalHost;
+extern CNode* pnodeLocalHost;
+extern uint64 nLocalHostNonce;
+extern boost::array<int, 10> vnThreadsRunning;
+extern SOCKET hListenSocket;
+
+extern std::vector<CNode*> vNodes;
+extern CCriticalSection cs_vNodes;
+extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
+extern CCriticalSection cs_mapAddresses;
+extern std::map<CInv, CDataStream> mapRelay;
+extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
+extern CCriticalSection cs_mapRelay;
+extern std::map<CInv, int64> mapAlreadyAskedFor;
+
+// Settings
+extern int fUseProxy;
+extern CAddress addrProxy;
+
+
+
+
+
+
+class CNode
+{
+public:
+    // socket
+    uint64 nServices;
+    SOCKET hSocket;
+    CDataStream vSend;
+    CDataStream vRecv;
+    CCriticalSection cs_vSend;
+    CCriticalSection cs_vRecv;
+    int64 nLastSend;
+    int64 nLastRecv;
+    int64 nLastSendEmpty;
+    int64 nTimeConnected;
+    unsigned int nHeaderStart;
+    unsigned int nMessageStart;
+    CAddress addr;
+    int nVersion;
+    std::string strSubVer;
+    bool fClient;
+    bool fInbound;
+    bool fNetworkNode;
+    bool fSuccessfullyConnected;
+    bool fDisconnect;
+protected:
+    int nRefCount;
+public:
+    int64 nReleaseTime;
+    std::map<uint256, CRequestTracker> mapRequests;
+    CCriticalSection cs_mapRequests;
+    uint256 hashContinue;
+    CBlockIndex* pindexLastGetBlocksBegin;
+    uint256 hashLastGetBlocksEnd;
+    int nStartingHeight;
+
+    // flood relay
+    std::vector<CAddress> vAddrToSend;
+    std::set<CAddress> setAddrKnown;
+    bool fGetAddr;
+    std::set<uint256> setKnown;
+
+    // inventory based relay
+    std::set<CInv> setInventoryKnown;
+    std::vector<CInv> vInventoryToSend;
+    CCriticalSection cs_inventory;
+    std::multimap<int64, CInv> mapAskFor;
+
+    // publish and subscription
+    std::vector<char> vfSubscribe;
+
+
+    CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
+    {
+        nServices = 0;
+        hSocket = hSocketIn;
+        vSend.SetType(SER_NETWORK);
+        vSend.SetVersion(0);
+        vRecv.SetType(SER_NETWORK);
+        vRecv.SetVersion(0);
+        // Version 0.2 obsoletes 20 Feb 2012
+        if (GetTime() > 1329696000)
+        {
+            vSend.SetVersion(209);
+            vRecv.SetVersion(209);
+        }
+        nLastSend = 0;
+        nLastRecv = 0;
+        nLastSendEmpty = GetTime();
+        nTimeConnected = GetTime();
+        nHeaderStart = -1;
+        nMessageStart = -1;
+        addr = addrIn;
+        nVersion = 0;
+        strSubVer = "";
+        fClient = false; // set by version message
+        fInbound = fInboundIn;
+        fNetworkNode = false;
+        fSuccessfullyConnected = false;
+        fDisconnect = false;
+        nRefCount = 0;
+        nReleaseTime = 0;
+        hashContinue = 0;
+        pindexLastGetBlocksBegin = 0;
+        hashLastGetBlocksEnd = 0;
+        nStartingHeight = -1;
+        fGetAddr = false;
+        vfSubscribe.assign(256, false);
+
+        // Be shy and don't send version until we hear
+        if (!fInbound)
+            PushVersion();
+    }
+
+    ~CNode()
+    {
+        if (hSocket != INVALID_SOCKET)
+        {
+            closesocket(hSocket);
+            hSocket = INVALID_SOCKET;
+        }
+    }
+
+private:
+    CNode(const CNode&);
+    void operator=(const CNode&);
+public:
+
+
+    int GetRefCount()
+    {
+        return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
+    }
+
+    CNode* AddRef(int64 nTimeout=0)
+    {
+        if (nTimeout != 0)
+            nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
+        else
+            nRefCount++;
+        return this;
+    }
+
+    void Release()
+    {
+        nRefCount--;
+    }
+
+
+
+    void AddAddressKnown(const CAddress& addr)
+    {
+        setAddrKnown.insert(addr);
+    }
+
+    void PushAddress(const CAddress& addr)
+    {
+        // Known checking here is only to save space from duplicates.
+        // SendMessages will filter it again for knowns that were added
+        // after addresses were pushed.
+        if (addr.IsValid() && !setAddrKnown.count(addr))
+            vAddrToSend.push_back(addr);
+    }
+
+
+    void AddInventoryKnown(const CInv& inv)
+    {
+        CRITICAL_BLOCK(cs_inventory)
+            setInventoryKnown.insert(inv);
+    }
+
+    void PushInventory(const CInv& inv)
+    {
+        CRITICAL_BLOCK(cs_inventory)
+            if (!setInventoryKnown.count(inv))
+                vInventoryToSend.push_back(inv);
+    }
+
+    void AskFor(const CInv& inv)
+    {
+        // We're using mapAskFor as a priority queue,
+        // the key is the earliest time the request can be sent
+        int64& nRequestTime = mapAlreadyAskedFor[inv];
+        printf("askfor %s   %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
+
+        // Make sure not to reuse time indexes to keep things in the same order
+        int64 nNow = (GetTime() - 1) * 1000000;
+        static int64 nLastTime;
+        nLastTime = nNow = std::max(nNow, ++nLastTime);
+
+        // Each retry is 2 minutes after the last
+        nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
+        mapAskFor.insert(std::make_pair(nRequestTime, inv));
+    }
+
+
+
+    void BeginMessage(const char* pszCommand)
+    {
+        cs_vSend.Enter();
+        if (nHeaderStart != -1)
+            AbortMessage();
+        nHeaderStart = vSend.size();
+        vSend << CMessageHeader(pszCommand, 0);
+        nMessageStart = vSend.size();
+        if (fDebug)
+            printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+        printf("sending: %s ", pszCommand);
+    }
+
+    void AbortMessage()
+    {
+        if (nHeaderStart == -1)
+            return;
+        vSend.resize(nHeaderStart);
+        nHeaderStart = -1;
+        nMessageStart = -1;
+        cs_vSend.Leave();
+        printf("(aborted)\n");
+    }
+
+    void EndMessage()
+    {
+        if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
+        {
+            printf("dropmessages DROPPING SEND MESSAGE\n");
+            AbortMessage();
+            return;
+        }
+
+        if (nHeaderStart == -1)
+            return;
+
+        // Set the size
+        unsigned int nSize = vSend.size() - nMessageStart;
+        memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
+
+        // Set the checksum
+        if (vSend.GetVersion() >= 209)
+        {
+            uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
+            unsigned int nChecksum = 0;
+            memcpy(&nChecksum, &hash, sizeof(nChecksum));
+            assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
+            memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
+        }
+
+        printf("(%d bytes) ", nSize);
+        printf("\n");
+
+        nHeaderStart = -1;
+        nMessageStart = -1;
+        cs_vSend.Leave();
+    }
+
+    void EndMessageAbortIfEmpty()
+    {
+        if (nHeaderStart == -1)
+            return;
+        int nSize = vSend.size() - nMessageStart;
+        if (nSize > 0)
+            EndMessage();
+        else
+            AbortMessage();
+    }
+
+
+
+    void PushVersion()
+    {
+        /// when NTP implemented, change to just nTime = GetAdjustedTime()
+        int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
+        CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
+        CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
+        RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
+        PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
+                    nLocalHostNonce, std::string(pszSubVer), nBestHeight);
+    }
+
+
+
+
+    void PushMessage(const char* pszCommand)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1>
+    void PushMessage(const char* pszCommand, const T1& a1)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+
+    void PushRequest(const char* pszCommand,
+                     void (*fn)(void*, CDataStream&), void* param1)
+    {
+        uint256 hashReply;
+        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
+
+        CRITICAL_BLOCK(cs_mapRequests)
+            mapRequests[hashReply] = CRequestTracker(fn, param1);
+
+        PushMessage(pszCommand, hashReply);
+    }
+
+    template<typename T1>
+    void PushRequest(const char* pszCommand, const T1& a1,
+                     void (*fn)(void*, CDataStream&), void* param1)
+    {
+        uint256 hashReply;
+        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
+
+        CRITICAL_BLOCK(cs_mapRequests)
+            mapRequests[hashReply] = CRequestTracker(fn, param1);
+
+        PushMessage(pszCommand, hashReply, a1);
+    }
+
+    template<typename T1, typename T2>
+    void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
+                     void (*fn)(void*, CDataStream&), void* param1)
+    {
+        uint256 hashReply;
+        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
+
+        CRITICAL_BLOCK(cs_mapRequests)
+            mapRequests[hashReply] = CRequestTracker(fn, param1);
+
+        PushMessage(pszCommand, hashReply, a1, a2);
+    }
+
+
+
+    void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
+    bool IsSubscribed(unsigned int nChannel);
+    void Subscribe(unsigned int nChannel, unsigned int nHops=0);
+    void CancelSubscribe(unsigned int nChannel);
+    void CloseSocketDisconnect();
+    void Cleanup();
+};
+
+
+
+
+
+
+
+
+
+
+inline void RelayInventory(const CInv& inv)
+{
+    // Put on lists to offer to the other nodes
+    CRITICAL_BLOCK(cs_vNodes)
+        BOOST_FOREACH(CNode* pnode, vNodes)
+            pnode->PushInventory(inv);
+}
+
+template<typename T>
+void RelayMessage(const CInv& inv, const T& a)
+{
+    CDataStream ss(SER_NETWORK);
+    ss.reserve(10000);
+    ss << a;
+    RelayMessage(inv, ss);
+}
+
+template<>
+inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
+{
+    CRITICAL_BLOCK(cs_mapRelay)
+    {
+        // Expire old relay messages
+        while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
+        {
+            mapRelay.erase(vRelayExpiration.front().second);
+            vRelayExpiration.pop_front();
+        }
+
+        // Save original serialized message so newer versions are preserved
+        mapRelay[inv] = ss;
+        vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
+    }
+
+    RelayInventory(inv);
+}
+
+
+
+
+
+
+
+
+//
+// Templates for the publish and subscription system.
+// The object being published as T& obj needs to have:
+//   a set<unsigned int> setSources member
+//   specializations of AdvertInsert and AdvertErase
+// Currently implemented for CTable and CProduct.
+//
+
+template<typename T>
+void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
+{
+    // Add to sources
+    obj.setSources.insert(pfrom->addr.ip);
+
+    if (!AdvertInsert(obj))
+        return;
+
+    // Relay
+    CRITICAL_BLOCK(cs_vNodes)
+        BOOST_FOREACH(CNode* pnode, vNodes)
+            if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
+                pnode->PushMessage("publish", nChannel, nHops, obj);
+}
+
+template<typename T>
+void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
+{
+    uint256 hash = obj.GetHash();
+
+    CRITICAL_BLOCK(cs_vNodes)
+        BOOST_FOREACH(CNode* pnode, vNodes)
+            if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
+                pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
+
+    AdvertErase(obj);
+}
+
+template<typename T>
+void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
+{
+    // Remove a source
+    obj.setSources.erase(pfrom->addr.ip);
+
+    // If no longer supported by any sources, cancel it
+    if (obj.setSources.empty())
+        AdvertStopPublish(pfrom, nChannel, nHops, obj);
+}
+
+#endif
index f810b33..8e7677a 100644 (file)
@@ -9,6 +9,9 @@
 #include <map>
 #include <set>
 #include <cassert>
+#include <climits>
+#include <cstring>
+#include <cstdio>
 
 #include <boost/type_traits/is_fundamental.hpp>
 #include <boost/tuple/tuple.hpp>
diff --git a/core/include/strlcpy.h b/core/include/strlcpy.h
new file mode 100644 (file)
index 0000000..d4d1908
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef BITCOIN_STRLCPY_H
+#define BITCOIN_STRLCPY_H
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+inline size_t strlcpy(char *dst, const char *src, size_t siz)
+{
+    char *d = dst;
+    const char *s = src;
+    size_t n = siz;
+
+    /* Copy as many bytes as will fit */
+    if (n != 0)
+    {
+        while (--n != 0)
+        {
+            if ((*d++ = *s++) == '\0')
+                break;
+        }
+    }
+
+    /* Not enough room in dst, add NUL and traverse rest of src */
+    if (n == 0)
+    {
+        if (siz != 0)
+            *d = '\0';  /* NUL-terminate dst */
+        while (*s++)
+            ;
+    }
+
+    return(s - src - 1); /* count does not include NUL */
+}
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+inline size_t strlcat(char *dst, const char *src, size_t siz)
+{
+    char *d = dst;
+    const char *s = src;
+    size_t n = siz;
+    size_t dlen;
+
+    /* Find the end of dst and adjust bytes left but don't go past end */
+    while (n-- != 0 && *d != '\0')
+        d++;
+    dlen = d - dst;
+    n = siz - dlen;
+
+    if (n == 0)
+        return(dlen + strlen(s));
+    while (*s != '\0')
+    {
+        if (n != 1)
+        {
+            *d++ = *s;
+            n--;
+        }
+        s++;
+    }
+    *d = '\0';
+
+    return(dlen + (s - src)); /* count does not include NUL */
+}
+#endif
index e25004f..2d1d429 100644 (file)
@@ -14,6 +14,7 @@
 #include <vector>
 #include <string>
 
+#include <boost/foreach.hpp>
 #include <boost/thread.hpp>
 #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
 #include <boost/date_time/gregorian/gregorian_types.hpp>
@@ -37,7 +38,6 @@ typedef unsigned long long  uint64;
 #define __forceinline  inline
 #endif
 
-//#define foreach             BOOST_FOREACH
 #define loop                for (;;)
 #define BEGIN(a)            ((char*)&(a))
 #define END(a)              ((char*)&((&(a))[1]))
diff --git a/core/src/util.cpp b/core/src/util.cpp
new file mode 100644 (file)
index 0000000..0e88e2e
--- /dev/null
@@ -0,0 +1,917 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#define __STDC_LIMIT_MACROS // to enable UINT64_MAX from stdint.h
+
+#include "util.h"
+#include "main.h"
+#include "strlcpy.h"
+
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+
+#include <stdint.h>
+#include <climits>
+
+using namespace std;
+
+map<string, string> mapArgs;
+map<string, vector<string> > mapMultiArgs;
+bool fDebug = false;
+bool fPrintToConsole = false;
+bool fPrintToDebugger = false;
+char pszSetDataDir[MAX_PATH] = "";
+bool fRequestShutdown = false;
+bool fShutdown = false;
+bool fDaemon = false;
+bool fServer = false;
+bool fCommandLine = false;
+string strMiscWarning;
+bool fTestNet = false;
+bool fNoListen = false;
+bool fLogTimestamps = false;
+
+
+
+
+// Workaround for "multiple definition of `_tls_used'"
+// http://svn.boost.org/trac/boost/ticket/4258
+extern "C" void tss_cleanup_implemented() { }
+
+
+
+
+
+// Init openssl library multithreading support
+static boost::interprocess::interprocess_mutex** ppmutexOpenSSL;
+void locking_callback(int mode, int i, const char* file, int line)
+{
+    if (mode & CRYPTO_LOCK)
+        ppmutexOpenSSL[i]->lock();
+    else
+        ppmutexOpenSSL[i]->unlock();
+}
+
+// Init
+class CInit
+{
+public:
+    CInit()
+    {
+        // Init openssl library multithreading support
+        ppmutexOpenSSL = (boost::interprocess::interprocess_mutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(boost::interprocess::interprocess_mutex*));
+        for (int i = 0; i < CRYPTO_num_locks(); i++)
+            ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex();
+        CRYPTO_set_locking_callback(locking_callback);
+
+#ifdef __WXMSW__
+        // Seed random number generator with screen scrape and other hardware sources
+        RAND_screen();
+#endif
+
+        // Seed random number generator with performance counter
+        RandAddSeed();
+    }
+    ~CInit()
+    {
+        // Shutdown openssl library multithreading support
+        CRYPTO_set_locking_callback(NULL);
+        for (int i = 0; i < CRYPTO_num_locks(); i++)
+            delete ppmutexOpenSSL[i];
+        OPENSSL_free(ppmutexOpenSSL);
+    }
+}
+instance_of_cinit;
+
+
+
+
+
+
+
+
+void RandAddSeed()
+{
+    // Seed with CPU performance counter
+    int64 nCounter = GetPerformanceCounter();
+    RAND_add(&nCounter, sizeof(nCounter), 1.5);
+    memset(&nCounter, 0, sizeof(nCounter));
+}
+
+void RandAddSeedPerfmon()
+{
+    RandAddSeed();
+
+    // This can take up to 2 seconds, so only do it every 10 minutes
+    static int64 nLastPerfmon;
+    if (GetTime() < nLastPerfmon + 10 * 60)
+        return;
+    nLastPerfmon = GetTime();
+
+#ifdef __WXMSW__
+    // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
+    // Seed with the entire set of perfmon data
+    unsigned char pdata[250000];
+    memset(pdata, 0, sizeof(pdata));
+    unsigned long nSize = sizeof(pdata);
+    long ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
+    RegCloseKey(HKEY_PERFORMANCE_DATA);
+    if (ret == ERROR_SUCCESS)
+    {
+        RAND_add(pdata, nSize, nSize/100.0);
+        memset(pdata, 0, nSize);
+        printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize);
+    }
+#endif
+}
+
+uint64 GetRand(uint64 nMax)
+{
+    if (nMax == 0)
+        return 0;
+
+    // The range of the random source must be a multiple of the modulus
+    // to give every possible output value an equal possibility
+    uint64 nRange = (UINT64_MAX / nMax) * nMax;
+    uint64 nRand = 0;
+    do
+        RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
+    while (nRand >= nRange);
+    return (nRand % nMax);
+}
+
+int GetRandInt(int nMax)
+{
+    return GetRand(nMax);
+}
+
+
+
+
+
+
+
+
+
+
+
+inline int OutputDebugStringF(const char* pszFormat, ...)
+{
+    int ret = 0;
+    if (fPrintToConsole)
+    {
+        // print to console
+        va_list arg_ptr;
+        va_start(arg_ptr, pszFormat);
+        ret = vprintf(pszFormat, arg_ptr);
+        va_end(arg_ptr);
+    }
+    else
+    {
+        // print to debug.log
+        static FILE* fileout = NULL;
+
+        if (!fileout)
+        {
+            char pszFile[MAX_PATH+100];
+            GetDataDir(pszFile);
+            strlcat(pszFile, "/debug.log", sizeof(pszFile));
+            fileout = fopen(pszFile, "a");
+            if (fileout) setbuf(fileout, NULL); // unbuffered
+        }
+        if (fileout)
+        {
+            static bool fStartedNewLine = true;
+
+            // Debug print useful for profiling
+            if (fLogTimestamps && fStartedNewLine)
+                fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+            if (pszFormat[strlen(pszFormat) - 1] == '\n')
+                fStartedNewLine = true;
+            else
+                fStartedNewLine = false;
+
+            va_list arg_ptr;
+            va_start(arg_ptr, pszFormat);
+            ret = vfprintf(fileout, pszFormat, arg_ptr);
+            va_end(arg_ptr);
+        }
+    }
+
+#ifdef __WXMSW__
+    if (fPrintToDebugger)
+    {
+        static CCriticalSection cs_OutputDebugStringF;
+
+        // accumulate a line at a time
+        CRITICAL_BLOCK(cs_OutputDebugStringF)
+        {
+            static char pszBuffer[50000];
+            static char* pend;
+            if (pend == NULL)
+                pend = pszBuffer;
+            va_list arg_ptr;
+            va_start(arg_ptr, pszFormat);
+            int limit = END(pszBuffer) - pend - 2;
+            int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr);
+            va_end(arg_ptr);
+            if (ret < 0 || ret >= limit)
+            {
+                pend = END(pszBuffer) - 2;
+                *pend++ = '\n';
+            }
+            else
+                pend += ret;
+            *pend = '\0';
+            char* p1 = pszBuffer;
+            char* p2;
+            while (p2 = strchr(p1, '\n'))
+            {
+                p2++;
+                char c = *p2;
+                *p2 = '\0';
+                OutputDebugStringA(p1);
+                *p2 = c;
+                p1 = p2;
+            }
+            if (p1 != pszBuffer)
+                memmove(pszBuffer, p1, pend - p1 + 1);
+            pend -= (p1 - pszBuffer);
+        }
+    }
+#endif
+    return ret;
+}
+
+
+// Safer snprintf
+//  - prints up to limit-1 characters
+//  - output string is always null terminated even if limit reached
+//  - return value is the number of characters actually printed
+int my_snprintf(char* buffer, size_t limit, const char* format, ...)
+{
+    if (limit == 0)
+        return 0;
+    va_list arg_ptr;
+    va_start(arg_ptr, format);
+    int ret = _vsnprintf(buffer, limit, format, arg_ptr);
+    va_end(arg_ptr);
+    if (ret < 0 || ret >= limit)
+    {
+        ret = limit - 1;
+        buffer[limit-1] = 0;
+    }
+    return ret;
+}
+
+
+string strprintf(const char* format, ...)
+{
+    char buffer[50000];
+    char* p = buffer;
+    int limit = sizeof(buffer);
+    int ret;
+    loop
+    {
+        va_list arg_ptr;
+        va_start(arg_ptr, format);
+        ret = _vsnprintf(p, limit, format, arg_ptr);
+        va_end(arg_ptr);
+        if (ret >= 0 && ret < limit)
+            break;
+        if (p != buffer)
+            delete p;
+        limit *= 2;
+        p = new char[limit];
+        if (p == NULL)
+            throw std::bad_alloc();
+    }
+    string str(p, p+ret);
+    if (p != buffer)
+        delete p;
+    return str;
+}
+
+
+bool error(const char* format, ...)
+{
+    char buffer[50000];
+    int limit = sizeof(buffer);
+    va_list arg_ptr;
+    va_start(arg_ptr, format);
+    int ret = _vsnprintf(buffer, limit, format, arg_ptr);
+    va_end(arg_ptr);
+    if (ret < 0 || ret >= limit)
+    {
+        ret = limit - 1;
+        buffer[limit-1] = 0;
+    }
+    printf("ERROR: %s\n", buffer);
+    return false;
+}
+
+
+void ParseString(const string& str, char c, vector<string>& v)
+{
+    if (str.empty())
+        return;
+    string::size_type i1 = 0;
+    string::size_type i2;
+    loop
+    {
+        i2 = str.find(c, i1);
+        if (i2 == str.npos)
+        {
+            v.push_back(str.substr(i1));
+            return;
+        }
+        v.push_back(str.substr(i1, i2-i1));
+        i1 = i2+1;
+    }
+}
+
+
+string FormatMoney(int64 n, bool fPlus)
+{
+    // Note: not using straight sprintf here because we do NOT want
+    // localized number formatting.
+    int64 n_abs = (n > 0 ? n : -n);
+    int64 quotient = n_abs/COIN;
+    int64 remainder = n_abs%COIN;
+    string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder);
+
+    // Right-trim excess 0's before the decimal point:
+    int nTrim = 0;
+    for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)
+        ++nTrim;
+    if (nTrim)
+        str.erase(str.size()-nTrim, nTrim);
+
+    // Insert thousands-separators:
+    size_t point = str.find(".");
+    for (int i = (str.size()-point)+3; i < str.size(); i += 4)
+        if (isdigit(str[str.size() - i - 1]))
+            str.insert(str.size() - i, 1, ',');
+    if (n < 0)
+        str.insert((unsigned int)0, 1, '-');
+    else if (fPlus && n > 0)
+        str.insert((unsigned int)0, 1, '+');
+    return str;
+}
+
+
+bool ParseMoney(const string& str, int64& nRet)
+{
+    return ParseMoney(str.c_str(), nRet);
+}
+
+bool ParseMoney(const char* pszIn, int64& nRet)
+{
+    string strWhole;
+    int64 nUnits = 0;
+    const char* p = pszIn;
+    while (isspace(*p))
+        p++;
+    for (; *p; p++)
+    {
+        if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))
+            continue;
+        if (*p == '.')
+        {
+            p++;
+            int64 nMult = CENT*10;
+            while (isdigit(*p) && (nMult > 0))
+            {
+                nUnits += nMult * (*p++ - '0');
+                nMult /= 10;
+            }
+            break;
+        }
+        if (isspace(*p))
+            break;
+        if (!isdigit(*p))
+            return false;
+        strWhole.insert(strWhole.end(), *p);
+    }
+    for (; *p; p++)
+        if (!isspace(*p))
+            return false;
+    if (strWhole.size() > 14)
+        return false;
+    if (nUnits < 0 || nUnits > COIN)
+        return false;
+    int64 nWhole = atoi64(strWhole);
+    int64 nValue = nWhole*COIN + nUnits;
+
+    nRet = nValue;
+    return true;
+}
+
+
+vector<unsigned char> ParseHex(const char* psz)
+{
+    static char phexdigit[256] =
+    { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
+      -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
+
+    // convert hex dump to vector
+    vector<unsigned char> vch;
+    loop
+    {
+        while (isspace(*psz))
+            psz++;
+        char c = phexdigit[(unsigned char)*psz++];
+        if (c == (char)-1)
+            break;
+        unsigned char n = (c << 4);
+        c = phexdigit[(unsigned char)*psz++];
+        if (c == (char)-1)
+            break;
+        n |= c;
+        vch.push_back(n);
+    }
+    return vch;
+}
+
+vector<unsigned char> ParseHex(const string& str)
+{
+    return ParseHex(str.c_str());
+}
+
+
+void ParseParameters(int argc, char* argv[])
+{
+    mapArgs.clear();
+    mapMultiArgs.clear();
+    for (int i = 1; i < argc; i++)
+    {
+        char psz[10000];
+        strlcpy(psz, argv[i], sizeof(psz));
+        char* pszValue = (char*)"";
+        if (strchr(psz, '='))
+        {
+            pszValue = strchr(psz, '=');
+            *pszValue++ = '\0';
+        }
+        #ifdef __WXMSW__
+        _strlwr(psz);
+        if (psz[0] == '/')
+            psz[0] = '-';
+        #endif
+        if (psz[0] != '-')
+            break;
+        mapArgs[psz] = pszValue;
+        mapMultiArgs[psz].push_back(pszValue);
+    }
+}
+
+
+const char* wxGetTranslation(const char* pszEnglish)
+{
+#ifdef GUI
+    // Wrapper of wxGetTranslation returning the same const char* type as was passed in
+    static CCriticalSection cs;
+    CRITICAL_BLOCK(cs)
+    {
+        // Look in cache
+        static map<string, char*> mapCache;
+        map<string, char*>::iterator mi = mapCache.find(pszEnglish);
+        if (mi != mapCache.end())
+            return (*mi).second;
+
+        // wxWidgets translation
+        wxString strTranslated = wxGetTranslation(wxString(pszEnglish, wxConvUTF8));
+
+        // We don't cache unknown strings because caller might be passing in a
+        // dynamic string and we would keep allocating memory for each variation.
+        if (strcmp(pszEnglish, strTranslated.utf8_str()) == 0)
+            return pszEnglish;
+
+        // Add to cache, memory doesn't need to be freed.  We only cache because
+        // we must pass back a pointer to permanently allocated memory.
+        char* pszCached = new char[strlen(strTranslated.utf8_str())+1];
+        strcpy(pszCached, strTranslated.utf8_str());
+        mapCache[pszEnglish] = pszCached;
+        return pszCached;
+    }
+    return NULL;
+#else
+    return pszEnglish;
+#endif
+}
+
+
+bool WildcardMatch(const char* psz, const char* mask)
+{
+    loop
+    {
+        switch (*mask)
+        {
+        case '\0':
+            return (*psz == '\0');
+        case '*':
+            return WildcardMatch(psz, mask+1) || (*psz && WildcardMatch(psz+1, mask));
+        case '?':
+            if (*psz == '\0')
+                return false;
+            break;
+        default:
+            if (*psz != *mask)
+                return false;
+            break;
+        }
+        psz++;
+        mask++;
+    }
+}
+
+bool WildcardMatch(const string& str, const string& mask)
+{
+    return WildcardMatch(str.c_str(), mask.c_str());
+}
+
+
+
+
+
+
+
+
+void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
+{
+#ifdef __WXMSW__
+    char pszModule[MAX_PATH];
+    pszModule[0] = '\0';
+    GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
+#else
+    const char* pszModule = "bitcoin";
+#endif
+    if (pex)
+        snprintf(pszMessage, 1000,
+            "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
+    else
+        snprintf(pszMessage, 1000,
+            "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);
+}
+
+void LogException(std::exception* pex, const char* pszThread)
+{
+    char pszMessage[10000];
+    FormatException(pszMessage, pex, pszThread);
+    printf("\n%s", pszMessage);
+}
+
+void PrintException(std::exception* pex, const char* pszThread)
+{
+    char pszMessage[10000];
+    FormatException(pszMessage, pex, pszThread);
+    printf("\n\n************************\n%s\n", pszMessage);
+    fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
+    strMiscWarning = pszMessage;
+#ifdef GUI
+    if (wxTheApp && !fDaemon)
+        MyMessageBox(pszMessage, "Bitcoin", wxOK | wxICON_ERROR);
+#endif
+    throw;
+}
+
+void ThreadOneMessageBox(string strMessage)
+{
+    // Skip message boxes if one is already open
+    static bool fMessageBoxOpen;
+    if (fMessageBoxOpen)
+        return;
+    fMessageBoxOpen = true;
+    ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
+    fMessageBoxOpen = false;
+}
+
+void PrintExceptionContinue(std::exception* pex, const char* pszThread)
+{
+    char pszMessage[10000];
+    FormatException(pszMessage, pex, pszThread);
+    printf("\n\n************************\n%s\n", pszMessage);
+    fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
+    strMiscWarning = pszMessage;
+#ifdef GUI
+    if (wxTheApp && !fDaemon)
+        boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
+#endif
+}
+
+
+
+
+
+
+
+
+#ifdef __WXMSW__
+typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
+
+string MyGetSpecialFolderPath(int nFolder, bool fCreate)
+{
+    char pszPath[MAX_PATH+100] = "";
+
+    // SHGetSpecialFolderPath isn't always available on old Windows versions
+    HMODULE hShell32 = LoadLibraryA("shell32.dll");
+    if (hShell32)
+    {
+        PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
+            (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
+        if (pSHGetSpecialFolderPath)
+            (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
+        FreeModule(hShell32);
+    }
+
+    // Backup option
+    if (pszPath[0] == '\0')
+    {
+        if (nFolder == CSIDL_STARTUP)
+        {
+            strcpy(pszPath, getenv("USERPROFILE"));
+            strcat(pszPath, "\\Start Menu\\Programs\\Startup");
+        }
+        else if (nFolder == CSIDL_APPDATA)
+        {
+            strcpy(pszPath, getenv("APPDATA"));
+        }
+    }
+
+    return pszPath;
+}
+#endif
+
+string GetDefaultDataDir()
+{
+    // Windows: C:\Documents and Settings\username\Application Data\Bitcoin
+    // Mac: ~/Library/Application Support/Bitcoin
+    // Unix: ~/.bitcoin
+#ifdef __WXMSW__
+    // Windows
+    return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
+#else
+    char* pszHome = getenv("HOME");
+    if (pszHome == NULL || strlen(pszHome) == 0)
+        pszHome = (char*)"/";
+    string strHome = pszHome;
+    if (strHome[strHome.size()-1] != '/')
+        strHome += '/';
+#ifdef __WXMAC_OSX__
+    // Mac
+    strHome += "Library/Application Support/";
+    filesystem::create_directory(strHome.c_str());
+    return strHome + "Bitcoin";
+#else
+    // Unix
+    return strHome + ".bitcoin";
+#endif
+#endif
+}
+
+void GetDataDir(char* pszDir)
+{
+    // pszDir must be at least MAX_PATH length.
+    int nVariation;
+    if (pszSetDataDir[0] != 0)
+    {
+        strlcpy(pszDir, pszSetDataDir, MAX_PATH);
+        nVariation = 0;
+    }
+    else
+    {
+        // This can be called during exceptions by printf, so we cache the
+        // value so we don't have to do memory allocations after that.
+        static char pszCachedDir[MAX_PATH];
+        if (pszCachedDir[0] == 0)
+            strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
+        strlcpy(pszDir, pszCachedDir, MAX_PATH);
+        nVariation = 1;
+    }
+    if (fTestNet)
+    {
+        char* p = pszDir + strlen(pszDir);
+        if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
+            *p++ = '/';
+        strcpy(p, "testnet");
+        nVariation += 2;
+    }
+    static bool pfMkdir[4];
+    if (!pfMkdir[nVariation])
+    {
+        pfMkdir[nVariation] = true;
+        filesystem::create_directory(pszDir);
+    }
+}
+
+string GetDataDir()
+{
+    char pszDir[MAX_PATH];
+    GetDataDir(pszDir);
+    return pszDir;
+}
+
+string GetConfigFile()
+{
+    namespace fs = boost::filesystem;
+    fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
+    if (!pathConfig.is_complete())
+        pathConfig = fs::path(GetDataDir()) / pathConfig;
+    return pathConfig.string();
+}
+
+void ReadConfigFile(map<string, string>& mapSettingsRet,
+                    map<string, vector<string> >& mapMultiSettingsRet)
+{
+    namespace fs = boost::filesystem;
+    namespace pod = boost::program_options::detail;
+
+    fs::ifstream streamConfig(GetConfigFile());
+    if (!streamConfig.good())
+        return;
+
+    set<string> setOptions;
+    setOptions.insert("*");
+    
+    for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
+    {
+        // Don't overwrite existing settings so command line settings override bitcoin.conf
+        string strKey = string("-") + it->string_key;
+        if (mapSettingsRet.count(strKey) == 0)
+            mapSettingsRet[strKey] = it->value[0];
+        mapMultiSettingsRet[strKey].push_back(it->value[0]);
+    }
+}
+
+string GetPidFile()
+{
+    namespace fs = boost::filesystem;
+    fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
+    if (!pathConfig.is_complete())
+        pathConfig = fs::path(GetDataDir()) / pathConfig;
+    return pathConfig.string();
+}
+
+void CreatePidFile(string pidFile, pid_t pid)
+{
+    FILE* file;
+    if (file = fopen(pidFile.c_str(), "w"))
+    {
+        fprintf(file, "%d\n", pid);
+        fclose(file);
+    }
+}
+
+int GetFilesize(FILE* file)
+{
+    int nSavePos = ftell(file);
+    int nFilesize = -1;
+    if (fseek(file, 0, SEEK_END) == 0)
+        nFilesize = ftell(file);
+    fseek(file, nSavePos, SEEK_SET);
+    return nFilesize;
+}
+
+void ShrinkDebugFile()
+{
+    // Scroll debug.log if it's getting too big
+    string strFile = GetDataDir() + "/debug.log";
+    FILE* file = fopen(strFile.c_str(), "r");
+    if (file && GetFilesize(file) > 10 * 1000000)
+    {
+        // Restart the file with some of the end
+        char pch[200000];
+        fseek(file, -sizeof(pch), SEEK_END);
+        int nBytes = fread(pch, 1, sizeof(pch), file);
+        fclose(file);
+        if (file = fopen(strFile.c_str(), "w"))
+        {
+            fwrite(pch, 1, nBytes, file);
+            fclose(file);
+        }
+    }
+}
+
+
+
+
+
+
+
+
+//
+// "Never go to sea with two chronometers; take one or three."
+// Our three time sources are:
+//  - System clock
+//  - Median of other nodes's clocks
+//  - The user (asking the user to fix the system clock if the first two disagree)
+//
+int64 GetTime()
+{
+    return time(NULL);
+}
+
+static int64 nTimeOffset = 0;
+
+int64 GetAdjustedTime()
+{
+    return GetTime() + nTimeOffset;
+}
+
+void AddTimeData(unsigned int ip, int64 nTime)
+{
+    int64 nOffsetSample = nTime - GetTime();
+
+    // Ignore duplicates
+    static set<unsigned int> setKnown;
+    if (!setKnown.insert(ip).second)
+        return;
+
+    // Add data
+    static vector<int64> vTimeOffsets;
+    if (vTimeOffsets.empty())
+        vTimeOffsets.push_back(0);
+    vTimeOffsets.push_back(nOffsetSample);
+    printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
+    if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
+    {
+        sort(vTimeOffsets.begin(), vTimeOffsets.end());
+        int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
+        // Only let other nodes change our time by so much
+        if (abs64(nMedian) < 70 * 60)
+        {
+            nTimeOffset = nMedian;
+        }
+        else
+        {
+            nTimeOffset = 0;
+
+            static bool fDone;
+            if (!fDone)
+            {
+                // If nobody has a time different than ours but within 5 minutes of ours, give a warning
+                bool fMatch = false;
+                foreach(int64 nOffset, vTimeOffsets)
+                    if (nOffset != 0 && abs64(nOffset) < 5 * 60)
+                        fMatch = true;
+
+                if (!fMatch)
+                {
+                    fDone = true;
+                    string strMessage = _("Warning: Please check that your computer's date and time are correct.  If your clock is wrong Bitcoin will not work properly.");
+                    strMiscWarning = strMessage;
+                    printf("*** %s\n", strMessage.c_str());
+                    boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
+                }
+            }
+        }
+        foreach(int64 n, vTimeOffsets)
+            printf("%+"PRI64d"  ", n);
+        printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
+    }
+}
+
+
+
+
+
+
+
+
+
+string FormatVersion(int nVersion)
+{
+    if (nVersion%100 == 0)
+        return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100);
+    else
+        return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100);
+}
+
+string FormatFullVersion()
+{
+    string s = FormatVersion(VERSION) + pszSubVer;
+    if (VERSION_IS_BETA)
+        s += _("-beta");
+    return s;
+}
+
+
+
+
+
index d1a06f7..8322eef 100644 (file)
@@ -3,8 +3,6 @@
 
 #include <QRegExpValidator>
 
-#include <base58.h>
-
 class BitcoinAddressValidator : public QRegExpValidator
 {
     Q_OBJECT
index 6c216d3..ce95244 100644 (file)
@@ -7,6 +7,8 @@
 #include <QApplication>
 #include <QClipboard>
 
+#include "base58.h"
+
 SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
     QDialog(parent),
     ui(new Ui::SendCoinsDialog)
@@ -24,7 +26,16 @@ SendCoinsDialog::~SendCoinsDialog()
 
 void SendCoinsDialog::on_sendButton_clicked()
 {
-    accept();
+    QByteArray payTo = ui->payTo->text().toUtf8();
+    uint160 payToHash = 0;
+    if(AddressToHash160(payTo.constData(), payToHash))
+    {
+        accept();
+    }
+    else
+    {
+
+    }
 }
 
 void SendCoinsDialog::on_pasteButton_clicked()